*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.281 2010/01/10 04:26:36 rhaas Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.282 2010/01/14 11:08:00 sriggs Exp $
*
*
* INTERFACE ROUTINES
xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) XLogRecGetData(record);
if (InHotStandby)
- {
- VirtualTransactionId *backends;
-
- backends = GetConflictingVirtualXIDs(xlrec->latestRemovedXid,
- InvalidOid,
- true);
- ResolveRecoveryConflictWithVirtualXIDs(backends,
- "VACUUM index cleanup",
- CONFLICT_MODE_ERROR);
- }
+ ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid);
/*
* Actual operation is a no-op. Record type exists to provide a means
* no queries running for which the removed tuples are still visible.
*/
if (InHotStandby)
- {
- VirtualTransactionId *backends;
-
- backends = GetConflictingVirtualXIDs(xlrec->latestRemovedXid,
- InvalidOid,
- true);
- ResolveRecoveryConflictWithVirtualXIDs(backends,
- "VACUUM heap cleanup",
- CONFLICT_MODE_ERROR);
- }
+ ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid);
RestoreBkpBlocks(lsn, record, true);
* consider the frozen xids as running.
*/
if (InHotStandby)
- {
- VirtualTransactionId *backends;
-
- /*
- * XXX: Using cutoff_xid is overly conservative. Even if cutoff_xid
- * is recent enough to conflict with a backend, the actual values
- * being frozen might not be. With a typical vacuum_freeze_min_age
- * setting in the ballpark of millions of transactions, it won't make
- * a difference, but it might if you run a manual VACUUM FREEZE.
- * Typically the cutoff is much earlier than any recently deceased
- * tuple versions removed by this vacuum, so don't worry too much.
- */
- backends = GetConflictingVirtualXIDs(cutoff_xid,
- InvalidOid,
- true);
- ResolveRecoveryConflictWithVirtualXIDs(backends,
- "VACUUM heap freeze",
- CONFLICT_MODE_ERROR);
- }
+ ResolveRecoveryConflictWithSnapshot(cutoff_xid);
RestoreBkpBlocks(lsn, record, false);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.57 2010/01/02 16:57:35 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.58 2010/01/14 11:08:00 sriggs Exp $
*
*-------------------------------------------------------------------------
*/
* just once when that arrives. After that any we know that no conflicts
* exist from individual btree vacuum records on that index.
*/
- if (InHotStandby)
+ if (InHotStandby && info == XLOG_BTREE_DELETE)
{
- if (info == XLOG_BTREE_DELETE)
- {
- xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
- VirtualTransactionId *backends;
-
- /*
- * XXX Currently we put everybody on death row, because
- * currently _bt_delitems() supplies InvalidTransactionId.
- * This can be fairly painful, so providing a better value
- * here is worth some thought and possibly some effort to
- * improve.
- */
- backends = GetConflictingVirtualXIDs(xlrec->latestRemovedXid,
- InvalidOid,
- true);
+ xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
- ResolveRecoveryConflictWithVirtualXIDs(backends,
- "b-tree delete",
- CONFLICT_MODE_ERROR);
- }
+ /*
+ * XXX Currently we put everybody on death row, because
+ * currently _bt_delitems() supplies InvalidTransactionId.
+ * This can be fairly painful, so providing a better value
+ * here is worth some thought and possibly some effort to
+ * improve.
+ */
+ ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid);
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.231 2010/01/10 15:44:28 sriggs Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.232 2010/01/14 11:08:00 sriggs Exp $
*
*-------------------------------------------------------------------------
*/
dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id);
if (InHotStandby)
- {
- /*
- * 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(xlrec->db_id) > 0)
- {
- CancelDBBackends(xlrec->db_id);
-
- /*
- * Wait awhile for them to die so that we avoid flooding an
- * unresponsive backend when system is heavily loaded.
- */
- pg_usleep(10000);
- }
- }
+ ResolveRecoveryConflictWithDatabase(xlrec->db_id);
/* Drop pages for this database that are in the shared buffer cache */
DropDatabaseBuffers(xlrec->db_id);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.71 2010/01/12 02:42:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.72 2010/01/14 11:08:01 sriggs Exp $
*
*-------------------------------------------------------------------------
*/
*/
if (!destroy_tablespace_directories(xlrec->ts_id, true))
{
- 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);
+ ResolveRecoveryConflictWithTablespace(xlrec->ts_id);
/*
* If we did recovery processing then hopefully the
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
*
* We may ask for a specific cancel_mode, typically ERROR or FATAL.
*/
-void
+static void
ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
char *reason, int cancel_mode)
{
}
}
+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
{
xl_standby_lock *newlock;
LOCKTAG locktag;
- bool report_memory_error = false;
- int num_attempts = 0;
/* Already processed? */
if (TransactionIdDidCommit(xid) || TransactionIdDidAbort(xid))
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
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/standby.h,v 1.2 2010/01/02 16:58:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/standby.h,v 1.3 2010/01/14 11:08:02 sriggs Exp $
*
*-------------------------------------------------------------------------
*/
#define CONFLICT_MODE_ERROR 1 /* Conflict can be resolved by canceling query */
#define CONFLICT_MODE_FATAL 2 /* Conflict can only be resolved by disconnecting session */
-extern void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
- char *reason, int cancel_mode);
+extern void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid);
+extern void ResolveRecoveryConflictWithTablespace(Oid tsid);
+extern void ResolveRecoveryConflictWithDatabase(Oid dbid);
extern void InitRecoveryTransactionEnvironment(void);
extern void ShutdownRecoveryTransactionEnvironment(void);