Beispiel #1
0
/*
 * 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 LW locks and buffer context locks we might be holding.
	 * This is a kluge to improve the odds that we won't get into a
	 * self-made stuck-lock scenario while trying to shut down.
	 */
	LWLockReleaseAll();
	AbortBufferIO();
	UnlockBuffers();

	/*
	 * 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 */
}
Beispiel #2
0
/*
 * AtSubAbort_smgr() --- Take care of subtransaction abort.
 *
 * Delete created relations and forget about deleted relations.
 * We can execute these operations immediately because we know this
 * subtransaction will not commit.
 */
void
AtSubAbort_smgr(void)
{
	smgrDoPendingDeletes(false);
}
Beispiel #3
0
/*
 *	CommitTransaction
 */
static void
CommitTransaction(void)
{
	TransactionState s = CurrentTransactionState;

	/*
	 * check the current transaction state
	 */
	if (s->state != TRANS_INPROGRESS)
		elog(WARNING, "CommitTransaction and not in in-progress state");

	/*
	 * Do pre-commit processing (most of this stuff requires database
	 * access, and in fact could still cause an error...)
	 */

	/*
	 * Tell the trigger manager that this transaction is about to be
	 * committed. He'll invoke all trigger deferred until XACT before we
	 * really start on committing the transaction.
	 */
	DeferredTriggerEndXact();

	/* Close open cursors */
	AtCommit_Portals();

	/*
	 * Let ON COMMIT management do its thing (must happen after closing
	 * cursors, to avoid dangling-reference problems)
	 */
	PreCommit_on_commit_actions();

	/* handle commit for large objects [ PA, 7/17/98 ] */
	/* XXX probably this does not belong here */
	lo_commit(true);

	/* NOTIFY commit must come before lower-level cleanup */
	AtCommit_Notify();

	/* Update the flat password file if we changed pg_shadow or pg_group */
	AtEOXact_UpdatePasswordFile(true);

	/* Prevent cancel/die interrupt while cleaning up */
	HOLD_INTERRUPTS();

	/*
	 * set the current transaction state information appropriately during
	 * the abort processing
	 */
	s->state = TRANS_COMMIT;

	/*
	 * Here is where we really truly commit.
	 */
	RecordTransactionCommit();

	/*
	 * Let others know about no transaction in progress by me. Note that
	 * this must be done _before_ releasing locks we hold and _after_
	 * RecordTransactionCommit.
	 *
	 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
	 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
	 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
	 * as running as well or it will see two tuple versions - one deleted
	 * by xid 1 and one inserted by xid 0.	See notes in GetSnapshotData.
	 */
	if (MyProc != (PGPROC *) NULL)
	{
		/* Lock SInvalLock because that's what GetSnapshotData uses. */
		LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
		MyProc->xid = InvalidTransactionId;
		MyProc->xmin = InvalidTransactionId;
		LWLockRelease(SInvalLock);
	}

	/*
	 * This is all post-commit cleanup.  Note that if an error is raised
	 * here, it's too late to abort the transaction.  This should be just
	 * noncritical resource releasing.
	 *
	 * The ordering of operations is not entirely random.  The idea is:
	 * release resources visible to other backends (eg, files, buffer
	 * pins); then release locks; then release backend-local resources. We
	 * want to release locks at the point where any backend waiting for us
	 * will see our transaction as being fully cleaned up.
	 */

	smgrDoPendingDeletes(true);
	AtCommit_Cache();
	AtEOXact_Buffers(true);
	/* smgrcommit already done */

	AtCommit_Locks();

	CallEOXactCallbacks(true);
	AtEOXact_GUC(true);
	AtEOXact_SPI();
	AtEOXact_gist();
	AtEOXact_hash();
	AtEOXact_nbtree();
	AtEOXact_rtree();
	AtEOXact_on_commit_actions(true);
	AtEOXact_Namespace(true);
	AtEOXact_CatCache(true);
	AtEOXact_Files();
	pgstat_count_xact_commit();
	AtCommit_Memory();

	/*
	 * done with commit processing, set current transaction state back to
	 * default
	 */
	s->state = TRANS_DEFAULT;

	RESUME_INTERRUPTS();
}
Beispiel #4
0
/*
 *	AbortTransaction
 */
static void
AbortTransaction(void)
{
	TransactionState s = CurrentTransactionState;

	/* Prevent cancel/die interrupt while cleaning up */
	HOLD_INTERRUPTS();

	/*
	 * Release any LW locks we might be holding as quickly as possible.
	 * (Regular locks, however, must be held till we finish aborting.)
	 * Releasing LW locks is critical since we might try to grab them
	 * again while cleaning up!
	 */
	LWLockReleaseAll();

	/* Clean up buffer I/O and buffer context locks, too */
	AbortBufferIO();
	UnlockBuffers();

	/*
	 * Also clean up any open wait for lock, since the lock manager will
	 * choke if we try to wait for another lock before doing this.
	 */
	LockWaitCancel();

	/*
	 * check the current transaction state
	 *
	 * reduced to DEBUG2 because this is expected when rejecting an
	 * invalidly-encoded query outside a transaction block.  PG 8.0
	 * and up fix it better, but it's not worth back-porting those
	 * changes to 7.4.
	 */
	if (s->state != TRANS_INPROGRESS)
		elog(DEBUG2, "AbortTransaction and not in in-progress state");

	/*
	 * set the current transaction state information appropriately during
	 * the abort processing
	 */
	s->state = TRANS_ABORT;

	/* Make sure we are in a valid memory context */
	AtAbort_Memory();

	/*
	 * Reset user id which might have been changed transiently
	 */
	SetUserId(GetSessionUserId());

	/*
	 * do abort processing
	 */
	DeferredTriggerAbortXact();
	AtAbort_Portals();
	lo_commit(false);			/* 'false' means it's abort */
	AtAbort_Notify();
	AtEOXact_UpdatePasswordFile(false);

	/* Advertise the fact that we aborted in pg_clog. */
	RecordTransactionAbort();

	/*
	 * Let others know about no transaction in progress by me. Note that
	 * this must be done _before_ releasing locks we hold and _after_
	 * RecordTransactionAbort.
	 */
	if (MyProc != (PGPROC *) NULL)
	{
		/* Lock SInvalLock because that's what GetSnapshotData uses. */
		LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
		MyProc->xid = InvalidTransactionId;
		MyProc->xmin = InvalidTransactionId;
		LWLockRelease(SInvalLock);
	}

	/*
	 * Post-abort cleanup.	See notes in CommitTransaction() concerning
	 * ordering.
	 */

	smgrDoPendingDeletes(false);
	AtAbort_Cache();
	AtEOXact_Buffers(false);
	smgrabort();

	AtAbort_Locks();

	CallEOXactCallbacks(false);
	AtEOXact_GUC(false);
	AtEOXact_SPI();
	AtEOXact_gist();
	AtEOXact_hash();
	AtEOXact_nbtree();
	AtEOXact_rtree();
	AtEOXact_on_commit_actions(false);
	AtEOXact_Namespace(false);
	AtEOXact_CatCache(false);
	AtEOXact_Files();
	SetReindexProcessing(InvalidOid, InvalidOid);
	pgstat_count_xact_rollback();

	/*
	 * State remains TRANS_ABORT until CleanupTransaction().
	 */
	RESUME_INTERRUPTS();
}