diff options
Diffstat (limited to 'src/backend/storage/buffer/bufmgr.c')
-rw-r--r-- | src/backend/storage/buffer/bufmgr.c | 327 |
1 files changed, 116 insertions, 211 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 89443ee160e..86c2c478f48 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.116 2001/07/06 21:04:25 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.117 2001/09/29 04:02:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -59,7 +59,6 @@ (*((XLogRecPtr*)MAKE_PTR((bufHdr)->data))) -extern SPINLOCK BufMgrLock; extern long int ReadBufferCount; extern long int ReadLocalBufferCount; extern long int BufferHitCount; @@ -76,7 +75,7 @@ extern long int LocalBufferFlushCount; */ bool SharedBufferChanged = false; -static void WaitIO(BufferDesc *buf, SPINLOCK spinlock); +static void WaitIO(BufferDesc *buf); static void StartBufferIO(BufferDesc *buf, bool forInput); static void TerminateBufferIO(BufferDesc *buf); static void ContinueBufferIO(BufferDesc *buf, bool forInput); @@ -130,7 +129,7 @@ ReadBuffer(Relation reln, BlockNumber blockNum) /* * ReadBufferInternal -- internal version of ReadBuffer with more options * - * bufferLockHeld: if true, caller already acquired the bufmgr spinlock. + * bufferLockHeld: if true, caller already acquired the bufmgr lock. * (This is assumed never to be true if dealing with a local buffer!) */ static Buffer @@ -179,7 +178,7 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum, * block is not currently in memory. */ if (!bufferLockHeld) - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); bufHdr = BufferAlloc(reln, blockNum, &found); if (found) { @@ -188,7 +187,7 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum, } } - /* At this point we do NOT hold the bufmgr spinlock. */ + /* At this point we do NOT hold the bufmgr lock. */ if (!bufHdr) return InvalidBuffer; @@ -208,9 +207,9 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum, */ if (!isLocalBuf) { - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); StartBufferIO(bufHdr, false); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); } } @@ -243,7 +242,7 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum, } /* lock buffer manager again to update IO IN PROGRESS */ - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); if (status == SM_FAIL) { @@ -251,7 +250,7 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum, if (!BufTableDelete(bufHdr)) { - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); elog(FATAL, "BufRead: buffer table broken after IO error"); } /* remember that BufferAlloc() pinned the buffer */ @@ -274,7 +273,7 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum, /* If anyone was waiting for IO to complete, wake them up now */ TerminateBufferIO(bufHdr); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); if (status == SM_FAIL) return InvalidBuffer; @@ -322,7 +321,7 @@ BufferAlloc(Relation reln, *foundPtr = TRUE; if (inProgress) /* confirm end of IO */ { - WaitIO(buf, BufMgrLock); + WaitIO(buf); inProgress = (buf->flags & BM_IO_IN_PROGRESS); } if (BUFFER_IS_BROKEN(buf)) @@ -354,7 +353,7 @@ BufferAlloc(Relation reln, if (!(*foundPtr)) StartBufferIO(buf, true); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); return buf; } @@ -364,7 +363,7 @@ BufferAlloc(Relation reln, /* * Didn't find it in the buffer pool. We'll have to initialize a new * buffer. First, grab one from the free list. If it's dirty, flush - * it to disk. Remember to unlock BufMgr spinlock while doing the IOs. + * it to disk. Remember to unlock BufMgrLock while doing the IOs. */ inProgress = FALSE; for (buf = (BufferDesc *) NULL; buf == (BufferDesc *) NULL;) @@ -502,7 +501,7 @@ BufferAlloc(Relation reln, *foundPtr = TRUE; if (inProgress) { - WaitIO(buf2, BufMgrLock); + WaitIO(buf2); inProgress = (buf2->flags & BM_IO_IN_PROGRESS); } if (BUFFER_IS_BROKEN(buf2)) @@ -510,7 +509,7 @@ BufferAlloc(Relation reln, if (!(*foundPtr)) StartBufferIO(buf2, true); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); return buf2; } @@ -534,7 +533,7 @@ BufferAlloc(Relation reln, if (!BufTableDelete(buf)) { - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); elog(FATAL, "buffer wasn't in the buffer table"); } @@ -542,7 +541,7 @@ BufferAlloc(Relation reln, if (!BufTableInsert(buf)) { - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); elog(FATAL, "Buffer in lookup table twice"); } @@ -561,7 +560,7 @@ BufferAlloc(Relation reln, _bm_trace((reln->rd_rel->relisshared ? 0 : MyDatabaseId), RelationGetRelid(reln), blockNum, BufferDescriptorGetBuffer(buf), BMT_ALLOCNOTFND); #endif /* BMTRACE */ - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); return buf; } @@ -595,13 +594,13 @@ WriteBuffer(Buffer buffer) SharedBufferChanged = true; - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); Assert(bufHdr->refcount > 0); bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED); UnpinBuffer(bufHdr); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); return TRUE; } @@ -625,12 +624,12 @@ WriteNoReleaseBuffer(Buffer buffer) SharedBufferChanged = true; - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); Assert(bufHdr->refcount > 0); bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); return STATUS_OK; } @@ -639,10 +638,10 @@ WriteNoReleaseBuffer(Buffer buffer) #undef ReleaseAndReadBuffer /* * ReleaseAndReadBuffer -- combine ReleaseBuffer() and ReadBuffer() - * to save a spinlock release/acquire. + * to save a lock release/acquire. * * Also, if the passed buffer is valid and already contains the desired block - * number, we simply return it without ever acquiring the spinlock at all. + * number, we simply return it without ever acquiring the lock at all. * Since the passed buffer must be pinned, it's OK to examine its block * number without getting the lock first. * @@ -652,7 +651,7 @@ WriteNoReleaseBuffer(Buffer buffer) * * Also note: while it will work to call this routine with blockNum == P_NEW, * it's best to avoid doing so, since that would result in calling - * smgrnblocks() while holding the bufmgr spinlock, hence some loss of + * smgrnblocks() while holding the bufmgr lock, hence some loss of * concurrency. */ Buffer @@ -684,7 +683,7 @@ ReleaseAndReadBuffer(Buffer buffer, PrivateRefCount[buffer - 1]--; else { - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); UnpinBuffer(bufHdr); return ReadBufferInternal(relation, blockNum, true); } @@ -712,12 +711,11 @@ BufferSync() for (i = 0, bufHdr = BufferDescriptors; i < NBuffers; i++, bufHdr++) { - - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); if (!(bufHdr->flags & BM_VALID)) { - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); continue; } @@ -731,7 +729,7 @@ BufferSync() */ if (!(bufHdr->flags & BM_DIRTY) && !(bufHdr->cntxDirty)) { - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); continue; } @@ -741,11 +739,11 @@ BufferSync() */ if (bufHdr->flags & BM_IO_IN_PROGRESS) { - WaitIO(bufHdr, BufMgrLock); + WaitIO(bufHdr); if (!(bufHdr->flags & BM_VALID) || (!(bufHdr->flags & BM_DIRTY) && !(bufHdr->cntxDirty))) { - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); continue; } } @@ -761,7 +759,7 @@ BufferSync() buffer = BufferDescriptorGetBuffer(bufHdr); rnode = bufHdr->tag.rnode; - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); /* * Try to find relation for buffer @@ -784,10 +782,10 @@ BufferSync() * should not be able to write it while we were busy with locking * and log flushing because of we setted IO flag. */ - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); Assert(bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty); bufHdr->flags &= ~BM_JUST_DIRTIED; - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); if (reln == (Relation) NULL) { @@ -822,7 +820,7 @@ BufferSync() LockBuffer(buffer, BUFFER_LOCK_UNLOCK); BufferFlushCount++; - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); bufHdr->flags &= ~BM_IO_IN_PROGRESS; /* mark IO finished */ TerminateBufferIO(bufHdr); /* Sync IO finished */ @@ -834,7 +832,7 @@ BufferSync() if (!(bufHdr->flags & BM_JUST_DIRTIED)) bufHdr->flags &= ~BM_DIRTY; UnpinBuffer(bufHdr); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); /* drop refcnt obtained by RelationNodeCacheGetRelation */ if (reln != (Relation) NULL) @@ -846,24 +844,25 @@ BufferSync() /* * WaitIO -- Block until the IO_IN_PROGRESS flag on 'buf' is cleared. * - * Should be entered with buffer manager spinlock held; releases it before + * Should be entered with buffer manager lock held; releases it before * waiting and re-acquires it afterwards. */ static void -WaitIO(BufferDesc *buf, SPINLOCK spinlock) +WaitIO(BufferDesc *buf) { - /* * Changed to wait until there's no IO - Inoue 01/13/2000 + * + * Note this is *necessary* because an error abort in the process + * doing I/O could release the io_in_progress_lock prematurely. + * See AbortBufferIO. */ while ((buf->flags & BM_IO_IN_PROGRESS) != 0) { - SpinRelease(spinlock); - HOLD_INTERRUPTS(); /* don't want to die() holding the lock... */ - S_LOCK(&(buf->io_in_progress_lock)); - S_UNLOCK(&(buf->io_in_progress_lock)); - RESUME_INTERRUPTS(); - SpinAcquire(spinlock); + LWLockRelease(BufMgrLock); + LWLockAcquire(buf->io_in_progress_lock, LW_SHARED); + LWLockRelease(buf->io_in_progress_lock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); } } @@ -932,9 +931,9 @@ ResetBufferPool(bool isCommit) BufferDesc *buf = &BufferDescriptors[i]; PrivateRefCount[i] = 1; /* make sure we release shared pin */ - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); UnpinBuffer(buf); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); Assert(PrivateRefCount[i] == 0); } } @@ -1039,7 +1038,7 @@ BufferReplace(BufferDesc *bufHdr) /* To check if block content changed while flushing. - vadim 01/17/97 */ bufHdr->flags &= ~BM_JUST_DIRTIED; - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); /* * No need to lock buffer context - no one should be able to end @@ -1067,7 +1066,7 @@ BufferReplace(BufferDesc *bufHdr) if (reln != (Relation) NULL) RelationDecrementReferenceCount(reln); - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); if (status == SM_FAIL) return FALSE; @@ -1140,7 +1139,8 @@ DropRelationBuffers(Relation rel) return; } - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); + for (i = 1; i <= NBuffers; i++) { bufHdr = &BufferDescriptors[i - 1]; @@ -1155,7 +1155,7 @@ recheck: */ if (bufHdr->flags & BM_IO_IN_PROGRESS) { - WaitIO(bufHdr, BufMgrLock); + WaitIO(bufHdr); /* * By now, the buffer very possibly belongs to some other @@ -1189,7 +1189,7 @@ recheck: } } - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); } /* --------------------------------------------------------------------- @@ -1223,7 +1223,8 @@ DropRelFileNodeBuffers(RelFileNode rnode) } } - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); + for (i = 1; i <= NBuffers; i++) { bufHdr = &BufferDescriptors[i - 1]; @@ -1238,7 +1239,7 @@ recheck: */ if (bufHdr->flags & BM_IO_IN_PROGRESS) { - WaitIO(bufHdr, BufMgrLock); + WaitIO(bufHdr); /* * By now, the buffer very possibly belongs to some other @@ -1272,7 +1273,7 @@ recheck: } } - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); } /* --------------------------------------------------------------------- @@ -1292,7 +1293,8 @@ DropBuffers(Oid dbid) int i; BufferDesc *bufHdr; - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); + for (i = 1; i <= NBuffers; i++) { bufHdr = &BufferDescriptors[i - 1]; @@ -1313,7 +1315,7 @@ recheck: */ if (bufHdr->flags & BM_IO_IN_PROGRESS) { - WaitIO(bufHdr, BufMgrLock); + WaitIO(bufHdr); /* * By now, the buffer very possibly belongs to some other @@ -1337,7 +1339,8 @@ recheck: BufTableDelete(bufHdr); } } - SpinRelease(BufMgrLock); + + LWLockRelease(BufMgrLock); } /* ----------------------------------------------------------------- @@ -1355,7 +1358,7 @@ PrintBufferDescs() if (IsUnderPostmaster) { - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); for (i = 0; i < NBuffers; ++i, ++buf) { elog(DEBUG, "[%02d] (freeNext=%d, freePrev=%d, rel=%u/%u, \ @@ -1365,7 +1368,7 @@ blockNum=%u, flags=0x%x, refcount=%d %ld)", buf->tag.blockNum, buf->flags, buf->refcount, PrivateRefCount[i]); } - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); } else { @@ -1386,7 +1389,7 @@ PrintPinnedBufs() int i; BufferDesc *buf = BufferDescriptors; - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); for (i = 0; i < NBuffers; ++i, ++buf) { if (PrivateRefCount[i] > 0) @@ -1397,7 +1400,7 @@ blockNum=%u, flags=0x%x, refcount=%d %ld)", buf->tag.blockNum, buf->flags, buf->refcount, PrivateRefCount[i]); } - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); } /* @@ -1514,7 +1517,8 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) return 0; } - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); + for (i = 0; i < NBuffers; i++) { bufHdr = &BufferDescriptors[i]; @@ -1524,8 +1528,8 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) { PinBuffer(bufHdr); if (bufHdr->flags & BM_IO_IN_PROGRESS) - WaitIO(bufHdr, BufMgrLock); - SpinRelease(BufMgrLock); + WaitIO(bufHdr); + LWLockRelease(BufMgrLock); /* * Force XLOG flush for buffer' LSN @@ -1537,16 +1541,16 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) * Now it's safe to write buffer to disk */ - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); if (bufHdr->flags & BM_IO_IN_PROGRESS) - WaitIO(bufHdr, BufMgrLock); + WaitIO(bufHdr); if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty) { bufHdr->flags &= ~BM_JUST_DIRTIED; StartBufferIO(bufHdr, false); /* output IO start */ - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); status = smgrwrite(DEFAULT_SMGR, rel, bufHdr->tag.blockNum, @@ -1560,7 +1564,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) BufferFlushCount++; - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); bufHdr->flags &= ~BM_IO_IN_PROGRESS; TerminateBufferIO(bufHdr); Assert(!(bufHdr->flags & BM_JUST_DIRTIED)); @@ -1578,7 +1582,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) } if (!(bufHdr->flags & BM_FREE)) { - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); elog(NOTICE, "FlushRelationBuffers(%s, %u): block %u is referenced (private %ld, global %d)", RelationGetRelationName(rel), firstDelBlock, bufHdr->tag.blockNum, @@ -1589,7 +1593,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) BufTableDelete(bufHdr); } } - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); return 0; } @@ -1621,9 +1625,9 @@ ReleaseBuffer(Buffer buffer) PrivateRefCount[buffer - 1]--; else { - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); UnpinBuffer(bufHdr); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); } return STATUS_OK; @@ -1919,13 +1923,18 @@ SetBufferCommitInfoNeedsSave(Buffer buffer) if ((bufHdr->flags & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); Assert(bufHdr->refcount > 0); bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); } } +/* + * Release buffer context locks for shared buffers. + * + * Used to clean up after errors. + */ void UnlockBuffers(void) { @@ -1942,36 +1951,15 @@ UnlockBuffers(void) Assert(BufferIsValid(i + 1)); buf = &(BufferDescriptors[i]); - HOLD_INTERRUPTS(); /* don't want to die() holding the lock... */ - - S_LOCK(&(buf->cntx_lock)); - - if (buflocks & BL_R_LOCK) - { - Assert(buf->r_locks > 0); - (buf->r_locks)--; - } - if (buflocks & BL_RI_LOCK) - { - /* - * Someone else could remove our RI lock when acquiring W - * lock. This is possible if we came here from elog(ERROR) - * from IpcSemaphore{Lock|Unlock}(WaitCLSemId). And so we - * don't do Assert(buf->ri_lock) here. - */ - buf->ri_lock = false; - } - if (buflocks & BL_W_LOCK) - { - Assert(buf->w_lock); - buf->w_lock = false; - } + HOLD_INTERRUPTS(); /* don't want to die() partway through... */ - S_UNLOCK(&(buf->cntx_lock)); + /* + * The buffer's cntx_lock has already been released by lwlock.c. + */ if (buflocks & BL_PIN_COUNT_LOCK) { - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); /* * Don't complain if flag bit not set; it could have been reset * but we got a cancel/die interrupt before getting the signal. @@ -1979,7 +1967,7 @@ UnlockBuffers(void) if ((buf->flags & BM_PIN_COUNT_WAITER) != 0 && buf->wait_backend_id == MyBackendId) buf->flags &= ~BM_PIN_COUNT_WAITER; - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); ProcCancelWaitForSignal(); } @@ -1989,94 +1977,31 @@ UnlockBuffers(void) } } -/* Max time to wait to acquire a buffer read or write lock */ -#define BUFFER_LOCK_TIMEOUT (10*60*1000000) /* 10 minutes */ - +/* + * Acquire or release the cntx_lock for the buffer. + */ void LockBuffer(Buffer buffer, int mode) { BufferDesc *buf; - bits8 *buflock; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) return; buf = &(BufferDescriptors[buffer - 1]); - buflock = &(BufferLocks[buffer - 1]); - - HOLD_INTERRUPTS(); /* don't want to die() holding the lock... */ - - S_LOCK(&(buf->cntx_lock)); if (mode == BUFFER_LOCK_UNLOCK) { - if (*buflock & BL_R_LOCK) - { - Assert(buf->r_locks > 0); - Assert(!(buf->w_lock)); - Assert(!(*buflock & (BL_W_LOCK | BL_RI_LOCK))); - (buf->r_locks)--; - *buflock &= ~BL_R_LOCK; - } - else if (*buflock & BL_W_LOCK) - { - Assert(buf->w_lock); - Assert(buf->r_locks == 0); - Assert(!(*buflock & (BL_R_LOCK | BL_RI_LOCK))); - buf->w_lock = false; - *buflock &= ~BL_W_LOCK; - } - else - { - S_UNLOCK(&(buf->cntx_lock)); - RESUME_INTERRUPTS(); - elog(ERROR, "UNLockBuffer: buffer %d is not locked", buffer); - } + LWLockRelease(buf->cntx_lock); } else if (mode == BUFFER_LOCK_SHARE) { - unsigned i = 0; - - Assert(!(*buflock & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK))); - while (buf->ri_lock || buf->w_lock) - { - S_UNLOCK(&(buf->cntx_lock)); - RESUME_INTERRUPTS(); - S_LOCK_SLEEP(&(buf->cntx_lock), i++, BUFFER_LOCK_TIMEOUT); - HOLD_INTERRUPTS(); - S_LOCK(&(buf->cntx_lock)); - } - (buf->r_locks)++; - *buflock |= BL_R_LOCK; + LWLockAcquire(buf->cntx_lock, LW_SHARED); } else if (mode == BUFFER_LOCK_EXCLUSIVE) { - unsigned i = 0; - - Assert(!(*buflock & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK))); - while (buf->r_locks > 0 || buf->w_lock) - { - if (buf->r_locks > 3 || (*buflock & BL_RI_LOCK)) - { - - /* - * Our RI lock might be removed by concurrent W lock - * acquiring (see what we do with RI locks below when our - * own W acquiring succeeded) and so we set RI lock again - * if we already did this. - */ - *buflock |= BL_RI_LOCK; - buf->ri_lock = true; - } - S_UNLOCK(&(buf->cntx_lock)); - RESUME_INTERRUPTS(); - S_LOCK_SLEEP(&(buf->cntx_lock), i++, BUFFER_LOCK_TIMEOUT); - HOLD_INTERRUPTS(); - S_LOCK(&(buf->cntx_lock)); - } - buf->w_lock = true; - *buflock |= BL_W_LOCK; + LWLockAcquire(buf->cntx_lock, LW_EXCLUSIVE); /* * This is not the best place to set cntxDirty flag (eg indices do @@ -2085,27 +2010,11 @@ LockBuffer(Buffer buffer, int mode) * changes with XLogInsert() - see comments in BufferSync(). */ buf->cntxDirty = true; - - if (*buflock & BL_RI_LOCK) - { - - /* - * It's possible to remove RI locks acquired by another W - * lockers here, but they'll take care about it. - */ - buf->ri_lock = false; - *buflock &= ~BL_RI_LOCK; - } } else { - S_UNLOCK(&(buf->cntx_lock)); - RESUME_INTERRUPTS(); elog(ERROR, "LockBuffer: unknown lock mode %d", mode); } - - S_UNLOCK(&(buf->cntx_lock)); - RESUME_INTERRUPTS(); } /* @@ -2152,25 +2061,25 @@ LockBufferForCleanup(Buffer buffer) { /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); - SpinAcquire(BufMgrLock); + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); Assert(bufHdr->refcount > 0); if (bufHdr->refcount == 1) { /* Successfully acquired exclusive lock with pincount 1 */ - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); return; } /* Failed, so mark myself as waiting for pincount 1 */ if (bufHdr->flags & BM_PIN_COUNT_WAITER) { - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); elog(ERROR, "Multiple backends attempting to wait for pincount 1"); } bufHdr->wait_backend_id = MyBackendId; bufHdr->flags |= BM_PIN_COUNT_WAITER; *buflock |= BL_PIN_COUNT_LOCK; - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); /* Wait to be signaled by UnpinBuffer() */ ProcWaitForSignal(); @@ -2183,8 +2092,7 @@ LockBufferForCleanup(Buffer buffer) * Functions for IO error handling * * Note : We assume that nested buffer IO never occur. - * i.e at most one io_in_progress spinlock is held - * per proc. + * i.e at most one io_in_progress lock is held per proc. */ static BufferDesc *InProgressBuf = (BufferDesc *) NULL; static bool IsForInput; @@ -2207,18 +2115,7 @@ StartBufferIO(BufferDesc *buf, bool forInput) Assert(!(buf->flags & BM_IO_IN_PROGRESS)); buf->flags |= BM_IO_IN_PROGRESS; - /* - * There used to be - * - * Assert(S_LOCK_FREE(&(buf->io_in_progress_lock))); - * - * here, but that's wrong because of the way WaitIO works: someone else - * waiting for the I/O to complete will succeed in grabbing the lock - * for a few instructions, and if we context-swap back to here the - * Assert could fail. Tiny window for failure, but I've seen it - * happen -- tgl - */ - S_LOCK(&(buf->io_in_progress_lock)); + LWLockAcquire(buf->io_in_progress_lock, LW_EXCLUSIVE); InProgressBuf = buf; IsForInput = forInput; @@ -2238,7 +2135,7 @@ static void TerminateBufferIO(BufferDesc *buf) { Assert(buf == InProgressBuf); - S_UNLOCK(&(buf->io_in_progress_lock)); + LWLockRelease(buf->io_in_progress_lock); InProgressBuf = (BufferDesc *) 0; } @@ -2271,7 +2168,6 @@ InitBufferIO(void) /* * Clean up any active buffer I/O after an error. - * This function is called from ProcReleaseSpins(). * BufMgrLock isn't held when this function is called. * * If I/O was in progress, we always set BM_IO_ERROR. @@ -2283,7 +2179,16 @@ AbortBufferIO(void) if (buf) { - SpinAcquire(BufMgrLock); + /* + * Since LWLockReleaseAll has already been called, + * we're not holding the buffer's io_in_progress_lock. + * We have to re-acquire it so that we can use TerminateBufferIO. + * Anyone who's executing WaitIO on the buffer will be in a busy spin + * until we succeed in doing this. + */ + LWLockAcquire(buf->io_in_progress_lock, LW_EXCLUSIVE); + + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); Assert(buf->flags & BM_IO_IN_PROGRESS); if (IsForInput) Assert(!(buf->flags & BM_DIRTY) && !(buf->cntxDirty)); @@ -2302,7 +2207,7 @@ AbortBufferIO(void) buf->flags |= BM_IO_ERROR; buf->flags &= ~BM_IO_IN_PROGRESS; TerminateBufferIO(buf); - SpinRelease(BufMgrLock); + LWLockRelease(BufMgrLock); } } |