1 /*-------------------------------------------------------------------------
4 * top level transaction system support routines
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.132 2002/09/04 20:31:13 momjian Exp $
14 * Transaction aborts can now occur two ways:
16 * 1) system dies from some internal cause (Assert, etc..)
19 * These two cases used to be treated identically, but now
20 * we need to distinguish them. Why? consider the following
25 * 1) user types BEGIN 1) user types BEGIN
26 * 2) user does something 2) user does something
27 * 3) user does not like what 3) system aborts for some reason
28 * she sees and types ABORT
30 * In case 1, we want to abort the transaction and return to the
31 * default state. In case 2, there may be more commands coming
32 * our way which are part of the same transaction block and we have
33 * to ignore these commands until we see an END transaction.
34 * (or an ABORT! --djm)
36 * Internal aborts are now handled by AbortTransactionBlock(), just as
37 * they always have been, and user aborts are now handled by
38 * UserAbortTransactionBlock(). Both of them rely on AbortTransaction()
39 * to do all the real work. The only difference is what state we
40 * enter after AbortTransaction() does its work:
42 * * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
43 * * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
45 * Low-level transaction abort handling is divided into two phases:
46 * * AbortTransaction() executes as soon as we realize the transaction
47 * has failed. It should release all shared resources (locks etc)
48 * so that we do not delay other backends unnecessarily.
49 * * CleanupTransaction() executes when we finally see a user COMMIT
50 * or ROLLBACK command; it cleans things up and gets us out of
51 * the transaction internally. In particular, we mustn't destroy
52 * TransactionCommandContext until this point.
55 * This file is an attempt at a redesign of the upper layer
56 * of the V1 transaction system which was too poorly thought
57 * out to describe. This new system hopes to be both simpler
58 * in design, simpler to extend and needs to contain added
59 * functionality to solve problems beyond the scope of the V1
60 * system. (In particuler, communication of transaction
61 * information between parallel backends has to be supported)
63 * The essential aspects of the transaction system are:
65 * o transaction id generation
66 * o transaction log updating
68 * o cache invalidation
71 * Hence, the functional division of the transaction code is
72 * based on what of the above things need to be done during
73 * a start/commit/abort transaction. For instance, the
74 * routine AtCommit_Memory() takes care of all the memory
75 * cleanup stuff done at commit time.
77 * The code is layered as follows:
84 * are provided to do the lower level work like recording
85 * the transaction status in the log and doing memory cleanup.
86 * above these routines are another set of functions:
88 * StartTransactionCommand
89 * CommitTransactionCommand
90 * AbortCurrentTransaction
92 * These are the routines used in the postgres main processing
93 * loop. They are sensitive to the current transaction block state
94 * and make calls to the lower level routines appropriately.
96 * Support for transaction blocks is provided via the functions:
98 * StartTransactionBlock
99 * CommitTransactionBlock
100 * AbortTransactionBlock
102 * These are invoked only in responce to a user "BEGIN", "END",
103 * or "ABORT" command. The tricky part about these functions
104 * is that they are called within the postgres main loop, in between
105 * the StartTransactionCommand() and CommitTransactionCommand().
107 * For example, consider the following sequence of user commands:
110 * 2) retrieve (foo.all)
111 * 3) append foo (bar = baz)
114 * in the main processing loop, this results in the following
115 * transaction sequence:
117 * / StartTransactionCommand();
118 * 1) / ProcessUtility(); << begin
119 * \ StartTransactionBlock();
120 * \ CommitTransactionCommand();
122 * / StartTransactionCommand();
123 * 2) < ProcessQuery(); << retrieve (foo.all)
124 * \ CommitTransactionCommand();
126 * / StartTransactionCommand();
127 * 3) < ProcessQuery(); << append foo (bar = baz)
128 * \ CommitTransactionCommand();
130 * / StartTransactionCommand();
131 * 4) / ProcessUtility(); << end
132 * \ CommitTransactionBlock();
133 * \ CommitTransactionCommand();
135 * The point of this example is to demonstrate the need for
136 * StartTransactionCommand() and CommitTransactionCommand() to
137 * be state smart -- they should do nothing in between the calls
138 * to StartTransactionBlock() and EndTransactionBlock() and
139 * outside these calls they need to do normal start/commit
142 * Furthermore, suppose the "retrieve (foo.all)" caused an abort
143 * condition. We would then want to abort the transaction and
144 * ignore all subsequent commands up to the "end".
147 *-------------------------------------------------------------------------
151 * Large object clean up added in CommitTransaction() to prevent buffer leaks.
153 * [PA] is Pascal André <andre@via.ecp.fr>
155 #include "postgres.h"
158 #include <sys/time.h>
160 #include "access/gistscan.h"
161 #include "access/hash.h"
162 #include "access/nbtree.h"
163 #include "access/rtree.h"
164 #include "access/xact.h"
165 #include "catalog/heap.h"
166 #include "catalog/index.h"
167 #include "catalog/namespace.h"
168 #include "commands/async.h"
169 #include "commands/trigger.h"
170 #include "executor/spi.h"
171 #include "libpq/be-fsstubs.h"
172 #include "miscadmin.h"
173 #include "storage/proc.h"
174 #include "storage/sinval.h"
175 #include "storage/smgr.h"
176 #include "utils/guc.h"
177 #include "utils/inval.h"
178 #include "utils/memutils.h"
179 #include "utils/portal.h"
180 #include "utils/catcache.h"
181 #include "utils/relcache.h"
185 static void AbortTransaction(void);
186 static void AtAbort_Cache(void);
187 static void AtAbort_Locks(void);
188 static void AtAbort_Memory(void);
189 static void AtCleanup_Memory(void);
190 static void AtCommit_Cache(void);
191 static void AtCommit_LocalCache(void);
192 static void AtCommit_Locks(void);
193 static void AtCommit_Memory(void);
194 static void AtStart_Cache(void);
195 static void AtStart_Locks(void);
196 static void AtStart_Memory(void);
197 static void CleanupTransaction(void);
198 static void CommitTransaction(void);
199 static void RecordTransactionAbort(void);
200 static void StartTransaction(void);
203 * global variables holding the current transaction state.
206 static TransactionStateData CurrentTransactionStateData = {
207 0, /* transaction id */
208 FirstCommandId, /* command id */
209 0, /* scan command id */
210 0x0, /* start time */
211 TRANS_DEFAULT, /* transaction state */
212 TBLOCK_DEFAULT /* transaction block state */
215 TransactionState CurrentTransactionState = &CurrentTransactionStateData;
218 * User-tweakable parameters
220 int DefaultXactIsoLevel = XACT_READ_COMMITTED;
223 bool autocommit = true;
225 int CommitDelay = 0; /* precommit delay in microseconds */
226 int CommitSiblings = 5; /* number of concurrent xacts needed to
230 static bool suppressChain = false;
232 static void (*_RollbackFunc) (void *) = NULL;
233 static void *_RollbackData = NULL;
236 /* ----------------------------------------------------------------
237 * transaction state accessors
238 * ----------------------------------------------------------------
243 /* --------------------------------
244 * TransactionFlushEnabled()
245 * SetTransactionFlushEnabled()
247 * These are used to test and set the "TransactionFlushState"
248 * varable. If this variable is true (the default), then
249 * the system will flush all dirty buffers to disk at the end
250 * of each transaction. If false then we are assuming the
251 * buffer pool resides in stable main memory, in which case we
252 * only do writes as necessary.
253 * --------------------------------
255 static int TransactionFlushState = 1;
258 TransactionFlushEnabled(void)
260 return TransactionFlushState;
264 SetTransactionFlushEnabled(bool state)
266 TransactionFlushState = (state == true);
271 /* --------------------------------
274 * This returns true if we are currently running a query
275 * within an executing transaction.
276 * --------------------------------
279 IsTransactionState(void)
281 TransactionState s = CurrentTransactionState;
289 case TRANS_INPROGRESS:
298 * Shouldn't get here, but lint is not happy with this...
303 /* --------------------------------
304 * IsAbortedTransactionBlockState
306 * This returns true if we are currently running a query
307 * within an aborted transaction block.
308 * --------------------------------
311 IsAbortedTransactionBlockState(void)
313 TransactionState s = CurrentTransactionState;
315 if (s->blockState == TBLOCK_ABORT)
322 /* --------------------------------
323 * GetCurrentTransactionId
324 * --------------------------------
327 GetCurrentTransactionId(void)
329 TransactionState s = CurrentTransactionState;
331 return s->transactionIdData;
335 /* --------------------------------
336 * GetCurrentCommandId
337 * --------------------------------
340 GetCurrentCommandId(void)
342 TransactionState s = CurrentTransactionState;
348 /* --------------------------------
349 * GetCurrentTransactionStartTime
350 * --------------------------------
353 GetCurrentTransactionStartTime(void)
355 TransactionState s = CurrentTransactionState;
361 /* --------------------------------
362 * GetCurrentTransactionStartTimeUsec
363 * --------------------------------
366 GetCurrentTransactionStartTimeUsec(int *msec)
368 TransactionState s = CurrentTransactionState;
370 *msec = s->startTimeUsec;
376 /* --------------------------------
377 * TransactionIdIsCurrentTransactionId
379 * During bootstrap, we cheat and say "it's not my transaction ID" even though
380 * it is. Along with transam.c's cheat to say that the bootstrap XID is
381 * already committed, this causes the tqual.c routines to see previously
382 * inserted tuples as committed, which is what we need during bootstrap.
383 * --------------------------------
386 TransactionIdIsCurrentTransactionId(TransactionId xid)
388 TransactionState s = CurrentTransactionState;
392 Assert(xid == BootstrapTransactionId);
396 return TransactionIdEquals(xid, s->transactionIdData);
400 /* --------------------------------
401 * CommandIdIsCurrentCommandId
402 * --------------------------------
405 CommandIdIsCurrentCommandId(CommandId cid)
407 TransactionState s = CurrentTransactionState;
409 return (cid == s->commandId) ? true : false;
413 /* --------------------------------
414 * CommandCounterIncrement
415 * --------------------------------
418 CommandCounterIncrement(void)
420 TransactionState s = CurrentTransactionState;
423 if (s->commandId == FirstCommandId) /* check for overflow */
424 elog(ERROR, "You may only have 2^32-1 commands per transaction");
426 /* Propagate new command ID into query snapshots, if set */
428 QuerySnapshot->curcid = s->commandId;
429 if (SerializableSnapshot)
430 SerializableSnapshot->curcid = s->commandId;
433 * make cache changes visible to me. AtCommit_LocalCache() instead of
434 * AtCommit_Cache() is called here.
436 AtCommit_LocalCache();
441 /* ----------------------------------------------------------------
442 * StartTransaction stuff
443 * ----------------------------------------------------------------
446 /* --------------------------------
448 * --------------------------------
453 AcceptInvalidationMessages();
456 /* --------------------------------
458 * --------------------------------
464 * at present, it is unknown to me what belongs here -cim 3/18/90
466 * There isn't anything to do at the start of a xact for locks. -mer
471 /* --------------------------------
473 * --------------------------------
479 * We shouldn't have any transaction contexts already.
481 Assert(TopTransactionContext == NULL);
482 Assert(TransactionCommandContext == NULL);
485 * Create a toplevel context for the transaction.
487 TopTransactionContext =
488 AllocSetContextCreate(TopMemoryContext,
489 "TopTransactionContext",
490 ALLOCSET_DEFAULT_MINSIZE,
491 ALLOCSET_DEFAULT_INITSIZE,
492 ALLOCSET_DEFAULT_MAXSIZE);
495 * Create a statement-level context and make it active.
497 TransactionCommandContext =
498 AllocSetContextCreate(TopTransactionContext,
499 "TransactionCommandContext",
500 ALLOCSET_DEFAULT_MINSIZE,
501 ALLOCSET_DEFAULT_INITSIZE,
502 ALLOCSET_DEFAULT_MAXSIZE);
503 MemoryContextSwitchTo(TransactionCommandContext);
507 /* ----------------------------------------------------------------
508 * CommitTransaction stuff
509 * ----------------------------------------------------------------
513 * RecordTransactionCommit
516 RecordTransactionCommit(void)
519 * If we made neither any XLOG entries nor any temp-rel updates, we
520 * can omit recording the transaction commit at all.
522 if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate)
524 TransactionId xid = GetCurrentTransactionId();
527 /* Tell bufmgr and smgr to prepare for commit */
530 START_CRIT_SECTION();
533 * We only need to log the commit in xlog if the transaction made
534 * any transaction-controlled XLOG entries. (Otherwise, its XID
535 * appears nowhere in permanent storage, so no one else will ever
536 * care if it committed.)
538 if (MyLastRecPtr.xrecoff != 0)
540 /* Need to emit a commit record */
542 xl_xact_commit xlrec;
544 xlrec.xtime = time(NULL);
545 rdata.buffer = InvalidBuffer;
546 rdata.data = (char *) (&xlrec);
547 rdata.len = SizeOfXactCommit;
551 * XXX SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
553 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, &rdata);
557 /* Just flush through last record written by me */
558 recptr = ProcLastRecEnd;
562 * We must flush our XLOG entries to disk if we made any XLOG
563 * entries, whether in or out of transaction control. For
564 * example, if we reported a nextval() result to the client, this
565 * ensures that any XLOG record generated by nextval will hit the
566 * disk before we report the transaction committed.
568 if (MyXactMadeXLogEntry)
571 * Sleep before flush! So we can flush more than one commit
572 * records per single fsync. (The idea is some other backend
573 * may do the XLogFlush while we're sleeping. This needs work
574 * still, because on most Unixen, the minimum select() delay
575 * is 10msec or more, which is way too long.)
577 * We do not sleep if enableFsync is not turned on, nor if there
578 * are fewer than CommitSiblings other backends with active
581 if (CommitDelay > 0 && enableFsync &&
582 CountActiveBackends() >= CommitSiblings)
584 struct timeval delay;
587 delay.tv_usec = CommitDelay;
588 (void) select(0, NULL, NULL, NULL, &delay);
595 * We must mark the transaction committed in clog if its XID
596 * appears either in permanent rels or in local temporary rels.
597 * We test this by seeing if we made transaction-controlled
598 * entries *OR* local-rel tuple updates. Note that if we made
599 * only the latter, we have not emitted an XLOG record for our
600 * commit, and so in the event of a crash the clog update might be
601 * lost. This is okay because no one else will ever care whether
604 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
605 TransactionIdCommit(xid);
610 /* Break the chain of back-links in the XLOG records I output */
611 MyLastRecPtr.xrecoff = 0;
612 MyXactMadeXLogEntry = false;
613 MyXactMadeTempRelUpdate = false;
615 /* Show myself as out of the transaction in PGPROC array */
616 MyProc->logRec.xrecoff = 0;
620 /* --------------------------------
622 * --------------------------------
628 * Clean up the relation cache.
630 AtEOXact_RelationCache(true);
633 * Make catalog changes visible to all backends.
635 AtEOXactInvalidationMessages(true);
638 /* --------------------------------
639 * AtCommit_LocalCache
640 * --------------------------------
643 AtCommit_LocalCache(void)
646 * Make catalog changes visible to me for the next command.
648 CommandEndInvalidationMessages(true);
651 /* --------------------------------
653 * --------------------------------
659 * XXX What if ProcReleaseLocks fails? (race condition?)
661 * Then you're up a creek! -mer 5/24/92
663 ProcReleaseLocks(true);
666 /* --------------------------------
668 * --------------------------------
671 AtCommit_Memory(void)
674 * Now that we're "out" of a transaction, have the system allocate
675 * things in the top memory context instead of per-transaction
678 MemoryContextSwitchTo(TopMemoryContext);
681 * Release all transaction-local memory.
683 Assert(TopTransactionContext != NULL);
684 MemoryContextDelete(TopTransactionContext);
685 TopTransactionContext = NULL;
686 TransactionCommandContext = NULL;
689 /* ----------------------------------------------------------------
690 * AbortTransaction stuff
691 * ----------------------------------------------------------------
695 * RecordTransactionAbort
698 RecordTransactionAbort(void)
701 * If we made neither any transaction-controlled XLOG entries nor any
702 * temp-rel updates, we can omit recording the transaction abort at
703 * all. No one will ever care that it aborted.
705 if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
707 TransactionId xid = GetCurrentTransactionId();
710 * Catch the scenario where we aborted partway through
711 * RecordTransactionCommit ...
713 if (TransactionIdDidCommit(xid))
714 elog(PANIC, "RecordTransactionAbort: xact %u already committed",
717 START_CRIT_SECTION();
720 * We only need to log the abort in XLOG if the transaction made
721 * any transaction-controlled XLOG entries. (Otherwise, its XID
722 * appears nowhere in permanent storage, so no one else will ever
723 * care if it committed.) We do not flush XLOG to disk in any
724 * case, since the default assumption after a crash would be that
725 * we aborted, anyway.
727 if (MyLastRecPtr.xrecoff != 0)
733 xlrec.xtime = time(NULL);
734 rdata.buffer = InvalidBuffer;
735 rdata.data = (char *) (&xlrec);
736 rdata.len = SizeOfXactAbort;
740 * SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
742 recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata);
746 * Mark the transaction aborted in clog. This is not absolutely
747 * necessary but we may as well do it while we are here.
749 TransactionIdAbort(xid);
754 /* Break the chain of back-links in the XLOG records I output */
755 MyLastRecPtr.xrecoff = 0;
756 MyXactMadeXLogEntry = false;
757 MyXactMadeTempRelUpdate = false;
759 /* Show myself as out of the transaction in PGPROC array */
760 MyProc->logRec.xrecoff = 0;
763 /* --------------------------------
765 * --------------------------------
770 AtEOXact_RelationCache(false);
771 AtEOXactInvalidationMessages(false);
774 /* --------------------------------
776 * --------------------------------
782 * XXX What if ProcReleaseLocks() fails? (race condition?)
784 * Then you're up a creek without a paddle! -mer
786 ProcReleaseLocks(false);
790 /* --------------------------------
792 * --------------------------------
798 * Make sure we are in a valid context (not a child of
799 * TransactionCommandContext...). Note that it is possible for this
800 * code to be called when we aren't in a transaction at all; go
801 * directly to TopMemoryContext in that case.
803 if (TransactionCommandContext != NULL)
805 MemoryContextSwitchTo(TransactionCommandContext);
808 * We do not want to destroy transaction contexts yet, but it
809 * should be OK to delete any command-local memory.
811 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
814 MemoryContextSwitchTo(TopMemoryContext);
818 /* ----------------------------------------------------------------
819 * CleanupTransaction stuff
820 * ----------------------------------------------------------------
823 /* --------------------------------
825 * --------------------------------
828 AtCleanup_Memory(void)
831 * Now that we're "out" of a transaction, have the system allocate
832 * things in the top memory context instead of per-transaction
835 MemoryContextSwitchTo(TopMemoryContext);
838 * Release all transaction-local memory.
840 if (TopTransactionContext != NULL)
841 MemoryContextDelete(TopTransactionContext);
842 TopTransactionContext = NULL;
843 TransactionCommandContext = NULL;
847 /* ----------------------------------------------------------------
849 * ----------------------------------------------------------------
852 /* --------------------------------
855 * --------------------------------
858 StartTransaction(void)
860 TransactionState s = CurrentTransactionState;
863 XactIsoLevel = DefaultXactIsoLevel;
866 * Check the current transaction state. If the transaction system is
867 * switched off, or if we're already in a transaction, do nothing.
868 * We're already in a transaction when the monitor sends a null
869 * command to the backend to flush the comm channel. This is a hacky
870 * fix to a communications problem, and we keep having to deal with it
871 * here. We should fix the comm channel code. mao 080891
873 if (s->state == TRANS_INPROGRESS)
877 * set the current transaction state information appropriately during
880 s->state = TRANS_START;
882 SetReindexProcessing(false);
885 * generate a new transaction id
887 s->transactionIdData = GetNewTransactionId();
889 XactLockTableInsert(s->transactionIdData);
892 * initialize current transaction state fields
894 s->commandId = FirstCommandId;
895 s->startTime = GetCurrentAbsoluteTimeUsec(&(s->startTimeUsec));
898 * initialize the various transaction subsystems
905 * Tell the trigger manager to we're starting a transaction
907 DeferredTriggerBeginXact();
910 * done with start processing, set current transaction state to "in
913 s->state = TRANS_INPROGRESS;
919 * Tell me if we are currently in progress
923 CurrentXactInProgress(void)
925 return CurrentTransactionState->state == TRANS_INPROGRESS;
929 /* --------------------------------
932 * --------------------------------
935 CommitTransaction(void)
937 TransactionState s = CurrentTransactionState;
940 * check the current transaction state
942 if (s->state != TRANS_INPROGRESS)
943 elog(WARNING, "CommitTransaction and not in in-progress state");
946 * Tell the trigger manager that this transaction is about to be
947 * committed. He'll invoke all trigger deferred until XACT before we
948 * really start on committing the transaction.
950 DeferredTriggerEndXact();
952 /* Prevent cancel/die interrupt while cleaning up */
956 * set the current transaction state information appropriately during
957 * the abort processing
959 s->state = TRANS_COMMIT;
962 * do commit processing
965 /* handle commit for large objects [ PA, 7/17/98 ] */
968 /* NOTIFY commit must also come before lower-level cleanup */
973 /* Here is where we really truly commit. */
974 RecordTransactionCommit();
977 * Let others know about no transaction in progress by me. Note that
978 * this must be done _before_ releasing locks we hold and _after_
979 * RecordTransactionCommit.
981 * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
982 * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
983 * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
984 * as running as well or it will see two tuple versions - one deleted
985 * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
987 if (MyProc != (PGPROC *) NULL)
989 /* Lock SInvalLock because that's what GetSnapshotData uses. */
990 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
991 MyProc->xid = InvalidTransactionId;
992 MyProc->xmin = InvalidTransactionId;
993 LWLockRelease(SInvalLock);
997 * This is all post-commit cleanup. Note that if an error is raised
998 * here, it's too late to abort the transaction. This should be just
999 * noncritical resource releasing.
1002 smgrDoPendingDeletes(true);
1010 AtEOXact_Namespace(true);
1013 AtEOXact_CatCache(true);
1015 AtEOXact_Buffers(true);
1019 /* Count transaction commit in statistics collector */
1020 pgstat_count_xact_commit();
1023 * done with commit processing, set current transaction state back to
1026 s->state = TRANS_DEFAULT;
1028 RESUME_INTERRUPTS();
1031 /* --------------------------------
1034 * --------------------------------
1037 AbortTransaction(void)
1039 TransactionState s = CurrentTransactionState;
1041 /* Prevent cancel/die interrupt while cleaning up */
1045 * Release any LW locks we might be holding as quickly as possible.
1046 * (Regular locks, however, must be held till we finish aborting.)
1047 * Releasing LW locks is critical since we might try to grab them
1048 * again while cleaning up!
1052 /* Clean up buffer I/O and buffer context locks, too */
1057 * Also clean up any open wait for lock, since the lock manager will
1058 * choke if we try to wait for another lock before doing this.
1063 * check the current transaction state
1065 if (s->state != TRANS_INPROGRESS)
1066 elog(WARNING, "AbortTransaction and not in in-progress state");
1069 * set the current transaction state information appropriately during
1070 * the abort processing
1072 s->state = TRANS_ABORT;
1075 * Reset user id which might have been changed transiently
1077 SetUserId(GetSessionUserId());
1080 * do abort processing
1082 DeferredTriggerAbortXact();
1083 lo_commit(false); /* 'false' means it's abort */
1087 /* Advertise the fact that we aborted in pg_clog. */
1088 RecordTransactionAbort();
1091 * Let others know about no transaction in progress by me. Note that
1092 * this must be done _before_ releasing locks we hold and _after_
1093 * RecordTransactionAbort.
1095 if (MyProc != (PGPROC *) NULL)
1097 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1098 LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
1099 MyProc->xid = InvalidTransactionId;
1100 MyProc->xmin = InvalidTransactionId;
1101 LWLockRelease(SInvalLock);
1104 smgrDoPendingDeletes(false);
1106 AtEOXact_GUC(false);
1112 AtEOXact_Namespace(false);
1114 AtEOXact_CatCache(false);
1116 AtEOXact_Buffers(false);
1120 /* Count transaction abort in statistics collector */
1121 pgstat_count_xact_rollback();
1124 * State remains TRANS_ABORT until CleanupTransaction().
1126 RESUME_INTERRUPTS();
1129 /* --------------------------------
1130 * CleanupTransaction
1132 * --------------------------------
1135 CleanupTransaction(void)
1137 TransactionState s = CurrentTransactionState;
1140 * State should still be TRANS_ABORT from AbortTransaction().
1142 if (s->state != TRANS_ABORT)
1143 elog(FATAL, "CleanupTransaction and not in abort state");
1146 * do abort cleanup processing
1151 * done with abort processing, set current transaction state back to
1154 s->state = TRANS_DEFAULT;
1157 /* --------------------------------
1158 * StartTransactionCommand
1160 * preventChain, if true, forces autocommit behavior at the next
1161 * CommitTransactionCommand call.
1162 * --------------------------------
1165 StartTransactionCommand(bool preventChain)
1167 TransactionState s = CurrentTransactionState;
1170 * Remember if caller wants to prevent autocommit-off chaining. This
1171 * is only allowed if not already in a transaction block.
1173 suppressChain = preventChain;
1174 if (preventChain && s->blockState != TBLOCK_DEFAULT)
1175 elog(ERROR, "StartTransactionCommand: can't prevent chain");
1177 switch (s->blockState)
1180 * if we aren't in a transaction block, we just do our usual
1181 * start transaction.
1183 case TBLOCK_DEFAULT:
1188 * We should never experience this -- if we do it means the
1189 * BEGIN state was not changed in the previous
1190 * CommitTransactionCommand(). If we get it, we print a
1191 * warning and change to the in-progress state.
1194 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1195 s->blockState = TBLOCK_INPROGRESS;
1199 * This is the case when are somewhere in a transaction block
1200 * and about to start a new command. For now we do nothing
1201 * but someday we may do command-local resource
1204 case TBLOCK_INPROGRESS:
1208 * As with BEGIN, we should never experience this if we do it
1209 * means the END state was not changed in the previous
1210 * CommitTransactionCommand(). If we get it, we print a
1211 * warning, commit the transaction, start a new transaction
1212 * and change to the default state.
1215 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_END");
1216 s->blockState = TBLOCK_DEFAULT;
1217 CommitTransaction();
1222 * Here we are in the middle of a transaction block but one of
1223 * the commands caused an abort so we do nothing but remain in
1224 * the abort state. Eventually we will get to the "END
1225 * TRANSACTION" which will set things straight.
1231 * This means we somehow aborted and the last call to
1232 * CommitTransactionCommand() didn't clear the state so we
1233 * remain in the ENDABORT state and maybe next time we get to
1234 * CommitTransactionCommand() the state will get reset to
1237 case TBLOCK_ENDABORT:
1238 elog(WARNING, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1243 * We must switch to TransactionCommandContext before returning. This
1244 * is already done if we called StartTransaction, otherwise not.
1246 Assert(TransactionCommandContext != NULL);
1247 MemoryContextSwitchTo(TransactionCommandContext);
1250 /* --------------------------------
1251 * CommitTransactionCommand
1253 * forceCommit = true forces autocommit behavior even when autocommit is off.
1254 * --------------------------------
1257 CommitTransactionCommand(bool forceCommit)
1259 TransactionState s = CurrentTransactionState;
1261 switch (s->blockState)
1264 * If we aren't in a transaction block, and we are doing
1265 * autocommit, just do our usual transaction commit. But if
1266 * we aren't doing autocommit, start a transaction block
1267 * automatically by switching to INPROGRESS state. (We handle
1268 * this choice here, and not earlier, so that an explicit
1269 * BEGIN issued in autocommit-off mode won't issue strange
1272 * Autocommit mode is forced by either a true forceCommit
1273 * parameter to me, or a true preventChain parameter to the
1274 * preceding StartTransactionCommand call. This is needed so
1275 * that commands like VACUUM can ensure that the right things
1278 case TBLOCK_DEFAULT:
1279 if (autocommit || forceCommit || suppressChain)
1280 CommitTransaction();
1283 BeginTransactionBlock();
1284 Assert(s->blockState == TBLOCK_INPROGRESS);
1285 /* This code must match the TBLOCK_INPROGRESS case below: */
1286 CommandCounterIncrement();
1287 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
1292 * This is the case right after we get a "BEGIN TRANSACTION"
1293 * command, but the user hasn't done anything else yet, so we
1294 * change to the "transaction block in progress" state and
1298 s->blockState = TBLOCK_INPROGRESS;
1302 * This is the case when we have finished executing a command
1303 * someplace within a transaction block. We increment the
1304 * command counter and return. Someday we may free resources
1305 * local to the command.
1307 * That someday is today, at least for memory allocated in
1308 * TransactionCommandContext. - vadim 03/25/97
1310 case TBLOCK_INPROGRESS:
1311 CommandCounterIncrement();
1312 MemoryContextResetAndDeleteChildren(TransactionCommandContext);
1316 * This is the case when we just got the "END TRANSACTION"
1317 * statement, so we commit the transaction and go back to the
1321 CommitTransaction();
1322 s->blockState = TBLOCK_DEFAULT;
1326 * Here we are in the middle of a transaction block but one of
1327 * the commands caused an abort so we do nothing but remain in
1328 * the abort state. Eventually we will get to the "END
1329 * TRANSACTION" which will set things straight.
1335 * Here we were in an aborted transaction block which just
1336 * processed the "END TRANSACTION" command from the user, so
1337 * clean up and return to the default state.
1339 case TBLOCK_ENDABORT:
1340 CleanupTransaction();
1341 s->blockState = TBLOCK_DEFAULT;
1346 /* --------------------------------
1347 * AbortCurrentTransaction
1348 * --------------------------------
1351 AbortCurrentTransaction(void)
1353 TransactionState s = CurrentTransactionState;
1355 switch (s->blockState)
1358 * if we aren't in a transaction block, we just do the basic
1359 * abort & cleanup transaction.
1361 case TBLOCK_DEFAULT:
1363 CleanupTransaction();
1367 * If we are in the TBLOCK_BEGIN it means something screwed up
1368 * right after reading "BEGIN TRANSACTION" so we enter the
1369 * abort state. Eventually an "END TRANSACTION" will fix
1373 s->blockState = TBLOCK_ABORT;
1375 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1379 * This is the case when are somewhere in a transaction block
1380 * which aborted so we abort the transaction and set the ABORT
1381 * state. Eventually an "END TRANSACTION" will fix things and
1382 * restore us to a normal state.
1384 case TBLOCK_INPROGRESS:
1385 s->blockState = TBLOCK_ABORT;
1387 /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1391 * Here, the system was fouled up just after the user wanted
1392 * to end the transaction block so we abort the transaction
1393 * and put us back into the default state.
1396 s->blockState = TBLOCK_DEFAULT;
1398 CleanupTransaction();
1402 * Here, we are already in an aborted transaction state and
1403 * are waiting for an "END TRANSACTION" to come along and lo
1404 * and behold, we abort again! So we just remain in the abort
1411 * Here we were in an aborted transaction block which just
1412 * processed the "END TRANSACTION" command but somehow aborted
1413 * again.. since we must have done the abort processing, we
1414 * clean up and return to the default state.
1416 case TBLOCK_ENDABORT:
1417 CleanupTransaction();
1418 s->blockState = TBLOCK_DEFAULT;
1423 /* ----------------------------------------------------------------
1424 * transaction block support
1425 * ----------------------------------------------------------------
1427 /* --------------------------------
1428 * BeginTransactionBlock
1429 * --------------------------------
1432 BeginTransactionBlock(void)
1434 TransactionState s = CurrentTransactionState;
1437 * check the current transaction state
1439 if (s->blockState != TBLOCK_DEFAULT)
1440 elog(WARNING, "BEGIN: already a transaction in progress");
1443 * set the current transaction block state information appropriately
1444 * during begin processing
1446 s->blockState = TBLOCK_BEGIN;
1449 * do begin processing. NOTE: if you put anything here, check that it
1450 * behaves properly in both autocommit-on and autocommit-off modes. In
1451 * the latter case we will already have done some work in the new
1456 * done with begin processing, set block state to inprogress
1458 s->blockState = TBLOCK_INPROGRESS;
1461 /* --------------------------------
1462 * EndTransactionBlock
1463 * --------------------------------
1466 EndTransactionBlock(void)
1468 TransactionState s = CurrentTransactionState;
1471 * check the current transaction state
1473 if (s->blockState == TBLOCK_INPROGRESS)
1476 * here we are in a transaction block which should commit when we
1477 * get to the upcoming CommitTransactionCommand() so we set the
1478 * state to "END". CommitTransactionCommand() will recognize this
1479 * and commit the transaction and return us to the default state
1481 s->blockState = TBLOCK_END;
1485 if (s->blockState == TBLOCK_ABORT)
1488 * here, we are in a transaction block which aborted and since the
1489 * AbortTransaction() was already done, we do whatever is needed
1490 * and change to the special "END ABORT" state. The upcoming
1491 * CommitTransactionCommand() will recognise this and then put us
1492 * back in the default state.
1494 s->blockState = TBLOCK_ENDABORT;
1499 * here, the user issued COMMIT when not inside a transaction. Issue a
1500 * WARNING and go to abort state. The upcoming call to
1501 * CommitTransactionCommand() will then put us back into the default
1504 elog(WARNING, "COMMIT: no transaction in progress");
1506 s->blockState = TBLOCK_ENDABORT;
1509 /* --------------------------------
1510 * AbortTransactionBlock
1511 * --------------------------------
1515 AbortTransactionBlock(void)
1517 TransactionState s = CurrentTransactionState;
1520 * check the current transaction state
1522 if (s->blockState == TBLOCK_INPROGRESS)
1525 * here we were inside a transaction block something screwed up
1526 * inside the system so we enter the abort state, do the abort
1527 * processing and then return. We remain in the abort state until
1528 * we see an END TRANSACTION command.
1530 s->blockState = TBLOCK_ABORT;
1536 * here, the user issued ABORT when not inside a transaction. Issue a
1537 * WARNING and go to abort state. The upcoming call to
1538 * CommitTransactionCommand() will then put us back into the default
1541 elog(WARNING, "ROLLBACK: no transaction in progress");
1543 s->blockState = TBLOCK_ENDABORT;
1547 /* --------------------------------
1548 * UserAbortTransactionBlock
1549 * --------------------------------
1552 UserAbortTransactionBlock(void)
1554 TransactionState s = CurrentTransactionState;
1557 * if the transaction has already been automatically aborted with an
1558 * error, and the user subsequently types 'abort', allow it. (the
1559 * behavior is the same as if they had typed 'end'.)
1561 if (s->blockState == TBLOCK_ABORT)
1563 s->blockState = TBLOCK_ENDABORT;
1567 if (s->blockState == TBLOCK_INPROGRESS)
1570 * here we were inside a transaction block and we got an abort
1571 * command from the user, so we move to the abort state, do the
1572 * abort processing and then change to the ENDABORT state so we
1573 * will end up in the default state after the upcoming
1574 * CommitTransactionCommand().
1576 s->blockState = TBLOCK_ABORT;
1578 s->blockState = TBLOCK_ENDABORT;
1583 * here, the user issued ABORT when not inside a transaction. Issue a
1584 * WARNING and go to abort state. The upcoming call to
1585 * CommitTransactionCommand() will then put us back into the default
1588 elog(WARNING, "ROLLBACK: no transaction in progress");
1590 s->blockState = TBLOCK_ENDABORT;
1593 /* --------------------------------
1594 * AbortOutOfAnyTransaction
1596 * This routine is provided for error recovery purposes. It aborts any
1597 * active transaction or transaction block, leaving the system in a known
1599 * --------------------------------
1602 AbortOutOfAnyTransaction(void)
1604 TransactionState s = CurrentTransactionState;
1607 * Get out of any low-level transaction
1612 case TRANS_INPROGRESS:
1614 /* In a transaction, so clean up */
1616 CleanupTransaction();
1619 /* AbortTransaction already done, still need Cleanup */
1620 CleanupTransaction();
1623 /* Not in a transaction, do nothing */
1628 * Now reset the high-level state
1630 s->blockState = TBLOCK_DEFAULT;
1634 IsTransactionBlock(void)
1636 TransactionState s = CurrentTransactionState;
1638 if (s->blockState == TBLOCK_INPROGRESS
1639 || s->blockState == TBLOCK_ABORT
1640 || s->blockState == TBLOCK_ENDABORT)
1647 xact_redo(XLogRecPtr lsn, XLogRecord *record)
1649 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1651 if (info == XLOG_XACT_COMMIT)
1653 TransactionIdCommit(record->xl_xid);
1654 /* SHOULD REMOVE FILES OF ALL DROPPED RELATIONS */
1656 else if (info == XLOG_XACT_ABORT)
1658 TransactionIdAbort(record->xl_xid);
1659 /* SHOULD REMOVE FILES OF ALL FAILED-TO-BE-CREATED RELATIONS */
1662 elog(PANIC, "xact_redo: unknown op code %u", info);
1666 xact_undo(XLogRecPtr lsn, XLogRecord *record)
1668 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1670 if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
1671 elog(PANIC, "xact_undo: can't undo committed xaction");
1672 else if (info != XLOG_XACT_ABORT)
1673 elog(PANIC, "xact_redo: unknown op code %u", info);
1677 xact_desc(char *buf, uint8 xl_info, char *rec)
1679 uint8 info = xl_info & ~XLR_INFO_MASK;
1681 if (info == XLOG_XACT_COMMIT)
1683 xl_xact_commit *xlrec = (xl_xact_commit *) rec;
1684 struct tm *tm = localtime(&xlrec->xtime);
1686 sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
1687 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1688 tm->tm_hour, tm->tm_min, tm->tm_sec);
1690 else if (info == XLOG_XACT_ABORT)
1692 xl_xact_abort *xlrec = (xl_xact_abort *) rec;
1693 struct tm *tm = localtime(&xlrec->xtime);
1695 sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
1696 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1697 tm->tm_hour, tm->tm_min, tm->tm_sec);
1700 strcat(buf, "UNKNOWN");
1704 XactPushRollback(void (*func) (void *), void *data)
1707 if (_RollbackFunc != NULL)
1708 elog(PANIC, "XactPushRollback: already installed");
1711 _RollbackFunc = func;
1712 _RollbackData = data;
1716 XactPopRollback(void)
1718 _RollbackFunc = NULL;