Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 89911b3

Browse files
committed
Fix GiST buffering build bug, which caused "failed to re-find parent" errors.
We use a hash table to track the parents of inner pages, but when inserting to a leaf page, the caller of gistbufferinginserttuples() must pass a correct block number of the leaf's parent page. Before gistProcessItup() descends to a child page, it checks if the downlink needs to be adjusted to accommodate the new tuple, and updates the downlink if necessary. However, updating the downlink might require splitting the page, which might move the downlink to a page to the right. gistProcessItup() doesn't realize that, so when it descends to the leaf page, it might pass an out-of-date parent block number as a result. Fix that by returning the block a tuple was inserted to from gistbufferinginserttuples(). This fixes the bug reported by Zdeněk Jílovec.
1 parent de3773d commit 89911b3

File tree

3 files changed

+41
-14
lines changed

3 files changed

+41
-14
lines changed

src/backend/access/gist/gist.c

+26-7
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,22 @@ gistinsert(PG_FUNCTION_ARGS)
148148
* pages are released; note that new tuple(s) are *not* on the root page
149149
* but in one of the new child pages.
150150
*
151+
* If 'newblkno' is not NULL, returns the block number of page the first
152+
* new/updated tuple was inserted to. Usually it's the given page, but could
153+
* be its right sibling if the page was split.
154+
*
151155
* Returns 'true' if the page was split, 'false' otherwise.
152156
*/
153157
bool
154158
gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
155159
Buffer buffer,
156160
IndexTuple *itup, int ntup, OffsetNumber oldoffnum,
161+
BlockNumber *newblkno,
157162
Buffer leftchildbuf,
158163
List **splitinfo,
159164
bool markfollowright)
160165
{
166+
BlockNumber blkno = BufferGetBlockNumber(buffer);
161167
Page page = BufferGetPage(buffer);
162168
bool is_leaf = (GistPageIsLeaf(page)) ? true : false;
163169
XLogRecPtr recptr;
@@ -199,7 +205,6 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
199205
BlockNumber oldrlink = InvalidBlockNumber;
200206
GistNSN oldnsn = 0;
201207
SplitedPageLayout rootpg;
202-
BlockNumber blkno = BufferGetBlockNumber(buffer);
203208
bool is_rootsplit;
204209

205210
is_rootsplit = (blkno == GIST_ROOT_BLKNO);
@@ -319,9 +324,19 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
319324

320325
for (i = 0; i < ptr->block.num; i++)
321326
{
322-
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, false, false) == InvalidOffsetNumber)
327+
IndexTuple thistup = (IndexTuple) data;
328+
329+
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize(thistup), i + FirstOffsetNumber, false, false) == InvalidOffsetNumber)
323330
elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(rel));
324-
data += IndexTupleSize((IndexTuple) data);
331+
332+
/*
333+
* If this is the first inserted/updated tuple, let the caller
334+
* know which page it landed on.
335+
*/
336+
if (newblkno && ItemPointerEquals(&thistup->t_tid, &(*itup)->t_tid))
337+
*newblkno = ptr->block.blkno;
338+
339+
data += IndexTupleSize(thistup);
325340
}
326341

327342
/* Set up rightlinks */
@@ -436,6 +451,9 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
436451
recptr = GetXLogRecPtrForTemp();
437452
PageSetLSN(page, recptr);
438453
}
454+
455+
if (newblkno)
456+
*newblkno = blkno;
439457
}
440458

