From: Tom Lane Date: Mon, 8 Aug 2005 03:12:16 +0000 (+0000) Subject: Cause ShutdownPostgres to do a normal transaction abort during backend X-Git-Tag: REL9_0_0~9557 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=7117cd3a77afcf76b6488bd3e1d06f3160595027;p=pg-rex%2Fsyncrep.git Cause ShutdownPostgres to do a normal transaction abort during backend exit, instead of trying to take shortcuts. Introduce some additional shutdown callback routines to eliminate kluges like having ProcKill be responsible for shutting down the buffer manager. Ensure that the order of operations during shutdown is predictable and what you would expect given the module layering. --- diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index e8261c8231..6f74ceaed7 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.205 2005/07/04 04:51:45 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.206 2005/08/08 03:11:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -378,9 +378,14 @@ BootstrapMain(int argc, char *argv[]) BaseInit(); - /* needed to get LWLocks */ + /* + * We aren't going to do the full InitPostgres pushups, but there + * are a couple of things that need to get lit up even in a dummy + * process. + */ if (IsUnderPostmaster) { + /* set up proc.c to get use of LWLocks */ switch (xlogop) { case BS_XLOG_BGWRITER: @@ -391,6 +396,9 @@ BootstrapMain(int argc, char *argv[]) InitDummyProcess(DUMMY_PROC_DEFAULT); break; } + + /* finish setting up bufmgr.c */ + InitBufferPoolBackend(); } /* diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 4bb0fc60e3..9a07915f79 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.102 2005/07/29 19:30:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.103 2005/08/08 03:11:40 tgl Exp $ * ---------- */ #include "postgres.h" @@ -665,7 +665,7 @@ pgstat_report_autovac(void) * pgstat_bestart() - * * Tell the collector that this new backend is soon ready to process - * queries. Called from tcop/postgres.c before entering the mainloop. + * queries. Called from InitPostgres. * ---------- */ void @@ -686,7 +686,7 @@ pgstat_bestart(void) * Set up a process-exit hook to ensure we flush the last batch of * statistics to the collector. */ - on_proc_exit(pgstat_beshutdown_hook, 0); + on_shmem_exit(pgstat_beshutdown_hook, 0); } /* --------- @@ -738,9 +738,7 @@ pgstat_report_analyze(Oid tableoid, bool shared, PgStat_Counter livetuples, /* * Flush any remaining statistics counts out to the collector at process * exit. Without this, operations triggered during backend exit (such as - * temp table deletions) won't be counted. This is an on_proc_exit hook, - * not on_shmem_exit, so that everything interesting must have happened - * already. + * temp table deletions) won't be counted. */ static void pgstat_beshutdown_hook(int code, Datum arg) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index b2537cbc07..52e6ae0222 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/buffer/buf_init.c,v 1.73 2005/05/19 21:35:46 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/buffer/buf_init.c,v 1.74 2005/08/08 03:11:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -149,6 +149,7 @@ InitBufferPool(void) * NB: this is called before InitProcess(), so we do not have a PGPROC and * cannot do LWLockAcquire; hence we can't actually access stuff in * shared memory yet. We are only initializing local data here. + * (See also InitBufferPoolBackend, over in bufmgr.c.) */ void InitBufferPoolAccess(void) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 4fb16eb614..4633ddef46 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.190 2005/08/02 20:52:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.191 2005/08/08 03:11:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -45,6 +45,7 @@ #include "storage/buf_internals.h" #include "storage/bufmgr.h" #include "storage/bufpage.h" +#include "storage/ipc.h" #include "storage/proc.h" #include "storage/smgr.h" #include "utils/relcache.h" @@ -93,6 +94,7 @@ static void buffer_write_error_callback(void *arg); static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr); static void FlushBuffer(BufferDesc *buf, SMgrRelation reln); +static void AtProcExit_Buffers(int code, Datum arg); static void write_buffer(Buffer buffer, bool unpin); @@ -1080,10 +1082,25 @@ AtEOXact_Buffers(bool isCommit) } /* - * Ensure we have released all shared-buffer locks and pins during backend exit + * InitBufferPoolBackend --- second-stage initialization of a new backend + * + * This is called after we have acquired a PGPROC and so can safely get + * LWLocks. We don't currently need to do anything at this stage ... + * except register a shmem-exit callback. AtProcExit_Buffers needs LWLock + * access, and thereby has to be called at the corresponding phase of + * backend shutdown. */ void -AtProcExit_Buffers(void) +InitBufferPoolBackend(void) +{ + on_shmem_exit(AtProcExit_Buffers, 0); +} + +/* + * Ensure we have released all shared-buffer locks and pins during backend exit + */ +static void +AtProcExit_Buffers(int code, Datum arg) { int i; @@ -1105,6 +1122,9 @@ AtProcExit_Buffers(void) Assert(PrivateRefCount[i] == 0); } } + + /* localbuf.c needs a chance too */ + AtProcExit_LocalBuffers(); } /* diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 2fb8165d2f..11ca95e833 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.119 2005/08/07 18:47:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.120 2005/08/08 03:11:49 tgl Exp $ * * NOTES: * @@ -297,6 +297,33 @@ pg_fdatasync(int fd) } /* + * InitFileAccess --- initialize this module during backend startup + * + * This is called during either normal or standalone backend start. + * It is *not* called in the postmaster. + */ +void +InitFileAccess(void) +{ + Assert(SizeVfdCache == 0); /* call me only once */ + + /* initialize cache header entry */ + VfdCache = (Vfd *) malloc(sizeof(Vfd)); + if (VfdCache == NULL) + ereport(FATAL, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + + MemSet((char *) &(VfdCache[0]), 0, sizeof(Vfd)); + VfdCache->fd = VFD_CLOSED; + + SizeVfdCache = 1; + + /* register proc-exit hook to ensure temp files are dropped at exit */ + on_proc_exit(AtProcExit_Files, 0); +} + +/* * count_usable_fds --- count how many FDs the system will let us open, * and estimate how many are already open. * @@ -622,25 +649,7 @@ AllocateVfd(void) DO_DB(elog(LOG, "AllocateVfd. Size %d", SizeVfdCache)); - if (SizeVfdCache == 0) - { - /* initialize header entry first time through */ - VfdCache = (Vfd *) malloc(sizeof(Vfd)); - if (VfdCache == NULL) - ereport(FATAL, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - MemSet((char *) &(VfdCache[0]), 0, sizeof(Vfd)); - VfdCache->fd = VFD_CLOSED; - - SizeVfdCache = 1; - - /* - * register proc-exit call to ensure temp files are dropped at - * exit - */ - on_proc_exit(AtProcExit_Files, 0); - } + Assert(SizeVfdCache > 0); /* InitFileAccess not called? */ if (VfdCache[0].nextFree == 0) { diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 11d0c70f6d..90a37332f3 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.161 2005/07/31 17:19:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.162 2005/08/08 03:11:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -144,7 +144,7 @@ InitProcGlobal(void) ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &foundProcGlobal); /* - * Create or attach to the PGPROC structures for dummy (checkpoint) + * Create or attach to the PGPROC structures for dummy (bgwriter) * processes, too. These do not get linked into the freeProcs list. */ DummyProcs = (PGPROC *) @@ -289,9 +289,10 @@ InitProcess(void) /* * InitDummyProcess -- create a dummy per-process data structure * - * This is called by checkpoint processes so that they will have a MyProc - * value that's real enough to let them wait for LWLocks. The PGPROC and - * sema that are assigned are the extra ones created during InitProcGlobal. + * This is called by bgwriter and similar processes so that they will have a + * MyProc value that's real enough to let them wait for LWLocks. The PGPROC + * and sema that are assigned are the extra ones created during + * InitProcGlobal. * * Dummy processes are presently not expected to wait for real (lockmgr) * locks, nor to participate in sinval messaging. @@ -485,27 +486,12 @@ ProcKill(int code, Datum arg) Assert(MyProc != NULL); - /* Release any LW locks I am holding */ - LWLockReleaseAll(); - /* - * Make real sure we release any buffer locks and pins we might be - * holding, too. It is pretty ugly to do this here and not in a - * shutdown callback registered by the bufmgr ... but we must do this - * *after* LWLockReleaseAll and *before* zapping MyProc. + * Release any LW locks I am holding. There really shouldn't be any, + * but it's cheap to check again before we cut the knees off the LWLock + * facility by releasing our PGPROC ... */ - AtProcExit_Buffers(); - - /* Get off any wait queue I might be on */ - LockWaitCancel(); - - /* Remove from the standard lock table */ - LockReleaseAll(DEFAULT_LOCKMETHOD, true); - -#ifdef USER_LOCKS - /* Remove from the user lock table */ - LockReleaseAll(USER_LOCKMETHOD, true); -#endif + LWLockReleaseAll(); /* Remove our PGPROC from the PGPROC array in shared memory */ ProcArrayRemove(MyProc); @@ -523,7 +509,7 @@ ProcKill(int code, Datum arg) } /* - * DummyProcKill() -- Cut-down version of ProcKill for dummy (checkpoint) + * DummyProcKill() -- Cut-down version of ProcKill for dummy (bgwriter) * processes. The PGPROC and sema are not released, only marked * as not-in-use. */ @@ -539,14 +525,9 @@ DummyProcKill(int code, Datum arg) Assert(MyProc == dummyproc); - /* Release any LW locks I am holding */ + /* Release any LW locks I am holding (see notes above) */ LWLockReleaseAll(); - /* Release buffer locks and pins, too */ - AtProcExit_Buffers(); - - /* I can't be on regular lock queues, so needn't check */ - /* Mark dummy proc no longer in use */ MyProc->pid = 0; diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index f286b20ee2..ac1767588d 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.91 2005/06/20 18:37:01 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.92 2005/08/08 03:12:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -136,11 +136,12 @@ static void smgr_internal_unlink(RelFileNode rnode, int which, /* - * smgrinit(), smgrshutdown() -- Initialize or shut down all storage + * smgrinit(), smgrshutdown() -- Initialize or shut down storage * managers. * - * Note: in the normal multiprocess scenario with a postmaster, these are - * called at postmaster start and stop, not per-backend. + * Note: smgrinit is called during backend startup (normal or standalone + * case), *not* during postmaster start. Therefore, any resources created + * here or destroyed in smgrshutdown are backend-local. */ void smgrinit(void) @@ -162,6 +163,9 @@ smgrinit(void) on_proc_exit(smgrshutdown, 0); } +/* + * on_proc_exit hook for smgr cleanup during backend shutdown + */ static void smgrshutdown(int code, Datum arg) { diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index ed5f050242..5025ab8f56 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.455 2005/07/21 03:56:11 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.456 2005/08/08 03:12:12 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -2953,13 +2953,6 @@ PostgresMain(int argc, char *argv[], const char *username) ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); - /* ---------- - * Tell the statistics collector that we're alive and - * to which database we belong. - * ---------- - */ - pgstat_bestart(); - /* * Remember stand-alone backend startup time */ diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index d06fa5db36..058872a73f 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.155 2005/07/31 17:19:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.156 2005/08/08 03:12:14 tgl Exp $ * * *------------------------------------------------------------------------- @@ -45,6 +45,7 @@ #include "utils/portal.h" #include "utils/relcache.h" #include "utils/syscache.h" +#include "pgstat.h" static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace); @@ -287,7 +288,8 @@ BaseInit(void) InitCommunication(); DebugFileOpen(); - /* Do local initialization of storage and buffer managers */ + /* Do local initialization of file, storage and buffer managers */ + InitFileAccess(); smgrinit(); InitBufferPoolAccess(); } @@ -399,6 +401,11 @@ InitPostgres(const char *dbname, const char *username) elog(FATAL, "bad backend id: %d", MyBackendId); /* + * bufmgr needs another initialization call too + */ + InitBufferPoolBackend(); + + /* * Initialize local process's access to XLOG. In bootstrap case we * may skip this since StartupXLOG() was run instead. */ @@ -503,6 +510,15 @@ InitPostgres(const char *dbname, const char *username) InitializeClientEncoding(); /* + * Initialize statistics collection for this backend. We do this + * here because the shutdown hook it sets up needs to be invoked + * at the corresponding phase of backend shutdown: after + * ShutdownPostgres and before we drop access to shared memory. + */ + if (IsUnderPostmaster) + pgstat_bestart(); + + /* * Set up process-exit callback to do pre-shutdown cleanup. This * should be last because we want shmem_exit to call this routine * before the exit callbacks that are registered by buffer manager, @@ -518,6 +534,7 @@ InitPostgres(const char *dbname, const char *username) return am_superuser; } + /* * Backend-shutdown callback. Do cleanup that we want to be sure happens * before all the supporting modules begin to nail their doors shut via @@ -533,32 +550,19 @@ InitPostgres(const char *dbname, const char *username) static void ShutdownPostgres(int code, Datum arg) { - /* - * These operations are really just a minimal subset of - * AbortTransaction(). We don't want to do any inessential cleanup, - * since that just raises the odds of failure --- but there's some - * stuff we need to do. - * - * Release any LW locks, buffer content locks, and buffer pins we might be - * holding. This is a kluge to improve the odds that we won't get into a - * self-made stuck-lock scenario while trying to shut down. We *must* - * release buffer pins to make it safe to do file deletion, since we - * might have some pins on pages of the target files. - */ - LWLockReleaseAll(); - AtProcExit_Buffers(); - AtProcExit_LocalBuffers(); + /* Make sure we've killed any active transaction */ + AbortOutOfAnyTransaction(); /* - * In case a transaction is open, delete any files it created. This - * has to happen before bufmgr shutdown, so having smgr register a - * callback for it wouldn't work. + * User locks are not released by transaction end, so be sure to + * release them explicitly. */ - smgrDoPendingDeletes(false); /* delete as though aborting xact */ +#ifdef USER_LOCKS + LockReleaseAll(USER_LOCKMETHOD, true); +#endif } - /* * Returns true if at least one role is defined in this database cluster. */ diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index b77c3cc467..eb7268edfc 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.93 2005/03/20 22:00:54 tgl Exp $ + * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.94 2005/08/08 03:12:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -123,10 +123,10 @@ extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, extern void InitBufferPool(void); extern void InitBufferPoolAccess(void); +extern void InitBufferPoolBackend(void); extern char *ShowBufferUsage(void); extern void ResetBufferUsage(void); extern void AtEOXact_Buffers(bool isCommit); -extern void AtProcExit_Buffers(void); extern void PrintBufferLeakWarning(Buffer buffer); extern void FlushBufferPool(void); extern BlockNumber BufferGetBlockNumber(Buffer buffer); diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index 0cebfb85bb..5a25e51879 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/fd.h,v 1.52 2005/06/19 21:34:03 tgl Exp $ + * $PostgreSQL: pgsql/src/include/storage/fd.h,v 1.53 2005/08/08 03:12:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -83,6 +83,7 @@ extern int FreeDir(DIR *dir); extern int BasicOpenFile(FileName fileName, int fileFlags, int fileMode); /* Miscellaneous support routines */ +extern void InitFileAccess(void); extern void set_max_safe_fds(void); extern void closeAllVfds(void); extern void AtEOXact_Files(void);