diff options
| -rw-r--r-- | src/backend/access/transam/twophase.c | 1 | ||||
| -rw-r--r-- | src/backend/commands/dbcommands.c | 10 | ||||
| -rw-r--r-- | src/backend/postmaster/autovacuum.c | 13 | ||||
| -rw-r--r-- | src/backend/postmaster/postmaster.c | 4 | ||||
| -rw-r--r-- | src/backend/storage/ipc/procarray.c | 29 | ||||
| -rw-r--r-- | src/backend/storage/lmgr/proc.c | 3 | ||||
| -rw-r--r-- | src/include/postmaster/autovacuum.h | 1 | ||||
| -rw-r--r-- | src/include/storage/proc.h | 1 | ||||
| -rw-r--r-- | src/include/storage/procarray.h | 2 |
9 files changed, 50 insertions, 14 deletions
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index f85c2c6842..636216f40a 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -280,6 +280,7 @@ MarkAsPreparing(TransactionId xid, const char *gid, gxact->proc.databaseId = databaseid; gxact->proc.roleId = owner; gxact->proc.inVacuum = false; + gxact->proc.isAutovacuum = false; gxact->proc.lwWaiting = false; gxact->proc.lwExclusive = false; gxact->proc.lwWaitLink = NULL; diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index a19695bab1..eb025ee6de 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -250,11 +250,11 @@ createdb(const CreatedbStmt *stmt) * (exception is to allow CREATE DB while connected to template1). * Otherwise we might copy inconsistent data. */ - if (DatabaseHasActiveBackends(src_dboid, true)) + if (DatabaseCancelAutovacuumActivity(src_dboid, true)) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), - errmsg("source database \"%s\" is being accessed by other users", - dbtemplate))); + errmsg("source database \"%s\" is being accessed by other users", + dbtemplate))); /* If encoding is defaulted, use source's encoding */ if (encoding < 0) @@ -602,7 +602,7 @@ dropdb(const char *dbname, bool missing_ok) * Check for active backends in the target database. (Because we hold the * database lock, no new ones can start after this.) */ - if (DatabaseHasActiveBackends(db_id, false)) + if (DatabaseCancelAutovacuumActivity(db_id, false)) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("database \"%s\" is being accessed by other users", @@ -706,7 +706,7 @@ RenameDatabase(const char *oldname, const char *newname) * Make sure the database does not have active sessions. This is the same * concern as above, but applied to other sessions. */ - if (DatabaseHasActiveBackends(db_id, false)) + if (DatabaseCancelAutovacuumActivity(db_id, false)) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("database \"%s\" is being accessed by other users", diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 68455e066c..42cfcfb6ec 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -216,6 +216,15 @@ autovac_forkexec(void) return postmaster_forkexec(ac, av); } + +/* + * We need this set from the outside, before InitProcess is called + */ +void +AutovacuumIAm(void) +{ + am_autovacuum = true; +} #endif /* EXEC_BACKEND */ /* @@ -307,8 +316,8 @@ AutoVacMain(int argc, char *argv[]) EmitErrorReport(); /* - * We can now go away. Note that because we'll call InitProcess, a - * callback will be registered to do ProcKill, which will clean up + * We can now go away. Note that because we called InitProcess, a + * callback was registered to do ProcKill, which will clean up * necessary state. */ proc_exit(0); diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index f5675231b6..36339ad999 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -3298,6 +3298,10 @@ SubPostmasterMain(int argc, char *argv[]) strcmp(argv[1], "--forkboot") == 0) PGSharedMemoryReAttach(); + /* autovacuum needs this set before calling InitProcess */ + if (strcmp(argv[1], "--forkautovac") == 0) + AutovacuumIAm(); + /* * Start our win32 signal implementation. This has to be done after we * read the backend variables, because we need to pick up the signal pipe diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 79a41029cf..2d1493bb09 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -29,6 +29,8 @@ */ #include "postgres.h" +#include <signal.h> + #include "access/subtrans.h" #include "access/transam.h" #include "access/xact.h" @@ -678,7 +680,9 @@ GetSnapshotData(Snapshot snapshot, bool serializable) } /* - * DatabaseHasActiveBackends -- are there any backends running in the given DB + * 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. @@ -691,11 +695,16 @@ GetSnapshotData(Snapshot snapshot, bool serializable) * backend startup. */ bool -DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself) +DatabaseCancelAutovacuumActivity(Oid databaseId, bool ignoreMyself) { - bool result = false; ProcArrayStruct *arrayP = procArray; int index; + int num; + +restart: + num = 0; + + CHECK_FOR_INTERRUPTS(); LWLockAcquire(ProcArrayLock, LW_SHARED); @@ -708,14 +717,22 @@ DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself) if (ignoreMyself && proc == MyProc) continue; - result = true; - break; + 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 result; + return (num != 0); } /* diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 2cb629aa4a..8cb1e0340c 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -38,6 +38,7 @@ #include "access/transam.h" #include "access/xact.h" #include "miscadmin.h" +#include "postmaster/autovacuum.h" #include "storage/ipc.h" #include "storage/proc.h" #include "storage/procarray.h" @@ -258,6 +259,7 @@ InitProcess(void) MyProc->databaseId = InvalidOid; MyProc->roleId = InvalidOid; MyProc->inVacuum = false; + MyProc->isAutovacuum = IsAutoVacuumProcess(); MyProc->lwWaiting = false; MyProc->lwExclusive = false; MyProc->lwWaitLink = NULL; @@ -390,6 +392,7 @@ InitDummyProcess(void) MyProc->databaseId = InvalidOid; MyProc->roleId = InvalidOid; MyProc->inVacuum = false; + MyProc->isAutovacuum = false; MyProc->lwWaiting = false; MyProc->lwExclusive = false; MyProc->lwWaitLink = NULL; diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h index e83684441c..4c7671faa8 100644 --- a/src/include/postmaster/autovacuum.h +++ b/src/include/postmaster/autovacuum.h @@ -36,6 +36,7 @@ extern void autovac_stopped(void); #ifdef EXEC_BACKEND extern void AutoVacMain(int argc, char *argv[]); +extern void AutovacuumIAm(void); #endif #endif /* AUTOVACUUM_H */ diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index fed061bb29..0012c24133 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -75,6 +75,7 @@ struct PGPROC Oid roleId; /* OID of role using this backend */ bool inVacuum; /* true if current xact is a LAZY VACUUM */ + bool isAutovacuum; /* true if it's autovacuum */ /* Info about LWLock the process is currently waiting for, if any. */ bool lwWaiting; /* true if waiting for an LW lock */ diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index 7fe9988e53..583235d746 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -29,7 +29,7 @@ extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum); extern PGPROC *BackendPidGetProc(int pid); extern int BackendXidGetPid(TransactionId xid); extern bool IsBackendPid(int pid); -extern bool DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself); +extern bool DatabaseCancelAutovacuumActivity(Oid databaseId, bool ignoreMyself); extern int CountActiveBackends(void); extern int CountDBBackends(Oid databaseid); |
