/* * 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 */ }
/* * 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); }
/* * 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(); }
/* * 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(); }