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, MarkBufferDirtyHint 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: When using a non-MVCC snapshot, we must check
14 * TransactionIdIsInProgress (which looks in the PGXACT array)
15 * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
16 * pg_clog). Otherwise we have a race condition: we might decide that a
17 * just-committed transaction crashed, because none of the tests succeed.
18 * xact.c is careful to record commit/abort in pg_clog before it unsets
19 * MyPgXact->xid in the PGXACT array. That fixes that problem, but it
20 * also means there is a window where TransactionIdIsInProgress and
21 * TransactionIdDidCommit will both return true. If we check only
22 * TransactionIdDidCommit, we could consider a tuple committed when a
23 * later GetSnapshotData call will still think the originating transaction
24 * is in progress, which leads to application-level inconsistency. The
25 * upshot is that we gotta check TransactionIdIsInProgress first in all
26 * code paths, except for a few cases where we are looking at
27 * subtransactions of our own main transaction and so there can't be any
30 * When using an MVCC snapshot, we rely on XidInMVCCSnapshot rather than
31 * TransactionIdIsInProgress, but the logic is otherwise the same: do not
32 * check pg_clog until after deciding that the xact is no longer in progress.
35 * Summary of visibility functions:
37 * HeapTupleSatisfiesMVCC()
38 * visible to supplied snapshot, excludes current command
39 * HeapTupleSatisfiesUpdate()
40 * visible to instant snapshot, with user-supplied command
41 * counter and more complex result
42 * HeapTupleSatisfiesSelf()
43 * visible to instant snapshot and current command
44 * HeapTupleSatisfiesDirty()
45 * like HeapTupleSatisfiesSelf(), but includes open transactions
46 * HeapTupleSatisfiesVacuum()
47 * visible to any running transaction, used by VACUUM
48 * HeapTupleSatisfiesToast()
49 * visible unless part of interrupted vacuum, used for TOAST
50 * HeapTupleSatisfiesAny()
51 * all tuples are visible
53 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
54 * Portions Copyright (c) 1994, Regents of the University of California
57 * src/backend/utils/time/tqual.c
59 *-------------------------------------------------------------------------
64 #include "access/htup_details.h"
65 #include "access/multixact.h"
66 #include "access/subtrans.h"
67 #include "access/transam.h"
68 #include "access/xact.h"
69 #include "access/xlog.h"
70 #include "storage/bufmgr.h"
71 #include "storage/procarray.h"
72 #include "utils/builtins.h"
73 #include "utils/combocid.h"
74 #include "utils/snapmgr.h"
75 #include "utils/tqual.h"
78 /* Static variables representing various special snapshot semantics */
79 SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf};
80 SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny};
81 SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast};
84 static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
89 * Set commit/abort hint bits on a tuple, if appropriate at this time.
91 * It is only safe to set a transaction-committed hint bit if we know the
92 * transaction's commit record has been flushed to disk, or if the table is
93 * temporary or unlogged and will be obliterated by a crash anyway. We
94 * cannot change the LSN of the page here because we may hold only a share
95 * lock on the buffer, so we can't use the LSN to interlock this; we have to
96 * just refrain from setting the hint bit until some future re-examination
99 * We can always set hint bits when marking a transaction aborted. (Some
100 * code in heapam.c relies on that!)
102 * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
103 * we can always set the hint bits, since pre-9.0 VACUUM FULL always used
104 * synchronous commits and didn't move tuples that weren't previously
105 * hinted. (This is not known by this subroutine, but is applied by its
106 * callers.) Note: old-style VACUUM FULL is gone, but we have to keep this
107 * module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
108 * support in-place update from pre-9.0 databases.
110 * Normal commits may be asynchronous, so for those we need to get the LSN
111 * of the transaction and then check whether this is flushed.
113 * The caller should pass xid as the XID of the transaction to check, or
114 * InvalidTransactionId if no check is needed.
117 SetHintBits(HeapTupleHeader tuple, Buffer buffer,
118 uint16 infomask, TransactionId xid)
120 if (TransactionIdIsValid(xid))
122 /* NB: xid must be known committed here! */
123 XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
125 if (XLogNeedsFlush(commitLSN) && BufferIsPermanent(buffer))
126 return; /* not flushed yet, so don't set hint */
129 tuple->t_infomask |= infomask;
130 MarkBufferDirtyHint(buffer, true);
134 * HeapTupleSetHintBits --- exported version of SetHintBits()
136 * This must be separate because of C99's brain-dead notions about how to
137 * implement inline functions.
140 HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
141 uint16 infomask, TransactionId xid)
143 SetHintBits(tuple, buffer, infomask, xid);
148 * HeapTupleSatisfiesSelf
149 * True iff heap tuple is valid "for itself".
151 * Here, we consider the effects of:
152 * all committed transactions (as of the current instant)
153 * previous commands of this transaction
154 * changes made by the current command
157 * Assumes heap tuple is valid.
159 * The satisfaction of "itself" requires the following:
161 * ((Xmin == my-transaction && the row was updated by the current transaction, and
162 * (Xmax is null it was not deleted
163 * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
166 * (Xmin is committed && the row was modified by a committed transaction, and
167 * (Xmax is null || the row has not been deleted, or
168 * (Xmax != my-transaction && the row was deleted by another transaction
169 * Xmax is not committed))) that has not been committed
172 HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
174 HeapTupleHeader tuple = htup->t_data;
176 Assert(ItemPointerIsValid(&htup->t_self));
177 Assert(htup->t_tableOid != InvalidOid);
179 if (!HeapTupleHeaderXminCommitted(tuple))
181 if (HeapTupleHeaderXminInvalid(tuple))
184 /* Used by pre-9.0 binary upgrades */
185 if (tuple->t_infomask & HEAP_MOVED_OFF)
187 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
189 if (TransactionIdIsCurrentTransactionId(xvac))
191 if (!TransactionIdIsInProgress(xvac))
193 if (TransactionIdDidCommit(xvac))
195 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
196 InvalidTransactionId);
199 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
200 InvalidTransactionId);
203 /* Used by pre-9.0 binary upgrades */
204 else if (tuple->t_infomask & HEAP_MOVED_IN)
206 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
208 if (!TransactionIdIsCurrentTransactionId(xvac))
210 if (TransactionIdIsInProgress(xvac))
212 if (TransactionIdDidCommit(xvac))
213 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
214 InvalidTransactionId);
217 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
218 InvalidTransactionId);
223 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
225 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
228 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
231 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
235 xmax = HeapTupleGetUpdateXid(tuple);
237 /* not LOCKED_ONLY, so it has to have an xmax */
238 Assert(TransactionIdIsValid(xmax));
240 /* updating subtransaction must have aborted */
241 if (!TransactionIdIsCurrentTransactionId(xmax))
247 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
249 /* deleting subtransaction must have aborted */
250 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
251 InvalidTransactionId);
257 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
259 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
260 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
261 HeapTupleHeaderGetRawXmin(tuple));
264 /* it must have aborted or crashed */
265 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
266 InvalidTransactionId);
271 /* by here, the inserting transaction has committed */
273 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
276 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
278 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
280 return false; /* updated by other */
283 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
287 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
290 xmax = HeapTupleGetUpdateXid(tuple);
292 /* not LOCKED_ONLY, so it has to have an xmax */
293 Assert(TransactionIdIsValid(xmax));
295 if (TransactionIdIsCurrentTransactionId(xmax))
297 if (TransactionIdIsInProgress(xmax))
299 if (TransactionIdDidCommit(xmax))
301 /* it must have aborted or crashed */
305 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
307 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
312 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
315 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
317 /* it must have aborted or crashed */
318 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
319 InvalidTransactionId);
323 /* xmax transaction committed */
325 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
327 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
328 InvalidTransactionId);
332 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
333 HeapTupleHeaderGetRawXmax(tuple));
338 * HeapTupleSatisfiesAny
339 * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
342 HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
348 * HeapTupleSatisfiesToast
349 * True iff heap tuple is valid as a TOAST row.
351 * This is a simplified version that only checks for VACUUM moving conditions.
352 * It's appropriate for TOAST usage because TOAST really doesn't want to do
353 * its own time qual checks; if you can see the main table row that contains
354 * a TOAST reference, you should be able to see the TOASTed value. However,
355 * vacuuming a TOAST table is independent of the main table, and in case such
356 * a vacuum fails partway through, we'd better do this much checking.
358 * Among other things, this means you can't do UPDATEs of rows in a TOAST
362 HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot,
365 HeapTupleHeader tuple = htup->t_data;
367 Assert(ItemPointerIsValid(&htup->t_self));
368 Assert(htup->t_tableOid != InvalidOid);
370 if (!HeapTupleHeaderXminCommitted(tuple))
372 if (HeapTupleHeaderXminInvalid(tuple))
375 /* Used by pre-9.0 binary upgrades */
376 if (tuple->t_infomask & HEAP_MOVED_OFF)
378 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
380 if (TransactionIdIsCurrentTransactionId(xvac))
382 if (!TransactionIdIsInProgress(xvac))
384 if (TransactionIdDidCommit(xvac))
386 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
387 InvalidTransactionId);
390 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
391 InvalidTransactionId);
394 /* Used by pre-9.0 binary upgrades */
395 else if (tuple->t_infomask & HEAP_MOVED_IN)
397 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
399 if (!TransactionIdIsCurrentTransactionId(xvac))
401 if (TransactionIdIsInProgress(xvac))
403 if (TransactionIdDidCommit(xvac))
404 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
405 InvalidTransactionId);
408 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
409 InvalidTransactionId);
416 * An invalid Xmin can be left behind by a speculative insertion that
417 * is cancelled by super-deleting the tuple. We shouldn't see any of
418 * those in TOAST tables, but better safe than sorry.
420 else if (!TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple)))
424 /* otherwise assume the tuple is valid for TOAST. */
429 * HeapTupleSatisfiesUpdate
431 * This function returns a more detailed result code than most of the
432 * functions in this file, since UPDATE needs to know more than "is it
433 * visible?". It also allows for user-supplied CommandId rather than
434 * relying on CurrentCommandId.
436 * The possible return codes are:
438 * HeapTupleInvisible: the tuple didn't exist at all when the scan started,
439 * e.g. it was created by a later CommandId.
441 * HeapTupleMayBeUpdated: The tuple is valid and visible, so it may be
444 * HeapTupleSelfUpdated: The tuple was updated by the current transaction,
445 * after the current scan started.
447 * HeapTupleUpdated: The tuple was updated by a committed transaction.
449 * HeapTupleBeingUpdated: The tuple is being updated by an in-progress
450 * transaction other than the current transaction. (Note: this includes
451 * the case where the tuple is share-locked by a MultiXact, even if the
452 * MultiXact includes the current transaction. Callers that want to
453 * distinguish that case must test for it themselves.)
456 HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
459 HeapTupleHeader tuple = htup->t_data;
461 Assert(ItemPointerIsValid(&htup->t_self));
462 Assert(htup->t_tableOid != InvalidOid);
464 if (!HeapTupleHeaderXminCommitted(tuple))
466 if (HeapTupleHeaderXminInvalid(tuple))
467 return HeapTupleInvisible;
469 /* Used by pre-9.0 binary upgrades */
470 if (tuple->t_infomask & HEAP_MOVED_OFF)
472 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
474 if (TransactionIdIsCurrentTransactionId(xvac))
475 return HeapTupleInvisible;
476 if (!TransactionIdIsInProgress(xvac))
478 if (TransactionIdDidCommit(xvac))
480 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
481 InvalidTransactionId);
482 return HeapTupleInvisible;
484 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
485 InvalidTransactionId);
488 /* Used by pre-9.0 binary upgrades */
489 else if (tuple->t_infomask & HEAP_MOVED_IN)
491 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
493 if (!TransactionIdIsCurrentTransactionId(xvac))
495 if (TransactionIdIsInProgress(xvac))
496 return HeapTupleInvisible;
497 if (TransactionIdDidCommit(xvac))
498 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
499 InvalidTransactionId);
502 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
503 InvalidTransactionId);
504 return HeapTupleInvisible;
508 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
510 if (HeapTupleHeaderGetCmin(tuple) >= curcid)
511 return HeapTupleInvisible; /* inserted after scan started */
513 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
514 return HeapTupleMayBeUpdated;
516 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
520 xmax = HeapTupleHeaderGetRawXmax(tuple);
523 * Careful here: even though this tuple was created by our own
524 * transaction, it might be locked by other transactions, if
525 * the original version was key-share locked when we updated
529 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
531 if (MultiXactIdIsRunning(xmax, true))
532 return HeapTupleBeingUpdated;
534 return HeapTupleMayBeUpdated;
538 * If the locker is gone, then there is nothing of interest
539 * left in this Xmax; otherwise, report the tuple as
542 if (!TransactionIdIsInProgress(xmax))
543 return HeapTupleMayBeUpdated;
544 return HeapTupleBeingUpdated;
547 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
551 xmax = HeapTupleGetUpdateXid(tuple);
553 /* not LOCKED_ONLY, so it has to have an xmax */
554 Assert(TransactionIdIsValid(xmax));
556 /* deleting subtransaction must have aborted */
557 if (!TransactionIdIsCurrentTransactionId(xmax))
559 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
561 return HeapTupleBeingUpdated;
562 return HeapTupleMayBeUpdated;
566 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
567 return HeapTupleSelfUpdated; /* updated after scan
570 return HeapTupleInvisible; /* updated before scan
575 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
577 /* deleting subtransaction must have aborted */
578 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
579 InvalidTransactionId);
580 return HeapTupleMayBeUpdated;
583 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
584 return HeapTupleSelfUpdated; /* updated after scan started */
586 return HeapTupleInvisible; /* updated before scan started */
588 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
589 return HeapTupleInvisible;
590 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
591 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
592 HeapTupleHeaderGetRawXmin(tuple));
595 /* it must have aborted or crashed */
596 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
597 InvalidTransactionId);
598 return HeapTupleInvisible;
602 /* by here, the inserting transaction has committed */
604 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
605 return HeapTupleMayBeUpdated;
607 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
609 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
610 return HeapTupleMayBeUpdated;
611 return HeapTupleUpdated; /* updated by other */
614 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
618 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
621 * If it's only locked but neither EXCL_LOCK nor KEYSHR_LOCK is
622 * set, it cannot possibly be running. Otherwise need to check.
624 if ((tuple->t_infomask & (HEAP_XMAX_EXCL_LOCK |
625 HEAP_XMAX_KEYSHR_LOCK)) &&
626 MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), true))
627 return HeapTupleBeingUpdated;
629 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
630 return HeapTupleMayBeUpdated;
633 xmax = HeapTupleGetUpdateXid(tuple);
634 if (!TransactionIdIsValid(xmax))
636 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
637 return HeapTupleBeingUpdated;
640 /* not LOCKED_ONLY, so it has to have an xmax */
641 Assert(TransactionIdIsValid(xmax));
643 if (TransactionIdIsCurrentTransactionId(xmax))
645 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
646 return HeapTupleSelfUpdated; /* updated after scan started */
648 return HeapTupleInvisible; /* updated before scan started */
651 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
652 return HeapTupleBeingUpdated;
654 if (TransactionIdDidCommit(xmax))
655 return HeapTupleUpdated;
658 * By here, the update in the Xmax is either aborted or crashed, but
659 * what about the other members?
662 if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
665 * There's no member, even just a locker, alive anymore, so we can
666 * mark the Xmax as invalid.
668 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
669 InvalidTransactionId);
670 return HeapTupleMayBeUpdated;
674 /* There are lockers running */
675 return HeapTupleBeingUpdated;
679 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
681 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
682 return HeapTupleBeingUpdated;
683 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
684 return HeapTupleSelfUpdated; /* updated after scan started */
686 return HeapTupleInvisible; /* updated before scan started */
689 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
690 return HeapTupleBeingUpdated;
692 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
694 /* it must have aborted or crashed */
695 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
696 InvalidTransactionId);
697 return HeapTupleMayBeUpdated;
700 /* xmax transaction committed */
702 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
704 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
705 InvalidTransactionId);
706 return HeapTupleMayBeUpdated;
709 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
710 HeapTupleHeaderGetRawXmax(tuple));
711 return HeapTupleUpdated; /* updated by other */
715 * HeapTupleSatisfiesDirty
716 * True iff heap tuple is valid including effects of open transactions.
718 * Here, we consider the effects of:
719 * all committed and in-progress transactions (as of the current instant)
720 * previous commands of this transaction
721 * changes made by the current command
723 * This is essentially like HeapTupleSatisfiesSelf as far as effects of
724 * the current transaction and committed/aborted xacts are concerned.
725 * However, we also include the effects of other xacts still in progress.
727 * A special hack is that the passed-in snapshot struct is used as an
728 * output argument to return the xids of concurrent xacts that affected the
729 * tuple. snapshot->xmin is set to the tuple's xmin if that is another
730 * transaction that's still in progress; or to InvalidTransactionId if the
731 * tuple's xmin is committed good, committed dead, or my own xact.
732 * Similarly for snapshot->xmax and the tuple's xmax. If the tuple was
733 * inserted speculatively, meaning that the inserter might still back down
734 * on the insertion without aborting the whole transaction, the associated
735 * token is also returned in snapshot->speculativeToken.
738 HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
741 HeapTupleHeader tuple = htup->t_data;
743 Assert(ItemPointerIsValid(&htup->t_self));
744 Assert(htup->t_tableOid != InvalidOid);
746 snapshot->xmin = snapshot->xmax = InvalidTransactionId;
747 snapshot->speculativeToken = 0;
749 if (!HeapTupleHeaderXminCommitted(tuple))
751 if (HeapTupleHeaderXminInvalid(tuple))
754 /* Used by pre-9.0 binary upgrades */
755 if (tuple->t_infomask & HEAP_MOVED_OFF)
757 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
759 if (TransactionIdIsCurrentTransactionId(xvac))
761 if (!TransactionIdIsInProgress(xvac))
763 if (TransactionIdDidCommit(xvac))
765 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
766 InvalidTransactionId);
769 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
770 InvalidTransactionId);
773 /* Used by pre-9.0 binary upgrades */
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(HeapTupleHeaderGetRawXmin(tuple)))
795 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
798 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
801 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
805 xmax = HeapTupleGetUpdateXid(tuple);
807 /* not LOCKED_ONLY, so it has to have an xmax */
808 Assert(TransactionIdIsValid(xmax));
810 /* updating subtransaction must have aborted */
811 if (!TransactionIdIsCurrentTransactionId(xmax))
817 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
819 /* deleting subtransaction must have aborted */
820 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
821 InvalidTransactionId);
827 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
830 * Return the speculative token to caller. Caller can worry about
831 * xmax, since it requires a conclusively locked row version, and
832 * a concurrent update to this tuple is a conflict of its
835 if (HeapTupleHeaderIsSpeculative(tuple))
837 snapshot->speculativeToken =
838 HeapTupleHeaderGetSpeculativeToken(tuple);
840 Assert(snapshot->speculativeToken != 0);
843 snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
844 /* XXX shouldn't we fall through to look at xmax? */
845 return true; /* in insertion by other */
847 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
848 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
849 HeapTupleHeaderGetRawXmin(tuple));
852 /* it must have aborted or crashed */
853 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
854 InvalidTransactionId);
859 /* by here, the inserting transaction has committed */
861 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
864 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
866 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
868 return false; /* updated by other */
871 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
875 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
878 xmax = HeapTupleGetUpdateXid(tuple);
880 /* not LOCKED_ONLY, so it has to have an xmax */
881 Assert(TransactionIdIsValid(xmax));
883 if (TransactionIdIsCurrentTransactionId(xmax))
885 if (TransactionIdIsInProgress(xmax))
887 snapshot->xmax = xmax;
890 if (TransactionIdDidCommit(xmax))
892 /* it must have aborted or crashed */
896 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
898 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
903 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
905 if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
906 snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
910 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
912 /* it must have aborted or crashed */
913 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
914 InvalidTransactionId);
918 /* xmax transaction committed */
920 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
922 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
923 InvalidTransactionId);
927 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
928 HeapTupleHeaderGetRawXmax(tuple));
929 return false; /* updated by other */
933 * HeapTupleSatisfiesMVCC
934 * True iff heap tuple is valid for the given MVCC snapshot.
936 * Here, we consider the effects of:
937 * all transactions committed as of the time of the given snapshot
938 * previous commands of this transaction
940 * Does _not_ include:
941 * transactions shown as in-progress by the snapshot
942 * transactions started after the snapshot was taken
943 * changes made by the current command
945 * Notice that here, we will not update the tuple status hint bits if the
946 * inserting/deleting transaction is still running according to our snapshot,
947 * even if in reality it's committed or aborted by now. This is intentional.
948 * Checking the true transaction state would require access to high-traffic
949 * shared data structures, creating contention we'd rather do without, and it
950 * would not change the result of our visibility check anyway. The hint bits
951 * will be updated by the first visitor that has a snapshot new enough to see
952 * the inserting/deleting transaction as done. In the meantime, the cost of
953 * leaving the hint bits unset is basically that each HeapTupleSatisfiesMVCC
954 * call will need to run TransactionIdIsCurrentTransactionId in addition to
955 * XidInMVCCSnapshot (but it would have to do the latter anyway). In the old
956 * coding where we tried to set the hint bits as soon as possible, we instead
957 * did TransactionIdIsInProgress in each call --- to no avail, as long as the
958 * inserting/deleting transaction was still running --- which was more cycles
959 * and more contention on the PGXACT array.
962 HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
965 HeapTupleHeader tuple = htup->t_data;
967 Assert(ItemPointerIsValid(&htup->t_self));
968 Assert(htup->t_tableOid != InvalidOid);
970 if (!HeapTupleHeaderXminCommitted(tuple))
972 if (HeapTupleHeaderXminInvalid(tuple))
975 /* Used by pre-9.0 binary upgrades */
976 if (tuple->t_infomask & HEAP_MOVED_OFF)
978 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
980 if (TransactionIdIsCurrentTransactionId(xvac))
982 if (!XidInMVCCSnapshot(xvac, snapshot))
984 if (TransactionIdDidCommit(xvac))
986 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
987 InvalidTransactionId);
990 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
991 InvalidTransactionId);
994 /* Used by pre-9.0 binary upgrades */
995 else if (tuple->t_infomask & HEAP_MOVED_IN)
997 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
999 if (!TransactionIdIsCurrentTransactionId(xvac))
1001 if (XidInMVCCSnapshot(xvac, snapshot))
1003 if (TransactionIdDidCommit(xvac))
1004 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1005 InvalidTransactionId);
1008 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1009 InvalidTransactionId);
1014 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
1016 if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
1017 return false; /* inserted after scan started */
1019 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1022 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
1025 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1029 xmax = HeapTupleGetUpdateXid(tuple);
1031 /* not LOCKED_ONLY, so it has to have an xmax */
1032 Assert(TransactionIdIsValid(xmax));
1034 /* updating subtransaction must have aborted */
1035 if (!TransactionIdIsCurrentTransactionId(xmax))
1037 else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1038 return true; /* updated after scan started */
1040 return false; /* updated before scan started */
1043 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
1045 /* deleting subtransaction must have aborted */
1046 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1047 InvalidTransactionId);
1051 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1052 return true; /* deleted after scan started */
1054 return false; /* deleted before scan started */
1056 else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1058 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
1059 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1060 HeapTupleHeaderGetRawXmin(tuple));
1063 /* it must have aborted or crashed */
1064 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1065 InvalidTransactionId);
1071 /* xmin is committed, but maybe not according to our snapshot */
1072 if (!HeapTupleHeaderXminFrozen(tuple) &&
1073 XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1074 return false; /* treat as still in progress */
1077 /* by here, the inserting transaction has committed */
1079 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1082 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1085 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1089 /* already checked above */
1090 Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
1092 xmax = HeapTupleGetUpdateXid(tuple);
1094 /* not LOCKED_ONLY, so it has to have an xmax */
1095 Assert(TransactionIdIsValid(xmax));
1097 if (TransactionIdIsCurrentTransactionId(xmax))
1099 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1100 return true; /* deleted after scan started */
1102 return false; /* deleted before scan started */
1104 if (XidInMVCCSnapshot(xmax, snapshot))
1106 if (TransactionIdDidCommit(xmax))
1107 return false; /* updating transaction committed */
1108 /* it must have aborted or crashed */
1112 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1114 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
1116 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1117 return true; /* deleted after scan started */
1119 return false; /* deleted before scan started */
1122 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1125 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
1127 /* it must have aborted or crashed */
1128 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1129 InvalidTransactionId);
1133 /* xmax transaction committed */
1134 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1135 HeapTupleHeaderGetRawXmax(tuple));
1139 /* xmax is committed, but maybe not according to our snapshot */
1140 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1141 return true; /* treat as still in progress */
1144 /* xmax transaction committed */
1151 * HeapTupleSatisfiesVacuum
1153 * Determine the status of tuples for VACUUM purposes. Here, what
1154 * we mainly want to know is if a tuple is potentially visible to *any*
1155 * running transaction. If so, it can't be removed yet by VACUUM.
1157 * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples
1158 * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
1159 * still be visible to some open transaction, so we can't remove them,
1160 * even if we see that the deleting transaction has committed.
1163 HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
1166 HeapTupleHeader tuple = htup->t_data;
1168 Assert(ItemPointerIsValid(&htup->t_self));
1169 Assert(htup->t_tableOid != InvalidOid);
1172 * Has inserting transaction committed?
1174 * If the inserting transaction aborted, then the tuple was never visible
1175 * to any other transaction, so we can delete it immediately.
1177 if (!HeapTupleHeaderXminCommitted(tuple))
1179 if (HeapTupleHeaderXminInvalid(tuple))
1180 return HEAPTUPLE_DEAD;
1181 /* Used by pre-9.0 binary upgrades */
1182 else if (tuple->t_infomask & HEAP_MOVED_OFF)
1184 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1186 if (TransactionIdIsCurrentTransactionId(xvac))
1187 return HEAPTUPLE_DELETE_IN_PROGRESS;
1188 if (TransactionIdIsInProgress(xvac))
1189 return HEAPTUPLE_DELETE_IN_PROGRESS;
1190 if (TransactionIdDidCommit(xvac))
1192 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1193 InvalidTransactionId);
1194 return HEAPTUPLE_DEAD;
1196 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1197 InvalidTransactionId);
1199 /* Used by pre-9.0 binary upgrades */
1200 else if (tuple->t_infomask & HEAP_MOVED_IN)
1202 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1204 if (TransactionIdIsCurrentTransactionId(xvac))
1205 return HEAPTUPLE_INSERT_IN_PROGRESS;
1206 if (TransactionIdIsInProgress(xvac))
1207 return HEAPTUPLE_INSERT_IN_PROGRESS;
1208 if (TransactionIdDidCommit(xvac))
1209 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1210 InvalidTransactionId);
1213 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1214 InvalidTransactionId);
1215 return HEAPTUPLE_DEAD;
1218 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
1220 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1221 return HEAPTUPLE_INSERT_IN_PROGRESS;
1222 /* only locked? run infomask-only check first, for performance */
1223 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
1224 HeapTupleHeaderIsOnlyLocked(tuple))
1225 return HEAPTUPLE_INSERT_IN_PROGRESS;
1226 /* inserted and then deleted by same xact */
1227 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
1228 return HEAPTUPLE_DELETE_IN_PROGRESS;
1229 /* deleting subtransaction must have aborted */
1230 return HEAPTUPLE_INSERT_IN_PROGRESS;
1232 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
1235 * It'd be possible to discern between INSERT/DELETE in progress
1236 * here by looking at xmax - but that doesn't seem beneficial for
1237 * the majority of callers and even detrimental for some. We'd
1238 * rather have callers look at/wait for xmin than xmax. It's
1239 * always correct to return INSERT_IN_PROGRESS because that's
1240 * what's happening from the view of other backends.
1242 return HEAPTUPLE_INSERT_IN_PROGRESS;
1244 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
1245 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1246 HeapTupleHeaderGetRawXmin(tuple));
1250 * Not in Progress, Not Committed, so either Aborted or crashed
1252 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1253 InvalidTransactionId);
1254 return HEAPTUPLE_DEAD;
1258 * At this point the xmin is known committed, but we might not have
1259 * been able to set the hint bit yet; so we can no longer Assert that
1265 * Okay, the inserter committed, so it was good at some point. Now what
1266 * about the deleting transaction?
1268 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1269 return HEAPTUPLE_LIVE;
1271 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1274 * "Deleting" xact really only locked it, so the tuple is live in any
1275 * case. However, we should make sure that either XMAX_COMMITTED or
1276 * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1277 * examining the tuple for future xacts. Also, marking dead
1278 * MultiXacts as invalid here provides defense against MultiXactId
1279 * wraparound (see also comments in heap_freeze_tuple()).
1281 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1283 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1286 * If it's only locked but neither EXCL_LOCK nor KEYSHR_LOCK
1287 * are set, it cannot possibly be running; otherwise have to
1290 if ((tuple->t_infomask & (HEAP_XMAX_EXCL_LOCK |
1291 HEAP_XMAX_KEYSHR_LOCK)) &&
1292 MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
1294 return HEAPTUPLE_LIVE;
1295 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1300 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1301 return HEAPTUPLE_LIVE;
1302 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1303 InvalidTransactionId);
1308 * We don't really care whether xmax did commit, abort or crash. We
1309 * know that xmax did lock the tuple, but it did not and will never
1310 * actually update it.
1313 return HEAPTUPLE_LIVE;
1316 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1320 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1322 /* already checked above */
1323 Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
1325 xmax = HeapTupleGetUpdateXid(tuple);
1327 /* not LOCKED_ONLY, so it has to have an xmax */
1328 Assert(TransactionIdIsValid(xmax));
1330 if (TransactionIdIsInProgress(xmax))
1331 return HEAPTUPLE_DELETE_IN_PROGRESS;
1332 else if (TransactionIdDidCommit(xmax))
1333 /* there are still lockers around -- can't return DEAD here */
1334 return HEAPTUPLE_RECENTLY_DEAD;
1335 /* updating transaction aborted */
1336 return HEAPTUPLE_LIVE;
1339 Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED));
1341 xmax = HeapTupleGetUpdateXid(tuple);
1343 /* not LOCKED_ONLY, so it has to have an xmax */
1344 Assert(TransactionIdIsValid(xmax));
1346 /* multi is not running -- updating xact cannot be */
1347 Assert(!TransactionIdIsInProgress(xmax));
1348 if (TransactionIdDidCommit(xmax))
1350 if (!TransactionIdPrecedes(xmax, OldestXmin))
1351 return HEAPTUPLE_RECENTLY_DEAD;
1353 return HEAPTUPLE_DEAD;
1357 * Not in Progress, Not Committed, so either Aborted or crashed.
1360 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1361 return HEAPTUPLE_LIVE;
1364 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1366 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1367 return HEAPTUPLE_DELETE_IN_PROGRESS;
1368 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
1369 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1370 HeapTupleHeaderGetRawXmax(tuple));
1374 * Not in Progress, Not Committed, so either Aborted or crashed
1376 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1377 InvalidTransactionId);
1378 return HEAPTUPLE_LIVE;
1382 * At this point the xmax is known committed, but we might not have
1383 * been able to set the hint bit yet; so we can no longer Assert that
1389 * Deleter committed, but perhaps it was recent enough that some open
1390 * transactions could still see the tuple.
1392 if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin))
1393 return HEAPTUPLE_RECENTLY_DEAD;
1395 /* Otherwise, it's dead and removable */
1396 return HEAPTUPLE_DEAD;
1400 * HeapTupleIsSurelyDead
1402 * Cheaply determine whether a tuple is surely dead to all onlookers.
1403 * We sometimes use this in lieu of HeapTupleSatisfiesVacuum when the
1404 * tuple has just been tested by another visibility routine (usually
1405 * HeapTupleSatisfiesMVCC) and, therefore, any hint bits that can be set
1406 * should already be set. We assume that if no hint bits are set, the xmin
1407 * or xmax transaction is still running. This is therefore faster than
1408 * HeapTupleSatisfiesVacuum, because we don't consult PGXACT nor CLOG.
1409 * It's okay to return FALSE when in doubt, but we must return TRUE only
1410 * if the tuple is removable.
1413 HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin)
1415 HeapTupleHeader tuple = htup->t_data;
1417 Assert(ItemPointerIsValid(&htup->t_self));
1418 Assert(htup->t_tableOid != InvalidOid);
1421 * If the inserting transaction is marked invalid, then it aborted, and
1422 * the tuple is definitely dead. If it's marked neither committed nor
1423 * invalid, then we assume it's still alive (since the presumption is that
1424 * all relevant hint bits were just set moments ago).
1426 if (!HeapTupleHeaderXminCommitted(tuple))
1427 return HeapTupleHeaderXminInvalid(tuple) ? true : false;
1430 * If the inserting transaction committed, but any deleting transaction
1431 * aborted, the tuple is still alive.
1433 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1437 * If the XMAX is just a lock, the tuple is still alive.
1439 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1443 * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1444 * know without checking pg_multixact.
1446 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1449 /* If deleter isn't known to have committed, assume it's still running. */
1450 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1453 /* Deleter committed, so tuple is dead if the XID is old enough. */
1454 return TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin);
1459 * Is the given XID still-in-progress according to the snapshot?
1461 * Note: GetSnapshotData never stores either top xid or subxids of our own
1462 * backend into a snapshot, so these xids will not be reported as "running"
1463 * by this function. This is OK for current uses, because we always check
1464 * TransactionIdIsCurrentTransactionId first, except for known-committed
1465 * XIDs which could not be ours anyway.
1468 XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
1473 * Make a quick range check to eliminate most XIDs without looking at the
1474 * xip arrays. Note that this is OK even if we convert a subxact XID to
1475 * its parent below, because a subxact with XID < xmin has surely also got
1476 * a parent with XID < xmin, while one with XID >= xmax must belong to a
1477 * parent that was not yet committed at the time of this snapshot.
1480 /* Any xid < xmin is not in-progress */
1481 if (TransactionIdPrecedes(xid, snapshot->xmin))
1483 /* Any xid >= xmax is in-progress */
1484 if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
1488 * Snapshot information is stored slightly differently in snapshots taken
1491 if (!snapshot->takenDuringRecovery)
1494 * If the snapshot contains full subxact data, the fastest way to
1495 * check things is just to compare the given XID against both subxact
1496 * XIDs and top-level XIDs. If the snapshot overflowed, we have to
1497 * use pg_subtrans to convert a subxact XID to its parent XID, but
1498 * then we need only look at top-level XIDs not subxacts.
1500 if (!snapshot->suboverflowed)
1502 /* we have full data, so search subxip */
1505 for (j = 0; j < snapshot->subxcnt; j++)
1507 if (TransactionIdEquals(xid, snapshot->subxip[j]))
1511 /* not there, fall through to search xip[] */
1516 * Snapshot overflowed, so convert xid to top-level. This is safe
1517 * because we eliminated too-old XIDs above.
1519 xid = SubTransGetTopmostTransaction(xid);
1522 * If xid was indeed a subxact, we might now have an xid < xmin,
1523 * so recheck to avoid an array scan. No point in rechecking
1526 if (TransactionIdPrecedes(xid, snapshot->xmin))
1530 for (i = 0; i < snapshot->xcnt; i++)
1532 if (TransactionIdEquals(xid, snapshot->xip[i]))
1541 * In recovery we store all xids in the subxact array because it is by
1542 * far the bigger array, and we mostly don't know which xids are
1543 * top-level and which are subxacts. The xip array is empty.
1545 * We start by searching subtrans, if we overflowed.
1547 if (snapshot->suboverflowed)
1550 * Snapshot overflowed, so convert xid to top-level. This is safe
1551 * because we eliminated too-old XIDs above.
1553 xid = SubTransGetTopmostTransaction(xid);
1556 * If xid was indeed a subxact, we might now have an xid < xmin,
1557 * so recheck to avoid an array scan. No point in rechecking
1560 if (TransactionIdPrecedes(xid, snapshot->xmin))
1565 * We now have either a top-level xid higher than xmin or an
1566 * indeterminate xid. We don't know whether it's top level or subxact
1567 * but it doesn't matter. If it's present, the xid is visible.
1569 for (j = 0; j < snapshot->subxcnt; j++)
1571 if (TransactionIdEquals(xid, snapshot->subxip[j]))
1580 * Is the tuple really only locked? That is, is it not updated?
1582 * It's easy to check just infomask bits if the locker is not a multi; but
1583 * otherwise we need to verify that the updating transaction has not aborted.
1585 * This function is here because it follows the same time qualification rules
1586 * laid out at the top of this file.
1589 HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
1593 /* if there's no valid Xmax, then there's obviously no update either */
1594 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1597 if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1600 /* invalid xmax means no update */
1601 if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
1605 * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1606 * necessarily have been updated
1608 if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1611 /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1612 xmax = HeapTupleGetUpdateXid(tuple);
1614 /* not LOCKED_ONLY, so it has to have an xmax */
1615 Assert(TransactionIdIsValid(xmax));
1617 if (TransactionIdIsCurrentTransactionId(xmax))
1619 if (TransactionIdIsInProgress(xmax))
1621 if (TransactionIdDidCommit(xmax))
1625 * not current, not in progress, not committed -- must have aborted or
1632 * check whether the transaciont id 'xid' is in the pre-sorted array 'xip'.
1635 TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
1637 return bsearch(&xid, xip, num,
1638 sizeof(TransactionId), xidComparator) != NULL;
1642 * See the comments for HeapTupleSatisfiesMVCC for the semantics this function
1645 * Only usable on tuples from catalog tables!
1647 * We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
1648 * reading catalog pages which couldn't have been created in an older version.
1650 * We don't set any hint bits in here as it seems unlikely to be beneficial as
1651 * those should already be set by normal access and it seems to be too
1652 * dangerous to do so as the semantics of doing so during timetravel are more
1653 * complicated than when dealing "only" with the present.
1656 HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
1659 HeapTupleHeader tuple = htup->t_data;
1660 TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
1661 TransactionId xmax = HeapTupleHeaderGetRawXmax(tuple);
1663 Assert(ItemPointerIsValid(&htup->t_self));
1664 Assert(htup->t_tableOid != InvalidOid);
1666 /* inserting transaction aborted */
1667 if (HeapTupleHeaderXminInvalid(tuple))
1669 Assert(!TransactionIdDidCommit(xmin));
1672 /* check if it's one of our txids, toplevel is also in there */
1673 else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1676 CommandId cmin = HeapTupleHeaderGetRawCommandId(tuple);
1677 CommandId cmax = InvalidCommandId;
1680 * another transaction might have (tried to) delete this tuple or
1681 * cmin/cmax was stored in a combocid. So we need to lookup the actual
1682 * values externally.
1684 resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
1689 elog(ERROR, "could not resolve cmin/cmax of catalog tuple");
1691 Assert(cmin != InvalidCommandId);
1693 if (cmin >= snapshot->curcid)
1694 return false; /* inserted after scan started */
1697 /* committed before our xmin horizon. Do a normal visibility check. */
1698 else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1700 Assert(!(HeapTupleHeaderXminCommitted(tuple) &&
1701 !TransactionIdDidCommit(xmin)));
1703 /* check for hint bit first, consult clog afterwards */
1704 if (!HeapTupleHeaderXminCommitted(tuple) &&
1705 !TransactionIdDidCommit(xmin))
1709 /* beyond our xmax horizon, i.e. invisible */
1710 else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1714 /* check if it's a committed transaction in [xmin, xmax) */
1715 else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1721 * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1729 /* at this point we know xmin is visible, go on to check xmax */
1731 /* xid invalid or aborted */
1732 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1734 /* locked tuples are always visible */
1735 else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1739 * We can see multis here if we're looking at user tables or if somebody
1740 * SELECT ... FOR SHARE/UPDATE a system table.
1742 else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1744 xmax = HeapTupleGetUpdateXid(tuple);
1747 /* check if it's one of our txids, toplevel is also in there */
1748 if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1752 CommandId cmax = HeapTupleHeaderGetRawCommandId(tuple);
1754 /* Lookup actual cmin/cmax values */
1755 resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
1760 elog(ERROR, "could not resolve combocid to cmax");
1762 Assert(cmax != InvalidCommandId);
1764 if (cmax >= snapshot->curcid)
1765 return true; /* deleted after scan started */
1767 return false; /* deleted before scan started */
1769 /* below xmin horizon, normal transaction state is valid */
1770 else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1772 Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
1773 !TransactionIdDidCommit(xmax)));
1775 /* check hint bit first */
1776 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1780 return !TransactionIdDidCommit(xmax);
1782 /* above xmax horizon, we cannot possibly see the deleting transaction */
1783 else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1785 /* xmax is between [xmin, xmax), check known committed array */
1786 else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1788 /* xmax is between [xmin, xmax), but known not to have committed yet */