441459
/*
@@ -1074,9 +1092,9 @@ gistinserttuple(GISTInsertState *state, GISTInsertStack *stack,
10741092
* is kept pinned.
10751093
* - Lock and pin on 'rightchild' are always released.
10761094
*
1077-
* Returns 'true' if the page had to be split. Note that if the page had
1078-
* be split, the inserted/updated might've been inserted to a right sibling
1079-
* of stack->buffer instead of stack->buffer itself.
1095+
* Returns 'true' if the page had to be split. Note that if the page was
1096+
* split, the inserted/updated tuples might've been inserted to a right
1097+
* sibling of stack->buffer instead of stack->buffer itself.
10801098
*/
10811099
static bool
10821100
gistinserttuples(GISTInsertState *state, GISTInsertStack *stack,
@@ -1091,7 +1109,8 @@ gistinserttuples(GISTInsertState *state, GISTInsertStack *stack,
10911109
/* Insert the tuple(s) to the page, splitting the page if necessary */
10921110
is_split = gistplacetopage(state->r, state->freespace, giststate,
10931111
stack->buffer,
1094-
tuples, ntup, oldoffnum,
1112+
tuples, ntup,
1113+
oldoffnum, NULL,
10951114
leftchild,
10961115
&splitinfo,
10971116
true);

src/backend/access/gist/gistbuild.c

+13-6
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ static void gistBufferingBuildInsert(GISTBuildState *buildstate,
8585
IndexTuple itup);
8686
static bool gistProcessItup(GISTBuildState *buildstate, IndexTuple itup,
8787
BlockNumber startblkno, int startlevel);
88-
static void gistbufferinginserttuples(GISTBuildState *buildstate,
88+
static BlockNumber gistbufferinginserttuples(GISTBuildState *buildstate,
8989
Buffer buffer, int level,
9090
IndexTuple *itup, int ntup, OffsetNumber oldoffnum,
9191
BlockNumber parentblk, OffsetNumber downlinkoffnum);
@@ -621,9 +621,9 @@ gistProcessItup(GISTBuildState *buildstate, IndexTuple itup,
621621
newtup = gistgetadjusted(indexrel, idxtuple, itup, giststate);
622622
if (newtup)
623623
{
624-
gistbufferinginserttuples(buildstate, buffer, level,
625-
&newtup, 1, childoffnum,
626-
InvalidBlockNumber, InvalidOffsetNumber);
624+
blkno = gistbufferinginserttuples(buildstate, buffer, level,
625+
&newtup, 1, childoffnum,
626+
InvalidBlockNumber, InvalidOffsetNumber);
627627
/* gistbufferinginserttuples() released the buffer */
628628
}
629629
else
@@ -676,23 +676,28 @@ gistProcessItup(GISTBuildState *buildstate, IndexTuple itup,
676676
*
677677
* This is analogous with gistinserttuples() in the regular insertion code.
678678
*
679+
* Returns the block number of the page where the (first) new or updated tuple
680+
* was inserted. Usually that's the original page, but might be a sibling page
681+
* if the original page was split.
682+
*
679683
* Caller should hold a lock on 'buffer' on entry. This function will unlock
680684
* and unpin it.
681685
*/
682-
static void
686+
static BlockNumber
683687
gistbufferinginserttuples(GISTBuildState *buildstate, Buffer buffer, int level,
684688
IndexTuple *itup, int ntup, OffsetNumber oldoffnum,
685689
BlockNumber parentblk, OffsetNumber downlinkoffnum)
686690
{
687691
GISTBuildBuffers *gfbb = buildstate->gfbb;
688692
List *splitinfo;
689693
bool is_split;
694+
BlockNumber placed_to_blk = InvalidBlockNumber;
690695

691696
is_split = gistplacetopage(buildstate->indexrel,
692697
buildstate->freespace,
693698
buildstate->giststate,
694699
buffer,
695-
itup, ntup, oldoffnum,
700+
itup, ntup, oldoffnum, &placed_to_blk,
696701
InvalidBuffer,
697702
&splitinfo,
698703
false);
@@ -823,6 +828,8 @@ gistbufferinginserttuples(GISTBuildState *buildstate, Buffer buffer, int level,
823828
}
824829
else
825830
UnlockReleaseBuffer(buffer);
831+
832+
return placed_to_blk;
826833
}
827834

828835
/*

src/include/access/gist_private.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,8 @@ typedef struct
430430

431431
extern bool gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
432432
Buffer buffer,
433-
IndexTuple *itup, int ntup, OffsetNumber oldoffnum,
433+
IndexTuple *itup, int ntup,
434+
OffsetNumber oldoffnum, BlockNumber *newblkno,
434435
Buffer leftchildbuf,
435436
List **splitinfo,
436437
bool markleftchild);

0 commit comments

Comments
 (0)