summaryrefslogtreecommitdiff
path: root/src/backend/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access')
-rw-r--r--src/backend/access/heap/hio.c24
-rw-r--r--src/backend/access/nbtree/nbtpage.c15
-rw-r--r--src/backend/access/nbtree/nbtree.c26
3 files changed, 49 insertions, 16 deletions
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index 27af323ed11..46c2fd31e04 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.54 2004/12/31 21:59:16 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.54.4.1 2005/05/07 21:32:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -247,13 +247,6 @@ RelationGetBufferForTuple(Relation relation, Size len,
buffer = ReadBuffer(relation, P_NEW);
/*
- * Release the file-extension lock; it's now OK for someone else to
- * extend the relation some more.
- */
- if (needLock)
- UnlockPage(relation, 0, ExclusiveLock);
-
- /*
* We can be certain that locking the otherBuffer first is OK, since
* it must have a lower page number.
*/
@@ -261,9 +254,22 @@ RelationGetBufferForTuple(Relation relation, Size len,
LockBuffer(otherBuffer, BUFFER_LOCK_EXCLUSIVE);
/*
- * We need to initialize the empty new page.
+ * Now acquire lock on the new page.
*/
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
+
+ /*
+ * Release the file-extension lock; it's now OK for someone else to
+ * extend the relation some more. Note that we cannot release this
+ * lock before we have buffer lock on the new page, or we risk a
+ * race condition against vacuumlazy.c --- see comments therein.
+ */
+ if (needLock)
+ UnlockPage(relation, 0, ExclusiveLock);
+
+ /*
+ * We need to initialize the empty new page.
+ */
pageHeader = (Page) BufferGetPage(buffer);
Assert(PageIsNew((PageHeader) pageHeader));
PageInit(pageHeader, BufferGetPageSize(buffer), 0);
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 3e2a9010a44..378c5f9d36f 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.81 2004/12/31 21:59:22 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.81.4.1 2005/05/07 21:32:53 tgl Exp $
*
* NOTES
* Postgres btree pages look like ordinary relation pages. The opaque
@@ -491,18 +491,21 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
buf = ReadBuffer(rel, P_NEW);
+ /* Acquire buffer lock on new page */
+ LockBuffer(buf, BT_WRITE);
+
/*
- * Release the file-extension lock; it's now OK for someone else
- * to extend the relation some more.
+ * Release the file-extension lock; it's now OK for someone else to
+ * extend the relation some more. Note that we cannot release this
+ * lock before we have buffer lock on the new page, or we risk a
+ * race condition against btvacuumcleanup --- see comments therein.
*/
if (needLock)
UnlockPage(rel, 0, ExclusiveLock);
- /* Acquire appropriate buffer lock on new page */
- LockBuffer(buf, access);
-
/* Initialize the new page before returning it */
page = BufferGetPage(buf);
+ Assert(PageIsNew((PageHeader) page));
_bt_pageinit(page, BufferGetPageSize(buf));
}
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index ba31abcbbfd..988cbc2a218 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.124 2004/12/31 21:59:22 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.124.4.1 2005/05/07 21:32:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -670,11 +670,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)