1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Make CREATE/DROP/RENAME DATABASE wait a little bit to see if other backends

will exit before failing because of conflicting DB usage.  Per discussion,
this seems a good idea to help mask the fact that backend exit takes nonzero
time.  Remove a couple of thereby-obsoleted sleeps in contrib and PL
regression test sequences.
This commit is contained in:
Tom Lane
2007-06-01 19:38:07 +00:00
parent 41ef1c0f32
commit bd0a260928
5 changed files with 141 additions and 108 deletions

View File

@ -23,7 +23,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.24 2007/04/03 16:34:36 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.25 2007/06/01 19:38:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -683,62 +683,6 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
return snapshot;
}
/*
* DatabaseCancelAutovacuumActivity -- are there any backends running in the
* given DB, apart from autovacuum? If an autovacuum process is running on the
* database, kill it and restart the counting.
*
* If 'ignoreMyself' is TRUE, ignore this particular backend while checking
* for backends in the target database.
*
* This function is used to interlock DROP DATABASE against there being
* any active backends in the target DB --- dropping the DB while active
* backends remain would be a Bad Thing. Note that we cannot detect here
* the possibility of a newly-started backend that is trying to connect
* to the doomed database, so additional interlocking is needed during
* backend startup.
*/
bool
DatabaseCancelAutovacuumActivity(Oid databaseId, bool ignoreMyself)
{
ProcArrayStruct *arrayP = procArray;
int index;
int num;
restart:
num = 0;
CHECK_FOR_INTERRUPTS();
LWLockAcquire(ProcArrayLock, LW_SHARED);
for (index = 0; index < arrayP->numProcs; index++)
{
PGPROC *proc = arrayP->procs[index];
if (proc->databaseId == databaseId)
{
if (ignoreMyself && proc == MyProc)
continue;
num++;
if (proc->isAutovacuum)
{
/* an autovacuum -- kill it and restart */
LWLockRelease(ProcArrayLock);
kill(proc->pid, SIGINT);
pg_usleep(100 * 1000); /* 100ms */
goto restart;
}
}
}
LWLockRelease(ProcArrayLock);
return (num != 0);
}
/*
* GetTransactionsInCommit -- Get the XIDs of transactions that are committing
*
@ -1005,6 +949,91 @@ CountUserBackends(Oid roleid)
return count;
}
/*
* CheckOtherDBBackends -- check for other backends running in the given DB
*
* If there are other backends in the DB, we will wait a maximum of 5 seconds
* for them to exit. Autovacuum backends are encouraged to exit early by
* sending them SIGINT, but normal user backends are just waited for.
*
* The current backend is always ignored; it is caller's responsibility to
* check whether the current backend uses the given DB, if it's important.
*
* Returns TRUE if there are (still) other backends in the DB, FALSE if not.
*
* This function is used to interlock DROP DATABASE and related commands
* against there being any active backends in the target DB --- dropping the
* DB while active backends remain would be a Bad Thing. Note that we cannot
* detect here the possibility of a newly-started backend that is trying to
* connect to the doomed database, so additional interlocking is needed during
* backend startup. The caller should normally hold an exclusive lock on the
* target DB before calling this, which is one reason we mustn't wait
* indefinitely.
*/
bool
CheckOtherDBBackends(Oid databaseId)
{
ProcArrayStruct *arrayP = procArray;
int tries;
/* 50 tries with 100ms sleep between tries makes 5 sec total wait */
for (tries = 0; tries < 50; tries++)
{
bool found = false;
int index;
CHECK_FOR_INTERRUPTS();
LWLockAcquire(ProcArrayLock, LW_SHARED);
for (index = 0; index < arrayP->numProcs; index++)
{
PGPROC *proc = arrayP->procs[index];
if (proc->databaseId != databaseId)
continue;
if (proc == MyProc)
continue;
found = true;
if (proc->isAutovacuum)
{
/* an autovacuum --- send it SIGINT before sleeping */
int autopid = proc->pid;
/*
* It's a bit awkward to release ProcArrayLock within the loop,
* but we'd probably better do so before issuing kill(). We
* have no idea what might block kill() inside the kernel...
*/
LWLockRelease(ProcArrayLock);
(void) kill(autopid, SIGINT); /* ignore any error */
break;
}
else
{
LWLockRelease(ProcArrayLock);
break;
}
}
/* if found is set, we released the lock within the loop body */
if (!found)
{
LWLockRelease(ProcArrayLock);
return false; /* no conflicting backends, so done */
}
/* else sleep and try again */
pg_usleep(100 * 1000L); /* 100ms */
}
return true; /* timed out, still conflicts */
}
#define XidCacheRemove(i) \
do { \