static void ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid) { VirtualTransactionId *backends; bool lock_acquired = false; int num_attempts = 0; LOCKTAG locktag; SET_LOCKTAG_RELATION(locktag, dbOid, relOid); /* * If blowing away everybody with conflicting locks doesn't work, after * the first two attempts then we just start blowing everybody away until * it does work. We do this because its likely that we either have too * many locks and we just can't get one at all, or that there are many * people crowding for the same table. Recovery must win; the end * justifies the means. */ while (!lock_acquired) { if (++num_attempts < 3) backends = GetLockConflicts(&locktag, AccessExclusiveLock); else backends = GetConflictingVirtualXIDs(InvalidTransactionId, InvalidOid); ResolveRecoveryConflictWithVirtualXIDs(backends, PROCSIG_RECOVERY_CONFLICT_LOCK); if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false) != LOCKACQUIRE_NOT_AVAIL) lock_acquired = true; } }
void ResolveRecoveryConflictWithTablespace(Oid tsid) { VirtualTransactionId *temp_file_users; /* * Standby users may be currently using this tablespace for for their * temporary files. We only care about current users because * temp_tablespace parameter will just ignore tablespaces that no longer * exist. * * Ask everybody to cancel their queries immediately so we can ensure no * temp files remain and we can remove the tablespace. Nuke the entire * site from orbit, it's the only way to be sure. * * XXX: We could work out the pids of active backends using this * tablespace by examining the temp filenames in the directory. We would * then convert the pids into VirtualXIDs before attempting to cancel * them. * * We don't wait for commit because drop tablespace is non-transactional. */ temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId, InvalidOid); ResolveRecoveryConflictWithVirtualXIDs(temp_file_users, PROCSIG_RECOVERY_CONFLICT_TABLESPACE); }
void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode node) { VirtualTransactionId *backends; /* * If we get passed InvalidTransactionId then we are a little surprised, * but it is theoretically possible, so spit out a DEBUG1 message, but not * one that needs translating. * * We grab latestCompletedXid instead because this is the very latest * value it could ever be. */ if (!TransactionIdIsValid(latestRemovedXid)) { elog(DEBUG1, "invalid latestremovexXid reported, using latestcompletedxid instead"); LWLockAcquire(ProcArrayLock, LW_SHARED); latestRemovedXid = ShmemVariableCache->latestCompletedXid; LWLockRelease(ProcArrayLock); } Assert(TransactionIdIsValid(latestRemovedXid)); backends = GetConflictingVirtualXIDs(latestRemovedXid, node.dbNode); ResolveRecoveryConflictWithVirtualXIDs(backends, PROCSIG_RECOVERY_CONFLICT_SNAPSHOT); }
void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode node) { VirtualTransactionId *backends; /* * If we get passed InvalidTransactionId then we are a little surprised, * but it is theoretically possible in normal running. It also happens * when replaying already applied WAL records after a standby crash or * restart. If latestRemovedXid is invalid then there is no conflict. That * rule applies across all record types that suffer from this conflict. */ if (!TransactionIdIsValid(latestRemovedXid)) return; backends = GetConflictingVirtualXIDs(latestRemovedXid, node.dbNode); ResolveRecoveryConflictWithVirtualXIDs(backends, PROCSIG_RECOVERY_CONFLICT_SNAPSHOT); }