diff options
-rw-r--r-- | src/backend/access/transam/parallel.c | 32 | ||||
-rw-r--r-- | src/backend/storage/lmgr/lock.c | 45 | ||||
-rw-r--r-- | src/include/storage/lock.h | 3 |
3 files changed, 79 insertions, 1 deletions
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index 3915750419..31b23a785b 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -807,6 +807,33 @@ HandleParallelMessage(ParallelContext *pcxt, int i, StringInfo msg) break; } + case 'L': /* Lock information */ + { + int i; + + Assert(msg->len > 1 && (msg->len % sizeof(LOCALLOCKTAG)) == 1); + + for (i = 1; i < msg->len; i += sizeof(LOCALLOCKTAG)) + { + LOCALLOCKTAG locallocktag; + + memcpy((char *) &locallocktag, &msg->data[i], sizeof(LOCALLOCKTAG)); + /* XXX. Now what? */ +#if 0 + ereport(NOTICE, + (errmsg("worker has lock %u/%u/%u/%u type %u method %u mode %u", + locallocktag.lock.locktag_field1, + locallocktag.lock.locktag_field2, + locallocktag.lock.locktag_field3, + locallocktag.lock.locktag_field4, + locallocktag.lock.locktag_type, + locallocktag.lock.locktag_lockmethodid, + locallocktag.mode))); +#endif + } + break; + } + case 'X': /* Terminate, indicating clean exit */ { pfree(pcxt->worker[i].error_mqh); @@ -1038,6 +1065,11 @@ ParallelWorkerMain(Datum main_arg) /* Must pop active snapshot so resowner.c doesn't complain. */ PopActiveSnapshot(); + /* Send a message to the leader with the heavyweight locks we still retain. */ + pq_beginmessage(&msgbuf, 'L'); + if (GetMyLocks(&msgbuf) != 0) + pq_endmessage(&msgbuf); + /* Shut down the parallel-worker transaction. */ EndParallelWorkerTransaction(); diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 7c7f250878..c308531ff1 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -707,7 +707,6 @@ LockAcquireExtended(const LOCKTAG *locktag, lockMethodTable = LockMethods[lockmethodid]; if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes) elog(ERROR, "unrecognized lock mode: %d", lockmode); - Assert(!IsInParallelMode() || MyProc->lockGroupLeader != NULL); if (RecoveryInProgress() && !InRecovery && (locktag->locktag_type == LOCKTAG_OBJECT || @@ -3538,6 +3537,50 @@ GetLockStatusData(void) } /* + * GetMyLocks -- Write all locks we hold into the provided StringInfo. + * + * For each lock, we write the LOCKTAG and LOCKMODE, a concept conveniently + * encapsulated by the LOCALLOCKTAG data type. + * + * We return the number of locks written. + */ +int +GetMyLocks(StringInfo buf) +{ + HASH_SEQ_STATUS status; + LOCALLOCK *locallock; + int count = 0; + + /* + * We choose to implement this by iterating over the local lock table. + * This carries the intrinsic risk that if any our lock management code + * is buggy, we might enumerate a different set of locks here than the + * shared lock table believes we actually hold. We could eliminate that + * risk by doing this based on the shared memory data structures rather + * than our local bookkeeping, but that would require acquiring every lock + * manager partition lock in turn. We prefer to minimize contention. + */ + hash_seq_init(&status, LockMethodLocalHash); + + while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) + { + /* + * Normally we remove entries from the hash table when nLocks == 0, + * but not if we run out of shared memory while setting up the lock. + * Skip any such unheld locks. + */ + if (locallock->nLocks == 0) + continue; + + appendBinaryStringInfo(buf, (char *) &locallock->tag, + sizeof(LOCALLOCKTAG)); + ++count; + } + + return count; +} + +/* * Returns a list of currently held AccessExclusiveLocks, for use by * LogStandbySnapshot(). The result is a palloc'd array, * with the number of elements returned into *nlocks. diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 6b4e3655f8..e54c613929 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -23,6 +23,8 @@ #include "storage/lwlock.h" #include "storage/shmem.h" +/* avoid including lib/stringinfo.h */ +struct StringInfoData; /* struct PGPROC is declared in proc.h, but must forward-reference it */ typedef struct PGPROC PGPROC; @@ -520,6 +522,7 @@ extern void GrantAwaitedLock(void); extern void RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode); extern Size LockShmemSize(void); extern LockData *GetLockStatusData(void); +extern int GetMyLocks(struct StringInfoData *buf); extern xl_standby_lock *GetRunningTransactionLocks(int *nlocks); extern const char *GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode); |