Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * xact.c
4 : : * top level transaction system support routines
5 : : *
6 : : * See src/backend/access/transam/README for more information.
7 : : *
8 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
9 : : * Portions Copyright (c) 1994, Regents of the University of California
10 : : *
11 : : *
12 : : * IDENTIFICATION
13 : : * src/backend/access/transam/xact.c
14 : : *
15 : : *-------------------------------------------------------------------------
16 : : */
17 : :
18 : : #include "postgres.h"
19 : :
20 : : #include <time.h>
21 : : #include <unistd.h>
22 : :
23 : : #include "access/commit_ts.h"
24 : : #include "access/multixact.h"
25 : : #include "access/parallel.h"
26 : : #include "access/subtrans.h"
27 : : #include "access/transam.h"
28 : : #include "access/twophase.h"
29 : : #include "access/xact.h"
30 : : #include "access/xlog.h"
31 : : #include "access/xloginsert.h"
32 : : #include "access/xlogrecovery.h"
33 : : #include "access/xlogutils.h"
34 : : #include "access/xlogwait.h"
35 : : #include "catalog/index.h"
36 : : #include "catalog/namespace.h"
37 : : #include "catalog/pg_enum.h"
38 : : #include "catalog/storage.h"
39 : : #include "commands/async.h"
40 : : #include "commands/tablecmds.h"
41 : : #include "commands/trigger.h"
42 : : #include "common/pg_prng.h"
43 : : #include "executor/spi.h"
44 : : #include "libpq/be-fsstubs.h"
45 : : #include "libpq/pqsignal.h"
46 : : #include "miscadmin.h"
47 : : #include "pg_trace.h"
48 : : #include "pgstat.h"
49 : : #include "replication/logical.h"
50 : : #include "replication/logicallauncher.h"
51 : : #include "replication/logicalworker.h"
52 : : #include "replication/origin.h"
53 : : #include "replication/snapbuild.h"
54 : : #include "replication/syncrep.h"
55 : : #include "storage/aio_subsys.h"
56 : : #include "storage/condition_variable.h"
57 : : #include "storage/fd.h"
58 : : #include "storage/lmgr.h"
59 : : #include "storage/md.h"
60 : : #include "storage/predicate.h"
61 : : #include "storage/proc.h"
62 : : #include "storage/procarray.h"
63 : : #include "storage/sinvaladt.h"
64 : : #include "storage/smgr.h"
65 : : #include "utils/builtins.h"
66 : : #include "utils/combocid.h"
67 : : #include "utils/guc.h"
68 : : #include "utils/injection_point.h"
69 : : #include "utils/inval.h"
70 : : #include "utils/memutils.h"
71 : : #include "utils/relmapper.h"
72 : : #include "utils/snapmgr.h"
73 : : #include "utils/timeout.h"
74 : : #include "utils/timestamp.h"
75 : : #include "utils/typcache.h"
76 : : #include "utils/wait_event.h"
77 : :
78 : : /*
79 : : * User-tweakable parameters
80 : : */
81 : : int DefaultXactIsoLevel = XACT_READ_COMMITTED;
82 : : int XactIsoLevel = XACT_READ_COMMITTED;
83 : :
84 : : bool DefaultXactReadOnly = false;
85 : : bool XactReadOnly;
86 : :
87 : : bool DefaultXactDeferrable = false;
88 : : bool XactDeferrable;
89 : :
90 : : int synchronous_commit = SYNCHRONOUS_COMMIT_ON;
91 : :
92 : : /*
93 : : * CheckXidAlive is a xid value pointing to a possibly ongoing (sub)
94 : : * transaction. Currently, it is used in logical decoding. It's possible
95 : : * that such transactions can get aborted while the decoding is ongoing in
96 : : * which case we skip decoding that particular transaction. To ensure that we
97 : : * check whether the CheckXidAlive is aborted after fetching the tuple from
98 : : * system tables. We also ensure that during logical decoding we never
99 : : * directly access the tableam or heap APIs because we are checking for the
100 : : * concurrent aborts only in systable_* APIs.
101 : : */
102 : : TransactionId CheckXidAlive = InvalidTransactionId;
103 : : bool bsysscan = false;
104 : :
105 : : /*
106 : : * When running as a parallel worker, we place only a single
107 : : * TransactionStateData on the parallel worker's state stack, and the XID
108 : : * reflected there will be that of the *innermost* currently-active
109 : : * subtransaction in the backend that initiated parallelism. However,
110 : : * GetTopTransactionId() and TransactionIdIsCurrentTransactionId()
111 : : * need to return the same answers in the parallel worker as they would have
112 : : * in the user backend, so we need some additional bookkeeping.
113 : : *
114 : : * XactTopFullTransactionId stores the XID of our toplevel transaction, which
115 : : * will be the same as TopTransactionStateData.fullTransactionId in an
116 : : * ordinary backend; but in a parallel backend, which does not have the entire
117 : : * transaction state, it will instead be copied from the backend that started
118 : : * the parallel operation.
119 : : *
120 : : * nParallelCurrentXids will be 0 and ParallelCurrentXids NULL in an ordinary
121 : : * backend, but in a parallel backend, nParallelCurrentXids will contain the
122 : : * number of XIDs that need to be considered current, and ParallelCurrentXids
123 : : * will contain the XIDs themselves. This includes all XIDs that were current
124 : : * or sub-committed in the parent at the time the parallel operation began.
125 : : * The XIDs are stored sorted in numerical order (not logical order) to make
126 : : * lookups as fast as possible.
127 : : */
128 : : static FullTransactionId XactTopFullTransactionId = {InvalidTransactionId};
129 : : static int nParallelCurrentXids = 0;
130 : : static TransactionId *ParallelCurrentXids;
131 : :
132 : : /*
133 : : * Miscellaneous flag bits to record events which occur on the top level
134 : : * transaction. These flags are only persisted in MyXactFlags and are intended
135 : : * so we remember to do certain things later on in the transaction. This is
136 : : * globally accessible, so can be set from anywhere in the code that requires
137 : : * recording flags.
138 : : */
139 : : int MyXactFlags;
140 : :
141 : : /*
142 : : * transaction states - transaction state from server perspective
143 : : */
144 : : typedef enum TransState
145 : : {
146 : : TRANS_DEFAULT, /* idle */
147 : : TRANS_START, /* transaction starting */
148 : : TRANS_INPROGRESS, /* inside a valid transaction */
149 : : TRANS_COMMIT, /* commit in progress */
150 : : TRANS_ABORT, /* abort in progress */
151 : : TRANS_PREPARE, /* prepare in progress */
152 : : } TransState;
153 : :
154 : : /*
155 : : * transaction block states - transaction state of client queries
156 : : *
157 : : * Note: the subtransaction states are used only for non-topmost
158 : : * transactions; the others appear only in the topmost transaction.
159 : : */
160 : : typedef enum TBlockState
161 : : {
162 : : /* not-in-transaction-block states */
163 : : TBLOCK_DEFAULT, /* idle */
164 : : TBLOCK_STARTED, /* running single-query transaction */
165 : :
166 : : /* transaction block states */
167 : : TBLOCK_BEGIN, /* starting transaction block */
168 : : TBLOCK_INPROGRESS, /* live transaction */
169 : : TBLOCK_IMPLICIT_INPROGRESS, /* live transaction after implicit BEGIN */
170 : : TBLOCK_PARALLEL_INPROGRESS, /* live transaction inside parallel worker */
171 : : TBLOCK_END, /* COMMIT received */
172 : : TBLOCK_ABORT, /* failed xact, awaiting ROLLBACK */
173 : : TBLOCK_ABORT_END, /* failed xact, ROLLBACK received */
174 : : TBLOCK_ABORT_PENDING, /* live xact, ROLLBACK received */
175 : : TBLOCK_PREPARE, /* live xact, PREPARE received */
176 : :
177 : : /* subtransaction states */
178 : : TBLOCK_SUBBEGIN, /* starting a subtransaction */
179 : : TBLOCK_SUBINPROGRESS, /* live subtransaction */
180 : : TBLOCK_SUBRELEASE, /* RELEASE received */
181 : : TBLOCK_SUBCOMMIT, /* COMMIT received while TBLOCK_SUBINPROGRESS */
182 : : TBLOCK_SUBABORT, /* failed subxact, awaiting ROLLBACK */
183 : : TBLOCK_SUBABORT_END, /* failed subxact, ROLLBACK received */
184 : : TBLOCK_SUBABORT_PENDING, /* live subxact, ROLLBACK received */
185 : : TBLOCK_SUBRESTART, /* live subxact, ROLLBACK TO received */
186 : : TBLOCK_SUBABORT_RESTART, /* failed subxact, ROLLBACK TO received */
187 : : } TBlockState;
188 : :
189 : : /*
190 : : * transaction state structure
191 : : *
192 : : * Note: parallelModeLevel counts the number of unmatched EnterParallelMode
193 : : * calls done at this transaction level. parallelChildXact is true if any
194 : : * upper transaction level has nonzero parallelModeLevel.
195 : : */
196 : : typedef struct TransactionStateData
197 : : {
198 : : FullTransactionId fullTransactionId; /* my FullTransactionId */
199 : : SubTransactionId subTransactionId; /* my subxact ID */
200 : : char *name; /* savepoint name, if any */
201 : : int savepointLevel; /* savepoint level */
202 : : TransState state; /* low-level state */
203 : : TBlockState blockState; /* high-level state */
204 : : int nestingLevel; /* transaction nesting depth */
205 : : int gucNestLevel; /* GUC context nesting depth */
206 : : MemoryContext curTransactionContext; /* my xact-lifetime context */
207 : : ResourceOwner curTransactionOwner; /* my query resources */
208 : : MemoryContext priorContext; /* CurrentMemoryContext before xact started */
209 : : TransactionId *childXids; /* subcommitted child XIDs, in XID order */
210 : : int nChildXids; /* # of subcommitted child XIDs */
211 : : int maxChildXids; /* allocated size of childXids[] */
212 : : Oid prevUser; /* previous CurrentUserId setting */
213 : : int prevSecContext; /* previous SecurityRestrictionContext */
214 : : bool prevXactReadOnly; /* entry-time xact r/o state */
215 : : bool startedInRecovery; /* did we start in recovery? */
216 : : bool didLogXid; /* has xid been included in WAL record? */
217 : : int parallelModeLevel; /* Enter/ExitParallelMode counter */
218 : : bool parallelChildXact; /* is any parent transaction parallel? */
219 : : bool chain; /* start a new block after this one */
220 : : bool topXidLogged; /* for a subxact: is top-level XID logged? */
221 : : struct TransactionStateData *parent; /* back link to parent */
222 : : } TransactionStateData;
223 : :
224 : : typedef TransactionStateData *TransactionState;
225 : :
226 : : /*
227 : : * Serialized representation used to transmit transaction state to parallel
228 : : * workers through shared memory.
229 : : */
230 : : typedef struct SerializedTransactionState
231 : : {
232 : : int xactIsoLevel;
233 : : bool xactDeferrable;
234 : : FullTransactionId topFullTransactionId;
235 : : FullTransactionId currentFullTransactionId;
236 : : CommandId currentCommandId;
237 : : int nParallelCurrentXids;
238 : : pg_attribute_counted_by(nParallelCurrentXids) TransactionId parallelCurrentXids[FLEXIBLE_ARRAY_MEMBER];
239 : : } SerializedTransactionState;
240 : :
241 : : /* The size of SerializedTransactionState, not including the final array. */
242 : : #define SerializedTransactionStateHeaderSize \
243 : : offsetof(SerializedTransactionState, parallelCurrentXids)
244 : :
245 : : /*
246 : : * CurrentTransactionState always points to the current transaction state
247 : : * block. It will point to TopTransactionStateData when not in a
248 : : * transaction at all, or when in a top-level transaction.
249 : : */
250 : : static TransactionStateData TopTransactionStateData = {
251 : : .state = TRANS_DEFAULT,
252 : : .blockState = TBLOCK_DEFAULT,
253 : : .topXidLogged = false,
254 : : };
255 : :
256 : : /*
257 : : * unreportedXids holds XIDs of all subtransactions that have not yet been
258 : : * reported in an XLOG_XACT_ASSIGNMENT record.
259 : : */
260 : : static int nUnreportedXids;
261 : : static TransactionId unreportedXids[PGPROC_MAX_CACHED_SUBXIDS];
262 : :
263 : : static TransactionState CurrentTransactionState = &TopTransactionStateData;
264 : :
265 : : /*
266 : : * The subtransaction ID and command ID assignment counters are global
267 : : * to a whole transaction, so we do not keep them in the state stack.
268 : : */
269 : : static SubTransactionId currentSubTransactionId;
270 : : static CommandId currentCommandId;
271 : : static bool currentCommandIdUsed;
272 : :
273 : : /*
274 : : * xactStartTimestamp is the value of transaction_timestamp().
275 : : * stmtStartTimestamp is the value of statement_timestamp().
276 : : * xactStopTimestamp is the time at which we log a commit / abort WAL record,
277 : : * or if that was skipped, the time of the first subsequent
278 : : * GetCurrentTransactionStopTimestamp() call.
279 : : *
280 : : * These do not change as we enter and exit subtransactions, so we don't
281 : : * keep them inside the TransactionState stack.
282 : : */
283 : : static TimestampTz xactStartTimestamp;
284 : : static TimestampTz stmtStartTimestamp;
285 : : static TimestampTz xactStopTimestamp;
286 : :
287 : : /*
288 : : * GID to be used for preparing the current transaction. This is also
289 : : * global to a whole transaction, so we don't keep it in the state stack.
290 : : */
291 : : static char *prepareGID;
292 : :
293 : : /*
294 : : * Some commands want to force synchronous commit.
295 : : */
296 : : static bool forceSyncCommit = false;
297 : :
298 : : /* Flag for logging statements in a transaction. */
299 : : bool xact_is_sampled = false;
300 : :
301 : : /*
302 : : * Private context for transaction-abort work --- we reserve space for this
303 : : * at startup to ensure that AbortTransaction and AbortSubTransaction can work
304 : : * when we've run out of memory.
305 : : */
306 : : static MemoryContext TransactionAbortContext = NULL;
307 : :
308 : : /*
309 : : * List of add-on start- and end-of-xact callbacks
310 : : */
311 : : typedef struct XactCallbackItem
312 : : {
313 : : struct XactCallbackItem *next;
314 : : XactCallback callback;
315 : : void *arg;
316 : : } XactCallbackItem;
317 : :
318 : : static XactCallbackItem *Xact_callbacks = NULL;
319 : :
320 : : /*
321 : : * List of add-on start- and end-of-subxact callbacks
322 : : */
323 : : typedef struct SubXactCallbackItem
324 : : {
325 : : struct SubXactCallbackItem *next;
326 : : SubXactCallback callback;
327 : : void *arg;
328 : : } SubXactCallbackItem;
329 : :
330 : : static SubXactCallbackItem *SubXact_callbacks = NULL;
331 : :
332 : :
333 : : /* local function prototypes */
334 : : static void AssignTransactionId(TransactionState s);
335 : : static void AbortTransaction(void);
336 : : static void AtAbort_Memory(void);
337 : : static void AtCleanup_Memory(void);
338 : : static void AtAbort_ResourceOwner(void);
339 : : static void AtCCI_LocalCache(void);
340 : : static void AtCommit_Memory(void);
341 : : static void AtStart_Cache(void);
342 : : static void AtStart_Memory(void);
343 : : static void AtStart_ResourceOwner(void);
344 : : static void CallXactCallbacks(XactEvent event);
345 : : static void CallSubXactCallbacks(SubXactEvent event,
346 : : SubTransactionId mySubid,
347 : : SubTransactionId parentSubid);
348 : : static void CleanupTransaction(void);
349 : : static void CheckTransactionBlock(bool isTopLevel, bool throwError,
350 : : const char *stmtType);
351 : : static void CommitTransaction(void);
352 : : static TransactionId RecordTransactionAbort(bool isSubXact);
353 : : static void StartTransaction(void);
354 : :
355 : : static bool CommitTransactionCommandInternal(void);
356 : : static bool AbortCurrentTransactionInternal(void);
357 : :
358 : : static void StartSubTransaction(void);
359 : : static void CommitSubTransaction(void);
360 : : static void AbortSubTransaction(void);
361 : : static void CleanupSubTransaction(void);
362 : : static void PushTransaction(void);
363 : : static void PopTransaction(void);
364 : :
365 : : static void AtSubAbort_Memory(void);
366 : : static void AtSubCleanup_Memory(void);
367 : : static void AtSubAbort_ResourceOwner(void);
368 : : static void AtSubCommit_Memory(void);
369 : : static void AtSubStart_Memory(void);
370 : : static void AtSubStart_ResourceOwner(void);
371 : :
372 : : static void ShowTransactionState(const char *str);
373 : : static void ShowTransactionStateRec(const char *str, TransactionState s);
374 : : static const char *BlockStateAsString(TBlockState blockState);
375 : : static const char *TransStateAsString(TransState state);
376 : :
377 : :
378 : : /* ----------------------------------------------------------------
379 : : * transaction state accessors
380 : : * ----------------------------------------------------------------
381 : : */
382 : :
383 : : /*
384 : : * IsTransactionState
385 : : *
386 : : * This returns true if we are inside a valid transaction; that is,
387 : : * it is safe to initiate database access, take heavyweight locks, etc.
388 : : */
389 : : bool
10952 bruce@momjian.us 390 :CBC 196288448 : IsTransactionState(void)
391 : : {
10651 392 : 196288448 : TransactionState s = CurrentTransactionState;
393 : :
394 : : /*
395 : : * TRANS_DEFAULT and TRANS_ABORT are obviously unsafe states. However, we
396 : : * also reject the startup/shutdown states TRANS_START, TRANS_COMMIT,
397 : : * TRANS_PREPARE since it might be too soon or too late within those
398 : : * transition states to do anything interesting. Hence, the only "valid"
399 : : * state is TRANS_INPROGRESS.
400 : : */
7091 tgl@sss.pgh.pa.us 401 : 196288448 : return (s->state == TRANS_INPROGRESS);
402 : : }
403 : :
404 : : /*
405 : : * IsAbortedTransactionBlockState
406 : : *
407 : : * This returns true if we are within an aborted transaction block.
408 : : */
409 : : bool
9508 410 : 944937 : IsAbortedTransactionBlockState(void)
411 : : {
10651 bruce@momjian.us 412 : 944937 : TransactionState s = CurrentTransactionState;
413 : :
8103 414 [ + + ]: 944937 : if (s->blockState == TBLOCK_ABORT ||
8162 tgl@sss.pgh.pa.us 415 [ + + ]: 943025 : s->blockState == TBLOCK_SUBABORT)
10651 bruce@momjian.us 416 : 2398 : return true;
417 : :
418 : 942539 : return false;
419 : : }
420 : :
421 : :
422 : : /*
423 : : * GetTopTransactionId
424 : : *
425 : : * This will return the XID of the main transaction, assigning one if
426 : : * it's not yet set. Be careful to call this only inside a valid xact.
427 : : */
428 : : TransactionId
8162 tgl@sss.pgh.pa.us 429 : 32119 : GetTopTransactionId(void)
430 : : {
2779 tmunro@postgresql.or 431 [ + + ]: 32119 : if (!FullTransactionIdIsValid(XactTopFullTransactionId))
7001 tgl@sss.pgh.pa.us 432 : 578 : AssignTransactionId(&TopTransactionStateData);
2779 tmunro@postgresql.or 433 : 32119 : return XidFromFullTransactionId(XactTopFullTransactionId);
434 : : }
435 : :
436 : : /*
437 : : * GetTopTransactionIdIfAny
438 : : *
439 : : * This will return the XID of the main transaction, if one is assigned.
440 : : * It will return InvalidTransactionId if we are not currently inside a
441 : : * transaction, or inside a transaction that hasn't yet been assigned an XID.
442 : : */
443 : : TransactionId
7001 tgl@sss.pgh.pa.us 444 : 86346768 : GetTopTransactionIdIfAny(void)
445 : : {
2779 tmunro@postgresql.or 446 : 86346768 : return XidFromFullTransactionId(XactTopFullTransactionId);
447 : : }
448 : :
449 : : /*
450 : : * GetCurrentTransactionId
451 : : *
452 : : * This will return the XID of the current transaction (main or sub
453 : : * transaction), assigning one if it's not yet set. Be careful to call this
454 : : * only inside a valid xact.
455 : : */
456 : : TransactionId
9508 tgl@sss.pgh.pa.us 457 : 17155618 : GetCurrentTransactionId(void)
458 : : {
10651 bruce@momjian.us 459 : 17155618 : TransactionState s = CurrentTransactionState;
460 : :
2779 tmunro@postgresql.or 461 [ + + ]: 17155618 : if (!FullTransactionIdIsValid(s->fullTransactionId))
7001 tgl@sss.pgh.pa.us 462 : 177128 : AssignTransactionId(s);
2779 tmunro@postgresql.or 463 : 17155618 : return XidFromFullTransactionId(s->fullTransactionId);
464 : : }
465 : :
466 : : /*
467 : : * GetCurrentTransactionIdIfAny
468 : : *
469 : : * This will return the XID of the current sub xact, if one is assigned.
470 : : * It will return InvalidTransactionId if we are not currently inside a
471 : : * transaction, or inside a transaction that hasn't been assigned an XID yet.
472 : : */
473 : : TransactionId
7001 tgl@sss.pgh.pa.us 474 : 24618606 : GetCurrentTransactionIdIfAny(void)
475 : : {
2779 tmunro@postgresql.or 476 : 24618606 : return XidFromFullTransactionId(CurrentTransactionState->fullTransactionId);
477 : : }
478 : :
479 : : /*
480 : : * GetTopFullTransactionId
481 : : *
482 : : * This will return the FullTransactionId of the main transaction, assigning
483 : : * one if it's not yet set. Be careful to call this only inside a valid xact.
484 : : */
485 : : FullTransactionId
486 : 3481 : GetTopFullTransactionId(void)
487 : : {
488 [ + + ]: 3481 : if (!FullTransactionIdIsValid(XactTopFullTransactionId))
489 : 2116 : AssignTransactionId(&TopTransactionStateData);
490 : 3481 : return XactTopFullTransactionId;
491 : : }
492 : :
493 : : /*
494 : : * GetTopFullTransactionIdIfAny
495 : : *
496 : : * This will return the FullTransactionId of the main transaction, if one is
497 : : * assigned. It will return InvalidFullTransactionId if we are not currently
498 : : * inside a transaction, or inside a transaction that hasn't yet been assigned
499 : : * one.
500 : : */
501 : : FullTransactionId
502 : 16 : GetTopFullTransactionIdIfAny(void)
503 : : {
504 : 16 : return XactTopFullTransactionId;
505 : : }
506 : :
507 : : /*
508 : : * GetCurrentFullTransactionId
509 : : *
510 : : * This will return the FullTransactionId of the current transaction (main or
511 : : * sub transaction), assigning one if it's not yet set. Be careful to call
512 : : * this only inside a valid xact.
513 : : */
514 : : FullTransactionId
515 : 371 : GetCurrentFullTransactionId(void)
516 : : {
517 : 371 : TransactionState s = CurrentTransactionState;
518 : :
519 [ + + ]: 371 : if (!FullTransactionIdIsValid(s->fullTransactionId))
520 : 14 : AssignTransactionId(s);
521 : 371 : return s->fullTransactionId;
522 : : }
523 : :
524 : : /*
525 : : * GetCurrentFullTransactionIdIfAny
526 : : *
527 : : * This will return the FullTransactionId of the current sub xact, if one is
528 : : * assigned. It will return InvalidFullTransactionId if we are not currently
529 : : * inside a transaction, or inside a transaction that hasn't been assigned one
530 : : * yet.
531 : : */
532 : : FullTransactionId
2779 tmunro@postgresql.or 533 :UBC 0 : GetCurrentFullTransactionIdIfAny(void)
534 : : {
535 : 0 : return CurrentTransactionState->fullTransactionId;
536 : : }
537 : :
538 : : /*
539 : : * MarkCurrentTransactionIdLoggedIfAny
540 : : *
541 : : * Remember that the current xid - if it is assigned - now has been wal logged.
542 : : */
543 : : void
4713 rhaas@postgresql.org 544 :CBC 24565171 : MarkCurrentTransactionIdLoggedIfAny(void)
545 : : {
2779 tmunro@postgresql.or 546 [ + + ]: 24565171 : if (FullTransactionIdIsValid(CurrentTransactionState->fullTransactionId))
4713 rhaas@postgresql.org 547 : 24208442 : CurrentTransactionState->didLogXid = true;
548 : 24565171 : }
549 : :
550 : : /*
551 : : * IsSubxactTopXidLogPending
552 : : *
553 : : * This is used to decide whether we need to WAL log the top-level XID for
554 : : * operation in a subtransaction. We require that for logical decoding, see
555 : : * LogicalDecodingProcessRecord.
556 : : *
557 : : * This returns true if effective_wal_level is logical and we are inside
558 : : * a valid subtransaction, for which the assignment was not yet written to
559 : : * any WAL record.
560 : : */
561 : : bool
1829 akapila@postgresql.o 562 : 24574180 : IsSubxactTopXidLogPending(void)
563 : : {
564 : : /* check whether it is already logged */
565 [ + + ]: 24574180 : if (CurrentTransactionState->topXidLogged)
566 : 102145 : return false;
567 : :
568 : : /* effective_wal_level has to be logical */
569 [ + + + + ]: 24472035 : if (!XLogLogicalInfoActive())
570 : 23867097 : return false;
571 : :
572 : : /* we need to be in a transaction state */
573 [ + + ]: 604938 : if (!IsTransactionState())
574 : 4425 : return false;
575 : :
576 : : /* it has to be a subtransaction */
577 [ + + ]: 600513 : if (!IsSubTransaction())
578 : 600043 : return false;
579 : :
580 : : /* the subtransaction has to have a XID assigned */
581 [ + + ]: 470 : if (!TransactionIdIsValid(GetCurrentTransactionIdIfAny()))
582 : 8 : return false;
583 : :
584 : 462 : return true;
585 : : }
586 : :
587 : : /*
588 : : * MarkSubxactTopXidLogged
589 : : *
590 : : * Remember that the top transaction id for the current subtransaction is WAL
591 : : * logged now.
592 : : */
593 : : void
594 : 230 : MarkSubxactTopXidLogged(void)
595 : : {
596 [ - + ]: 230 : Assert(IsSubxactTopXidLogPending());
597 : :
598 : 230 : CurrentTransactionState->topXidLogged = true;
599 : 230 : }
600 : :
601 : : /*
602 : : * GetStableLatestTransactionId
603 : : *
604 : : * Get the transaction's XID if it has one, else read the next-to-be-assigned
605 : : * XID. Once we have a value, return that same value for the remainder of the
606 : : * current transaction. This is meant to provide the reference point for the
607 : : * age(xid) function, but might be useful for other maintenance tasks as well.
608 : : */
609 : : TransactionId
5291 simon@2ndQuadrant.co 610 : 119 : GetStableLatestTransactionId(void)
611 : : {
612 : : static LocalTransactionId lxid = InvalidLocalTransactionId;
613 : : static TransactionId stablexid = InvalidTransactionId;
614 : :
977 heikki.linnakangas@i 615 [ + + ]: 119 : if (lxid != MyProc->vxid.lxid)
616 : : {
617 : 2 : lxid = MyProc->vxid.lxid;
5290 simon@2ndQuadrant.co 618 : 2 : stablexid = GetTopTransactionIdIfAny();
619 [ + - ]: 2 : if (!TransactionIdIsValid(stablexid))
2089 tmunro@postgresql.or 620 : 2 : stablexid = ReadNextTransactionId();
621 : : }
622 : :
5290 simon@2ndQuadrant.co 623 [ - + ]: 119 : Assert(TransactionIdIsValid(stablexid));
624 : :
5291 625 : 119 : return stablexid;
626 : : }
627 : :
628 : : /*
629 : : * AssignTransactionId
630 : : *
631 : : * Assigns a new permanent FullTransactionId to the given TransactionState.
632 : : * We do not assign XIDs to transactions until/unless this is called.
633 : : * Also, any parent TransactionStates that don't yet have XIDs are assigned
634 : : * one; this maintains the invariant that a child transaction has an XID
635 : : * following its parent's.
636 : : */
637 : : static void
7001 tgl@sss.pgh.pa.us 638 : 181064 : AssignTransactionId(TransactionState s)
639 : : {
6930 bruce@momjian.us 640 : 181064 : bool isSubXact = (s->parent != NULL);
641 : : ResourceOwner currentOwner;
4566 642 : 181064 : bool log_unknown_top = false;
643 : :
644 : : /* Assert that caller didn't screw up */
2779 tmunro@postgresql.or 645 [ - + ]: 181064 : Assert(!FullTransactionIdIsValid(s->fullTransactionId));
8085 tgl@sss.pgh.pa.us 646 [ - + ]: 181064 : Assert(s->state == TRANS_INPROGRESS);
647 : :
648 : : /*
649 : : * Workers synchronize transaction state at the beginning of each parallel
650 : : * operation, so we can't account for new XIDs at this point.
651 : : */
4038 rhaas@postgresql.org 652 [ + - - + ]: 181064 : if (IsInParallelMode() || IsParallelWorker())
952 tgl@sss.pgh.pa.us 653 [ # # ]:UBC 0 : ereport(ERROR,
654 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
655 : : errmsg("cannot assign transaction IDs during a parallel operation")));
656 : :
657 : : /*
658 : : * Ensure parent(s) have XIDs, so that a child always has an XID later
659 : : * than its parent. Mustn't recurse here, or we might get a stack
660 : : * overflow if we're at the bottom of a huge stack of subtransactions none
661 : : * of which have XIDs yet.
662 : : */
2779 tmunro@postgresql.or 663 [ + + + + ]:CBC 181064 : if (isSubXact && !FullTransactionIdIsValid(s->parent->fullTransactionId))
664 : : {
5688 bruce@momjian.us 665 : 635 : TransactionState p = s->parent;
666 : : TransactionState *parents;
667 : 635 : size_t parentOffset = 0;
668 : :
330 michael@paquier.xyz 669 : 635 : parents = palloc_array(TransactionState, s->nestingLevel);
2779 tmunro@postgresql.or 670 [ + + + + ]: 1863 : while (p != NULL && !FullTransactionIdIsValid(p->fullTransactionId))
671 : : {
5949 rhaas@postgresql.org 672 : 1228 : parents[parentOffset++] = p;
673 : 1228 : p = p->parent;
674 : : }
675 : :
676 : : /*
677 : : * This is technically a recursive call, but the recursion will never
678 : : * be more than one layer deep.
679 : : */
680 [ + + ]: 1863 : while (parentOffset != 0)
681 : 1228 : AssignTransactionId(parents[--parentOffset]);
682 : :
683 : 635 : pfree(parents);
684 : : }
685 : :
686 : : /*
687 : : * When effective_wal_level is logical, guarantee that a subtransaction's
688 : : * xid can only be seen in the WAL stream if its toplevel xid has been
689 : : * logged before. If necessary we log an xact_assignment record with fewer
690 : : * than PGPROC_MAX_CACHED_SUBXIDS. Note that it is fine if didLogXid isn't
691 : : * set for a transaction even though it appears in a WAL record, we just
692 : : * might superfluously log something. That can happen when an xid is
693 : : * included somewhere inside a wal record, but not in XLogRecord->xl_xid,
694 : : * like in xl_standby_locks.
695 : : */
4713 696 [ + + + + : 181064 : if (isSubXact && XLogLogicalInfoActive() &&
+ + ]
697 [ + + ]: 312 : !TopTransactionStateData.didLogXid)
698 : 28 : log_unknown_top = true;
699 : :
700 : : /*
701 : : * Generate a new FullTransactionId and record its xid in PGPROC and
702 : : * pg_subtrans.
703 : : *
704 : : * NB: we must make the subtrans entry BEFORE the Xid appears anywhere in
705 : : * shared storage other than PGPROC; because if there's no room for it in
706 : : * PGPROC, the subtrans entry is needed to ensure that other backends see
707 : : * the Xid as "running". See GetNewTransactionId.
708 : : */
2779 tmunro@postgresql.or 709 : 181064 : s->fullTransactionId = GetNewTransactionId(isSubXact);
4207 rhaas@postgresql.org 710 [ + + ]: 181064 : if (!isSubXact)
2779 tmunro@postgresql.or 711 : 164579 : XactTopFullTransactionId = s->fullTransactionId;
712 : :
7001 tgl@sss.pgh.pa.us 713 [ + + ]: 181064 : if (isSubXact)
2779 tmunro@postgresql.or 714 : 16485 : SubTransSetParent(XidFromFullTransactionId(s->fullTransactionId),
715 : 16485 : XidFromFullTransactionId(s->parent->fullTransactionId));
716 : :
717 : : /*
718 : : * If it's a top-level transaction, the predicate locking system needs to
719 : : * be told about it too.
720 : : */
5662 tgl@sss.pgh.pa.us 721 [ + + ]: 181064 : if (!isSubXact)
2779 tmunro@postgresql.or 722 : 164579 : RegisterPredicateLockingXid(XidFromFullTransactionId(s->fullTransactionId));
723 : :
724 : : /*
725 : : * Acquire lock on the transaction XID. (We assume this cannot block.) We
726 : : * have to ensure that the lock is assigned to the transaction's own
727 : : * ResourceOwner.
728 : : */
8085 tgl@sss.pgh.pa.us 729 : 181064 : currentOwner = CurrentResourceOwner;
3312 730 : 181064 : CurrentResourceOwner = s->curTransactionOwner;
731 : :
2779 tmunro@postgresql.or 732 : 181064 : XactLockTableInsert(XidFromFullTransactionId(s->fullTransactionId));
733 : :
8085 tgl@sss.pgh.pa.us 734 : 181064 : CurrentResourceOwner = currentOwner;
735 : :
736 : : /*
737 : : * Every PGPROC_MAX_CACHED_SUBXIDS assigned transaction ids within each
738 : : * top-level transaction we issue a WAL record for the assignment. We
739 : : * include the top-level xid and all the subxids that have not yet been
740 : : * reported using XLOG_XACT_ASSIGNMENT records.
741 : : *
742 : : * This is required to limit the amount of shared memory required in a hot
743 : : * standby server to keep track of in-progress XIDs. See notes for
744 : : * RecordKnownAssignedTransactionIds().
745 : : *
746 : : * We don't keep track of the immediate parent of each subxid, only the
747 : : * top-level transaction that each subxact belongs to. This is correct in
748 : : * recovery only because aborted subtransactions are separately WAL
749 : : * logged.
750 : : *
751 : : * This is correct even for the case where several levels above us didn't
752 : : * have an xid assigned as we recursed up to them beforehand.
753 : : */
6165 simon@2ndQuadrant.co 754 [ + + + + ]: 181064 : if (isSubXact && XLogStandbyInfoActive())
755 : : {
2779 tmunro@postgresql.or 756 : 16223 : unreportedXids[nUnreportedXids] = XidFromFullTransactionId(s->fullTransactionId);
6165 simon@2ndQuadrant.co 757 : 16223 : nUnreportedXids++;
758 : :
759 : : /*
760 : : * ensure this test matches similar one in
761 : : * RecoverPreparedTransactions()
762 : : */
4713 rhaas@postgresql.org 763 [ + + + + ]: 16223 : if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS ||
764 : : log_unknown_top)
765 : : {
766 : : xl_xact_assignment xlrec;
767 : :
768 : : /*
769 : : * xtop is always set by now because we recurse up transaction
770 : : * stack to the highest unassigned xid and then come back down
771 : : */
6165 simon@2ndQuadrant.co 772 : 254 : xlrec.xtop = GetTopTransactionId();
773 [ - + ]: 254 : Assert(TransactionIdIsValid(xlrec.xtop));
774 : 254 : xlrec.nsubxacts = nUnreportedXids;
775 : :
4368 heikki.linnakangas@i 776 : 254 : XLogBeginInsert();
632 peter@eisentraut.org 777 : 254 : XLogRegisterData(&xlrec, MinSizeOfXactAssignment);
778 : 254 : XLogRegisterData(unreportedXids,
779 : : nUnreportedXids * sizeof(TransactionId));
780 : :
4368 heikki.linnakangas@i 781 : 254 : (void) XLogInsert(RM_XACT_ID, XLOG_XACT_ASSIGNMENT);
782 : :
6165 simon@2ndQuadrant.co 783 : 254 : nUnreportedXids = 0;
784 : : /* mark top, not current xact as having been logged */
4713 rhaas@postgresql.org 785 : 254 : TopTransactionStateData.didLogXid = true;
786 : : }
787 : : }
6165 simon@2ndQuadrant.co 788 : 181064 : }
789 : :
790 : : /*
791 : : * GetCurrentSubTransactionId
792 : : */
793 : : SubTransactionId
8085 tgl@sss.pgh.pa.us 794 : 2013661 : GetCurrentSubTransactionId(void)
795 : : {
796 : 2013661 : TransactionState s = CurrentTransactionState;
797 : :
798 : 2013661 : return s->subTransactionId;
799 : : }
800 : :
801 : : /*
802 : : * SubTransactionIsActive
803 : : *
804 : : * Test if the specified subxact ID is still active. Note caller is
805 : : * responsible for checking whether this ID is relevant to the current xact.
806 : : */
807 : : bool
4995 tgl@sss.pgh.pa.us 808 :UBC 0 : SubTransactionIsActive(SubTransactionId subxid)
809 : : {
810 : : TransactionState s;
811 : :
812 [ # # ]: 0 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
813 : : {
814 [ # # ]: 0 : if (s->state == TRANS_ABORT)
815 : 0 : continue;
816 [ # # ]: 0 : if (s->subTransactionId == subxid)
817 : 0 : return true;
818 : : }
819 : 0 : return false;
820 : : }
821 : :
822 : :
823 : : /*
824 : : * GetCurrentCommandId
825 : : *
826 : : * "used" must be true if the caller intends to use the command ID to mark
827 : : * inserted/updated/deleted tuples. false means the ID is being fetched
828 : : * for read-only purposes (ie, as a snapshot validity cutoff). See
829 : : * CommandCounterIncrement() for discussion.
830 : : */
831 : : CommandId
6915 tgl@sss.pgh.pa.us 832 :CBC 7442661 : GetCurrentCommandId(bool used)
833 : : {
834 : : /* this is global to a transaction, not subtransaction-local */
835 [ + + ]: 7442661 : if (used)
836 : : {
837 : : /*
838 : : * Forbid setting currentCommandIdUsed in a parallel worker, because
839 : : * we have no provision for communicating this back to the leader. We
840 : : * could relax this restriction when currentCommandIdUsed was already
841 : : * true at the start of the parallel operation.
842 : : */
952 843 [ - + ]: 4255675 : if (IsParallelWorker())
952 tgl@sss.pgh.pa.us 844 [ # # ]:UBC 0 : ereport(ERROR,
845 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
846 : : errmsg("cannot modify data in a parallel worker")));
847 : :
6915 tgl@sss.pgh.pa.us 848 :CBC 4255675 : currentCommandIdUsed = true;
849 : : }
8085 850 : 7442661 : return currentCommandId;
851 : : }
852 : :
853 : : /*
854 : : * SetParallelStartTimestamps
855 : : *
856 : : * In a parallel worker, we should inherit the parent transaction's
857 : : * timestamps rather than setting our own. The parallel worker
858 : : * infrastructure must call this to provide those values before
859 : : * calling StartTransaction() or SetCurrentStatementStartTimestamp().
860 : : */
861 : : void
2952 862 : 2043 : SetParallelStartTimestamps(TimestampTz xact_ts, TimestampTz stmt_ts)
863 : : {
864 [ - + ]: 2043 : Assert(IsParallelWorker());
865 : 2043 : xactStartTimestamp = xact_ts;
866 : 2043 : stmtStartTimestamp = stmt_ts;
867 : 2043 : }
868 : :
869 : : /*
870 : : * GetCurrentTransactionStartTimestamp
871 : : */
872 : : TimestampTz
7799 873 : 45298 : GetCurrentTransactionStartTimestamp(void)
874 : : {
875 : 45298 : return xactStartTimestamp;
876 : : }
877 : :
878 : : /*
879 : : * GetCurrentStatementStartTimestamp
880 : : */
881 : : TimestampTz
7499 bruce@momjian.us 882 : 1405221 : GetCurrentStatementStartTimestamp(void)
883 : : {
884 : 1405221 : return stmtStartTimestamp;
885 : : }
886 : :
887 : : /*
888 : : * GetCurrentTransactionStopTimestamp
889 : : *
890 : : * If the transaction stop time hasn't already been set, which can happen if
891 : : * we decided we don't need to log an XLOG record, set xactStopTimestamp.
892 : : */
893 : : TimestampTz
7129 tgl@sss.pgh.pa.us 894 : 1335684 : GetCurrentTransactionStopTimestamp(void)
895 : : {
1483 andres@anarazel.de 896 : 1335684 : TransactionState s PG_USED_FOR_ASSERTS_ONLY = CurrentTransactionState;
897 : :
898 : : /* should only be called after commit / abort processing */
899 [ + + + + : 1335684 : Assert(s->state == TRANS_DEFAULT ||
- + - - ]
900 : : s->state == TRANS_COMMIT ||
901 : : s->state == TRANS_ABORT ||
902 : : s->state == TRANS_PREPARE);
903 : :
904 [ + + ]: 1335684 : if (xactStopTimestamp == 0)
905 : 374350 : xactStopTimestamp = GetCurrentTimestamp();
906 : :
907 : 1335684 : return xactStopTimestamp;
908 : : }
909 : :
910 : : /*
911 : : * SetCurrentStatementStartTimestamp
912 : : *
913 : : * In a parallel worker, this should already have been provided by a call
914 : : * to SetParallelStartTimestamps().
915 : : */
916 : : void
7499 bruce@momjian.us 917 : 655387 : SetCurrentStatementStartTimestamp(void)
918 : : {
2952 tgl@sss.pgh.pa.us 919 [ + + ]: 655387 : if (!IsParallelWorker())
920 : 653344 : stmtStartTimestamp = GetCurrentTimestamp();
921 : : else
922 [ - + ]: 2043 : Assert(stmtStartTimestamp != 0);
7499 bruce@momjian.us 923 : 655387 : }
924 : :
925 : : /*
926 : : * GetCurrentTransactionNestLevel
927 : : *
928 : : * Note: this will return zero when not inside any transaction, one when
929 : : * inside a top-level transaction, etc.
930 : : */
931 : : int
8162 tgl@sss.pgh.pa.us 932 : 25795496 : GetCurrentTransactionNestLevel(void)
933 : : {
934 : 25795496 : TransactionState s = CurrentTransactionState;
935 : :
936 : 25795496 : return s->nestingLevel;
937 : : }
938 : :
939 : :
940 : : /*
941 : : * TransactionIdIsCurrentTransactionId
942 : : */
943 : : bool
11076 scrappy@hub.org 944 : 86545693 : TransactionIdIsCurrentTransactionId(TransactionId xid)
945 : : {
946 : : TransactionState s;
947 : :
948 : : /*
949 : : * We always say that BootstrapTransactionId is "not my transaction ID"
950 : : * even when it is (ie, during bootstrap). Along with the fact that
951 : : * transam.c always treats BootstrapTransactionId as already committed,
952 : : * this causes the heapam_visibility.c routines to see all tuples as
953 : : * committed, which is what we need during bootstrap. (Bootstrap mode
954 : : * only inserts tuples, it never updates or deletes them, so all tuples
955 : : * can be presumed good immediately.)
956 : : *
957 : : * Likewise, InvalidTransactionId and FrozenTransactionId are certainly
958 : : * not my transaction ID, so we can just return "false" immediately for
959 : : * any non-normal XID.
960 : : */
7305 tgl@sss.pgh.pa.us 961 [ + + ]: 86545693 : if (!TransactionIdIsNormal(xid))
10651 bruce@momjian.us 962 : 757819 : return false;
963 : :
2551 tmunro@postgresql.or 964 [ + + ]: 85787874 : if (TransactionIdEquals(xid, GetTopTransactionIdIfAny()))
965 : 61647323 : return true;
966 : :
967 : : /*
968 : : * In parallel workers, the XIDs we must consider as current are stored in
969 : : * ParallelCurrentXids rather than the transaction-state stack. Note that
970 : : * the XIDs in this array are sorted numerically rather than according to
971 : : * transactionIdPrecedes order.
972 : : */
4207 rhaas@postgresql.org 973 [ + + ]: 24140551 : if (nParallelCurrentXids > 0)
974 : : {
975 : : int low,
976 : : high;
977 : :
978 : 4954711 : low = 0;
979 : 4954711 : high = nParallelCurrentXids - 1;
980 [ + + ]: 19523580 : while (low <= high)
981 : : {
982 : : int middle;
983 : : TransactionId probe;
984 : :
985 : 19376061 : middle = low + (high - low) / 2;
986 : 19376061 : probe = ParallelCurrentXids[middle];
987 [ + + ]: 19376061 : if (probe == xid)
988 : 4807192 : return true;
989 [ + + ]: 14568869 : else if (probe < xid)
990 : 14421354 : low = middle + 1;
991 : : else
992 : 147515 : high = middle - 1;
993 : : }
994 : 147519 : return false;
995 : : }
996 : :
997 : : /*
998 : : * We will return true for the Xid of the current subtransaction, any of
999 : : * its subcommitted children, any of its parents, or any of their
1000 : : * previously subcommitted children. However, a transaction being aborted
1001 : : * is no longer "current", even though it may still have an entry on the
1002 : : * state stack.
1003 : : */
8104 tgl@sss.pgh.pa.us 1004 [ + + ]: 38288848 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
1005 : : {
1006 : : int low,
1007 : : high;
1008 : :
1009 [ - + ]: 19270036 : if (s->state == TRANS_ABORT)
8104 tgl@sss.pgh.pa.us 1010 :UBC 0 : continue;
2779 tmunro@postgresql.or 1011 [ + + ]:CBC 19270036 : if (!FullTransactionIdIsValid(s->fullTransactionId))
8085 tgl@sss.pgh.pa.us 1012 : 6187065 : continue; /* it can't have any child XIDs either */
2779 tmunro@postgresql.or 1013 [ + + ]: 13082971 : if (TransactionIdEquals(xid, XidFromFullTransactionId(s->fullTransactionId)))
8162 tgl@sss.pgh.pa.us 1014 : 163968 : return true;
1015 : : /* As the childXids array is ordered, we can use binary search */
6807 1016 : 12919003 : low = 0;
1017 : 12919003 : high = s->nChildXids - 1;
1018 [ + + ]: 12919890 : while (low <= high)
1019 : : {
1020 : : int middle;
1021 : : TransactionId probe;
1022 : :
1023 : 3947 : middle = low + (high - low) / 2;
1024 : 3947 : probe = s->childXids[middle];
1025 [ + + ]: 3947 : if (TransactionIdEquals(probe, xid))
8162 1026 : 3060 : return true;
6807 1027 [ + + ]: 887 : else if (TransactionIdPrecedes(probe, xid))
1028 : 803 : low = middle + 1;
1029 : : else
1030 : 84 : high = middle - 1;
1031 : : }
1032 : : }
1033 : :
8162 1034 : 19018812 : return false;
1035 : : }
1036 : :
1037 : : /*
1038 : : * TransactionStartedDuringRecovery
1039 : : *
1040 : : * Returns true if the current transaction started while recovery was still
1041 : : * in progress. Recovery might have ended since so RecoveryInProgress() might
1042 : : * return false already.
1043 : : */
1044 : : bool
6165 simon@2ndQuadrant.co 1045 : 9371682 : TransactionStartedDuringRecovery(void)
1046 : : {
1047 : 9371682 : return CurrentTransactionState->startedInRecovery;
1048 : : }
1049 : :
1050 : : /*
1051 : : * GetTopReadOnlyTransactionNestLevel
1052 : : *
1053 : : * Note: this will return zero when not inside any transaction or when neither
1054 : : * a top-level transaction nor subtransactions are read-only, one when the
1055 : : * top-level transaction is read-only, two when one level of subtransaction is
1056 : : * read-only, etc.
1057 : : *
1058 : : * Note: subtransactions of the topmost read-only transaction are also
1059 : : * read-only, because they inherit read-only mode from the transaction, and
1060 : : * thus can't change to read-write mode (see check_transaction_read_only).
1061 : : */
1062 : : int
214 efujita@postgresql.o 1063 : 9 : GetTopReadOnlyTransactionNestLevel(void)
1064 : : {
1065 : 9 : TransactionState s = CurrentTransactionState;
1066 : :
1067 [ - + ]: 9 : if (!XactReadOnly)
214 efujita@postgresql.o 1068 :UBC 0 : return 0;
214 efujita@postgresql.o 1069 [ + + ]:CBC 10 : while (s->nestingLevel > 1)
1070 : : {
1071 [ + + ]: 4 : if (!s->prevXactReadOnly)
1072 : 3 : return s->nestingLevel;
1073 : 1 : s = s->parent;
1074 : : }
1075 : 6 : return s->nestingLevel;
1076 : : }
1077 : :
1078 : : /*
1079 : : * EnterParallelMode
1080 : : */
1081 : : void
4207 rhaas@postgresql.org 1082 : 4735 : EnterParallelMode(void)
1083 : : {
1084 : 4735 : TransactionState s = CurrentTransactionState;
1085 : :
1086 [ - + ]: 4735 : Assert(s->parallelModeLevel >= 0);
1087 : :
1088 : 4735 : ++s->parallelModeLevel;
1089 : 4735 : }
1090 : :
1091 : : /*
1092 : : * ExitParallelMode
1093 : : */
1094 : : void
1095 : 2683 : ExitParallelMode(void)
1096 : : {
1097 : 2683 : TransactionState s = CurrentTransactionState;
1098 : :
1099 [ - + ]: 2683 : Assert(s->parallelModeLevel > 0);
952 tgl@sss.pgh.pa.us 1100 [ + - + - : 2683 : Assert(s->parallelModeLevel > 1 || s->parallelChildXact ||
- + ]
1101 : : !ParallelContextActive());
1102 : :
4207 rhaas@postgresql.org 1103 : 2683 : --s->parallelModeLevel;
1104 : 2683 : }
1105 : :
1106 : : /*
1107 : : * IsInParallelMode
1108 : : *
1109 : : * Are we in a parallel operation, as either the leader or a worker? Check
1110 : : * this to prohibit operations that change backend-local state expected to
1111 : : * match across all workers. Mere caches usually don't require such a
1112 : : * restriction. State modified in a strict push/pop fashion, such as the
1113 : : * active snapshot stack, is often fine.
1114 : : *
1115 : : * We say we are in parallel mode if we are in a subxact of a transaction
1116 : : * that's initiated a parallel operation; for most purposes that context
1117 : : * has all the same restrictions.
1118 : : */
1119 : : bool
1120 : 7451961 : IsInParallelMode(void)
1121 : : {
952 tgl@sss.pgh.pa.us 1122 : 7451961 : TransactionState s = CurrentTransactionState;
1123 : :
1124 [ + + + + ]: 7451961 : return s->parallelModeLevel != 0 || s->parallelChildXact;
1125 : : }
1126 : :
1127 : : /*
1128 : : * CommandCounterIncrement
1129 : : */
1130 : : void
9508 1131 : 1956293 : CommandCounterIncrement(void)
1132 : : {
1133 : : /*
1134 : : * If the current value of the command counter hasn't been "used" to mark
1135 : : * tuples, we need not increment it, since there's no need to distinguish
1136 : : * a read-only command from others. This helps postpone command counter
1137 : : * overflow, and keeps no-op CommandCounterIncrement operations cheap.
1138 : : */
6915 1139 [ + + ]: 1956293 : if (currentCommandIdUsed)
1140 : : {
1141 : : /*
1142 : : * Workers synchronize transaction state at the beginning of each
1143 : : * parallel operation, so we can't account for new commands after that
1144 : : * point.
1145 : : */
4038 rhaas@postgresql.org 1146 [ + - - + ]: 723518 : if (IsInParallelMode() || IsParallelWorker())
952 tgl@sss.pgh.pa.us 1147 [ # # ]:UBC 0 : ereport(ERROR,
1148 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
1149 : : errmsg("cannot start commands during a parallel operation")));
1150 : :
6915 tgl@sss.pgh.pa.us 1151 :CBC 723518 : currentCommandId += 1;
4805 rhaas@postgresql.org 1152 [ - + ]: 723518 : if (currentCommandId == InvalidCommandId)
1153 : : {
6915 tgl@sss.pgh.pa.us 1154 :UBC 0 : currentCommandId -= 1;
1155 [ # # ]: 0 : ereport(ERROR,
1156 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1157 : : errmsg("cannot have more than 2^32-2 commands in a transaction")));
1158 : : }
6915 tgl@sss.pgh.pa.us 1159 :CBC 723518 : currentCommandIdUsed = false;
1160 : :
1161 : : /* Propagate new command ID into static snapshots */
6751 alvherre@alvh.no-ip. 1162 : 723518 : SnapshotSetCommandId(currentCommandId);
1163 : :
1164 : : /*
1165 : : * Make any catalog changes done by the just-completed command visible
1166 : : * in the local syscache. We obviously don't need to do this after a
1167 : : * read-only command. (But see hacks in inval.c to make real sure we
1168 : : * don't think a command that queued inval messages was read-only.)
1169 : : */
6115 tgl@sss.pgh.pa.us 1170 : 723518 : AtCCI_LocalCache();
1171 : : }
11076 scrappy@hub.org 1172 : 1956289 : }
1173 : :
1174 : : /*
1175 : : * ForceSyncCommit
1176 : : *
1177 : : * Interface routine to allow commands to force a synchronous commit of the
1178 : : * current top-level transaction. Currently, two-phase commit does not
1179 : : * persist and restore this variable. So long as all callers use
1180 : : * PreventInTransactionBlock(), that omission has no consequences.
1181 : : */
1182 : : void
7036 tgl@sss.pgh.pa.us 1183 : 595 : ForceSyncCommit(void)
1184 : : {
1185 : 595 : forceSyncCommit = true;
1186 : 595 : }
1187 : :
1188 : :
1189 : : /* ----------------------------------------------------------------
1190 : : * StartTransaction stuff
1191 : : * ----------------------------------------------------------------
1192 : : */
1193 : :
1194 : : /*
1195 : : * AtStart_Cache
1196 : : */
1197 : : static void
9508 1198 : 428421 : AtStart_Cache(void)
1199 : : {
9270 1200 : 428421 : AcceptInvalidationMessages();
11076 scrappy@hub.org 1201 : 428421 : }
1202 : :
1203 : : /*
1204 : : * AtStart_Memory
1205 : : */
1206 : : static void
9508 tgl@sss.pgh.pa.us 1207 : 428421 : AtStart_Memory(void)
1208 : : {
8162 1209 : 428421 : TransactionState s = CurrentTransactionState;
1210 : :
1211 : : /*
1212 : : * Remember the memory context that was active prior to transaction start.
1213 : : */
857 1214 : 428421 : s->priorContext = CurrentMemoryContext;
1215 : :
1216 : : /*
1217 : : * If this is the first time through, create a private context for
1218 : : * AbortTransaction to work in. By reserving some space now, we can
1219 : : * insulate AbortTransaction from out-of-memory scenarios. Like
1220 : : * ErrorContext, we set it up with slow growth rate and a nonzero minimum
1221 : : * size, so that space will be reserved immediately.
1222 : : */
7287 1223 [ + + ]: 428421 : if (TransactionAbortContext == NULL)
1224 : 19533 : TransactionAbortContext =
2946 1225 : 19533 : AllocSetContextCreate(TopMemoryContext,
1226 : : "TransactionAbortContext",
1227 : : 32 * 1024,
1228 : : 32 * 1024,
1229 : : 32 * 1024);
1230 : :
1231 : : /*
1232 : : * Likewise, if this is the first time through, create a top-level context
1233 : : * for transaction-local data. This context will be reset at transaction
1234 : : * end, and then re-used in later transactions.
1235 : : */
857 1236 [ + + ]: 428421 : if (TopTransactionContext == NULL)
1237 : 19533 : TopTransactionContext =
1238 : 19533 : AllocSetContextCreate(TopMemoryContext,
1239 : : "TopTransactionContext",
1240 : : ALLOCSET_DEFAULT_SIZES);
1241 : :
1242 : : /*
1243 : : * In a top-level transaction, CurTransactionContext is the same as
1244 : : * TopTransactionContext.
1245 : : */
8162 1246 : 428421 : CurTransactionContext = TopTransactionContext;
1247 : 428421 : s->curTransactionContext = CurTransactionContext;
1248 : :
1249 : : /* Make the CurTransactionContext active. */
1250 : 428421 : MemoryContextSwitchTo(CurTransactionContext);
11076 scrappy@hub.org 1251 : 428421 : }
1252 : :
1253 : : /*
1254 : : * AtStart_ResourceOwner
1255 : : */
1256 : : static void
8146 tgl@sss.pgh.pa.us 1257 : 428421 : AtStart_ResourceOwner(void)
1258 : : {
1259 : 428421 : TransactionState s = CurrentTransactionState;
1260 : :
1261 : : /*
1262 : : * We shouldn't have a transaction resource owner already.
1263 : : */
1264 [ - + ]: 428421 : Assert(TopTransactionResourceOwner == NULL);
1265 : :
1266 : : /*
1267 : : * Create a toplevel resource owner for the transaction.
1268 : : */
1269 : 428421 : s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
1270 : :
1271 : 428421 : TopTransactionResourceOwner = s->curTransactionOwner;
1272 : 428421 : CurTransactionResourceOwner = s->curTransactionOwner;
1273 : 428421 : CurrentResourceOwner = s->curTransactionOwner;
1274 : 428421 : }
1275 : :
1276 : : /* ----------------------------------------------------------------
1277 : : * StartSubTransaction stuff
1278 : : * ----------------------------------------------------------------
1279 : : */
1280 : :
1281 : : /*
1282 : : * AtSubStart_Memory
1283 : : */
1284 : : static void
8162 1285 : 22999 : AtSubStart_Memory(void)
1286 : : {
1287 : 22999 : TransactionState s = CurrentTransactionState;
1288 : :
1289 [ - + ]: 22999 : Assert(CurTransactionContext != NULL);
1290 : :
1291 : : /*
1292 : : * Remember the context that was active prior to subtransaction start.
1293 : : */
857 1294 : 22999 : s->priorContext = CurrentMemoryContext;
1295 : :
1296 : : /*
1297 : : * Create a CurTransactionContext, which will be used to hold data that
1298 : : * survives subtransaction commit but disappears on subtransaction abort.
1299 : : * We make it a child of the immediate parent's CurTransactionContext.
1300 : : */
8162 1301 : 22999 : CurTransactionContext = AllocSetContextCreate(CurTransactionContext,
1302 : : "CurTransactionContext",
1303 : : ALLOCSET_DEFAULT_SIZES);
1304 : 22999 : s->curTransactionContext = CurTransactionContext;
1305 : :
1306 : : /* Make the CurTransactionContext active. */
1307 : 22999 : MemoryContextSwitchTo(CurTransactionContext);
1308 : 22999 : }
1309 : :
1310 : : /*
1311 : : * AtSubStart_ResourceOwner
1312 : : */
1313 : : static void
8146 1314 : 22999 : AtSubStart_ResourceOwner(void)
1315 : : {
1316 : 22999 : TransactionState s = CurrentTransactionState;
1317 : :
1318 [ - + ]: 22999 : Assert(s->parent != NULL);
1319 : :
1320 : : /*
1321 : : * Create a resource owner for the subtransaction. We make it a child of
1322 : : * the immediate parent's resource owner.
1323 : : */
1324 : 22999 : s->curTransactionOwner =
1325 : 22999 : ResourceOwnerCreate(s->parent->curTransactionOwner,
1326 : : "SubTransaction");
1327 : :
1328 : 22999 : CurTransactionResourceOwner = s->curTransactionOwner;
1329 : 22999 : CurrentResourceOwner = s->curTransactionOwner;
1330 : 22999 : }
1331 : :
1332 : : /* ----------------------------------------------------------------
1333 : : * CommitTransaction stuff
1334 : : * ----------------------------------------------------------------
1335 : : */
1336 : :
1337 : : /*
1338 : : * RecordTransactionCommit
1339 : : *
1340 : : * Returns latest XID among xact and its children, or InvalidTransactionId
1341 : : * if the xact has no XID. (We compute that here just because it's easier.)
1342 : : *
1343 : : * If you change this function, see RecordTransactionCommitPrepared also.
1344 : : */
1345 : : static TransactionId
6114 1346 : 390315 : RecordTransactionCommit(void)
1347 : : {
7001 1348 : 390315 : TransactionId xid = GetTopTransactionIdIfAny();
6930 bruce@momjian.us 1349 : 390315 : bool markXidCommitted = TransactionIdIsValid(xid);
6998 tgl@sss.pgh.pa.us 1350 : 390315 : TransactionId latestXid = InvalidTransactionId;
1351 : : int nrels;
1352 : : RelFileLocator *rels;
1353 : : int nchildren;
1354 : : TransactionId *children;
1674 andres@anarazel.de 1355 : 390315 : int ndroppedstats = 0;
1356 : 390315 : xl_xact_stats_item *droppedstats = NULL;
5928 rhaas@postgresql.org 1357 : 390315 : int nmsgs = 0;
6165 simon@2ndQuadrant.co 1358 : 390315 : SharedInvalidationMessage *invalMessages = NULL;
5928 rhaas@postgresql.org 1359 : 390315 : bool RelcacheInitFileInval = false;
1360 : : bool wrote_xlog;
1361 : :
1362 : : /*
1363 : : * Log pending invalidations for logical decoding of in-progress
1364 : : * transactions. Normally for DDLs, we log this at each command end,
1365 : : * however, for certain cases where we directly update the system table
1366 : : * without a transaction block, the invalidations are not logged till this
1367 : : * time.
1368 : : */
2296 akapila@postgresql.o 1369 [ + + + + ]: 390315 : if (XLogLogicalInfoActive())
1370 : 15572 : LogLogicalInvalidations();
1371 : :
1372 : : /* Get data needed for commit record */
5928 rhaas@postgresql.org 1373 : 390315 : nrels = smgrGetPendingDeletes(true, &rels);
8146 tgl@sss.pgh.pa.us 1374 : 390315 : nchildren = xactGetCommittedChildren(&children);
1674 andres@anarazel.de 1375 : 390315 : ndroppedstats = pgstat_get_transactional_drops(true, &droppedstats);
5928 rhaas@postgresql.org 1376 [ + + ]: 390315 : if (XLogStandbyInfoActive())
1377 : 328289 : nmsgs = xactGetCommittedInvalidationMessages(&invalMessages,
1378 : : &RelcacheInitFileInval);
5247 heikki.linnakangas@i 1379 : 390315 : wrote_xlog = (XactLastRecEnd != 0);
1380 : :
1381 : : /* Load the injection point before entering the critical section */
42 alvherre@kurilemu.de 1382 : 390315 : INJECTION_POINT_LOAD("commit-before-clog-update");
1383 : :
1384 : : /*
1385 : : * If we haven't been assigned an XID yet, we neither can, nor do we want
1386 : : * to write a COMMIT record.
1387 : : */
7001 tgl@sss.pgh.pa.us 1388 [ + + ]: 390315 : if (!markXidCommitted)
1389 : : {
1390 : : /*
1391 : : * We expect that every RelationDropStorage is followed by a catalog
1392 : : * update, and hence XID assignment, so we shouldn't get here with any
1393 : : * pending deletes. Same is true for dropping stats.
1394 : : *
1395 : : * Use a real test not just an Assert to check this, since it's a bit
1396 : : * fragile.
1397 : : */
1674 andres@anarazel.de 1398 [ + - - + ]: 234422 : if (nrels != 0 || ndroppedstats != 0)
7001 tgl@sss.pgh.pa.us 1399 [ # # ]:UBC 0 : elog(ERROR, "cannot commit a transaction that deleted files but has no xid");
1400 : :
1401 : : /* Can't have child XIDs either; AssignTransactionId enforces this */
7001 tgl@sss.pgh.pa.us 1402 [ - + ]:CBC 234422 : Assert(nchildren == 0);
1403 : :
1404 : : /*
1405 : : * Transactions without an assigned xid can contain invalidation
1406 : : * messages. While inplace updates do this, this is not known to be
1407 : : * necessary; see comment at inplace CacheInvalidateHeapTuple().
1408 : : * Extensions might still rely on this capability, and standbys may
1409 : : * need to process those invals. We can't emit a commit record
1410 : : * without an xid, and we don't want to force assigning an xid,
1411 : : * because that'd be problematic for e.g. vacuum. Hence we emit a
1412 : : * bespoke record for the invalidations. We don't want to use that in
1413 : : * case a commit record is emitted, so they happen synchronously with
1414 : : * commits (besides not wanting to emit more WAL records).
1415 : : *
1416 : : * XXX Every known use of this capability is a defect. Since an XID
1417 : : * isn't controlling visibility of the change that prompted invals,
1418 : : * other sessions need the inval even if this transactions aborts.
1419 : : *
1420 : : * ON COMMIT DELETE ROWS does a nontransactional index_build(), which
1421 : : * queues a relcache inval, including in transactions without an xid
1422 : : * that had read the (empty) table. Standbys don't need any ON COMMIT
1423 : : * DELETE ROWS invals, but we've not done the work to withhold them.
1424 : : */
3848 andres@anarazel.de 1425 [ + + ]: 234422 : if (nmsgs != 0)
1426 : : {
1427 : 11504 : LogStandbyInvalidations(nmsgs, invalMessages,
1428 : : RelcacheInitFileInval);
3801 rhaas@postgresql.org 1429 : 11504 : wrote_xlog = true; /* not strictly necessary */
1430 : : }
1431 : :
1432 : : /*
1433 : : * If we didn't create XLOG entries, we're done here; otherwise we
1434 : : * should trigger flushing those entries the same as a commit record
1435 : : * would. This will primarily happen for HOT pruning and the like; we
1436 : : * want these to be flushed to disk in due time.
1437 : : */
5799 1438 [ + + ]: 234422 : if (!wrote_xlog)
7001 tgl@sss.pgh.pa.us 1439 : 206025 : goto cleanup;
1440 : : }
1441 : : else
1442 : : {
1443 : : bool replorigin;
1444 : :
1445 : : /*
1446 : : * Are we using the replication origins feature? Or, in other words,
1447 : : * are we replaying remote actions?
1448 : : */
281 msawada@postgresql.o 1449 [ + + ]: 156976 : replorigin = (replorigin_xact_state.origin != InvalidReplOriginId &&
1450 [ + - ]: 1083 : replorigin_xact_state.origin != DoNotReplicateId);
1451 : :
1452 : : /*
1453 : : * Mark ourselves as within our "commit critical section". This
1454 : : * forces any concurrent checkpoint to wait until we've updated
1455 : : * pg_xact. Without this, it is possible for the checkpoint to set
1456 : : * REDO after the XLOG record but fail to flush the pg_xact update to
1457 : : * disk, leading to loss of the transaction commit if the system
1458 : : * crashes a little later.
1459 : : *
1460 : : * Note: we could, but don't bother to, set this flag in
1461 : : * RecordTransactionAbort. That's because loss of a transaction abort
1462 : : * is noncritical; the presumption would be that it aborted, anyway.
1463 : : *
1464 : : * It's safe to change the delayChkptFlags flag of our own backend
1465 : : * without holding the ProcArrayLock, since we're the only one
1466 : : * modifying it. This makes checkpoint's determination of which xacts
1467 : : * are delaying the checkpoint a bit fuzzy, but it doesn't matter.
1468 : : *
1469 : : * Note, it is important to get the commit timestamp after marking the
1470 : : * transaction in the commit critical section. See
1471 : : * RecordTransactionCommitPrepared.
1472 : : */
470 akapila@postgresql.o 1473 [ - + ]: 155893 : Assert((MyProc->delayChkptFlags & DELAY_CHKPT_IN_COMMIT) == 0);
7001 tgl@sss.pgh.pa.us 1474 : 155893 : START_CRIT_SECTION();
470 akapila@postgresql.o 1475 : 155893 : MyProc->delayChkptFlags |= DELAY_CHKPT_IN_COMMIT;
1476 : :
1477 [ - + ]: 155893 : Assert(xactStopTimestamp == 0);
1478 : :
1479 : : /*
1480 : : * Ensures the DELAY_CHKPT_IN_COMMIT flag write is globally visible
1481 : : * before commit time is written.
1482 : : */
1483 : 155893 : pg_write_barrier();
1484 : :
1485 : : /*
1486 : : * Insert the commit XLOG record.
1487 : : */
1483 andres@anarazel.de 1488 : 155893 : XactLogCommitRecord(GetCurrentTransactionStopTimestamp(),
1489 : : nchildren, children, nrels, rels,
1490 : : ndroppedstats, droppedstats,
1491 : : nmsgs, invalMessages,
1492 : : RelcacheInitFileInval,
1493 : : MyXactFlags,
1494 : : InvalidTransactionId, NULL /* plain commit */ );
1495 : :
4055 alvherre@alvh.no-ip. 1496 [ + + ]: 155893 : if (replorigin)
1497 : : /* Move LSNs forward for this replication origin */
281 msawada@postgresql.o 1498 : 1083 : replorigin_session_advance(replorigin_xact_state.origin_lsn,
1499 : : XactLastRecEnd);
1500 : :
1501 : : /*
1502 : : * Record commit timestamp. The value comes from plain commit
1503 : : * timestamp if there's no replication origin; otherwise, the
1504 : : * timestamp was already set in replorigin_xact_state.origin_timestamp
1505 : : * by replication.
1506 : : *
1507 : : * We don't need to WAL-log anything here, as the commit record
1508 : : * written above already contains the data.
1509 : : */
1510 : :
1511 [ + + + + ]: 155893 : if (!replorigin || replorigin_xact_state.origin_timestamp == 0)
1512 : 154918 : replorigin_xact_state.origin_timestamp = GetCurrentTransactionStopTimestamp();
1513 : :
4355 alvherre@alvh.no-ip. 1514 : 155893 : TransactionTreeSetCommitTsData(xid, nchildren, children,
1515 : : replorigin_xact_state.origin_timestamp,
281 msawada@postgresql.o 1516 : 155893 : replorigin_xact_state.origin);
1517 : : }
1518 : :
1519 : : /*
1520 : : * Check if we want to commit asynchronously. We can allow the XLOG flush
1521 : : * to happen asynchronously if synchronous_commit=off, or if the current
1522 : : * transaction has not performed any WAL-logged operation or didn't assign
1523 : : * an xid. The transaction can end up not writing any WAL, even if it has
1524 : : * an xid, if it only wrote to temporary and/or unlogged tables. It can
1525 : : * end up having written WAL without an xid if it did HOT pruning. In
1526 : : * case of a crash, the loss of such a transaction will be irrelevant;
1527 : : * temp tables will be lost anyway, unlogged tables will be truncated and
1528 : : * HOT pruning will be done again later. (Given the foregoing, you might
1529 : : * think that it would be unnecessary to emit the XLOG record at all in
1530 : : * this case, but we don't currently try to do that. It would certainly
1531 : : * cause problems at least in Hot Standby mode, where the
1532 : : * KnownAssignedXids machinery requires tracking every XID assignment. It
1533 : : * might be OK to skip it only when wal_level < replica, but for now we
1534 : : * don't.)
1535 : : *
1536 : : * However, if we're doing cleanup of any non-temp rels or committing any
1537 : : * command that wanted to force sync commit, then we must flush XLOG
1538 : : * immediately. (We must not allow asynchronous commit if there are any
1539 : : * non-temp tables to be deleted, because we might delete the files before
1540 : : * the COMMIT record is flushed to disk. We do allow asynchronous commit
1541 : : * if all to-be-deleted tables are temporary though, since they are lost
1542 : : * anyway if we crash.)
1543 : : */
4270 andres@anarazel.de 1544 [ + + + + ]: 184290 : if ((wrote_xlog && markXidCommitted &&
1545 [ + + + + ]: 184290 : synchronous_commit > SYNCHRONOUS_COMMIT_OFF) ||
5694 rhaas@postgresql.org 1546 [ + + ]: 35659 : forceSyncCommit || nrels > 0)
1547 : : {
7001 tgl@sss.pgh.pa.us 1548 : 148650 : XLogFlush(XactLastRecEnd);
1549 : :
1550 : : /*
1551 : : * The commit record is on disk, but not in CLOG yet. A test can stop
1552 : : * here to see what others make of the transaction meanwhile.
1553 : : */
42 alvherre@kurilemu.de 1554 : 148650 : INJECTION_POINT_CACHED("commit-before-clog-update", NULL);
1555 : :
1556 : : /*
1557 : : * Now we may update the CLOG, if we wrote a COMMIT record above
1558 : : */
7001 tgl@sss.pgh.pa.us 1559 [ + - ]: 148650 : if (markXidCommitted)
6590 alvherre@alvh.no-ip. 1560 : 148650 : TransactionIdCommitTree(xid, nchildren, children);
1561 : : }
1562 : : else
1563 : : {
1564 : : /*
1565 : : * Asynchronous commit case:
1566 : : *
1567 : : * This enables possible committed transaction loss in the case of a
1568 : : * postmaster crash because WAL buffers are left unwritten. Ideally we
1569 : : * could issue the WAL write without the fsync, but some
1570 : : * wal_sync_methods do not allow separate write/fsync.
1571 : : *
1572 : : * Report the latest async commit LSN, so that the WAL writer knows to
1573 : : * flush this commit.
1574 : : */
5943 simon@2ndQuadrant.co 1575 : 35640 : XLogSetAsyncXactLSN(XactLastRecEnd);
1576 : :
1577 : : /*
1578 : : * We must not immediately update the CLOG, since we didn't flush the
1579 : : * XLOG. Instead, we store the LSN up to which the XLOG must be
1580 : : * flushed before the CLOG may be updated.
1581 : : */
7001 tgl@sss.pgh.pa.us 1582 [ + + ]: 35640 : if (markXidCommitted)
6590 alvherre@alvh.no-ip. 1583 : 7243 : TransactionIdAsyncCommitTree(xid, nchildren, children, XactLastRecEnd);
1584 : : }
1585 : :
1586 : : /*
1587 : : * If we entered a commit critical section, leave it now, and let
1588 : : * checkpoints proceed.
1589 : : */
7001 tgl@sss.pgh.pa.us 1590 [ + + ]: 184290 : if (markXidCommitted)
1591 : : {
470 akapila@postgresql.o 1592 : 155893 : MyProc->delayChkptFlags &= ~DELAY_CHKPT_IN_COMMIT;
9428 tgl@sss.pgh.pa.us 1593 [ - + ]: 155893 : END_CRIT_SECTION();
1594 : : }
1595 : :
1596 : : /* Compute latestXid while we have the child XIDs handy */
6998 1597 : 184290 : latestXid = TransactionIdLatest(xid, nchildren, children);
1598 : :
1599 : : /*
1600 : : * Wait for synchronous replication, if required. Similar to the decision
1601 : : * above about using committing asynchronously we only want to wait if
1602 : : * this backend assigned an xid and wrote WAL. No need to wait if an xid
1603 : : * was assigned due to temporary/unlogged tables or due to HOT pruning.
1604 : : *
1605 : : * Note that at this stage we have marked clog, but still show as running
1606 : : * in the procarray and continue to hold locks.
1607 : : */
4270 andres@anarazel.de 1608 [ + + + + ]: 184290 : if (wrote_xlog && markXidCommitted)
3873 rhaas@postgresql.org 1609 : 151146 : SyncRepWaitForLSN(XactLastRecEnd, true);
1610 : :
1611 : : /* remember end of last commit record */
4208 andres@anarazel.de 1612 : 184290 : XactLastCommitEnd = XactLastRecEnd;
1613 : :
1614 : : /* Reset XactLastRecEnd until the next transaction writes something */
5247 heikki.linnakangas@i 1615 : 184290 : XactLastRecEnd = 0;
7001 tgl@sss.pgh.pa.us 1616 : 390315 : cleanup:
1617 : : /* Clean up local data */
7811 1618 [ + + ]: 390315 : if (rels)
1619 : 12318 : pfree(rels);
1674 andres@anarazel.de 1620 [ + + ]: 390315 : if (ndroppedstats)
1621 : 14758 : pfree(droppedstats);
1622 : :
6998 tgl@sss.pgh.pa.us 1623 : 390315 : return latestXid;
1624 : : }
1625 : :
1626 : :
1627 : : /*
1628 : : * AtCCI_LocalCache
1629 : : */
1630 : : static void
6115 1631 : 723518 : AtCCI_LocalCache(void)
1632 : : {
1633 : : /*
1634 : : * Make any pending relation map changes visible. We must do this before
1635 : : * processing local sinval messages, so that the map changes will get
1636 : : * reflected into the relcache when relcache invals are processed.
1637 : : */
1638 : 723518 : AtCCI_RelationMap();
1639 : :
1640 : : /*
1641 : : * Make catalog changes visible to me for the next command.
1642 : : */
8162 1643 : 723518 : CommandEndInvalidationMessages();
9796 inoue@tpf.co.jp 1644 : 723514 : }
1645 : :
1646 : : /*
1647 : : * AtCommit_Memory
1648 : : */
1649 : : static void
9508 tgl@sss.pgh.pa.us 1650 : 392654 : AtCommit_Memory(void)
1651 : : {
857 1652 : 392654 : TransactionState s = CurrentTransactionState;
1653 : :
1654 : : /*
1655 : : * Return to the memory context that was current before we started the
1656 : : * transaction. (In principle, this could not be any of the contexts we
1657 : : * are about to delete. If it somehow is, assertions in mcxt.c will
1658 : : * complain.)
1659 : : */
1660 : 392654 : MemoryContextSwitchTo(s->priorContext);
1661 : :
1662 : : /*
1663 : : * Release all transaction-local memory. TopTransactionContext survives
1664 : : * but becomes empty; any sub-contexts go away.
1665 : : */
9622 1666 [ - + ]: 392654 : Assert(TopTransactionContext != NULL);
857 1667 : 392654 : MemoryContextReset(TopTransactionContext);
1668 : :
1669 : : /*
1670 : : * Clear these pointers as a pro-forma matter. (Notionally, while
1671 : : * TopTransactionContext still exists, it's currently not associated with
1672 : : * this TransactionState struct.)
1673 : : */
8162 1674 : 392654 : CurTransactionContext = NULL;
857 1675 : 392654 : s->curTransactionContext = NULL;
8162 1676 : 392654 : }
1677 : :
1678 : : /* ----------------------------------------------------------------
1679 : : * CommitSubTransaction stuff
1680 : : * ----------------------------------------------------------------
1681 : : */
1682 : :
1683 : : /*
1684 : : * AtSubCommit_Memory
1685 : : */
1686 : : static void
1687 : 17382 : AtSubCommit_Memory(void)
1688 : : {
1689 : 17382 : TransactionState s = CurrentTransactionState;
1690 : :
1691 [ - + ]: 17382 : Assert(s->parent != NULL);
1692 : :
1693 : : /* Return to parent transaction level's memory context. */
1694 : 17382 : CurTransactionContext = s->parent->curTransactionContext;
1695 : 17382 : MemoryContextSwitchTo(CurTransactionContext);
1696 : :
1697 : : /*
1698 : : * Ordinarily we cannot throw away the child's CurTransactionContext,
1699 : : * since the data it contains will be needed at upper commit. However, if
1700 : : * there isn't actually anything in it, we can throw it away. This avoids
1701 : : * a small memory leak in the common case of "trivial" subxacts.
1702 : : */
8085 1703 [ + + ]: 17382 : if (MemoryContextIsEmpty(s->curTransactionContext))
1704 : : {
1705 : 17365 : MemoryContextDelete(s->curTransactionContext);
1706 : 17365 : s->curTransactionContext = NULL;
1707 : : }
8162 1708 : 17382 : }
1709 : :
1710 : : /*
1711 : : * AtSubCommit_childXids
1712 : : *
1713 : : * Pass my own XID and my child XIDs up to my parent as committed children.
1714 : : */
1715 : : static void
1716 : 15473 : AtSubCommit_childXids(void)
1717 : : {
1718 : 15473 : TransactionState s = CurrentTransactionState;
1719 : : int new_nChildXids;
1720 : :
1721 [ - + ]: 15473 : Assert(s->parent != NULL);
1722 : :
1723 : : /*
1724 : : * The parent childXids array will need to hold my XID and all my
1725 : : * childXids, in addition to the XIDs already there.
1726 : : */
6807 1727 : 15473 : new_nChildXids = s->parent->nChildXids + s->nChildXids + 1;
1728 : :
1729 : : /* Allocate or enlarge the parent array if necessary */
1730 [ + + ]: 15473 : if (s->parent->maxChildXids < new_nChildXids)
1731 : : {
1732 : : int new_maxChildXids;
1733 : : TransactionId *new_childXids;
1734 : :
1735 : : /*
1736 : : * Make it 2x what's needed right now, to avoid having to enlarge it
1737 : : * repeatedly. But we can't go above MaxAllocSize. (The latter limit
1738 : : * is what ensures that we don't need to worry about integer overflow
1739 : : * here or in the calculation of new_nChildXids.)
1740 : : */
1741 : 1729 : new_maxChildXids = Min(new_nChildXids * 2,
1742 : : (int) (MaxAllocSize / sizeof(TransactionId)));
1743 : :
1744 [ - + ]: 1729 : if (new_maxChildXids < new_nChildXids)
6807 tgl@sss.pgh.pa.us 1745 [ # # ]:UBC 0 : ereport(ERROR,
1746 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1747 : : errmsg("maximum number of committed subtransactions (%d) exceeded",
1748 : : (int) (MaxAllocSize / sizeof(TransactionId)))));
1749 : :
1750 : : /*
1751 : : * We keep the child-XID arrays in TopTransactionContext; this avoids
1752 : : * setting up child-transaction contexts for what might be just a few
1753 : : * bytes of grandchild XIDs.
1754 : : */
6807 tgl@sss.pgh.pa.us 1755 [ + + ]:CBC 1729 : if (s->parent->childXids == NULL)
1756 : : new_childXids =
6356 bruce@momjian.us 1757 : 1652 : MemoryContextAlloc(TopTransactionContext,
1758 : : new_maxChildXids * sizeof(TransactionId));
1759 : : else
80 michael@paquier.xyz 1760 :GNC 77 : new_childXids = repalloc_array(s->parent->childXids, TransactionId, new_maxChildXids);
1761 : :
6356 bruce@momjian.us 1762 :CBC 1729 : s->parent->childXids = new_childXids;
6807 tgl@sss.pgh.pa.us 1763 : 1729 : s->parent->maxChildXids = new_maxChildXids;
1764 : : }
1765 : :
1766 : : /*
1767 : : * Copy all my XIDs to parent's array.
1768 : : *
1769 : : * Note: We rely on the fact that the XID of a child always follows that
1770 : : * of its parent. By copying the XID of this subtransaction before the
1771 : : * XIDs of its children, we ensure that the array stays ordered. Likewise,
1772 : : * all XIDs already in the array belong to subtransactions started and
1773 : : * subcommitted before us, so their XIDs must precede ours.
1774 : : */
2779 tmunro@postgresql.or 1775 : 15473 : s->parent->childXids[s->parent->nChildXids] = XidFromFullTransactionId(s->fullTransactionId);
1776 : :
6807 tgl@sss.pgh.pa.us 1777 [ + + ]: 15473 : if (s->nChildXids > 0)
1778 : 1022 : memcpy(&s->parent->childXids[s->parent->nChildXids + 1],
1779 : 1022 : s->childXids,
1780 : 1022 : s->nChildXids * sizeof(TransactionId));
1781 : :
1782 : 15473 : s->parent->nChildXids = new_nChildXids;
1783 : :
1784 : : /* Release child's array to avoid leakage */
1785 [ + + ]: 15473 : if (s->childXids != NULL)
1786 : 1022 : pfree(s->childXids);
1787 : : /* We must reset these to avoid double-free if fail later in commit */
1788 : 15473 : s->childXids = NULL;
1789 : 15473 : s->nChildXids = 0;
1790 : 15473 : s->maxChildXids = 0;
8162 1791 : 15473 : }
1792 : :
1793 : : /* ----------------------------------------------------------------
1794 : : * AbortTransaction stuff
1795 : : * ----------------------------------------------------------------
1796 : : */
1797 : :
1798 : : /*
1799 : : * RecordTransactionAbort
1800 : : *
1801 : : * Returns latest XID among xact and its children, or InvalidTransactionId
1802 : : * if the xact has no XID. (We compute that here just because it's easier.)
1803 : : */
1804 : : static TransactionId
7001 1805 : 41375 : RecordTransactionAbort(bool isSubXact)
1806 : : {
1807 : 41375 : TransactionId xid = GetCurrentTransactionIdIfAny();
1808 : : TransactionId latestXid;
1809 : : int nrels;
1810 : : RelFileLocator *rels;
1674 andres@anarazel.de 1811 : 41375 : int ndroppedstats = 0;
1812 : 41375 : xl_xact_stats_item *droppedstats = NULL;
1813 : : int nchildren;
1814 : : TransactionId *children;
1815 : : TimestampTz xact_time;
1816 : : bool replorigin;
1817 : :
1818 : : /*
1819 : : * If we haven't been assigned an XID, nobody will care whether we aborted
1820 : : * or not. Hence, we're done in that case. It does not matter if we have
1821 : : * rels to delete (note that this routine is not responsible for actually
1822 : : * deleting 'em). We cannot have any child XIDs, either.
1823 : : */
7001 tgl@sss.pgh.pa.us 1824 [ + + ]: 41375 : if (!TransactionIdIsValid(xid))
1825 : : {
1826 : : /* Reset XactLastRecEnd until the next transaction writes something */
1827 [ + + ]: 31982 : if (!isSubXact)
5247 heikki.linnakangas@i 1828 : 27377 : XactLastRecEnd = 0;
6998 tgl@sss.pgh.pa.us 1829 : 31982 : return InvalidTransactionId;
1830 : : }
1831 : :
1832 : : /*
1833 : : * We have a valid XID, so we should write an ABORT record for it.
1834 : : *
1835 : : * We do not flush XLOG to disk here, since the default assumption after a
1836 : : * crash would be that we aborted, anyway. For the same reason, we don't
1837 : : * need to worry about interlocking against checkpoint start.
1838 : : */
1839 : :
1840 : : /*
1841 : : * Check that we haven't aborted halfway through RecordTransactionCommit.
1842 : : */
7001 1843 [ - + ]: 9393 : if (TransactionIdDidCommit(xid))
7001 tgl@sss.pgh.pa.us 1844 [ # # ]:UBC 0 : elog(PANIC, "cannot abort transaction %u, it was already committed",
1845 : : xid);
1846 : :
1847 : : /*
1848 : : * Are we using the replication origins feature? Or, in other words, are
1849 : : * we replaying remote actions?
1850 : : */
281 msawada@postgresql.o 1851 [ + + ]:CBC 9414 : replorigin = (replorigin_xact_state.origin != InvalidReplOriginId &&
1852 [ + - ]: 21 : replorigin_xact_state.origin != DoNotReplicateId);
1853 : :
1854 : : /* Fetch the data we need for the abort record */
5928 rhaas@postgresql.org 1855 : 9393 : nrels = smgrGetPendingDeletes(false, &rels);
7001 tgl@sss.pgh.pa.us 1856 : 9393 : nchildren = xactGetCommittedChildren(&children);
1674 andres@anarazel.de 1857 : 9393 : ndroppedstats = pgstat_get_transactional_drops(false, &droppedstats);
1858 : :
1859 : : /* XXX do we really need a critical section here? */
7001 tgl@sss.pgh.pa.us 1860 : 9393 : START_CRIT_SECTION();
1861 : :
1862 : : /* Write the ABORT record */
1863 [ + + ]: 9393 : if (isSubXact)
4253 andres@anarazel.de 1864 : 1012 : xact_time = GetCurrentTimestamp();
1865 : : else
1866 : : {
1483 1867 : 8381 : xact_time = GetCurrentTransactionStopTimestamp();
1868 : : }
1869 : :
4253 1870 : 9393 : XactLogAbortRecord(xact_time,
1871 : : nchildren, children,
1872 : : nrels, rels,
1873 : : ndroppedstats, droppedstats,
1874 : : MyXactFlags, InvalidTransactionId,
1875 : : NULL);
1876 : :
1396 akapila@postgresql.o 1877 [ + + ]: 9393 : if (replorigin)
1878 : : /* Move LSNs forward for this replication origin */
281 msawada@postgresql.o 1879 : 21 : replorigin_session_advance(replorigin_xact_state.origin_lsn,
1880 : : XactLastRecEnd);
1881 : :
1882 : : /*
1883 : : * Report the latest async abort LSN, so that the WAL writer knows to
1884 : : * flush this abort. There's nothing to be gained by delaying this, since
1885 : : * WALWriter may as well do this when it can. This is important with
1886 : : * streaming replication because if we don't flush WAL regularly we will
1887 : : * find that large aborts leave us with a long backlog for when commits
1888 : : * occur after the abort, increasing our window of data loss should
1889 : : * problems occur at that point.
1890 : : */
6020 simon@2ndQuadrant.co 1891 [ + + ]: 9393 : if (!isSubXact)
5943 1892 : 8381 : XLogSetAsyncXactLSN(XactLastRecEnd);
1893 : :
1894 : : /*
1895 : : * Mark the transaction aborted in clog. This is not absolutely necessary
1896 : : * but we may as well do it while we are here; also, in the subxact case
1897 : : * it is helpful because XactLockTableWait makes use of it to avoid
1898 : : * waiting for already-aborted subtransactions. It is OK to do it without
1899 : : * having flushed the ABORT record to disk, because in event of a crash
1900 : : * we'd be assumed to have aborted anyway.
1901 : : */
6590 alvherre@alvh.no-ip. 1902 : 9393 : TransactionIdAbortTree(xid, nchildren, children);
1903 : :
7001 tgl@sss.pgh.pa.us 1904 [ - + ]: 9393 : END_CRIT_SECTION();
1905 : :
1906 : : /* Compute latestXid while we have the child XIDs handy */
6998 1907 : 9393 : latestXid = TransactionIdLatest(xid, nchildren, children);
1908 : :
1909 : : /*
1910 : : * If we're aborting a subtransaction, we can immediately remove failed
1911 : : * XIDs from PGPROC's cache of running child XIDs. We do that here for
1912 : : * subxacts, because we already have the child XID array at hand. For
1913 : : * main xacts, the equivalent happens just after this function returns.
1914 : : */
7001 1915 [ + + ]: 9393 : if (isSubXact)
6998 1916 : 1012 : XidCacheRemoveRunningXids(xid, nchildren, children, latestXid);
1917 : :
1918 : : /* Reset XactLastRecEnd until the next transaction writes something */
7001 1919 [ + + ]: 9393 : if (!isSubXact)
5247 heikki.linnakangas@i 1920 : 8381 : XactLastRecEnd = 0;
1921 : :
1922 : : /* And clean up local data */
7811 tgl@sss.pgh.pa.us 1923 [ + + ]: 9393 : if (rels)
1924 : 1418 : pfree(rels);
1674 andres@anarazel.de 1925 [ + + ]: 9393 : if (ndroppedstats)
1926 : 1993 : pfree(droppedstats);
1927 : :
1928 : : /*
1929 : : * Test the window where the transaction is aborted in pg_xact but still
1930 : : * present in ProcArray.
1931 : : */
21 heikki.linnakangas@i 1932 : 9393 : INJECTION_POINT("transaction-abort-after-clog", NULL);
1933 : :
6998 tgl@sss.pgh.pa.us 1934 : 9393 : return latestXid;
1935 : : }
1936 : :
1937 : : /*
1938 : : * AtAbort_Memory
1939 : : */
1940 : : static void
9508 1941 : 55855 : AtAbort_Memory(void)
1942 : : {
1943 : : /*
1944 : : * Switch into TransactionAbortContext, which should have some free space
1945 : : * even if nothing else does. We'll work in this context until we've
1946 : : * finished cleaning up.
1947 : : *
1948 : : * It is barely possible to get here when we've not been able to create
1949 : : * TransactionAbortContext yet; if so use TopMemoryContext.
1950 : : */
7287 1951 [ + - ]: 55855 : if (TransactionAbortContext != NULL)
1952 : 55855 : MemoryContextSwitchTo(TransactionAbortContext);
1953 : : else
9622 tgl@sss.pgh.pa.us 1954 :UBC 0 : MemoryContextSwitchTo(TopMemoryContext);
9626 tgl@sss.pgh.pa.us 1955 :CBC 55855 : }
1956 : :
1957 : : /*
1958 : : * AtSubAbort_Memory
1959 : : */
1960 : : static void
8162 1961 : 5617 : AtSubAbort_Memory(void)
1962 : : {
7287 1963 [ - + ]: 5617 : Assert(TransactionAbortContext != NULL);
1964 : :
1965 : 5617 : MemoryContextSwitchTo(TransactionAbortContext);
8162 1966 : 5617 : }
1967 : :
1968 : :
1969 : : /*
1970 : : * AtAbort_ResourceOwner
1971 : : */
1972 : : static void
8067 1973 : 35767 : AtAbort_ResourceOwner(void)
1974 : : {
1975 : : /*
1976 : : * Make sure we have a valid ResourceOwner, if possible (else it will be
1977 : : * NULL, which is OK)
1978 : : */
1979 : 35767 : CurrentResourceOwner = TopTransactionResourceOwner;
1980 : 35767 : }
1981 : :
1982 : : /*
1983 : : * AtSubAbort_ResourceOwner
1984 : : */
1985 : : static void
1986 : 5617 : AtSubAbort_ResourceOwner(void)
1987 : : {
1988 : 5617 : TransactionState s = CurrentTransactionState;
1989 : :
1990 : : /* Make sure we have a valid ResourceOwner */
1991 : 5617 : CurrentResourceOwner = s->curTransactionOwner;
1992 : 5617 : }
1993 : :
1994 : :
1995 : : /*
1996 : : * AtSubAbort_childXids
1997 : : */
1998 : : static void
8085 1999 : 1012 : AtSubAbort_childXids(void)
2000 : : {
2001 : 1012 : TransactionState s = CurrentTransactionState;
2002 : :
2003 : : /*
2004 : : * We keep the child-XID arrays in TopTransactionContext (see
2005 : : * AtSubCommit_childXids). This means we'd better free the array
2006 : : * explicitly at abort to avoid leakage.
2007 : : */
6807 2008 [ + + ]: 1012 : if (s->childXids != NULL)
2009 : 27 : pfree(s->childXids);
2010 : 1012 : s->childXids = NULL;
2011 : 1012 : s->nChildXids = 0;
2012 : 1012 : s->maxChildXids = 0;
2013 : :
2014 : : /*
2015 : : * We could prune the unreportedXids array here. But we don't bother. That
2016 : : * would potentially reduce number of XLOG_XACT_ASSIGNMENT records but it
2017 : : * would likely introduce more CPU time into the more common paths, so we
2018 : : * choose not to do that.
2019 : : */
8085 2020 : 1012 : }
2021 : :
2022 : : /* ----------------------------------------------------------------
2023 : : * CleanupTransaction stuff
2024 : : * ----------------------------------------------------------------
2025 : : */
2026 : :
2027 : : /*
2028 : : * AtCleanup_Memory
2029 : : */
2030 : : static void
9508 2031 : 35767 : AtCleanup_Memory(void)
2032 : : {
857 2033 : 35767 : TransactionState s = CurrentTransactionState;
2034 : :
2035 : : /* Should be at top level */
2036 [ - + ]: 35767 : Assert(s->parent == NULL);
2037 : :
2038 : : /*
2039 : : * Return to the memory context that was current before we started the
2040 : : * transaction. (In principle, this could not be any of the contexts we
2041 : : * are about to delete. If it somehow is, assertions in mcxt.c will
2042 : : * complain.)
2043 : : */
2044 : 35767 : MemoryContextSwitchTo(s->priorContext);
2045 : :
2046 : : /*
2047 : : * Clear the special abort context for next time.
2048 : : */
7287 2049 [ + - ]: 35767 : if (TransactionAbortContext != NULL)
1086 nathan@postgresql.or 2050 : 35767 : MemoryContextReset(TransactionAbortContext);
2051 : :
2052 : : /*
2053 : : * Release all transaction-local memory, the same as in AtCommit_Memory,
2054 : : * except we must cope with the possibility that we didn't get as far as
2055 : : * creating TopTransactionContext.
2056 : : */
9622 tgl@sss.pgh.pa.us 2057 [ + - ]: 35767 : if (TopTransactionContext != NULL)
857 2058 : 35767 : MemoryContextReset(TopTransactionContext);
2059 : :
2060 : : /*
2061 : : * Clear these pointers as a pro-forma matter. (Notionally, while
2062 : : * TopTransactionContext still exists, it's currently not associated with
2063 : : * this TransactionState struct.)
2064 : : */
8162 2065 : 35767 : CurTransactionContext = NULL;
857 2066 : 35767 : s->curTransactionContext = NULL;
11076 scrappy@hub.org 2067 : 35767 : }
2068 : :
2069 : :
2070 : : /* ----------------------------------------------------------------
2071 : : * CleanupSubTransaction stuff
2072 : : * ----------------------------------------------------------------
2073 : : */
2074 : :
2075 : : /*
2076 : : * AtSubCleanup_Memory
2077 : : */
2078 : : static void
8162 tgl@sss.pgh.pa.us 2079 : 5617 : AtSubCleanup_Memory(void)
2080 : : {
2081 : 5617 : TransactionState s = CurrentTransactionState;
2082 : :
2083 [ - + ]: 5617 : Assert(s->parent != NULL);
2084 : :
2085 : : /*
2086 : : * Return to the memory context that was current before we started the
2087 : : * subtransaction. (In principle, this could not be any of the contexts
2088 : : * we are about to delete. If it somehow is, assertions in mcxt.c will
2089 : : * complain.)
2090 : : */
857 2091 : 5617 : MemoryContextSwitchTo(s->priorContext);
2092 : :
2093 : : /* Update CurTransactionContext (might not be same as priorContext) */
8162 2094 : 5617 : CurTransactionContext = s->parent->curTransactionContext;
2095 : :
2096 : : /*
2097 : : * Clear the special abort context for next time.
2098 : : */
7287 2099 [ + - ]: 5617 : if (TransactionAbortContext != NULL)
1086 nathan@postgresql.or 2100 : 5617 : MemoryContextReset(TransactionAbortContext);
2101 : :
2102 : : /*
2103 : : * Delete the subxact local memory contexts. Its CurTransactionContext can
2104 : : * go too (note this also kills CurTransactionContexts from any children
2105 : : * of the subxact).
2106 : : */
8085 tgl@sss.pgh.pa.us 2107 [ + - ]: 5617 : if (s->curTransactionContext)
2108 : 5617 : MemoryContextDelete(s->curTransactionContext);
2109 : 5617 : s->curTransactionContext = NULL;
8162 2110 : 5617 : }
2111 : :
2112 : : /* ----------------------------------------------------------------
2113 : : * interface routines
2114 : : * ----------------------------------------------------------------
2115 : : */
2116 : :
2117 : : /*
2118 : : * StartTransaction
2119 : : */
2120 : : static void
9508 2121 : 428421 : StartTransaction(void)
2122 : : {
2123 : : TransactionState s;
2124 : : VirtualTransactionId vxid;
2125 : :
2126 : : /*
2127 : : * Let's just make sure the state stack is empty
2128 : : */
8085 2129 : 428421 : s = &TopTransactionStateData;
2130 : 428421 : CurrentTransactionState = s;
2131 : :
2779 tmunro@postgresql.or 2132 [ - + ]: 428421 : Assert(!FullTransactionIdIsValid(XactTopFullTransactionId));
2133 : :
2134 : : /* check the current transaction state */
2913 michael@paquier.xyz 2135 [ - + ]: 428421 : Assert(s->state == TRANS_DEFAULT);
2136 : :
2137 : : /*
2138 : : * Set the current transaction state information appropriately during
2139 : : * start processing. Note that once the transaction status is switched
2140 : : * this process cannot fail until the user ID and the security context
2141 : : * flags are fetched below.
2142 : : */
10651 bruce@momjian.us 2143 : 428421 : s->state = TRANS_START;
2779 tmunro@postgresql.or 2144 : 428421 : s->fullTransactionId = InvalidFullTransactionId; /* until assigned */
2145 : :
2146 : : /* Determine if statements are logged in this transaction */
2773 alvherre@alvh.no-ip. 2147 [ - + ]: 428421 : xact_is_sampled = log_xact_sample_rate != 0 &&
2773 alvherre@alvh.no-ip. 2148 [ # # ]:UBC 0 : (log_xact_sample_rate == 1 ||
1803 tgl@sss.pgh.pa.us 2149 [ # # ]: 0 : pg_prng_double(&pg_global_prng_state) <= log_xact_sample_rate);
2150 : :
2151 : : /*
2152 : : * initialize current transaction state fields
2153 : : *
2154 : : * note: prevXactReadOnly is not used at the outermost level
2155 : : */
2913 michael@paquier.xyz 2156 :CBC 428421 : s->nestingLevel = 1;
2157 : 428421 : s->gucNestLevel = 1;
2158 : 428421 : s->childXids = NULL;
2159 : 428421 : s->nChildXids = 0;
2160 : 428421 : s->maxChildXids = 0;
2161 : :
2162 : : /*
2163 : : * Once the current user ID and the security context flags are fetched,
2164 : : * both will be properly reset even if transaction startup fails.
2165 : : */
2166 : 428421 : GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
2167 : :
2168 : : /* SecurityRestrictionContext should never be set outside a transaction */
2169 [ - + ]: 428421 : Assert(s->prevSecContext == 0);
2170 : :
2171 : : /*
2172 : : * Make sure we've reset xact state variables
2173 : : *
2174 : : * If recovery is still in progress, mark this transaction as read-only.
2175 : : * We have lower level defences in XLogInsert and elsewhere to stop us
2176 : : * from modifying data during recovery, but this gives the normal
2177 : : * indication to the user that the transaction is read-only.
2178 : : */
6165 simon@2ndQuadrant.co 2179 [ + + ]: 428421 : if (RecoveryInProgress())
2180 : : {
2181 : 2592 : s->startedInRecovery = true;
2182 : 2592 : XactReadOnly = true;
2183 : : }
2184 : : else
2185 : : {
2186 : 425829 : s->startedInRecovery = false;
2187 : 425829 : XactReadOnly = DefaultXactReadOnly;
2188 : : }
5750 heikki.linnakangas@i 2189 : 428421 : XactDeferrable = DefaultXactDeferrable;
8421 tgl@sss.pgh.pa.us 2190 : 428421 : XactIsoLevel = DefaultXactIsoLevel;
7036 2191 : 428421 : forceSyncCommit = false;
3515 simon@2ndQuadrant.co 2192 : 428421 : MyXactFlags = 0;
2193 : :
2194 : : /*
2195 : : * reinitialize within-transaction counters
2196 : : */
8085 tgl@sss.pgh.pa.us 2197 : 428421 : s->subTransactionId = TopSubTransactionId;
2198 : 428421 : currentSubTransactionId = TopSubTransactionId;
2199 : 428421 : currentCommandId = FirstCommandId;
6915 2200 : 428421 : currentCommandIdUsed = false;
2201 : :
2202 : : /*
2203 : : * initialize reported xid accounting
2204 : : */
6165 simon@2ndQuadrant.co 2205 : 428421 : nUnreportedXids = 0;
4713 rhaas@postgresql.org 2206 : 428421 : s->didLogXid = false;
2207 : :
2208 : : /*
2209 : : * must initialize resource-management stuff first
2210 : : */
8146 tgl@sss.pgh.pa.us 2211 : 428421 : AtStart_Memory();
2212 : 428421 : AtStart_ResourceOwner();
2213 : :
2214 : : /*
2215 : : * Assign a new LocalTransactionId, and combine it with the proc number to
2216 : : * form a virtual transaction id.
2217 : : */
977 heikki.linnakangas@i 2218 : 428421 : vxid.procNumber = MyProcNumber;
7001 tgl@sss.pgh.pa.us 2219 : 428421 : vxid.localTransactionId = GetNextLocalTransactionId();
2220 : :
2221 : : /*
2222 : : * Lock the virtual transaction id before we announce it in the proc array
2223 : : */
2224 : 428421 : VirtualXactLockTableInsert(vxid);
2225 : :
2226 : : /*
2227 : : * Advertise it in the proc array. We assume assignment of
2228 : : * localTransactionId is atomic, and the proc number should be set
2229 : : * already.
2230 : : */
977 heikki.linnakangas@i 2231 [ - + ]: 428421 : Assert(MyProc->vxid.procNumber == vxid.procNumber);
2232 : 428421 : MyProc->vxid.lxid = vxid.localTransactionId;
2233 : :
2234 : : TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);
2235 : :
2236 : : /*
2237 : : * set transaction_timestamp() (a/k/a now()). Normally, we want this to
2238 : : * be the same as the first command's statement_timestamp(), so don't do a
2239 : : * fresh GetCurrentTimestamp() call (which'd be expensive anyway). But
2240 : : * for transactions started inside procedures (i.e., nonatomic SPI
2241 : : * contexts), we do need to advance the timestamp. Also, in a parallel
2242 : : * worker, the timestamp should already have been provided by a call to
2243 : : * SetParallelStartTimestamps().
2244 : : */
2952 tgl@sss.pgh.pa.us 2245 [ + + ]: 428421 : if (!IsParallelWorker())
2246 : : {
2950 2247 [ + + ]: 422292 : if (!SPI_inside_nonatomic_context())
2248 : 420071 : xactStartTimestamp = stmtStartTimestamp;
2249 : : else
2250 : 2221 : xactStartTimestamp = GetCurrentTimestamp();
2251 : : }
2252 : : else
2952 2253 [ - + ]: 6129 : Assert(xactStartTimestamp != 0);
6995 2254 : 428421 : pgstat_report_xact_timestamp(xactStartTimestamp);
2255 : : /* Mark xactStopTimestamp as unset. */
2950 2256 : 428421 : xactStopTimestamp = 0;
2257 : :
2258 : : /*
2259 : : * initialize other subsystems for new transaction
2260 : : */
7003 2261 : 428421 : AtStart_GUC();
10651 bruce@momjian.us 2262 : 428421 : AtStart_Cache();
8091 tgl@sss.pgh.pa.us 2263 : 428421 : AfterTriggerBeginXact();
2264 : :
2265 : : /*
2266 : : * done with start processing, set current transaction state to "in
2267 : : * progress"
2268 : : */
10651 bruce@momjian.us 2269 : 428421 : s->state = TRANS_INPROGRESS;
2270 : :
2271 : : /* Schedule transaction timeout */
994 akorotkov@postgresql 2272 [ + + ]: 428421 : if (TransactionTimeout > 0)
2273 : 1 : enable_timeout_after(TRANSACTION_TIMEOUT, TransactionTimeout);
2274 : :
8162 tgl@sss.pgh.pa.us 2275 : 428421 : ShowTransactionState("StartTransaction");
11076 scrappy@hub.org 2276 : 428421 : }
2277 : :
2278 : :
2279 : : /*
2280 : : * CommitTransaction
2281 : : *
2282 : : * NB: if you change this routine, better look at PrepareTransaction too!
2283 : : */
2284 : : static void
9508 tgl@sss.pgh.pa.us 2285 : 392663 : CommitTransaction(void)
2286 : : {
10651 bruce@momjian.us 2287 : 392663 : TransactionState s = CurrentTransactionState;
2288 : : TransactionId latestXid;
2289 : : bool is_parallel_worker;
2290 : :
4207 rhaas@postgresql.org 2291 : 392663 : is_parallel_worker = (s->blockState == TBLOCK_PARALLEL_INPROGRESS);
2292 : :
2293 : : /* Enforce parallel mode restrictions during parallel worker commit. */
4038 2294 [ + + ]: 392663 : if (is_parallel_worker)
2295 : 2034 : EnterParallelMode();
2296 : :
8162 tgl@sss.pgh.pa.us 2297 : 392663 : ShowTransactionState("CommitTransaction");
2298 : :
2299 : : /*
2300 : : * check the current transaction state
2301 : : */
10651 bruce@momjian.us 2302 [ - + ]: 392663 : if (s->state != TRANS_INPROGRESS)
8135 tgl@sss.pgh.pa.us 2303 [ # # ]:UBC 0 : elog(WARNING, "CommitTransaction while in %s state",
2304 : : TransStateAsString(s->state));
8162 tgl@sss.pgh.pa.us 2305 [ + - ]:CBC 392663 : Assert(s->parent == NULL);
2306 : :
2307 : : /*
2308 : : * Do pre-commit processing that involves calling user-defined code, such
2309 : : * as triggers. SECURITY_RESTRICTED_OPERATION contexts must not queue an
2310 : : * action that would run here, because that would bypass the sandbox.
2311 : : * Since closing cursors could queue trigger actions, triggers could open
2312 : : * cursors, etc, we have to keep looping until there's nothing left to do.
2313 : : */
2314 : : for (;;)
2315 : : {
2316 : : /*
2317 : : * Fire all currently pending deferred triggers.
2318 : : */
7878 2319 : 399963 : AfterTriggerFireDeferred();
2320 : :
2321 : : /*
2322 : : * Close open portals (converting holdable ones into static portals).
2323 : : * If there weren't any, we are done ... otherwise loop back to check
2324 : : * if they queued deferred triggers. Lather, rinse, repeat.
2325 : : */
5730 2326 [ + + ]: 399814 : if (!PreCommit_Portals(false))
7878 2327 : 392514 : break;
2328 : : }
2329 : :
2330 : : /*
2331 : : * The remaining actions cannot call any user-defined code, so it's safe
2332 : : * to start shutting down within-transaction services. But note that most
2333 : : * of this stuff could still throw an error, which would switch us into
2334 : : * the transaction-abort path.
2335 : : */
2336 : :
2187 noah@leadboat.com 2337 [ + + ]: 392514 : CallXactCallbacks(is_parallel_worker ? XACT_EVENT_PARALLEL_PRE_COMMIT
2338 : : : XACT_EVENT_PRE_COMMIT);
2339 : :
2340 : : /*
2341 : : * If this xact has started any unfinished parallel operation, clean up
2342 : : * its workers, warning about leaked resources. (But we don't actually
2343 : : * reset parallelModeLevel till entering TRANS_COMMIT, a bit below. This
2344 : : * keeps parallel mode restrictions active as long as possible in a
2345 : : * parallel worker.)
2346 : : */
952 tgl@sss.pgh.pa.us 2347 : 392513 : AtEOXact_Parallel(true);
2348 [ + + ]: 392513 : if (is_parallel_worker)
2349 : : {
2350 [ - + ]: 2034 : if (s->parallelModeLevel != 1)
952 tgl@sss.pgh.pa.us 2351 [ # # ]:UBC 0 : elog(WARNING, "parallelModeLevel is %d not 1 at end of parallel worker transaction",
2352 : : s->parallelModeLevel);
2353 : : }
2354 : : else
2355 : : {
952 tgl@sss.pgh.pa.us 2356 [ - + ]:CBC 390479 : if (s->parallelModeLevel != 0)
952 tgl@sss.pgh.pa.us 2357 [ # # ]:UBC 0 : elog(WARNING, "parallelModeLevel is %d not 0 at end of transaction",
2358 : : s->parallelModeLevel);
2359 : : }
2360 : :
2361 : : /* Shut down the deferred-trigger manager */
5730 tgl@sss.pgh.pa.us 2362 :CBC 392513 : AfterTriggerEndXact(true);
2363 : :
2364 : : /*
2365 : : * Let ON COMMIT management do its thing (must happen after closing
2366 : : * cursors, to avoid dangling-reference problems)
2367 : : */
8042 2368 : 392513 : PreCommit_on_commit_actions();
2369 : :
2370 : : /*
2371 : : * Synchronize files that are created and not WAL-logged during this
2372 : : * transaction. This must happen before AtEOXact_RelationMap(), so that we
2373 : : * don't see committed-but-broken files after a crash.
2374 : : */
2406 noah@leadboat.com 2375 : 392509 : smgrDoPendingSyncs(true, is_parallel_worker);
2376 : :
2377 : : /* close large objects before lower-level cleanup */
8135 tgl@sss.pgh.pa.us 2378 : 392509 : AtEOXact_LargeObject(true);
2379 : :
2380 : : /*
2381 : : * Insert notifications sent by NOTIFY commands into the queue. This
2382 : : * should be late in the pre-commit sequence to minimize time spent
2383 : : * holding the notify-insertion lock. However, this could result in
2384 : : * creating a snapshot, so we must do it before serializable cleanup.
2385 : : */
2538 2386 : 392509 : PreCommit_Notify();
2387 : :
2388 : : /*
2389 : : * Mark serializable transaction as complete for predicate locking
2390 : : * purposes. This should be done as late as we can put it and still allow
2391 : : * errors to be raised for failure patterns found at commit. This is not
2392 : : * appropriate in a parallel worker however, because we aren't committing
2393 : : * the leader's transaction and its serializable state will live on.
2394 : : */
2792 tmunro@postgresql.or 2395 [ + + ]: 392509 : if (!is_parallel_worker)
2396 : 390475 : PreCommit_CheckForSerializationFailure();
2397 : :
2398 : : /* Prevent cancel/die interrupt while cleaning up */
8042 tgl@sss.pgh.pa.us 2399 : 392349 : HOLD_INTERRUPTS();
2400 : :
2401 : : /* Commit updates to the relation map --- do this as late as possible */
3009 pg@bowt.ie 2402 : 392349 : AtEOXact_RelationMap(true, is_parallel_worker);
2403 : :
2404 : : /*
2405 : : * set the current transaction state information appropriately during
2406 : : * commit processing
2407 : : */
8042 tgl@sss.pgh.pa.us 2408 : 392349 : s->state = TRANS_COMMIT;
4038 rhaas@postgresql.org 2409 : 392349 : s->parallelModeLevel = 0;
952 tgl@sss.pgh.pa.us 2410 : 392349 : s->parallelChildXact = false; /* should be false already */
2411 : :
2412 : : /* Disable transaction timeout */
993 akorotkov@postgresql 2413 [ + + ]: 392349 : if (TransactionTimeout > 0)
2414 : 1 : disable_timeout(TRANSACTION_TIMEOUT, false);
2415 : :
4207 rhaas@postgresql.org 2416 [ + + ]: 392349 : if (!is_parallel_worker)
2417 : : {
2418 : : /*
2419 : : * We need to mark our XIDs as committed in pg_xact. This is where we
2420 : : * durably commit.
2421 : : */
2422 : 390315 : latestXid = RecordTransactionCommit();
2423 : : }
2424 : : else
2425 : : {
2426 : : /*
2427 : : * We must not mark our XID committed; the parallel leader is
2428 : : * responsible for that.
2429 : : */
2430 : 2034 : latestXid = InvalidTransactionId;
2431 : :
2432 : : /*
2433 : : * Make sure the leader will know about any WAL we wrote before it
2434 : : * commits.
2435 : : */
2436 : 2034 : ParallelWorkerReportLastRecEnd(XactLastRecEnd);
2437 : : }
2438 : :
2439 : : TRACE_POSTGRESQL_TRANSACTION_COMMIT(MyProc->vxid.lxid);
2440 : :
2441 : : /*
2442 : : * Let others know about no transaction in progress by me. Note that this
2443 : : * must be done _before_ releasing locks we hold and _after_
2444 : : * RecordTransactionCommit.
2445 : : */
6998 tgl@sss.pgh.pa.us 2446 : 392349 : ProcArrayEndTransaction(MyProc, latestXid);
2447 : :
2448 : : /*
2449 : : * This is all post-commit cleanup. Note that if an error is raised here,
2450 : : * it's too late to abort the transaction. This should be just
2451 : : * noncritical resource releasing.
2452 : : *
2453 : : * The ordering of operations is not entirely random. The idea is:
2454 : : * release resources visible to other backends (eg, files, buffer pins);
2455 : : * then release locks; then release backend-local resources. We want to
2456 : : * release locks at the point where any backend waiting for us will see
2457 : : * our transaction as being fully cleaned up.
2458 : : *
2459 : : * Resources that can be associated with individual queries are handled by
2460 : : * the ResourceOwner mechanism. The other calls here are for backend-wide
2461 : : * state.
2462 : : */
2463 : :
4207 rhaas@postgresql.org 2464 : 392349 : CallXactCallbacks(is_parallel_worker ? XACT_EVENT_PARALLEL_COMMIT
2465 : : : XACT_EVENT_COMMIT);
2466 : :
1086 heikki.linnakangas@i 2467 : 392349 : CurrentResourceOwner = NULL;
8146 tgl@sss.pgh.pa.us 2468 : 392349 : ResourceOwnerRelease(TopTransactionResourceOwner,
2469 : : RESOURCE_RELEASE_BEFORE_LOCKS,
2470 : : true, true);
2471 : :
598 andres@anarazel.de 2472 : 392349 : AtEOXact_Aio(true);
2473 : :
2474 : : /* Check we've released all buffer pins */
8055 tgl@sss.pgh.pa.us 2475 : 392349 : AtEOXact_Buffers(true);
2476 : :
2477 : : /* Clean up the relation cache */
7759 2478 : 392349 : AtEOXact_RelationCache(true);
2479 : :
2480 : : /* Clean up the type cache */
742 akorotkov@postgresql 2481 : 392349 : AtEOXact_TypeCache();
2482 : :
2483 : : /*
2484 : : * Make catalog changes visible to all backends. This has to happen after
2485 : : * relcache references are dropped (see comments for
2486 : : * AtEOXact_RelationCache), but before locks are released (if anyone is
2487 : : * waiting for lock on a relation we've modified, we want them to know
2488 : : * about the catalog change before they start using the relation).
2489 : : */
8146 tgl@sss.pgh.pa.us 2490 : 392349 : AtEOXact_Inval(true);
2491 : :
7861 2492 : 392349 : AtEOXact_MultiXact();
2493 : :
8146 2494 : 392349 : ResourceOwnerRelease(TopTransactionResourceOwner,
2495 : : RESOURCE_RELEASE_LOCKS,
2496 : : true, true);
2497 : 392349 : ResourceOwnerRelease(TopTransactionResourceOwner,
2498 : : RESOURCE_RELEASE_AFTER_LOCKS,
2499 : : true, true);
2500 : :
2501 : : /*
2502 : : * Likewise, dropping of files deleted during the transaction is best done
2503 : : * after releasing relcache and buffer pins. (This is not strictly
2504 : : * necessary during commit, since such pins should have been released
2505 : : * already, but this ordering is definitely critical during abort.) Since
2506 : : * this may take many seconds, also delay until after releasing locks.
2507 : : * Other backends will observe the attendant catalog changes and not
2508 : : * attempt to access affected files.
2509 : : */
5257 rhaas@postgresql.org 2510 : 392349 : smgrDoPendingDeletes(true);
2511 : :
2512 : : /*
2513 : : * Send out notification signals to other backends (and do other
2514 : : * post-commit NOTIFY cleanup). This must not happen until after our
2515 : : * transaction is fully done from the viewpoint of other backends.
2516 : : */
6106 tgl@sss.pgh.pa.us 2517 : 392349 : AtCommit_Notify();
2518 : :
2519 : : /*
2520 : : * Everything after this should be purely internal-to-this-backend
2521 : : * cleanup.
2522 : : */
7003 2523 : 392349 : AtEOXact_GUC(true, 1);
8374 mail@joeconway.com 2524 : 392349 : AtEOXact_SPI(true);
2949 tmunro@postgresql.or 2525 : 392349 : AtEOXact_Enum();
8085 tgl@sss.pgh.pa.us 2526 : 392349 : AtEOXact_on_commit_actions(true);
4207 rhaas@postgresql.org 2527 : 392349 : AtEOXact_Namespace(true, is_parallel_worker);
5132 tgl@sss.pgh.pa.us 2528 : 392349 : AtEOXact_SMgr();
3113 2529 : 392349 : AtEOXact_Files(true);
7209 2530 : 392349 : AtEOXact_ComboCid();
7133 2531 : 392349 : AtEOXact_HashTables(true);
129 amitlan@postgresql.o 2532 : 392349 : AtEOXact_RI(true);
2766 akapila@postgresql.o 2533 : 392349 : AtEOXact_PgStat(true, is_parallel_worker);
3500 simon@2ndQuadrant.co 2534 : 392349 : AtEOXact_Snapshot(true, false);
3475 peter_e@gmx.net 2535 : 392349 : AtEOXact_ApplyLauncher(true);
1399 tgl@sss.pgh.pa.us 2536 : 392349 : AtEOXact_LogicalRepWorkers(true);
317 msawada@postgresql.o 2537 : 392349 : AtEOXact_LogicalCtl();
6995 tgl@sss.pgh.pa.us 2538 : 392349 : pgstat_report_xact_timestamp(0);
2539 : :
8146 2540 : 392349 : ResourceOwnerDelete(TopTransactionResourceOwner);
2541 : 392349 : s->curTransactionOwner = NULL;
2542 : 392349 : CurTransactionResourceOwner = NULL;
2543 : 392349 : TopTransactionResourceOwner = NULL;
2544 : :
8780 2545 : 392349 : AtCommit_Memory();
2546 : :
2779 tmunro@postgresql.or 2547 : 392349 : s->fullTransactionId = InvalidFullTransactionId;
8085 tgl@sss.pgh.pa.us 2548 : 392349 : s->subTransactionId = InvalidSubTransactionId;
8162 2549 : 392349 : s->nestingLevel = 0;
7003 2550 : 392349 : s->gucNestLevel = 0;
6807 2551 : 392349 : s->childXids = NULL;
2552 : 392349 : s->nChildXids = 0;
2553 : 392349 : s->maxChildXids = 0;
2554 : :
2779 tmunro@postgresql.or 2555 : 392349 : XactTopFullTransactionId = InvalidFullTransactionId;
4207 rhaas@postgresql.org 2556 : 392349 : nParallelCurrentXids = 0;
2557 : :
2558 : : /*
2559 : : * done with commit processing, set current transaction state back to
2560 : : * default
2561 : : */
10651 bruce@momjian.us 2562 : 392349 : s->state = TRANS_DEFAULT;
2563 : :
9421 tgl@sss.pgh.pa.us 2564 [ - + ]: 392349 : RESUME_INTERRUPTS();
11076 scrappy@hub.org 2565 : 392349 : }
2566 : :
2567 : :
2568 : : /*
2569 : : * PrepareTransaction
2570 : : *
2571 : : * NB: if you change this routine, better look at CommitTransaction too!
2572 : : */
2573 : : static void
7811 tgl@sss.pgh.pa.us 2574 : 371 : PrepareTransaction(void)
2575 : : {
7691 bruce@momjian.us 2576 : 371 : TransactionState s = CurrentTransactionState;
486 michael@paquier.xyz 2577 : 371 : FullTransactionId fxid = GetCurrentFullTransactionId();
2578 : : GlobalTransaction gxact;
2579 : : TimestampTz prepared_at;
2580 : :
4207 rhaas@postgresql.org 2581 [ - + ]: 371 : Assert(!IsInParallelMode());
2582 : :
7811 tgl@sss.pgh.pa.us 2583 : 371 : ShowTransactionState("PrepareTransaction");
2584 : :
2585 : : /*
2586 : : * check the current transaction state
2587 : : */
2588 [ - + ]: 371 : if (s->state != TRANS_INPROGRESS)
7811 tgl@sss.pgh.pa.us 2589 [ # # ]:UBC 0 : elog(WARNING, "PrepareTransaction while in %s state",
2590 : : TransStateAsString(s->state));
7811 tgl@sss.pgh.pa.us 2591 [ + - ]:CBC 371 : Assert(s->parent == NULL);
2592 : :
2593 : : /*
2594 : : * Do pre-commit processing that involves calling user-defined code, such
2595 : : * as triggers. Since closing cursors could queue trigger actions,
2596 : : * triggers could open cursors, etc, we have to keep looping until there's
2597 : : * nothing left to do.
2598 : : */
2599 : : for (;;)
2600 : : {
2601 : : /*
2602 : : * Fire all currently pending deferred triggers.
2603 : : */
2604 : 373 : AfterTriggerFireDeferred();
2605 : :
2606 : : /*
2607 : : * Close open portals (converting holdable ones into static portals).
2608 : : * If there weren't any, we are done ... otherwise loop back to check
2609 : : * if they queued deferred triggers. Lather, rinse, repeat.
2610 : : */
5730 2611 [ + + ]: 373 : if (!PreCommit_Portals(true))
7811 2612 : 371 : break;
2613 : : }
2614 : :
5012 2615 : 371 : CallXactCallbacks(XACT_EVENT_PRE_PREPARE);
2616 : :
2617 : : /*
2618 : : * The remaining actions cannot call any user-defined code, so it's safe
2619 : : * to start shutting down within-transaction services. But note that most
2620 : : * of this stuff could still throw an error, which would switch us into
2621 : : * the transaction-abort path.
2622 : : */
2623 : :
2624 : : /* Shut down the deferred-trigger manager */
5730 2625 : 370 : AfterTriggerEndXact(true);
2626 : :
2627 : : /*
2628 : : * Let ON COMMIT management do its thing (must happen after closing
2629 : : * cursors, to avoid dangling-reference problems)
2630 : : */
7811 2631 : 370 : PreCommit_on_commit_actions();
2632 : :
2633 : : /*
2634 : : * Synchronize files that are created and not WAL-logged during this
2635 : : * transaction. This must happen before EndPrepare(), so that we don't see
2636 : : * committed-but-broken files after a crash and COMMIT PREPARED.
2637 : : */
2406 noah@leadboat.com 2638 : 370 : smgrDoPendingSyncs(true, false);
2639 : :
2640 : : /* close large objects before lower-level cleanup */
7811 tgl@sss.pgh.pa.us 2641 : 370 : AtEOXact_LargeObject(true);
2642 : :
2643 : : /* NOTIFY requires no work at this point */
2644 : :
2645 : : /*
2646 : : * Mark serializable transaction as complete for predicate locking
2647 : : * purposes. This should be done as late as we can put it and still allow
2648 : : * errors to be raised for failure patterns found at commit.
2649 : : */
5750 heikki.linnakangas@i 2650 : 370 : PreCommit_CheckForSerializationFailure();
2651 : :
2652 : : /*
2653 : : * Don't allow PREPARE TRANSACTION if we've accessed a temporary table in
2654 : : * this transaction. Having the prepared xact hold locks on another
2655 : : * backend's temp table seems a bad idea --- for instance it would prevent
2656 : : * the backend from exiting. There are other problems too, such as how to
2657 : : * clean up the source backend's local buffers and ON COMMIT state if the
2658 : : * prepared xact includes a DROP of a temp table.
2659 : : *
2660 : : * Other objects types, like functions, operators or extensions, share the
2661 : : * same restriction as they should not be created, locked or dropped as
2662 : : * this can mess up with this session or even a follow-up session trying
2663 : : * to use the same temporary namespace.
2664 : : *
2665 : : * We must check this after executing any ON COMMIT actions, because they
2666 : : * might still access a temp relation.
2667 : : *
2668 : : * XXX In principle this could be relaxed to allow some useful special
2669 : : * cases, such as a temp table created and dropped all within the
2670 : : * transaction. That seems to require much more bookkeeping though.
2671 : : */
2848 michael@paquier.xyz 2672 [ + + ]: 370 : if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPNAMESPACE))
2673 [ + - ]: 45 : ereport(ERROR,
2674 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2675 : : errmsg("cannot PREPARE a transaction that has operated on temporary objects")));
2676 : :
2677 : : /*
2678 : : * Likewise, don't allow PREPARE after pg_export_snapshot. This could be
2679 : : * supported if we added cleanup logic to twophase.c, but for now it
2680 : : * doesn't seem worth the trouble.
2681 : : */
5493 tgl@sss.pgh.pa.us 2682 [ - + ]: 325 : if (XactHasExportedSnapshots())
5493 tgl@sss.pgh.pa.us 2683 [ # # ]:UBC 0 : ereport(ERROR,
2684 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2685 : : errmsg("cannot PREPARE a transaction that has exported snapshots")));
2686 : :
2687 : : /* Prevent cancel/die interrupt while cleaning up */
7811 tgl@sss.pgh.pa.us 2688 :CBC 325 : HOLD_INTERRUPTS();
2689 : :
2690 : : /*
2691 : : * set the current transaction state information appropriately during
2692 : : * prepare processing
2693 : : */
2694 : 325 : s->state = TRANS_PREPARE;
2695 : :
2696 : : /* Disable transaction timeout */
993 akorotkov@postgresql 2697 [ - + ]: 325 : if (TransactionTimeout > 0)
993 akorotkov@postgresql 2698 :UBC 0 : disable_timeout(TRANSACTION_TIMEOUT, false);
2699 : :
7799 tgl@sss.pgh.pa.us 2700 :CBC 325 : prepared_at = GetCurrentTimestamp();
2701 : :
2702 : : /*
2703 : : * Reserve the GID for this transaction. This could fail if the requested
2704 : : * GID is invalid or already in use.
2705 : : */
486 michael@paquier.xyz 2706 : 325 : gxact = MarkAsPreparing(fxid, prepareGID, prepared_at,
2707 : : GetUserId(), MyDatabaseId);
7811 tgl@sss.pgh.pa.us 2708 : 307 : prepareGID = NULL;
2709 : :
2710 : : /*
2711 : : * Collect data for the 2PC state file. Note that in general, no actual
2712 : : * state change should happen in the called modules during this step,
2713 : : * since it's still possible to fail before commit, and in that case we
2714 : : * want transaction abort to be able to clean up. (In particular, the
2715 : : * AtPrepare routines may error out if they find cases they cannot
2716 : : * handle.) State cleanup should happen in the PostPrepare routines
2717 : : * below. However, some modules can go ahead and clear state here because
2718 : : * they wouldn't do anything with it during abort anyway.
2719 : : *
2720 : : * Note: because the 2PC state file records will be replayed in the same
2721 : : * order they are made, the order of these calls has to match the order in
2722 : : * which we want things to happen during COMMIT PREPARED or ROLLBACK
2723 : : * PREPARED; in particular, pay attention to whether things should happen
2724 : : * before or after releasing the transaction's locks.
2725 : : */
2726 : 307 : StartPrepare(gxact);
2727 : :
2728 : 307 : AtPrepare_Notify();
2729 : 307 : AtPrepare_Locks();
5750 heikki.linnakangas@i 2730 : 305 : AtPrepare_PredicateLocks();
7102 tgl@sss.pgh.pa.us 2731 : 305 : AtPrepare_PgStat();
6191 heikki.linnakangas@i 2732 : 305 : AtPrepare_MultiXact();
6115 tgl@sss.pgh.pa.us 2733 : 305 : AtPrepare_RelationMap();
2734 : :
2735 : : /*
2736 : : * Here is where we really truly prepare.
2737 : : *
2738 : : * We have to record transaction prepares even if we didn't make any
2739 : : * updates, because the transaction manager might get confused if we lose
2740 : : * a global transaction.
2741 : : */
7811 2742 : 305 : EndPrepare(gxact);
2743 : :
2744 : : /*
2745 : : * Now we clean up backend-internal state and release internal resources.
2746 : : */
2747 : :
2748 : : /* Reset XactLastRecEnd until the next transaction writes something */
5247 heikki.linnakangas@i 2749 : 305 : XactLastRecEnd = 0;
2750 : :
2751 : : /*
2752 : : * Transfer our locks to a dummy PGPROC. This has to be done before
2753 : : * ProcArrayClearTransaction(). Otherwise, a GetLockConflicts() would
2754 : : * conclude "xact already committed or aborted" for our locks.
2755 : : */
486 michael@paquier.xyz 2756 : 305 : PostPrepare_Locks(fxid);
2757 : :
2758 : : /*
2759 : : * Let others know about no transaction in progress by me. This has to be
2760 : : * done *after* the prepared transaction has been marked valid, else
2761 : : * someone may think it is unlocked and recyclable.
2762 : : */
6998 tgl@sss.pgh.pa.us 2763 : 305 : ProcArrayClearTransaction(MyProc);
2764 : :
2765 : : /*
2766 : : * In normal commit-processing, this is all non-critical post-transaction
2767 : : * cleanup. When the transaction is prepared, however, it's important
2768 : : * that the locks and other per-backend resources are transferred to the
2769 : : * prepared transaction's PGPROC entry. Note that if an error is raised
2770 : : * here, it's too late to abort the transaction. XXX: This probably should
2771 : : * be in a critical section, to force a PANIC if any of this fails, but
2772 : : * that cure could be worse than the disease.
2773 : : */
2774 : :
7811 2775 : 305 : CallXactCallbacks(XACT_EVENT_PREPARE);
2776 : :
2777 : 305 : ResourceOwnerRelease(TopTransactionResourceOwner,
2778 : : RESOURCE_RELEASE_BEFORE_LOCKS,
2779 : : true, true);
2780 : :
598 andres@anarazel.de 2781 : 305 : AtEOXact_Aio(true);
2782 : :
2783 : : /* Check we've released all buffer pins */
7811 tgl@sss.pgh.pa.us 2784 : 305 : AtEOXact_Buffers(true);
2785 : :
2786 : : /* Clean up the relation cache */
7759 2787 : 305 : AtEOXact_RelationCache(true);
2788 : :
2789 : : /* Clean up the type cache */
742 akorotkov@postgresql 2790 : 305 : AtEOXact_TypeCache();
2791 : :
2792 : : /* notify doesn't need a postprepare call */
2793 : :
7102 tgl@sss.pgh.pa.us 2794 : 305 : PostPrepare_PgStat();
2795 : :
7811 2796 : 305 : PostPrepare_Inval();
2797 : :
2798 : 305 : PostPrepare_smgr();
2799 : :
486 michael@paquier.xyz 2800 : 305 : PostPrepare_MultiXact(fxid);
2801 : :
2802 : 305 : PostPrepare_PredicateLocks(fxid);
2803 : :
7811 tgl@sss.pgh.pa.us 2804 : 305 : ResourceOwnerRelease(TopTransactionResourceOwner,
2805 : : RESOURCE_RELEASE_LOCKS,
2806 : : true, true);
2807 : 305 : ResourceOwnerRelease(TopTransactionResourceOwner,
2808 : : RESOURCE_RELEASE_AFTER_LOCKS,
2809 : : true, true);
2810 : :
2811 : : /*
2812 : : * Allow another backend to finish the transaction. After
2813 : : * PostPrepare_Twophase(), the transaction is completely detached from our
2814 : : * backend. The rest is just non-critical cleanup of backend-local state.
2815 : : */
4557 heikki.linnakangas@i 2816 : 305 : PostPrepare_Twophase();
2817 : :
2818 : : /* PREPARE acts the same as COMMIT as far as GUC is concerned */
7003 tgl@sss.pgh.pa.us 2819 : 305 : AtEOXact_GUC(true, 1);
7811 2820 : 305 : AtEOXact_SPI(true);
2949 tmunro@postgresql.or 2821 : 305 : AtEOXact_Enum();
7811 tgl@sss.pgh.pa.us 2822 : 305 : AtEOXact_on_commit_actions(true);
4207 rhaas@postgresql.org 2823 : 305 : AtEOXact_Namespace(true, false);
5132 tgl@sss.pgh.pa.us 2824 : 305 : AtEOXact_SMgr();
3113 2825 : 305 : AtEOXact_Files(true);
7209 2826 : 305 : AtEOXact_ComboCid();
7133 2827 : 305 : AtEOXact_HashTables(true);
129 amitlan@postgresql.o 2828 : 305 : AtEOXact_RI(true);
2829 : : /* don't call AtEOXact_PgStat here; we fixed pgstat state above */
3500 simon@2ndQuadrant.co 2830 : 305 : AtEOXact_Snapshot(true, true);
2831 : : /* we treat PREPARE as ROLLBACK so far as waking workers goes */
1399 tgl@sss.pgh.pa.us 2832 : 305 : AtEOXact_ApplyLauncher(false);
2833 : 305 : AtEOXact_LogicalRepWorkers(false);
317 msawada@postgresql.o 2834 : 305 : AtEOXact_LogicalCtl();
4578 tgl@sss.pgh.pa.us 2835 : 305 : pgstat_report_xact_timestamp(0);
2836 : :
7811 2837 : 305 : CurrentResourceOwner = NULL;
2838 : 305 : ResourceOwnerDelete(TopTransactionResourceOwner);
2839 : 305 : s->curTransactionOwner = NULL;
2840 : 305 : CurTransactionResourceOwner = NULL;
2841 : 305 : TopTransactionResourceOwner = NULL;
2842 : :
2843 : 305 : AtCommit_Memory();
2844 : :
2779 tmunro@postgresql.or 2845 : 305 : s->fullTransactionId = InvalidFullTransactionId;
7811 tgl@sss.pgh.pa.us 2846 : 305 : s->subTransactionId = InvalidSubTransactionId;
2847 : 305 : s->nestingLevel = 0;
7003 2848 : 305 : s->gucNestLevel = 0;
6807 2849 : 305 : s->childXids = NULL;
2850 : 305 : s->nChildXids = 0;
2851 : 305 : s->maxChildXids = 0;
2852 : :
2779 tmunro@postgresql.or 2853 : 305 : XactTopFullTransactionId = InvalidFullTransactionId;
4207 rhaas@postgresql.org 2854 : 305 : nParallelCurrentXids = 0;
2855 : :
2856 : : /*
2857 : : * done with 1st phase commit processing, set current transaction state
2858 : : * back to default
2859 : : */
7811 tgl@sss.pgh.pa.us 2860 : 305 : s->state = TRANS_DEFAULT;
2861 : :
2862 [ - + ]: 305 : RESUME_INTERRUPTS();
2863 : 305 : }
2864 : :
2865 : :
2866 : : /*
2867 : : * AbortTransaction
2868 : : */
2869 : : static void
9508 2870 : 35767 : AbortTransaction(void)
2871 : : {
10651 bruce@momjian.us 2872 : 35767 : TransactionState s = CurrentTransactionState;
2873 : : TransactionId latestXid;
2874 : : bool is_parallel_worker;
2875 : :
2876 : : /* Prevent cancel/die interrupt while cleaning up */
9421 tgl@sss.pgh.pa.us 2877 : 35767 : HOLD_INTERRUPTS();
2878 : :
2879 : : /* Disable transaction timeout */
993 akorotkov@postgresql 2880 [ + + ]: 35767 : if (TransactionTimeout > 0)
2881 : 1 : disable_timeout(TRANSACTION_TIMEOUT, false);
2882 : :
2883 : : /* Make sure we have a valid memory context and resource owner */
7287 tgl@sss.pgh.pa.us 2884 : 35767 : AtAbort_Memory();
2885 : 35767 : AtAbort_ResourceOwner();
2886 : :
2887 : : /*
2888 : : * Release any LW locks we might be holding as quickly as possible.
2889 : : * (Regular locks, however, must be held till we finish aborting.)
2890 : : * Releasing LW locks is critical since we might try to grab them again
2891 : : * while cleaning up!
2892 : : */
9168 2893 : 35767 : LWLockReleaseAll();
2894 : :
2895 : : /*
2896 : : * Cleanup waiting for LSN if any.
2897 : : */
365 akorotkov@postgresql 2898 : 35767 : WaitLSNCleanup();
2899 : :
2900 : : /* Clear wait information and command progress indicator */
3892 rhaas@postgresql.org 2901 : 35767 : pgstat_report_wait_end();
2902 : 35767 : pgstat_progress_end_command();
2903 : :
598 andres@anarazel.de 2904 : 35767 : pgaio_error_cleanup();
2905 : :
2906 : : /* Clean up buffer content locks, too */
9453 tgl@sss.pgh.pa.us 2907 : 35767 : UnlockBuffers();
2908 : :
2909 : : /* Reset WAL record construction state */
4368 heikki.linnakangas@i 2910 : 35767 : XLogResetInsertion();
2911 : :
2912 : : /* Cancel condition variable sleep */
3635 rhaas@postgresql.org 2913 : 35767 : ConditionVariableCancelSleep();
2914 : :
2915 : : /*
2916 : : * Also clean up any open wait for lock, since the lock manager will choke
2917 : : * if we try to wait for another lock before doing this.
2918 : : */
5314 2919 : 35767 : LockErrorCleanup();
2920 : :
2921 : : /*
2922 : : * If any timeout events are still active, make sure the timeout interrupt
2923 : : * is scheduled. This covers possible loss of a timeout interrupt due to
2924 : : * longjmp'ing out of the SIGINT handler (see notes in handle_sig_alarm).
2925 : : * We delay this till after LockErrorCleanup so that we don't uselessly
2926 : : * reschedule lock or deadlock check timeouts.
2927 : : */
4724 tgl@sss.pgh.pa.us 2928 : 35767 : reschedule_timeouts();
2929 : :
2930 : : /*
2931 : : * Re-enable signals, in case we got here by longjmp'ing out of a signal
2932 : : * handler. We do this fairly early in the sequence so that the timeout
2933 : : * infrastructure will be functional if needed while aborting.
2934 : : */
1371 tmunro@postgresql.or 2935 : 35767 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
2936 : :
2937 : : /*
2938 : : * check the current transaction state
2939 : : */
4207 rhaas@postgresql.org 2940 : 35767 : is_parallel_worker = (s->blockState == TBLOCK_PARALLEL_INPROGRESS);
7811 tgl@sss.pgh.pa.us 2941 [ + + - + ]: 35767 : if (s->state != TRANS_INPROGRESS && s->state != TRANS_PREPARE)
8135 tgl@sss.pgh.pa.us 2942 [ # # ]:UBC 0 : elog(WARNING, "AbortTransaction while in %s state",
2943 : : TransStateAsString(s->state));
8162 tgl@sss.pgh.pa.us 2944 [ - + ]:CBC 35767 : Assert(s->parent == NULL);
2945 : :
2946 : : /*
2947 : : * set the current transaction state information appropriately during the
2948 : : * abort processing
2949 : : */
10651 bruce@momjian.us 2950 : 35767 : s->state = TRANS_ABORT;
2951 : :
2952 : : /*
2953 : : * Reset user ID which might have been changed transiently. We need this
2954 : : * to clean up in case control escaped out of a SECURITY DEFINER function
2955 : : * or other local change of CurrentUserId; therefore, the prior value of
2956 : : * SecurityRestrictionContext also needs to be restored.
2957 : : *
2958 : : * (Note: it is not necessary to restore session authorization or role
2959 : : * settings here because those can only be changed via GUC, and GUC will
2960 : : * take care of rolling them back if need be.)
2961 : : */
6175 tgl@sss.pgh.pa.us 2962 : 35767 : SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
2963 : :
2964 : : /* Forget about any active REINDEX. */
2389 2965 : 35767 : ResetReindexState(s->nestingLevel);
2966 : :
2967 : : /* Reset logical streaming state. */
2280 akapila@postgresql.o 2968 : 35767 : ResetLogicalStreamingState();
2969 : :
2970 : : /* Reset snapshot export state. */
1844 michael@paquier.xyz 2971 : 35767 : SnapBuildResetExportedSnapshotState();
2972 : :
2973 : : /*
2974 : : * If this xact has started any unfinished parallel operation, clean up
2975 : : * its workers and exit parallel mode. Don't warn about leaked resources.
2976 : : */
952 tgl@sss.pgh.pa.us 2977 : 35767 : AtEOXact_Parallel(false);
2978 : 35767 : s->parallelModeLevel = 0;
2979 : 35767 : s->parallelChildXact = false; /* should be false already */
2980 : :
2981 : : /*
2982 : : * do abort processing
2983 : : */
6096 bruce@momjian.us 2984 : 35767 : AfterTriggerEndXact(false); /* 'false' means it's abort */
8588 tgl@sss.pgh.pa.us 2985 : 35767 : AtAbort_Portals();
2406 noah@leadboat.com 2986 : 35767 : smgrDoPendingSyncs(false, is_parallel_worker);
6115 tgl@sss.pgh.pa.us 2987 : 35767 : AtEOXact_LargeObject(false);
10257 2988 : 35767 : AtAbort_Notify();
3009 pg@bowt.ie 2989 : 35767 : AtEOXact_RelationMap(false, is_parallel_worker);
4557 heikki.linnakangas@i 2990 : 35767 : AtAbort_Twophase();
2991 : :
2992 : : /*
2993 : : * Advertise the fact that we aborted in pg_xact (assuming that we got as
2994 : : * far as assigning an XID to advertise). But if we're inside a parallel
2995 : : * worker, skip this; the user backend must be the one to write the abort
2996 : : * record.
2997 : : */
4207 rhaas@postgresql.org 2998 [ + + ]: 35767 : if (!is_parallel_worker)
2999 : 35758 : latestXid = RecordTransactionAbort(false);
3000 : : else
3001 : : {
3002 : 9 : latestXid = InvalidTransactionId;
3003 : :
3004 : : /*
3005 : : * Since the parallel leader won't get our value of XactLastRecEnd in
3006 : : * this case, we nudge WAL-writer ourselves in this case. See related
3007 : : * comments in RecordTransactionAbort for why this matters.
3008 : : */
3009 : 9 : XLogSetAsyncXactLSN(XactLastRecEnd);
3010 : : }
3011 : :
3012 : : TRACE_POSTGRESQL_TRANSACTION_ABORT(MyProc->vxid.lxid);
3013 : :
3014 : : /*
3015 : : * Let others know about no transaction in progress by me. Note that this
3016 : : * must be done _before_ releasing locks we hold and _after_
3017 : : * RecordTransactionAbort.
3018 : : */
6998 tgl@sss.pgh.pa.us 3019 : 35767 : ProcArrayEndTransaction(MyProc, latestXid);
3020 : :
3021 : : /*
3022 : : * Post-abort cleanup. See notes in CommitTransaction() concerning
3023 : : * ordering. We can skip all of it if the transaction failed before
3024 : : * creating a resource owner.
3025 : : */
6129 3026 [ + - ]: 35767 : if (TopTransactionResourceOwner != NULL)
3027 : : {
4207 rhaas@postgresql.org 3028 [ + + ]: 35767 : if (is_parallel_worker)
3029 : 9 : CallXactCallbacks(XACT_EVENT_PARALLEL_ABORT);
3030 : : else
3031 : 35758 : CallXactCallbacks(XACT_EVENT_ABORT);
3032 : :
6129 tgl@sss.pgh.pa.us 3033 : 35767 : ResourceOwnerRelease(TopTransactionResourceOwner,
3034 : : RESOURCE_RELEASE_BEFORE_LOCKS,
3035 : : false, true);
598 andres@anarazel.de 3036 : 35767 : AtEOXact_Aio(false);
6129 tgl@sss.pgh.pa.us 3037 : 35767 : AtEOXact_Buffers(false);
3038 : 35767 : AtEOXact_RelationCache(false);
742 akorotkov@postgresql 3039 : 35767 : AtEOXact_TypeCache();
6129 tgl@sss.pgh.pa.us 3040 : 35767 : AtEOXact_Inval(false);
3041 : 35767 : AtEOXact_MultiXact();
3042 : 35767 : ResourceOwnerRelease(TopTransactionResourceOwner,
3043 : : RESOURCE_RELEASE_LOCKS,
3044 : : false, true);
3045 : 35767 : ResourceOwnerRelease(TopTransactionResourceOwner,
3046 : : RESOURCE_RELEASE_AFTER_LOCKS,
3047 : : false, true);
5257 rhaas@postgresql.org 3048 : 35767 : smgrDoPendingDeletes(false);
3049 : :
6129 tgl@sss.pgh.pa.us 3050 : 35767 : AtEOXact_GUC(false, 1);
3051 : 35767 : AtEOXact_SPI(false);
2949 tmunro@postgresql.or 3052 : 35767 : AtEOXact_Enum();
6129 tgl@sss.pgh.pa.us 3053 : 35767 : AtEOXact_on_commit_actions(false);
4207 rhaas@postgresql.org 3054 : 35767 : AtEOXact_Namespace(false, is_parallel_worker);
5132 tgl@sss.pgh.pa.us 3055 : 35767 : AtEOXact_SMgr();
3113 3056 : 35767 : AtEOXact_Files(false);
6129 3057 : 35767 : AtEOXact_ComboCid();
3058 : 35767 : AtEOXact_HashTables(false);
129 amitlan@postgresql.o 3059 : 35767 : AtEOXact_RI(false);
2766 akapila@postgresql.o 3060 : 35767 : AtEOXact_PgStat(false, is_parallel_worker);
3475 peter_e@gmx.net 3061 : 35767 : AtEOXact_ApplyLauncher(false);
1399 tgl@sss.pgh.pa.us 3062 : 35767 : AtEOXact_LogicalRepWorkers(false);
6129 3063 : 35767 : pgstat_report_xact_timestamp(0);
3064 : : }
3065 : :
3066 : : /*
3067 : : * State remains TRANS_ABORT until CleanupTransaction().
3068 : : */
9421 3069 [ - + ]: 35767 : RESUME_INTERRUPTS();
9626 3070 : 35767 : }
3071 : :
3072 : : /*
3073 : : * CleanupTransaction
3074 : : */
3075 : : static void
9508 3076 : 35767 : CleanupTransaction(void)
3077 : : {
9626 3078 : 35767 : TransactionState s = CurrentTransactionState;
3079 : :
3080 : : /*
3081 : : * State should still be TRANS_ABORT from AbortTransaction().
3082 : : */
3083 [ - + ]: 35767 : if (s->state != TRANS_ABORT)
8132 tgl@sss.pgh.pa.us 3084 [ # # ]:UBC 0 : elog(FATAL, "CleanupTransaction: unexpected state %s",
3085 : : TransStateAsString(s->state));
3086 : :
3087 : : /*
3088 : : * do abort cleanup processing
3089 : : */
8588 tgl@sss.pgh.pa.us 3090 :CBC 35767 : AtCleanup_Portals(); /* now safe to release portal memory */
3424 3091 : 35767 : AtEOXact_Snapshot(false, true); /* and release the transaction's snapshots */
3092 : :
8103 bruce@momjian.us 3093 : 35767 : CurrentResourceOwner = NULL; /* and resource owner */
8085 tgl@sss.pgh.pa.us 3094 [ + - ]: 35767 : if (TopTransactionResourceOwner)
3095 : 35767 : ResourceOwnerDelete(TopTransactionResourceOwner);
8146 3096 : 35767 : s->curTransactionOwner = NULL;
3097 : 35767 : CurTransactionResourceOwner = NULL;
3098 : 35767 : TopTransactionResourceOwner = NULL;
3099 : :
8588 3100 : 35767 : AtCleanup_Memory(); /* and transaction memory */
3101 : :
2779 tmunro@postgresql.or 3102 : 35767 : s->fullTransactionId = InvalidFullTransactionId;
8085 tgl@sss.pgh.pa.us 3103 : 35767 : s->subTransactionId = InvalidSubTransactionId;
8162 3104 : 35767 : s->nestingLevel = 0;
7003 3105 : 35767 : s->gucNestLevel = 0;
6807 3106 : 35767 : s->childXids = NULL;
3107 : 35767 : s->nChildXids = 0;
3108 : 35767 : s->maxChildXids = 0;
4207 rhaas@postgresql.org 3109 : 35767 : s->parallelModeLevel = 0;
952 tgl@sss.pgh.pa.us 3110 : 35767 : s->parallelChildXact = false;
3111 : :
2779 tmunro@postgresql.or 3112 : 35767 : XactTopFullTransactionId = InvalidFullTransactionId;
4207 rhaas@postgresql.org 3113 : 35767 : nParallelCurrentXids = 0;
3114 : :
3115 : : /*
3116 : : * Apply any pending XLogLogicalInfo update. This must be done here
3117 : : * rather than in AbortTransaction(), because a failed transaction block
3118 : : * keeps its XID until ROLLBACK, so a barrier absorbed meanwhile is
3119 : : * deferred. Unlike CommitTransaction() and PrepareTransaction(), we are
3120 : : * not necessarily holding interrupts here, so do this after resetting the
3121 : : * top-level XID; otherwise a barrier absorbed in between would be left
3122 : : * pending into the next transaction.
3123 : : */
30 msawada@postgresql.o 3124 : 35767 : AtEOXact_LogicalCtl();
3125 : :
3126 : : /*
3127 : : * done with abort processing, set current transaction state back to
3128 : : * default
3129 : : */
10651 bruce@momjian.us 3130 : 35767 : s->state = TRANS_DEFAULT;
3131 : 35767 : }
3132 : :
3133 : : /*
3134 : : * StartTransactionCommand
3135 : : */
3136 : : void
8576 tgl@sss.pgh.pa.us 3137 : 538746 : StartTransactionCommand(void)
3138 : : {
10651 bruce@momjian.us 3139 : 538746 : TransactionState s = CurrentTransactionState;
3140 : :
3141 [ + + + - : 538746 : switch (s->blockState)
- ]
3142 : : {
3143 : : /*
3144 : : * if we aren't in a transaction block, we just do our usual start
3145 : : * transaction.
3146 : : */
10650 3147 : 426338 : case TBLOCK_DEFAULT:
3148 : 426338 : StartTransaction();
8249 3149 : 426338 : s->blockState = TBLOCK_STARTED;
3150 : 426338 : break;
3151 : :
3152 : : /*
3153 : : * We are somewhere in a transaction block or subtransaction and
3154 : : * about to start a new command. For now we do nothing, but
3155 : : * someday we may do command-local resource initialization. (Note
3156 : : * that any needed CommandCounterIncrement was done by the
3157 : : * previous CommitTransactionCommand.)
3158 : : */
10650 3159 : 111214 : case TBLOCK_INPROGRESS:
3160 : : case TBLOCK_IMPLICIT_INPROGRESS:
3161 : : case TBLOCK_SUBINPROGRESS:
3162 : 111214 : break;
3163 : :
3164 : : /*
3165 : : * Here we are in a failed transaction block (one of the commands
3166 : : * caused an abort) so we do nothing but remain in the abort
3167 : : * state. Eventually we will get a ROLLBACK command which will
3168 : : * get us out of this state. (It is up to other code to ensure
3169 : : * that no commands other than ROLLBACK will be processed in these
3170 : : * states.)
3171 : : */
3172 : 1194 : case TBLOCK_ABORT:
3173 : : case TBLOCK_SUBABORT:
3174 : 1194 : break;
3175 : :
3176 : : /* These cases are invalid. */
8162 tgl@sss.pgh.pa.us 3177 :UBC 0 : case TBLOCK_STARTED:
3178 : : case TBLOCK_BEGIN:
3179 : : case TBLOCK_PARALLEL_INPROGRESS:
3180 : : case TBLOCK_SUBBEGIN:
3181 : : case TBLOCK_END:
3182 : : case TBLOCK_SUBRELEASE:
3183 : : case TBLOCK_SUBCOMMIT:
3184 : : case TBLOCK_ABORT_END:
3185 : : case TBLOCK_SUBABORT_END:
3186 : : case TBLOCK_ABORT_PENDING:
3187 : : case TBLOCK_SUBABORT_PENDING:
3188 : : case TBLOCK_SUBRESTART:
3189 : : case TBLOCK_SUBABORT_RESTART:
3190 : : case TBLOCK_PREPARE:
8085 3191 [ # # ]: 0 : elog(ERROR, "StartTransactionCommand: unexpected state %s",
3192 : : BlockStateAsString(s->blockState));
3193 : : break;
3194 : : }
3195 : :
3196 : : /*
3197 : : * We must switch to CurTransactionContext before returning. This is
3198 : : * already done if we called StartTransaction, otherwise not.
3199 : : */
8162 tgl@sss.pgh.pa.us 3200 [ - + ]:CBC 538746 : Assert(CurTransactionContext != NULL);
3201 : 538746 : MemoryContextSwitchTo(CurTransactionContext);
10651 bruce@momjian.us 3202 : 538746 : }
3203 : :
3204 : :
3205 : : /*
3206 : : * Simple system for saving and restoring transaction characteristics
3207 : : * (isolation level, read only, deferrable). We need this for transaction
3208 : : * chaining, so that we can set the characteristics of the new transaction to
3209 : : * be the same as the previous one. (We need something like this because the
3210 : : * GUC system resets the characteristics at transaction end, so for example
3211 : : * just skipping the reset in StartTransaction() won't work.)
3212 : : */
3213 : : void
1711 tgl@sss.pgh.pa.us 3214 : 505626 : SaveTransactionCharacteristics(SavedTransactionCharacteristics *s)
3215 : : {
3216 : 505626 : s->save_XactIsoLevel = XactIsoLevel;
3217 : 505626 : s->save_XactReadOnly = XactReadOnly;
3218 : 505626 : s->save_XactDeferrable = XactDeferrable;
2783 peter@eisentraut.org 3219 : 505626 : }
3220 : :
3221 : : void
1711 tgl@sss.pgh.pa.us 3222 : 44 : RestoreTransactionCharacteristics(const SavedTransactionCharacteristics *s)
3223 : : {
3224 : 44 : XactIsoLevel = s->save_XactIsoLevel;
3225 : 44 : XactReadOnly = s->save_XactReadOnly;
3226 : 44 : XactDeferrable = s->save_XactDeferrable;
2783 peter@eisentraut.org 3227 : 44 : }
3228 : :
3229 : : /*
3230 : : * CommitTransactionCommand -- a wrapper function handling the
3231 : : * loop over subtransactions to avoid a potentially dangerous recursion
3232 : : * in CommitTransactionCommandInternal().
3233 : : */
3234 : : void
8576 tgl@sss.pgh.pa.us 3235 : 505295 : CommitTransactionCommand(void)
3236 : : {
3237 : : /*
3238 : : * Repeatedly call CommitTransactionCommandInternal() until all the work
3239 : : * is done.
3240 : : */
931 akorotkov@postgresql 3241 [ + + ]: 505622 : while (!CommitTransactionCommandInternal())
3242 : : {
3243 : : }
972 3244 : 504915 : }
3245 : :
3246 : : /*
3247 : : * CommitTransactionCommandInternal - a function doing an iteration of work
3248 : : * regarding handling the commit transaction command. In the case of
3249 : : * subtransactions more than one iterations could be required. Returns
3250 : : * true when no more iterations required, false otherwise.
3251 : : */
3252 : : static bool
3253 : 505622 : CommitTransactionCommandInternal(void)
3254 : : {
10651 bruce@momjian.us 3255 : 505622 : TransactionState s = CurrentTransactionState;
3256 : : SavedTransactionCharacteristics savetc;
3257 : :
3258 : : /* Must save in case we need to restore below */
1711 tgl@sss.pgh.pa.us 3259 : 505622 : SaveTransactionCharacteristics(&savetc);
3260 : :
10651 bruce@momjian.us 3261 [ - + + + : 505622 : switch (s->blockState)
+ + + + +
+ + + + +
+ + - ]
3262 : : {
3263 : : /*
3264 : : * These shouldn't happen. TBLOCK_DEFAULT means the previous
3265 : : * StartTransactionCommand didn't set the STARTED state
3266 : : * appropriately, while TBLOCK_PARALLEL_INPROGRESS should be ended
3267 : : * by EndParallelWorkerTransaction(), not this function.
3268 : : */
8249 bruce@momjian.us 3269 :UBC 0 : case TBLOCK_DEFAULT:
3270 : : case TBLOCK_PARALLEL_INPROGRESS:
8136 tgl@sss.pgh.pa.us 3271 [ # # ]: 0 : elog(FATAL, "CommitTransactionCommand: unexpected state %s",
3272 : : BlockStateAsString(s->blockState));
3273 : : break;
3274 : :
3275 : : /*
3276 : : * If we aren't in a transaction block, just do our usual
3277 : : * transaction commit, and return to the idle state.
3278 : : */
8249 bruce@momjian.us 3279 :CBC 381491 : case TBLOCK_STARTED:
8576 tgl@sss.pgh.pa.us 3280 : 381491 : CommitTransaction();
8249 bruce@momjian.us 3281 : 381448 : s->blockState = TBLOCK_DEFAULT;
10650 3282 : 381448 : break;
3283 : :
3284 : : /*
3285 : : * We are completing a "BEGIN TRANSACTION" command, so we change
3286 : : * to the "transaction block in progress" state and return. (We
3287 : : * assume the BEGIN did nothing to the database, so we need no
3288 : : * CommandCounterIncrement.)
3289 : : */
3290 : 12486 : case TBLOCK_BEGIN:
3291 : 12486 : s->blockState = TBLOCK_INPROGRESS;
3292 : 12486 : break;
3293 : :
3294 : : /*
3295 : : * This is the case when we have finished executing a command
3296 : : * someplace within a transaction block. We increment the command
3297 : : * counter and return.
3298 : : */
3299 : 75864 : case TBLOCK_INPROGRESS:
3300 : : case TBLOCK_IMPLICIT_INPROGRESS:
3301 : : case TBLOCK_SUBINPROGRESS:
3302 : 75864 : CommandCounterIncrement();
3303 : 75864 : break;
3304 : :
3305 : : /*
3306 : : * We are completing a "COMMIT" command. Do it and return to the
3307 : : * idle state.
3308 : : */
3309 : 8733 : case TBLOCK_END:
3310 : 8733 : CommitTransaction();
9626 tgl@sss.pgh.pa.us 3311 : 8479 : s->blockState = TBLOCK_DEFAULT;
2783 peter@eisentraut.org 3312 [ + + ]: 8479 : if (s->chain)
3313 : : {
3314 : 8 : StartTransaction();
3315 : 8 : s->blockState = TBLOCK_INPROGRESS;
3316 : 8 : s->chain = false;
1711 tgl@sss.pgh.pa.us 3317 : 8 : RestoreTransactionCharacteristics(&savetc);
3318 : : }
10650 bruce@momjian.us 3319 : 8479 : break;
3320 : :
3321 : : /*
3322 : : * Here we are in the middle of a transaction block but one of the
3323 : : * commands caused an abort so we do nothing but remain in the
3324 : : * abort state. Eventually we will get a ROLLBACK command.
3325 : : */
3326 : 13 : case TBLOCK_ABORT:
3327 : : case TBLOCK_SUBABORT:
3328 : 13 : break;
3329 : :
3330 : : /*
3331 : : * Here we were in an aborted transaction block and we just got
3332 : : * the ROLLBACK command from the user, so clean up the
3333 : : * already-aborted transaction and return to the idle state.
3334 : : */
8085 tgl@sss.pgh.pa.us 3335 : 883 : case TBLOCK_ABORT_END:
9626 3336 : 883 : CleanupTransaction();
10650 bruce@momjian.us 3337 : 883 : s->blockState = TBLOCK_DEFAULT;
2783 peter@eisentraut.org 3338 [ + + ]: 883 : if (s->chain)
3339 : : {
3340 : 8 : StartTransaction();
3341 : 8 : s->blockState = TBLOCK_INPROGRESS;
3342 : 8 : s->chain = false;
1711 tgl@sss.pgh.pa.us 3343 : 8 : RestoreTransactionCharacteristics(&savetc);
3344 : : }
10650 bruce@momjian.us 3345 : 883 : break;
3346 : :
3347 : : /*
3348 : : * Here we were in a perfectly good transaction block but the user
3349 : : * told us to ROLLBACK anyway. We have to abort the transaction
3350 : : * and then clean up.
3351 : : */
8085 tgl@sss.pgh.pa.us 3352 : 1868 : case TBLOCK_ABORT_PENDING:
3353 : 1868 : AbortTransaction();
3354 : 1868 : CleanupTransaction();
3355 : 1868 : s->blockState = TBLOCK_DEFAULT;
2783 peter@eisentraut.org 3356 [ + + ]: 1868 : if (s->chain)
3357 : : {
3358 : 12 : StartTransaction();
3359 : 12 : s->blockState = TBLOCK_INPROGRESS;
3360 : 12 : s->chain = false;
1711 tgl@sss.pgh.pa.us 3361 : 12 : RestoreTransactionCharacteristics(&savetc);
3362 : : }
8136 3363 : 1868 : break;
3364 : :
3365 : : /*
3366 : : * We are completing a "PREPARE TRANSACTION" command. Do it and
3367 : : * return to the idle state.
3368 : : */
7811 3369 : 272 : case TBLOCK_PREPARE:
3370 : 272 : PrepareTransaction();
3371 : 208 : s->blockState = TBLOCK_DEFAULT;
3372 : 208 : break;
3373 : :
3374 : : /*
3375 : : * The user issued a SAVEPOINT inside a transaction block. Start a
3376 : : * subtransaction. (DefineSavepoint already did PushTransaction,
3377 : : * so as to have someplace to put the SUBBEGIN state.)
3378 : : */
8162 3379 : 22470 : case TBLOCK_SUBBEGIN:
3380 : 22470 : StartSubTransaction();
3381 : 22470 : s->blockState = TBLOCK_SUBINPROGRESS;
3382 : 22470 : break;
3383 : :
3384 : : /*
3385 : : * The user issued a RELEASE command, so we end the current
3386 : : * subtransaction and return to the parent transaction. The parent
3387 : : * might be ended too, so repeat till we find an INPROGRESS
3388 : : * transaction or subtransaction.
3389 : : */
5588 simon@2ndQuadrant.co 3390 : 269 : case TBLOCK_SUBRELEASE:
3391 : : do
3392 : : {
5538 3393 : 269 : CommitSubTransaction();
8103 bruce@momjian.us 3394 : 269 : s = CurrentTransactionState; /* changed by pop */
5588 simon@2ndQuadrant.co 3395 [ + + ]: 269 : } while (s->blockState == TBLOCK_SUBRELEASE);
3396 : :
3397 [ + + - + ]: 182 : Assert(s->blockState == TBLOCK_INPROGRESS ||
3398 : : s->blockState == TBLOCK_SUBINPROGRESS);
3399 : 182 : break;
3400 : :
3401 : : /*
3402 : : * The user issued a COMMIT, so we end the current subtransaction
3403 : : * hierarchy and perform final commit. We do this by rolling up
3404 : : * any subtransactions into their parent, which leads to O(N^2)
3405 : : * operations with respect to resource owners - this isn't that
3406 : : * bad until we approach a thousands of savepoints but is
3407 : : * necessary for correctness should after triggers create new
3408 : : * resource owners.
3409 : : */
3410 : 597 : case TBLOCK_SUBCOMMIT:
3411 : : do
3412 : : {
5538 3413 : 597 : CommitSubTransaction();
5588 3414 : 597 : s = CurrentTransactionState; /* changed by pop */
3415 [ + + ]: 597 : } while (s->blockState == TBLOCK_SUBCOMMIT);
3416 : : /* If we had a COMMIT command, finish off the main xact too */
8091 tgl@sss.pgh.pa.us 3417 [ + + ]: 504 : if (s->blockState == TBLOCK_END)
3418 : : {
3419 [ - + ]: 405 : Assert(s->parent == NULL);
3420 : 405 : CommitTransaction();
3421 : 388 : s->blockState = TBLOCK_DEFAULT;
2085 fujii@postgresql.org 3422 [ + + ]: 388 : if (s->chain)
3423 : : {
3424 : 12 : StartTransaction();
3425 : 12 : s->blockState = TBLOCK_INPROGRESS;
3426 : 12 : s->chain = false;
1711 tgl@sss.pgh.pa.us 3427 : 12 : RestoreTransactionCharacteristics(&savetc);
3428 : : }
3429 : : }
7811 3430 [ + - ]: 99 : else if (s->blockState == TBLOCK_PREPARE)
3431 : : {
3432 [ - + ]: 99 : Assert(s->parent == NULL);
3433 : 99 : PrepareTransaction();
3434 : 97 : s->blockState = TBLOCK_DEFAULT;
3435 : : }
3436 : : else
5588 simon@2ndQuadrant.co 3437 [ # # ]:UBC 0 : elog(ERROR, "CommitTransactionCommand: unexpected state %s",
3438 : : BlockStateAsString(s->blockState));
8162 tgl@sss.pgh.pa.us 3439 :CBC 485 : break;
3440 : :
3441 : : /*
3442 : : * The current already-failed subtransaction is ending due to a
3443 : : * ROLLBACK or ROLLBACK TO command, so pop it and recursively
3444 : : * examine the parent (which could be in any of several states).
3445 : : * As we need to examine the parent, return false to request the
3446 : : * caller to do the next iteration.
3447 : : */
931 akorotkov@postgresql 3448 : 51 : case TBLOCK_SUBABORT_END:
3449 : 51 : CleanupSubTransaction();
3450 : 51 : return false;
3451 : :
3452 : : /*
3453 : : * As above, but it's not dead yet, so abort first.
3454 : : */
3455 : 276 : case TBLOCK_SUBABORT_PENDING:
3456 : 276 : AbortSubTransaction();
3457 : 276 : CleanupSubTransaction();
3458 : 276 : return false;
3459 : :
3460 : : /*
3461 : : * The current subtransaction is the target of a ROLLBACK TO
3462 : : * command. Abort and pop it, then start a new subtransaction
3463 : : * with the same name.
3464 : : */
8085 tgl@sss.pgh.pa.us 3465 : 344 : case TBLOCK_SUBRESTART:
3466 : : {
3467 : : char *name;
3468 : : int savepointLevel;
3469 : :
3470 : : /* save name and keep Cleanup from freeing it */
3471 : 344 : name = s->name;
3472 : 344 : s->name = NULL;
3473 : 344 : savepointLevel = s->savepointLevel;
3474 : :
3475 : 344 : AbortSubTransaction();
3476 : 344 : CleanupSubTransaction();
3477 : :
3478 : 344 : DefineSavepoint(NULL);
3479 : 344 : s = CurrentTransactionState; /* changed by push */
3480 : 344 : s->name = name;
3481 : 344 : s->savepointLevel = savepointLevel;
3482 : :
3483 : : /* This is the same as TBLOCK_SUBBEGIN case */
1469 peter@eisentraut.org 3484 [ - + ]: 344 : Assert(s->blockState == TBLOCK_SUBBEGIN);
8136 tgl@sss.pgh.pa.us 3485 : 344 : StartSubTransaction();
3486 : 344 : s->blockState = TBLOCK_SUBINPROGRESS;
3487 : : }
8162 3488 : 344 : break;
3489 : :
3490 : : /*
3491 : : * Same as above, but the subtransaction had already failed, so we
3492 : : * don't need AbortSubTransaction.
3493 : : */
8085 3494 : 185 : case TBLOCK_SUBABORT_RESTART:
3495 : : {
3496 : : char *name;
3497 : : int savepointLevel;
3498 : :
3499 : : /* save name and keep Cleanup from freeing it */
3500 : 185 : name = s->name;
3501 : 185 : s->name = NULL;
3502 : 185 : savepointLevel = s->savepointLevel;
3503 : :
3504 : 185 : CleanupSubTransaction();
3505 : :
3506 : 185 : DefineSavepoint(NULL);
3507 : 185 : s = CurrentTransactionState; /* changed by push */
3508 : 185 : s->name = name;
3509 : 185 : s->savepointLevel = savepointLevel;
3510 : :
3511 : : /* This is the same as TBLOCK_SUBBEGIN case */
1469 peter@eisentraut.org 3512 [ - + ]: 185 : Assert(s->blockState == TBLOCK_SUBBEGIN);
8085 tgl@sss.pgh.pa.us 3513 : 185 : StartSubTransaction();
3514 : 185 : s->blockState = TBLOCK_SUBINPROGRESS;
3515 : : }
3516 : 185 : break;
3517 : : }
3518 : :
3519 : : /* Done, no more iterations required */
931 akorotkov@postgresql 3520 : 504915 : return true;
3521 : : }
3522 : :
3523 : : /*
3524 : : * AbortCurrentTransaction -- a wrapper function handling the
3525 : : * loop over subtransactions to avoid potentially dangerous recursion in
3526 : : * AbortCurrentTransactionInternal().
3527 : : */
3528 : : void
8162 tgl@sss.pgh.pa.us 3529 : 34653 : AbortCurrentTransaction(void)
3530 : : {
3531 : : /*
3532 : : * Repeatedly call AbortCurrentTransactionInternal() until all the work is
3533 : : * done.
3534 : : */
931 akorotkov@postgresql 3535 [ - + ]: 34653 : while (!AbortCurrentTransactionInternal())
3536 : : {
3537 : : }
972 3538 : 34653 : }
3539 : :
3540 : : /*
3541 : : * AbortCurrentTransactionInternal - a function doing an iteration of work
3542 : : * regarding handling the current transaction abort. In the case of
3543 : : * subtransactions more than one iterations could be required. Returns
3544 : : * true when no more iterations required, false otherwise.
3545 : : */
3546 : : static bool
3547 : 34653 : AbortCurrentTransactionInternal(void)
3548 : : {
8162 tgl@sss.pgh.pa.us 3549 : 34653 : TransactionState s = CurrentTransactionState;
3550 : :
3551 [ + + - + : 34653 : switch (s->blockState)
+ + - - +
+ - - - ]
3552 : : {
8249 bruce@momjian.us 3553 : 60 : case TBLOCK_DEFAULT:
7928 tgl@sss.pgh.pa.us 3554 [ - + ]: 60 : if (s->state == TRANS_DEFAULT)
3555 : : {
3556 : : /* we are idle, so nothing to do */
3557 : : }
3558 : : else
3559 : : {
3560 : : /*
3561 : : * We can get here after an error during transaction start
3562 : : * (state will be TRANS_START). Need to clean up the
3563 : : * incompletely started transaction. First, adjust the
3564 : : * low-level state to suppress warning message from
3565 : : * AbortTransaction.
3566 : : */
7928 tgl@sss.pgh.pa.us 3567 [ # # ]:UBC 0 : if (s->state == TRANS_START)
3568 : 0 : s->state = TRANS_INPROGRESS;
3569 : 0 : AbortTransaction();
3570 : 0 : CleanupTransaction();
3571 : : }
8249 bruce@momjian.us 3572 :CBC 60 : break;
3573 : :
3574 : : /*
3575 : : * If we aren't in a transaction block, we just do the basic abort
3576 : : * & cleanup transaction. For this purpose, we treat an implicit
3577 : : * transaction block as if it were a simple statement.
3578 : : */
3579 : 32026 : case TBLOCK_STARTED:
3580 : : case TBLOCK_IMPLICIT_INPROGRESS:
10650 3581 : 32026 : AbortTransaction();
8576 tgl@sss.pgh.pa.us 3582 : 32026 : CleanupTransaction();
8249 bruce@momjian.us 3583 : 32026 : s->blockState = TBLOCK_DEFAULT;
10650 3584 : 32026 : break;
3585 : :
3586 : : /*
3587 : : * If we are in TBLOCK_BEGIN it means something screwed up right
3588 : : * after reading "BEGIN TRANSACTION". We assume that the user
3589 : : * will interpret the error as meaning the BEGIN failed to get him
3590 : : * into a transaction block, so we should abort and return to idle
3591 : : * state.
3592 : : */
10650 bruce@momjian.us 3593 :UBC 0 : case TBLOCK_BEGIN:
3594 : 0 : AbortTransaction();
8085 tgl@sss.pgh.pa.us 3595 : 0 : CleanupTransaction();
3596 : 0 : s->blockState = TBLOCK_DEFAULT;
10650 bruce@momjian.us 3597 : 0 : break;
3598 : :
3599 : : /*
3600 : : * We are somewhere in a transaction block and we've gotten a
3601 : : * failure, so we abort the transaction and set up the persistent
3602 : : * ABORT state. We will stay in ABORT until we get a ROLLBACK.
3603 : : */
10650 bruce@momjian.us 3604 :CBC 900 : case TBLOCK_INPROGRESS:
3605 : : case TBLOCK_PARALLEL_INPROGRESS:
3606 : 900 : AbortTransaction();
8249 3607 : 900 : s->blockState = TBLOCK_ABORT;
3608 : : /* CleanupTransaction happens when we exit TBLOCK_ABORT_END */
10650 3609 : 900 : break;
3610 : :
3611 : : /*
3612 : : * Here, we failed while trying to COMMIT. Clean up the
3613 : : * transaction and return to idle state (we do not want to stay in
3614 : : * the transaction).
3615 : : */
3616 : 271 : case TBLOCK_END:
3617 : 271 : AbortTransaction();
9626 tgl@sss.pgh.pa.us 3618 : 271 : CleanupTransaction();
8249 bruce@momjian.us 3619 : 271 : s->blockState = TBLOCK_DEFAULT;
10650 3620 : 271 : break;
3621 : :
3622 : : /*
3623 : : * Here, we are already in an aborted transaction state and are
3624 : : * waiting for a ROLLBACK, but for some reason we failed again! So
3625 : : * we just remain in the abort state.
3626 : : */
3627 : 63 : case TBLOCK_ABORT:
3628 : : case TBLOCK_SUBABORT:
3629 : 63 : break;
3630 : :
3631 : : /*
3632 : : * We are in a failed transaction and we got the ROLLBACK command.
3633 : : * We have already aborted, we just need to cleanup and go to idle
3634 : : * state.
3635 : : */
8085 tgl@sss.pgh.pa.us 3636 :UBC 0 : case TBLOCK_ABORT_END:
9626 3637 : 0 : CleanupTransaction();
10650 bruce@momjian.us 3638 : 0 : s->blockState = TBLOCK_DEFAULT;
3639 : 0 : break;
3640 : :
3641 : : /*
3642 : : * We are in a live transaction and we got a ROLLBACK command.
3643 : : * Abort, cleanup, go to idle state.
3644 : : */
8085 tgl@sss.pgh.pa.us 3645 : 0 : case TBLOCK_ABORT_PENDING:
3646 : 0 : AbortTransaction();
3647 : 0 : CleanupTransaction();
3648 : 0 : s->blockState = TBLOCK_DEFAULT;
8162 3649 : 0 : break;
3650 : :
3651 : : /*
3652 : : * Here, we failed while trying to PREPARE. Clean up the
3653 : : * transaction and return to idle state (we do not want to stay in
3654 : : * the transaction).
3655 : : */
7811 tgl@sss.pgh.pa.us 3656 :CBC 64 : case TBLOCK_PREPARE:
3657 : 64 : AbortTransaction();
3658 : 64 : CleanupTransaction();
3659 : 64 : s->blockState = TBLOCK_DEFAULT;
3660 : 64 : break;
3661 : :
3662 : : /*
3663 : : * We got an error inside a subtransaction. Abort just the
3664 : : * subtransaction, and go to the persistent SUBABORT state until
3665 : : * we get ROLLBACK.
3666 : : */
8162 3667 : 1269 : case TBLOCK_SUBINPROGRESS:
3668 : 1269 : AbortSubTransaction();
3669 : 1269 : s->blockState = TBLOCK_SUBABORT;
3670 : 1269 : break;
3671 : :
3672 : : /*
3673 : : * If we failed while trying to create a subtransaction, clean up
3674 : : * the broken subtransaction and abort the parent. The same
3675 : : * applies if we get a failure while ending a subtransaction. As
3676 : : * we need to abort the parent, return false to request the caller
3677 : : * to do the next iteration.
3678 : : */
931 akorotkov@postgresql 3679 :UBC 0 : case TBLOCK_SUBBEGIN:
3680 : : case TBLOCK_SUBRELEASE:
3681 : : case TBLOCK_SUBCOMMIT:
3682 : : case TBLOCK_SUBABORT_PENDING:
3683 : : case TBLOCK_SUBRESTART:
3684 : 0 : AbortSubTransaction();
3685 : 0 : CleanupSubTransaction();
3686 : 0 : return false;
3687 : :
3688 : : /*
3689 : : * Same as above, except the Abort() was already done.
3690 : : */
3691 : 0 : case TBLOCK_SUBABORT_END:
3692 : : case TBLOCK_SUBABORT_RESTART:
3693 : 0 : CleanupSubTransaction();
3694 : 0 : return false;
3695 : : }
3696 : :
3697 : : /* Done, no more iterations required */
931 akorotkov@postgresql 3698 :CBC 34653 : return true;
3699 : : }
3700 : :
3701 : : /*
3702 : : * PreventInTransactionBlock
3703 : : *
3704 : : * This routine is to be called by statements that must not run inside
3705 : : * a transaction block, typically because they have non-rollback-able
3706 : : * side effects or do internal commits.
3707 : : *
3708 : : * If this routine completes successfully, then the calling statement is
3709 : : * guaranteed that if it completes without error, its results will be
3710 : : * committed immediately.
3711 : : *
3712 : : * If we have already started a transaction block, issue an error; also issue
3713 : : * an error if we appear to be running inside a user-defined function (which
3714 : : * could issue more commands and possibly cause a failure after the statement
3715 : : * completes). Subtransactions are verboten too.
3716 : : *
3717 : : * We must also set XACT_FLAGS_NEEDIMMEDIATECOMMIT in MyXactFlags, to ensure
3718 : : * that postgres.c follows through by committing after the statement is done.
3719 : : *
3720 : : * isTopLevel: passed down from ProcessUtility to determine whether we are
3721 : : * inside a function. (We will always fail if this is false, but it's
3722 : : * convenient to centralize the check here instead of making callers do it.)
3723 : : * stmtType: statement type name, for error messages.
3724 : : */
3725 : : void
3184 peter_e@gmx.net 3726 : 9217 : PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
3727 : : {
3728 : : /*
3729 : : * xact block already started?
3730 : : */
8781 tgl@sss.pgh.pa.us 3731 [ + + ]: 9217 : if (IsTransactionBlock())
8508 3732 [ + - ]: 82 : ereport(ERROR,
3733 : : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
3734 : : /* translator: %s represents an SQL statement name */
3735 : : errmsg("%s cannot run inside a transaction block",
3736 : : stmtType)));
3737 : :
3738 : : /*
3739 : : * subtransaction?
3740 : : */
8162 3741 [ - + ]: 9135 : if (IsSubTransaction())
8162 tgl@sss.pgh.pa.us 3742 [ # # ]:UBC 0 : ereport(ERROR,
3743 : : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
3744 : : /* translator: %s represents an SQL statement name */
3745 : : errmsg("%s cannot run inside a subtransaction",
3746 : : stmtType)));
3747 : :
3748 : : /*
3749 : : * inside a function call?
3750 : : */
7177 tgl@sss.pgh.pa.us 3751 [ + + ]:CBC 9135 : if (!isTopLevel)
8508 3752 [ + - ]: 8 : ereport(ERROR,
3753 : : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
3754 : : /* translator: %s represents an SQL statement name */
3755 : : errmsg("%s cannot be executed from a function or procedure",
3756 : : stmtType)));
3757 : :
3758 : : /* If we got past IsTransactionBlock test, should be in default state */
8249 bruce@momjian.us 3759 [ + + ]: 9127 : if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
8202 tgl@sss.pgh.pa.us 3760 [ - + ]: 8057 : CurrentTransactionState->blockState != TBLOCK_STARTED)
8162 tgl@sss.pgh.pa.us 3761 [ # # ]:UBC 0 : elog(FATAL, "cannot prevent transaction chain");
3762 : :
3763 : : /* All okay. Set the flag to make sure the right thing happens later. */
1563 tgl@sss.pgh.pa.us 3764 :CBC 9127 : MyXactFlags |= XACT_FLAGS_NEEDIMMEDIATECOMMIT;
8781 3765 : 9127 : }
3766 : :
3767 : : /*
3768 : : * WarnNoTransactionBlock
3769 : : * RequireTransactionBlock
3770 : : *
3771 : : * These two functions allow for warnings or errors if a command is executed
3772 : : * outside of a transaction block. This is useful for commands that have no
3773 : : * effects that persist past transaction end (and so calling them outside a
3774 : : * transaction block is presumably an error). DECLARE CURSOR is an example.
3775 : : * While top-level transaction control commands (BEGIN/COMMIT/ABORT) and SET
3776 : : * that have no effect issue warnings, all other no-effect commands generate
3777 : : * errors.
3778 : : *
3779 : : * If we appear to be running inside a user-defined function, we do not
3780 : : * issue anything, since the function could issue more commands that make
3781 : : * use of the current statement's results. Likewise subtransactions.
3782 : : * Thus these are inverses for PreventInTransactionBlock.
3783 : : *
3784 : : * isTopLevel: passed down from ProcessUtility to determine whether we are
3785 : : * inside a function.
3786 : : * stmtType: statement type name, for warning or error messages.
3787 : : */
3788 : : void
3184 peter_e@gmx.net 3789 : 1527 : WarnNoTransactionBlock(bool isTopLevel, const char *stmtType)
3790 : : {
3791 : 1527 : CheckTransactionBlock(isTopLevel, false, stmtType);
4728 bruce@momjian.us 3792 : 1527 : }
3793 : :
3794 : : void
3184 peter_e@gmx.net 3795 : 5153 : RequireTransactionBlock(bool isTopLevel, const char *stmtType)
3796 : : {
3797 : 5153 : CheckTransactionBlock(isTopLevel, true, stmtType);
4728 bruce@momjian.us 3798 : 5130 : }
3799 : :
3800 : : /*
3801 : : * This is the implementation of the above two.
3802 : : */
3803 : : static void
3184 peter_e@gmx.net 3804 : 6680 : CheckTransactionBlock(bool isTopLevel, bool throwError, const char *stmtType)
3805 : : {
3806 : : /*
3807 : : * xact block already started?
3808 : : */
8753 tgl@sss.pgh.pa.us 3809 [ + + ]: 6680 : if (IsTransactionBlock())
3810 : 6561 : return;
3811 : :
3812 : : /*
3813 : : * subtransaction?
3814 : : */
8162 3815 [ - + ]: 119 : if (IsSubTransaction())
8162 tgl@sss.pgh.pa.us 3816 :UBC 0 : return;
3817 : :
3818 : : /*
3819 : : * inside a function call?
3820 : : */
7177 tgl@sss.pgh.pa.us 3821 [ + + ]:CBC 119 : if (!isTopLevel)
8753 3822 : 82 : return;
3823 : :
4728 bruce@momjian.us 3824 [ + + + - ]: 37 : ereport(throwError ? ERROR : WARNING,
3825 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
3826 : : /* translator: %s represents an SQL statement name */
3827 : : errmsg("%s can only be used in transaction blocks",
3828 : : stmtType)));
3829 : : }
3830 : :
3831 : : /*
3832 : : * IsInTransactionBlock
3833 : : *
3834 : : * This routine is for statements that need to behave differently inside
3835 : : * a transaction block than when running as single commands. ANALYZE is
3836 : : * currently the only example.
3837 : : *
3838 : : * If this routine returns "false", then the calling statement is allowed
3839 : : * to perform internal transaction-commit-and-start cycles; there is not a
3840 : : * risk of messing up any transaction already in progress. (Note that this
3841 : : * is not the identical guarantee provided by PreventInTransactionBlock,
3842 : : * since we will not force a post-statement commit.)
3843 : : *
3844 : : * isTopLevel: passed down from ProcessUtility to determine whether we are
3845 : : * inside a function.
3846 : : */
3847 : : bool
3184 peter_e@gmx.net 3848 : 3384 : IsInTransactionBlock(bool isTopLevel)
3849 : : {
3850 : : /*
3851 : : * Return true on same conditions that would make
3852 : : * PreventInTransactionBlock error out
3853 : : */
8202 tgl@sss.pgh.pa.us 3854 [ + + ]: 3384 : if (IsTransactionBlock())
3855 : 110 : return true;
3856 : :
8162 3857 [ - + ]: 3274 : if (IsSubTransaction())
8162 tgl@sss.pgh.pa.us 3858 :UBC 0 : return true;
3859 : :
7177 tgl@sss.pgh.pa.us 3860 [ + + ]:CBC 3274 : if (!isTopLevel)
8202 3861 : 74 : return true;
3862 : :
3863 [ + - ]: 3200 : if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
3864 [ - + ]: 3200 : CurrentTransactionState->blockState != TBLOCK_STARTED)
8202 tgl@sss.pgh.pa.us 3865 :UBC 0 : return true;
3866 : :
8202 tgl@sss.pgh.pa.us 3867 :CBC 3200 : return false;
3868 : : }
3869 : :
3870 : :
3871 : : /*
3872 : : * Register or deregister callback functions for start- and end-of-xact
3873 : : * operations.
3874 : : *
3875 : : * These functions are intended for use by dynamically loaded modules.
3876 : : * For built-in modules we generally just hardwire the appropriate calls
3877 : : * (mainly because it's easier to control the order that way, where needed).
3878 : : *
3879 : : * At transaction end, the callback occurs post-commit or post-abort, so the
3880 : : * callback functions can only do noncritical cleanup.
3881 : : */
3882 : : void
8131 3883 : 2340 : RegisterXactCallback(XactCallback callback, void *arg)
3884 : : {
3885 : : XactCallbackItem *item;
3886 : :
3887 : : item = (XactCallbackItem *)
3888 : 2340 : MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
8439 3889 : 2340 : item->callback = callback;
3890 : 2340 : item->arg = arg;
8131 3891 : 2340 : item->next = Xact_callbacks;
3892 : 2340 : Xact_callbacks = item;
8439 3893 : 2340 : }
3894 : :
3895 : : void
8131 tgl@sss.pgh.pa.us 3896 :UBC 0 : UnregisterXactCallback(XactCallback callback, void *arg)
3897 : : {
3898 : : XactCallbackItem *item;
3899 : : XactCallbackItem *prev;
3900 : :
8439 3901 : 0 : prev = NULL;
8131 3902 [ # # ]: 0 : for (item = Xact_callbacks; item; prev = item, item = item->next)
3903 : : {
8439 3904 [ # # # # ]: 0 : if (item->callback == callback && item->arg == arg)
3905 : : {
3906 [ # # ]: 0 : if (prev)
3907 : 0 : prev->next = item->next;
3908 : : else
8131 3909 : 0 : Xact_callbacks = item->next;
8439 3910 : 0 : pfree(item);
3911 : 0 : break;
3912 : : }
3913 : : }
3914 : 0 : }
3915 : :
3916 : : static void
8085 tgl@sss.pgh.pa.us 3917 :CBC 821306 : CallXactCallbacks(XactEvent event)
3918 : : {
3919 : : XactCallbackItem *item;
3920 : : XactCallbackItem *next;
3921 : :
1499 3922 [ + + ]: 1029572 : for (item = Xact_callbacks; item; item = next)
3923 : : {
3924 : : /* allow callbacks to unregister themselves when called */
3925 : 208268 : next = item->next;
3346 peter_e@gmx.net 3926 : 208268 : item->callback(event, item->arg);
3927 : : }
8085 tgl@sss.pgh.pa.us 3928 : 821304 : }
3929 : :
3930 : :
3931 : : /*
3932 : : * Register or deregister callback functions for start- and end-of-subxact
3933 : : * operations.
3934 : : *
3935 : : * Pretty much same as above, but for subtransaction events.
3936 : : *
3937 : : * At subtransaction end, the callback occurs post-subcommit or post-subabort,
3938 : : * so the callback functions can only do noncritical cleanup. At
3939 : : * subtransaction start, the callback is called when the subtransaction has
3940 : : * finished initializing.
3941 : : */
3942 : : void
3943 : 2340 : RegisterSubXactCallback(SubXactCallback callback, void *arg)
3944 : : {
3945 : : SubXactCallbackItem *item;
3946 : :
3947 : : item = (SubXactCallbackItem *)
3948 : 2340 : MemoryContextAlloc(TopMemoryContext, sizeof(SubXactCallbackItem));
3949 : 2340 : item->callback = callback;
3950 : 2340 : item->arg = arg;
3951 : 2340 : item->next = SubXact_callbacks;
3952 : 2340 : SubXact_callbacks = item;
3953 : 2340 : }
3954 : :
3955 : : void
8085 tgl@sss.pgh.pa.us 3956 :UBC 0 : UnregisterSubXactCallback(SubXactCallback callback, void *arg)
3957 : : {
3958 : : SubXactCallbackItem *item;
3959 : : SubXactCallbackItem *prev;
3960 : :
3961 : 0 : prev = NULL;
3962 [ # # ]: 0 : for (item = SubXact_callbacks; item; prev = item, item = item->next)
3963 : : {
3964 [ # # # # ]: 0 : if (item->callback == callback && item->arg == arg)
3965 : : {
3966 [ # # ]: 0 : if (prev)
3967 : 0 : prev->next = item->next;
3968 : : else
3969 : 0 : SubXact_callbacks = item->next;
3970 : 0 : pfree(item);
3971 : 0 : break;
3972 : : }
3973 : : }
3974 : 0 : }
3975 : :
3976 : : static void
8085 tgl@sss.pgh.pa.us 3977 :CBC 63380 : CallSubXactCallbacks(SubXactEvent event,
3978 : : SubTransactionId mySubid,
3979 : : SubTransactionId parentSubid)
3980 : : {
3981 : : SubXactCallbackItem *item;
3982 : : SubXactCallbackItem *next;
3983 : :
1499 3984 [ + + ]: 120719 : for (item = SubXact_callbacks; item; item = next)
3985 : : {
3986 : : /* allow callbacks to unregister themselves when called */
3987 : 57339 : next = item->next;
3346 peter_e@gmx.net 3988 : 57339 : item->callback(event, mySubid, parentSubid, item->arg);
3989 : : }
8439 tgl@sss.pgh.pa.us 3990 : 63380 : }
3991 : :
3992 : :
3993 : : /* ----------------------------------------------------------------
3994 : : * transaction block support
3995 : : * ----------------------------------------------------------------
3996 : : */
3997 : :
3998 : : /*
3999 : : * BeginTransactionBlock
4000 : : * This executes a BEGIN command.
4001 : : */
4002 : : void
10651 bruce@momjian.us 4003 : 12486 : BeginTransactionBlock(void)
4004 : : {
4005 : 12486 : TransactionState s = CurrentTransactionState;
4006 : :
8136 tgl@sss.pgh.pa.us 4007 [ + + - - : 12486 : switch (s->blockState)
- ]
4008 : : {
4009 : : /*
4010 : : * We are not inside a transaction block, so allow one to begin.
4011 : : */
8249 bruce@momjian.us 4012 : 11975 : case TBLOCK_STARTED:
4013 : 11975 : s->blockState = TBLOCK_BEGIN;
4014 : 11975 : break;
4015 : :
4016 : : /*
4017 : : * BEGIN converts an implicit transaction block to a regular one.
4018 : : * (Note that we allow this even if we've already done some
4019 : : * commands, which is a bit odd but matches historical practice.)
4020 : : */
3346 tgl@sss.pgh.pa.us 4021 : 511 : case TBLOCK_IMPLICIT_INPROGRESS:
4022 : 511 : s->blockState = TBLOCK_BEGIN;
4023 : 511 : break;
4024 : :
4025 : : /*
4026 : : * Already a transaction block in progress.
4027 : : */
8249 bruce@momjian.us 4028 :UBC 0 : case TBLOCK_INPROGRESS:
4029 : : case TBLOCK_PARALLEL_INPROGRESS:
4030 : : case TBLOCK_SUBINPROGRESS:
4031 : : case TBLOCK_ABORT:
4032 : : case TBLOCK_SUBABORT:
8136 tgl@sss.pgh.pa.us 4033 [ # # ]: 0 : ereport(WARNING,
4034 : : (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
4035 : : errmsg("there is already a transaction in progress")));
8249 bruce@momjian.us 4036 : 0 : break;
4037 : :
4038 : : /* These cases are invalid. */
4039 : 0 : case TBLOCK_DEFAULT:
4040 : : case TBLOCK_BEGIN:
4041 : : case TBLOCK_SUBBEGIN:
4042 : : case TBLOCK_END:
4043 : : case TBLOCK_SUBRELEASE:
4044 : : case TBLOCK_SUBCOMMIT:
4045 : : case TBLOCK_ABORT_END:
4046 : : case TBLOCK_SUBABORT_END:
4047 : : case TBLOCK_ABORT_PENDING:
4048 : : case TBLOCK_SUBABORT_PENDING:
4049 : : case TBLOCK_SUBRESTART:
4050 : : case TBLOCK_SUBABORT_RESTART:
4051 : : case TBLOCK_PREPARE:
8162 tgl@sss.pgh.pa.us 4052 [ # # ]: 0 : elog(FATAL, "BeginTransactionBlock: unexpected state %s",
4053 : : BlockStateAsString(s->blockState));
4054 : : break;
4055 : : }
11076 scrappy@hub.org 4056 :CBC 12486 : }
4057 : :
4058 : : /*
4059 : : * PrepareTransactionBlock
4060 : : * This executes a PREPARE command.
4061 : : *
4062 : : * Since PREPARE may actually do a ROLLBACK, the result indicates what
4063 : : * happened: true for PREPARE, false for ROLLBACK.
4064 : : *
4065 : : * Note that we don't actually do anything here except change blockState.
4066 : : * The real work will be done in the upcoming PrepareTransaction().
4067 : : * We do it this way because it's not convenient to change memory context,
4068 : : * resource owner, etc while executing inside a Portal.
4069 : : */
4070 : : bool
3292 peter_e@gmx.net 4071 : 373 : PrepareTransactionBlock(const char *gid)
4072 : : {
4073 : : TransactionState s;
4074 : : bool result;
4075 : :
4076 : : /* Set up to commit the current transaction */
2783 peter@eisentraut.org 4077 : 373 : result = EndTransactionBlock(false);
4078 : :
4079 : : /* If successful, change outer tblock state to PREPARE */
7811 tgl@sss.pgh.pa.us 4080 [ + + ]: 373 : if (result)
4081 : : {
4082 : 371 : s = CurrentTransactionState;
4083 : :
4084 [ + + ]: 480 : while (s->parent != NULL)
4085 : 109 : s = s->parent;
4086 : :
4087 [ + - ]: 371 : if (s->blockState == TBLOCK_END)
4088 : : {
4089 : : /* Save GID where PrepareTransaction can find it again */
4090 : 371 : prepareGID = MemoryContextStrdup(TopTransactionContext, gid);
4091 : :
4092 : 371 : s->blockState = TBLOCK_PREPARE;
4093 : : }
4094 : : else
4095 : : {
4096 : : /*
4097 : : * ignore case where we are not in a transaction;
4098 : : * EndTransactionBlock already issued a warning.
4099 : : */
3346 tgl@sss.pgh.pa.us 4100 [ # # # # ]:UBC 0 : Assert(s->blockState == TBLOCK_STARTED ||
4101 : : s->blockState == TBLOCK_IMPLICIT_INPROGRESS);
4102 : : /* Don't send back a PREPARE result tag... */
7811 4103 : 0 : result = false;
4104 : : }
4105 : : }
4106 : :
7811 tgl@sss.pgh.pa.us 4107 :CBC 373 : return result;
4108 : : }
4109 : :
4110 : : /*
4111 : : * EndTransactionBlock
4112 : : * This executes a COMMIT command.
4113 : : *
4114 : : * Since COMMIT may actually do a ROLLBACK, the result indicates what
4115 : : * happened: true for COMMIT, false for ROLLBACK.
4116 : : *
4117 : : * Note that we don't actually do anything here except change blockState.
4118 : : * The real work will be done in the upcoming CommitTransactionCommand().
4119 : : * We do it this way because it's not convenient to change memory context,
4120 : : * resource owner, etc while executing inside a Portal.
4121 : : */
4122 : : bool
2783 peter@eisentraut.org 4123 : 10022 : EndTransactionBlock(bool chain)
4124 : : {
10651 bruce@momjian.us 4125 : 10022 : TransactionState s = CurrentTransactionState;
8136 tgl@sss.pgh.pa.us 4126 : 10022 : bool result = false;
4127 : :
4128 [ + + + + : 10022 : switch (s->blockState)
+ + - -
- ]
4129 : : {
4130 : : /*
4131 : : * We are in a transaction block, so tell CommitTransactionCommand
4132 : : * to COMMIT.
4133 : : */
8249 bruce@momjian.us 4134 : 8989 : case TBLOCK_INPROGRESS:
8136 tgl@sss.pgh.pa.us 4135 : 8989 : s->blockState = TBLOCK_END;
4136 : 8989 : result = true;
8162 4137 : 8989 : break;
4138 : :
4139 : : /*
4140 : : * We are in an implicit transaction block. If AND CHAIN was
4141 : : * specified, error. Otherwise commit, but issue a warning
4142 : : * because there was no explicit BEGIN before this.
4143 : : */
3346 4144 : 32 : case TBLOCK_IMPLICIT_INPROGRESS:
2615 peter@eisentraut.org 4145 [ + + ]: 32 : if (chain)
4146 [ + - ]: 16 : ereport(ERROR,
4147 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4148 : : /* translator: %s represents an SQL statement name */
4149 : : errmsg("%s can only be used in transaction blocks",
4150 : : "COMMIT AND CHAIN")));
4151 : : else
4152 [ + - ]: 16 : ereport(WARNING,
4153 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4154 : : errmsg("there is no transaction in progress")));
3346 tgl@sss.pgh.pa.us 4155 : 16 : s->blockState = TBLOCK_END;
4156 : 16 : result = true;
4157 : 16 : break;
4158 : :
4159 : : /*
4160 : : * We are in a failed transaction block. Tell
4161 : : * CommitTransactionCommand it's time to exit the block.
4162 : : */
8249 bruce@momjian.us 4163 : 443 : case TBLOCK_ABORT:
8085 tgl@sss.pgh.pa.us 4164 : 443 : s->blockState = TBLOCK_ABORT_END;
8249 bruce@momjian.us 4165 : 443 : break;
4166 : :
4167 : : /*
4168 : : * We are in a live subtransaction block. Set up to subcommit all
4169 : : * open subtransactions and then commit the main transaction.
4170 : : */
8091 tgl@sss.pgh.pa.us 4171 : 504 : case TBLOCK_SUBINPROGRESS:
4172 [ + + ]: 1101 : while (s->parent != NULL)
4173 : : {
8085 4174 [ + - ]: 597 : if (s->blockState == TBLOCK_SUBINPROGRESS)
5588 simon@2ndQuadrant.co 4175 : 597 : s->blockState = TBLOCK_SUBCOMMIT;
4176 : : else
8085 tgl@sss.pgh.pa.us 4177 [ # # ]:UBC 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4178 : : BlockStateAsString(s->blockState));
8091 tgl@sss.pgh.pa.us 4179 :CBC 597 : s = s->parent;
4180 : : }
8085 4181 [ + - ]: 504 : if (s->blockState == TBLOCK_INPROGRESS)
4182 : 504 : s->blockState = TBLOCK_END;
4183 : : else
8085 tgl@sss.pgh.pa.us 4184 [ # # ]:UBC 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4185 : : BlockStateAsString(s->blockState));
8091 tgl@sss.pgh.pa.us 4186 :CBC 504 : result = true;
4187 : 504 : break;
4188 : :
4189 : : /*
4190 : : * Here we are inside an aborted subtransaction. Treat the COMMIT
4191 : : * as ROLLBACK: set up to abort everything and exit the main
4192 : : * transaction.
4193 : : */
8162 4194 : 38 : case TBLOCK_SUBABORT:
8085 4195 [ + + ]: 76 : while (s->parent != NULL)
4196 : : {
4197 [ - + ]: 38 : if (s->blockState == TBLOCK_SUBINPROGRESS)
8085 tgl@sss.pgh.pa.us 4198 :UBC 0 : s->blockState = TBLOCK_SUBABORT_PENDING;
8085 tgl@sss.pgh.pa.us 4199 [ + - ]:CBC 38 : else if (s->blockState == TBLOCK_SUBABORT)
4200 : 38 : s->blockState = TBLOCK_SUBABORT_END;
4201 : : else
8085 tgl@sss.pgh.pa.us 4202 [ # # ]:UBC 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4203 : : BlockStateAsString(s->blockState));
8085 tgl@sss.pgh.pa.us 4204 :CBC 38 : s = s->parent;
4205 : : }
4206 [ + - ]: 38 : if (s->blockState == TBLOCK_INPROGRESS)
4207 : 38 : s->blockState = TBLOCK_ABORT_PENDING;
8085 tgl@sss.pgh.pa.us 4208 [ # # ]:UBC 0 : else if (s->blockState == TBLOCK_ABORT)
4209 : 0 : s->blockState = TBLOCK_ABORT_END;
4210 : : else
4211 [ # # ]: 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4212 : : BlockStateAsString(s->blockState));
8162 tgl@sss.pgh.pa.us 4213 :CBC 38 : break;
4214 : :
4215 : : /*
4216 : : * The user issued COMMIT when not inside a transaction. For
4217 : : * COMMIT without CHAIN, issue a WARNING, staying in
4218 : : * TBLOCK_STARTED state. The upcoming call to
4219 : : * CommitTransactionCommand() will then close the transaction and
4220 : : * put us back into the default state. For COMMIT AND CHAIN,
4221 : : * error.
4222 : : */
8085 4223 : 16 : case TBLOCK_STARTED:
2615 peter@eisentraut.org 4224 [ + + ]: 16 : if (chain)
4225 [ + - ]: 4 : ereport(ERROR,
4226 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4227 : : /* translator: %s represents an SQL statement name */
4228 : : errmsg("%s can only be used in transaction blocks",
4229 : : "COMMIT AND CHAIN")));
4230 : : else
4231 [ + - ]: 12 : ereport(WARNING,
4232 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4233 : : errmsg("there is no transaction in progress")));
8041 tgl@sss.pgh.pa.us 4234 : 12 : result = true;
8249 bruce@momjian.us 4235 : 12 : break;
4236 : :
4237 : : /*
4238 : : * The user issued a COMMIT that somehow ran inside a parallel
4239 : : * worker. We can't cope with that.
4240 : : */
4207 rhaas@postgresql.org 4241 :UBC 0 : case TBLOCK_PARALLEL_INPROGRESS:
4242 [ # # ]: 0 : ereport(FATAL,
4243 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4244 : : errmsg("cannot commit during a parallel operation")));
4245 : : break;
4246 : :
4247 : : /* These cases are invalid. */
8249 bruce@momjian.us 4248 : 0 : case TBLOCK_DEFAULT:
4249 : : case TBLOCK_BEGIN:
4250 : : case TBLOCK_SUBBEGIN:
4251 : : case TBLOCK_END:
4252 : : case TBLOCK_SUBRELEASE:
4253 : : case TBLOCK_SUBCOMMIT:
4254 : : case TBLOCK_ABORT_END:
4255 : : case TBLOCK_SUBABORT_END:
4256 : : case TBLOCK_ABORT_PENDING:
4257 : : case TBLOCK_SUBABORT_PENDING:
4258 : : case TBLOCK_SUBRESTART:
4259 : : case TBLOCK_SUBABORT_RESTART:
4260 : : case TBLOCK_PREPARE:
8162 tgl@sss.pgh.pa.us 4261 [ # # ]: 0 : elog(FATAL, "EndTransactionBlock: unexpected state %s",
4262 : : BlockStateAsString(s->blockState));
4263 : : break;
4264 : : }
4265 : :
2783 peter@eisentraut.org 4266 [ + + + + :CBC 10002 : Assert(s->blockState == TBLOCK_STARTED ||
+ + - + ]
4267 : : s->blockState == TBLOCK_END ||
4268 : : s->blockState == TBLOCK_ABORT_END ||
4269 : : s->blockState == TBLOCK_ABORT_PENDING);
4270 : :
4271 : 10002 : s->chain = chain;
4272 : :
8136 tgl@sss.pgh.pa.us 4273 : 10002 : return result;
4274 : : }
4275 : :
4276 : : /*
4277 : : * UserAbortTransactionBlock
4278 : : * This executes a ROLLBACK command.
4279 : : *
4280 : : * As above, we don't actually do anything here except change blockState.
4281 : : */
4282 : : void
2783 peter@eisentraut.org 4283 : 2290 : UserAbortTransactionBlock(bool chain)
4284 : : {
10651 bruce@momjian.us 4285 : 2290 : TransactionState s = CurrentTransactionState;
4286 : :
8136 tgl@sss.pgh.pa.us 4287 [ + + + + : 2290 : switch (s->blockState)
- - - ]
4288 : : {
4289 : : /*
4290 : : * We are inside a transaction block and we got a ROLLBACK command
4291 : : * from the user, so tell CommitTransactionCommand to abort and
4292 : : * exit the transaction block.
4293 : : */
8085 4294 : 1712 : case TBLOCK_INPROGRESS:
4295 : 1712 : s->blockState = TBLOCK_ABORT_PENDING;
8162 4296 : 1712 : break;
4297 : :
4298 : : /*
4299 : : * We are inside a failed transaction block and we got a ROLLBACK
4300 : : * command from the user. Abort processing is already done, so
4301 : : * CommitTransactionCommand just has to cleanup and go back to
4302 : : * idle state.
4303 : : */
8085 4304 : 440 : case TBLOCK_ABORT:
4305 : 440 : s->blockState = TBLOCK_ABORT_END;
8162 4306 : 440 : break;
4307 : :
4308 : : /*
4309 : : * We are inside a subtransaction. Mark everything up to top
4310 : : * level as exitable.
4311 : : */
4312 : 87 : case TBLOCK_SUBINPROGRESS:
4313 : : case TBLOCK_SUBABORT:
8085 4314 [ + + ]: 338 : while (s->parent != NULL)
4315 : : {
4316 [ + + ]: 251 : if (s->blockState == TBLOCK_SUBINPROGRESS)
4317 : 238 : s->blockState = TBLOCK_SUBABORT_PENDING;
4318 [ + - ]: 13 : else if (s->blockState == TBLOCK_SUBABORT)
4319 : 13 : s->blockState = TBLOCK_SUBABORT_END;
4320 : : else
8085 tgl@sss.pgh.pa.us 4321 [ # # ]:UBC 0 : elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
4322 : : BlockStateAsString(s->blockState));
8085 tgl@sss.pgh.pa.us 4323 :CBC 251 : s = s->parent;
4324 : : }
4325 [ + - ]: 87 : if (s->blockState == TBLOCK_INPROGRESS)
4326 : 87 : s->blockState = TBLOCK_ABORT_PENDING;
8085 tgl@sss.pgh.pa.us 4327 [ # # ]:UBC 0 : else if (s->blockState == TBLOCK_ABORT)
4328 : 0 : s->blockState = TBLOCK_ABORT_END;
4329 : : else
4330 [ # # ]: 0 : elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
4331 : : BlockStateAsString(s->blockState));
8162 tgl@sss.pgh.pa.us 4332 :CBC 87 : break;
4333 : :
4334 : : /*
4335 : : * The user issued ABORT when not inside a transaction. For
4336 : : * ROLLBACK without CHAIN, issue a WARNING and go to abort state.
4337 : : * The upcoming call to CommitTransactionCommand() will then put
4338 : : * us back into the default state. For ROLLBACK AND CHAIN, error.
4339 : : *
4340 : : * We do the same thing with ABORT inside an implicit transaction,
4341 : : * although in this case we might be rolling back actual database
4342 : : * state changes. (It's debatable whether we should issue a
4343 : : * WARNING in this case, but we have done so historically.)
4344 : : */
4345 : 51 : case TBLOCK_STARTED:
4346 : : case TBLOCK_IMPLICIT_INPROGRESS:
2615 peter@eisentraut.org 4347 [ + + ]: 51 : if (chain)
4348 [ + - ]: 20 : ereport(ERROR,
4349 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4350 : : /* translator: %s represents an SQL statement name */
4351 : : errmsg("%s can only be used in transaction blocks",
4352 : : "ROLLBACK AND CHAIN")));
4353 : : else
4354 [ + - ]: 31 : ereport(WARNING,
4355 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4356 : : errmsg("there is no transaction in progress")));
8085 tgl@sss.pgh.pa.us 4357 : 31 : s->blockState = TBLOCK_ABORT_PENDING;
8162 4358 : 31 : break;
4359 : :
4360 : : /*
4361 : : * The user issued an ABORT that somehow ran inside a parallel
4362 : : * worker. We can't cope with that.
4363 : : */
4207 rhaas@postgresql.org 4364 :UBC 0 : case TBLOCK_PARALLEL_INPROGRESS:
4365 [ # # ]: 0 : ereport(FATAL,
4366 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4367 : : errmsg("cannot abort during a parallel operation")));
4368 : : break;
4369 : :
4370 : : /* These cases are invalid. */
8162 tgl@sss.pgh.pa.us 4371 : 0 : case TBLOCK_DEFAULT:
4372 : : case TBLOCK_BEGIN:
4373 : : case TBLOCK_SUBBEGIN:
4374 : : case TBLOCK_END:
4375 : : case TBLOCK_SUBRELEASE:
4376 : : case TBLOCK_SUBCOMMIT:
4377 : : case TBLOCK_ABORT_END:
4378 : : case TBLOCK_SUBABORT_END:
4379 : : case TBLOCK_ABORT_PENDING:
4380 : : case TBLOCK_SUBABORT_PENDING:
4381 : : case TBLOCK_SUBRESTART:
4382 : : case TBLOCK_SUBABORT_RESTART:
4383 : : case TBLOCK_PREPARE:
4384 [ # # ]: 0 : elog(FATAL, "UserAbortTransactionBlock: unexpected state %s",
4385 : : BlockStateAsString(s->blockState));
4386 : : break;
4387 : : }
4388 : :
2783 peter@eisentraut.org 4389 [ + + - + ]:CBC 2270 : Assert(s->blockState == TBLOCK_ABORT_END ||
4390 : : s->blockState == TBLOCK_ABORT_PENDING);
4391 : :
4392 : 2270 : s->chain = chain;
8136 tgl@sss.pgh.pa.us 4393 : 2270 : }
4394 : :
4395 : : /*
4396 : : * BeginImplicitTransactionBlock
4397 : : * Start an implicit transaction block if we're not already in one.
4398 : : *
4399 : : * Unlike BeginTransactionBlock, this is called directly from the main loop
4400 : : * in postgres.c, not within a Portal. So we can just change blockState
4401 : : * without a lot of ceremony. We do not expect caller to do
4402 : : * CommitTransactionCommand/StartTransactionCommand.
4403 : : */
4404 : : void
3346 4405 : 47839 : BeginImplicitTransactionBlock(void)
4406 : : {
4407 : 47839 : TransactionState s = CurrentTransactionState;
4408 : :
4409 : : /*
4410 : : * If we are in STARTED state (that is, no transaction block is open),
4411 : : * switch to IMPLICIT_INPROGRESS state, creating an implicit transaction
4412 : : * block.
4413 : : *
4414 : : * For caller convenience, we consider all other transaction states as
4415 : : * legal here; otherwise the caller would need its own state check, which
4416 : : * seems rather pointless.
4417 : : */
4418 [ + + ]: 47839 : if (s->blockState == TBLOCK_STARTED)
4419 : 6221 : s->blockState = TBLOCK_IMPLICIT_INPROGRESS;
4420 : 47839 : }
4421 : :
4422 : : /*
4423 : : * EndImplicitTransactionBlock
4424 : : * End an implicit transaction block, if we're in one.
4425 : : *
4426 : : * Like EndTransactionBlock, we just make any needed blockState change here.
4427 : : * The real work will be done in the upcoming CommitTransactionCommand().
4428 : : */
4429 : : void
4430 : 19588 : EndImplicitTransactionBlock(void)
4431 : : {
4432 : 19588 : TransactionState s = CurrentTransactionState;
4433 : :
4434 : : /*
4435 : : * If we are in IMPLICIT_INPROGRESS state, switch back to STARTED state,
4436 : : * allowing CommitTransactionCommand to commit whatever happened during
4437 : : * the implicit transaction block as though it were a single statement.
4438 : : *
4439 : : * For caller convenience, we consider all other transaction states as
4440 : : * legal here; otherwise the caller would need its own state check, which
4441 : : * seems rather pointless.
4442 : : */
4443 [ + + ]: 19588 : if (s->blockState == TBLOCK_IMPLICIT_INPROGRESS)
4444 : 5597 : s->blockState = TBLOCK_STARTED;
4445 : 19588 : }
4446 : :
4447 : : /*
4448 : : * DefineSavepoint
4449 : : * This executes a SAVEPOINT command.
4450 : : */
4451 : : void
3292 peter_e@gmx.net 4452 : 1732 : DefineSavepoint(const char *name)
4453 : : {
8103 bruce@momjian.us 4454 : 1732 : TransactionState s = CurrentTransactionState;
4455 : :
4456 : : /*
4457 : : * Workers synchronize transaction state at the beginning of each parallel
4458 : : * operation, so we can't account for new subtransactions after that
4459 : : * point. (Note that this check will certainly error out if s->blockState
4460 : : * is TBLOCK_PARALLEL_INPROGRESS, so we can treat that as an invalid case
4461 : : * below.)
4462 : : */
952 tgl@sss.pgh.pa.us 4463 [ + - - + ]: 1732 : if (IsInParallelMode() || IsParallelWorker())
4207 rhaas@postgresql.org 4464 [ # # ]:UBC 0 : ereport(ERROR,
4465 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4466 : : errmsg("cannot define savepoints during a parallel operation")));
4467 : :
8136 tgl@sss.pgh.pa.us 4468 [ + + - - ]:CBC 1732 : switch (s->blockState)
4469 : : {
4470 : 1724 : case TBLOCK_INPROGRESS:
4471 : : case TBLOCK_SUBINPROGRESS:
4472 : : /* Normal subtransaction start */
4473 : 1724 : PushTransaction();
3424 4474 : 1724 : s = CurrentTransactionState; /* changed by push */
4475 : :
4476 : : /*
4477 : : * Savepoint names, like the TransactionState block itself, live
4478 : : * in TopTransactionContext.
4479 : : */
8085 4480 [ + + ]: 1724 : if (name)
4481 : 1195 : s->name = MemoryContextStrdup(TopTransactionContext, name);
8136 4482 : 1724 : break;
4483 : :
4484 : : /*
4485 : : * We disallow savepoint commands in implicit transaction blocks.
4486 : : * There would be no great difficulty in allowing them so far as
4487 : : * this module is concerned, but a savepoint seems inconsistent
4488 : : * with exec_simple_query's behavior of abandoning the whole query
4489 : : * string upon error. Also, the point of an implicit transaction
4490 : : * block (as opposed to a regular one) is to automatically close
4491 : : * after an error, so it's hard to see how a savepoint would fit
4492 : : * into that.
4493 : : *
4494 : : * The error messages for this are phrased as if there were no
4495 : : * active transaction block at all, which is historical but
4496 : : * perhaps could be improved.
4497 : : */
3346 4498 : 8 : case TBLOCK_IMPLICIT_INPROGRESS:
4499 [ + - ]: 8 : ereport(ERROR,
4500 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4501 : : /* translator: %s represents an SQL statement name */
4502 : : errmsg("%s can only be used in transaction blocks",
4503 : : "SAVEPOINT")));
4504 : : break;
4505 : :
4506 : : /* These cases are invalid. */
8136 tgl@sss.pgh.pa.us 4507 :UBC 0 : case TBLOCK_DEFAULT:
4508 : : case TBLOCK_STARTED:
4509 : : case TBLOCK_BEGIN:
4510 : : case TBLOCK_PARALLEL_INPROGRESS:
4511 : : case TBLOCK_SUBBEGIN:
4512 : : case TBLOCK_END:
4513 : : case TBLOCK_SUBRELEASE:
4514 : : case TBLOCK_SUBCOMMIT:
4515 : : case TBLOCK_ABORT:
4516 : : case TBLOCK_SUBABORT:
4517 : : case TBLOCK_ABORT_END:
4518 : : case TBLOCK_SUBABORT_END:
4519 : : case TBLOCK_ABORT_PENDING:
4520 : : case TBLOCK_SUBABORT_PENDING:
4521 : : case TBLOCK_SUBRESTART:
4522 : : case TBLOCK_SUBABORT_RESTART:
4523 : : case TBLOCK_PREPARE:
8132 4524 [ # # ]: 0 : elog(FATAL, "DefineSavepoint: unexpected state %s",
4525 : : BlockStateAsString(s->blockState));
4526 : : break;
4527 : : }
8136 tgl@sss.pgh.pa.us 4528 :CBC 1724 : }
4529 : :
4530 : : /*
4531 : : * ReleaseSavepoint
4532 : : * This executes a RELEASE command.
4533 : : *
4534 : : * As above, we don't actually do anything here except change blockState.
4535 : : */
4536 : : void
3184 peter_e@gmx.net 4537 : 186 : ReleaseSavepoint(const char *name)
4538 : : {
8103 bruce@momjian.us 4539 : 186 : TransactionState s = CurrentTransactionState;
4540 : : TransactionState target,
4541 : : xact;
4542 : :
4543 : : /*
4544 : : * Workers synchronize transaction state at the beginning of each parallel
4545 : : * operation, so we can't account for transaction state change after that
4546 : : * point. (Note that this check will certainly error out if s->blockState
4547 : : * is TBLOCK_PARALLEL_INPROGRESS, so we can treat that as an invalid case
4548 : : * below.)
4549 : : */
952 tgl@sss.pgh.pa.us 4550 [ + - - + ]: 186 : if (IsInParallelMode() || IsParallelWorker())
4207 rhaas@postgresql.org 4551 [ # # ]:UBC 0 : ereport(ERROR,
4552 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4553 : : errmsg("cannot release savepoints during a parallel operation")));
4554 : :
8136 tgl@sss.pgh.pa.us 4555 [ - + + - :CBC 186 : switch (s->blockState)
- ]
4556 : : {
4557 : : /*
4558 : : * We can't release a savepoint if there is no savepoint defined.
4559 : : */
8136 tgl@sss.pgh.pa.us 4560 :UBC 0 : case TBLOCK_INPROGRESS:
4561 [ # # ]: 0 : ereport(ERROR,
4562 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4563 : : errmsg("savepoint \"%s\" does not exist", name)));
4564 : : break;
4565 : :
3346 tgl@sss.pgh.pa.us 4566 :CBC 4 : case TBLOCK_IMPLICIT_INPROGRESS:
4567 : : /* See comment about implicit transactions in DefineSavepoint */
4568 [ + - ]: 4 : ereport(ERROR,
4569 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4570 : : /* translator: %s represents an SQL statement name */
4571 : : errmsg("%s can only be used in transaction blocks",
4572 : : "RELEASE SAVEPOINT")));
4573 : : break;
4574 : :
4575 : : /*
4576 : : * We are in a non-aborted subtransaction. This is the only valid
4577 : : * case.
4578 : : */
8136 4579 : 182 : case TBLOCK_SUBINPROGRESS:
4580 : 182 : break;
4581 : :
4582 : : /* These cases are invalid. */
8136 tgl@sss.pgh.pa.us 4583 :UBC 0 : case TBLOCK_DEFAULT:
4584 : : case TBLOCK_STARTED:
4585 : : case TBLOCK_BEGIN:
4586 : : case TBLOCK_PARALLEL_INPROGRESS:
4587 : : case TBLOCK_SUBBEGIN:
4588 : : case TBLOCK_END:
4589 : : case TBLOCK_SUBRELEASE:
4590 : : case TBLOCK_SUBCOMMIT:
4591 : : case TBLOCK_ABORT:
4592 : : case TBLOCK_SUBABORT:
4593 : : case TBLOCK_ABORT_END:
4594 : : case TBLOCK_SUBABORT_END:
4595 : : case TBLOCK_ABORT_PENDING:
4596 : : case TBLOCK_SUBABORT_PENDING:
4597 : : case TBLOCK_SUBRESTART:
4598 : : case TBLOCK_SUBABORT_RESTART:
4599 : : case TBLOCK_PREPARE:
4600 [ # # ]: 0 : elog(FATAL, "ReleaseSavepoint: unexpected state %s",
4601 : : BlockStateAsString(s->blockState));
4602 : : break;
4603 : : }
4604 : :
407 peter@eisentraut.org 4605 [ + - ]:CBC 269 : for (target = s; target; target = target->parent)
4606 : : {
4607 [ + - + + ]: 269 : if (target->name && strcmp(target->name, name) == 0)
8136 tgl@sss.pgh.pa.us 4608 : 182 : break;
4609 : : }
4610 : :
407 peter@eisentraut.org 4611 [ - + ]: 182 : if (!target)
8136 tgl@sss.pgh.pa.us 4612 [ # # ]:UBC 0 : ereport(ERROR,
4613 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4614 : : errmsg("savepoint \"%s\" does not exist", name)));
4615 : :
4616 : : /* disallow crossing savepoint level boundaries */
8107 tgl@sss.pgh.pa.us 4617 [ - + ]:CBC 182 : if (target->savepointLevel != s->savepointLevel)
8107 tgl@sss.pgh.pa.us 4618 [ # # ]:UBC 0 : ereport(ERROR,
4619 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4620 : : errmsg("savepoint \"%s\" does not exist within current savepoint level", name)));
4621 : :
4622 : : /*
4623 : : * Mark "commit pending" all subtransactions up to the target
4624 : : * subtransaction. The actual commits will happen when control gets to
4625 : : * CommitTransactionCommand.
4626 : : */
8107 tgl@sss.pgh.pa.us 4627 :CBC 182 : xact = CurrentTransactionState;
4628 : : for (;;)
4629 : : {
4630 [ - + ]: 269 : Assert(xact->blockState == TBLOCK_SUBINPROGRESS);
5588 simon@2ndQuadrant.co 4631 : 269 : xact->blockState = TBLOCK_SUBRELEASE;
8107 tgl@sss.pgh.pa.us 4632 [ + + ]: 269 : if (xact == target)
4633 : 182 : break;
4634 : 87 : xact = xact->parent;
407 peter@eisentraut.org 4635 [ - + ]: 87 : Assert(xact);
4636 : : }
8136 tgl@sss.pgh.pa.us 4637 : 182 : }
4638 : :
4639 : : /*
4640 : : * RollbackToSavepoint
4641 : : * This executes a ROLLBACK TO <savepoint> command.
4642 : : *
4643 : : * As above, we don't actually do anything here except change blockState.
4644 : : */
4645 : : void
3184 peter_e@gmx.net 4646 : 537 : RollbackToSavepoint(const char *name)
4647 : : {
8136 tgl@sss.pgh.pa.us 4648 : 537 : TransactionState s = CurrentTransactionState;
4649 : : TransactionState target,
4650 : : xact;
4651 : :
4652 : : /*
4653 : : * Workers synchronize transaction state at the beginning of each parallel
4654 : : * operation, so we can't account for transaction state change after that
4655 : : * point. (Note that this check will certainly error out if s->blockState
4656 : : * is TBLOCK_PARALLEL_INPROGRESS, so we can treat that as an invalid case
4657 : : * below.)
4658 : : */
952 4659 [ + - - + ]: 537 : if (IsInParallelMode() || IsParallelWorker())
4207 rhaas@postgresql.org 4660 [ # # ]:UBC 0 : ereport(ERROR,
4661 : : (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
4662 : : errmsg("cannot rollback to savepoints during a parallel operation")));
4663 : :
8136 tgl@sss.pgh.pa.us 4664 [ + + + - :CBC 537 : switch (s->blockState)
- ]
4665 : : {
4666 : : /*
4667 : : * We can't rollback to a savepoint if there is no savepoint
4668 : : * defined.
4669 : : */
4670 : 4 : case TBLOCK_INPROGRESS:
4671 : : case TBLOCK_ABORT:
4672 [ + - ]: 4 : ereport(ERROR,
4673 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4674 : : errmsg("savepoint \"%s\" does not exist", name)));
4675 : : break;
4676 : :
3346 4677 : 4 : case TBLOCK_IMPLICIT_INPROGRESS:
4678 : : /* See comment about implicit transactions in DefineSavepoint */
4679 [ + - ]: 4 : ereport(ERROR,
4680 : : (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
4681 : : /* translator: %s represents an SQL statement name */
4682 : : errmsg("%s can only be used in transaction blocks",
4683 : : "ROLLBACK TO SAVEPOINT")));
4684 : : break;
4685 : :
4686 : : /*
4687 : : * There is at least one savepoint, so proceed.
4688 : : */
8136 4689 : 529 : case TBLOCK_SUBINPROGRESS:
4690 : : case TBLOCK_SUBABORT:
4691 : 529 : break;
4692 : :
4693 : : /* These cases are invalid. */
8136 tgl@sss.pgh.pa.us 4694 :UBC 0 : case TBLOCK_DEFAULT:
4695 : : case TBLOCK_STARTED:
4696 : : case TBLOCK_BEGIN:
4697 : : case TBLOCK_PARALLEL_INPROGRESS:
4698 : : case TBLOCK_SUBBEGIN:
4699 : : case TBLOCK_END:
4700 : : case TBLOCK_SUBRELEASE:
4701 : : case TBLOCK_SUBCOMMIT:
4702 : : case TBLOCK_ABORT_END:
4703 : : case TBLOCK_SUBABORT_END:
4704 : : case TBLOCK_ABORT_PENDING:
4705 : : case TBLOCK_SUBABORT_PENDING:
4706 : : case TBLOCK_SUBRESTART:
4707 : : case TBLOCK_SUBABORT_RESTART:
4708 : : case TBLOCK_PREPARE:
4709 [ # # ]: 0 : elog(FATAL, "RollbackToSavepoint: unexpected state %s",
4710 : : BlockStateAsString(s->blockState));
4711 : : break;
4712 : : }
4713 : :
407 peter@eisentraut.org 4714 [ + - ]:CBC 567 : for (target = s; target; target = target->parent)
4715 : : {
4716 [ + - + + ]: 567 : if (target->name && strcmp(target->name, name) == 0)
8136 tgl@sss.pgh.pa.us 4717 : 529 : break;
4718 : : }
4719 : :
407 peter@eisentraut.org 4720 [ - + ]: 529 : if (!target)
8136 tgl@sss.pgh.pa.us 4721 [ # # ]:UBC 0 : ereport(ERROR,
4722 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4723 : : errmsg("savepoint \"%s\" does not exist", name)));
4724 : :
4725 : : /* disallow crossing savepoint level boundaries */
8129 tgl@sss.pgh.pa.us 4726 [ - + ]:CBC 529 : if (target->savepointLevel != s->savepointLevel)
8129 tgl@sss.pgh.pa.us 4727 [ # # ]:UBC 0 : ereport(ERROR,
4728 : : (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
4729 : : errmsg("savepoint \"%s\" does not exist within current savepoint level", name)));
4730 : :
4731 : : /*
4732 : : * Mark "abort pending" all subtransactions up to the target
4733 : : * subtransaction. The actual aborts will happen when control gets to
4734 : : * CommitTransactionCommand.
4735 : : */
8136 tgl@sss.pgh.pa.us 4736 :CBC 529 : xact = CurrentTransactionState;
4737 : : for (;;)
4738 : : {
8085 4739 [ + + ]: 567 : if (xact == target)
4740 : 529 : break;
4741 [ + - ]: 38 : if (xact->blockState == TBLOCK_SUBINPROGRESS)
4742 : 38 : xact->blockState = TBLOCK_SUBABORT_PENDING;
8085 tgl@sss.pgh.pa.us 4743 [ # # ]:UBC 0 : else if (xact->blockState == TBLOCK_SUBABORT)
4744 : 0 : xact->blockState = TBLOCK_SUBABORT_END;
4745 : : else
4746 [ # # ]: 0 : elog(FATAL, "RollbackToSavepoint: unexpected state %s",
4747 : : BlockStateAsString(xact->blockState));
8136 tgl@sss.pgh.pa.us 4748 :CBC 38 : xact = xact->parent;
407 peter@eisentraut.org 4749 [ - + ]: 38 : Assert(xact);
4750 : : }
4751 : :
4752 : : /* And mark the target as "restart pending" */
8085 tgl@sss.pgh.pa.us 4753 [ + + ]: 529 : if (xact->blockState == TBLOCK_SUBINPROGRESS)
4754 : 344 : xact->blockState = TBLOCK_SUBRESTART;
4755 [ + - ]: 185 : else if (xact->blockState == TBLOCK_SUBABORT)
4756 : 185 : xact->blockState = TBLOCK_SUBABORT_RESTART;
4757 : : else
8085 tgl@sss.pgh.pa.us 4758 [ # # ]:UBC 0 : elog(FATAL, "RollbackToSavepoint: unexpected state %s",
4759 : : BlockStateAsString(xact->blockState));
8136 tgl@sss.pgh.pa.us 4760 :CBC 529 : }
4761 : :
4762 : : /*
4763 : : * BeginInternalSubTransaction
4764 : : * This is the same as DefineSavepoint except it allows TBLOCK_STARTED,
4765 : : * TBLOCK_IMPLICIT_INPROGRESS, TBLOCK_PARALLEL_INPROGRESS, TBLOCK_END,
4766 : : * and TBLOCK_PREPARE states, and therefore it can safely be used in
4767 : : * functions that might be called when not inside a BEGIN block or when
4768 : : * running deferred triggers at COMMIT/PREPARE time. Also, it
4769 : : * automatically does CommitTransactionCommand/StartTransactionCommand
4770 : : * instead of expecting the caller to do it.
4771 : : */
4772 : : void
3292 peter_e@gmx.net 4773 : 21275 : BeginInternalSubTransaction(const char *name)
4774 : : {
8103 bruce@momjian.us 4775 : 21275 : TransactionState s = CurrentTransactionState;
952 tgl@sss.pgh.pa.us 4776 : 21275 : bool save_ExitOnAnyError = ExitOnAnyError;
4777 : :
4778 : : /*
4779 : : * Errors within this function are improbable, but if one does happen we
4780 : : * force a FATAL exit. Callers generally aren't prepared to handle losing
4781 : : * control, and moreover our transaction state is probably corrupted if we
4782 : : * fail partway through; so an ordinary ERROR longjmp isn't okay.
4783 : : */
4784 : 21275 : ExitOnAnyError = true;
4785 : :
4786 : : /*
4787 : : * We do not check for parallel mode here. It's permissible to start and
4788 : : * end "internal" subtransactions while in parallel mode, so long as no
4789 : : * new XIDs or command IDs are assigned. Enforcement of that occurs in
4790 : : * AssignTransactionId() and CommandCounterIncrement().
4791 : : */
4792 : :
8132 4793 [ + - - ]: 21275 : switch (s->blockState)
4794 : : {
4795 : 21275 : case TBLOCK_STARTED:
4796 : : case TBLOCK_INPROGRESS:
4797 : : case TBLOCK_IMPLICIT_INPROGRESS:
4798 : : case TBLOCK_PARALLEL_INPROGRESS:
4799 : : case TBLOCK_END:
4800 : : case TBLOCK_PREPARE:
4801 : : case TBLOCK_SUBINPROGRESS:
4802 : : /* Normal subtransaction start */
4803 : 21275 : PushTransaction();
3424 4804 : 21275 : s = CurrentTransactionState; /* changed by push */
4805 : :
4806 : : /*
4807 : : * Savepoint names, like the TransactionState block itself, live
4808 : : * in TopTransactionContext.
4809 : : */
8132 4810 [ + + ]: 21275 : if (name)
8085 4811 : 1033 : s->name = MemoryContextStrdup(TopTransactionContext, name);
8132 4812 : 21275 : break;
4813 : :
4814 : : /* These cases are invalid. */
8132 tgl@sss.pgh.pa.us 4815 :UBC 0 : case TBLOCK_DEFAULT:
4816 : : case TBLOCK_BEGIN:
4817 : : case TBLOCK_SUBBEGIN:
4818 : : case TBLOCK_SUBRELEASE:
4819 : : case TBLOCK_SUBCOMMIT:
4820 : : case TBLOCK_ABORT:
4821 : : case TBLOCK_SUBABORT:
4822 : : case TBLOCK_ABORT_END:
4823 : : case TBLOCK_SUBABORT_END:
4824 : : case TBLOCK_ABORT_PENDING:
4825 : : case TBLOCK_SUBABORT_PENDING:
4826 : : case TBLOCK_SUBRESTART:
4827 : : case TBLOCK_SUBABORT_RESTART:
4828 [ # # ]: 0 : elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
4829 : : BlockStateAsString(s->blockState));
4830 : : break;
4831 : : }
4832 : :
8132 tgl@sss.pgh.pa.us 4833 :CBC 21275 : CommitTransactionCommand();
4834 : 21275 : StartTransactionCommand();
4835 : :
952 4836 : 21275 : ExitOnAnyError = save_ExitOnAnyError;
8132 4837 : 21275 : }
4838 : :
4839 : : /*
4840 : : * ReleaseCurrentSubTransaction
4841 : : *
4842 : : * RELEASE (ie, commit) the innermost subtransaction, regardless of its
4843 : : * savepoint name (if any).
4844 : : * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
4845 : : */
4846 : : void
4847 : 16516 : ReleaseCurrentSubTransaction(void)
4848 : : {
4849 : 16516 : TransactionState s = CurrentTransactionState;
4850 : :
4851 : : /*
4852 : : * We do not check for parallel mode here. It's permissible to start and
4853 : : * end "internal" subtransactions while in parallel mode, so long as no
4854 : : * new XIDs or command IDs are assigned.
4855 : : */
4856 : :
4857 [ - + ]: 16516 : if (s->blockState != TBLOCK_SUBINPROGRESS)
8132 tgl@sss.pgh.pa.us 4858 [ # # ]:UBC 0 : elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
4859 : : BlockStateAsString(s->blockState));
8091 tgl@sss.pgh.pa.us 4860 [ - + ]:CBC 16516 : Assert(s->state == TRANS_INPROGRESS);
8132 4861 : 16516 : MemoryContextSwitchTo(CurTransactionContext);
5538 simon@2ndQuadrant.co 4862 : 16516 : CommitSubTransaction();
7691 bruce@momjian.us 4863 : 16516 : s = CurrentTransactionState; /* changed by pop */
8091 tgl@sss.pgh.pa.us 4864 [ - + ]: 16516 : Assert(s->state == TRANS_INPROGRESS);
8132 4865 : 16516 : }
4866 : :
4867 : : /*
4868 : : * RollbackAndReleaseCurrentSubTransaction
4869 : : *
4870 : : * ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
4871 : : * of its savepoint name (if any).
4872 : : * NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
4873 : : */
4874 : : void
4875 : 4759 : RollbackAndReleaseCurrentSubTransaction(void)
4876 : : {
4877 : 4759 : TransactionState s = CurrentTransactionState;
4878 : :
4879 : : /*
4880 : : * We do not check for parallel mode here. It's permissible to start and
4881 : : * end "internal" subtransactions while in parallel mode, so long as no
4882 : : * new XIDs or command IDs are assigned.
4883 : : */
4884 : :
4885 [ + - - ]: 4759 : switch (s->blockState)
4886 : : {
4887 : : /* Must be in a subtransaction */
4888 : 4759 : case TBLOCK_SUBINPROGRESS:
4889 : : case TBLOCK_SUBABORT:
4890 : 4759 : break;
4891 : :
4892 : : /* These cases are invalid. */
8132 tgl@sss.pgh.pa.us 4893 :UBC 0 : case TBLOCK_DEFAULT:
4894 : : case TBLOCK_STARTED:
4895 : : case TBLOCK_BEGIN:
4896 : : case TBLOCK_IMPLICIT_INPROGRESS:
4897 : : case TBLOCK_PARALLEL_INPROGRESS:
4898 : : case TBLOCK_SUBBEGIN:
4899 : : case TBLOCK_INPROGRESS:
4900 : : case TBLOCK_END:
4901 : : case TBLOCK_SUBRELEASE:
4902 : : case TBLOCK_SUBCOMMIT:
4903 : : case TBLOCK_ABORT:
4904 : : case TBLOCK_ABORT_END:
4905 : : case TBLOCK_SUBABORT_END:
4906 : : case TBLOCK_ABORT_PENDING:
4907 : : case TBLOCK_SUBABORT_PENDING:
4908 : : case TBLOCK_SUBRESTART:
4909 : : case TBLOCK_SUBABORT_RESTART:
4910 : : case TBLOCK_PREPARE:
4911 [ # # ]: 0 : elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
4912 : : BlockStateAsString(s->blockState));
4913 : : break;
4914 : : }
4915 : :
4916 : : /*
4917 : : * Abort the current subtransaction, if needed.
4918 : : */
8132 tgl@sss.pgh.pa.us 4919 [ + + ]:CBC 4759 : if (s->blockState == TBLOCK_SUBINPROGRESS)
4920 : 3726 : AbortSubTransaction();
4921 : :
4922 : : /* And clean it up, too */
8085 4923 : 4759 : CleanupSubTransaction();
4924 : :
4925 : 4759 : s = CurrentTransactionState; /* changed by pop */
1469 peter@eisentraut.org 4926 [ + + + + : 4759 : Assert(s->blockState == TBLOCK_SUBINPROGRESS ||
+ - + + +
+ + - -
+ ]
4927 : : s->blockState == TBLOCK_INPROGRESS ||
4928 : : s->blockState == TBLOCK_IMPLICIT_INPROGRESS ||
4929 : : s->blockState == TBLOCK_PARALLEL_INPROGRESS ||
4930 : : s->blockState == TBLOCK_END ||
4931 : : s->blockState == TBLOCK_PREPARE ||
4932 : : s->blockState == TBLOCK_STARTED);
11076 scrappy@hub.org 4933 : 4759 : }
4934 : :
4935 : : /*
4936 : : * AbortOutOfAnyTransaction
4937 : : *
4938 : : * This routine is provided for error recovery purposes. It aborts any
4939 : : * active transaction or transaction block, leaving the system in a known
4940 : : * idle state.
4941 : : */
4942 : : void
9508 tgl@sss.pgh.pa.us 4943 : 20088 : AbortOutOfAnyTransaction(void)
4944 : : {
10257 4945 : 20088 : TransactionState s = CurrentTransactionState;
4946 : :
4947 : : /* Ensure we're not running in a doomed memory context */
3370 4948 : 20088 : AtAbort_Memory();
4949 : :
4950 : : /*
4951 : : * Get out of any transaction or nested transaction
4952 : : */
4953 : : do
4954 : : {
8162 4955 [ + + + + : 20090 : switch (s->blockState)
- - ]
4956 : : {
4957 : 19433 : case TBLOCK_DEFAULT:
5274 4958 [ - + ]: 19433 : if (s->state == TRANS_DEFAULT)
4959 : : {
4960 : : /* Not in a transaction, do nothing */
4961 : : }
4962 : : else
4963 : : {
4964 : : /*
4965 : : * We can get here after an error during transaction start
4966 : : * (state will be TRANS_START). Need to clean up the
4967 : : * incompletely started transaction. First, adjust the
4968 : : * low-level state to suppress warning message from
4969 : : * AbortTransaction.
4970 : : */
5274 tgl@sss.pgh.pa.us 4971 [ # # ]:UBC 0 : if (s->state == TRANS_START)
4972 : 0 : s->state = TRANS_INPROGRESS;
4973 : 0 : AbortTransaction();
4974 : 0 : CleanupTransaction();
4975 : : }
8162 tgl@sss.pgh.pa.us 4976 :CBC 19433 : break;
4977 : 638 : case TBLOCK_STARTED:
4978 : : case TBLOCK_BEGIN:
4979 : : case TBLOCK_INPROGRESS:
4980 : : case TBLOCK_IMPLICIT_INPROGRESS:
4981 : : case TBLOCK_PARALLEL_INPROGRESS:
4982 : : case TBLOCK_END:
4983 : : case TBLOCK_ABORT_PENDING:
4984 : : case TBLOCK_PREPARE:
4985 : : /* In a transaction, so clean up */
4986 : 638 : AbortTransaction();
4987 : 638 : CleanupTransaction();
4988 : 638 : s->blockState = TBLOCK_DEFAULT;
4989 : 638 : break;
4990 : 17 : case TBLOCK_ABORT:
4991 : : case TBLOCK_ABORT_END:
4992 : :
4993 : : /*
4994 : : * AbortTransaction is already done, still need Cleanup.
4995 : : * However, if we failed partway through running ROLLBACK,
4996 : : * there will be an active portal running that command, which
4997 : : * we need to shut down before doing CleanupTransaction.
4998 : : */
3370 4999 : 17 : AtAbort_Portals();
8162 5000 : 17 : CleanupTransaction();
5001 : 17 : s->blockState = TBLOCK_DEFAULT;
5002 : 17 : break;
5003 : :
5004 : : /*
5005 : : * In a subtransaction, so clean it up and abort parent too
5006 : : */
8085 5007 : 2 : case TBLOCK_SUBBEGIN:
5008 : : case TBLOCK_SUBINPROGRESS:
5009 : : case TBLOCK_SUBRELEASE:
5010 : : case TBLOCK_SUBCOMMIT:
5011 : : case TBLOCK_SUBABORT_PENDING:
5012 : : case TBLOCK_SUBRESTART:
8162 5013 : 2 : AbortSubTransaction();
5014 : 2 : CleanupSubTransaction();
8103 bruce@momjian.us 5015 : 2 : s = CurrentTransactionState; /* changed by pop */
8162 tgl@sss.pgh.pa.us 5016 : 2 : break;
5017 : :
8162 tgl@sss.pgh.pa.us 5018 :UBC 0 : case TBLOCK_SUBABORT:
5019 : : case TBLOCK_SUBABORT_END:
5020 : : case TBLOCK_SUBABORT_RESTART:
5021 : : /* As above, but AbortSubTransaction already done */
3370 5022 [ # # ]: 0 : if (s->curTransactionOwner)
5023 : : {
5024 : : /* As in TBLOCK_ABORT, might have a live portal to zap */
5025 : 0 : AtSubAbort_Portals(s->subTransactionId,
5026 : 0 : s->parent->subTransactionId,
5027 : : s->curTransactionOwner,
5028 : 0 : s->parent->curTransactionOwner);
5029 : : }
8162 5030 : 0 : CleanupSubTransaction();
8103 bruce@momjian.us 5031 : 0 : s = CurrentTransactionState; /* changed by pop */
8162 tgl@sss.pgh.pa.us 5032 : 0 : break;
5033 : : }
8162 tgl@sss.pgh.pa.us 5034 [ + + ]:CBC 20090 : } while (s->blockState != TBLOCK_DEFAULT);
5035 : :
5036 : : /* Should be out of all subxacts now */
5037 [ - + ]: 20088 : Assert(s->parent == NULL);
5038 : :
5039 : : /*
5040 : : * Revert to TopMemoryContext, to ensure we exit in a well-defined state
5041 : : * whether there were any transactions to close or not. (Callers that
5042 : : * don't intend to exit soon should switch to some other context to avoid
5043 : : * long-term memory leaks.)
5044 : : */
857 5045 : 20088 : MemoryContextSwitchTo(TopMemoryContext);
10257 5046 : 20088 : }
5047 : :
5048 : : /*
5049 : : * IsTransactionBlock --- are we within a transaction block?
5050 : : */
5051 : : bool
9508 5052 : 243184 : IsTransactionBlock(void)
5053 : : {
10651 bruce@momjian.us 5054 : 243184 : TransactionState s = CurrentTransactionState;
5055 : :
8249 5056 [ + + + + ]: 243184 : if (s->blockState == TBLOCK_DEFAULT || s->blockState == TBLOCK_STARTED)
8594 tgl@sss.pgh.pa.us 5057 : 173446 : return false;
5058 : :
5059 : 69738 : return true;
5060 : : }
5061 : :
5062 : : /*
5063 : : * IsTransactionOrTransactionBlock --- are we within either a transaction
5064 : : * or a transaction block? (The backend is only really "idle" when this
5065 : : * returns false.)
5066 : : *
5067 : : * This should match up with IsTransactionBlock and IsTransactionState.
5068 : : */
5069 : : bool
8421 5070 : 848745 : IsTransactionOrTransactionBlock(void)
5071 : : {
5072 : 848745 : TransactionState s = CurrentTransactionState;
5073 : :
8249 bruce@momjian.us 5074 [ + + ]: 848745 : if (s->blockState == TBLOCK_DEFAULT)
8421 tgl@sss.pgh.pa.us 5075 : 756908 : return false;
5076 : :
5077 : 91837 : return true;
5078 : : }
5079 : :
5080 : : /*
5081 : : * TransactionBlockStatusCode - return status code to send in ReadyForQuery
5082 : : */
5083 : : char
8594 5084 : 416138 : TransactionBlockStatusCode(void)
5085 : : {
5086 : 416138 : TransactionState s = CurrentTransactionState;
5087 : :
5088 [ + + + - ]: 416138 : switch (s->blockState)
5089 : : {
5090 : 325076 : case TBLOCK_DEFAULT:
5091 : : case TBLOCK_STARTED:
5092 : 325076 : return 'I'; /* idle --- not in transaction */
5093 : 89851 : case TBLOCK_BEGIN:
5094 : : case TBLOCK_SUBBEGIN:
5095 : : case TBLOCK_INPROGRESS:
5096 : : case TBLOCK_IMPLICIT_INPROGRESS:
5097 : : case TBLOCK_PARALLEL_INPROGRESS:
5098 : : case TBLOCK_SUBINPROGRESS:
5099 : : case TBLOCK_END:
5100 : : case TBLOCK_SUBRELEASE:
5101 : : case TBLOCK_SUBCOMMIT:
5102 : : case TBLOCK_PREPARE:
5103 : 89851 : return 'T'; /* in transaction */
5104 : 1211 : case TBLOCK_ABORT:
5105 : : case TBLOCK_SUBABORT:
5106 : : case TBLOCK_ABORT_END:
5107 : : case TBLOCK_SUBABORT_END:
5108 : : case TBLOCK_ABORT_PENDING:
5109 : : case TBLOCK_SUBABORT_PENDING:
5110 : : case TBLOCK_SUBRESTART:
5111 : : case TBLOCK_SUBABORT_RESTART:
5112 : 1211 : return 'E'; /* in failed transaction */
5113 : : }
5114 : :
5115 : : /* should never get here */
8162 tgl@sss.pgh.pa.us 5116 [ # # ]:UBC 0 : elog(FATAL, "invalid transaction block state: %s",
5117 : : BlockStateAsString(s->blockState));
5118 : : return 0; /* keep compiler quiet */
5119 : : }
5120 : :
5121 : : /*
5122 : : * IsSubTransaction
5123 : : */
5124 : : bool
8162 tgl@sss.pgh.pa.us 5125 :CBC 625300 : IsSubTransaction(void)
5126 : : {
5127 : 625300 : TransactionState s = CurrentTransactionState;
5128 : :
8131 5129 [ + + ]: 625300 : if (s->nestingLevel >= 2)
5130 : 487 : return true;
5131 : :
5132 : 624813 : return false;
5133 : : }
5134 : :
5135 : : /*
5136 : : * StartSubTransaction
5137 : : *
5138 : : * If you're wondering why this is separate from PushTransaction: it's because
5139 : : * we can't conveniently do this stuff right inside DefineSavepoint. The
5140 : : * SAVEPOINT utility command will be executed inside a Portal, and if we
5141 : : * muck with CurrentMemoryContext or CurrentResourceOwner then exit from
5142 : : * the Portal will undo those settings. So we make DefineSavepoint just
5143 : : * push a dummy transaction block, and when control returns to the main
5144 : : * idle loop, CommitTransactionCommand will be called, and we'll come here
5145 : : * to finish starting the subtransaction.
5146 : : */
5147 : : static void
8162 5148 : 22999 : StartSubTransaction(void)
5149 : : {
5150 : 22999 : TransactionState s = CurrentTransactionState;
5151 : :
5152 [ - + ]: 22999 : if (s->state != TRANS_DEFAULT)
8135 tgl@sss.pgh.pa.us 5153 [ # # ]:UBC 0 : elog(WARNING, "StartSubTransaction while in %s state",
5154 : : TransStateAsString(s->state));
5155 : :
8162 tgl@sss.pgh.pa.us 5156 :CBC 22999 : s->state = TRANS_START;
5157 : :
5158 : : /*
5159 : : * Initialize subsystems for new subtransaction
5160 : : *
5161 : : * must initialize resource-management stuff first
5162 : : */
8146 5163 : 22999 : AtSubStart_Memory();
5164 : 22999 : AtSubStart_ResourceOwner();
8091 5165 : 22999 : AfterTriggerBeginSubXact();
5166 : :
8162 5167 : 22999 : s->state = TRANS_INPROGRESS;
5168 : :
5169 : : /*
5170 : : * Call start-of-subxact callbacks
5171 : : */
8085 5172 : 22999 : CallSubXactCallbacks(SUBXACT_EVENT_START_SUB, s->subTransactionId,
5173 : 22999 : s->parent->subTransactionId);
5174 : :
8162 5175 : 22999 : ShowTransactionState("StartSubTransaction");
5176 : 22999 : }
5177 : :
5178 : : /*
5179 : : * CommitSubTransaction
5180 : : *
5181 : : * The caller has to make sure to always reassign CurrentTransactionState
5182 : : * if it has a local pointer to it after calling this function.
5183 : : */
5184 : : static void
5538 simon@2ndQuadrant.co 5185 : 17382 : CommitSubTransaction(void)
5186 : : {
8162 tgl@sss.pgh.pa.us 5187 : 17382 : TransactionState s = CurrentTransactionState;
5188 : :
5189 : 17382 : ShowTransactionState("CommitSubTransaction");
5190 : :
5191 [ - + ]: 17382 : if (s->state != TRANS_INPROGRESS)
8135 tgl@sss.pgh.pa.us 5192 [ # # ]:UBC 0 : elog(WARNING, "CommitSubTransaction while in %s state",
5193 : : TransStateAsString(s->state));
5194 : :
5195 : : /* Pre-commit processing goes here */
5196 : :
5012 tgl@sss.pgh.pa.us 5197 :CBC 17382 : CallSubXactCallbacks(SUBXACT_EVENT_PRE_COMMIT_SUB, s->subTransactionId,
5198 : 17382 : s->parent->subTransactionId);
5199 : :
5200 : : /*
5201 : : * If this subxact has started any unfinished parallel operation, clean up
5202 : : * its workers and exit parallel mode. Warn about leaked resources.
5203 : : */
952 5204 : 17382 : AtEOSubXact_Parallel(true, s->subTransactionId);
5205 [ - + ]: 17382 : if (s->parallelModeLevel != 0)
5206 : : {
952 tgl@sss.pgh.pa.us 5207 [ # # ]:UBC 0 : elog(WARNING, "parallelModeLevel is %d not 0 at end of subtransaction",
5208 : : s->parallelModeLevel);
4207 rhaas@postgresql.org 5209 : 0 : s->parallelModeLevel = 0;
5210 : : }
5211 : :
5212 : : /* Do the actual "commit", such as it is */
8162 tgl@sss.pgh.pa.us 5213 :CBC 17382 : s->state = TRANS_COMMIT;
5214 : :
5215 : : /* Must CCI to ensure commands of subtransaction are seen as done */
5216 : 17382 : CommandCounterIncrement();
5217 : :
5218 : : /*
5219 : : * Prior to 8.4 we marked subcommit in clog at this point. We now only
5220 : : * perform that step, if required, as part of the atomic update of the
5221 : : * whole transaction tree at top level commit or abort.
5222 : : */
5223 : :
5224 : : /* Post-commit cleanup */
2779 tmunro@postgresql.or 5225 [ + + ]: 17382 : if (FullTransactionIdIsValid(s->fullTransactionId))
7001 tgl@sss.pgh.pa.us 5226 : 15473 : AtSubCommit_childXids();
8091 5227 : 17382 : AfterTriggerEndSubXact(true);
8085 5228 : 17382 : AtSubCommit_Portals(s->subTransactionId,
5229 : 17382 : s->parent->subTransactionId,
1861 5230 : 17382 : s->parent->nestingLevel,
8131 5231 : 17382 : s->parent->curTransactionOwner);
8085 5232 : 17382 : AtEOSubXact_LargeObject(true, s->subTransactionId,
5233 : 17382 : s->parent->subTransactionId);
8131 5234 : 17382 : AtSubCommit_Notify();
5235 : :
8085 5236 : 17382 : CallSubXactCallbacks(SUBXACT_EVENT_COMMIT_SUB, s->subTransactionId,
5237 : 17382 : s->parent->subTransactionId);
5238 : :
8146 5239 : 17382 : ResourceOwnerRelease(s->curTransactionOwner,
5240 : : RESOURCE_RELEASE_BEFORE_LOCKS,
5241 : : true, false);
8085 5242 : 17382 : AtEOSubXact_RelationCache(true, s->subTransactionId,
5243 : 17382 : s->parent->subTransactionId);
742 akorotkov@postgresql 5244 : 17382 : AtEOSubXact_TypeCache();
8131 tgl@sss.pgh.pa.us 5245 : 17382 : AtEOSubXact_Inval(true);
8095 5246 : 17382 : AtSubCommit_smgr();
5247 : :
5248 : : /*
5249 : : * The only lock we actually release here is the subtransaction XID lock.
5250 : : */
8085 5251 : 17382 : CurrentResourceOwner = s->curTransactionOwner;
2779 tmunro@postgresql.or 5252 [ + + ]: 17382 : if (FullTransactionIdIsValid(s->fullTransactionId))
5253 : 15473 : XactLockTableDelete(XidFromFullTransactionId(s->fullTransactionId));
5254 : :
5255 : : /*
5256 : : * Other locks should get transferred to their parent resource owner.
5257 : : */
8107 tgl@sss.pgh.pa.us 5258 : 17382 : ResourceOwnerRelease(s->curTransactionOwner,
5259 : : RESOURCE_RELEASE_LOCKS,
5260 : : true, false);
8146 5261 : 17382 : ResourceOwnerRelease(s->curTransactionOwner,
5262 : : RESOURCE_RELEASE_AFTER_LOCKS,
5263 : : true, false);
5264 : :
7003 5265 : 17382 : AtEOXact_GUC(true, s->gucNestLevel);
8085 5266 : 17382 : AtEOSubXact_SPI(true, s->subTransactionId);
5267 : 17382 : AtEOSubXact_on_commit_actions(true, s->subTransactionId,
5268 : 17382 : s->parent->subTransactionId);
5269 : 17382 : AtEOSubXact_Namespace(true, s->subTransactionId,
5270 : 17382 : s->parent->subTransactionId);
5271 : 17382 : AtEOSubXact_Files(true, s->subTransactionId,
5272 : 17382 : s->parent->subTransactionId);
7133 5273 : 17382 : AtEOSubXact_HashTables(true, s->nestingLevel);
7102 5274 : 17382 : AtEOSubXact_PgStat(true, s->nestingLevel);
6751 alvherre@alvh.no-ip. 5275 : 17382 : AtSubCommit_Snapshot(s->nestingLevel);
5276 : :
5277 : : /*
5278 : : * We need to restore the upper transaction's read-only state, in case the
5279 : : * upper is read-write while the child is read-only; GUC will incorrectly
5280 : : * think it should leave the child state in place.
5281 : : */
8135 tgl@sss.pgh.pa.us 5282 : 17382 : XactReadOnly = s->prevXactReadOnly;
5283 : :
8146 5284 : 17382 : CurrentResourceOwner = s->parent->curTransactionOwner;
5285 : 17382 : CurTransactionResourceOwner = s->parent->curTransactionOwner;
8107 5286 : 17382 : ResourceOwnerDelete(s->curTransactionOwner);
8146 5287 : 17382 : s->curTransactionOwner = NULL;
5288 : :
8162 5289 : 17382 : AtSubCommit_Memory();
5290 : :
5291 : 17382 : s->state = TRANS_DEFAULT;
5292 : :
8085 5293 : 17382 : PopTransaction();
8162 5294 : 17382 : }
5295 : :
5296 : : /*
5297 : : * AbortSubTransaction
5298 : : */
5299 : : static void
5300 : 5617 : AbortSubTransaction(void)
5301 : : {
5302 : 5617 : TransactionState s = CurrentTransactionState;
5303 : :
5304 : : /* Prevent cancel/die interrupt while cleaning up */
5305 : 5617 : HOLD_INTERRUPTS();
5306 : :
5307 : : /* Make sure we have a valid memory context and resource owner */
7287 5308 : 5617 : AtSubAbort_Memory();
5309 : 5617 : AtSubAbort_ResourceOwner();
5310 : :
5311 : : /*
5312 : : * Release any LW locks we might be holding as quickly as possible.
5313 : : * (Regular locks, however, must be held till we finish aborting.)
5314 : : * Releasing LW locks is critical since we might try to grab them again
5315 : : * while cleaning up!
5316 : : *
5317 : : * FIXME This may be incorrect --- Are there some locks we should keep?
5318 : : * Buffer locks, for example? I don't think so but I'm not sure.
5319 : : */
8162 5320 : 5617 : LWLockReleaseAll();
5321 : :
5322 : : /*
5323 : : * Cleanup waiting for LSN if any.
5324 : : */
183 akorotkov@postgresql 5325 : 5617 : WaitLSNCleanup();
5326 : :
3892 rhaas@postgresql.org 5327 : 5617 : pgstat_report_wait_end();
5328 : 5617 : pgstat_progress_end_command();
5329 : :
598 andres@anarazel.de 5330 : 5617 : pgaio_error_cleanup();
5331 : :
8162 tgl@sss.pgh.pa.us 5332 : 5617 : UnlockBuffers();
5333 : :
5334 : : /* Reset WAL record construction state */
4368 heikki.linnakangas@i 5335 : 5617 : XLogResetInsertion();
5336 : :
5337 : : /* Cancel condition variable sleep */
3241 rhaas@postgresql.org 5338 : 5617 : ConditionVariableCancelSleep();
5339 : :
5340 : : /*
5341 : : * Also clean up any open wait for lock, since the lock manager will choke
5342 : : * if we try to wait for another lock before doing this.
5343 : : */
5314 5344 : 5617 : LockErrorCleanup();
5345 : :
5346 : : /*
5347 : : * If any timeout events are still active, make sure the timeout interrupt
5348 : : * is scheduled. This covers possible loss of a timeout interrupt due to
5349 : : * longjmp'ing out of the SIGINT handler (see notes in handle_sig_alarm).
5350 : : * We delay this till after LockErrorCleanup so that we don't uselessly
5351 : : * reschedule lock or deadlock check timeouts.
5352 : : */
4724 tgl@sss.pgh.pa.us 5353 : 5617 : reschedule_timeouts();
5354 : :
5355 : : /*
5356 : : * Re-enable signals, in case we got here by longjmp'ing out of a signal
5357 : : * handler. We do this fairly early in the sequence so that the timeout
5358 : : * infrastructure will be functional if needed while aborting.
5359 : : */
1371 tmunro@postgresql.or 5360 : 5617 : sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
5361 : :
5362 : : /*
5363 : : * check the current transaction state
5364 : : */
7287 tgl@sss.pgh.pa.us 5365 : 5617 : ShowTransactionState("AbortSubTransaction");
5366 : :
5367 [ - + ]: 5617 : if (s->state != TRANS_INPROGRESS)
7287 tgl@sss.pgh.pa.us 5368 [ # # ]:UBC 0 : elog(WARNING, "AbortSubTransaction while in %s state",
5369 : : TransStateAsString(s->state));
5370 : :
7287 tgl@sss.pgh.pa.us 5371 :CBC 5617 : s->state = TRANS_ABORT;
5372 : :
5373 : : /*
5374 : : * Reset user ID which might have been changed transiently. (See notes in
5375 : : * AbortTransaction.)
5376 : : */
6175 5377 : 5617 : SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
5378 : :
5379 : : /* Forget about any active REINDEX. */
2389 5380 : 5617 : ResetReindexState(s->nestingLevel);
5381 : :
5382 : : /* Reset logical streaming state. */
2280 akapila@postgresql.o 5383 : 5617 : ResetLogicalStreamingState();
5384 : :
5385 : : /*
5386 : : * No need for SnapBuildResetExportedSnapshotState() here, snapshot
5387 : : * exports are not supported in subtransactions.
5388 : : */
5389 : :
5390 : : /*
5391 : : * If this subxact has started any unfinished parallel operation, clean up
5392 : : * its workers and exit parallel mode. Don't warn about leaked resources.
5393 : : */
952 tgl@sss.pgh.pa.us 5394 : 5617 : AtEOSubXact_Parallel(false, s->subTransactionId);
5395 : 5617 : s->parallelModeLevel = 0;
5396 : :
5397 : : /*
5398 : : * We can skip all this stuff if the subxact failed before creating a
5399 : : * ResourceOwner...
5400 : : */
8085 5401 [ + - ]: 5617 : if (s->curTransactionOwner)
5402 : : {
5403 : 5617 : AfterTriggerEndSubXact(false);
5404 : 5617 : AtSubAbort_Portals(s->subTransactionId,
5405 : 5617 : s->parent->subTransactionId,
5406 : : s->curTransactionOwner,
5407 : 5617 : s->parent->curTransactionOwner);
5408 : 5617 : AtEOSubXact_LargeObject(false, s->subTransactionId,
5409 : 5617 : s->parent->subTransactionId);
5410 : 5617 : AtSubAbort_Notify();
5411 : :
5412 : : /* Advertise the fact that we aborted in pg_xact. */
6998 5413 : 5617 : (void) RecordTransactionAbort(true);
5414 : :
5415 : : /* Post-abort cleanup */
2779 tmunro@postgresql.or 5416 [ + + ]: 5617 : if (FullTransactionIdIsValid(s->fullTransactionId))
8085 tgl@sss.pgh.pa.us 5417 : 1012 : AtSubAbort_childXids();
5418 : :
5419 : 5617 : CallSubXactCallbacks(SUBXACT_EVENT_ABORT_SUB, s->subTransactionId,
5420 : 5617 : s->parent->subTransactionId);
5421 : :
5422 : 5617 : ResourceOwnerRelease(s->curTransactionOwner,
5423 : : RESOURCE_RELEASE_BEFORE_LOCKS,
5424 : : false, false);
5425 : :
598 andres@anarazel.de 5426 : 5617 : AtEOXact_Aio(false);
8085 tgl@sss.pgh.pa.us 5427 : 5617 : AtEOSubXact_RelationCache(false, s->subTransactionId,
5428 : 5617 : s->parent->subTransactionId);
742 akorotkov@postgresql 5429 : 5617 : AtEOSubXact_TypeCache();
8085 tgl@sss.pgh.pa.us 5430 : 5617 : AtEOSubXact_Inval(false);
5431 : 5617 : ResourceOwnerRelease(s->curTransactionOwner,
5432 : : RESOURCE_RELEASE_LOCKS,
5433 : : false, false);
5434 : 5617 : ResourceOwnerRelease(s->curTransactionOwner,
5435 : : RESOURCE_RELEASE_AFTER_LOCKS,
5436 : : false, false);
5257 rhaas@postgresql.org 5437 : 5617 : AtSubAbort_smgr();
5438 : :
7003 tgl@sss.pgh.pa.us 5439 : 5617 : AtEOXact_GUC(false, s->gucNestLevel);
8085 5440 : 5617 : AtEOSubXact_SPI(false, s->subTransactionId);
5441 : 5617 : AtEOSubXact_on_commit_actions(false, s->subTransactionId,
5442 : 5617 : s->parent->subTransactionId);
5443 : 5617 : AtEOSubXact_Namespace(false, s->subTransactionId,
5444 : 5617 : s->parent->subTransactionId);
5445 : 5617 : AtEOSubXact_Files(false, s->subTransactionId,
5446 : 5617 : s->parent->subTransactionId);
7133 5447 : 5617 : AtEOSubXact_HashTables(false, s->nestingLevel);
7102 5448 : 5617 : AtEOSubXact_PgStat(false, s->nestingLevel);
6751 alvherre@alvh.no-ip. 5449 : 5617 : AtSubAbort_Snapshot(s->nestingLevel);
5450 : : }
5451 : :
5452 : : /*
5453 : : * Restore the upper transaction's read-only state, too. This should be
5454 : : * redundant with GUC's cleanup but we may as well do it for consistency
5455 : : * with the commit case.
5456 : : */
8135 tgl@sss.pgh.pa.us 5457 : 5617 : XactReadOnly = s->prevXactReadOnly;
5458 : :
8162 5459 [ - + ]: 5617 : RESUME_INTERRUPTS();
5460 : 5617 : }
5461 : :
5462 : : /*
5463 : : * CleanupSubTransaction
5464 : : *
5465 : : * The caller has to make sure to always reassign CurrentTransactionState
5466 : : * if it has a local pointer to it after calling this function.
5467 : : */
5468 : : static void
5469 : 5617 : CleanupSubTransaction(void)
5470 : : {
5471 : 5617 : TransactionState s = CurrentTransactionState;
5472 : :
5473 : 5617 : ShowTransactionState("CleanupSubTransaction");
5474 : :
5475 [ - + ]: 5617 : if (s->state != TRANS_ABORT)
8135 tgl@sss.pgh.pa.us 5476 [ # # ]:UBC 0 : elog(WARNING, "CleanupSubTransaction while in %s state",
5477 : : TransStateAsString(s->state));
5478 : :
8085 tgl@sss.pgh.pa.us 5479 :CBC 5617 : AtSubCleanup_Portals(s->subTransactionId);
5480 : :
8146 5481 : 5617 : CurrentResourceOwner = s->parent->curTransactionOwner;
5482 : 5617 : CurTransactionResourceOwner = s->parent->curTransactionOwner;
8085 5483 [ + - ]: 5617 : if (s->curTransactionOwner)
5484 : 5617 : ResourceOwnerDelete(s->curTransactionOwner);
8146 5485 : 5617 : s->curTransactionOwner = NULL;
5486 : :
8162 5487 : 5617 : AtSubCleanup_Memory();
5488 : :
5489 : 5617 : s->state = TRANS_DEFAULT;
5490 : :
8085 5491 : 5617 : PopTransaction();
8162 5492 : 5617 : }
5493 : :
5494 : : /*
5495 : : * PushTransaction
5496 : : * Create transaction state stack entry for a subtransaction
5497 : : *
5498 : : * The caller has to make sure to always reassign CurrentTransactionState
5499 : : * if it has a local pointer to it after calling this function.
5500 : : */
5501 : : static void
5502 : 22999 : PushTransaction(void)
5503 : : {
8103 bruce@momjian.us 5504 : 22999 : TransactionState p = CurrentTransactionState;
5505 : : TransactionState s;
5506 : :
5507 : : /*
5508 : : * We keep subtransaction state nodes in TopTransactionContext.
5509 : : */
5510 : : s = (TransactionState)
8162 tgl@sss.pgh.pa.us 5511 : 22999 : MemoryContextAllocZero(TopTransactionContext,
5512 : : sizeof(TransactionStateData));
5513 : :
5514 : : /*
5515 : : * Assign a subtransaction ID, watching out for counter wraparound.
5516 : : */
8085 5517 : 22999 : currentSubTransactionId += 1;
5518 [ - + ]: 22999 : if (currentSubTransactionId == InvalidSubTransactionId)
5519 : : {
8085 tgl@sss.pgh.pa.us 5520 :UBC 0 : currentSubTransactionId -= 1;
5521 : 0 : pfree(s);
5522 [ # # ]: 0 : ereport(ERROR,
5523 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5524 : : errmsg("cannot have more than 2^32-1 subtransactions in a transaction")));
5525 : : }
5526 : :
5527 : : /*
5528 : : * We can now stack a minimally valid subtransaction without fear of
5529 : : * failure.
5530 : : */
2779 tmunro@postgresql.or 5531 :CBC 22999 : s->fullTransactionId = InvalidFullTransactionId; /* until assigned */
8085 tgl@sss.pgh.pa.us 5532 : 22999 : s->subTransactionId = currentSubTransactionId;
8162 5533 : 22999 : s->parent = p;
5534 : 22999 : s->nestingLevel = p->nestingLevel + 1;
7003 5535 : 22999 : s->gucNestLevel = NewGUCNestLevel();
8136 5536 : 22999 : s->savepointLevel = p->savepointLevel;
8162 5537 : 22999 : s->state = TRANS_DEFAULT;
5538 : 22999 : s->blockState = TBLOCK_SUBBEGIN;
6175 5539 : 22999 : GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
8085 5540 : 22999 : s->prevXactReadOnly = XactReadOnly;
1059 michael@paquier.xyz 5541 : 22999 : s->startedInRecovery = p->startedInRecovery;
4207 rhaas@postgresql.org 5542 : 22999 : s->parallelModeLevel = 0;
952 tgl@sss.pgh.pa.us 5543 [ + + - + ]: 22999 : s->parallelChildXact = (p->parallelModeLevel != 0 || p->parallelChildXact);
1829 akapila@postgresql.o 5544 : 22999 : s->topXidLogged = false;
5545 : :
8085 tgl@sss.pgh.pa.us 5546 : 22999 : CurrentTransactionState = s;
5547 : :
5548 : : /*
5549 : : * AbortSubTransaction and CleanupSubTransaction have to be able to cope
5550 : : * with the subtransaction from here on out; in particular they should not
5551 : : * assume that it necessarily has a transaction context, resource owner,
5552 : : * or XID.
5553 : : */
8162 5554 : 22999 : }
5555 : :
5556 : : /*
5557 : : * PopTransaction
5558 : : * Pop back to parent transaction state
5559 : : *
5560 : : * The caller has to make sure to always reassign CurrentTransactionState
5561 : : * if it has a local pointer to it after calling this function.
5562 : : */
5563 : : static void
5564 : 22999 : PopTransaction(void)
5565 : : {
5566 : 22999 : TransactionState s = CurrentTransactionState;
5567 : :
5568 [ - + ]: 22999 : if (s->state != TRANS_DEFAULT)
8135 tgl@sss.pgh.pa.us 5569 [ # # ]:UBC 0 : elog(WARNING, "PopTransaction while in %s state",
5570 : : TransStateAsString(s->state));
5571 : :
8162 tgl@sss.pgh.pa.us 5572 [ - + ]:CBC 22999 : if (s->parent == NULL)
8162 tgl@sss.pgh.pa.us 5573 [ # # ]:UBC 0 : elog(FATAL, "PopTransaction with no parent");
5574 : :
8162 tgl@sss.pgh.pa.us 5575 :CBC 22999 : CurrentTransactionState = s->parent;
5576 : :
5577 : : /* Let's just make sure CurTransactionContext is good */
5578 : 22999 : CurTransactionContext = s->parent->curTransactionContext;
5579 : 22999 : MemoryContextSwitchTo(CurTransactionContext);
5580 : :
5581 : : /* Ditto for ResourceOwner links */
8146 5582 : 22999 : CurTransactionResourceOwner = s->parent->curTransactionOwner;
5583 : 22999 : CurrentResourceOwner = s->parent->curTransactionOwner;
5584 : :
5585 : : /* Free the old child structure */
8136 5586 [ + + ]: 22999 : if (s->name)
5587 : 2228 : pfree(s->name);
8162 5588 : 22999 : pfree(s);
5589 : 22999 : }
5590 : :
5591 : : /*
5592 : : * EstimateTransactionStateSpace
5593 : : * Estimate the amount of space that will be needed by
5594 : : * SerializeTransactionState. It would be OK to overestimate slightly,
5595 : : * but it's simple for us to work out the precise value, so we do.
5596 : : */
5597 : : Size
4207 rhaas@postgresql.org 5598 : 674 : EstimateTransactionStateSpace(void)
5599 : : {
5600 : : TransactionState s;
2779 tmunro@postgresql.or 5601 : 674 : Size nxids = 0;
5602 : 674 : Size size = SerializedTransactionStateHeaderSize;
5603 : :
4207 rhaas@postgresql.org 5604 [ + + ]: 3040 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
5605 : : {
2779 tmunro@postgresql.or 5606 [ + + ]: 2366 : if (FullTransactionIdIsValid(s->fullTransactionId))
4207 rhaas@postgresql.org 5607 : 1363 : nxids = add_size(nxids, 1);
5608 : 2366 : nxids = add_size(nxids, s->nChildXids);
5609 : : }
5610 : :
2764 tmunro@postgresql.or 5611 : 674 : return add_size(size, mul_size(sizeof(TransactionId), nxids));
5612 : : }
5613 : :
5614 : : /*
5615 : : * SerializeTransactionState
5616 : : * Write out relevant details of our transaction state that will be
5617 : : * needed by a parallel worker.
5618 : : *
5619 : : * We need to save and restore XactDeferrable, XactIsoLevel, and the XIDs
5620 : : * associated with this transaction. These are serialized into a
5621 : : * caller-supplied buffer big enough to hold the number of bytes reported by
5622 : : * EstimateTransactionStateSpace(). We emit the XIDs in sorted order for the
5623 : : * convenience of the receiving process.
5624 : : */
5625 : : void
4207 rhaas@postgresql.org 5626 : 674 : SerializeTransactionState(Size maxsize, char *start_address)
5627 : : {
5628 : : TransactionState s;
4184 bruce@momjian.us 5629 : 674 : Size nxids = 0;
5630 : 674 : Size i = 0;
5631 : : TransactionId *workspace;
5632 : : SerializedTransactionState *result;
5633 : :
2779 tmunro@postgresql.or 5634 : 674 : result = (SerializedTransactionState *) start_address;
5635 : :
5636 : 674 : result->xactIsoLevel = XactIsoLevel;
5637 : 674 : result->xactDeferrable = XactDeferrable;
5638 : 674 : result->topFullTransactionId = XactTopFullTransactionId;
5639 : 674 : result->currentFullTransactionId =
5640 : 674 : CurrentTransactionState->fullTransactionId;
5641 : 674 : result->currentCommandId = currentCommandId;
5642 : :
5643 : : /*
5644 : : * If we're running in a parallel worker and launching a parallel worker
5645 : : * of our own, we can just pass along the information that was passed to
5646 : : * us.
5647 : : */
4207 rhaas@postgresql.org 5648 [ - + ]: 674 : if (nParallelCurrentXids > 0)
5649 : : {
2779 tmunro@postgresql.or 5650 :UBC 0 : result->nParallelCurrentXids = nParallelCurrentXids;
5651 : 0 : memcpy(&result->parallelCurrentXids[0], ParallelCurrentXids,
5652 : : nParallelCurrentXids * sizeof(TransactionId));
4207 rhaas@postgresql.org 5653 : 0 : return;
5654 : : }
5655 : :
5656 : : /*
5657 : : * OK, we need to generate a sorted list of XIDs that our workers should
5658 : : * view as current. First, figure out how many there are.
5659 : : */
4207 rhaas@postgresql.org 5660 [ + + ]:CBC 3040 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
5661 : : {
2779 tmunro@postgresql.or 5662 [ + + ]: 2366 : if (FullTransactionIdIsValid(s->fullTransactionId))
4207 rhaas@postgresql.org 5663 : 1363 : nxids = add_size(nxids, 1);
5664 : 2366 : nxids = add_size(nxids, s->nChildXids);
5665 : : }
2779 tmunro@postgresql.or 5666 [ - + ]: 674 : Assert(SerializedTransactionStateHeaderSize + nxids * sizeof(TransactionId)
5667 : : <= maxsize);
5668 : :
5669 : : /* Copy them to our scratch space. */
80 michael@paquier.xyz 5670 :GNC 674 : workspace = palloc_array(TransactionId, nxids);
4207 rhaas@postgresql.org 5671 [ + + ]:CBC 3040 : for (s = CurrentTransactionState; s != NULL; s = s->parent)
5672 : : {
2779 tmunro@postgresql.or 5673 [ + + ]: 2366 : if (FullTransactionIdIsValid(s->fullTransactionId))
5674 : 1363 : workspace[i++] = XidFromFullTransactionId(s->fullTransactionId);
1708 tgl@sss.pgh.pa.us 5675 [ - + ]: 2366 : if (s->nChildXids > 0)
1708 tgl@sss.pgh.pa.us 5676 :UBC 0 : memcpy(&workspace[i], s->childXids,
5677 : 0 : s->nChildXids * sizeof(TransactionId));
4207 rhaas@postgresql.org 5678 :CBC 2366 : i += s->nChildXids;
5679 : : }
5680 [ - + ]: 674 : Assert(i == nxids);
5681 : :
5682 : : /* Sort them. */
5683 : 674 : qsort(workspace, nxids, sizeof(TransactionId), xidComparator);
5684 : :
5685 : : /* Copy data into output area. */
2779 tmunro@postgresql.or 5686 : 674 : result->nParallelCurrentXids = nxids;
5687 : 674 : memcpy(&result->parallelCurrentXids[0], workspace,
5688 : : nxids * sizeof(TransactionId));
5689 : : }
5690 : :
5691 : : /*
5692 : : * StartParallelWorkerTransaction
5693 : : * Start a parallel worker transaction, restoring the relevant
5694 : : * transaction state serialized by SerializeTransactionState.
5695 : : */
5696 : : void
4207 rhaas@postgresql.org 5697 : 2043 : StartParallelWorkerTransaction(char *tstatespace)
5698 : : {
5699 : : SerializedTransactionState *tstate;
5700 : :
5701 [ - + ]: 2043 : Assert(CurrentTransactionState->blockState == TBLOCK_DEFAULT);
5702 : 2043 : StartTransaction();
5703 : :
2779 tmunro@postgresql.or 5704 : 2043 : tstate = (SerializedTransactionState *) tstatespace;
5705 : 2043 : XactIsoLevel = tstate->xactIsoLevel;
5706 : 2043 : XactDeferrable = tstate->xactDeferrable;
5707 : 2043 : XactTopFullTransactionId = tstate->topFullTransactionId;
5708 : 2043 : CurrentTransactionState->fullTransactionId =
5709 : : tstate->currentFullTransactionId;
5710 : 2043 : currentCommandId = tstate->currentCommandId;
5711 : 2043 : nParallelCurrentXids = tstate->nParallelCurrentXids;
5712 : 2043 : ParallelCurrentXids = &tstate->parallelCurrentXids[0];
5713 : :
4207 rhaas@postgresql.org 5714 : 2043 : CurrentTransactionState->blockState = TBLOCK_PARALLEL_INPROGRESS;
5715 : 2043 : }
5716 : :
5717 : : /*
5718 : : * EndParallelWorkerTransaction
5719 : : * End a parallel worker transaction.
5720 : : */
5721 : : void
5722 : 2034 : EndParallelWorkerTransaction(void)
5723 : : {
5724 [ - + ]: 2034 : Assert(CurrentTransactionState->blockState == TBLOCK_PARALLEL_INPROGRESS);
5725 : 2034 : CommitTransaction();
5726 : 2034 : CurrentTransactionState->blockState = TBLOCK_DEFAULT;
5727 : 2034 : }
5728 : :
5729 : : /*
5730 : : * ShowTransactionState
5731 : : * Debug support
5732 : : */
5733 : : static void
8162 tgl@sss.pgh.pa.us 5734 : 873070 : ShowTransactionState(const char *str)
5735 : : {
5736 : : /* skip work if message will definitely not be printed */
2173 5737 [ - + ]: 873070 : if (message_level_is_interesting(DEBUG5))
3640 rhaas@postgresql.org 5738 :UBC 0 : ShowTransactionStateRec(str, CurrentTransactionState);
8162 tgl@sss.pgh.pa.us 5739 :CBC 873070 : }
5740 : :
5741 : : /*
5742 : : * ShowTransactionStateRec
5743 : : * Recursive subroutine for ShowTransactionState
5744 : : */
5745 : : static void
3640 rhaas@postgresql.org 5746 :UBC 0 : ShowTransactionStateRec(const char *str, TransactionState s)
5747 : : {
5748 : : StringInfoData buf;
5749 : :
972 akorotkov@postgresql 5750 [ # # ]: 0 : if (s->parent)
5751 : : {
5752 : : /*
5753 : : * Since this function recurses, it could be driven to stack overflow.
5754 : : * This is just a debugging aid, so we can leave out some details
5755 : : * instead of erroring out with check_stack_depth().
5756 : : */
5757 [ # # ]: 0 : if (stack_is_too_deep())
5758 [ # # ]: 0 : ereport(DEBUG5,
5759 : : (errmsg_internal("%s(%d): parent omitted to avoid stack overflow",
5760 : : str, s->nestingLevel)));
5761 : : else
5762 : 0 : ShowTransactionStateRec(str, s->parent);
5763 : : }
5764 : :
5765 : 0 : initStringInfo(&buf);
6807 tgl@sss.pgh.pa.us 5766 [ # # ]: 0 : if (s->nChildXids > 0)
5767 : : {
5768 : : int i;
5769 : :
3640 rhaas@postgresql.org 5770 : 0 : appendStringInfo(&buf, ", children: %u", s->childXids[0]);
6807 tgl@sss.pgh.pa.us 5771 [ # # ]: 0 : for (i = 1; i < s->nChildXids; i++)
5772 : 0 : appendStringInfo(&buf, " %u", s->childXids[i]);
5773 : : }
3640 rhaas@postgresql.org 5774 [ # # # # : 0 : ereport(DEBUG5,
# # ]
5775 : : (errmsg_internal("%s(%d) name: %s; blockState: %s; state: %s, xid/subid/cid: %u/%u/%u%s%s",
5776 : : str, s->nestingLevel,
5777 : : s->name ? s->name : "unnamed",
5778 : : BlockStateAsString(s->blockState),
5779 : : TransStateAsString(s->state),
5780 : : XidFromFullTransactionId(s->fullTransactionId),
5781 : : s->subTransactionId,
5782 : : currentCommandId,
5783 : : currentCommandIdUsed ? " (used)" : "",
5784 : : buf.data)));
6807 tgl@sss.pgh.pa.us 5785 : 0 : pfree(buf.data);
8162 5786 : 0 : }
5787 : :
5788 : : /*
5789 : : * BlockStateAsString
5790 : : * Debug support
5791 : : */
5792 : : static const char *
5793 : 0 : BlockStateAsString(TBlockState blockState)
5794 : : {
8136 5795 [ # # # # : 0 : switch (blockState)
# # # # #
# # # # #
# # # # #
# # ]
5796 : : {
8162 5797 : 0 : case TBLOCK_DEFAULT:
5798 : 0 : return "DEFAULT";
5799 : 0 : case TBLOCK_STARTED:
5800 : 0 : return "STARTED";
5801 : 0 : case TBLOCK_BEGIN:
5802 : 0 : return "BEGIN";
5803 : 0 : case TBLOCK_INPROGRESS:
5804 : 0 : return "INPROGRESS";
3346 5805 : 0 : case TBLOCK_IMPLICIT_INPROGRESS:
5806 : 0 : return "IMPLICIT_INPROGRESS";
4207 rhaas@postgresql.org 5807 : 0 : case TBLOCK_PARALLEL_INPROGRESS:
5808 : 0 : return "PARALLEL_INPROGRESS";
8162 tgl@sss.pgh.pa.us 5809 : 0 : case TBLOCK_END:
5810 : 0 : return "END";
5811 : 0 : case TBLOCK_ABORT:
5812 : 0 : return "ABORT";
8085 5813 : 0 : case TBLOCK_ABORT_END:
3183 peter_e@gmx.net 5814 : 0 : return "ABORT_END";
8085 tgl@sss.pgh.pa.us 5815 : 0 : case TBLOCK_ABORT_PENDING:
3183 peter_e@gmx.net 5816 : 0 : return "ABORT_PENDING";
7811 tgl@sss.pgh.pa.us 5817 : 0 : case TBLOCK_PREPARE:
5818 : 0 : return "PREPARE";
8162 5819 : 0 : case TBLOCK_SUBBEGIN:
3183 peter_e@gmx.net 5820 : 0 : return "SUBBEGIN";
8162 tgl@sss.pgh.pa.us 5821 : 0 : case TBLOCK_SUBINPROGRESS:
3183 peter_e@gmx.net 5822 : 0 : return "SUBINPROGRESS";
5588 simon@2ndQuadrant.co 5823 : 0 : case TBLOCK_SUBRELEASE:
3183 peter_e@gmx.net 5824 : 0 : return "SUBRELEASE";
5588 simon@2ndQuadrant.co 5825 : 0 : case TBLOCK_SUBCOMMIT:
3183 peter_e@gmx.net 5826 : 0 : return "SUBCOMMIT";
8162 tgl@sss.pgh.pa.us 5827 : 0 : case TBLOCK_SUBABORT:
3183 peter_e@gmx.net 5828 : 0 : return "SUBABORT";
8085 tgl@sss.pgh.pa.us 5829 : 0 : case TBLOCK_SUBABORT_END:
3183 peter_e@gmx.net 5830 : 0 : return "SUBABORT_END";
8136 tgl@sss.pgh.pa.us 5831 : 0 : case TBLOCK_SUBABORT_PENDING:
3183 peter_e@gmx.net 5832 : 0 : return "SUBABORT_PENDING";
8085 tgl@sss.pgh.pa.us 5833 : 0 : case TBLOCK_SUBRESTART:
3183 peter_e@gmx.net 5834 : 0 : return "SUBRESTART";
8085 tgl@sss.pgh.pa.us 5835 : 0 : case TBLOCK_SUBABORT_RESTART:
3183 peter_e@gmx.net 5836 : 0 : return "SUBABORT_RESTART";
5837 : : }
8162 tgl@sss.pgh.pa.us 5838 : 0 : return "UNRECOGNIZED";
5839 : : }
5840 : :
5841 : : /*
5842 : : * TransStateAsString
5843 : : * Debug support
5844 : : */
5845 : : static const char *
5846 : 0 : TransStateAsString(TransState state)
5847 : : {
8136 5848 [ # # # # : 0 : switch (state)
# # # ]
5849 : : {
8162 5850 : 0 : case TRANS_DEFAULT:
5851 : 0 : return "DEFAULT";
5852 : 0 : case TRANS_START:
5853 : 0 : return "START";
7811 5854 : 0 : case TRANS_INPROGRESS:
3183 peter_e@gmx.net 5855 : 0 : return "INPROGRESS";
8162 tgl@sss.pgh.pa.us 5856 : 0 : case TRANS_COMMIT:
5857 : 0 : return "COMMIT";
5858 : 0 : case TRANS_ABORT:
5859 : 0 : return "ABORT";
7811 5860 : 0 : case TRANS_PREPARE:
5861 : 0 : return "PREPARE";
5862 : : }
8162 5863 : 0 : return "UNRECOGNIZED";
5864 : : }
5865 : :
5866 : : /*
5867 : : * xactGetCommittedChildren
5868 : : *
5869 : : * Gets the list of committed children of the current transaction. The return
5870 : : * value is the number of child transactions. *ptr is set to point to an
5871 : : * array of TransactionIds. The array is allocated in TopTransactionContext;
5872 : : * the caller should *not* pfree() it (this is a change from pre-8.4 code!).
5873 : : * If there are no subxacts, *ptr is set to NULL.
5874 : : */
5875 : : int
8146 tgl@sss.pgh.pa.us 5876 :CBC 400025 : xactGetCommittedChildren(TransactionId **ptr)
5877 : : {
8103 bruce@momjian.us 5878 : 400025 : TransactionState s = CurrentTransactionState;
5879 : :
6807 tgl@sss.pgh.pa.us 5880 [ + + ]: 400025 : if (s->nChildXids == 0)
8162 5881 : 399395 : *ptr = NULL;
5882 : : else
6807 5883 : 630 : *ptr = s->childXids;
5884 : :
5885 : 400025 : return s->nChildXids;
5886 : : }
5887 : :
5888 : : /*
5889 : : * XLOG support routines
5890 : : */
5891 : :
5892 : :
5893 : : /*
5894 : : * Log the commit record for a plain or twophase transaction commit.
5895 : : *
5896 : : * A 2pc commit will be emitted when twophase_xid is valid, a plain one
5897 : : * otherwise.
5898 : : */
5899 : : XLogRecPtr
4253 andres@anarazel.de 5900 : 156156 : XactLogCommitRecord(TimestampTz commit_time,
5901 : : int nsubxacts, TransactionId *subxacts,
5902 : : int nrels, RelFileLocator *rels,
5903 : : int ndroppedstats, xl_xact_stats_item *droppedstats,
5904 : : int nmsgs, SharedInvalidationMessage *msgs,
5905 : : bool relcacheInval,
5906 : : int xactflags, TransactionId twophase_xid,
5907 : : const char *twophase_gid)
5908 : : {
5909 : : xl_xact_commit xlrec;
5910 : : xl_xact_xinfo xl_xinfo;
5911 : : xl_xact_dbinfo xl_dbinfo;
5912 : : xl_xact_subxacts xl_subxacts;
5913 : : xl_xact_relfilelocators xl_relfilelocators;
5914 : : xl_xact_stats_items xl_dropped_stats;
5915 : : xl_xact_invals xl_invals;
5916 : : xl_xact_twophase xl_twophase;
5917 : : xl_xact_origin xl_origin;
5918 : : uint8 info;
5919 : :
5920 [ - + ]: 156156 : Assert(CritSectionCount > 0);
5921 : :
5922 : 156156 : xl_xinfo.xinfo = 0;
5923 : :
5924 : : /* decide between a plain and 2pc commit */
5925 [ + + ]: 156156 : if (!TransactionIdIsValid(twophase_xid))
5926 : 155893 : info = XLOG_XACT_COMMIT;
5927 : : else
5928 : 263 : info = XLOG_XACT_COMMIT_PREPARED;
5929 : :
5930 : : /* First figure out and collect all the information needed */
5931 : :
5932 : 156156 : xlrec.xact_time = commit_time;
5933 : :
5934 [ + + ]: 156156 : if (relcacheInval)
5935 : 4693 : xl_xinfo.xinfo |= XACT_COMPLETION_UPDATE_RELCACHE_FILE;
5936 [ + + ]: 156156 : if (forceSyncCommit)
5937 : 595 : xl_xinfo.xinfo |= XACT_COMPLETION_FORCE_SYNC_COMMIT;
3515 simon@2ndQuadrant.co 5938 [ + + ]: 156156 : if ((xactflags & XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK))
5939 : 63394 : xl_xinfo.xinfo |= XACT_XINFO_HAS_AE_LOCKS;
5940 : :
5941 : : /*
5942 : : * Check if the caller would like to ask standbys for immediate feedback
5943 : : * once this commit is applied.
5944 : : */
3873 rhaas@postgresql.org 5945 [ + + ]: 156156 : if (synchronous_commit >= SYNCHRONOUS_COMMIT_REMOTE_APPLY)
5946 : 3 : xl_xinfo.xinfo |= XACT_COMPLETION_APPLY_FEEDBACK;
5947 : :
5948 : : /*
5949 : : * Relcache invalidations requires information about the current database
5950 : : * and so does logical decoding.
5951 : : */
4253 andres@anarazel.de 5952 [ + + + + : 156156 : if (nmsgs > 0 || XLogLogicalInfoActive())
+ + ]
5953 : : {
5954 : 112199 : xl_xinfo.xinfo |= XACT_XINFO_HAS_DBINFO;
5955 : 112199 : xl_dbinfo.dbId = MyDatabaseId;
5956 : 112199 : xl_dbinfo.tsId = MyDatabaseTableSpace;
5957 : : }
5958 : :
5959 [ + + ]: 156156 : if (nsubxacts > 0)
5960 : : {
5961 : 524 : xl_xinfo.xinfo |= XACT_XINFO_HAS_SUBXACTS;
5962 : 524 : xl_subxacts.nsubxacts = nsubxacts;
5963 : : }
5964 : :
5965 [ + + ]: 156156 : if (nrels > 0)
5966 : : {
1583 rhaas@postgresql.org 5967 : 12331 : xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILELOCATORS;
5968 : 12331 : xl_relfilelocators.nrels = nrels;
2271 heikki.linnakangas@i 5969 : 12331 : info |= XLR_SPECIAL_REL_UPDATE;
5970 : : }
5971 : :
1674 andres@anarazel.de 5972 [ + + ]: 156156 : if (ndroppedstats > 0)
5973 : : {
5974 : 14771 : xl_xinfo.xinfo |= XACT_XINFO_HAS_DROPPED_STATS;
5975 : 14771 : xl_dropped_stats.nitems = ndroppedstats;
5976 : : }
5977 : :
4253 5978 [ + + ]: 156156 : if (nmsgs > 0)
5979 : : {
5980 : 111229 : xl_xinfo.xinfo |= XACT_XINFO_HAS_INVALS;
5981 : 111229 : xl_invals.nmsgs = nmsgs;
5982 : : }
5983 : :
5984 [ + + ]: 156156 : if (TransactionIdIsValid(twophase_xid))
5985 : : {
5986 : 263 : xl_xinfo.xinfo |= XACT_XINFO_HAS_TWOPHASE;
5987 : 263 : xl_twophase.xid = twophase_xid;
3144 simon@2ndQuadrant.co 5988 [ - + ]: 263 : Assert(twophase_gid != NULL);
5989 : :
5990 [ + + - + ]: 263 : if (XLogLogicalInfoActive())
5991 : 43 : xl_xinfo.xinfo |= XACT_XINFO_HAS_GID;
5992 : : }
5993 : :
5994 : : /* dump transaction origin information */
281 msawada@postgresql.o 5995 [ + + ]: 156156 : if (replorigin_xact_state.origin != InvalidReplOriginId)
5996 : : {
4208 andres@anarazel.de 5997 : 1106 : xl_xinfo.xinfo |= XACT_XINFO_HAS_ORIGIN;
5998 : :
281 msawada@postgresql.o 5999 : 1106 : xl_origin.origin_lsn = replorigin_xact_state.origin_lsn;
6000 : 1106 : xl_origin.origin_timestamp = replorigin_xact_state.origin_timestamp;
6001 : : }
6002 : :
4253 andres@anarazel.de 6003 [ + + ]: 156156 : if (xl_xinfo.xinfo != 0)
6004 : 115289 : info |= XLOG_XACT_HAS_INFO;
6005 : :
6006 : : /* Then include all the collected data into the commit record. */
6007 : :
6008 : 156156 : XLogBeginInsert();
6009 : :
632 peter@eisentraut.org 6010 : 156156 : XLogRegisterData(&xlrec, sizeof(xl_xact_commit));
6011 : :
4253 andres@anarazel.de 6012 [ + + ]: 156156 : if (xl_xinfo.xinfo != 0)
632 peter@eisentraut.org 6013 : 115289 : XLogRegisterData(&xl_xinfo.xinfo, sizeof(xl_xinfo.xinfo));
6014 : :
4253 andres@anarazel.de 6015 [ + + ]: 156156 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_DBINFO)
632 peter@eisentraut.org 6016 : 112199 : XLogRegisterData(&xl_dbinfo, sizeof(xl_dbinfo));
6017 : :
4253 andres@anarazel.de 6018 [ + + ]: 156156 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_SUBXACTS)
6019 : : {
632 peter@eisentraut.org 6020 : 524 : XLogRegisterData(&xl_subxacts,
6021 : : MinSizeOfXactSubxacts);
6022 : 524 : XLogRegisterData(subxacts,
6023 : : nsubxacts * sizeof(TransactionId));
6024 : : }
6025 : :
1583 rhaas@postgresql.org 6026 [ + + ]: 156156 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_RELFILELOCATORS)
6027 : : {
632 peter@eisentraut.org 6028 : 12331 : XLogRegisterData(&xl_relfilelocators,
6029 : : MinSizeOfXactRelfileLocators);
6030 : 12331 : XLogRegisterData(rels,
6031 : : nrels * sizeof(RelFileLocator));
6032 : : }
6033 : :
1674 andres@anarazel.de 6034 [ + + ]: 156156 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_DROPPED_STATS)
6035 : : {
632 peter@eisentraut.org 6036 : 14771 : XLogRegisterData(&xl_dropped_stats,
6037 : : MinSizeOfXactStatsItems);
6038 : 14771 : XLogRegisterData(droppedstats,
6039 : : ndroppedstats * sizeof(xl_xact_stats_item));
6040 : : }
6041 : :
4253 andres@anarazel.de 6042 [ + + ]: 156156 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_INVALS)
6043 : : {
632 peter@eisentraut.org 6044 : 111229 : XLogRegisterData(&xl_invals, MinSizeOfXactInvals);
6045 : 111229 : XLogRegisterData(msgs,
6046 : : nmsgs * sizeof(SharedInvalidationMessage));
6047 : : }
6048 : :
4253 andres@anarazel.de 6049 [ + + ]: 156156 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_TWOPHASE)
6050 : : {
632 peter@eisentraut.org 6051 : 263 : XLogRegisterData(&xl_twophase, sizeof(xl_xact_twophase));
3144 simon@2ndQuadrant.co 6052 [ + + ]: 263 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_GID)
793 peter@eisentraut.org 6053 : 43 : XLogRegisterData(twophase_gid, strlen(twophase_gid) + 1);
6054 : : }
6055 : :
4208 andres@anarazel.de 6056 [ + + ]: 156156 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_ORIGIN)
632 peter@eisentraut.org 6057 : 1106 : XLogRegisterData(&xl_origin, sizeof(xl_xact_origin));
6058 : :
6059 : : /* we allow filtering by xacts */
3605 andres@anarazel.de 6060 : 156156 : XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
6061 : :
4253 6062 : 156156 : return XLogInsert(RM_XACT_ID, info);
6063 : : }
6064 : :
6065 : : /*
6066 : : * Log the commit record for a plain or twophase transaction abort.
6067 : : *
6068 : : * A 2pc abort will be emitted when twophase_xid is valid, a plain one
6069 : : * otherwise.
6070 : : */
6071 : : XLogRecPtr
6072 : 9443 : XactLogAbortRecord(TimestampTz abort_time,
6073 : : int nsubxacts, TransactionId *subxacts,
6074 : : int nrels, RelFileLocator *rels,
6075 : : int ndroppedstats, xl_xact_stats_item *droppedstats,
6076 : : int xactflags, TransactionId twophase_xid,
6077 : : const char *twophase_gid)
6078 : : {
6079 : : xl_xact_abort xlrec;
6080 : : xl_xact_xinfo xl_xinfo;
6081 : : xl_xact_subxacts xl_subxacts;
6082 : : xl_xact_relfilelocators xl_relfilelocators;
6083 : : xl_xact_stats_items xl_dropped_stats;
6084 : : xl_xact_twophase xl_twophase;
6085 : : xl_xact_dbinfo xl_dbinfo;
6086 : : xl_xact_origin xl_origin;
6087 : :
6088 : : uint8 info;
6089 : :
6090 [ - + ]: 9443 : Assert(CritSectionCount > 0);
6091 : :
6092 : 9443 : xl_xinfo.xinfo = 0;
6093 : :
6094 : : /* decide between a plain and 2pc abort */
6095 [ + + ]: 9443 : if (!TransactionIdIsValid(twophase_xid))
6096 : 9393 : info = XLOG_XACT_ABORT;
6097 : : else
6098 : 50 : info = XLOG_XACT_ABORT_PREPARED;
6099 : :
6100 : :
6101 : : /* First figure out and collect all the information needed */
6102 : :
6103 : 9443 : xlrec.xact_time = abort_time;
6104 : :
3515 simon@2ndQuadrant.co 6105 [ + + ]: 9443 : if ((xactflags & XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK))
6106 : 5175 : xl_xinfo.xinfo |= XACT_XINFO_HAS_AE_LOCKS;
6107 : :
4253 andres@anarazel.de 6108 [ + + ]: 9443 : if (nsubxacts > 0)
6109 : : {
6110 : 110 : xl_xinfo.xinfo |= XACT_XINFO_HAS_SUBXACTS;
6111 : 110 : xl_subxacts.nsubxacts = nsubxacts;
6112 : : }
6113 : :
6114 [ + + ]: 9443 : if (nrels > 0)
6115 : : {
1583 rhaas@postgresql.org 6116 : 1426 : xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILELOCATORS;
6117 : 1426 : xl_relfilelocators.nrels = nrels;
2271 heikki.linnakangas@i 6118 : 1426 : info |= XLR_SPECIAL_REL_UPDATE;
6119 : : }
6120 : :
1674 andres@anarazel.de 6121 [ + + ]: 9443 : if (ndroppedstats > 0)
6122 : : {
6123 : 1999 : xl_xinfo.xinfo |= XACT_XINFO_HAS_DROPPED_STATS;
6124 : 1999 : xl_dropped_stats.nitems = ndroppedstats;
6125 : : }
6126 : :
4253 6127 [ + + ]: 9443 : if (TransactionIdIsValid(twophase_xid))
6128 : : {
6129 : 50 : xl_xinfo.xinfo |= XACT_XINFO_HAS_TWOPHASE;
6130 : 50 : xl_twophase.xid = twophase_xid;
3144 simon@2ndQuadrant.co 6131 [ - + ]: 50 : Assert(twophase_gid != NULL);
6132 : :
6133 [ + + - + ]: 50 : if (XLogLogicalInfoActive())
6134 : 15 : xl_xinfo.xinfo |= XACT_XINFO_HAS_GID;
6135 : : }
6136 : :
6137 [ + + + + : 9443 : if (TransactionIdIsValid(twophase_xid) && XLogLogicalInfoActive())
- + ]
6138 : : {
6139 : 15 : xl_xinfo.xinfo |= XACT_XINFO_HAS_DBINFO;
6140 : 15 : xl_dbinfo.dbId = MyDatabaseId;
6141 : 15 : xl_dbinfo.tsId = MyDatabaseTableSpace;
6142 : : }
6143 : :
6144 : : /*
6145 : : * Dump transaction origin information. We need this during recovery to
6146 : : * update the replication origin progress.
6147 : : */
281 msawada@postgresql.o 6148 [ + + ]: 9443 : if (replorigin_xact_state.origin != InvalidReplOriginId)
6149 : : {
3144 simon@2ndQuadrant.co 6150 : 27 : xl_xinfo.xinfo |= XACT_XINFO_HAS_ORIGIN;
6151 : :
281 msawada@postgresql.o 6152 : 27 : xl_origin.origin_lsn = replorigin_xact_state.origin_lsn;
6153 : 27 : xl_origin.origin_timestamp = replorigin_xact_state.origin_timestamp;
6154 : : }
6155 : :
4253 andres@anarazel.de 6156 [ + + ]: 9443 : if (xl_xinfo.xinfo != 0)
6157 : 5431 : info |= XLOG_XACT_HAS_INFO;
6158 : :
6159 : : /* Then include all the collected data into the abort record. */
6160 : :
6161 : 9443 : XLogBeginInsert();
6162 : :
632 peter@eisentraut.org 6163 : 9443 : XLogRegisterData(&xlrec, MinSizeOfXactAbort);
6164 : :
4253 andres@anarazel.de 6165 [ + + ]: 9443 : if (xl_xinfo.xinfo != 0)
632 peter@eisentraut.org 6166 : 5431 : XLogRegisterData(&xl_xinfo, sizeof(xl_xinfo));
6167 : :
3144 simon@2ndQuadrant.co 6168 [ + + ]: 9443 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_DBINFO)
632 peter@eisentraut.org 6169 : 15 : XLogRegisterData(&xl_dbinfo, sizeof(xl_dbinfo));
6170 : :
4253 andres@anarazel.de 6171 [ + + ]: 9443 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_SUBXACTS)
6172 : : {
632 peter@eisentraut.org 6173 : 110 : XLogRegisterData(&xl_subxacts,
6174 : : MinSizeOfXactSubxacts);
6175 : 110 : XLogRegisterData(subxacts,
6176 : : nsubxacts * sizeof(TransactionId));
6177 : : }
6178 : :
1583 rhaas@postgresql.org 6179 [ + + ]: 9443 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_RELFILELOCATORS)
6180 : : {
632 peter@eisentraut.org 6181 : 1426 : XLogRegisterData(&xl_relfilelocators,
6182 : : MinSizeOfXactRelfileLocators);
6183 : 1426 : XLogRegisterData(rels,
6184 : : nrels * sizeof(RelFileLocator));
6185 : : }
6186 : :
1674 andres@anarazel.de 6187 [ + + ]: 9443 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_DROPPED_STATS)
6188 : : {
632 peter@eisentraut.org 6189 : 1999 : XLogRegisterData(&xl_dropped_stats,
6190 : : MinSizeOfXactStatsItems);
6191 : 1999 : XLogRegisterData(droppedstats,
6192 : : ndroppedstats * sizeof(xl_xact_stats_item));
6193 : : }
6194 : :
4253 andres@anarazel.de 6195 [ + + ]: 9443 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_TWOPHASE)
6196 : : {
632 peter@eisentraut.org 6197 : 50 : XLogRegisterData(&xl_twophase, sizeof(xl_xact_twophase));
3144 simon@2ndQuadrant.co 6198 [ + + ]: 50 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_GID)
793 peter@eisentraut.org 6199 : 15 : XLogRegisterData(twophase_gid, strlen(twophase_gid) + 1);
6200 : : }
6201 : :
3144 simon@2ndQuadrant.co 6202 [ + + ]: 9443 : if (xl_xinfo.xinfo & XACT_XINFO_HAS_ORIGIN)
632 peter@eisentraut.org 6203 : 27 : XLogRegisterData(&xl_origin, sizeof(xl_xact_origin));
6204 : :
6205 : : /* Include the replication origin */
1396 akapila@postgresql.o 6206 : 9443 : XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
6207 : :
4253 andres@anarazel.de 6208 : 9443 : return XLogInsert(RM_XACT_ID, info);
6209 : : }
6210 : :
6211 : : /*
6212 : : * Before 9.0 this was a fairly short function, but now it performs many
6213 : : * actions for which the order of execution is critical.
6214 : : */
6215 : : static void
6216 : 23666 : xact_redo_commit(xl_xact_parsed_commit *parsed,
6217 : : TransactionId xid,
6218 : : XLogRecPtr lsn,
6219 : : ReplOriginId origin_id)
6220 : : {
6221 : : TransactionId max_xid;
6222 : : TimestampTz commit_time;
6223 : :
3431 alvherre@alvh.no-ip. 6224 [ - + ]: 23666 : Assert(TransactionIdIsValid(xid));
6225 : :
4253 andres@anarazel.de 6226 : 23666 : max_xid = TransactionIdLatest(xid, parsed->nsubxacts, parsed->subxacts);
6227 : :
6228 : : /* Make sure nextXid is beyond any XID mentioned in the record. */
2779 tmunro@postgresql.or 6229 : 23666 : AdvanceNextFullTransactionIdPastXid(max_xid);
6230 : :
3875 andres@anarazel.de 6231 [ - + ]: 23666 : Assert(((parsed->xinfo & XACT_XINFO_HAS_ORIGIN) == 0) ==
6232 : : (origin_id == InvalidReplOriginId));
6233 : :
4208 6234 [ + + ]: 23666 : if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
6235 : 20 : commit_time = parsed->origin_timestamp;
6236 : : else
6237 : 23646 : commit_time = parsed->xact_time;
6238 : :
6239 : : /* Set the transaction commit timestamp and metadata */
4253 6240 : 23666 : TransactionTreeSetCommitTsData(xid, parsed->nsubxacts, parsed->subxacts,
6241 : : commit_time, origin_id);
6242 : :
6020 simon@2ndQuadrant.co 6243 [ + + ]: 23666 : if (standbyState == STANDBY_DISABLED)
6244 : : {
6245 : : /*
6246 : : * Mark the transaction committed in pg_xact.
6247 : : */
4253 andres@anarazel.de 6248 : 2226 : TransactionIdCommitTree(xid, parsed->nsubxacts, parsed->subxacts);
6249 : : }
6250 : : else
6251 : : {
6252 : : /*
6253 : : * If a transaction completion record arrives that has as-yet
6254 : : * unobserved subtransactions then this will not have been fully
6255 : : * handled by the call to RecordKnownAssignedTransactionIds() in the
6256 : : * main recovery loop in PerformWalRecovery(). So we need to do
6257 : : * bookkeeping again to cover that case. This is confusing and it is
6258 : : * easy to think this call is irrelevant, which has happened three
6259 : : * times in development already. Leave it in.
6260 : : */
6165 simon@2ndQuadrant.co 6261 : 21440 : RecordKnownAssignedTransactionIds(max_xid);
6262 : :
6263 : : /*
6264 : : * Mark the transaction committed in pg_xact. We use async commit
6265 : : * protocol during recovery to provide information on database
6266 : : * consistency for when users try to set hint bits. It is important
6267 : : * that we do not set hint bits until the minRecoveryPoint is past
6268 : : * this commit record. This ensures that if we crash we don't see hint
6269 : : * bits set on changes made by transactions that haven't yet
6270 : : * recovered. It's unlikely but it's good to be safe.
6271 : : */
2471 alvherre@alvh.no-ip. 6272 : 21440 : TransactionIdAsyncCommitTree(xid, parsed->nsubxacts, parsed->subxacts, lsn);
6273 : :
6274 : : /*
6275 : : * We must mark clog before we update the ProcArray.
6276 : : */
6277 : 21440 : ExpireTreeKnownAssignedTransactionIds(xid, parsed->nsubxacts, parsed->subxacts, max_xid);
6278 : :
6279 : : /*
6280 : : * Send any cache invalidations attached to the commit. We must
6281 : : * maintain the same order of invalidation then release locks as
6282 : : * occurs in CommitTransaction().
6283 : : */
6284 : 21440 : ProcessCommittedInvalidationMessages(parsed->msgs, parsed->nmsgs,
3424 tgl@sss.pgh.pa.us 6285 : 21440 : XactCompletionRelcacheInitFileInval(parsed->xinfo),
6286 : : parsed->dbId, parsed->tsId);
6287 : :
6288 : : /*
6289 : : * Release locks, if any. We do this for both two phase and normal one
6290 : : * phase transactions. In effect we are ignoring the prepare phase and
6291 : : * just going straight to lock release.
6292 : : */
3515 simon@2ndQuadrant.co 6293 [ + + ]: 21440 : if (parsed->xinfo & XACT_XINFO_HAS_AE_LOCKS)
3064 6294 : 10407 : StandbyReleaseLockTree(xid, parsed->nsubxacts, parsed->subxacts);
6295 : : }
6296 : :
4208 andres@anarazel.de 6297 [ + + ]: 23666 : if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
6298 : : {
6299 : : /* recover apply progress */
6300 : 20 : replorigin_advance(origin_id, parsed->origin_lsn, lsn,
6301 : : false /* backward */ , false /* WAL */ );
6302 : : }
6303 : :
6304 : : /* Make sure files supposed to be dropped are dropped */
4253 6305 [ + + ]: 23666 : if (parsed->nrels > 0)
6306 : : {
6307 : : /*
6308 : : * First update minimum recovery point to cover this WAL record. Once
6309 : : * a relation is deleted, there's no going back. The buffer manager
6310 : : * enforces the WAL-first rule for normal updates to relation files,
6311 : : * so that the minimum recovery point is always updated before the
6312 : : * corresponding change in the data file is flushed to disk, but we
6313 : : * have to do the same here since we're bypassing the buffer manager.
6314 : : *
6315 : : * Doing this before deleting the files means that if a deletion fails
6316 : : * for some reason, you cannot start up the system even after restart,
6317 : : * until you fix the underlying situation so that the deletion will
6318 : : * succeed. Alternatively, we could update the minimum recovery point
6319 : : * after deletion, but that would leave a small window where the
6320 : : * WAL-first rule would be violated.
6321 : : */
5078 heikki.linnakangas@i 6322 : 2255 : XLogFlush(lsn);
6323 : :
6324 : : /* Make sure files supposed to be dropped are dropped */
1583 rhaas@postgresql.org 6325 : 2255 : DropRelationFiles(parsed->xlocators, parsed->nrels, true);
6326 : : }
6327 : :
1674 andres@anarazel.de 6328 [ + + ]: 23666 : if (parsed->nstats > 0)
6329 : : {
6330 : : /* see equivalent call for relations above */
6331 : 2931 : XLogFlush(lsn);
6332 : :
6 nathan@postgresql.or 6333 :GNC 2931 : pgstat_execute_transactional_drops(parsed->nstats, parsed->stats);
6334 : : }
6335 : :
6336 : : /*
6337 : : * We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
6338 : : * in normal operation. For example, in CREATE DATABASE, we copy all files
6339 : : * from the template database, and then commit the transaction. If we
6340 : : * crash after all the files have been copied but before the commit, you
6341 : : * have files in the data directory without an entry in pg_database. To
6342 : : * minimize the window for that, we use ForceSyncCommit() to rush the
6343 : : * commit record to disk as quick as possible. We have the same window
6344 : : * during recovery, and forcing an XLogFlush() (which updates
6345 : : * minRecoveryPoint during recovery) helps to reduce that problem window,
6346 : : * for any user that requested ForceSyncCommit().
6347 : : */
4253 andres@anarazel.de 6348 [ + + ]:CBC 23666 : if (XactCompletionForceSyncCommit(parsed->xinfo))
6165 simon@2ndQuadrant.co 6349 : 51 : XLogFlush(lsn);
6350 : :
6351 : : /*
6352 : : * If asked by the primary (because someone is waiting for a synchronous
6353 : : * commit = remote_apply), we will need to ask walreceiver to send a reply
6354 : : * immediately.
6355 : : */
3873 rhaas@postgresql.org 6356 [ + + ]: 23666 : if (XactCompletionApplyFeedback(parsed->xinfo))
6357 : 3 : XLogRequestWalReceiverReply();
5609 simon@2ndQuadrant.co 6358 : 23666 : }
6359 : :
6360 : : /*
6361 : : * Be careful with the order of execution, as with xact_redo_commit().
6362 : : * The two functions are similar but differ in key places.
6363 : : *
6364 : : * Note also that an abort can be for a subtransaction and its children,
6365 : : * not just for a top level abort. That means we have to consider
6366 : : * topxid != xid, whereas in commit we would find topxid == xid always
6367 : : * because subtransaction commit is never WAL logged.
6368 : : */
6369 : : static void
2068 akapila@postgresql.o 6370 : 2022 : xact_redo_abort(xl_xact_parsed_abort *parsed, TransactionId xid,
6371 : : XLogRecPtr lsn, ReplOriginId origin_id)
6372 : : {
6373 : : TransactionId max_xid;
6374 : :
3431 alvherre@alvh.no-ip. 6375 [ - + ]: 2022 : Assert(TransactionIdIsValid(xid));
6376 : :
6377 : : /* Make sure nextXid is beyond any XID mentioned in the record. */
4253 andres@anarazel.de 6378 : 2022 : max_xid = TransactionIdLatest(xid,
6379 : : parsed->nsubxacts,
6380 : 2022 : parsed->subxacts);
2779 tmunro@postgresql.or 6381 : 2022 : AdvanceNextFullTransactionIdPastXid(max_xid);
6382 : :
6020 simon@2ndQuadrant.co 6383 [ + + ]: 2022 : if (standbyState == STANDBY_DISABLED)
6384 : : {
6385 : : /* Mark the transaction aborted in pg_xact, no need for async stuff */
4253 andres@anarazel.de 6386 : 20 : TransactionIdAbortTree(xid, parsed->nsubxacts, parsed->subxacts);
6387 : : }
6388 : : else
6389 : : {
6390 : : /*
6391 : : * If a transaction completion record arrives that has as-yet
6392 : : * unobserved subtransactions then this will not have been fully
6393 : : * handled by the call to RecordKnownAssignedTransactionIds() in the
6394 : : * main recovery loop in PerformWalRecovery(). So we need to do
6395 : : * bookkeeping again to cover that case. This is confusing and it is
6396 : : * easy to think this call is irrelevant, which has happened three
6397 : : * times in development already. Leave it in.
6398 : : */
6165 simon@2ndQuadrant.co 6399 : 2002 : RecordKnownAssignedTransactionIds(max_xid);
6400 : :
6401 : : /* Mark the transaction aborted in pg_xact, no need for async stuff */
4253 andres@anarazel.de 6402 : 2002 : TransactionIdAbortTree(xid, parsed->nsubxacts, parsed->subxacts);
6403 : :
6404 : : /*
6405 : : * We must update the ProcArray after we have marked clog.
6406 : : */
2471 alvherre@alvh.no-ip. 6407 : 2002 : ExpireTreeKnownAssignedTransactionIds(xid, parsed->nsubxacts, parsed->subxacts, max_xid);
6408 : :
6409 : : /*
6410 : : * There are no invalidation messages to send or undo.
6411 : : */
6412 : :
6413 : : /*
6414 : : * Release locks, if any. There are no invalidations to send.
6415 : : */
3515 simon@2ndQuadrant.co 6416 [ + + ]: 2002 : if (parsed->xinfo & XACT_XINFO_HAS_AE_LOCKS)
6417 : 1247 : StandbyReleaseLockTree(xid, parsed->nsubxacts, parsed->subxacts);
6418 : : }
6419 : :
2068 akapila@postgresql.o 6420 [ + + ]: 2022 : if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN)
6421 : : {
6422 : : /* recover apply progress */
6423 : 5 : replorigin_advance(origin_id, parsed->origin_lsn, lsn,
6424 : : false /* backward */ , false /* WAL */ );
6425 : : }
6426 : :
6427 : : /* Make sure files supposed to be dropped are dropped */
1925 fujii@postgresql.org 6428 [ + + ]: 2022 : if (parsed->nrels > 0)
6429 : : {
6430 : : /*
6431 : : * See comments about update of minimum recovery point on truncation,
6432 : : * in xact_redo_commit().
6433 : : */
6434 : 348 : XLogFlush(lsn);
6435 : :
1583 rhaas@postgresql.org 6436 : 348 : DropRelationFiles(parsed->xlocators, parsed->nrels, true);
6437 : : }
6438 : :
1674 andres@anarazel.de 6439 [ + + ]: 2022 : if (parsed->nstats > 0)
6440 : : {
6441 : : /* see equivalent call for relations above */
6442 : 473 : XLogFlush(lsn);
6443 : :
6 nathan@postgresql.or 6444 :GNC 473 : pgstat_execute_transactional_drops(parsed->nstats, parsed->stats);
6445 : : }
7811 tgl@sss.pgh.pa.us 6446 :CBC 2022 : }
6447 : :
6448 : : void
4368 heikki.linnakangas@i 6449 : 26074 : xact_redo(XLogReaderState *record)
6450 : : {
4253 andres@anarazel.de 6451 : 26074 : uint8 info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
6452 : :
6453 : : /* Backup blocks are not used in xact records */
4368 heikki.linnakangas@i 6454 [ - + ]: 26074 : Assert(!XLogRecHasAnyBlockRefs(record));
6455 : :
3431 alvherre@alvh.no-ip. 6456 [ + + ]: 26074 : if (info == XLOG_XACT_COMMIT)
6457 : : {
8303 tgl@sss.pgh.pa.us 6458 : 23620 : xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
6459 : : xl_xact_parsed_commit parsed;
6460 : :
3431 alvherre@alvh.no-ip. 6461 : 23620 : ParseCommitRecord(XLogRecGetInfo(record), xlrec, &parsed);
6462 : 23620 : xact_redo_commit(&parsed, XLogRecGetXid(record),
6463 : 23620 : record->EndRecPtr, XLogRecGetOrigin(record));
6464 : : }
6465 [ + + ]: 2454 : else if (info == XLOG_XACT_COMMIT_PREPARED)
6466 : : {
6467 : 46 : xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
6468 : : xl_xact_parsed_commit parsed;
6469 : :
6470 : 46 : ParseCommitRecord(XLogRecGetInfo(record), xlrec, &parsed);
6471 : 46 : xact_redo_commit(&parsed, parsed.twophase_xid,
6472 : 46 : record->EndRecPtr, XLogRecGetOrigin(record));
6473 : :
6474 : : /* Delete TwoPhaseState gxact entry and/or 2PC file. */
6475 : 46 : LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);
6476 : 46 : PrepareRedoRemove(parsed.twophase_xid, false);
6477 : 46 : LWLockRelease(TwoPhaseStateLock);
6478 : : }
6479 [ + + ]: 2408 : else if (info == XLOG_XACT_ABORT)
6480 : : {
7811 tgl@sss.pgh.pa.us 6481 : 1997 : xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
6482 : : xl_xact_parsed_abort parsed;
6483 : :
3431 alvherre@alvh.no-ip. 6484 : 1997 : ParseAbortRecord(XLogRecGetInfo(record), xlrec, &parsed);
2068 akapila@postgresql.o 6485 : 1997 : xact_redo_abort(&parsed, XLogRecGetXid(record),
6486 : 1997 : record->EndRecPtr, XLogRecGetOrigin(record));
6487 : : }
3431 alvherre@alvh.no-ip. 6488 [ + + ]: 411 : else if (info == XLOG_XACT_ABORT_PREPARED)
6489 : : {
6490 : 25 : xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
6491 : : xl_xact_parsed_abort parsed;
6492 : :
6493 : 25 : ParseAbortRecord(XLogRecGetInfo(record), xlrec, &parsed);
2068 akapila@postgresql.o 6494 : 25 : xact_redo_abort(&parsed, parsed.twophase_xid,
6495 : 25 : record->EndRecPtr, XLogRecGetOrigin(record));
6496 : :
6497 : : /* Delete TwoPhaseState gxact entry and/or 2PC file. */
3431 alvherre@alvh.no-ip. 6498 : 25 : LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);
6499 : 25 : PrepareRedoRemove(parsed.twophase_xid, false);
6500 : 25 : LWLockRelease(TwoPhaseStateLock);
6501 : : }
7811 tgl@sss.pgh.pa.us 6502 [ + + ]: 386 : else if (info == XLOG_XACT_PREPARE)
6503 : : {
6504 : : /*
6505 : : * Store xid and start/end pointers of the WAL record in TwoPhaseState
6506 : : * gxact entry.
6507 : : */
3431 alvherre@alvh.no-ip. 6508 : 82 : LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);
486 michael@paquier.xyz 6509 : 82 : PrepareRedoAdd(InvalidFullTransactionId,
6510 : 82 : XLogRecGetData(record),
6511 : : record->ReadRecPtr,
6512 : : record->EndRecPtr,
3144 simon@2ndQuadrant.co 6513 : 82 : XLogRecGetOrigin(record));
3431 alvherre@alvh.no-ip. 6514 : 82 : LWLockRelease(TwoPhaseStateLock);
6515 : : }
6165 simon@2ndQuadrant.co 6516 [ + + ]: 304 : else if (info == XLOG_XACT_ASSIGNMENT)
6517 : : {
6518 : 22 : xl_xact_assignment *xlrec = (xl_xact_assignment *) XLogRecGetData(record);
6519 : :
6020 6520 [ + - ]: 22 : if (standbyState >= STANDBY_INITIALIZED)
6165 6521 : 22 : ProcArrayApplyXidAssignment(xlrec->xtop,
6522 : 22 : xlrec->nsubxacts, xlrec->xsub);
6523 : : }
2296 akapila@postgresql.o 6524 [ - + ]: 282 : else if (info == XLOG_XACT_INVALIDATIONS)
6525 : : {
6526 : : /*
6527 : : * XXX we do ignore this for now, what matters are invalidations
6528 : : * written into the commit record.
6529 : : */
6530 : : }
6531 : : else
7811 tgl@sss.pgh.pa.us 6532 [ # # ]:UBC 0 : elog(PANIC, "xact_redo: unknown op code %u", info);
7811 tgl@sss.pgh.pa.us 6533 :CBC 26074 : }
|