diff options
Diffstat (limited to 'src/backend/storage/ipc/standby.c')
-rw-r--r-- | src/backend/storage/ipc/standby.c | 156 |
1 files changed, 121 insertions, 35 deletions
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 98a6ad6dd0b..bc9302c4bca 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.3 2010/01/02 16:57:51 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.4 2010/01/14 11:08:02 sriggs Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,9 @@ int vacuum_defer_cleanup_age; static List *RecoveryLockList; +static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, + char *reason, int cancel_mode); +static void ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid); static void LogCurrentRunningXacts(RunningTransactions CurrRunningXacts); static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks); @@ -162,7 +165,7 @@ WaitExceedsMaxStandbyDelay(void) * * We may ask for a specific cancel_mode, typically ERROR or FATAL. */ -void +static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, char *reason, int cancel_mode) { @@ -272,6 +275,119 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, } } +void +ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid) +{ + VirtualTransactionId *backends; + + backends = GetConflictingVirtualXIDs(latestRemovedXid, + InvalidOid, + true); + + ResolveRecoveryConflictWithVirtualXIDs(backends, + "snapshot conflict", + CONFLICT_MODE_ERROR); +} + +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, + false); + ResolveRecoveryConflictWithVirtualXIDs(temp_file_users, + "drop tablespace", + CONFLICT_MODE_ERROR); +} + +void +ResolveRecoveryConflictWithDatabase(Oid dbid) +{ + /* + * We don't do ResolveRecoveryConflictWithVirutalXIDs() here since + * that only waits for transactions and completely idle sessions + * would block us. This is rare enough that we do this as simply + * as possible: no wait, just force them off immediately. + * + * No locking is required here because we already acquired + * AccessExclusiveLock. Anybody trying to connect while we do this + * will block during InitPostgres() and then disconnect when they + * see the database has been removed. + */ + while (CountDBBackends(dbid) > 0) + { + CancelDBBackends(dbid); + + /* + * Wait awhile for them to die so that we avoid flooding an + * unresponsive backend when system is heavily loaded. + */ + pg_usleep(10000); + } +} + +static void +ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid) +{ + VirtualTransactionId *backends; + bool report_memory_error = false; + 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, + true); + report_memory_error = true; + } + + ResolveRecoveryConflictWithVirtualXIDs(backends, + "exclusive lock", + CONFLICT_MODE_ERROR); + + if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false) + != LOCKACQUIRE_NOT_AVAIL) + lock_acquired = true; + } +} + /* * ----------------------------------------------------- * Locking in Recovery Mode @@ -303,8 +419,6 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid) { xl_standby_lock *newlock; LOCKTAG locktag; - bool report_memory_error = false; - int num_attempts = 0; /* Already processed? */ if (TransactionIdDidCommit(xid) || TransactionIdDidAbort(xid)) @@ -323,41 +437,13 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid) RecoveryLockList = lappend(RecoveryLockList, newlock); /* - * Attempt to acquire the lock as requested. + * Attempt to acquire the lock as requested, if not resolve conflict */ SET_LOCKTAG_RELATION(locktag, newlock->dbOid, newlock->relOid); - /* - * Wait for lock to clear or kill anyone in our way. - */ - while (LockAcquireExtended(&locktag, AccessExclusiveLock, - true, true, report_memory_error) + if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false) == LOCKACQUIRE_NOT_AVAIL) - { - VirtualTransactionId *backends; - - /* - * 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. - */ - if (++num_attempts < 3) - backends = GetLockConflicts(&locktag, AccessExclusiveLock); - else - { - backends = GetConflictingVirtualXIDs(InvalidTransactionId, - InvalidOid, - true); - report_memory_error = true; - } - - ResolveRecoveryConflictWithVirtualXIDs(backends, - "exclusive lock", - CONFLICT_MODE_ERROR); - } + ResolveRecoveryConflictWithLock(newlock->dbOid, newlock->relOid); } static void |