diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 477982d..a555c91 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -319,7 +319,7 @@ MarkAsPreparing(TransactionId xid, const char *gid, gxact->proc.inCommit = false; gxact->proc.vacuumFlags = 0; gxact->proc.lwWaiting = false; - gxact->proc.lwExclusive = false; + gxact->proc.lwMode = LW_SHARED; gxact->proc.lwWaitLink = NULL; gxact->proc.waitLock = NULL; gxact->proc.waitProcLock = NULL; diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 1a48485..5b60029 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -359,7 +359,7 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) */ Assert(TransactionIdIsValid(proc->xid)); - LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + LWLockAcquire(ProcArrayLock, LW_SHARED2); proc->xid = InvalidTransactionId; proc->lxid = InvalidLocalTransactionId; diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 079eb29..8658c83 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -32,6 +32,7 @@ #include "storage/proc.h" #include "storage/spin.h" +#define LWLOCK_STATS 1 /* We use the ShmemLock spinlock to protect LWLockAssign */ extern slock_t *ShmemLock; @@ -42,7 +43,8 @@ typedef struct LWLock slock_t mutex; /* Protects LWLock and queue of PGPROCs */ bool releaseOK; /* T if ok to release waiters */ char exclusive; /* # of exclusive holders (0 or 1) */ - int shared; /* # of shared holders (0..MaxBackends) */ + int shared1; /* # of shared1 holders (0..MaxBackends) */ + int shared2; /* # of shared2 holders (0..MaxBackends) */ PGPROC *head; /* head of list of waiting PGPROCs */ PGPROC *tail; /* tail of list of waiting PGPROCs */ /* tail is undefined when head is NULL */ @@ -92,7 +94,8 @@ static bool lock_addin_request_allowed = true; #ifdef LWLOCK_STATS static int counts_for_pid = 0; -static int *sh_acquire_counts; +static int *sh1_acquire_counts; +static int *sh2_acquire_counts; static int *ex_acquire_counts; static int *block_counts; #endif @@ -104,9 +107,9 @@ inline static void PRINT_LWDEBUG(const char *where, LWLockId lockid, const volatile LWLock *lock) { if (Trace_lwlocks) - elog(LOG, "%s(%d): excl %d shared %d head %p rOK %d", + elog(LOG, "%s(%d): excl %d shared1 %d shared2 %d head %p rOK %d", where, (int) lockid, - (int) lock->exclusive, lock->shared, lock->head, + (int) lock->exclusive, lock->shared1, lock->shared2, lock->head, (int) lock->releaseOK); } @@ -135,9 +138,9 @@ print_lwlock_stats(int code, Datum arg) for (i = 0; i < numLocks; i++) { - if (sh_acquire_counts[i] || ex_acquire_counts[i] || block_counts[i]) - fprintf(stderr, "PID %d lwlock %d: shacq %u exacq %u blk %u\n", - MyProcPid, i, sh_acquire_counts[i], ex_acquire_counts[i], + if (sh1_acquire_counts[i] || sh2_acquire_counts[i] || ex_acquire_counts[i] || block_counts[i]) + fprintf(stderr, "PID %d lwlock %d: shacq1 %u shacq2 %u exacq %u blk %u\n", + MyProcPid, i, sh1_acquire_counts[i], sh2_acquire_counts[i], ex_acquire_counts[i], block_counts[i]); } @@ -268,7 +271,8 @@ CreateLWLocks(void) SpinLockInit(&lock->lock.mutex); lock->lock.releaseOK = true; lock->lock.exclusive = 0; - lock->lock.shared = 0; + lock->lock.shared1 = 0; + lock->lock.shared2 = 0; lock->lock.head = NULL; lock->lock.tail = NULL; } @@ -336,7 +340,8 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode) int *LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int)); int numLocks = LWLockCounter[1]; - sh_acquire_counts = calloc(numLocks, sizeof(int)); + sh1_acquire_counts = calloc(numLocks, sizeof(int)); + sh2_acquire_counts = calloc(numLocks, sizeof(int)); ex_acquire_counts = calloc(numLocks, sizeof(int)); block_counts = calloc(numLocks, sizeof(int)); counts_for_pid = MyProcPid; @@ -345,8 +350,10 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode) /* Count lock acquisition attempts */ if (mode == LW_EXCLUSIVE) ex_acquire_counts[lockid]++; + else if (mode == LW_SHARED) + sh1_acquire_counts[lockid]++; else - sh_acquire_counts[lockid]++; + sh2_acquire_counts[lockid]++; #endif /* LWLOCK_STATS */ /* @@ -397,7 +404,7 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode) /* If I can get the lock, do so quickly. */ if (mode == LW_EXCLUSIVE) { - if (lock->exclusive == 0 && lock->shared == 0) + if (lock->exclusive == 0 && lock->shared1 == 0 && lock->shared2 == 0) { lock->exclusive++; mustwait = false; @@ -405,11 +412,21 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode) else mustwait = true; } + else if (mode == LW_SHARED) + { + if (lock->exclusive == 0 && lock->shared2 == 0) + { + lock->shared1++; + mustwait = false; + } + else + mustwait = true; + } else { - if (lock->exclusive == 0) + if (lock->exclusive == 0 && lock->shared1 == 0) { - lock->shared++; + lock->shared2++; mustwait = false; } else @@ -430,7 +447,7 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode) elog(PANIC, "cannot wait without a PGPROC structure"); proc->lwWaiting = true; - proc->lwExclusive = (mode == LW_EXCLUSIVE); + proc->lwMode = mode; proc->lwWaitLink = NULL; if (lock->head == NULL) lock->head = proc; @@ -525,7 +542,7 @@ LWLockConditionalAcquire(LWLockId lockid, LWLockMode mode) /* If I can get the lock, do so quickly. */ if (mode == LW_EXCLUSIVE) { - if (lock->exclusive == 0 && lock->shared == 0) + if (lock->exclusive == 0 && lock->shared1 == 0 && lock->shared2 == 0) { lock->exclusive++; mustwait = false; @@ -533,11 +550,21 @@ LWLockConditionalAcquire(LWLockId lockid, LWLockMode mode) else mustwait = true; } + else if (mode == LW_SHARED) + { + if (lock->exclusive == 0 && lock->shared2 == 0) + { + lock->shared1++; + mustwait = false; + } + else + mustwait = true; + } else { - if (lock->exclusive == 0) + if (lock->exclusive == 0 && lock->shared1 == 0) { - lock->shared++; + lock->shared2++; mustwait = false; } else @@ -598,10 +625,12 @@ LWLockRelease(LWLockId lockid) /* Release my hold on lock */ if (lock->exclusive > 0) lock->exclusive--; + else if (lock->shared1 > 0) + lock->shared1--; else { - Assert(lock->shared > 0); - lock->shared--; + Assert(lock->shared2 > 0); + lock->shared2--; } /* @@ -613,7 +642,8 @@ LWLockRelease(LWLockId lockid) head = lock->head; if (head != NULL) { - if (lock->exclusive == 0 && lock->shared == 0 && lock->releaseOK) + if (lock->exclusive == 0 && lock->shared1 == 0 && lock->shared2 == 0 + && lock->releaseOK) { /* * Remove the to-be-awakened PGPROCs from the queue. If the front @@ -621,10 +651,12 @@ LWLockRelease(LWLockId lockid) * as many waiters as want shared access. */ proc = head; - if (!proc->lwExclusive) + if (proc->lwMode != LW_EXCLUSIVE) { + LWLockMode wake_mode = proc->lwMode; + while (proc->lwWaitLink != NULL && - !proc->lwWaitLink->lwExclusive) + proc->lwWaitLink->lwMode == wake_mode) proc = proc->lwWaitLink; } /* proc is now the last PGPROC to be released */ diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index eda3a98..be48a47 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -326,7 +326,7 @@ InitProcess(void) if (IsAutoVacuumWorkerProcess()) MyProc->vacuumFlags |= PROC_IS_AUTOVACUUM; MyProc->lwWaiting = false; - MyProc->lwExclusive = false; + MyProc->lwMode = LW_SHARED; MyProc->lwWaitLink = NULL; MyProc->waitLock = NULL; MyProc->waitProcLock = NULL; @@ -480,7 +480,7 @@ InitAuxiliaryProcess(void) MyProc->inCommit = false; MyProc->vacuumFlags = 0; MyProc->lwWaiting = false; - MyProc->lwExclusive = false; + MyProc->lwMode = LW_SHARED; MyProc->lwWaitLink = NULL; MyProc->waitLock = NULL; MyProc->waitProcLock = NULL; diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h index 438a48d..3b1c1c0 100644 --- a/src/include/storage/lwlock.h +++ b/src/include/storage/lwlock.h @@ -94,7 +94,8 @@ typedef enum LWLockId typedef enum LWLockMode { LW_EXCLUSIVE, - LW_SHARED + LW_SHARED, + LW_SHARED2 } LWLockMode; diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 6e798b1..d4220a7 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -116,7 +116,7 @@ struct PGPROC /* Info about LWLock the process is currently waiting for, if any. */ bool lwWaiting; /* true if waiting for an LW lock */ - bool lwExclusive; /* true if waiting for exclusive access */ + LWLockMode lwMode; /* mode we're waiting for */ struct PGPROC *lwWaitLink; /* next waiter for same LW lock */ /* Info about lock the process is currently waiting for, if any. */