Commit a626b78c authored by Tom Lane's avatar Tom Lane

Clean up backend-exit-time cleanup behavior. Use on_shmem_exit callbacks

to ensure that we have released buffer refcounts and so forth, rather than
putting ad-hoc operations before (some of the calls to) proc_exit.  Add
commentary to discourage future hackers from repeating that mistake.
parent 8c8ed4f4
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.88 2000/12/07 10:03:46 inoue Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.89 2000/12/18 00:44:45 tgl Exp $
* *
* NOTES * NOTES
* Transaction aborts can now occur two ways: * Transaction aborts can now occur two ways:
...@@ -1095,6 +1095,15 @@ AbortTransaction(void) ...@@ -1095,6 +1095,15 @@ AbortTransaction(void)
MyProc->xmin = InvalidTransactionId; 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 * check the current transaction state
* ---------------- * ----------------
...@@ -1105,18 +1114,6 @@ AbortTransaction(void) ...@@ -1105,18 +1114,6 @@ AbortTransaction(void)
if (s->state != TRANS_INPROGRESS) if (s->state != TRANS_INPROGRESS)
elog(NOTICE, "AbortTransaction and not in in-progress state"); 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 * set the current transaction state information
* appropriately during the abort processing * appropriately during the abort processing
...@@ -1124,12 +1121,17 @@ AbortTransaction(void) ...@@ -1124,12 +1121,17 @@ AbortTransaction(void)
*/ */
s->state = TRANS_ABORT; s->state = TRANS_ABORT;
/*
* Reset user id which might have been changed transiently
*/
SetUserId(GetSessionUserId());
/* ---------------- /* ----------------
* do abort processing * do abort processing
* ---------------- * ----------------
*/ */
DeferredTriggerAbortXact();
lo_commit(false); /* 'false' means it's abort */ lo_commit(false); /* 'false' means it's abort */
UnlockBuffers();
AtAbort_Notify(); AtAbort_Notify();
CloseSequences(); CloseSequences();
AtEOXact_portals(); AtEOXact_portals();
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.42 2000/12/11 19:27:42 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.43 2000/12/18 00:44:45 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
int XLOGbuffers = 8; int XLOGbuffers = 8;
XLogRecPtr MyLastRecPtr = {0, 0}; XLogRecPtr MyLastRecPtr = {0, 0};
uint32 StopIfError = 0; uint32 CritSectionCount = 0;
bool InRecovery = false; bool InRecovery = false;
StartUpID ThisStartUpID = 0; StartUpID ThisStartUpID = 0;
...@@ -1531,7 +1531,7 @@ StartupXLOG() ...@@ -1531,7 +1531,7 @@ StartupXLOG()
char buffer[MAXLOGRECSZ + SizeOfXLogRecord]; char buffer[MAXLOGRECSZ + SizeOfXLogRecord];
elog(LOG, "starting up"); elog(LOG, "starting up");
StopIfError++; CritSectionCount++;
XLogCtl->xlblocks = (XLogRecPtr *) (((char *) XLogCtl) + sizeof(XLogCtlData)); XLogCtl->xlblocks = (XLogRecPtr *) (((char *) XLogCtl) + sizeof(XLogCtlData));
XLogCtl->pages = ((char *) XLogCtl->xlblocks + sizeof(XLogRecPtr) * XLOGbuffers); XLogCtl->pages = ((char *) XLogCtl->xlblocks + sizeof(XLogRecPtr) * XLOGbuffers);
...@@ -1748,7 +1748,7 @@ StartupXLOG() ...@@ -1748,7 +1748,7 @@ StartupXLOG()
XLogCtl->ThisStartUpID = ThisStartUpID; XLogCtl->ThisStartUpID = ThisStartUpID;
elog(LOG, "database system is in production state"); elog(LOG, "database system is in production state");
StopIfError--; CritSectionCount--;
return; return;
} }
...@@ -1771,10 +1771,10 @@ ShutdownXLOG() ...@@ -1771,10 +1771,10 @@ ShutdownXLOG()
{ {
elog(LOG, "shutting down"); elog(LOG, "shutting down");
StopIfError++; CritSectionCount++;
CreateDummyCaches(); CreateDummyCaches();
CreateCheckPoint(true); CreateCheckPoint(true);
StopIfError--; CritSectionCount--;
elog(LOG, "database system is shut down"); elog(LOG, "database system is shut down");
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.81 2000/11/20 20:36:47 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.82 2000/12/18 00:44:46 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1432,7 +1432,7 @@ deferredTriggerInvokeEvents(bool immediate_only) ...@@ -1432,7 +1432,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
* transactions. * transactions.
* ---------- * ----------
*/ */
int void
DeferredTriggerInit(void) DeferredTriggerInit(void)
{ {
deftrig_gcxt = AllocSetContextCreate(TopMemoryContext, deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
...@@ -1440,8 +1440,6 @@ DeferredTriggerInit(void) ...@@ -1440,8 +1440,6 @@ DeferredTriggerInit(void)
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
return 0;
} }
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pqcomm.c,v 1.114 2000/11/29 20:59:51 tgl Exp $ * $Id: pqcomm.c,v 1.115 2000/12/18 00:44:46 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -85,6 +85,9 @@ ...@@ -85,6 +85,9 @@
#endif #endif
static void pq_close(void);
/* /*
* Configuration options * Configuration options
*/ */
...@@ -122,6 +125,7 @@ pq_init(void) ...@@ -122,6 +125,7 @@ pq_init(void)
{ {
PqSendPointer = PqRecvPointer = PqRecvLength = 0; PqSendPointer = PqRecvPointer = PqRecvLength = 0;
DoingCopyOut = false; DoingCopyOut = false;
on_proc_exit(pq_close, 0);
} }
...@@ -132,7 +136,7 @@ pq_init(void) ...@@ -132,7 +136,7 @@ pq_init(void)
* don't crash during exit... * don't crash during exit...
* -------------------------------- * --------------------------------
*/ */
void static void
pq_close(void) pq_close(void)
{ {
if (MyProcPort != NULL) if (MyProcPort != NULL)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.39 2000/11/30 01:39:07 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.40 2000/12/18 00:44:46 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#include "utils/hsearch.h" #include "utils/hsearch.h"
#include "utils/memutils.h" #include "utils/memutils.h"
static void ShutdownBufferPoolAccess(void);
/* /*
* if BMTRACE is defined, we trace the last 200 buffer allocations and * if BMTRACE is defined, we trace the last 200 buffer allocations and
* deallocations in a circular buffer in shared memory. * deallocations in a circular buffer in shared memory.
...@@ -73,7 +76,7 @@ bool *BufferDirtiedByMe; /* T if buf has been dirtied in cur xact */ ...@@ -73,7 +76,7 @@ bool *BufferDirtiedByMe; /* T if buf has been dirtied in cur xact */
* Two important notes. First, the buffer has to be * Two important notes. First, the buffer has to be
* available for lookup BEFORE an IO begins. Otherwise * available for lookup BEFORE an IO begins. Otherwise
* a second process trying to read the buffer will * a second process trying to read the buffer will
* allocate its own copy and the buffeer pool will * allocate its own copy and the buffer pool will
* become inconsistent. * become inconsistent.
* *
* Buffer Replacement: * Buffer Replacement:
...@@ -126,10 +129,10 @@ long int LocalBufferFlushCount; ...@@ -126,10 +129,10 @@ long int LocalBufferFlushCount;
/* /*
* Initialize module: called once during shared-memory initialization * Initialize shared buffer pool
* *
* should calculate size of pool dynamically based on the * This is called once during shared-memory initialization (either in the
* amount of available memory. * postmaster, or in a standalone backend).
*/ */
void void
InitBufferPool(void) InitBufferPool(void)
...@@ -144,6 +147,10 @@ InitBufferPool(void) ...@@ -144,6 +147,10 @@ InitBufferPool(void)
Lookup_List_Descriptor = Data_Descriptors + 1; Lookup_List_Descriptor = Data_Descriptors + 1;
Num_Descriptors = 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); SpinAcquire(BufMgrLock);
#ifdef BMTRACE #ifdef BMTRACE
...@@ -203,12 +210,28 @@ InitBufferPool(void) ...@@ -203,12 +210,28 @@ InitBufferPool(void)
BufferDescriptors[Data_Descriptors - 1].freeNext = 0; BufferDescriptors[Data_Descriptors - 1].freeNext = 0;
} }
/* Init the rest of the module */ /* Init other shared buffer-management stuff */
InitBufTable(); InitBufTable();
InitFreeList(!foundDescs); InitFreeList(!foundDescs);
SpinRelease(BufMgrLock); 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)); BufferBlockPointers = (Block *) calloc(NBuffers, sizeof(Block));
PrivateRefCount = (long *) calloc(NBuffers, sizeof(long)); PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
BufferLocks = (bits8 *) calloc(NBuffers, sizeof(bits8)); BufferLocks = (bits8 *) calloc(NBuffers, sizeof(bits8));
...@@ -224,6 +247,27 @@ InitBufferPool(void) ...@@ -224,6 +247,27 @@ InitBufferPool(void)
{ {
BufferBlockPointers[i] = (Block) MAKE_PTR(BufferDescriptors[i].data); 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);
} }
/* ----------------------------------------------------- /* -----------------------------------------------------
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.86 2000/12/11 16:35:59 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.87 2000/12/18 00:44:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,7 +29,8 @@ ...@@ -29,7 +29,8 @@
* *
* Interface (b): * Interface (b):
* *
* ProcReleaseLocks -- frees the locks associated with this process, * ProcReleaseLocks -- frees the locks associated with current transaction
*
* ProcKill -- destroys the shared memory state (and locks) * ProcKill -- destroys the shared memory state (and locks)
* associated with the process. * associated with the process.
* *
...@@ -47,7 +48,7 @@ ...@@ -47,7 +48,7 @@
* This is so that we can support more backends. (system-wide semaphore * This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95 * sets run out pretty fast.) -ay 4/95
* *
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.86 2000/12/11 16:35:59 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.87 2000/12/18 00:44:47 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -332,7 +333,7 @@ GetOffWaitqueue(PROC *proc) ...@@ -332,7 +333,7 @@ GetOffWaitqueue(PROC *proc)
} }
/* /*
* ProcReleaseLocks() -- release all locks associated with this process * ProcReleaseLocks() -- release all locks associated with current transaction
* *
*/ */
void void
...@@ -340,7 +341,7 @@ ProcReleaseLocks() ...@@ -340,7 +341,7 @@ ProcReleaseLocks()
{ {
if (!MyProc) if (!MyProc)
return; return;
LockReleaseAll(1, &MyProc->lockQueue); LockReleaseAll(DEFAULT_LOCKMETHOD, &MyProc->lockQueue);
GetOffWaitqueue(MyProc); GetOffWaitqueue(MyProc);
} }
...@@ -423,8 +424,6 @@ ProcKill(int exitStatus, Datum pid) ...@@ -423,8 +424,6 @@ ProcKill(int exitStatus, Datum pid)
* ---------------- * ----------------
*/ */
GetOffWaitqueue(proc); GetOffWaitqueue(proc);
return;
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.194 2000/12/03 10:27:27 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.195 2000/12/18 00:44:47 tgl Exp $
* *
* NOTES * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -61,7 +61,6 @@ ...@@ -61,7 +61,6 @@
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/ps_status.h" #include "utils/ps_status.h"
#include "utils/temprel.h"
#ifdef MULTIBYTE #ifdef MULTIBYTE
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#endif #endif
...@@ -95,7 +94,7 @@ DLLIMPORT sigjmp_buf Warn_restart; ...@@ -95,7 +94,7 @@ DLLIMPORT sigjmp_buf Warn_restart;
bool Warn_restart_ready = false; bool Warn_restart_ready = false;
bool InError = false; bool InError = false;
bool ExitAfterAbort = false; bool ProcDiePending = false;
static bool EchoQuery = false; /* default don't echo */ static bool EchoQuery = false; /* default don't echo */
char pg_pathname[MAXPGPATH]; char pg_pathname[MAXPGPATH];
...@@ -921,7 +920,8 @@ finish_xact_command(void) ...@@ -921,7 +920,8 @@ finish_xact_command(void)
void void
handle_warn(SIGNAL_ARGS) handle_warn(SIGNAL_ARGS)
{ {
if (StopIfError) /* Don't joggle the elbow of a critical section */
if (CritSectionCount > 0)
{ {
QueryCancel = true; QueryCancel = true;
return; return;
...@@ -958,13 +958,15 @@ die(SIGNAL_ARGS) ...@@ -958,13 +958,15 @@ die(SIGNAL_ARGS)
{ {
PG_SETMASK(&BlockSig); PG_SETMASK(&BlockSig);
ExitAfterAbort = true; /* Don't joggle the elbow of a critical section */
if (StopIfError) if (CritSectionCount > 0)
{ {
QueryCancel = true; QueryCancel = true;
ProcDiePending = true;
return; return;
} }
if (InError) /* If ERROR/FATAL is in progress... */ /* Don't joggle the elbow of proc_exit, either */
if (proc_exit_inprogress)
return; return;
elog(FATAL, "The system is shutting down"); elog(FATAL, "The system is shutting down");
} }
...@@ -1096,6 +1098,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1096,6 +1098,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
MemoryContextInit(); MemoryContextInit();
} }
SetProcessingMode(InitProcessing);
/* /*
* Set default values for command-line options. * Set default values for command-line options.
*/ */
...@@ -1109,8 +1113,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1109,8 +1113,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
} }
StatFp = stderr; StatFp = stderr;
SetProcessingMode(InitProcessing);
/* Check for PGDATESTYLE environment variable */ /* Check for PGDATESTYLE environment variable */
set_default_datestyle(); set_default_datestyle();
...@@ -1428,11 +1430,16 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1428,11 +1430,16 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
break; 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 && if (Show_query_stats &&
(Show_parser_stats || Show_planner_stats || Show_executor_stats)) (Show_parser_stats || Show_planner_stats || Show_executor_stats))
{ {
elog(NOTICE, "Query statistics are disabled because parser, planner, or executor statistics are on."); fprintf(stderr, "Query statistics are disabled because parser, planner, or executor statistics are on.\n");
Show_query_stats = false; Show_query_stats = false;
} }
...@@ -1528,7 +1535,13 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1528,7 +1535,13 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
XLOGPathInit(); XLOGPathInit();
BaseInit(); BaseInit();
/*
* Start up xlog for standalone backend, and register to have it
* closed down at exit.
*/
StartupXLOG(); StartupXLOG();
on_shmem_exit(ShutdownXLOG, 0);
} }
/* /*
...@@ -1602,20 +1615,17 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1602,20 +1615,17 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
remote_host, username, DBName); remote_host, username, DBName);
/* /*
* general initialization * 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) if (DebugLvl > 1)
elog(DEBUG, "InitPostgres"); elog(DEBUG, "InitPostgres");
InitPostgres(DBName, username); InitPostgres(DBName, username);
#ifdef MULTIBYTE SetProcessingMode(NormalProcessing);
/* 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. * Send this backend's cancellation info to the frontend.
...@@ -1636,17 +1646,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1636,17 +1646,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.194 $ $Date: 2000/12/03 10:27:27 $\n"); puts("$Revision: 1.195 $ $Date: 2000/12/18 00:44:47 $\n");
} }
/*
* Initialize the deferred trigger manager
*/
if (DeferredTriggerInit() != 0)
goto normalexit;
SetProcessingMode(NormalProcessing);
/* /*
* Create the memory context we will use in the main loop. * Create the memory context we will use in the main loop.
* *
...@@ -1671,6 +1673,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1671,6 +1673,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
if (sigsetjmp(Warn_restart, 1) != 0) 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. * Make sure we are in a valid memory context during recovery.
* *
* We use ErrorContext in hopes that it will have some free space * We use ErrorContext in hopes that it will have some free space
...@@ -1678,19 +1684,22 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1678,19 +1684,22 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
*/ */
MemoryContextSwitchTo(ErrorContext); MemoryContextSwitchTo(ErrorContext);
/* Do the recovery */
if (DebugLvl >= 1) if (DebugLvl >= 1)
elog(DEBUG, "AbortCurrentTransaction"); elog(DEBUG, "AbortCurrentTransaction");
AbortCurrentTransaction(); AbortCurrentTransaction();
if (ExitAfterAbort)
goto errorexit;
/* /*
* If we recovered successfully, return to normal top-level context * Now return to normal top-level context and clear ErrorContext
* and clear ErrorContext for next time. * for next time.
*/ */
MemoryContextSwitchTo(TopMemoryContext); MemoryContextSwitchTo(TopMemoryContext);
MemoryContextResetAndDeleteChildren(ErrorContext); 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; InError = false;
} }
...@@ -1775,7 +1784,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1775,7 +1784,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
if (HandleFunctionRequest() == EOF) if (HandleFunctionRequest() == EOF)
{ {
/* lost frontend connection during F message input */ /* lost frontend connection during F message input */
goto normalexit; proc_exit(0);
} }
/* commit the function-invocation transaction */ /* commit the function-invocation transaction */
...@@ -1830,7 +1839,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1830,7 +1839,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
*/ */
case 'X': case 'X':
case EOF: case EOF:
goto normalexit; /*
* 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: default:
elog(ERROR, "unknown frontend message was received"); elog(ERROR, "unknown frontend message was received");
...@@ -1845,16 +1861,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1845,16 +1861,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
#endif #endif
} /* end of input-reading loop */ } /* end of input-reading loop */
normalexit: /* can't get here because the above loop never exits */
ExitAfterAbort = true; /* ensure we will exit if elog during abort */ Assert(false);
AbortOutOfAnyTransaction();
if (!IsUnderPostmaster)
ShutdownXLOG();
errorexit:
pq_close();
ProcReleaseLocks(); /* Just to be sure... */
proc_exit(0);
return 1; /* keep compiler quiet */ return 1; /* keep compiler quiet */
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.73 2000/12/06 17:25:46 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.74 2000/12/18 00:44:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -159,7 +159,7 @@ elog(int lev, const char *fmt, ...) ...@@ -159,7 +159,7 @@ elog(int lev, const char *fmt, ...)
/* this is probably redundant... */ /* this is probably redundant... */
if (IsInitProcessingMode()) if (IsInitProcessingMode())
lev = FATAL; lev = FATAL;
if (StopIfError) if (CritSectionCount > 0)
lev = STOP; lev = STOP;
} }
...@@ -445,21 +445,26 @@ elog(int lev, const char *fmt, ...) ...@@ -445,21 +445,26 @@ elog(int lev, const char *fmt, ...)
{ {
/* /*
* 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 * If we have not yet entered the main backend loop (ie, we are in
* the postmaster or in backend startup), then go directly to * the postmaster or in backend startup), we also go directly to
* proc_exit. The same is true if anyone tries to report an error * 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 * after proc_exit has begun to run. (It's proc_exit's
* responsibility to see that this doesn't turn into infinite * responsibility to see that this doesn't turn into infinite
* recursion!) But in the latter case, we exit with nonzero exit * recursion!) But in the latter case, we exit with nonzero exit
* code to indicate that something's pretty wrong. * code to indicate that something's pretty wrong.
*/ */
if (proc_exit_inprogress || !Warn_restart_ready) 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(stdout);
fflush(stderr); 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); proc_exit((int) proc_exit_inprogress);
} }
...@@ -471,13 +476,8 @@ elog(int lev, const char *fmt, ...) ...@@ -471,13 +476,8 @@ elog(int lev, const char *fmt, ...)
InError = true; InError = true;
/* /*
* Otherwise we can return to the main loop in postgres.c. In the * Otherwise we can return to the main loop in postgres.c.
* 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); siglongjmp(Warn_restart, 1);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.75 2000/12/14 23:51:35 wieck Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.76 2000/12/18 00:44:48 tgl Exp $
* *
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "commands/trigger.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/backendid.h" #include "storage/backendid.h"
#include "storage/proc.h" #include "storage/proc.h"
...@@ -37,6 +38,7 @@ ...@@ -37,6 +38,7 @@
#include "utils/portal.h" #include "utils/portal.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/temprel.h"
#ifdef MULTIBYTE #ifdef MULTIBYTE
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
...@@ -44,6 +46,9 @@ ...@@ -44,6 +46,9 @@
static void ReverifyMyDatabase(const char *name); static void ReverifyMyDatabase(const char *name);
static void InitCommunication(void); static void InitCommunication(void);
static void ShutdownPostgres(void);
int lockingOff = 0; /* backend -L switch */
/*** InitPostgres support ***/ /*** InitPostgres support ***/
...@@ -115,12 +120,8 @@ ReverifyMyDatabase(const char *name) ...@@ -115,12 +120,8 @@ ReverifyMyDatabase(const char *name)
*/ */
dbform = (Form_pg_database) GETSTRUCT(tup); dbform = (Form_pg_database) GETSTRUCT(tup);
if (! dbform->datallowconn) if (! dbform->datallowconn)
{
heap_endscan(pgdbscan);
heap_close(pgdbrel, AccessShareLock);
elog(FATAL, "Database \"%s\" is not currently accepting connections", elog(FATAL, "Database \"%s\" is not currently accepting connections",
name); name);
}
/* /*
* OK, we're golden. Only other to-do item is to save the MULTIBYTE * OK, we're golden. Only other to-do item is to save the MULTIBYTE
...@@ -163,6 +164,28 @@ InitCommunication(void) ...@@ -163,6 +164,28 @@ InitCommunication(void)
} }
/*
* 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 * InitPostgres
...@@ -172,16 +195,13 @@ InitCommunication(void) ...@@ -172,16 +195,13 @@ InitCommunication(void)
* Be very careful with the order of calls in the InitPostgres function. * Be very careful with the order of calls in the InitPostgres function.
* -------------------------------- * --------------------------------
*/ */
int lockingOff = 0; /* backend -L switch */
/*
*/
void void
InitPostgres(const char *dbname, const char *username) InitPostgres(const char *dbname, const char *username)
{ {
bool bootstrap = IsBootstrapProcessingMode(); bool bootstrap = IsBootstrapProcessingMode();
SetDatabaseName(dbname); SetDatabaseName(dbname);
/* ---------------- /* ----------------
* initialize the database id used for system caches and lock tables * initialize the database id used for system caches and lock tables
* ---------------- * ----------------
...@@ -299,6 +319,12 @@ InitPostgres(const char *dbname, const char *username) ...@@ -299,6 +319,12 @@ InitPostgres(const char *dbname, const char *username)
*/ */
InitCatalogCache(); InitCatalogCache();
/*
* Initialize the deferred trigger manager --- must happen before
* first transaction start.
*/
DeferredTriggerInit();
/* start a new transaction here before access to db */ /* start a new transaction here before access to db */
if (!bootstrap) if (!bootstrap)
StartTransactionCommand(); StartTransactionCommand();
...@@ -322,27 +348,62 @@ InitPostgres(const char *dbname, const char *username) ...@@ -322,27 +348,62 @@ InitPostgres(const char *dbname, const char *username)
/* /*
* Unless we are bootstrapping, double-check that InitMyDatabaseInfo() * Unless we are bootstrapping, double-check that InitMyDatabaseInfo()
* got a correct result. We can't do this until essentially all the * got a correct result. We can't do this until all the database-access
* infrastructure is up, so just do it at the end. * infrastructure is up.
*/ */
if (!bootstrap) if (!bootstrap)
ReverifyMyDatabase(dbname); ReverifyMyDatabase(dbname);
}
void #ifdef MULTIBYTE
BaseInit(void) /* set default client encoding --- uses info from ReverifyMyDatabase */
{ set_default_client_encoding();
#endif
/* /*
* Attach to shared memory and semaphores, and initialize our * Set up process-exit callbacks to remove temp relations and then
* input/output/debugging file descriptors. * 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!
*/ */
InitCommunication(); on_shmem_exit(ShutdownPostgres, 0);
DebugFileOpen(); /* because callbacks are called in reverse order, this gets done first: */
on_shmem_exit(remove_all_temp_relations, 0);
smgrinit();
EnablePortalManager(); /* memory for portal/transaction stuff */ /* close the transaction we started above */
if (!bootstrap)
CommitTransactionCommand();
}
/* initialize the local buffer manager */ /*
InitLocalBuffer(); * 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 */
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* PostgreSQL transaction log manager * PostgreSQL transaction log manager
* *
* $Header: /cvsroot/pgsql/src/include/access/xlog.h,v 1.13 2000/12/03 10:27:28 vadim Exp $ * $Header: /cvsroot/pgsql/src/include/access/xlog.h,v 1.14 2000/12/18 00:44:48 tgl Exp $
*/ */
#ifndef XLOG_H #ifndef XLOG_H
#define XLOG_H #define XLOG_H
...@@ -88,7 +88,7 @@ typedef XLogPageHeaderData *XLogPageHeader; ...@@ -88,7 +88,7 @@ typedef XLogPageHeaderData *XLogPageHeader;
extern StartUpID ThisStartUpID; /* current SUI */ extern StartUpID ThisStartUpID; /* current SUI */
extern bool InRecovery; extern bool InRecovery;
extern XLogRecPtr MyLastRecPtr; extern XLogRecPtr MyLastRecPtr;
extern uint32 StopIfError; extern uint32 CritSectionCount;
typedef struct RmgrData typedef struct RmgrData
{ {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: trigger.h,v 1.21 2000/06/08 22:37:42 momjian Exp $ * $Id: trigger.h,v 1.22 2000/12/18 00:44:48 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -129,7 +129,7 @@ typedef struct DeferredTriggerEventData ...@@ -129,7 +129,7 @@ typedef struct DeferredTriggerEventData
typedef struct DeferredTriggerEventData *DeferredTriggerEvent; typedef struct DeferredTriggerEventData *DeferredTriggerEvent;
extern int DeferredTriggerInit(void); extern void DeferredTriggerInit(void);
extern void DeferredTriggerBeginXact(void); extern void DeferredTriggerBeginXact(void);
extern void DeferredTriggerEndQuery(void); extern void DeferredTriggerEndQuery(void);
extern void DeferredTriggerEndXact(void); extern void DeferredTriggerEndXact(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: libpq.h,v 1.41 2000/11/14 01:15:04 momjian Exp $ * $Id: libpq.h,v 1.42 2000/12/18 00:44:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -60,7 +60,6 @@ extern int StreamServerPort(int family, char *hostName, ...@@ -60,7 +60,6 @@ extern int StreamServerPort(int family, char *hostName,
extern int StreamConnection(int server_fd, Port *port); extern int StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock); extern void StreamClose(int sock);
extern void pq_init(void); extern void pq_init(void);
extern void pq_close(void);
extern int pq_getbytes(char *s, size_t len); extern int pq_getbytes(char *s, size_t len);
extern int pq_getstring(StringInfo s); extern int pq_getstring(StringInfo s);
extern int pq_peekbyte(void); extern int pq_peekbyte(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: bufmgr.h,v 1.46 2000/11/30 08:46:26 vadim Exp $ * $Id: bufmgr.h,v 1.47 2000/12/18 00:44:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -168,6 +168,7 @@ extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, ...@@ -168,6 +168,7 @@ extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation,
extern int FlushBuffer(Buffer buffer, bool sync, bool release); extern int FlushBuffer(Buffer buffer, bool sync, bool release);
extern void InitBufferPool(void); extern void InitBufferPool(void);
extern void InitBufferPoolAccess(void);
extern void PrintBufferUsage(FILE *statfp); extern void PrintBufferUsage(FILE *statfp);
extern void ResetBufferUsage(void); extern void ResetBufferUsage(void);
extern void ResetBufferPool(bool isCommit); extern void ResetBufferPool(bool isCommit);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: elog.h,v 1.20 2000/12/06 17:25:45 tgl Exp $ * $Id: elog.h,v 1.21 2000/12/18 00:44:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -28,24 +28,24 @@ extern int Use_syslog; ...@@ -28,24 +28,24 @@ extern int Use_syslog;
#endif #endif
/* /*
* If StopIfError > 0 signal handlers mustn't do * If CritSectionCount > 0, signal handlers mustn't do
* elog(ERROR|FATAL), instead remember what action is * elog(ERROR|FATAL), instead remember what action is
* required with QueryCancel & ExitAfterAbort. * required with QueryCancel & ProcDiePending.
*/ */
extern uint32 StopIfError; /* duplicates access/xlog.h */ extern uint32 CritSectionCount; /* duplicates access/xlog.h */
extern bool QueryCancel; /* duplicates miscadmin.h */ extern bool QueryCancel; /* duplicates miscadmin.h */
extern bool ExitAfterAbort; extern bool ProcDiePending;
#define START_CRIT_CODE (StopIfError++) #define START_CRIT_CODE (CritSectionCount++)
#define END_CRIT_CODE \ #define END_CRIT_CODE \
do { \ do { \
if (!StopIfError) \ if (CritSectionCount == 0) \
elog(STOP, "Not in critical section"); \ elog(STOP, "Not in critical section"); \
StopIfError--; \ CritSectionCount--; \
if (!StopIfError && QueryCancel) \ if (CritSectionCount == 0 && QueryCancel) \
{ \ { \
if (ExitAfterAbort) \ if (ProcDiePending) \
elog(FATAL, "The system is shutting down"); \ elog(FATAL, "The system is shutting down"); \
else \ else \
elog(ERROR, "Query was cancelled."); \ elog(ERROR, "Query was cancelled."); \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment