From bbf99acca380543c2943c79454ac07b97fd6f2f2 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Sun, 15 Nov 2015 10:37:19 -0500 Subject: [PATCH] tranche-ify buffer locks --- src/backend/storage/buffer/buf_init.c | 22 ++++++++++-- src/backend/storage/buffer/bufmgr.c | 52 +++++++++++++-------------- src/backend/storage/lmgr/lwlock.c | 7 ++-- src/include/storage/buf_internals.h | 4 +-- src/include/storage/lwlock.h | 9 +++++ 5 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 3ae2848da0..422e8a9e31 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -20,6 +20,8 @@ BufferDescPadded *BufferDescriptors; char *BufferBlocks; +static LWLockTranche BufferContentLWLockTranche; +static LWLockTranche BufferIOLWLockTranche; /* @@ -59,7 +61,8 @@ char *BufferBlocks; * Initialize shared buffer pool * * This is called once during shared-memory initialization (either in the - * postmaster, or in a standalone backend). + * postmaster, or in a standalone backend). It is also called by a backend + * forked from the postmaster in the EXEC_BACKEND case. */ void InitBufferPool(void) @@ -110,14 +113,27 @@ InitBufferPool(void) */ buf->freeNext = i + 1; - buf->io_in_progress_lock = LWLockAssign(); - buf->content_lock = LWLockAssign(); + LWLockInitialize(&buf->io_in_progress_lock, + LWTRANCHE_BUFFER_IO_IN_PROGRESS); + LWLockInitialize(&buf->content_lock, LWTRANCHE_BUFFER_CONTENT); } /* Correct last entry of linked list */ GetBufferDescriptor(NBuffers - 1)->freeNext = FREENEXT_END_OF_LIST; } + /* Register LWLock tranches. */ + BufferContentLWLockTranche.name = "buffer_content"; + BufferContentLWLockTranche.array_base = BufferDescriptors; + BufferContentLWLockTranche.array_stride = sizeof(BufferDesc); + LWLockRegisterTranche(LWTRANCHE_BUFFER_CONTENT, + &BufferContentLWLockTranche); + BufferIOLWLockTranche.name = "buffer_io"; + BufferIOLWLockTranche.array_base = BufferDescriptors; + BufferIOLWLockTranche.array_stride = sizeof(BufferDesc); + LWLockRegisterTranche(LWTRANCHE_BUFFER_IO_IN_PROGRESS, + &BufferContentLWLockTranche); + /* Init other shared buffer-management stuff */ StrategyInitialize(!foundDescs); } diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 63188a3932..eb61f6382f 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -738,7 +738,7 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, if (!isLocalBuf) { if (mode == RBM_ZERO_AND_LOCK) - LWLockAcquire(bufHdr->content_lock, LW_EXCLUSIVE); + LWLockAcquire(&bufHdr->content_lock, LW_EXCLUSIVE); else if (mode == RBM_ZERO_AND_CLEANUP_LOCK) LockBufferForCleanup(BufferDescriptorGetBuffer(bufHdr)); } @@ -879,7 +879,7 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, if ((mode == RBM_ZERO_AND_LOCK || mode == RBM_ZERO_AND_CLEANUP_LOCK) && !isLocalBuf) { - LWLockAcquire(bufHdr->content_lock, LW_EXCLUSIVE); + LWLockAcquire(&bufHdr->content_lock, LW_EXCLUSIVE); } if (isLocalBuf) @@ -1045,7 +1045,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, * happens to be trying to split the page the first one got from * StrategyGetBuffer.) */ - if (LWLockConditionalAcquire(buf->content_lock, LW_SHARED)) + if (LWLockConditionalAcquire(&buf->content_lock, LW_SHARED)) { /* * If using a nondefault strategy, and writing the buffer @@ -1067,7 +1067,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, StrategyRejectBuffer(strategy, buf)) { /* Drop lock/pin and loop around for another buffer */ - LWLockRelease(buf->content_lock); + LWLockRelease(&buf->content_lock); UnpinBuffer(buf, true); continue; } @@ -1080,7 +1080,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, smgr->smgr_rnode.node.relNode); FlushBuffer(buf, NULL); - LWLockRelease(buf->content_lock); + LWLockRelease(&buf->content_lock); TRACE_POSTGRESQL_BUFFER_WRITE_DIRTY_DONE(forkNum, blockNum, smgr->smgr_rnode.node.spcNode, @@ -1395,7 +1395,7 @@ MarkBufferDirty(Buffer buffer) Assert(BufferIsPinned(buffer)); /* unfortunately we can't check if the lock is held exclusively */ - Assert(LWLockHeldByMe(bufHdr->content_lock)); + Assert(LWLockHeldByMe(&bufHdr->content_lock)); LockBufHdr(bufHdr); @@ -1595,8 +1595,8 @@ UnpinBuffer(BufferDesc *buf, bool fixOwner) if (ref->refcount == 0) { /* I'd better not still hold any locks on the buffer */ - Assert(!LWLockHeldByMe(buf->content_lock)); - Assert(!LWLockHeldByMe(buf->io_in_progress_lock)); + Assert(!LWLockHeldByMe(&buf->content_lock)); + Assert(!LWLockHeldByMe(&buf->io_in_progress_lock)); LockBufHdr(buf); @@ -2116,11 +2116,11 @@ SyncOneBuffer(int buf_id, bool skip_recently_used) * buffer is clean by the time we've locked it.) */ PinBuffer_Locked(bufHdr); - LWLockAcquire(bufHdr->content_lock, LW_SHARED); + LWLockAcquire(&bufHdr->content_lock, LW_SHARED); FlushBuffer(bufHdr, NULL); - LWLockRelease(bufHdr->content_lock); + LWLockRelease(&bufHdr->content_lock); UnpinBuffer(bufHdr, true); return result | BUF_WRITTEN; @@ -2926,9 +2926,9 @@ FlushRelationBuffers(Relation rel) (bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY)) { PinBuffer_Locked(bufHdr); - LWLockAcquire(bufHdr->content_lock, LW_SHARED); + LWLockAcquire(&bufHdr->content_lock, LW_SHARED); FlushBuffer(bufHdr, rel->rd_smgr); - LWLockRelease(bufHdr->content_lock); + LWLockRelease(&bufHdr->content_lock); UnpinBuffer(bufHdr, true); } else @@ -2978,9 +2978,9 @@ FlushDatabaseBuffers(Oid dbid) (bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY)) { PinBuffer_Locked(bufHdr); - LWLockAcquire(bufHdr->content_lock, LW_SHARED); + LWLockAcquire(&bufHdr->content_lock, LW_SHARED); FlushBuffer(bufHdr, NULL); - LWLockRelease(bufHdr->content_lock); + LWLockRelease(&bufHdr->content_lock); UnpinBuffer(bufHdr, true); } else @@ -3080,7 +3080,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) Assert(GetPrivateRefCount(buffer) > 0); /* here, either share or exclusive lock is OK */ - Assert(LWLockHeldByMe(bufHdr->content_lock)); + Assert(LWLockHeldByMe(&bufHdr->content_lock)); /* * This routine might get called many times on the same page, if we are @@ -3233,11 +3233,11 @@ LockBuffer(Buffer buffer, int mode) buf = GetBufferDescriptor(buffer - 1); if (mode == BUFFER_LOCK_UNLOCK) - LWLockRelease(buf->content_lock); + LWLockRelease(&buf->content_lock); else if (mode == BUFFER_LOCK_SHARE) - LWLockAcquire(buf->content_lock, LW_SHARED); + LWLockAcquire(&buf->content_lock, LW_SHARED); else if (mode == BUFFER_LOCK_EXCLUSIVE) - LWLockAcquire(buf->content_lock, LW_EXCLUSIVE); + LWLockAcquire(&buf->content_lock, LW_EXCLUSIVE); else elog(ERROR, "unrecognized buffer lock mode: %d", mode); } @@ -3258,7 +3258,7 @@ ConditionalLockBuffer(Buffer buffer) buf = GetBufferDescriptor(buffer - 1); - return LWLockConditionalAcquire(buf->content_lock, LW_EXCLUSIVE); + return LWLockConditionalAcquire(&buf->content_lock, LW_EXCLUSIVE); } /* @@ -3468,8 +3468,8 @@ WaitIO(BufferDesc *buf) UnlockBufHdr(buf); if (!(sv_flags & BM_IO_IN_PROGRESS)) break; - LWLockAcquire(buf->io_in_progress_lock, LW_SHARED); - LWLockRelease(buf->io_in_progress_lock); + LWLockAcquire(&buf->io_in_progress_lock, LW_SHARED); + LWLockRelease(&buf->io_in_progress_lock); } } @@ -3502,7 +3502,7 @@ StartBufferIO(BufferDesc *buf, bool forInput) * Grab the io_in_progress lock so that other processes can wait for * me to finish the I/O. */ - LWLockAcquire(buf->io_in_progress_lock, LW_EXCLUSIVE); + LWLockAcquire(&buf->io_in_progress_lock, LW_EXCLUSIVE); LockBufHdr(buf); @@ -3516,7 +3516,7 @@ StartBufferIO(BufferDesc *buf, bool forInput) * him to get unwedged. */ UnlockBufHdr(buf); - LWLockRelease(buf->io_in_progress_lock); + LWLockRelease(&buf->io_in_progress_lock); WaitIO(buf); } @@ -3526,7 +3526,7 @@ StartBufferIO(BufferDesc *buf, bool forInput) { /* someone else already did the I/O */ UnlockBufHdr(buf); - LWLockRelease(buf->io_in_progress_lock); + LWLockRelease(&buf->io_in_progress_lock); return false; } @@ -3574,7 +3574,7 @@ TerminateBufferIO(BufferDesc *buf, bool clear_dirty, int set_flag_bits) InProgressBuf = NULL; - LWLockRelease(buf->io_in_progress_lock); + LWLockRelease(&buf->io_in_progress_lock); } /* @@ -3599,7 +3599,7 @@ AbortBufferIO(void) * 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(&buf->io_in_progress_lock, LW_EXCLUSIVE); LockBufHdr(buf); Assert(buf->flags & BM_IO_IN_PROGRESS); diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 6bca02c5f2..43534d63c3 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -445,7 +445,7 @@ CreateLWLocks(void) /* Initialize all LWLocks in main array */ for (id = 0, lock = MainLWLockArray; id < numLocks; id++, lock++) - LWLockInitialize(&lock->lock, 0); + LWLockInitialize(&lock->lock, LWTRANCHE_MAIN); /* * Initialize the dynamic-allocation counters, which are stored just @@ -457,7 +457,7 @@ CreateLWLocks(void) LWLockCounter = (int *) ((char *) MainLWLockArray - 3 * sizeof(int)); LWLockCounter[0] = NUM_FIXED_LWLOCKS; LWLockCounter[1] = numLocks; - LWLockCounter[2] = 1; /* 0 is the main array */ + LWLockCounter[2] = LWTRANCHE_LAST_BUILTIN_ID + 1; } if (LWLockTrancheArray == NULL) @@ -466,12 +466,13 @@ CreateLWLocks(void) LWLockTrancheArray = (LWLockTranche **) MemoryContextAlloc(TopMemoryContext, LWLockTranchesAllocated * sizeof(LWLockTranche *)); + Assert(LWLockTranchesAllocated > LWTRANCHE_LAST_BUILTIN_ID); } MainLWLockTranche.name = "main"; MainLWLockTranche.array_base = MainLWLockArray; MainLWLockTranche.array_stride = sizeof(LWLockPadded); - LWLockRegisterTranche(0, &MainLWLockTranche); + LWLockRegisterTranche(LWTRANCHE_MAIN, &MainLWLockTranche); } /* diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 19247c4b2b..c64ce97579 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -147,8 +147,8 @@ typedef struct BufferDesc int buf_id; /* buffer's index number (from 0) */ int freeNext; /* link in freelist chain */ - LWLock *io_in_progress_lock; /* to wait for I/O to complete */ - LWLock *content_lock; /* to lock access to buffer contents */ + LWLock io_in_progress_lock; /* to wait for I/O to complete */ + LWLock content_lock; /* to lock access to buffer contents */ } BufferDesc; /* diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h index 4653e099b0..a5fbd20e97 100644 --- a/src/include/storage/lwlock.h +++ b/src/include/storage/lwlock.h @@ -176,6 +176,15 @@ extern int LWLockNewTrancheId(void); extern void LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche); extern void LWLockInitialize(LWLock *lock, int tranche_id); +/* + * We reserve a few predefined tranche IDs. These values will never be + * returned by LWLockNewTrancheId. + */ +#define LWTRANCHE_MAIN 0 +#define LWTRANCHE_BUFFER_CONTENT 1 +#define LWTRANCHE_BUFFER_IO_IN_PROGRESS 2 +#define LWTRANCHE_LAST_BUILTIN_ID LWTRANCHE_BUFFER_IO_IN_PROGRESS + /* * Prior to PostgreSQL 9.4, we used an enum type called LWLockId to refer * to LWLocks. New code should instead use LWLock *. However, for the -- 2.39.5