Commit cd255bb0 authored by Tom Lane's avatar Tom Lane

Fix boundary condition in btbulkdelete: don't examine high key in case

where rightmost index page splits while we are waiting to obtain exclusive
lock on it.  Not clear this would actually hurt (probably the callback
would always fail), but better safe than sorry.
Also, improve comments describing concurrency considerations in this code.
parent b104ffbd
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.85 2001/11/10 23:51:13 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.86 2001/11/23 23:41:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -592,6 +592,7 @@ btbulkdelete(PG_FUNCTION_ARGS) ...@@ -592,6 +592,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
BlockNumber blkno; BlockNumber blkno;
OffsetNumber offnum; OffsetNumber offnum;
BTItem btitem; BTItem btitem;
BTPageOpaque opaque;
IndexTuple itup; IndexTuple itup;
ItemPointer htup; ItemPointer htup;
...@@ -608,9 +609,17 @@ btbulkdelete(PG_FUNCTION_ARGS) ...@@ -608,9 +609,17 @@ btbulkdelete(PG_FUNCTION_ARGS)
/* /*
* If this is first deletion on this page, trade in read * If this is first deletion on this page, trade in read
* lock for a really-exclusive write lock. Then, step * lock for a really-exclusive write lock. Then, step
* back one and re-examine the item, because someone else * back one and re-examine the item, because other backends
* might have inserted an item while we weren't holding * might have inserted item(s) while we weren't holding
* the lock! * the lock!
*
* We assume that only concurrent insertions, not deletions,
* can occur while we're not holding the page lock (the caller
* should hold a suitable relation lock to ensure this).
* Therefore, the item we want to delete is either in the
* same slot as before, or some slot to its right.
* Rechecking the same slot is necessary and sufficient to
* get back in sync after any insertions.
*/ */
if (blkno != lockedBlock) if (blkno != lockedBlock)
{ {
...@@ -620,7 +629,7 @@ btbulkdelete(PG_FUNCTION_ARGS) ...@@ -620,7 +629,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
} }
else else
{ {
/* Delete the item from the page */ /* Okay to delete the item from the page */
_bt_itemdel(rel, buf, current); _bt_itemdel(rel, buf, current);
/* Mark buffer dirty, but keep the lock and pin */ /* Mark buffer dirty, but keep the lock and pin */
...@@ -630,14 +639,23 @@ btbulkdelete(PG_FUNCTION_ARGS) ...@@ -630,14 +639,23 @@ btbulkdelete(PG_FUNCTION_ARGS)
} }
/* /*
* We need to back up the scan one item so that the next * In either case, we now need to back up the scan one item,
* cycle will re-examine the same offnum on this page. * so that the next cycle will re-examine the same offnum on
* this page.
* *
* For now, just hack the current-item index. Will need to * For now, just hack the current-item index. Will need to
* be smarter when deletion includes removal of empty * be smarter when deletion includes removal of empty
* index pages. * index pages.
*
* We must decrement ip_posid in all cases but one: if the
* page was formerly rightmost but was split while we didn't
* hold the lock, and ip_posid is pointing to item 1, then
* ip_posid now points at the high key not a valid data item.
* In this case we do want to step forward.
*/ */
current->ip_posid--; opaque = (BTPageOpaque) PageGetSpecialPointer(page);
if (current->ip_posid >= P_FIRSTDATAKEY(opaque))
current->ip_posid--;
} }
else else
num_index_tuples += 1; num_index_tuples += 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment