aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gist/gistbuild.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2012-08-16 12:42:11 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2012-08-16 12:56:24 +0300
commit89911b3ab848915dd64d21ca3d3537470c93f89c (patch)
tree0285c9e6686ee083ea403c322f350548c20212c0 /src/backend/access/gist/gistbuild.c
parentde3773d951bfc85d8860295248cf91db524a4ef8 (diff)
downloadpostgresql-89911b3ab848915dd64d21ca3d3537470c93f89c.tar.gz
postgresql-89911b3ab848915dd64d21ca3d3537470c93f89c.zip
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.
Diffstat (limited to 'src/backend/access/gist/gistbuild.c')
-rw-r--r--src/backend/access/gist/gistbuild.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c
index 8caf4856763..bcd95a8a4d8 100644
--- a/src/backend/access/gist/gistbuild.c
+++ b/src/backend/access/gist/gistbuild.c
@@ -85,7 +85,7 @@ static void gistBufferingBuildInsert(GISTBuildState *buildstate,
IndexTuple itup);
static bool gistProcessItup(GISTBuildState *buildstate, IndexTuple itup,
BlockNumber startblkno, int startlevel);
-static void gistbufferinginserttuples(GISTBuildState *buildstate,
+static BlockNumber gistbufferinginserttuples(GISTBuildState *buildstate,
Buffer buffer, int level,
IndexTuple *itup, int ntup, OffsetNumber oldoffnum,
BlockNumber parentblk, OffsetNumber downlinkoffnum);
@@ -621,9 +621,9 @@ gistProcessItup(GISTBuildState *buildstate, IndexTuple itup,
newtup = gistgetadjusted(indexrel, idxtuple, itup, giststate);
if (newtup)
{
- gistbufferinginserttuples(buildstate, buffer, level,
- &newtup, 1, childoffnum,
- InvalidBlockNumber, InvalidOffsetNumber);
+ blkno = gistbufferinginserttuples(buildstate, buffer, level,
+ &newtup, 1, childoffnum,
+ InvalidBlockNumber, InvalidOffsetNumber);
/* gistbufferinginserttuples() released the buffer */
}
else
@@ -676,10 +676,14 @@ gistProcessItup(GISTBuildState *buildstate, IndexTuple itup,
*
* This is analogous with gistinserttuples() in the regular insertion code.
*
+ * Returns the block number of the page where the (first) new or updated tuple
+ * was inserted. Usually that's the original page, but might be a sibling page
+ * if the original page was split.
+ *
* Caller should hold a lock on 'buffer' on entry. This function will unlock
* and unpin it.
*/
-static void
+static BlockNumber
gistbufferinginserttuples(GISTBuildState *buildstate, Buffer buffer, int level,
IndexTuple *itup, int ntup, OffsetNumber oldoffnum,
BlockNumber parentblk, OffsetNumber downlinkoffnum)
@@ -687,12 +691,13 @@ gistbufferinginserttuples(GISTBuildState *buildstate, Buffer buffer, int level,
GISTBuildBuffers *gfbb = buildstate->gfbb;
List *splitinfo;
bool is_split;
+ BlockNumber placed_to_blk = InvalidBlockNumber;
is_split = gistplacetopage(buildstate->indexrel,
buildstate->freespace,
buildstate->giststate,
buffer,
- itup, ntup, oldoffnum,
+ itup, ntup, oldoffnum, &placed_to_blk,
InvalidBuffer,
&splitinfo,
false);
@@ -823,6 +828,8 @@ gistbufferinginserttuples(GISTBuildState *buildstate, Buffer buffer, int level,
}
else
UnlockReleaseBuffer(buffer);
+
+ return placed_to_blk;
}
/*