1 /*-------------------------------------------------------------------------
4 * POSTGRES "time qualification" code, ie, tuple visibility rules.
6 * NOTE: all the HeapTupleSatisfies routines will update the tuple's
7 * "hint" status bits if we see that the inserting or deleting transaction
8 * has now committed or aborted (and it is safe to set the hint bits).
9 * If the hint bits are changed, SetBufferCommitInfoNeedsSave is called on
10 * the passed-in buffer. The caller must hold not only a pin, but at least
11 * shared buffer content lock on the buffer containing the tuple.
13 * NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array)
14 * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
15 * pg_clog). Otherwise we have a race condition: we might decide that a
16 * just-committed transaction crashed, because none of the tests succeed.
17 * xact.c is careful to record commit/abort in pg_clog before it unsets
18 * MyProc->xid in PGPROC array. That fixes that problem, but it also
19 * means there is a window where TransactionIdIsInProgress and
20 * TransactionIdDidCommit will both return true. If we check only
21 * TransactionIdDidCommit, we could consider a tuple committed when a
22 * later GetSnapshotData call will still think the originating transaction
23 * is in progress, which leads to application-level inconsistency. The
24 * upshot is that we gotta check TransactionIdIsInProgress first in all
25 * code paths, except for a few cases where we are looking at
26 * subtransactions of our own main transaction and so there can't be any
30 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
31 * Portions Copyright (c) 1994, Regents of the University of California
34 * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.106 2007/09/21 18:24:28 tgl Exp $
36 *-------------------------------------------------------------------------
41 #include "access/multixact.h"
42 #include "access/subtrans.h"
43 #include "access/transam.h"
44 #include "access/xact.h"
45 #include "storage/bufmgr.h"
46 #include "storage/procarray.h"
47 #include "utils/tqual.h"
50 /* Static variables representing various special snapshot semantics */
51 SnapshotData SnapshotNowData = {HeapTupleSatisfiesNow};
52 SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf};
53 SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny};
54 SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast};
57 * These SnapshotData structs are static to simplify memory allocation
58 * (see the hack in GetSnapshotData to avoid repeated malloc/free).
60 static SnapshotData SerializableSnapshotData = {HeapTupleSatisfiesMVCC};
61 static SnapshotData LatestSnapshotData = {HeapTupleSatisfiesMVCC};
63 /* Externally visible pointers to valid snapshots: */
64 Snapshot SerializableSnapshot = NULL;
65 Snapshot LatestSnapshot = NULL;
68 * This pointer is not maintained by this module, but it's convenient
69 * to declare it here anyway. Callers typically assign a copy of
70 * GetTransactionSnapshot's result to ActiveSnapshot.
72 Snapshot ActiveSnapshot = NULL;
75 * These are updated by GetSnapshotData. We initialize them this way
76 * for the convenience of TransactionIdIsInProgress: even in bootstrap
77 * mode, we don't want it to say that BootstrapTransactionId is in progress.
79 TransactionId TransactionXmin = FirstNormalTransactionId;
80 TransactionId RecentXmin = FirstNormalTransactionId;
81 TransactionId RecentGlobalXmin = FirstNormalTransactionId;
84 static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
90 * Set commit/abort hint bits on a tuple, if appropriate at this time.
92 * It is only safe to set a transaction-committed hint bit if we know the
93 * transaction's commit record has been flushed to disk. We cannot change
94 * the LSN of the page here because we may hold only a share lock on the
95 * buffer, so we can't use the LSN to interlock this; we have to just refrain
96 * from setting the hint bit until some future re-examination of the tuple.
98 * We can always set hint bits when marking a transaction aborted. (Some
99 * code in heapam.c relies on that!)
101 * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
102 * we can always set the hint bits, since VACUUM FULL always uses synchronous
103 * commits and doesn't move tuples that weren't previously hinted. (This is
104 * not known by this subroutine, but is applied by its callers.)
106 * Normal commits may be asynchronous, so for those we need to get the LSN
107 * of the transaction and then check whether this is flushed.
109 * The caller should pass xid as the XID of the transaction to check, or
110 * InvalidTransactionId if no check is needed.
113 SetHintBits(HeapTupleHeader tuple, Buffer buffer,
114 uint16 infomask, TransactionId xid)
116 if (TransactionIdIsValid(xid))
118 /* NB: xid must be known committed here! */
119 XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
121 if (XLogNeedsFlush(commitLSN))
122 return; /* not flushed yet, so don't set hint */
125 tuple->t_infomask |= infomask;
126 SetBufferCommitInfoNeedsSave(buffer);
130 * HeapTupleSetHintBits --- exported version of SetHintBits()
132 * This must be separate because of C99's brain-dead notions about how to
133 * implement inline functions.
136 HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
137 uint16 infomask, TransactionId xid)
139 SetHintBits(tuple, buffer, infomask, xid);
144 * HeapTupleSatisfiesSelf
145 * True iff heap tuple is valid "for itself".
147 * Here, we consider the effects of:
148 * all committed transactions (as of the current instant)
149 * previous commands of this transaction
150 * changes made by the current command
153 * Assumes heap tuple is valid.
155 * The satisfaction of "itself" requires the following:
157 * ((Xmin == my-transaction && the row was updated by the current transaction, and
158 * (Xmax is null it was not deleted
159 * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
162 * (Xmin is committed && the row was modified by a committed transaction, and
163 * (Xmax is null || the row has not been deleted, or
164 * (Xmax != my-transaction && the row was deleted by another transaction
165 * Xmax is not committed))) that has not been committed
168 HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
170 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
172 if (tuple->t_infomask & HEAP_XMIN_INVALID)
175 if (tuple->t_infomask & HEAP_MOVED_OFF)
177 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
179 if (TransactionIdIsCurrentTransactionId(xvac))
181 if (!TransactionIdIsInProgress(xvac))
183 if (TransactionIdDidCommit(xvac))
185 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
186 InvalidTransactionId);
189 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
190 InvalidTransactionId);
193 else if (tuple->t_infomask & HEAP_MOVED_IN)
195 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
197 if (!TransactionIdIsCurrentTransactionId(xvac))
199 if (TransactionIdIsInProgress(xvac))
201 if (TransactionIdDidCommit(xvac))
202 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
203 InvalidTransactionId);
206 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
207 InvalidTransactionId);
212 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
214 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
217 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
220 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
222 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
224 /* deleting subtransaction must have aborted */
225 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
226 InvalidTransactionId);
232 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
234 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
235 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
236 HeapTupleHeaderGetXmin(tuple));
239 /* it must have aborted or crashed */
240 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
241 InvalidTransactionId);
246 /* by here, the inserting transaction has committed */
248 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
251 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
253 if (tuple->t_infomask & HEAP_IS_LOCKED)
255 return false; /* updated by other */
258 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
260 /* MultiXacts are currently only allowed to lock tuples */
261 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
265 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
267 if (tuple->t_infomask & HEAP_IS_LOCKED)
272 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
275 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
277 /* it must have aborted or crashed */
278 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
279 InvalidTransactionId);
283 /* xmax transaction committed */
285 if (tuple->t_infomask & HEAP_IS_LOCKED)
287 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
288 InvalidTransactionId);
292 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
293 HeapTupleHeaderGetXmax(tuple));
298 * HeapTupleSatisfiesNow
299 * True iff heap tuple is valid "now".
301 * Here, we consider the effects of:
302 * all committed transactions (as of the current instant)
303 * previous commands of this transaction
305 * Note we do _not_ include changes made by the current command. This
306 * solves the "Halloween problem" wherein an UPDATE might try to re-update
307 * its own output tuples.
310 * Assumes heap tuple is valid.
312 * The satisfaction of "now" requires the following:
314 * ((Xmin == my-transaction && inserted by the current transaction
315 * Cmin < my-command && before this command, and
316 * (Xmax is null || the row has not been deleted, or
317 * (Xmax == my-transaction && it was deleted by the current transaction
318 * Cmax >= my-command))) but not before this command,
320 * (Xmin is committed && the row was inserted by a committed transaction, and
321 * (Xmax is null || the row has not been deleted, or
322 * (Xmax == my-transaction && the row is being deleted by this transaction
323 * Cmax >= my-command) || but it's not deleted "yet", or
324 * (Xmax != my-transaction && the row was deleted by another transaction
325 * Xmax is not committed)))) that has not been committed
327 * mao says 17 march 1993: the tests in this routine are correct;
328 * if you think they're not, you're wrong, and you should think
329 * about it again. i know, it happened to me. we don't need to
330 * check commit time against the start time of this transaction
331 * because 2ph locking protects us from doing the wrong thing.
332 * if you mess around here, you'll break serializability. the only
333 * problem with this code is that it does the wrong thing for system
334 * catalog updates, because the catalogs aren't subject to 2ph, so
335 * the serializability guarantees we provide don't extend to xacts
336 * that do catalog accesses. this is unfortunate, but not critical.
339 HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
341 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
343 if (tuple->t_infomask & HEAP_XMIN_INVALID)
346 if (tuple->t_infomask & HEAP_MOVED_OFF)
348 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
350 if (TransactionIdIsCurrentTransactionId(xvac))
352 if (!TransactionIdIsInProgress(xvac))
354 if (TransactionIdDidCommit(xvac))
356 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
357 InvalidTransactionId);
360 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
361 InvalidTransactionId);
364 else if (tuple->t_infomask & HEAP_MOVED_IN)
366 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
368 if (!TransactionIdIsCurrentTransactionId(xvac))
370 if (TransactionIdIsInProgress(xvac))
372 if (TransactionIdDidCommit(xvac))
373 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
374 InvalidTransactionId);
377 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
378 InvalidTransactionId);
383 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
385 if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId())
386 return false; /* inserted after scan started */
388 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
391 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
394 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
396 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
398 /* deleting subtransaction must have aborted */
399 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
400 InvalidTransactionId);
404 if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
405 return true; /* deleted after scan started */
407 return false; /* deleted before scan started */
409 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
411 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
412 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
413 HeapTupleHeaderGetXmin(tuple));
416 /* it must have aborted or crashed */
417 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
418 InvalidTransactionId);
423 /* by here, the inserting transaction has committed */
425 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
428 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
430 if (tuple->t_infomask & HEAP_IS_LOCKED)
435 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
437 /* MultiXacts are currently only allowed to lock tuples */
438 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
442 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
444 if (tuple->t_infomask & HEAP_IS_LOCKED)
446 if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
447 return true; /* deleted after scan started */
449 return false; /* deleted before scan started */
452 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
455 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
457 /* it must have aborted or crashed */
458 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
459 InvalidTransactionId);
463 /* xmax transaction committed */
465 if (tuple->t_infomask & HEAP_IS_LOCKED)
467 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
468 InvalidTransactionId);
472 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
473 HeapTupleHeaderGetXmax(tuple));
478 * HeapTupleSatisfiesAny
479 * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
482 HeapTupleSatisfiesAny(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
488 * HeapTupleSatisfiesToast
489 * True iff heap tuple is valid as a TOAST row.
491 * This is a simplified version that only checks for VACUUM moving conditions.
492 * It's appropriate for TOAST usage because TOAST really doesn't want to do
493 * its own time qual checks; if you can see the main table row that contains
494 * a TOAST reference, you should be able to see the TOASTed value. However,
495 * vacuuming a TOAST table is independent of the main table, and in case such
496 * a vacuum fails partway through, we'd better do this much checking.
498 * Among other things, this means you can't do UPDATEs of rows in a TOAST
502 HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot,
505 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
507 if (tuple->t_infomask & HEAP_XMIN_INVALID)
510 if (tuple->t_infomask & HEAP_MOVED_OFF)
512 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
514 if (TransactionIdIsCurrentTransactionId(xvac))
516 if (!TransactionIdIsInProgress(xvac))
518 if (TransactionIdDidCommit(xvac))
520 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
521 InvalidTransactionId);
524 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
525 InvalidTransactionId);
528 else if (tuple->t_infomask & HEAP_MOVED_IN)
530 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
532 if (!TransactionIdIsCurrentTransactionId(xvac))
534 if (TransactionIdIsInProgress(xvac))
536 if (TransactionIdDidCommit(xvac))
537 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
538 InvalidTransactionId);
541 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
542 InvalidTransactionId);
549 /* otherwise assume the tuple is valid for TOAST. */
554 * HeapTupleSatisfiesUpdate
556 * Same logic as HeapTupleSatisfiesNow, but returns a more detailed result
557 * code, since UPDATE needs to know more than "is it visible?". Also,
558 * tuples of my own xact are tested against the passed CommandId not
561 * The possible return codes are:
563 * HeapTupleInvisible: the tuple didn't exist at all when the scan started,
564 * e.g. it was created by a later CommandId.
566 * HeapTupleMayBeUpdated: The tuple is valid and visible, so it may be
569 * HeapTupleSelfUpdated: The tuple was updated by the current transaction,
570 * after the current scan started.
572 * HeapTupleUpdated: The tuple was updated by a committed transaction.
574 * HeapTupleBeingUpdated: The tuple is being updated by an in-progress
575 * transaction other than the current transaction. (Note: this includes
576 * the case where the tuple is share-locked by a MultiXact, even if the
577 * MultiXact includes the current transaction. Callers that want to
578 * distinguish that case must test for it themselves.)
581 HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
584 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
586 if (tuple->t_infomask & HEAP_XMIN_INVALID)
587 return HeapTupleInvisible;
589 if (tuple->t_infomask & HEAP_MOVED_OFF)
591 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
593 if (TransactionIdIsCurrentTransactionId(xvac))
594 return HeapTupleInvisible;
595 if (!TransactionIdIsInProgress(xvac))
597 if (TransactionIdDidCommit(xvac))
599 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
600 InvalidTransactionId);
601 return HeapTupleInvisible;
603 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
604 InvalidTransactionId);
607 else if (tuple->t_infomask & HEAP_MOVED_IN)
609 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
611 if (!TransactionIdIsCurrentTransactionId(xvac))
613 if (TransactionIdIsInProgress(xvac))
614 return HeapTupleInvisible;
615 if (TransactionIdDidCommit(xvac))
616 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
617 InvalidTransactionId);
620 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
621 InvalidTransactionId);
622 return HeapTupleInvisible;
626 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
628 if (HeapTupleHeaderGetCmin(tuple) >= curcid)
629 return HeapTupleInvisible; /* inserted after scan started */
631 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
632 return HeapTupleMayBeUpdated;
634 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
635 return HeapTupleMayBeUpdated;
637 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
639 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
641 /* deleting subtransaction must have aborted */
642 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
643 InvalidTransactionId);
644 return HeapTupleMayBeUpdated;
647 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
648 return HeapTupleSelfUpdated; /* updated after scan started */
650 return HeapTupleInvisible; /* updated before scan started */
652 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
653 return HeapTupleInvisible;
654 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
655 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
656 HeapTupleHeaderGetXmin(tuple));
659 /* it must have aborted or crashed */
660 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
661 InvalidTransactionId);
662 return HeapTupleInvisible;
666 /* by here, the inserting transaction has committed */
668 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
669 return HeapTupleMayBeUpdated;
671 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
673 if (tuple->t_infomask & HEAP_IS_LOCKED)
674 return HeapTupleMayBeUpdated;
675 return HeapTupleUpdated; /* updated by other */
678 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
680 /* MultiXacts are currently only allowed to lock tuples */
681 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
683 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
684 return HeapTupleBeingUpdated;
685 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
686 InvalidTransactionId);
687 return HeapTupleMayBeUpdated;
690 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
692 if (tuple->t_infomask & HEAP_IS_LOCKED)
693 return HeapTupleMayBeUpdated;
694 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
695 return HeapTupleSelfUpdated; /* updated after scan started */
697 return HeapTupleInvisible; /* updated before scan started */
700 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
701 return HeapTupleBeingUpdated;
703 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
705 /* it must have aborted or crashed */
706 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
707 InvalidTransactionId);
708 return HeapTupleMayBeUpdated;
711 /* xmax transaction committed */
713 if (tuple->t_infomask & HEAP_IS_LOCKED)
715 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
716 InvalidTransactionId);
717 return HeapTupleMayBeUpdated;
720 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
721 HeapTupleHeaderGetXmax(tuple));
722 return HeapTupleUpdated; /* updated by other */
726 * HeapTupleSatisfiesDirty
727 * True iff heap tuple is valid including effects of open transactions.
729 * Here, we consider the effects of:
730 * all committed and in-progress transactions (as of the current instant)
731 * previous commands of this transaction
732 * changes made by the current command
734 * This is essentially like HeapTupleSatisfiesSelf as far as effects of
735 * the current transaction and committed/aborted xacts are concerned.
736 * However, we also include the effects of other xacts still in progress.
738 * A special hack is that the passed-in snapshot struct is used as an
739 * output argument to return the xids of concurrent xacts that affected the
740 * tuple. snapshot->xmin is set to the tuple's xmin if that is another
741 * transaction that's still in progress; or to InvalidTransactionId if the
742 * tuple's xmin is committed good, committed dead, or my own xact. Similarly
743 * for snapshot->xmax and the tuple's xmax.
746 HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
749 snapshot->xmin = snapshot->xmax = InvalidTransactionId;
751 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
753 if (tuple->t_infomask & HEAP_XMIN_INVALID)
756 if (tuple->t_infomask & HEAP_MOVED_OFF)
758 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
760 if (TransactionIdIsCurrentTransactionId(xvac))
762 if (!TransactionIdIsInProgress(xvac))
764 if (TransactionIdDidCommit(xvac))
766 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
767 InvalidTransactionId);
770 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
771 InvalidTransactionId);
774 else if (tuple->t_infomask & HEAP_MOVED_IN)
776 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
778 if (!TransactionIdIsCurrentTransactionId(xvac))
780 if (TransactionIdIsInProgress(xvac))
782 if (TransactionIdDidCommit(xvac))
783 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
784 InvalidTransactionId);
787 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
788 InvalidTransactionId);
793 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
795 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
798 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
801 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
803 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
805 /* deleting subtransaction must have aborted */
806 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
807 InvalidTransactionId);
813 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
815 snapshot->xmin = HeapTupleHeaderGetXmin(tuple);
816 /* XXX shouldn't we fall through to look at xmax? */
817 return true; /* in insertion by other */
819 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
820 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
821 HeapTupleHeaderGetXmin(tuple));
824 /* it must have aborted or crashed */
825 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
826 InvalidTransactionId);
831 /* by here, the inserting transaction has committed */
833 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
836 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
838 if (tuple->t_infomask & HEAP_IS_LOCKED)
840 return false; /* updated by other */
843 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
845 /* MultiXacts are currently only allowed to lock tuples */
846 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
850 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
852 if (tuple->t_infomask & HEAP_IS_LOCKED)
857 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
859 snapshot->xmax = HeapTupleHeaderGetXmax(tuple);
863 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
865 /* it must have aborted or crashed */
866 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
867 InvalidTransactionId);
871 /* xmax transaction committed */
873 if (tuple->t_infomask & HEAP_IS_LOCKED)
875 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
876 InvalidTransactionId);
880 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
881 HeapTupleHeaderGetXmax(tuple));
882 return false; /* updated by other */
886 * HeapTupleSatisfiesMVCC
887 * True iff heap tuple is valid for the given MVCC snapshot.
889 * Here, we consider the effects of:
890 * all transactions committed as of the time of the given snapshot
891 * previous commands of this transaction
893 * Does _not_ include:
894 * transactions shown as in-progress by the snapshot
895 * transactions started after the snapshot was taken
896 * changes made by the current command
898 * This is the same as HeapTupleSatisfiesNow, except that transactions that
899 * were in progress or as yet unstarted when the snapshot was taken will
900 * be treated as uncommitted, even if they have committed by now.
902 * (Notice, however, that the tuple status hint bits will be updated on the
903 * basis of the true state of the transaction, even if we then pretend we
907 HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
910 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
912 if (tuple->t_infomask & HEAP_XMIN_INVALID)
915 if (tuple->t_infomask & HEAP_MOVED_OFF)
917 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
919 if (TransactionIdIsCurrentTransactionId(xvac))
921 if (!TransactionIdIsInProgress(xvac))
923 if (TransactionIdDidCommit(xvac))
925 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
926 InvalidTransactionId);
929 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
930 InvalidTransactionId);
933 else if (tuple->t_infomask & HEAP_MOVED_IN)
935 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
937 if (!TransactionIdIsCurrentTransactionId(xvac))
939 if (TransactionIdIsInProgress(xvac))
941 if (TransactionIdDidCommit(xvac))
942 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
943 InvalidTransactionId);
946 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
947 InvalidTransactionId);
952 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
954 if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
955 return false; /* inserted after scan started */
957 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
960 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
963 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
965 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
967 /* deleting subtransaction must have aborted */
968 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
969 InvalidTransactionId);
973 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
974 return true; /* deleted after scan started */
976 return false; /* deleted before scan started */
978 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
980 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
981 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
982 HeapTupleHeaderGetXmin(tuple));
985 /* it must have aborted or crashed */
986 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
987 InvalidTransactionId);
993 * By here, the inserting transaction has committed - have to check
996 if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot))
997 return false; /* treat as still in progress */
999 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1002 if (tuple->t_infomask & HEAP_IS_LOCKED)
1005 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1007 /* MultiXacts are currently only allowed to lock tuples */
1008 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
1012 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1014 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
1016 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1017 return true; /* deleted after scan started */
1019 return false; /* deleted before scan started */
1022 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1025 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
1027 /* it must have aborted or crashed */
1028 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1029 InvalidTransactionId);
1033 /* xmax transaction committed */
1034 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1035 HeapTupleHeaderGetXmax(tuple));
1039 * OK, the deleting transaction committed too ... but when?
1041 if (XidInMVCCSnapshot(HeapTupleHeaderGetXmax(tuple), snapshot))
1042 return true; /* treat as still in progress */
1049 * HeapTupleSatisfiesVacuum
1051 * Determine the status of tuples for VACUUM purposes. Here, what
1052 * we mainly want to know is if a tuple is potentially visible to *any*
1053 * running transaction. If so, it can't be removed yet by VACUUM.
1055 * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples
1056 * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
1057 * still be visible to some open transaction, so we can't remove them,
1058 * even if we see that the deleting transaction has committed.
1061 HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
1065 * Has inserting transaction committed?
1067 * If the inserting transaction aborted, then the tuple was never visible
1068 * to any other transaction, so we can delete it immediately.
1070 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
1072 if (tuple->t_infomask & HEAP_XMIN_INVALID)
1073 return HEAPTUPLE_DEAD;
1074 else if (tuple->t_infomask & HEAP_MOVED_OFF)
1076 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1078 if (TransactionIdIsCurrentTransactionId(xvac))
1079 return HEAPTUPLE_DELETE_IN_PROGRESS;
1080 if (TransactionIdIsInProgress(xvac))
1081 return HEAPTUPLE_DELETE_IN_PROGRESS;
1082 if (TransactionIdDidCommit(xvac))
1084 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1085 InvalidTransactionId);
1086 return HEAPTUPLE_DEAD;
1088 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1089 InvalidTransactionId);
1091 else if (tuple->t_infomask & HEAP_MOVED_IN)
1093 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1095 if (TransactionIdIsCurrentTransactionId(xvac))
1096 return HEAPTUPLE_INSERT_IN_PROGRESS;
1097 if (TransactionIdIsInProgress(xvac))
1098 return HEAPTUPLE_INSERT_IN_PROGRESS;
1099 if (TransactionIdDidCommit(xvac))
1100 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1101 InvalidTransactionId);
1104 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1105 InvalidTransactionId);
1106 return HEAPTUPLE_DEAD;
1109 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
1111 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1112 return HEAPTUPLE_INSERT_IN_PROGRESS;
1113 if (tuple->t_infomask & HEAP_IS_LOCKED)
1114 return HEAPTUPLE_INSERT_IN_PROGRESS;
1115 /* inserted and then deleted by same xact */
1116 return HEAPTUPLE_DELETE_IN_PROGRESS;
1118 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
1119 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1120 HeapTupleHeaderGetXmin(tuple));
1124 * Not in Progress, Not Committed, so either Aborted or crashed
1126 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1127 InvalidTransactionId);
1128 return HEAPTUPLE_DEAD;
1131 * At this point the xmin is known committed, but we might not have
1132 * been able to set the hint bit yet; so we can no longer Assert
1138 * Okay, the inserter committed, so it was good at some point. Now what
1139 * about the deleting transaction?
1141 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1142 return HEAPTUPLE_LIVE;
1144 if (tuple->t_infomask & HEAP_IS_LOCKED)
1147 * "Deleting" xact really only locked it, so the tuple is live in any
1148 * case. However, we should make sure that either XMAX_COMMITTED or
1149 * XMAX_INVALID gets set once the xact is gone, to reduce the costs
1150 * of examining the tuple for future xacts. Also, marking dead
1151 * MultiXacts as invalid here provides defense against MultiXactId
1152 * wraparound (see also comments in heap_freeze_tuple()).
1154 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1156 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1158 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
1159 return HEAPTUPLE_LIVE;
1163 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1164 return HEAPTUPLE_LIVE;
1168 * We don't really care whether xmax did commit, abort or crash.
1169 * We know that xmax did lock the tuple, but it did not and will
1170 * never actually update it.
1172 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1173 InvalidTransactionId);
1175 return HEAPTUPLE_LIVE;
1178 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1180 /* MultiXacts are currently only allowed to lock tuples */
1181 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
1182 return HEAPTUPLE_LIVE;
1185 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1187 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1188 return HEAPTUPLE_DELETE_IN_PROGRESS;
1189 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
1190 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1191 HeapTupleHeaderGetXmax(tuple));
1195 * Not in Progress, Not Committed, so either Aborted or crashed
1197 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1198 InvalidTransactionId);
1199 return HEAPTUPLE_LIVE;
1202 * At this point the xmax is known committed, but we might not have
1203 * been able to set the hint bit yet; so we can no longer Assert
1209 * Deleter committed, but check special cases.
1212 if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),
1213 HeapTupleHeaderGetXmax(tuple)))
1216 * Inserter also deleted it, so it was never visible to anyone else.
1217 * However, we can only remove it early if it's not an updated tuple;
1218 * else its parent tuple is linking to it via t_ctid, and this tuple
1219 * mustn't go away before the parent does.
1221 if (!(tuple->t_infomask & HEAP_UPDATED))
1222 return HEAPTUPLE_DEAD;
1225 if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin))
1227 /* deleting xact is too recent, tuple could still be visible */
1228 return HEAPTUPLE_RECENTLY_DEAD;
1231 /* Otherwise, it's dead and removable */
1232 return HEAPTUPLE_DEAD;
1237 * GetTransactionSnapshot
1238 * Get the appropriate snapshot for a new query in a transaction.
1240 * The SerializableSnapshot is the first one taken in a transaction.
1241 * In serializable mode we just use that one throughout the transaction.
1242 * In read-committed mode, we take a new snapshot each time we are called.
1244 * Note that the return value points at static storage that will be modified
1245 * by future calls and by CommandCounterIncrement(). Callers should copy
1246 * the result with CopySnapshot() if it is to be used very long.
1249 GetTransactionSnapshot(void)
1251 /* First call in transaction? */
1252 if (SerializableSnapshot == NULL)
1254 SerializableSnapshot = GetSnapshotData(&SerializableSnapshotData, true);
1255 return SerializableSnapshot;
1258 if (IsXactIsoLevelSerializable)
1259 return SerializableSnapshot;
1261 LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false);
1263 return LatestSnapshot;
1268 * Get a snapshot that is up-to-date as of the current instant,
1269 * even if we are executing in SERIALIZABLE mode.
1272 GetLatestSnapshot(void)
1274 /* Should not be first call in transaction */
1275 if (SerializableSnapshot == NULL)
1276 elog(ERROR, "no snapshot has been set");
1278 LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false);
1280 return LatestSnapshot;
1285 * Copy the given snapshot.
1287 * The copy is palloc'd in the current memory context.
1290 CopySnapshot(Snapshot snapshot)
1296 /* We allocate any XID arrays needed in the same palloc block. */
1297 size = subxipoff = sizeof(SnapshotData) +
1298 snapshot->xcnt * sizeof(TransactionId);
1299 if (snapshot->subxcnt > 0)
1300 size += snapshot->subxcnt * sizeof(TransactionId);
1302 newsnap = (Snapshot) palloc(size);
1303 memcpy(newsnap, snapshot, sizeof(SnapshotData));
1305 /* setup XID array */
1306 if (snapshot->xcnt > 0)
1308 newsnap->xip = (TransactionId *) (newsnap + 1);
1309 memcpy(newsnap->xip, snapshot->xip,
1310 snapshot->xcnt * sizeof(TransactionId));
1313 newsnap->xip = NULL;
1315 /* setup subXID array */
1316 if (snapshot->subxcnt > 0)
1318 newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff);
1319 memcpy(newsnap->subxip, snapshot->subxip,
1320 snapshot->subxcnt * sizeof(TransactionId));
1323 newsnap->subxip = NULL;
1330 * Free a snapshot previously copied with CopySnapshot.
1332 * This is currently identical to pfree, but is provided for cleanliness.
1334 * Do *not* apply this to the results of GetTransactionSnapshot or
1335 * GetLatestSnapshot, since those are just static structs.
1338 FreeSnapshot(Snapshot snapshot)
1345 * Free snapshot(s) at end of transaction.
1348 FreeXactSnapshot(void)
1351 * We do not free the xip arrays for the static snapshot structs; they
1352 * will be reused soon. So this is now just a state change to prevent
1353 * outside callers from accessing the snapshots.
1355 SerializableSnapshot = NULL;
1356 LatestSnapshot = NULL;
1357 ActiveSnapshot = NULL; /* just for cleanliness */
1362 * Is the given XID still-in-progress according to the snapshot?
1364 * Note: GetSnapshotData never stores either top xid or subxids of our own
1365 * backend into a snapshot, so these xids will not be reported as "running"
1366 * by this function. This is OK for current uses, because we actually only
1367 * apply this for known-committed XIDs.
1370 XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
1375 * Make a quick range check to eliminate most XIDs without looking at the
1376 * xip arrays. Note that this is OK even if we convert a subxact XID to
1377 * its parent below, because a subxact with XID < xmin has surely also got
1378 * a parent with XID < xmin, while one with XID >= xmax must belong to a
1379 * parent that was not yet committed at the time of this snapshot.
1382 /* Any xid < xmin is not in-progress */
1383 if (TransactionIdPrecedes(xid, snapshot->xmin))
1385 /* Any xid >= xmax is in-progress */
1386 if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
1390 * If the snapshot contains full subxact data, the fastest way to check
1391 * things is just to compare the given XID against both subxact XIDs and
1392 * top-level XIDs. If the snapshot overflowed, we have to use pg_subtrans
1393 * to convert a subxact XID to its parent XID, but then we need only look
1394 * at top-level XIDs not subxacts.
1396 if (snapshot->subxcnt >= 0)
1398 /* full data, so search subxip */
1401 for (j = 0; j < snapshot->subxcnt; j++)
1403 if (TransactionIdEquals(xid, snapshot->subxip[j]))
1407 /* not there, fall through to search xip[] */
1411 /* overflowed, so convert xid to top-level */
1412 xid = SubTransGetTopmostTransaction(xid);
1415 * If xid was indeed a subxact, we might now have an xid < xmin, so
1416 * recheck to avoid an array scan. No point in rechecking xmax.
1418 if (TransactionIdPrecedes(xid, snapshot->xmin))
1422 for (i = 0; i < snapshot->xcnt; i++)
1424 if (TransactionIdEquals(xid, snapshot->xip[i]))