PostgreSQL Source Code  git master
heapam_visibility.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * heapam_visibility.c
4  * Tuple visibility rules for tuples stored in heap.
5  *
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.
12  *
13  * NOTE: When using a non-MVCC snapshot, we must check
14  * TransactionIdIsInProgress (which looks in the PGPROC array)
15  * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
16  * pg_xact). 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_xact before it unsets
19  * MyProc->xid in the PGPROC 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
28  * race condition.
29  *
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_xact until after deciding that the xact is no longer in progress.
33  *
34  *
35  * Summary of visibility functions:
36  *
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  * HeapTupleSatisfiesNonVacuumable()
49  * Snapshot-style API for HeapTupleSatisfiesVacuum
50  * HeapTupleSatisfiesToast()
51  * visible unless part of interrupted vacuum, used for TOAST
52  * HeapTupleSatisfiesAny()
53  * all tuples are visible
54  *
55  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
56  * Portions Copyright (c) 1994, Regents of the University of California
57  *
58  * IDENTIFICATION
59  * src/backend/access/heap/heapam_visibility.c
60  *
61  *-------------------------------------------------------------------------
62  */
63 
64 #include "postgres.h"
65 
66 #include "access/heapam.h"
67 #include "access/htup_details.h"
68 #include "access/multixact.h"
69 #include "access/subtrans.h"
70 #include "access/tableam.h"
71 #include "access/transam.h"
72 #include "access/xact.h"
73 #include "access/xlog.h"
74 #include "storage/bufmgr.h"
75 #include "storage/procarray.h"
76 #include "utils/builtins.h"
77 #include "utils/combocid.h"
78 #include "utils/snapmgr.h"
79 
80 
81 /*
82  * SetHintBits()
83  *
84  * Set commit/abort hint bits on a tuple, if appropriate at this time.
85  *
86  * It is only safe to set a transaction-committed hint bit if we know the
87  * transaction's commit record is guaranteed to be flushed to disk before the
88  * buffer, or if the table is temporary or unlogged and will be obliterated by
89  * a crash anyway. We cannot change the LSN of the page here, because we may
90  * hold only a share lock on the buffer, so we can only use the LSN to
91  * interlock this if the buffer's LSN already is newer than the commit LSN;
92  * otherwise we have to just refrain from setting the hint bit until some
93  * future re-examination of the tuple.
94  *
95  * We can always set hint bits when marking a transaction aborted. (Some
96  * code in heapam.c relies on that!)
97  *
98  * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
99  * we can always set the hint bits, since pre-9.0 VACUUM FULL always used
100  * synchronous commits and didn't move tuples that weren't previously
101  * hinted. (This is not known by this subroutine, but is applied by its
102  * callers.) Note: old-style VACUUM FULL is gone, but we have to keep this
103  * module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
104  * support in-place update from pre-9.0 databases.
105  *
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.
108  *
109  * The caller should pass xid as the XID of the transaction to check, or
110  * InvalidTransactionId if no check is needed.
111  */
112 static inline void
114  uint16 infomask, TransactionId xid)
115 {
116  if (TransactionIdIsValid(xid))
117  {
118  /* NB: xid must be known committed here! */
119  XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
120 
121  if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
122  BufferGetLSNAtomic(buffer) < commitLSN)
123  {
124  /* not flushed and no LSN interlock, so don't set hint */
125  return;
126  }
127  }
128 
129  tuple->t_infomask |= infomask;
130  MarkBufferDirtyHint(buffer, true);
131 }
132 
133 /*
134  * HeapTupleSetHintBits --- exported version of SetHintBits()
135  *
136  * This must be separate because of C99's brain-dead notions about how to
137  * implement inline functions.
138  */
139 void
141  uint16 infomask, TransactionId xid)
142 {
143  SetHintBits(tuple, buffer, infomask, xid);
144 }
145 
146 
147 /*
148  * HeapTupleSatisfiesSelf
149  * True iff heap tuple is valid "for itself".
150  *
151  * See SNAPSHOT_MVCC's definition for the intended behaviour.
152  *
153  * Note:
154  * Assumes heap tuple is valid.
155  *
156  * The satisfaction of "itself" requires the following:
157  *
158  * ((Xmin == my-transaction && the row was updated by the current transaction, and
159  * (Xmax is null it was not deleted
160  * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
161  * ||
162  *
163  * (Xmin is committed && the row was modified by a committed transaction, and
164  * (Xmax is null || the row has not been deleted, or
165  * (Xmax != my-transaction && the row was deleted by another transaction
166  * Xmax is not committed))) that has not been committed
167  */
168 static bool
170 {
171  HeapTupleHeader tuple = htup->t_data;
172 
174  Assert(htup->t_tableOid != InvalidOid);
175 
176  if (!HeapTupleHeaderXminCommitted(tuple))
177  {
178  if (HeapTupleHeaderXminInvalid(tuple))
179  return false;
180 
181  /* Used by pre-9.0 binary upgrades */
182  if (tuple->t_infomask & HEAP_MOVED_OFF)
183  {
185 
187  return false;
188  if (!TransactionIdIsInProgress(xvac))
189  {
190  if (TransactionIdDidCommit(xvac))
191  {
192  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
194  return false;
195  }
196  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
198  }
199  }
200  /* Used by pre-9.0 binary upgrades */
201  else if (tuple->t_infomask & HEAP_MOVED_IN)
202  {
204 
206  {
207  if (TransactionIdIsInProgress(xvac))
208  return false;
209  if (TransactionIdDidCommit(xvac))
210  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
212  else
213  {
214  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
216  return false;
217  }
218  }
219  }
221  {
222  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
223  return true;
224 
225  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
226  return true;
227 
228  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
229  {
230  TransactionId xmax;
231 
232  xmax = HeapTupleGetUpdateXid(tuple);
233 
234  /* not LOCKED_ONLY, so it has to have an xmax */
236 
237  /* updating subtransaction must have aborted */
239  return true;
240  else
241  return false;
242  }
243 
245  {
246  /* deleting subtransaction must have aborted */
247  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
249  return true;
250  }
251 
252  return false;
253  }
255  return false;
257  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
259  else
260  {
261  /* it must have aborted or crashed */
262  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
264  return false;
265  }
266  }
267 
268  /* by here, the inserting transaction has committed */
269 
270  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
271  return true;
272 
273  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
274  {
276  return true;
277  return false; /* updated by other */
278  }
279 
280  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
281  {
282  TransactionId xmax;
283 
285  return true;
286 
287  xmax = HeapTupleGetUpdateXid(tuple);
288 
289  /* not LOCKED_ONLY, so it has to have an xmax */
291 
293  return false;
294  if (TransactionIdIsInProgress(xmax))
295  return true;
296  if (TransactionIdDidCommit(xmax))
297  return false;
298  /* it must have aborted or crashed */
299  return true;
300  }
301 
303  {
305  return true;
306  return false;
307  }
308 
310  return true;
311 
313  {
314  /* it must have aborted or crashed */
315  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
317  return true;
318  }
319 
320  /* xmax transaction committed */
321 
323  {
324  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
326  return true;
327  }
328 
329  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
331  return false;
332 }
333 
334 /*
335  * HeapTupleSatisfiesAny
336  * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
337  */
338 static bool
340 {
341  return true;
342 }
343 
344 /*
345  * HeapTupleSatisfiesToast
346  * True iff heap tuple is valid as a TOAST row.
347  *
348  * See SNAPSHOT_TOAST's definition for the intended behaviour.
349  *
350  * This is a simplified version that only checks for VACUUM moving conditions.
351  * It's appropriate for TOAST usage because TOAST really doesn't want to do
352  * its own time qual checks; if you can see the main table row that contains
353  * a TOAST reference, you should be able to see the TOASTed value. However,
354  * vacuuming a TOAST table is independent of the main table, and in case such
355  * a vacuum fails partway through, we'd better do this much checking.
356  *
357  * Among other things, this means you can't do UPDATEs of rows in a TOAST
358  * table.
359  */
360 static bool
362  Buffer buffer)
363 {
364  HeapTupleHeader tuple = htup->t_data;
365 
367  Assert(htup->t_tableOid != InvalidOid);
368 
369  if (!HeapTupleHeaderXminCommitted(tuple))
370  {
371  if (HeapTupleHeaderXminInvalid(tuple))
372  return false;
373 
374  /* Used by pre-9.0 binary upgrades */
375  if (tuple->t_infomask & HEAP_MOVED_OFF)
376  {
378 
380  return false;
381  if (!TransactionIdIsInProgress(xvac))
382  {
383  if (TransactionIdDidCommit(xvac))
384  {
385  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
387  return false;
388  }
389  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
391  }
392  }
393  /* Used by pre-9.0 binary upgrades */
394  else if (tuple->t_infomask & HEAP_MOVED_IN)
395  {
397 
399  {
400  if (TransactionIdIsInProgress(xvac))
401  return false;
402  if (TransactionIdDidCommit(xvac))
403  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
405  else
406  {
407  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
409  return false;
410  }
411  }
412  }
413 
414  /*
415  * An invalid Xmin can be left behind by a speculative insertion that
416  * is canceled by super-deleting the tuple. This also applies to
417  * TOAST tuples created during speculative insertion.
418  */
420  return false;
421  }
422 
423  /* otherwise assume the tuple is valid for TOAST. */
424  return true;
425 }
426 
427 /*
428  * HeapTupleSatisfiesUpdate
429  *
430  * This function returns a more detailed result code than most of the
431  * functions in this file, since UPDATE needs to know more than "is it
432  * visible?". It also allows for user-supplied CommandId rather than
433  * relying on CurrentCommandId.
434  *
435  * The possible return codes are:
436  *
437  * TM_Invisible: the tuple didn't exist at all when the scan started, e.g. it
438  * was created by a later CommandId.
439  *
440  * TM_Ok: The tuple is valid and visible, so it may be updated.
441  *
442  * TM_SelfModified: The tuple was updated by the current transaction, after
443  * the current scan started.
444  *
445  * TM_Updated: The tuple was updated by a committed transaction (including
446  * the case where the tuple was moved into a different partition).
447  *
448  * TM_Deleted: The tuple was deleted by a committed transaction.
449  *
450  * TM_BeingModified: The tuple is being updated by an in-progress transaction
451  * other than the current transaction. (Note: this includes the case where
452  * the tuple is share-locked by a MultiXact, even if the MultiXact includes
453  * the current transaction. Callers that want to distinguish that case must
454  * test for it themselves.)
455  */
456 TM_Result
458  Buffer buffer)
459 {
460  HeapTupleHeader tuple = htup->t_data;
461 
463  Assert(htup->t_tableOid != InvalidOid);
464 
465  if (!HeapTupleHeaderXminCommitted(tuple))
466  {
467  if (HeapTupleHeaderXminInvalid(tuple))
468  return TM_Invisible;
469 
470  /* Used by pre-9.0 binary upgrades */
471  if (tuple->t_infomask & HEAP_MOVED_OFF)
472  {
474 
476  return TM_Invisible;
477  if (!TransactionIdIsInProgress(xvac))
478  {
479  if (TransactionIdDidCommit(xvac))
480  {
481  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
483  return TM_Invisible;
484  }
485  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
487  }
488  }
489  /* Used by pre-9.0 binary upgrades */
490  else if (tuple->t_infomask & HEAP_MOVED_IN)
491  {
493 
495  {
496  if (TransactionIdIsInProgress(xvac))
497  return TM_Invisible;
498  if (TransactionIdDidCommit(xvac))
499  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
501  else
502  {
503  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
505  return TM_Invisible;
506  }
507  }
508  }
510  {
511  if (HeapTupleHeaderGetCmin(tuple) >= curcid)
512  return TM_Invisible; /* inserted after scan started */
513 
514  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
515  return TM_Ok;
516 
518  {
519  TransactionId xmax;
520 
521  xmax = HeapTupleHeaderGetRawXmax(tuple);
522 
523  /*
524  * Careful here: even though this tuple was created by our own
525  * transaction, it might be locked by other transactions, if
526  * the original version was key-share locked when we updated
527  * it.
528  */
529 
530  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
531  {
532  if (MultiXactIdIsRunning(xmax, true))
533  return TM_BeingModified;
534  else
535  return TM_Ok;
536  }
537 
538  /*
539  * If the locker is gone, then there is nothing of interest
540  * left in this Xmax; otherwise, report the tuple as
541  * locked/updated.
542  */
543  if (!TransactionIdIsInProgress(xmax))
544  return TM_Ok;
545  return TM_BeingModified;
546  }
547 
548  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
549  {
550  TransactionId xmax;
551 
552  xmax = HeapTupleGetUpdateXid(tuple);
553 
554  /* not LOCKED_ONLY, so it has to have an xmax */
556 
557  /* deleting subtransaction must have aborted */
559  {
561  false))
562  return TM_BeingModified;
563  return TM_Ok;
564  }
565  else
566  {
567  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
568  return TM_SelfModified; /* updated after scan started */
569  else
570  return TM_Invisible; /* updated before scan started */
571  }
572  }
573 
575  {
576  /* deleting subtransaction must have aborted */
577  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
579  return TM_Ok;
580  }
581 
582  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
583  return TM_SelfModified; /* updated after scan started */
584  else
585  return TM_Invisible; /* updated before scan started */
586  }
588  return TM_Invisible;
590  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
592  else
593  {
594  /* it must have aborted or crashed */
595  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
597  return TM_Invisible;
598  }
599  }
600 
601  /* by here, the inserting transaction has committed */
602 
603  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
604  return TM_Ok;
605 
606  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
607  {
609  return TM_Ok;
610  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid) ||
612  return TM_Updated; /* updated by other */
613  else
614  return TM_Deleted; /* deleted by other */
615  }
616 
617  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
618  {
619  TransactionId xmax;
620 
621  if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
622  return TM_Ok;
623 
625  {
627  return TM_BeingModified;
628 
630  return TM_Ok;
631  }
632 
633  xmax = HeapTupleGetUpdateXid(tuple);
634  if (!TransactionIdIsValid(xmax))
635  {
637  return TM_BeingModified;
638  }
639 
640  /* not LOCKED_ONLY, so it has to have an xmax */
642 
644  {
645  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
646  return TM_SelfModified; /* updated after scan started */
647  else
648  return TM_Invisible; /* updated before scan started */
649  }
650 
652  return TM_BeingModified;
653 
654  if (TransactionIdDidCommit(xmax))
655  {
656  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid) ||
658  return TM_Updated;
659  else
660  return TM_Deleted;
661  }
662 
663  /*
664  * By here, the update in the Xmax is either aborted or crashed, but
665  * what about the other members?
666  */
667 
669  {
670  /*
671  * There's no member, even just a locker, alive anymore, so we can
672  * mark the Xmax as invalid.
673  */
674  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
676  return TM_Ok;
677  }
678  else
679  {
680  /* There are lockers running */
681  return TM_BeingModified;
682  }
683  }
684 
686  {
688  return TM_BeingModified;
689  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
690  return TM_SelfModified; /* updated after scan started */
691  else
692  return TM_Invisible; /* updated before scan started */
693  }
694 
696  return TM_BeingModified;
697 
699  {
700  /* it must have aborted or crashed */
701  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
703  return TM_Ok;
704  }
705 
706  /* xmax transaction committed */
707 
709  {
710  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
712  return TM_Ok;
713  }
714 
715  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
717  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid) ||
719  return TM_Updated; /* updated by other */
720  else
721  return TM_Deleted; /* deleted by other */
722 }
723 
724 /*
725  * HeapTupleSatisfiesDirty
726  * True iff heap tuple is valid including effects of open transactions.
727  *
728  * See SNAPSHOT_DIRTY's definition for the intended behaviour.
729  *
730  * This is essentially like HeapTupleSatisfiesSelf as far as effects of
731  * the current transaction and committed/aborted xacts are concerned.
732  * However, we also include the effects of other xacts still in progress.
733  *
734  * A special hack is that the passed-in snapshot struct is used as an
735  * output argument to return the xids of concurrent xacts that affected the
736  * tuple. snapshot->xmin is set to the tuple's xmin if that is another
737  * transaction that's still in progress; or to InvalidTransactionId if the
738  * tuple's xmin is committed good, committed dead, or my own xact.
739  * Similarly for snapshot->xmax and the tuple's xmax. If the tuple was
740  * inserted speculatively, meaning that the inserter might still back down
741  * on the insertion without aborting the whole transaction, the associated
742  * token is also returned in snapshot->speculativeToken.
743  */
744 static bool
746  Buffer buffer)
747 {
748  HeapTupleHeader tuple = htup->t_data;
749 
751  Assert(htup->t_tableOid != InvalidOid);
752 
753  snapshot->xmin = snapshot->xmax = InvalidTransactionId;
754  snapshot->speculativeToken = 0;
755 
756  if (!HeapTupleHeaderXminCommitted(tuple))
757  {
758  if (HeapTupleHeaderXminInvalid(tuple))
759  return false;
760 
761  /* Used by pre-9.0 binary upgrades */
762  if (tuple->t_infomask & HEAP_MOVED_OFF)
763  {
765 
767  return false;
768  if (!TransactionIdIsInProgress(xvac))
769  {
770  if (TransactionIdDidCommit(xvac))
771  {
772  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
774  return false;
775  }
776  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
778  }
779  }
780  /* Used by pre-9.0 binary upgrades */
781  else if (tuple->t_infomask & HEAP_MOVED_IN)
782  {
784 
786  {
787  if (TransactionIdIsInProgress(xvac))
788  return false;
789  if (TransactionIdDidCommit(xvac))
790  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
792  else
793  {
794  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
796  return false;
797  }
798  }
799  }
801  {
802  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
803  return true;
804 
805  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
806  return true;
807 
808  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
809  {
810  TransactionId xmax;
811 
812  xmax = HeapTupleGetUpdateXid(tuple);
813 
814  /* not LOCKED_ONLY, so it has to have an xmax */
816 
817  /* updating subtransaction must have aborted */
819  return true;
820  else
821  return false;
822  }
823 
825  {
826  /* deleting subtransaction must have aborted */
827  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
829  return true;
830  }
831 
832  return false;
833  }
835  {
836  /*
837  * Return the speculative token to caller. Caller can worry about
838  * xmax, since it requires a conclusively locked row version, and
839  * a concurrent update to this tuple is a conflict of its
840  * purposes.
841  */
842  if (HeapTupleHeaderIsSpeculative(tuple))
843  {
844  snapshot->speculativeToken =
846 
847  Assert(snapshot->speculativeToken != 0);
848  }
849 
850  snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
851  /* XXX shouldn't we fall through to look at xmax? */
852  return true; /* in insertion by other */
853  }
855  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
857  else
858  {
859  /* it must have aborted or crashed */
860  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
862  return false;
863  }
864  }
865 
866  /* by here, the inserting transaction has committed */
867 
868  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
869  return true;
870 
871  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
872  {
874  return true;
875  return false; /* updated by other */
876  }
877 
878  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
879  {
880  TransactionId xmax;
881 
883  return true;
884 
885  xmax = HeapTupleGetUpdateXid(tuple);
886 
887  /* not LOCKED_ONLY, so it has to have an xmax */
889 
891  return false;
892  if (TransactionIdIsInProgress(xmax))
893  {
894  snapshot->xmax = xmax;
895  return true;
896  }
897  if (TransactionIdDidCommit(xmax))
898  return false;
899  /* it must have aborted or crashed */
900  return true;
901  }
902 
904  {
906  return true;
907  return false;
908  }
909 
911  {
913  snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
914  return true;
915  }
916 
918  {
919  /* it must have aborted or crashed */
920  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
922  return true;
923  }
924 
925  /* xmax transaction committed */
926 
928  {
929  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
931  return true;
932  }
933 
934  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
936  return false; /* updated by other */
937 }
938 
939 /*
940  * HeapTupleSatisfiesMVCC
941  * True iff heap tuple is valid for the given MVCC snapshot.
942  *
943  * See SNAPSHOT_MVCC's definition for the intended behaviour.
944  *
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 ProcArrayLock.
960  */
961 static bool
963  Buffer buffer)
964 {
965  HeapTupleHeader tuple = htup->t_data;
966 
968  Assert(htup->t_tableOid != InvalidOid);
969 
970  if (!HeapTupleHeaderXminCommitted(tuple))
971  {
972  if (HeapTupleHeaderXminInvalid(tuple))
973  return false;
974 
975  /* Used by pre-9.0 binary upgrades */
976  if (tuple->t_infomask & HEAP_MOVED_OFF)
977  {
979 
981  return false;
982  if (!XidInMVCCSnapshot(xvac, snapshot))
983  {
984  if (TransactionIdDidCommit(xvac))
985  {
986  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
988  return false;
989  }
990  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
992  }
993  }
994  /* Used by pre-9.0 binary upgrades */
995  else if (tuple->t_infomask & HEAP_MOVED_IN)
996  {
998 
1000  {
1001  if (XidInMVCCSnapshot(xvac, snapshot))
1002  return false;
1003  if (TransactionIdDidCommit(xvac))
1004  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1006  else
1007  {
1008  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1010  return false;
1011  }
1012  }
1013  }
1015  {
1016  if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
1017  return false; /* inserted after scan started */
1018 
1019  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1020  return true;
1021 
1022  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
1023  return true;
1024 
1025  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1026  {
1027  TransactionId xmax;
1028 
1029  xmax = HeapTupleGetUpdateXid(tuple);
1030 
1031  /* not LOCKED_ONLY, so it has to have an xmax */
1033 
1034  /* updating subtransaction must have aborted */
1036  return true;
1037  else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1038  return true; /* updated after scan started */
1039  else
1040  return false; /* updated before scan started */
1041  }
1042 
1044  {
1045  /* deleting subtransaction must have aborted */
1046  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1048  return true;
1049  }
1050 
1051  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1052  return true; /* deleted after scan started */
1053  else
1054  return false; /* deleted before scan started */
1055  }
1056  else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1057  return false;
1059  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1060  HeapTupleHeaderGetRawXmin(tuple));
1061  else
1062  {
1063  /* it must have aborted or crashed */
1064  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1066  return false;
1067  }
1068  }
1069  else
1070  {
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 */
1075  }
1076 
1077  /* by here, the inserting transaction has committed */
1078 
1079  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1080  return true;
1081 
1083  return true;
1084 
1085  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1086  {
1087  TransactionId xmax;
1088 
1089  /* already checked above */
1091 
1092  xmax = HeapTupleGetUpdateXid(tuple);
1093 
1094  /* not LOCKED_ONLY, so it has to have an xmax */
1096 
1098  {
1099  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1100  return true; /* deleted after scan started */
1101  else
1102  return false; /* deleted before scan started */
1103  }
1104  if (XidInMVCCSnapshot(xmax, snapshot))
1105  return true;
1106  if (TransactionIdDidCommit(xmax))
1107  return false; /* updating transaction committed */
1108  /* it must have aborted or crashed */
1109  return true;
1110  }
1111 
1112  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1113  {
1115  {
1116  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1117  return true; /* deleted after scan started */
1118  else
1119  return false; /* deleted before scan started */
1120  }
1121 
1122  if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1123  return true;
1124 
1126  {
1127  /* it must have aborted or crashed */
1128  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1130  return true;
1131  }
1132 
1133  /* xmax transaction committed */
1134  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1135  HeapTupleHeaderGetRawXmax(tuple));
1136  }
1137  else
1138  {
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 */
1142  }
1143 
1144  /* xmax transaction committed */
1145 
1146  return false;
1147 }
1148 
1149 
1150 /*
1151  * HeapTupleSatisfiesVacuum
1152  *
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.
1156  *
1157  * OldestXmin is a cutoff XID (obtained from
1158  * GetOldestNonRemovableTransactionId()). Tuples deleted by XIDs >=
1159  * OldestXmin are deemed "recently dead"; they might still be visible to some
1160  * open transaction, so we can't remove them, even if we see that the deleting
1161  * transaction has committed.
1162  */
1165  Buffer buffer)
1166 {
1167  TransactionId dead_after = InvalidTransactionId;
1168  HTSV_Result res;
1169 
1170  res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1171 
1172  if (res == HEAPTUPLE_RECENTLY_DEAD)
1173  {
1174  Assert(TransactionIdIsValid(dead_after));
1175 
1176  if (TransactionIdPrecedes(dead_after, OldestXmin))
1177  res = HEAPTUPLE_DEAD;
1178  }
1179  else
1180  Assert(!TransactionIdIsValid(dead_after));
1181 
1182  return res;
1183 }
1184 
1185 /*
1186  * Work horse for HeapTupleSatisfiesVacuum and similar routines.
1187  *
1188  * In contrast to HeapTupleSatisfiesVacuum this routine, when encountering a
1189  * tuple that could still be visible to some backend, stores the xid that
1190  * needs to be compared with the horizon in *dead_after, and returns
1191  * HEAPTUPLE_RECENTLY_DEAD. The caller then can perform the comparison with
1192  * the horizon. This is e.g. useful when comparing with different horizons.
1193  *
1194  * Note: HEAPTUPLE_DEAD can still be returned here, e.g. if the inserting
1195  * transaction aborted.
1196  */
1199 {
1200  HeapTupleHeader tuple = htup->t_data;
1201 
1202  Assert(ItemPointerIsValid(&htup->t_self));
1203  Assert(htup->t_tableOid != InvalidOid);
1204  Assert(dead_after != NULL);
1205 
1206  *dead_after = InvalidTransactionId;
1207 
1208  /*
1209  * Has inserting transaction committed?
1210  *
1211  * If the inserting transaction aborted, then the tuple was never visible
1212  * to any other transaction, so we can delete it immediately.
1213  */
1214  if (!HeapTupleHeaderXminCommitted(tuple))
1215  {
1216  if (HeapTupleHeaderXminInvalid(tuple))
1217  return HEAPTUPLE_DEAD;
1218  /* Used by pre-9.0 binary upgrades */
1219  else if (tuple->t_infomask & HEAP_MOVED_OFF)
1220  {
1221  TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1222 
1225  if (TransactionIdIsInProgress(xvac))
1227  if (TransactionIdDidCommit(xvac))
1228  {
1229  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1231  return HEAPTUPLE_DEAD;
1232  }
1233  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1235  }
1236  /* Used by pre-9.0 binary upgrades */
1237  else if (tuple->t_infomask & HEAP_MOVED_IN)
1238  {
1239  TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1240 
1243  if (TransactionIdIsInProgress(xvac))
1245  if (TransactionIdDidCommit(xvac))
1246  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1248  else
1249  {
1250  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1252  return HEAPTUPLE_DEAD;
1253  }
1254  }
1256  {
1257  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1259  /* only locked? run infomask-only check first, for performance */
1260  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
1263  /* inserted and then deleted by same xact */
1266  /* deleting subtransaction must have aborted */
1268  }
1270  {
1271  /*
1272  * It'd be possible to discern between INSERT/DELETE in progress
1273  * here by looking at xmax - but that doesn't seem beneficial for
1274  * the majority of callers and even detrimental for some. We'd
1275  * rather have callers look at/wait for xmin than xmax. It's
1276  * always correct to return INSERT_IN_PROGRESS because that's
1277  * what's happening from the view of other backends.
1278  */
1280  }
1282  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1283  HeapTupleHeaderGetRawXmin(tuple));
1284  else
1285  {
1286  /*
1287  * Not in Progress, Not Committed, so either Aborted or crashed
1288  */
1289  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1291  return HEAPTUPLE_DEAD;
1292  }
1293 
1294  /*
1295  * At this point the xmin is known committed, but we might not have
1296  * been able to set the hint bit yet; so we can no longer Assert that
1297  * it's set.
1298  */
1299  }
1300 
1301  /*
1302  * Okay, the inserter committed, so it was good at some point. Now what
1303  * about the deleting transaction?
1304  */
1305  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1306  return HEAPTUPLE_LIVE;
1307 
1309  {
1310  /*
1311  * "Deleting" xact really only locked it, so the tuple is live in any
1312  * case. However, we should make sure that either XMAX_COMMITTED or
1313  * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1314  * examining the tuple for future xacts.
1315  */
1316  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1317  {
1318  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1319  {
1320  /*
1321  * If it's a pre-pg_upgrade tuple, the multixact cannot
1322  * possibly be running; otherwise have to check.
1323  */
1324  if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
1326  true))
1327  return HEAPTUPLE_LIVE;
1329  }
1330  else
1331  {
1333  return HEAPTUPLE_LIVE;
1334  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1336  }
1337  }
1338 
1339  /*
1340  * We don't really care whether xmax did commit, abort or crash. We
1341  * know that xmax did lock the tuple, but it did not and will never
1342  * actually update it.
1343  */
1344 
1345  return HEAPTUPLE_LIVE;
1346  }
1347 
1348  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1349  {
1350  TransactionId xmax = HeapTupleGetUpdateXid(tuple);
1351 
1352  /* already checked above */
1354 
1355  /* not LOCKED_ONLY, so it has to have an xmax */
1357 
1358  if (TransactionIdIsInProgress(xmax))
1360  else if (TransactionIdDidCommit(xmax))
1361  {
1362  /*
1363  * The multixact might still be running due to lockers. Need to
1364  * allow for pruning if below the xid horizon regardless --
1365  * otherwise we could end up with a tuple where the updater has to
1366  * be removed due to the horizon, but is not pruned away. It's
1367  * not a problem to prune that tuple, because any remaining
1368  * lockers will also be present in newer tuple versions.
1369  */
1370  *dead_after = xmax;
1371  return HEAPTUPLE_RECENTLY_DEAD;
1372  }
1373  else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1374  {
1375  /*
1376  * Not in Progress, Not Committed, so either Aborted or crashed.
1377  * Mark the Xmax as invalid.
1378  */
1380  }
1381 
1382  return HEAPTUPLE_LIVE;
1383  }
1384 
1385  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1386  {
1390  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1391  HeapTupleHeaderGetRawXmax(tuple));
1392  else
1393  {
1394  /*
1395  * Not in Progress, Not Committed, so either Aborted or crashed
1396  */
1397  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1399  return HEAPTUPLE_LIVE;
1400  }
1401 
1402  /*
1403  * At this point the xmax is known committed, but we might not have
1404  * been able to set the hint bit yet; so we can no longer Assert that
1405  * it's set.
1406  */
1407  }
1408 
1409  /*
1410  * Deleter committed, allow caller to check if it was recent enough that
1411  * some open transactions could still see the tuple.
1412  */
1413  *dead_after = HeapTupleHeaderGetRawXmax(tuple);
1414  return HEAPTUPLE_RECENTLY_DEAD;
1415 }
1416 
1417 
1418 /*
1419  * HeapTupleSatisfiesNonVacuumable
1420  *
1421  * True if tuple might be visible to some transaction; false if it's
1422  * surely dead to everyone, ie, vacuumable.
1423  *
1424  * See SNAPSHOT_NON_VACUUMABLE's definition for the intended behaviour.
1425  *
1426  * This is an interface to HeapTupleSatisfiesVacuum that's callable via
1427  * HeapTupleSatisfiesSnapshot, so it can be used through a Snapshot.
1428  * snapshot->vistest must have been set up with the horizon to use.
1429  */
1430 static bool
1432  Buffer buffer)
1433 {
1434  TransactionId dead_after = InvalidTransactionId;
1435  HTSV_Result res;
1436 
1437  res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1438 
1439  if (res == HEAPTUPLE_RECENTLY_DEAD)
1440  {
1441  Assert(TransactionIdIsValid(dead_after));
1442 
1443  if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after))
1444  res = HEAPTUPLE_DEAD;
1445  }
1446  else
1447  Assert(!TransactionIdIsValid(dead_after));
1448 
1449  return res != HEAPTUPLE_DEAD;
1450 }
1451 
1452 
1453 /*
1454  * HeapTupleIsSurelyDead
1455  *
1456  * Cheaply determine whether a tuple is surely dead to all onlookers.
1457  * We sometimes use this in lieu of HeapTupleSatisfiesVacuum when the
1458  * tuple has just been tested by another visibility routine (usually
1459  * HeapTupleSatisfiesMVCC) and, therefore, any hint bits that can be set
1460  * should already be set. We assume that if no hint bits are set, the xmin
1461  * or xmax transaction is still running. This is therefore faster than
1462  * HeapTupleSatisfiesVacuum, because we consult neither procarray nor CLOG.
1463  * It's okay to return false when in doubt, but we must return true only
1464  * if the tuple is removable.
1465  */
1466 bool
1468 {
1469  HeapTupleHeader tuple = htup->t_data;
1470 
1471  Assert(ItemPointerIsValid(&htup->t_self));
1472  Assert(htup->t_tableOid != InvalidOid);
1473 
1474  /*
1475  * If the inserting transaction is marked invalid, then it aborted, and
1476  * the tuple is definitely dead. If it's marked neither committed nor
1477  * invalid, then we assume it's still alive (since the presumption is that
1478  * all relevant hint bits were just set moments ago).
1479  */
1480  if (!HeapTupleHeaderXminCommitted(tuple))
1481  return HeapTupleHeaderXminInvalid(tuple) ? true : false;
1482 
1483  /*
1484  * If the inserting transaction committed, but any deleting transaction
1485  * aborted, the tuple is still alive.
1486  */
1487  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1488  return false;
1489 
1490  /*
1491  * If the XMAX is just a lock, the tuple is still alive.
1492  */
1494  return false;
1495 
1496  /*
1497  * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1498  * know without checking pg_multixact.
1499  */
1500  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1501  return false;
1502 
1503  /* If deleter isn't known to have committed, assume it's still running. */
1504  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1505  return false;
1506 
1507  /* Deleter committed, so tuple is dead if the XID is old enough. */
1508  return GlobalVisTestIsRemovableXid(vistest,
1509  HeapTupleHeaderGetRawXmax(tuple));
1510 }
1511 
1512 /*
1513  * Is the tuple really only locked? That is, is it not updated?
1514  *
1515  * It's easy to check just infomask bits if the locker is not a multi; but
1516  * otherwise we need to verify that the updating transaction has not aborted.
1517  *
1518  * This function is here because it follows the same visibility rules laid out
1519  * at the top of this file.
1520  */
1521 bool
1523 {
1524  TransactionId xmax;
1525 
1526  /* if there's no valid Xmax, then there's obviously no update either */
1527  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1528  return true;
1529 
1530  if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1531  return true;
1532 
1533  /* invalid xmax means no update */
1535  return true;
1536 
1537  /*
1538  * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1539  * necessarily have been updated
1540  */
1541  if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1542  return false;
1543 
1544  /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1545  xmax = HeapTupleGetUpdateXid(tuple);
1546 
1547  /* not LOCKED_ONLY, so it has to have an xmax */
1549 
1551  return false;
1552  if (TransactionIdIsInProgress(xmax))
1553  return false;
1554  if (TransactionIdDidCommit(xmax))
1555  return false;
1556 
1557  /*
1558  * not current, not in progress, not committed -- must have aborted or
1559  * crashed
1560  */
1561  return true;
1562 }
1563 
1564 /*
1565  * check whether the transaction id 'xid' is in the pre-sorted array 'xip'.
1566  */
1567 static bool
1569 {
1570  return bsearch(&xid, xip, num,
1571  sizeof(TransactionId), xidComparator) != NULL;
1572 }
1573 
1574 /*
1575  * See the comments for HeapTupleSatisfiesMVCC for the semantics this function
1576  * obeys.
1577  *
1578  * Only usable on tuples from catalog tables!
1579  *
1580  * We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
1581  * reading catalog pages which couldn't have been created in an older version.
1582  *
1583  * We don't set any hint bits in here as it seems unlikely to be beneficial as
1584  * those should already be set by normal access and it seems to be too
1585  * dangerous to do so as the semantics of doing so during timetravel are more
1586  * complicated than when dealing "only" with the present.
1587  */
1588 static bool
1590  Buffer buffer)
1591 {
1592  HeapTupleHeader tuple = htup->t_data;
1593  TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
1595 
1596  Assert(ItemPointerIsValid(&htup->t_self));
1597  Assert(htup->t_tableOid != InvalidOid);
1598 
1599  /* inserting transaction aborted */
1600  if (HeapTupleHeaderXminInvalid(tuple))
1601  {
1603  return false;
1604  }
1605  /* check if it's one of our txids, toplevel is also in there */
1606  else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1607  {
1608  bool resolved;
1610  CommandId cmax = InvalidCommandId;
1611 
1612  /*
1613  * another transaction might have (tried to) delete this tuple or
1614  * cmin/cmax was stored in a combocid. So we need to lookup the actual
1615  * values externally.
1616  */
1618  htup, buffer,
1619  &cmin, &cmax);
1620 
1621  /*
1622  * If we haven't resolved the combocid to cmin/cmax, that means we
1623  * have not decoded the combocid yet. That means the cmin is
1624  * definitely in the future, and we're not supposed to see the tuple
1625  * yet.
1626  *
1627  * XXX This only applies to decoding of in-progress transactions. In
1628  * regular logical decoding we only execute this code at commit time,
1629  * at which point we should have seen all relevant combocids. So
1630  * ideally, we should error out in this case but in practice, this
1631  * won't happen. If we are too worried about this then we can add an
1632  * elog inside ResolveCminCmaxDuringDecoding.
1633  *
1634  * XXX For the streaming case, we can track the largest combocid
1635  * assigned, and error out based on this (when unable to resolve
1636  * combocid below that observed maximum value).
1637  */
1638  if (!resolved)
1639  return false;
1640 
1641  Assert(cmin != InvalidCommandId);
1642 
1643  if (cmin >= snapshot->curcid)
1644  return false; /* inserted after scan started */
1645  /* fall through */
1646  }
1647  /* committed before our xmin horizon. Do a normal visibility check. */
1648  else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1649  {
1651  !TransactionIdDidCommit(xmin)));
1652 
1653  /* check for hint bit first, consult clog afterwards */
1654  if (!HeapTupleHeaderXminCommitted(tuple) &&
1655  !TransactionIdDidCommit(xmin))
1656  return false;
1657  /* fall through */
1658  }
1659  /* beyond our xmax horizon, i.e. invisible */
1660  else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1661  {
1662  return false;
1663  }
1664  /* check if it's a committed transaction in [xmin, xmax) */
1665  else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1666  {
1667  /* fall through */
1668  }
1669 
1670  /*
1671  * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1672  * invisible.
1673  */
1674  else
1675  {
1676  return false;
1677  }
1678 
1679  /* at this point we know xmin is visible, go on to check xmax */
1680 
1681  /* xid invalid or aborted */
1682  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1683  return true;
1684  /* locked tuples are always visible */
1685  else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1686  return true;
1687 
1688  /*
1689  * We can see multis here if we're looking at user tables or if somebody
1690  * SELECT ... FOR SHARE/UPDATE a system table.
1691  */
1692  else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1693  {
1694  xmax = HeapTupleGetUpdateXid(tuple);
1695  }
1696 
1697  /* check if it's one of our txids, toplevel is also in there */
1698  if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1699  {
1700  bool resolved;
1701  CommandId cmin;
1703 
1704  /* Lookup actual cmin/cmax values */
1706  htup, buffer,
1707  &cmin, &cmax);
1708 
1709  /*
1710  * If we haven't resolved the combocid to cmin/cmax, that means we
1711  * have not decoded the combocid yet. That means the cmax is
1712  * definitely in the future, and we're still supposed to see the
1713  * tuple.
1714  *
1715  * XXX This only applies to decoding of in-progress transactions. In
1716  * regular logical decoding we only execute this code at commit time,
1717  * at which point we should have seen all relevant combocids. So
1718  * ideally, we should error out in this case but in practice, this
1719  * won't happen. If we are too worried about this then we can add an
1720  * elog inside ResolveCminCmaxDuringDecoding.
1721  *
1722  * XXX For the streaming case, we can track the largest combocid
1723  * assigned, and error out based on this (when unable to resolve
1724  * combocid below that observed maximum value).
1725  */
1726  if (!resolved || cmax == InvalidCommandId)
1727  return true;
1728 
1729  if (cmax >= snapshot->curcid)
1730  return true; /* deleted after scan started */
1731  else
1732  return false; /* deleted before scan started */
1733  }
1734  /* below xmin horizon, normal transaction state is valid */
1735  else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1736  {
1737  Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
1738  !TransactionIdDidCommit(xmax)));
1739 
1740  /* check hint bit first */
1741  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1742  return false;
1743 
1744  /* check clog */
1745  return !TransactionIdDidCommit(xmax);
1746  }
1747  /* above xmax horizon, we cannot possibly see the deleting transaction */
1748  else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1749  return true;
1750  /* xmax is between [xmin, xmax), check known committed array */
1751  else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1752  return false;
1753  /* xmax is between [xmin, xmax), but known not to have committed yet */
1754  else
1755  return true;
1756 }
1757 
1758 /*
1759  * HeapTupleSatisfiesVisibility
1760  * True iff heap tuple satisfies a time qual.
1761  *
1762  * Notes:
1763  * Assumes heap tuple is valid, and buffer at least share locked.
1764  *
1765  * Hint bits in the HeapTuple's t_infomask may be updated as a side effect;
1766  * if so, the indicated buffer is marked dirty.
1767  */
1768 bool
1770 {
1771  switch (snapshot->snapshot_type)
1772  {
1773  case SNAPSHOT_MVCC:
1774  return HeapTupleSatisfiesMVCC(tup, snapshot, buffer);
1775  break;
1776  case SNAPSHOT_SELF:
1777  return HeapTupleSatisfiesSelf(tup, snapshot, buffer);
1778  break;
1779  case SNAPSHOT_ANY:
1780  return HeapTupleSatisfiesAny(tup, snapshot, buffer);
1781  break;
1782  case SNAPSHOT_TOAST:
1783  return HeapTupleSatisfiesToast(tup, snapshot, buffer);
1784  break;
1785  case SNAPSHOT_DIRTY:
1786  return HeapTupleSatisfiesDirty(tup, snapshot, buffer);
1787  break;
1789  return HeapTupleSatisfiesHistoricMVCC(tup, snapshot, buffer);
1790  break;
1792  return HeapTupleSatisfiesNonVacuumable(tup, snapshot, buffer);
1793  break;
1794  }
1795 
1796  return false; /* keep compiler quiet */
1797 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
uint32 CommandId
Definition: c.h:534
bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
Definition: snapmgr.c:2259
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:196
#define HeapTupleHeaderGetSpeculativeToken(tup)
Definition: htup_details.h:434
uint32 TransactionId
Definition: c.h:520
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:3588
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:869
struct GlobalVisState * vistest
Definition: snapshot.h:199
bool XLogNeedsFlush(XLogRecPtr record)
Definition: xlog.c:3165
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1281
TransactionId HeapTupleGetUpdateXid(HeapTupleHeader tuple)
Definition: heapam.c:6542
CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup)
Definition: combocid.c:104
static void SetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:429
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:252
#define HeapTupleHeaderIndicatesMovedPartitions(tup)
Definition: htup_details.h:445
#define HeapTupleHeaderXminInvalid(tup)
Definition: htup_details.h:329
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:206
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
TM_Result HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer)
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:3927
static bool HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
HeapTupleHeader t_data
Definition: htup.h:68
#define HEAP_XMIN_INVALID
Definition: htup_details.h:204
#define true
Definition: c.h:328
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:375
unsigned short uint16
Definition: c.h:373
static bool HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot, Buffer buffer)
#define HEAP_XMAX_INVALID
Definition: htup_details.h:207
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
#define HeapTupleHeaderXminCommitted(tup)
Definition: htup_details.h:324
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:2931
#define InvalidTransactionId
Definition: transam.h:31
#define HeapTupleHeaderGetXvac(tup)
Definition: htup_details.h:415
static TransactionId OldestXmin
Definition: vacuumlazy.c:332
static bool HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
SnapshotType snapshot_type
Definition: snapshot.h:144
Oid t_tableOid
Definition: htup.h:66
TransactionId xmax
Definition: snapshot.h:158
TransactionId xmin
Definition: snapshot.h:157
#define HEAP_MOVED_IN
Definition: htup_details.h:213
bool BufferIsPermanent(Buffer buffer)
Definition: bufmgr.c:2901
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
static bool HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot, Buffer buffer)
HTSV_Result HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after)
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
TransactionId * xip
Definition: snapshot.h:168
static bool HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
TM_Result
Definition: tableam.h:70
static bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
Definition: transam.c:402
#define InvalidCommandId
Definition: c.h:537
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:230
#define HeapTupleHeaderXminFrozen(tup)
Definition: htup_details.h:335
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
#define HEAP_XMIN_COMMITTED
Definition: htup_details.h:203
#define InvalidOid
Definition: postgres_ext.h:36
CommandId curcid
Definition: snapshot.h:187
uint32 speculativeToken
Definition: snapshot.h:193
#define HEAP_MOVED_OFF
Definition: htup_details.h:210
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:745
CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup)
Definition: combocid.c:118
void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
Definition: tableam.h:76
static bool HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot, Buffer buffer)
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
size_t Size
Definition: c.h:473
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:308
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
static bool TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
#define HeapTupleHeaderGetRawCommandId(tup)
Definition: htup_details.h:391
HTAB * HistoricSnapshotGetTupleCids(void)
Definition: snapmgr.c:2082
uint32 xcnt
Definition: snapshot.h:169
bool HeapTupleIsSurelyDead(HeapTuple htup, GlobalVisState *vistest)
HTSV_Result
Definition: heapam.h:87
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int Buffer
Definition: buf.h:23
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:551
TransactionId * subxip
Definition: snapshot.h:180
int xidComparator(const void *arg1, const void *arg2)
Definition: xid.c:139
int32 subxcnt
Definition: snapshot.h:181
bool HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)
bool ResolveCminCmaxDuringDecoding(HTAB *tuplecid_data, Snapshot snapshot, HeapTuple htup, Buffer buffer, CommandId *cmin, CommandId *cmax)