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."); \