diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index d2e38f631f88b103fe4c3384fcef1670942a9117..846f59244b4b0b70d143f41798d4b1a7cadf76f3 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -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 */ diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index ccaf8420f5daf5ac0db5354a5c780f9b6f7aaf0f..01a7c2123f1534ccda836dd167e7de67bd7e713d 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -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 */ diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index 2a12a83bd08b5943465fb62dbd2d7e388b4216a5..4572f489af812a91a2e0a0933b0f5c69e6b8f3a0 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -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);