Skip site navigation (1) Skip section navigation (2)

Re: Cleaning up backend-exit cleanup

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: pgsql-patches(at)postgreSQL(dot)org
Subject: Re: Cleaning up backend-exit cleanup
Date: 2000-12-18 00:50:04
Message-ID: 8368.977100604@sss.pgh.pa.us (view raw or flat)
Thread:
Lists: 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

Next:From: Ronald GuestDate: 2000-12-18 01:47:06
Subject: --enable-odbc issue for Darwin/Mac OS X
Previous:From: Tom LaneDate: 2000-12-17 02:43:18
Subject: Re: Bug fix

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group