From 36147525a12101d8bde6c00a238759cd371eefcc Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 24 Jul 2019 14:35:13 -0700 Subject: [PATCH 3/3] Account for posting list overhead during splits. --- src/backend/access/nbtree/nbtsplitloc.c | 37 +++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/backend/access/nbtree/nbtsplitloc.c b/src/backend/access/nbtree/nbtsplitloc.c index fbb12dbff1..77e1d46672 100644 --- a/src/backend/access/nbtree/nbtsplitloc.c +++ b/src/backend/access/nbtree/nbtsplitloc.c @@ -459,6 +459,7 @@ _bt_recsplitloc(FindSplitData *state, int16 leftfree, rightfree; Size firstrightitemsz; + Size postingsubhikey = 0; bool newitemisfirstonright; /* Is the new item going to be the first item on the right page? */ @@ -466,10 +467,33 @@ _bt_recsplitloc(FindSplitData *state, && !newitemonleft); if (newitemisfirstonright) + { firstrightitemsz = state->newitemsz; + + /* Calculate posting list overhead, if any */ + if (state->is_leaf && BTreeTupleIsPosting(state->newitem)) + postingsubhikey = IndexTupleSize(state->newitem) - + BTreeTupleGetPostingOffset(state->newitem); + } else + { firstrightitemsz = firstoldonrightsz; + /* Calculate posting list overhead, if any */ + if (state->is_leaf) + { + ItemId itemid; + IndexTuple newhighkey; + + itemid = PageGetItemId(state->page, firstoldonright); + newhighkey = (IndexTuple) PageGetItem(state->page, itemid); + + if (BTreeTupleIsPosting(newhighkey)) + postingsubhikey = IndexTupleSize(newhighkey) - + BTreeTupleGetPostingOffset(newhighkey); + } + } + /* Account for all the old tuples */ leftfree = state->leftspace - olddataitemstoleft; rightfree = state->rightspace - @@ -492,16 +516,13 @@ _bt_recsplitloc(FindSplitData *state, * adding a heap TID to the left half's new high key when splitting at the * leaf level. In practice the new high key will often be smaller and * will rarely be larger, but conservatively assume the worst case. - * - * FIXME: We can make better choices about split points by being clever - * about the BTreeTupleIsPosting() case here. All we need to do is - * subtract the whole size of the posting list, then add - * MAXALIGN(sizeof(ItemPointerData)), since we know for sure that - * _bt_truncate() won't make a final high key that is larger even in the - * worst case. + * Truncation always truncates away any posting list that appears in the + * first right tuple, though, so it's safe to subtract that overhead + * (while still conservatively assuming that truncation might have to add + * back a single heap TID using the pivot tuple heap TID representation). */ if (state->is_leaf) - leftfree -= (int16) (firstrightitemsz + + leftfree -= (int16) ((firstrightitemsz - postingsubhikey) + MAXALIGN(sizeof(ItemPointerData))); else leftfree -= (int16) firstrightitemsz; -- 2.17.1