]> granicus.if.org Git - postgresql/commitdiff
First part of refactoring of code for ResolveRecoveryConflict. Purposes
authorSimon Riggs <simon@2ndQuadrant.com>
Thu, 14 Jan 2010 11:08:02 +0000 (11:08 +0000)
committerSimon Riggs <simon@2ndQuadrant.com>
Thu, 14 Jan 2010 11:08:02 +0000 (11:08 +0000)
of this are to centralise the conflict code to allow further change,
as well as to allow passing through the full reason for the conflict
through to the conflicting backends. Backend state alters how we
can handle different types of conflict so this is now required.
As originally suggested by Heikki, no longer optional.

src/backend/access/heap/heapam.c
src/backend/access/nbtree/nbtxlog.c
src/backend/commands/dbcommands.c
src/backend/commands/tablespace.c
src/backend/storage/ipc/standby.c
src/include/storage/standby.h

index de061279a14d1f2f81d5280511cf1fc562da7d73..5cd4f005c6544a8a74208839d58c5cb779cf4a0d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -4139,16 +4139,7 @@ heap_xlog_cleanup_info(XLogRecPtr lsn, XLogRecord *record)
        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
@@ -4180,16 +4171,7 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record, bool clean_move)
         * 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);
 
@@ -4259,25 +4241,7 @@ heap_xlog_freeze(XLogRecPtr lsn, XLogRecord *record)
         * 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);
 
index 55f05bdc2c9f1f0a280033d3a9fa61f7899f2db5..9e2ebd9a9f5fd70e3da06ebb515d9c2328c39cc9 100644 (file)
@@ -8,7 +8,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -822,28 +822,18 @@ btree_redo(XLogRecPtr lsn, XLogRecord *record)
         * 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);
        }
 
        /*
index 846f59244b4b0b70d143f41798d4b1a7cadf76f3..a45b351dd54ecd2d505073900ca7bb6c47266118 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1944,29 +1944,7 @@ dbase_redo(XLogRecPtr lsn, XLogRecord *record)
                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);
index 1eaa0abeea2e6d2689a71982546a6ffda4519d52..2ff3835ab0f370d3e94efd2044ff8b4fdb13969d 100644 (file)
@@ -40,7 +40,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1377,33 +1377,7 @@ tblspc_redo(XLogRecPtr lsn, XLogRecord *record)
                 */
                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
index 98a6ad6dd0bb4274bb8d3f433d3489c65fc0b293..bc9302c4bca5a0a53286a18f25873d517b569d2b 100644 (file)
@@ -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
index a58d666f0de48d94cfaa76be1e784bab5855e064..3f2e2c2d85587fdd2701428d5aadcfb42a2aa977 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,8 +24,9 @@ extern int    vacuum_defer_cleanup_age;
 #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);