diff options
-rw-r--r-- | src/backend/access/heap/hio.c | 24 | ||||
-rw-r--r-- | src/backend/commands/vacuumlazy.c | 26 |
2 files changed, 39 insertions, 11 deletions
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index 67eb4ad7e24..2d0c0a93255 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Id: hio.c,v 1.46 2002/08/06 02:36:33 tgl Exp $ + * $Id: hio.c,v 1.46.2.1 2005/05/07 21:33:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -250,13 +250,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. */ @@ -264,9 +257,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/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 9495301ddd8..6e6d815524b 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -31,7 +31,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.20 2002/09/20 19:56:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.20.2.1 2005/05/07 21:33:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -261,8 +261,30 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, if (PageIsNew(page)) { - /* Not sure we still need to handle this case, but... */ + /* + * An all-zeroes page could be left over if a backend extends + * the relation but crashes before initializing the page. + * Reclaim such pages for use. + * + * We have to be careful here because we could be looking at + * a page that someone has just added to the relation and not + * yet been able to initialize (see RelationGetBufferForTuple). + * To interlock against that, release the buffer read lock + * (which we must do anyway) and grab the relation extension + * lock before re-locking in exclusive mode. If the page is + * still uninitialized by then, it must be left over from a + * crashed backend, and we can initialize it. + * + * We don't really need the relation lock when this is a new + * or temp relation, but it's probably not worth the code space + * to check that, since this surely isn't a critical path. + * + * Note: the comparable code in vacuum.c need not do all this + * because it's got exclusive lock on the whole relation. + */ LockBuffer(buf, BUFFER_LOCK_UNLOCK); + LockPage(onerel, 0, ExclusiveLock); + UnlockPage(onerel, 0, ExclusiveLock); LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); if (PageIsNew(page)) { |