Re: Cleaning up backend-exit cleanup - Mailing list pgsql-patches
From | Tom Lane |
---|---|
Subject | Re: Cleaning up backend-exit cleanup |
Date | |
Msg-id | 8368.977100604@sss.pgh.pa.us Whole thread Raw |
List | pgsql-patches |
This just-applied patch deals with my pghackers message dated 15 Dec 2000 16:25:56 -0500. It ensures that all required cleanup happens via on_proc_exit or on_shmem_exit callbacks, rather than ad-hoc operations invoked before (only some of the calls to) elog() or proc_exit(). elog() can now go directly to proc_exit() in the fatal-exit case, so the ExitAfterAbort hack is eliminated. Clean up the order/location of some initialization actions, and rename variables associated with END_CRIT_SECTION to more intelligible (IMHO) names. Finally, add commentary to try to discourage future hackers from making these same mistakes again ... regards, tom lane *** src/backend/access/transam/xact.c.orig Thu Dec 7 13:44:00 2000 --- src/backend/access/transam/xact.c Sun Dec 17 17:12:05 2000 *************** *** 1095,1100 **** --- 1095,1109 ---- MyProc->xmin = InvalidTransactionId; } + /* + * Release any spinlocks or buffer context locks we might be holding + * as quickly as possible. (Real locks, however, must be held till + * we finish aborting.) Releasing spinlocks is critical since we + * might try to grab them again while cleaning up! + */ + ProcReleaseSpins(NULL); + UnlockBuffers(); + /* ---------------- * check the current transaction state * ---------------- *************** *** 1105,1122 **** if (s->state != TRANS_INPROGRESS) elog(NOTICE, "AbortTransaction and not in in-progress state"); - /* - * Reset user id which might have been changed transiently - */ - SetUserId(GetSessionUserId()); - - /* ---------------- - * Tell the trigger manager that this transaction is about to be - * aborted. - * ---------------- - */ - DeferredTriggerAbortXact(); - /* ---------------- * set the current transaction state information * appropriately during the abort processing --- 1114,1119 ---- *************** *** 1124,1135 **** */ s->state = TRANS_ABORT; /* ---------------- * do abort processing * ---------------- */ lo_commit(false); /* 'false' means it's abort */ - UnlockBuffers(); AtAbort_Notify(); CloseSequences(); AtEOXact_portals(); --- 1121,1137 ---- */ s->state = TRANS_ABORT; + /* + * Reset user id which might have been changed transiently + */ + SetUserId(GetSessionUserId()); + /* ---------------- * do abort processing * ---------------- */ + DeferredTriggerAbortXact(); lo_commit(false); /* 'false' means it's abort */ AtAbort_Notify(); CloseSequences(); AtEOXact_portals(); *** src/backend/access/transam/xlog.c.orig Thu Dec 14 17:32:04 2000 --- src/backend/access/transam/xlog.c Sun Dec 17 17:12:08 2000 *************** *** 40,46 **** int XLOGbuffers = 8; XLogRecPtr MyLastRecPtr = {0, 0}; ! uint32 StopIfError = 0; bool InRecovery = false; StartUpID ThisStartUpID = 0; --- 40,46 ---- int XLOGbuffers = 8; XLogRecPtr MyLastRecPtr = {0, 0}; ! uint32 CritSectionCount = 0; bool InRecovery = false; StartUpID ThisStartUpID = 0; *************** *** 1531,1537 **** char buffer[MAXLOGRECSZ + SizeOfXLogRecord]; elog(LOG, "starting up"); ! StopIfError++; XLogCtl->xlblocks = (XLogRecPtr *) (((char *) XLogCtl) + sizeof(XLogCtlData)); XLogCtl->pages = ((char *) XLogCtl->xlblocks + sizeof(XLogRecPtr) * XLOGbuffers); --- 1531,1537 ---- char buffer[MAXLOGRECSZ + SizeOfXLogRecord]; elog(LOG, "starting up"); ! CritSectionCount++; XLogCtl->xlblocks = (XLogRecPtr *) (((char *) XLogCtl) + sizeof(XLogCtlData)); XLogCtl->pages = ((char *) XLogCtl->xlblocks + sizeof(XLogRecPtr) * XLOGbuffers); *************** *** 1748,1754 **** XLogCtl->ThisStartUpID = ThisStartUpID; elog(LOG, "database system is in production state"); ! StopIfError--; return; } --- 1748,1754 ---- XLogCtl->ThisStartUpID = ThisStartUpID; elog(LOG, "database system is in production state"); ! CritSectionCount--; return; } *************** *** 1771,1780 **** { elog(LOG, "shutting down"); ! StopIfError++; CreateDummyCaches(); CreateCheckPoint(true); ! StopIfError--; elog(LOG, "database system is shut down"); } --- 1771,1780 ---- { elog(LOG, "shutting down"); ! CritSectionCount++; CreateDummyCaches(); CreateCheckPoint(true); ! CritSectionCount--; elog(LOG, "database system is shut down"); } *** src/backend/commands/trigger.c.orig Mon Nov 20 15:36:47 2000 --- src/backend/commands/trigger.c Sun Dec 17 17:12:27 2000 *************** *** 1432,1438 **** * transactions. * ---------- */ ! int DeferredTriggerInit(void) { deftrig_gcxt = AllocSetContextCreate(TopMemoryContext, --- 1432,1438 ---- * transactions. * ---------- */ ! void DeferredTriggerInit(void) { deftrig_gcxt = AllocSetContextCreate(TopMemoryContext, *************** *** 1440,1447 **** ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); - - return 0; } --- 1440,1445 ---- *** src/backend/libpq/pqcomm.c.orig Wed Nov 29 15:59:51 2000 --- src/backend/libpq/pqcomm.c Sun Dec 17 17:12:43 2000 *************** *** 85,90 **** --- 85,93 ---- #endif + static void pq_close(void); + + /* * Configuration options */ *************** *** 122,127 **** --- 125,131 ---- { PqSendPointer = PqRecvPointer = PqRecvLength = 0; DoingCopyOut = false; + on_proc_exit(pq_close, 0); } *************** *** 132,138 **** * don't crash during exit... * -------------------------------- */ ! void pq_close(void) { if (MyProcPort != NULL) --- 136,142 ---- * don't crash during exit... * -------------------------------- */ ! static void pq_close(void) { if (MyProcPort != NULL) *** src/backend/storage/buffer/buf_init.c.orig Wed Nov 29 20:39:07 2000 --- src/backend/storage/buffer/buf_init.c Sun Dec 17 18:31:26 2000 *************** *** 36,41 **** --- 36,44 ---- #include "utils/hsearch.h" #include "utils/memutils.h" + + static void ShutdownBufferPoolAccess(void); + /* * if BMTRACE is defined, we trace the last 200 buffer allocations and * deallocations in a circular buffer in shared memory. *************** *** 73,79 **** * Two important notes. First, the buffer has to be * available for lookup BEFORE an IO begins. Otherwise * a second process trying to read the buffer will ! * allocate its own copy and the buffeer pool will * become inconsistent. * * Buffer Replacement: --- 76,82 ---- * Two important notes. First, the buffer has to be * available for lookup BEFORE an IO begins. Otherwise * a second process trying to read the buffer will ! * allocate its own copy and the buffer pool will * become inconsistent. * * Buffer Replacement: *************** *** 126,135 **** /* ! * Initialize module: called once during shared-memory initialization * ! * should calculate size of pool dynamically based on the ! * amount of available memory. */ void InitBufferPool(void) --- 129,138 ---- /* ! * Initialize shared buffer pool * ! * This is called once during shared-memory initialization (either in the ! * postmaster, or in a standalone backend). */ void InitBufferPool(void) *************** *** 144,149 **** --- 147,156 ---- Lookup_List_Descriptor = Data_Descriptors + 1; Num_Descriptors = Data_Descriptors + 1; + /* + * It's probably not really necessary to grab the lock --- if there's + * anyone else attached to the shmem at this point, we've got problems. + */ SpinAcquire(BufMgrLock); #ifdef BMTRACE *************** *** 203,214 **** BufferDescriptors[Data_Descriptors - 1].freeNext = 0; } ! /* Init the rest of the module */ InitBufTable(); InitFreeList(!foundDescs); SpinRelease(BufMgrLock); BufferBlockPointers = (Block *) calloc(NBuffers, sizeof(Block)); PrivateRefCount = (long *) calloc(NBuffers, sizeof(long)); BufferLocks = (bits8 *) calloc(NBuffers, sizeof(bits8)); --- 210,237 ---- BufferDescriptors[Data_Descriptors - 1].freeNext = 0; } ! /* Init other shared buffer-management stuff */ InitBufTable(); InitFreeList(!foundDescs); SpinRelease(BufMgrLock); + } + + /* + * Initialize access to shared buffer pool + * + * This is called during backend startup (whether standalone or under the + * postmaster). It sets up for this backend's access to the already-existing + * buffer pool. + */ + void + InitBufferPoolAccess(void) + { + int i; + /* + * Allocate and zero local arrays of per-buffer info. + */ BufferBlockPointers = (Block *) calloc(NBuffers, sizeof(Block)); PrivateRefCount = (long *) calloc(NBuffers, sizeof(long)); BufferLocks = (bits8 *) calloc(NBuffers, sizeof(bits8)); *************** *** 224,229 **** --- 247,273 ---- { BufferBlockPointers[i] = (Block) MAKE_PTR(BufferDescriptors[i].data); } + + /* + * Now that buffer access is initialized, set up a callback to shut it + * down again at backend exit. + */ + on_shmem_exit(ShutdownBufferPoolAccess, 0); + } + + /* + * Shut down buffer manager at backend exit. + * + * This is needed mainly to ensure that we don't leave any buffer reference + * counts set during an error exit. + */ + static void + ShutdownBufferPoolAccess(void) + { + /* Release any buffer context locks we are holding */ + UnlockBuffers(); + /* Release any buffer reference counts we are holding */ + ResetBufferPool(false); } /* ----------------------------------------------------- *** src/backend/storage/lmgr/proc.c.orig Mon Dec 11 11:35:59 2000 --- src/backend/storage/lmgr/proc.c Sun Dec 17 17:12:35 2000 *************** *** 29,35 **** * * Interface (b): * ! * ProcReleaseLocks -- frees the locks associated with this process, * ProcKill -- destroys the shared memory state (and locks) * associated with the process. * --- 29,36 ---- * * Interface (b): * ! * ProcReleaseLocks -- frees the locks associated with current transaction ! * * ProcKill -- destroys the shared memory state (and locks) * associated with the process. * *************** *** 332,338 **** } /* ! * ProcReleaseLocks() -- release all locks associated with this process * */ void --- 333,339 ---- } /* ! * ProcReleaseLocks() -- release all locks associated with current transaction * */ void *************** *** 340,346 **** { if (!MyProc) return; ! LockReleaseAll(1, &MyProc->lockQueue); GetOffWaitqueue(MyProc); } --- 341,347 ---- { if (!MyProc) return; ! LockReleaseAll(DEFAULT_LOCKMETHOD, &MyProc->lockQueue); GetOffWaitqueue(MyProc); } *************** *** 423,430 **** * ---------------- */ GetOffWaitqueue(proc); - - return; } /* --- 424,429 ---- *** src/backend/tcop/postgres.c.orig Tue Dec 5 18:37:41 2000 --- src/backend/tcop/postgres.c Sun Dec 17 19:32:42 2000 *************** *** 61,67 **** #include "utils/guc.h" #include "utils/memutils.h" #include "utils/ps_status.h" - #include "utils/temprel.h" #ifdef MULTIBYTE #include "mb/pg_wchar.h" #endif --- 61,66 ---- *************** *** 95,101 **** bool Warn_restart_ready = false; bool InError = false; ! bool ExitAfterAbort = false; static bool EchoQuery = false; /* default don't echo */ char pg_pathname[MAXPGPATH]; --- 94,100 ---- bool Warn_restart_ready = false; bool InError = false; ! bool ProcDiePending = false; static bool EchoQuery = false; /* default don't echo */ char pg_pathname[MAXPGPATH]; *************** *** 921,927 **** void handle_warn(SIGNAL_ARGS) { ! if (StopIfError) { QueryCancel = true; return; --- 920,927 ---- void handle_warn(SIGNAL_ARGS) { ! /* Don't joggle the elbow of a critical section */ ! if (CritSectionCount > 0) { QueryCancel = true; return; *************** *** 958,970 **** { PG_SETMASK(&BlockSig); ! ExitAfterAbort = true; ! if (StopIfError) { QueryCancel = true; return; } ! if (InError) /* If ERROR/FATAL is in progress... */ return; elog(FATAL, "The system is shutting down"); } --- 958,972 ---- { PG_SETMASK(&BlockSig); ! /* Don't joggle the elbow of a critical section */ ! if (CritSectionCount > 0) { QueryCancel = true; + ProcDiePending = true; return; } ! /* Don't joggle the elbow of proc_exit, either */ ! if (proc_exit_inprogress) return; elog(FATAL, "The system is shutting down"); } *************** *** 1096,1101 **** --- 1098,1105 ---- MemoryContextInit(); } + SetProcessingMode(InitProcessing); + /* * Set default values for command-line options. */ *************** *** 1109,1116 **** } StatFp = stderr; - SetProcessingMode(InitProcessing); - /* Check for PGDATESTYLE environment variable */ set_default_datestyle(); --- 1113,1118 ---- *************** *** 1428,1438 **** break; } ! if (Show_query_stats && (Show_parser_stats || Show_planner_stats || Show_executor_stats)) { ! elog(NOTICE, "Query statistics are disabled because parser, planner, or executor statistics are on."); Show_query_stats = false; } --- 1430,1445 ---- break; } ! /* ! * Post-processing for command line options. ! * ! * XXX It'd be nice if libpq were already running here, so we could do ! * elog(NOTICE) instead of just writing on stderr... ! */ if (Show_query_stats && (Show_parser_stats || Show_planner_stats || Show_executor_stats)) { ! fprintf(stderr, "Query statistics are disabled because parser, planner, or executor statistics are on.\n"); Show_query_stats = false; } *************** *** 1528,1534 **** --- 1535,1547 ---- XLOGPathInit(); BaseInit(); + + /* + * Start up xlog for standalone backend, and register to have it + * closed down at exit. + */ StartupXLOG(); + on_shmem_exit(ShutdownXLOG, 0); } /* *************** *** 1602,1621 **** remote_host, username, DBName); /* ! * general initialization */ if (DebugLvl > 1) elog(DEBUG, "InitPostgres"); InitPostgres(DBName, username); ! #ifdef MULTIBYTE ! /* set default client encoding */ ! if (DebugLvl > 1) ! elog(DEBUG, "set_default_client_encoding"); ! set_default_client_encoding(); ! #endif ! ! on_shmem_exit(remove_all_temp_relations, 0); /* * Send this backend's cancellation info to the frontend. --- 1615,1631 ---- remote_host, username, DBName); /* ! * General initialization. ! * ! * NOTE: if you are tempted to add code in this vicinity, consider ! * putting it inside InitPostgres() instead. In particular, anything ! * that involves database access should be there, not here. */ if (DebugLvl > 1) elog(DEBUG, "InitPostgres"); InitPostgres(DBName, username); ! SetProcessingMode(NormalProcessing); /* * Send this backend's cancellation info to the frontend. *************** *** 1640,1653 **** } /* - * Initialize the deferred trigger manager - */ - if (DeferredTriggerInit() != 0) - goto normalexit; - - SetProcessingMode(NormalProcessing); - - /* * Create the memory context we will use in the main loop. * * QueryContext is reset once per iteration of the main loop, --- 1650,1655 ---- *************** *** 1671,1676 **** --- 1673,1682 ---- if (sigsetjmp(Warn_restart, 1) != 0) { /* + * NOTE: if you are tempted to add more code in this if-block, + * consider the probability that it should be in AbortTransaction() + * instead. + * * Make sure we are in a valid memory context during recovery. * * We use ErrorContext in hopes that it will have some free space *************** *** 1678,1696 **** */ MemoryContextSwitchTo(ErrorContext); if (DebugLvl >= 1) elog(DEBUG, "AbortCurrentTransaction"); AbortCurrentTransaction(); - if (ExitAfterAbort) - goto errorexit; - /* ! * If we recovered successfully, return to normal top-level context ! * and clear ErrorContext for next time. */ MemoryContextSwitchTo(TopMemoryContext); MemoryContextResetAndDeleteChildren(ErrorContext); InError = false; } --- 1684,1705 ---- */ MemoryContextSwitchTo(ErrorContext); + /* Do the recovery */ if (DebugLvl >= 1) elog(DEBUG, "AbortCurrentTransaction"); AbortCurrentTransaction(); /* ! * Now return to normal top-level context and clear ErrorContext ! * for next time. */ MemoryContextSwitchTo(TopMemoryContext); MemoryContextResetAndDeleteChildren(ErrorContext); + + /* + * Clear flag to indicate that we got out of error recovery mode + * successfully. (Flag was set in elog.c before longjmp().) + */ InError = false; } *************** *** 1775,1781 **** if (HandleFunctionRequest() == EOF) { /* lost frontend connection during F message input */ ! goto normalexit; } /* commit the function-invocation transaction */ --- 1784,1790 ---- if (HandleFunctionRequest() == EOF) { /* lost frontend connection during F message input */ ! proc_exit(0); } /* commit the function-invocation transaction */ *************** *** 1830,1836 **** */ case 'X': case EOF: ! goto normalexit; default: elog(ERROR, "unknown frontend message was received"); --- 1839,1852 ---- */ case 'X': case EOF: ! /* ! * NOTE: if you are tempted to add more code here, DON'T! ! * Whatever you had in mind to do should be set up as ! * an on_proc_exit or on_shmem_exit callback, instead. ! * Otherwise it will fail to be called during other ! * backend-shutdown scenarios. ! */ ! proc_exit(0); default: elog(ERROR, "unknown frontend message was received"); *************** *** 1845,1860 **** #endif } /* end of input-reading loop */ ! normalexit: ! ExitAfterAbort = true; /* ensure we will exit if elog during abort */ ! AbortOutOfAnyTransaction(); ! if (!IsUnderPostmaster) ! ShutdownXLOG(); ! ! errorexit: ! pq_close(); ! ProcReleaseLocks(); /* Just to be sure... */ ! proc_exit(0); return 1; /* keep compiler quiet */ } --- 1861,1868 ---- #endif } /* end of input-reading loop */ ! /* can't get here because the above loop never exits */ ! Assert(false); return 1; /* keep compiler quiet */ } *** src/backend/utils/error/elog.c.orig Wed Dec 6 12:25:46 2000 --- src/backend/utils/error/elog.c Sun Dec 17 17:13:28 2000 *************** *** 159,165 **** /* this is probably redundant... */ if (IsInitProcessingMode()) lev = FATAL; ! if (StopIfError) lev = STOP; } --- 159,165 ---- /* this is probably redundant... */ if (IsInitProcessingMode()) lev = FATAL; ! if (CritSectionCount > 0) lev = STOP; } *************** *** 445,465 **** { /* * If we have not yet entered the main backend loop (ie, we are in ! * the postmaster or in backend startup), then go directly to * proc_exit. The same is true if anyone tries to report an error * after proc_exit has begun to run. (It's proc_exit's * responsibility to see that this doesn't turn into infinite * recursion!) But in the latter case, we exit with nonzero exit * code to indicate that something's pretty wrong. */ ! if (proc_exit_inprogress || !Warn_restart_ready) { fflush(stdout); fflush(stderr); - ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */ - ProcReleaseLocks(); /* get rid of real locks we hold */ - /* XXX shouldn't proc_exit be doing the above?? */ proc_exit((int) proc_exit_inprogress); } --- 445,470 ---- { /* + * For a FATAL error, we let proc_exit clean up and exit. + * * If we have not yet entered the main backend loop (ie, we are in ! * the postmaster or in backend startup), we also go directly to * proc_exit. The same is true if anyone tries to report an error * after proc_exit has begun to run. (It's proc_exit's * responsibility to see that this doesn't turn into infinite * recursion!) But in the latter case, we exit with nonzero exit * code to indicate that something's pretty wrong. */ ! if (lev == FATAL || !Warn_restart_ready || proc_exit_inprogress) { + /* + * fflush here is just to improve the odds that we get to see + * the error message, in case things are so hosed that proc_exit + * crashes. Any other code you might be tempted to add here + * should probably be in an on_proc_exit callback instead. + */ fflush(stdout); fflush(stderr); proc_exit((int) proc_exit_inprogress); } *************** *** 471,483 **** InError = true; /* ! * Otherwise we can return to the main loop in postgres.c. In the ! * FATAL case, postgres.c will call proc_exit, but not till after ! * completing a standard transaction-abort sequence. */ - ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */ - if (lev == FATAL) - ExitAfterAbort = true; siglongjmp(Warn_restart, 1); } --- 476,483 ---- InError = true; /* ! * Otherwise we can return to the main loop in postgres.c. */ siglongjmp(Warn_restart, 1); } *** src/backend/utils/init/postinit.c.orig Sat Dec 16 14:59:03 2000 --- src/backend/utils/init/postinit.c Sun Dec 17 19:28:44 2000 *************** *** 28,33 **** --- 28,34 ---- #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/pg_database.h" + #include "commands/trigger.h" #include "miscadmin.h" #include "storage/backendid.h" #include "storage/proc.h" *************** *** 37,42 **** --- 38,44 ---- #include "utils/portal.h" #include "utils/relcache.h" #include "utils/syscache.h" + #include "utils/temprel.h" #ifdef MULTIBYTE #include "mb/pg_wchar.h" *************** *** 44,49 **** --- 46,54 ---- static void ReverifyMyDatabase(const char *name); static void InitCommunication(void); + static void ShutdownPostgres(void); + + int lockingOff = 0; /* backend -L switch */ /*** InitPostgres support ***/ *************** *** 115,126 **** */ dbform = (Form_pg_database) GETSTRUCT(tup); if (! dbform->datallowconn) - { - heap_endscan(pgdbscan); - heap_close(pgdbrel, AccessShareLock); elog(FATAL, "Database \"%s\" is not currently accepting connections", name); - } /* * OK, we're golden. Only other to-do item is to save the MULTIBYTE --- 120,127 ---- *************** *** 163,168 **** --- 164,191 ---- } + /* + * Early initialization of a backend (either standalone or under postmaster). + * This happens even before InitPostgres. + */ + void + BaseInit(void) + { + /* + * Attach to shared memory and semaphores, and initialize our + * input/output/debugging file descriptors. + */ + InitCommunication(); + DebugFileOpen(); + + /* Do local initialization of storage and buffer managers */ + smgrinit(); + InitBufferPoolAccess(); + InitLocalBuffer(); + + EnablePortalManager(); /* memory for portal/transaction stuff */ + } + /* -------------------------------- * InitPostgres *************** *** 172,187 **** * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ - int lockingOff = 0; /* backend -L switch */ - - /* - */ void InitPostgres(const char *dbname, const char *username) { bool bootstrap = IsBootstrapProcessingMode(); SetDatabaseName(dbname); /* ---------------- * initialize the database id used for system caches and lock tables * ---------------- --- 195,207 ---- * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ void InitPostgres(const char *dbname, const char *username) { bool bootstrap = IsBootstrapProcessingMode(); SetDatabaseName(dbname); + /* ---------------- * initialize the database id used for system caches and lock tables * ---------------- *************** *** 299,304 **** --- 319,330 ---- */ InitCatalogCache(); + /* + * Initialize the deferred trigger manager --- must happen before + * first transaction start. + */ + DeferredTriggerInit(); + /* start a new transaction here before access to db */ if (!bootstrap) StartTransactionCommand(); *************** *** 322,348 **** /* * Unless we are bootstrapping, double-check that InitMyDatabaseInfo() ! * got a correct result. We can't do this until essentially all the ! * infrastructure is up, so just do it at the end. */ if (!bootstrap) ReverifyMyDatabase(dbname); } ! void ! BaseInit(void) { /* ! * Attach to shared memory and semaphores, and initialize our ! * input/output/debugging file descriptors. */ ! InitCommunication(); ! DebugFileOpen(); ! ! smgrinit(); ! ! EnablePortalManager(); /* memory for portal/transaction stuff */ ! ! /* initialize the local buffer manager */ ! InitLocalBuffer(); } --- 348,409 ---- /* * Unless we are bootstrapping, double-check that InitMyDatabaseInfo() ! * got a correct result. We can't do this until all the database-access ! * infrastructure is up. */ if (!bootstrap) ReverifyMyDatabase(dbname); + + #ifdef MULTIBYTE + /* set default client encoding --- uses info from ReverifyMyDatabase */ + set_default_client_encoding(); + #endif + + /* + * Set up process-exit callbacks to remove temp relations and then + * do pre-shutdown cleanup. This should be last because we want + * shmem_exit to call these routines before the exit callbacks that + * are registered by buffer manager, lock manager, etc. We need + * to run this code before we close down database access! + */ + on_shmem_exit(ShutdownPostgres, 0); + /* because callbacks are called in reverse order, this gets done first: */ + on_shmem_exit(remove_all_temp_relations, 0); + + /* close the transaction we started above */ + if (!bootstrap) + CommitTransactionCommand(); } ! /* ! * Backend-shutdown callback. Do cleanup that we want to be sure happens ! * before all the supporting modules begin to nail their doors shut via ! * their own callbacks. Note that because this has to be registered very ! * late in startup, it will not get called if we suffer a failure *during* ! * startup. ! * ! * User-level cleanup, such as temp-relation removal and UNLISTEN, happens ! * via separate callbacks that execute before this one. We don't combine the ! * callbacks because we still want this one to happen if the user-level ! * cleanup fails. ! */ ! static void ! ShutdownPostgres(void) { /* ! * 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 spinlocks that we may hold. This is a kluge to improve ! * the odds that we won't get into a self-made stuck spinlock scenario ! * while trying to shut down. */ ! ProcReleaseSpins(NULL); ! /* ! * 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. ! */ ! smgrDoPendingDeletes(false); /* delete as though aborting xact */ } *** src/include/access/xlog.h.orig Sun Dec 3 11:11:19 2000 --- src/include/access/xlog.h Sun Dec 17 17:11:56 2000 *************** *** 88,94 **** extern StartUpID ThisStartUpID; /* current SUI */ extern bool InRecovery; extern XLogRecPtr MyLastRecPtr; ! extern uint32 StopIfError; typedef struct RmgrData { --- 88,94 ---- extern StartUpID ThisStartUpID; /* current SUI */ extern bool InRecovery; extern XLogRecPtr MyLastRecPtr; ! extern uint32 CritSectionCount; typedef struct RmgrData { *** src/include/commands/trigger.h.orig Thu Jun 8 21:14:37 2000 --- src/include/commands/trigger.h Sun Dec 17 17:12:17 2000 *************** *** 129,135 **** typedef struct DeferredTriggerEventData *DeferredTriggerEvent; ! extern int DeferredTriggerInit(void); extern void DeferredTriggerBeginXact(void); extern void DeferredTriggerEndQuery(void); extern void DeferredTriggerEndXact(void); --- 129,135 ---- typedef struct DeferredTriggerEventData *DeferredTriggerEvent; ! extern void DeferredTriggerInit(void); extern void DeferredTriggerBeginXact(void); extern void DeferredTriggerEndQuery(void); extern void DeferredTriggerEndXact(void); *** src/include/libpq/libpq.h.orig Mon Nov 13 20:37:52 2000 --- src/include/libpq/libpq.h Sun Dec 17 17:13:11 2000 *************** *** 60,66 **** extern int StreamConnection(int server_fd, Port *port); extern void StreamClose(int sock); extern void pq_init(void); - extern void pq_close(void); extern int pq_getbytes(char *s, size_t len); extern int pq_getstring(StringInfo s); extern int pq_peekbyte(void); --- 60,65 ---- *** src/include/storage/bufmgr.h.orig Thu Nov 30 10:15:17 2000 --- src/include/storage/bufmgr.h Sun Dec 17 18:30:23 2000 *************** *** 168,173 **** --- 168,174 ---- extern int FlushBuffer(Buffer buffer, bool sync, bool release); extern void InitBufferPool(void); + extern void InitBufferPoolAccess(void); extern void PrintBufferUsage(FILE *statfp); extern void ResetBufferUsage(void); extern void ResetBufferPool(bool isCommit); *** src/include/utils/elog.h.orig Wed Dec 6 12:25:45 2000 --- src/include/utils/elog.h Sun Dec 17 17:13:19 2000 *************** *** 28,51 **** #endif /* ! * If StopIfError > 0 signal handlers mustn't do * elog(ERROR|FATAL), instead remember what action is ! * required with QueryCancel & ExitAfterAbort. */ ! extern uint32 StopIfError; /* duplicates access/xlog.h */ extern bool QueryCancel; /* duplicates miscadmin.h */ ! extern bool ExitAfterAbort; ! #define START_CRIT_CODE (StopIfError++) #define END_CRIT_CODE \ do { \ ! if (!StopIfError) \ elog(STOP, "Not in critical section"); \ ! StopIfError--; \ ! if (!StopIfError && QueryCancel) \ { \ ! if (ExitAfterAbort) \ elog(FATAL, "The system is shutting down"); \ else \ elog(ERROR, "Query was cancelled."); \ --- 28,51 ---- #endif /* ! * If CritSectionCount > 0, signal handlers mustn't do * elog(ERROR|FATAL), instead remember what action is ! * required with QueryCancel & ProcDiePending. */ ! extern uint32 CritSectionCount; /* duplicates access/xlog.h */ extern bool QueryCancel; /* duplicates miscadmin.h */ ! extern bool ProcDiePending; ! #define START_CRIT_CODE (CritSectionCount++) #define END_CRIT_CODE \ do { \ ! if (CritSectionCount == 0) \ elog(STOP, "Not in critical section"); \ ! CritSectionCount--; \ ! if (CritSectionCount == 0 && QueryCancel) \ { \ ! if (ProcDiePending) \ elog(FATAL, "The system is shutting down"); \ else \ elog(ERROR, "Query was cancelled."); \
pgsql-patches by date: