Move btbulkdelete's vacuum_delay_point() call to a place in the loop where
authorTom Lane <[email protected]>
Tue, 14 Feb 2006 17:20:17 +0000 (17:20 +0000)
committerTom Lane <[email protected]>
Tue, 14 Feb 2006 17:20:17 +0000 (17:20 +0000)
we are not holding a buffer content lock; where it was, InterruptHoldoffCount
is positive and so we'd not respond to cancel signals as intended.  Also
add missing vacuum_delay_point() call in btvacuumcleanup.  This should fix
complaint from Evgeny Gridasov about failure to respond to SIGINT/SIGTERM
in a timely fashion (bug #2257).

src/backend/access/nbtree/nbtree.c

index 4f742886bd378b1fab335947290c6645a3b0f99c..642f2dcb348aac6d5b2cbbd6a4bca214384c3554 100644 (file)
@@ -571,8 +571,6 @@ btbulkdelete(PG_FUNCTION_ARGS)
                                                maxoff;
                        BlockNumber nextpage;
 
-                       vacuum_delay_point();
-
                        ndeletable = 0;
                        page = BufferGetPage(buf);
                        opaque = (BTPageOpaque) PageGetSpecialPointer(page);
@@ -631,6 +629,10 @@ btbulkdelete(PG_FUNCTION_ARGS)
                        }
                        else
                                _bt_relbuf(rel, buf);
+
+                       /* call vacuum_delay_point while not holding any buffer lock */
+                       vacuum_delay_point();
+
                        /* And advance to next page, if any */
                        if (nextpage == P_NONE)
                                break;
@@ -670,11 +672,35 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
        BlockNumber pages_deleted = 0;
        MemoryContext mycontext;
        MemoryContext oldcontext;
+       bool            needLock;
 
        Assert(stats != NULL);
 
+       /*
+        * First find out the number of pages in the index.  We must acquire
+        * the relation-extension lock while doing this to avoid a race
+        * condition: if someone else is extending the relation, there is
+        * a window where bufmgr/smgr have created a new all-zero page but
+        * it hasn't yet been write-locked by _bt_getbuf().  If we manage to
+        * scan such a page here, we'll improperly assume it can be recycled.
+        * Taking the lock synchronizes things enough to prevent a problem:
+        * either num_pages won't include the new page, or _bt_getbuf already
+        * has write lock on the buffer and it will be fully initialized before
+        * we can examine it.  (See also vacuumlazy.c, which has the same issue.)
+        *
+        * We can skip locking for new or temp relations,
+        * however, since no one else could be accessing them.
+        */
+       needLock = !RELATION_IS_LOCAL(rel);
+
+       if (needLock)
+               LockPage(rel, 0, ExclusiveLock);
+
        num_pages = RelationGetNumberOfBlocks(rel);
 
+       if (needLock)
+               UnlockPage(rel, 0, ExclusiveLock);
+
        /* No point in remembering more than MaxFSMPages pages */
        maxFreePages = MaxFSMPages;
        if ((BlockNumber) maxFreePages > num_pages)
@@ -700,6 +726,8 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
                Page            page;
                BTPageOpaque opaque;
 
+               vacuum_delay_point();
+
                buf = _bt_getbuf(rel, blkno, BT_READ);
                page = BufferGetPage(buf);
                opaque = (BTPageOpaque) PageGetSpecialPointer(page);