During Hot Standby, fix drop database when sessions idle.
authorSimon Riggs <simon@2ndQuadrant.com>
Sun, 10 Jan 2010 15:44:28 +0000 (15:44 +0000)
committerSimon Riggs <simon@2ndQuadrant.com>
Sun, 10 Jan 2010 15:44:28 +0000 (15:44 +0000)
Previously we only cancelled sessions that were in-transaction.

Simple fix is to just cancel all sessions without waiting. Doing
it this way avoids complicating common code paths, which would
not be worth the trouble to cover this rare case.

Problem report and fix by Andres Freund, edited somewhat by me

src/backend/commands/dbcommands.c
src/backend/storage/ipc/procarray.c
src/include/storage/procarray.h

index d2e38f631f88b103fe4c3384fcef1670942a9117..846f59244b4b0b70d143f41798d4b1a7cadf76f3 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.230 2010/01/02 16:57:37 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.231 2010/01/10 15:44:28 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1945,22 +1945,27 @@ dbase_redo(XLogRecPtr lsn, XLogRecord *record)
 
                if (InHotStandby)
                {
-                       VirtualTransactionId *database_users;
-
                        /*
-                        * Find all users connected to this database and ask them
-                        * politely to immediately kill their sessions before processing
-                        * the drop database record, after the usual grace period.
-                        * We don't wait for commit because drop database is
-                        * non-transactional.
+                        * 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.
                         */
-                   database_users = GetConflictingVirtualXIDs(InvalidTransactionId,
-                                                                                                          xlrec->db_id,
-                                                                                                          false);
+                       while (CountDBBackends(xlrec->db_id) > 0)
+                       {
+                               CancelDBBackends(xlrec->db_id);
 
-                       ResolveRecoveryConflictWithVirtualXIDs(database_users,
-                                                                                                  "drop database",
-                                                                                                  CONFLICT_MODE_FATAL);
+                               /*
+                                * Wait awhile for them to die so that we avoid flooding an
+                                * unresponsive backend when system is heavily loaded.
+                                */
+                               pg_usleep(10000);
+                       }
                }
 
                /* Drop pages for this database that are in the shared buffer cache */
index ccaf8420f5daf5ac0db5354a5c780f9b6f7aaf0f..01a7c2123f1534ccda836dd167e7de67bd7e713d 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.54 2010/01/02 16:57:51 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.55 2010/01/10 15:44:28 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1826,6 +1826,32 @@ CountDBBackends(Oid databaseid)
        return count;
 }
 
+/*
+ * CancelDBBackends --- cancel backends that are using specified database
+ */
+void
+CancelDBBackends(Oid databaseid)
+{
+       ProcArrayStruct *arrayP = procArray;
+       int                     index;
+
+       /* tell all backends to die */
+       LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+
+       for (index = 0; index < arrayP->numProcs; index++)
+       {
+               volatile PGPROC *proc = arrayP->procs[index];
+
+               if (proc->databaseId == databaseid)
+               {
+                       proc->recoveryConflictMode = CONFLICT_MODE_FATAL;
+                       kill(proc->pid, SIGINT);
+               }
+       }
+
+       LWLockRelease(ProcArrayLock);
+}
+
 /*
  * CountUserBackends --- count backends that are used by specified user
  */
index 2a12a83bd08b5943465fb62dbd2d7e388b4216a5..4572f489af812a91a2e0a0933b0f5c69e6b8f3a0 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/procarray.h,v 1.28 2010/01/02 16:58:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.29 2010/01/10 15:44:28 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,6 +63,7 @@ extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid,
 
 extern int     CountActiveBackends(void);
 extern int     CountDBBackends(Oid databaseid);
+extern void    CancelDBBackends(Oid databaseid);
 extern int     CountUserBackends(Oid roleid);
 extern bool CountOtherDBBackends(Oid databaseId,
                                         int *nbackends, int *nprepared);