/* * update hash entry with state */ static int FaultInjector_UpdateHashEntry( FaultInjectorEntry_s *entry) { FaultInjectorEntry_s *entryLocal; bool exists; int status = STATUS_OK; LockAcquire(); entryLocal = FaultInjector_InsertHashEntry(entry->faultInjectorIdentifier, &exists); /* entry should be found since fault has not been injected yet */ Assert(entryLocal != NULL); if (!exists) { LockRelease(); status = STATUS_ERROR; ereport(WARNING, (errmsg("could not update fault injection hash entry with fault injection status, " "no entry found, " "fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[entry->faultInjectorIdentifier], FaultInjectorTypeEnumToString[entry->faultInjectorType]))); goto exit; } if (entry->faultInjectorType == FaultInjectorTypeResume) { entryLocal->faultInjectorType = FaultInjectorTypeResume; } else { entryLocal->faultInjectorState = entry->faultInjectorState; entryLocal->occurrence = entry->occurrence; } LockRelease(); ereport(DEBUG1, (errmsg("LOG(fault injector): update fault injection hash entry " "identifier:'%s' state:'%s' occurrence:'%d' ", FaultInjectorIdentifierEnumToString[entry->faultInjectorIdentifier], FaultInjectorStateEnumToString[entryLocal->faultInjectorState], entry->occurrence))); exit: return status; }
/* * XactLockTableWait * * Wait for the specified transaction to commit or abort. */ void XactLockTableWait(TransactionId xid) { LOCKTAG tag; TransactionId myxid = GetCurrentTransactionId(); Assert(!TransactionIdEquals(xid, myxid)); MemSet(&tag, 0, sizeof(tag)); tag.relId = XactLockTableId; tag.dbId = InvalidOid; tag.objId.xid = xid; if (!LockAcquire(LockTableId, &tag, myxid, ShareLock, false)) elog(ERROR, "LockAcquire failed"); LockRelease(LockTableId, &tag, myxid, ShareLock); /* * Transaction was committed/aborted/crashed - we have to update * pg_clog if transaction is still marked as running. */ if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid)) TransactionIdAbort(xid); }
//--------------------------------------------------------------------------- // CondHandleWait // // This function makes the calling process block on the condition variable // till either ConditionHandleSignal or ConditionHandleBroadcast is // received. The process calling CondHandleWait must have acquired the // lock associated with the condition variable (the lock that was passed // to CondCreate. This implies the lock handle needs to be stored // somewhere. hint! hint!) for this function to // succeed. If the calling process has not acquired the lock, it does not // block on the condition variable, but a value of 1 is returned // indicating that the call was not successful. Return value of 0 implies // that the call was successful. // // This function should be written in such a way that the calling process // should release the lock associated with this condition variable before // going to sleep, so that the process that intends to signal this // process could acquire the lock for that purpose. After waking up, the // blocked process should acquire (i.e. wait on) the lock associated with // the condition variable. In other words, this process does not // "actually" wake up until the process calling CondHandleSignal or // CondHandleBroadcast releases the lock explicitly. //--------------------------------------------------------------------------- int CondWait(Cond *c) { Link *l; int intrval; if (!c) return SYNC_FAIL; // Conds are atomic intrval = DisableIntrs (); dbprintf ('I', "CondWait: Old interrupt value was 0x%x.\n", intrval); // Check to see if the current process owns the lock if (c->lock->pid != GetCurrentPid()) { dbprintf('s', "CondWait: Proc %d does not own cond %d\n", GetCurrentPid(), (int)(c-conds)); RestoreIntrs(intrval); return SYNC_FAIL; } dbprintf ('s', "CondWait: Proc %d waiting on cond %d. Putting to sleep.\n", GetCurrentPid(), (int)(c-conds)); if ((l = AQueueAllocLink ((void *)currentPCB)) == NULL) { printf("FATAL ERROR: could not allocate link for cond queue in CondWait!\n"); exitsim(); } if (AQueueInsertLast (&c->waiting, l) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not insert new link into cond waiting queue in CondWait!\n"); exitsim(); } // Release the lock before going to sleep LockRelease(c->lock); RestoreIntrs(intrval); // Don't want interrupts disabled while we sleep ProcessSleep(); // Immediately acquire the lock upon waking LockAcquire(c->lock); return SYNC_SUCCESS; }
bool FaultInjector_IsFaultInjected( FaultInjectorIdentifier_e identifier) { FaultInjectorEntry_s *entry = NULL; bool isCompleted = FALSE; bool retval = FALSE; bool isRemoved; LockAcquire(); entry = FaultInjector_LookupHashEntry(identifier); if (entry == NULL) { retval = TRUE; isCompleted = TRUE; goto exit; } switch (entry->faultInjectorState) { case FaultInjectorStateWaiting: /* No operation */ break; case FaultInjectorStateTriggered: /* No operation */ break; case FaultInjectorStateCompleted: retval = TRUE; /* NO break */ case FaultInjectorStateFailed: isCompleted = TRUE; isRemoved = FaultInjector_RemoveHashEntry(identifier); if (isRemoved == FALSE) { ereport(DEBUG1, (errmsg("LOG(fault injector): could not remove fault injection from hash" "identifier:'%s' ", FaultInjectorIdentifierEnumToString[identifier]))); } else { faultInjectorShmem->faultInjectorSlots--; } break; default: Assert(0); } exit: LockRelease(); if ((isCompleted == TRUE) && (retval == FALSE)) { ereport(WARNING, (errmsg("could not complete fault injection, fault name:'%s' fault type:'%s' ", FaultInjectorIdentifierEnumToString[identifier], FaultInjectorTypeEnumToString[entry->faultInjectorType]))); } return isCompleted; }
/* * XactLockTableDelete * * Delete the lock showing that the given transaction ID is running. * (This is never used for main transaction IDs; those locks are only * released implicitly at transaction end. But we do use it for subtrans IDs.) */ void XactLockTableDelete(TransactionId xid) { LOCKTAG tag; SET_LOCKTAG_TRANSACTION(tag, xid); LockRelease(&tag, ExclusiveLock, false); }
/* * UnlockRelationOid * * Unlock, given only a relation Oid. Use UnlockRelationId if you can. */ void UnlockRelationOid(Oid relid, LOCKMODE lockmode) { LOCKTAG tag; SetLocktagRelationOid(&tag, relid); LockRelease(&tag, lockmode, false); }
/* * UnlockRelationIdForSession */ void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode) { LOCKTAG tag; SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId); LockRelease(&tag, lockmode, true); }
/* * SpeculativeInsertionLockRelease * * Delete the lock showing that the given transaction is speculatively * inserting a tuple. */ void SpeculativeInsertionLockRelease(TransactionId xid) { LOCKTAG tag; SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken); LockRelease(&tag, ExclusiveLock, false); }
/* Releases the lock associated with the relay file fetching/DML task. */ void UnlockShardResource(uint64 shardId, LOCKMODE lockmode) { LOCKTAG tag; const bool sessionLock = false; SET_LOCKTAG_SHARD_RESOURCE(tag, MyDatabaseId, shardId); LockRelease(&tag, lockmode, sessionLock); }
/* Releases the lock for resources associated with the given job id. */ void UnlockJobResource(uint64 jobId, LOCKMODE lockmode) { LOCKTAG tag; const bool sessionLock = false; SET_LOCKTAG_JOB_RESOURCE(tag, MyDatabaseId, jobId); LockRelease(&tag, lockmode, sessionLock); }
/* * VirtualXactLockTableDelete * * Release a Virtual Transaction lock. Only called by Startup process * at end of Hot Standby. */ void VirtualXactLockTableDelete(VirtualTransactionId vxid) { LOCKTAG tag; Assert(VirtualTransactionIdIsValid(vxid)); SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid); (void) LockRelease(&tag, ExclusiveLock, false); }
/* * UnlockRelationForExtension */ void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode) { LOCKTAG tag; SET_LOCKTAG_RELATION_EXTEND(tag, relation->rd_lockInfo.lockRelId.dbId, relation->rd_lockInfo.lockRelId.relId); LockRelease(&tag, lockmode, false); }
void UnlockRelationForResynchronize(RelFileNode *relFileNode, LOCKMODE lockmode) { LOCKTAG tag; SET_LOCKTAG_RELATION_RESYNCHRONIZE(tag, relFileNode->dbNode, relFileNode->relNode); LockRelease(&tag, lockmode, false); }
/* * Separate routine for UnlockRelationForExtension() because resync workers do not have relation. */ void UnlockRelationForResyncExtension(RelFileNode *relFileNode, LOCKMODE lockmode) { LOCKTAG tag; SET_LOCKTAG_RELATION_EXTEND(tag, relFileNode->dbNode, relFileNode->relNode); LockRelease(&tag, lockmode, false); }
/* * UnlockPage */ void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode) { LOCKTAG tag; MemSet(&tag, 0, sizeof(tag)); tag.relId = relation->rd_lockInfo.lockRelId.relId; tag.dbId = relation->rd_lockInfo.lockRelId.dbId; tag.objId.blkno = blkno; LockRelease(LockTableId, &tag, GetCurrentTransactionId(), lockmode); }
/* * UnlockRelationForSession */ void UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode) { LOCKTAG tag; MemSet(&tag, 0, sizeof(tag)); tag.relId = relid->relId; tag.dbId = relid->dbId; tag.objId.blkno = InvalidBlockNumber; LockRelease(LockTableId, &tag, InvalidTransactionId, lockmode); }
void UnlockRelationAppendOnlySegmentFile(RelFileNode *relFileNode, int32 segno, LOCKMODE lockmode) { LOCKTAG tag; SET_LOCKTAG_RELATION_APPENDONLY_SEGMENT_FILE(tag, relFileNode->dbNode, relFileNode->relNode, segno); LockRelease(&tag, lockmode, false); }
/* * UnlockPage */ void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode) { LOCKTAG tag; SET_LOCKTAG_PAGE(tag, relation->rd_lockInfo.lockRelId.dbId, relation->rd_lockInfo.lockRelId.relId, blkno); LockRelease(&tag, lockmode, false); }
/* * UnlockTuple */ void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode) { LOCKTAG tag; SET_LOCKTAG_TUPLE(tag, relation->rd_lockInfo.lockRelId.dbId, relation->rd_lockInfo.lockRelId.relId, ItemPointerGetBlockNumber(tid), ItemPointerGetOffsetNumber(tid)); LockRelease(&tag, lockmode, false); }
/* * VirtualXactLockTableWait * * Waits until the lock on the given VXID is released, which shows that * the top-level transaction owning the VXID has ended. */ void VirtualXactLockTableWait(VirtualTransactionId vxid) { LOCKTAG tag; Assert(VirtualTransactionIdIsValid(vxid)); SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid); (void) LockAcquire(&tag, ShareLock, false, false); LockRelease(&tag, ShareLock, false); }
/* * pg_advisory_unlock_shared(int8) - release share lock on an int8 key * * Returns true if successful, false if lock was not held */ Datum pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS) { int64 key = PG_GETARG_INT64(0); LOCKTAG tag; bool res; SET_LOCKTAG_INT64(tag, key); res = LockRelease(&tag, ShareLock, true); PG_RETURN_BOOL(res); }
/* * SpeculativeInsertionWait * * Wait for the specified transaction to finish or abort the insertion of a * tuple. */ void SpeculativeInsertionWait(TransactionId xid, uint32 token) { LOCKTAG tag; SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, token); Assert(TransactionIdIsValid(xid)); Assert(token != 0); (void) LockAcquire(&tag, ShareLock, false, false); LockRelease(&tag, ShareLock, false); }
/* * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys * * Returns true if successful, false if lock was not held */ Datum pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS) { int32 key1 = PG_GETARG_INT32(0); int32 key2 = PG_GETARG_INT32(1); LOCKTAG tag; bool res; SET_LOCKTAG_INT32(tag, key1, key2); res = LockRelease(&tag, ShareLock, true); PG_RETURN_BOOL(res); }
/* * UnlockSharedObjectForSession */ void UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode) { LOCKTAG tag; SET_LOCKTAG_OBJECT(tag, InvalidOid, classid, objid, objsubid); LockRelease(&tag, lockmode, true); }
/* * pg_advisory_unlock(int8) - release exclusive lock on an int8 key * * Returns true if successful, false if lock was not held */ Datum pg_advisory_unlock_int8(PG_FUNCTION_ARGS) { int64 key = PG_GETARG_INT64(0); LOCKTAG tag; bool res; PreventAdvisoryLocksInParallelMode(); SET_LOCKTAG_INT64(tag, key); res = LockRelease(&tag, ExclusiveLock, true); PG_RETURN_BOOL(res); }
/* * UnlockDatabaseObject */ void UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode) { LOCKTAG tag; SET_LOCKTAG_OBJECT(tag, MyDatabaseId, classid, objid, objsubid); LockRelease(&tag, lockmode, false); }
/* * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys * * Returns true if successful, false if lock was not held */ Datum pg_advisory_unlock_int4(PG_FUNCTION_ARGS) { int32 key1 = PG_GETARG_INT32(0); int32 key2 = PG_GETARG_INT32(1); LOCKTAG tag; bool res; PreventAdvisoryLocksInParallelMode(); SET_LOCKTAG_INT32(tag, key1, key2); res = LockRelease(&tag, ExclusiveLock, true); PG_RETURN_BOOL(res); }
/* * ConditionalVirtualXactLockTableWait * * As above, but only lock if we can get the lock without blocking. * Returns TRUE if the lock was acquired. */ bool ConditionalVirtualXactLockTableWait(VirtualTransactionId vxid) { LOCKTAG tag; Assert(VirtualTransactionIdIsValid(vxid)); SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid); if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL) return false; LockRelease(&tag, ShareLock, false); return true; }
/* * XactLockTableWait * * Wait for the specified transaction to commit or abort. If an operation * is specified, an error context callback is set up. If 'oper' is passed as * None, no error context callback is set up. * * Note that this does the right thing for subtransactions: if we wait on a * subtransaction, we will exit as soon as it aborts or its top parent commits. * It takes some extra work to ensure this, because to save on shared memory * the XID lock of a subtransaction is released when it ends, whether * successfully or unsuccessfully. So we have to check if it's "still running" * and if so wait for its parent. */ void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper) { LOCKTAG tag; XactLockTableWaitInfo info; ErrorContextCallback callback; /* * If an operation is specified, set up our verbose error context * callback. */ if (oper != XLTW_None) { Assert(RelationIsValid(rel)); Assert(ItemPointerIsValid(ctid)); info.rel = rel; info.ctid = ctid; info.oper = oper; callback.callback = XactLockTableWaitErrorCb; callback.arg = &info; callback.previous = error_context_stack; error_context_stack = &callback; } for (;;) { Assert(TransactionIdIsValid(xid)); Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny())); SET_LOCKTAG_TRANSACTION(tag, xid); (void) LockAcquire(&tag, ShareLock, false, false); LockRelease(&tag, ShareLock, false); if (!TransactionIdIsInProgress(xid)) break; xid = SubTransGetParent(xid); } if (oper != XLTW_None) error_context_stack = callback.previous; }
/* * XactLockTableWait * * Wait for the specified transaction to commit or abort. * * Note that this does the right thing for subtransactions: if we wait on a * subtransaction, we will exit as soon as it aborts or its top parent commits. * It takes some extra work to ensure this, because to save on shared memory * the XID lock of a subtransaction is released when it ends, whether * successfully or unsuccessfully. So we have to check if it's "still running" * and if so wait for its parent. */ void XactLockTableWait(TransactionId xid) { LOCKTAG tag; for (;;) { Assert(TransactionIdIsValid(xid)); Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny())); SET_LOCKTAG_TRANSACTION(tag, xid); (void) LockAcquire(&tag, ShareLock, false, false); LockRelease(&tag, ShareLock, false); if (!TransactionIdIsInProgress(xid)) break; xid = SubTransGetParent(xid); } }