📄 lock.c
字号:
MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG)); proclocktag.lock = MAKE_OFFSET(lock); proclocktag.proc = MAKE_OFFSET(newproc); newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], (void *) &proclocktag, HASH_ENTER_NULL, &found); if (!newproclock) ereport(PANIC, /* should not happen */ (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of shared memory"), errdetail("Not enough memory for reassigning the prepared transaction's locks."))); /* * If new, initialize the new entry */ if (!found) { newproclock->holdMask = 0; newproclock->releaseMask = 0; /* Add new proclock to appropriate lists */ SHMQueueInsertBefore(&lock->procLocks, &newproclock->lockLink); SHMQueueInsertBefore(&newproc->procLocks, &newproclock->procLink); PROCLOCK_PRINT("PostPrepare_Locks: new", newproclock); } else { PROCLOCK_PRINT("PostPrepare_Locks: found", newproclock); Assert((newproclock->holdMask & ~lock->grantMask) == 0); } /* * Pass over the identified lock ownership. */ Assert((newproclock->holdMask & holdMask) == 0); newproclock->holdMask |= holdMask;next_item: proclock = nextplock; } LWLockRelease(masterLock); END_CRIT_SECTION();}/* * Estimate shared-memory space used for lock tables */SizeLockShmemSize(void){ Size size; long max_table_size = NLOCKENTS(); /* lock method headers */ size = MAX_LOCK_METHODS * MAXALIGN(sizeof(LockMethodData)); /* lockHash table */ size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK))); /* proclockHash table */ size = add_size(size, hash_estimate_size(max_table_size, sizeof(PROCLOCK))); /* * Note we count only one pair of hash tables, since the userlocks table * actually overlays the main one. * * Since the lockHash entry count above is only an estimate, add 10% * safety margin. */ size = add_size(size, size / 10); return size;}/* * GetLockStatusData - Return a summary of the lock manager's internal * status, for use in a user-level reporting function. * * The return data consists of an array of PROCLOCK objects, with the * associated PGPROC and LOCK objects for each. Note that multiple * copies of the same PGPROC and/or LOCK objects are likely to appear. * It is the caller's responsibility to match up duplicates if wanted. * * The design goal is to hold the LockMgrLock for as short a time as possible; * thus, this function simply makes a copy of the necessary data and releases * the lock, allowing the caller to contemplate and format the data for as * long as it pleases. */LockData *GetLockStatusData(void){ LockData *data; HTAB *proclockTable; PROCLOCK *proclock; HASH_SEQ_STATUS seqstat; int i; data = (LockData *) palloc(sizeof(LockData)); LWLockAcquire(LockMgrLock, LW_EXCLUSIVE); proclockTable = LockMethodProcLockHash[DEFAULT_LOCKMETHOD]; data->nelements = i = proclockTable->hctl->nentries; data->proclockaddrs = (SHMEM_OFFSET *) palloc(sizeof(SHMEM_OFFSET) * i); data->proclocks = (PROCLOCK *) palloc(sizeof(PROCLOCK) * i); data->procs = (PGPROC *) palloc(sizeof(PGPROC) * i); data->locks = (LOCK *) palloc(sizeof(LOCK) * i); hash_seq_init(&seqstat, proclockTable); i = 0; while ((proclock = hash_seq_search(&seqstat))) { PGPROC *proc = (PGPROC *) MAKE_PTR(proclock->tag.proc); LOCK *lock = (LOCK *) MAKE_PTR(proclock->tag.lock); data->proclockaddrs[i] = MAKE_OFFSET(proclock); memcpy(&(data->proclocks[i]), proclock, sizeof(PROCLOCK)); memcpy(&(data->procs[i]), proc, sizeof(PGPROC)); memcpy(&(data->locks[i]), lock, sizeof(LOCK)); i++; } LWLockRelease(LockMgrLock); Assert(i == data->nelements); return data;}/* Provide the textual name of any lock mode */const char *GetLockmodeName(LOCKMODE mode){ Assert(mode <= MAX_LOCKMODES); return lock_mode_names[mode];}#ifdef LOCK_DEBUG/* * Dump all locks in the given proc's procLocks list. * * Must have already acquired the masterLock. */voidDumpLocks(PGPROC *proc){ SHM_QUEUE *procLocks; PROCLOCK *proclock; LOCK *lock; int lockmethodid = DEFAULT_LOCKMETHOD; LockMethod lockMethodTable; if (proc == NULL) return; procLocks = &proc->procLocks; Assert(lockmethodid < NumLockMethods); lockMethodTable = LockMethods[lockmethodid]; if (!lockMethodTable) return; if (proc->waitLock) LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0); proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks, offsetof(PROCLOCK, procLink)); while (proclock) { Assert(proclock->tag.proc == MAKE_OFFSET(proc)); lock = (LOCK *) MAKE_PTR(proclock->tag.lock); PROCLOCK_PRINT("DumpLocks", proclock); LOCK_PRINT("DumpLocks", lock, 0); proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->procLink, offsetof(PROCLOCK, procLink)); }}/* * Dump all postgres locks. Must have already acquired the masterLock. */voidDumpAllLocks(void){ PGPROC *proc; PROCLOCK *proclock; LOCK *lock; int lockmethodid = DEFAULT_LOCKMETHOD; LockMethod lockMethodTable; HTAB *proclockTable; HASH_SEQ_STATUS status; proc = MyProc; if (proc == NULL) return; Assert(lockmethodid < NumLockMethods); lockMethodTable = LockMethods[lockmethodid]; if (!lockMethodTable) return; proclockTable = LockMethodProcLockHash[lockmethodid]; if (proc->waitLock) LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0); hash_seq_init(&status, proclockTable); while ((proclock = (PROCLOCK *) hash_seq_search(&status)) != NULL) { PROCLOCK_PRINT("DumpAllLocks", proclock); if (proclock->tag.lock) { lock = (LOCK *) MAKE_PTR(proclock->tag.lock); LOCK_PRINT("DumpAllLocks", lock, 0); } else elog(LOG, "DumpAllLocks: proclock->tag.lock = NULL"); }}#endif /* LOCK_DEBUG *//* * LOCK 2PC resource manager's routines *//* * Re-acquire a lock belonging to a transaction that was prepared. * * Because this function is run at db startup, re-acquiring the locks should * never conflict with running transactions because there are none. We * assume that the lock state represented by the stored 2PC files is legal. */voidlock_twophase_recover(TransactionId xid, uint16 info, void *recdata, uint32 len){ TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata; PGPROC *proc = TwoPhaseGetDummyProc(xid); LOCKTAG *locktag; LOCKMODE lockmode; LOCKMETHODID lockmethodid; LOCK *lock; PROCLOCK *proclock; PROCLOCKTAG proclocktag; bool found; LWLockId masterLock; LockMethod lockMethodTable; Assert(len == sizeof(TwoPhaseLockRecord)); locktag = &rec->locktag; lockmode = rec->lockmode; lockmethodid = locktag->locktag_lockmethodid; Assert(lockmethodid < NumLockMethods); lockMethodTable = LockMethods[lockmethodid]; if (!lockMethodTable) elog(ERROR, "unrecognized lock method: %d", lockmethodid); masterLock = lockMethodTable->masterLock; LWLockAcquire(masterLock, LW_EXCLUSIVE); /* * Find or create a lock with this tag. */ lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid], (void *) locktag, HASH_ENTER_NULL, &found); if (!lock) { LWLockRelease(masterLock); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of shared memory"), errhint("You may need to increase max_locks_per_transaction."))); } /* * if it's a new lock object, initialize it */ if (!found) { lock->grantMask = 0; lock->waitMask = 0; SHMQueueInit(&(lock->procLocks)); ProcQueueInit(&(lock->waitProcs)); lock->nRequested = 0; lock->nGranted = 0; MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES); MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES); LOCK_PRINT("lock_twophase_recover: new", lock, lockmode); } else { LOCK_PRINT("lock_twophase_recover: found", lock, lockmode); Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0)); Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0)); Assert(lock->nGranted <= lock->nRequested); } /* * Create the hash key for the proclock table. */ MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG)); /* must clear padding */ proclocktag.lock = MAKE_OFFSET(lock); proclocktag.proc = MAKE_OFFSET(proc); /* * Find or create a proclock entry with this tag */ proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], (void *) &proclocktag, HASH_ENTER_NULL, &found); if (!proclock) { /* Ooops, not enough shmem for the proclock */ if (lock->nRequested == 0) { /* * There are no other requestors of this lock, so garbage-collect * the lock object. We *must* do this to avoid a permanent leak * of shared memory, because there won't be anything to cause * anyone to release the lock object later. */ Assert(SHMQueueEmpty(&(lock->procLocks))); if (!hash_search(LockMethodLockHash[lockmethodid], (void *) &(lock->tag), HASH_REMOVE, NULL)) elog(PANIC, "lock table corrupted"); } LWLockRelease(masterLock); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of shared memory"), errhint("You may need to increase max_locks_per_transaction."))); } /* * If new, initialize the new entry */ if (!found) { proclock->holdMask = 0; proclock->releaseMask = 0; /* Add proclock to appropriate lists */ SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink); SHMQueueInsertBefore(&proc->procLocks, &proclock->procLink); PROCLOCK_PRINT("lock_twophase_recover: new", proclock); } else { PROCLOCK_PRINT("lock_twophase_recover: found", proclock); Assert((proclock->holdMask & ~lock->grantMask) == 0); } /* * lock->nRequested and lock->requested[] count the total number of * requests, whether granted or waiting, so increment those immediately. */ lock->nRequested++; lock->requested[lockmode]++; Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0)); /* * We shouldn't already hold the desired lock. */ if (proclock->holdMask & LOCKBIT_ON(lockmode)) elog(ERROR, "lock %s on object %u/%u/%u is already held", lock_mode_names[lockmode], lock->tag.locktag_field1, lock->tag.locktag_field2, lock->tag.locktag_field3); /* * We ignore any possible conflicts and just grant ourselves the lock. */ GrantLock(lock, proclock, lockmode); LWLockRelease(masterLock);}/* * 2PC processing routine for COMMIT PREPARED case. * * Find and release the lock indicated by the 2PC record. */voidlock_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len){ TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata; PGPROC *proc = TwoPhaseGetDummyProc(xid); LOCKTAG *locktag; LOCKMODE lockmode; LOCKMETHODID lockmethodid; PROCLOCKTAG proclocktag; LOCK *lock; PROCLOCK *proclock; LWLockId masterLock; LockMethod lockMethodTable; bool wakeupNeeded; Assert(len == sizeof(TwoPhaseLockRecord)); locktag = &rec->locktag; lockmode = rec->lockmode; lockmethodid = locktag->locktag_lockmethodid; Assert(lockmethodid < NumLockMethods); lockMethodTable = LockMethods[lockmethodid]; if (!lockMethodTable) elog(ERROR, "unrecognized lock method: %d", lockmethodid); masterLock = lockMethodTable->masterLock; LWLockAcquire(masterLock, LW_EXCLUSIVE); /* * Re-find the lock object (it had better be there). */ lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid], (void *) locktag, HASH_FIND, NULL); if (!lock) elog(PANIC, "failed to re-find shared lock object"); /* * Re-find the proclock object (ditto). */ MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG)); /* must clear padding */ proclocktag.lock = MAKE_OFFSET(lock); proclocktag.proc = MAKE_OFFSET(proc); proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], (void *) &proclocktag, HASH_FIND, NULL); if (!proclock) elog(PANIC, "failed to re-find shared proclock object"); /* * Double-check that we are actually holdin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -