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 PGXACT 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  * 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
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-2019, 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 the PGXACT array.
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 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.
1161  */
1164  Buffer buffer)
1165 {
1166  HeapTupleHeader tuple = htup->t_data;
1167 
1168  Assert(ItemPointerIsValid(&htup->t_self));
1169  Assert(htup->t_tableOid != InvalidOid);
1170 
1171  /*
1172  * Has inserting transaction committed?
1173  *
1174  * If the inserting transaction aborted, then the tuple was never visible
1175  * to any other transaction, so we can delete it immediately.
1176  */
1177  if (!HeapTupleHeaderXminCommitted(tuple))
1178  {
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)
1183  {
1184  TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1185 
1188  if (TransactionIdIsInProgress(xvac))
1190  if (TransactionIdDidCommit(xvac))
1191  {
1192  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1194  return HEAPTUPLE_DEAD;
1195  }
1196  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1198  }
1199  /* Used by pre-9.0 binary upgrades */
1200  else if (tuple->t_infomask & HEAP_MOVED_IN)
1201  {
1202  TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1203 
1206  if (TransactionIdIsInProgress(xvac))
1208  if (TransactionIdDidCommit(xvac))
1209  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1211  else
1212  {
1213  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1215  return HEAPTUPLE_DEAD;
1216  }
1217  }
1219  {
1220  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1222  /* only locked? run infomask-only check first, for performance */
1223  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
1226  /* inserted and then deleted by same xact */
1229  /* deleting subtransaction must have aborted */
1231  }
1233  {
1234  /*
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.
1241  */
1243  }
1245  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1246  HeapTupleHeaderGetRawXmin(tuple));
1247  else
1248  {
1249  /*
1250  * Not in Progress, Not Committed, so either Aborted or crashed
1251  */
1252  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1254  return HEAPTUPLE_DEAD;
1255  }
1256 
1257  /*
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
1260  * it's set.
1261  */
1262  }
1263 
1264  /*
1265  * Okay, the inserter committed, so it was good at some point. Now what
1266  * about the deleting transaction?
1267  */
1268  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1269  return HEAPTUPLE_LIVE;
1270 
1272  {
1273  /*
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.
1278  */
1279  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1280  {
1281  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1282  {
1283  /*
1284  * If it's a pre-pg_upgrade tuple, the multixact cannot
1285  * possibly be running; otherwise have to check.
1286  */
1287  if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
1289  true))
1290  return HEAPTUPLE_LIVE;
1292  }
1293  else
1294  {
1296  return HEAPTUPLE_LIVE;
1297  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1299  }
1300  }
1301 
1302  /*
1303  * We don't really care whether xmax did commit, abort or crash. We
1304  * know that xmax did lock the tuple, but it did not and will never
1305  * actually update it.
1306  */
1307 
1308  return HEAPTUPLE_LIVE;
1309  }
1310 
1311  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1312  {
1313  TransactionId xmax = HeapTupleGetUpdateXid(tuple);
1314 
1315  /* already checked above */
1317 
1318  /* not LOCKED_ONLY, so it has to have an xmax */
1320 
1321  if (TransactionIdIsInProgress(xmax))
1323  else if (TransactionIdDidCommit(xmax))
1324  {
1325  /*
1326  * The multixact might still be running due to lockers. If the
1327  * updater is below the xid horizon, we have to return DEAD
1328  * regardless -- otherwise we could end up with a tuple where the
1329  * updater has to be removed due to the horizon, but is not pruned
1330  * away. It's not a problem to prune that tuple, because any
1331  * remaining lockers will also be present in newer tuple versions.
1332  */
1333  if (!TransactionIdPrecedes(xmax, OldestXmin))
1334  return HEAPTUPLE_RECENTLY_DEAD;
1335 
1336  return HEAPTUPLE_DEAD;
1337  }
1338  else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1339  {
1340  /*
1341  * Not in Progress, Not Committed, so either Aborted or crashed.
1342  * Mark the Xmax as invalid.
1343  */
1345  }
1346 
1347  return HEAPTUPLE_LIVE;
1348  }
1349 
1350  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1351  {
1355  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1356  HeapTupleHeaderGetRawXmax(tuple));
1357  else
1358  {
1359  /*
1360  * Not in Progress, Not Committed, so either Aborted or crashed
1361  */
1362  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1364  return HEAPTUPLE_LIVE;
1365  }
1366 
1367  /*
1368  * At this point the xmax is known committed, but we might not have
1369  * been able to set the hint bit yet; so we can no longer Assert that
1370  * it's set.
1371  */
1372  }
1373 
1374  /*
1375  * Deleter committed, but perhaps it was recent enough that some open
1376  * transactions could still see the tuple.
1377  */
1378  if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin))
1379  return HEAPTUPLE_RECENTLY_DEAD;
1380 
1381  /* Otherwise, it's dead and removable */
1382  return HEAPTUPLE_DEAD;
1383 }
1384 
1385 
1386 /*
1387  * HeapTupleSatisfiesNonVacuumable
1388  *
1389  * True if tuple might be visible to some transaction; false if it's
1390  * surely dead to everyone, ie, vacuumable.
1391  *
1392  * See SNAPSHOT_TOAST's definition for the intended behaviour.
1393  *
1394  * This is an interface to HeapTupleSatisfiesVacuum that's callable via
1395  * HeapTupleSatisfiesSnapshot, so it can be used through a Snapshot.
1396  * snapshot->xmin must have been set up with the xmin horizon to use.
1397  */
1398 static bool
1400  Buffer buffer)
1401 {
1402  return HeapTupleSatisfiesVacuum(htup, snapshot->xmin, buffer)
1403  != HEAPTUPLE_DEAD;
1404 }
1405 
1406 
1407 /*
1408  * HeapTupleIsSurelyDead
1409  *
1410  * Cheaply determine whether a tuple is surely dead to all onlookers.
1411  * We sometimes use this in lieu of HeapTupleSatisfiesVacuum when the
1412  * tuple has just been tested by another visibility routine (usually
1413  * HeapTupleSatisfiesMVCC) and, therefore, any hint bits that can be set
1414  * should already be set. We assume that if no hint bits are set, the xmin
1415  * or xmax transaction is still running. This is therefore faster than
1416  * HeapTupleSatisfiesVacuum, because we don't consult PGXACT nor CLOG.
1417  * It's okay to return false when in doubt, but we must return true only
1418  * if the tuple is removable.
1419  */
1420 bool
1422 {
1423  HeapTupleHeader tuple = htup->t_data;
1424 
1425  Assert(ItemPointerIsValid(&htup->t_self));
1426  Assert(htup->t_tableOid != InvalidOid);
1427 
1428  /*
1429  * If the inserting transaction is marked invalid, then it aborted, and
1430  * the tuple is definitely dead. If it's marked neither committed nor
1431  * invalid, then we assume it's still alive (since the presumption is that
1432  * all relevant hint bits were just set moments ago).
1433  */
1434  if (!HeapTupleHeaderXminCommitted(tuple))
1435  return HeapTupleHeaderXminInvalid(tuple) ? true : false;
1436 
1437  /*
1438  * If the inserting transaction committed, but any deleting transaction
1439  * aborted, the tuple is still alive.
1440  */
1441  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1442  return false;
1443 
1444  /*
1445  * If the XMAX is just a lock, the tuple is still alive.
1446  */
1448  return false;
1449 
1450  /*
1451  * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1452  * know without checking pg_multixact.
1453  */
1454  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1455  return false;
1456 
1457  /* If deleter isn't known to have committed, assume it's still running. */
1458  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1459  return false;
1460 
1461  /* Deleter committed, so tuple is dead if the XID is old enough. */
1462  return TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin);
1463 }
1464 
1465 /*
1466  * Is the tuple really only locked? That is, is it not updated?
1467  *
1468  * It's easy to check just infomask bits if the locker is not a multi; but
1469  * otherwise we need to verify that the updating transaction has not aborted.
1470  *
1471  * This function is here because it follows the same visibility rules laid out
1472  * at the top of this file.
1473  */
1474 bool
1476 {
1477  TransactionId xmax;
1478 
1479  /* if there's no valid Xmax, then there's obviously no update either */
1480  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1481  return true;
1482 
1483  if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1484  return true;
1485 
1486  /* invalid xmax means no update */
1488  return true;
1489 
1490  /*
1491  * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1492  * necessarily have been updated
1493  */
1494  if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1495  return false;
1496 
1497  /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1498  xmax = HeapTupleGetUpdateXid(tuple);
1499 
1500  /* not LOCKED_ONLY, so it has to have an xmax */
1502 
1504  return false;
1505  if (TransactionIdIsInProgress(xmax))
1506  return false;
1507  if (TransactionIdDidCommit(xmax))
1508  return false;
1509 
1510  /*
1511  * not current, not in progress, not committed -- must have aborted or
1512  * crashed
1513  */
1514  return true;
1515 }
1516 
1517 /*
1518  * check whether the transaction id 'xid' is in the pre-sorted array 'xip'.
1519  */
1520 static bool
1522 {
1523  return bsearch(&xid, xip, num,
1524  sizeof(TransactionId), xidComparator) != NULL;
1525 }
1526 
1527 /*
1528  * See the comments for HeapTupleSatisfiesMVCC for the semantics this function
1529  * obeys.
1530  *
1531  * Only usable on tuples from catalog tables!
1532  *
1533  * We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
1534  * reading catalog pages which couldn't have been created in an older version.
1535  *
1536  * We don't set any hint bits in here as it seems unlikely to be beneficial as
1537  * those should already be set by normal access and it seems to be too
1538  * dangerous to do so as the semantics of doing so during timetravel are more
1539  * complicated than when dealing "only" with the present.
1540  */
1541 static bool
1543  Buffer buffer)
1544 {
1545  HeapTupleHeader tuple = htup->t_data;
1546  TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
1548 
1549  Assert(ItemPointerIsValid(&htup->t_self));
1550  Assert(htup->t_tableOid != InvalidOid);
1551 
1552  /* inserting transaction aborted */
1553  if (HeapTupleHeaderXminInvalid(tuple))
1554  {
1556  return false;
1557  }
1558  /* check if it's one of our txids, toplevel is also in there */
1559  else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1560  {
1561  bool resolved;
1563  CommandId cmax = InvalidCommandId;
1564 
1565  /*
1566  * another transaction might have (tried to) delete this tuple or
1567  * cmin/cmax was stored in a combocid. So we need to lookup the actual
1568  * values externally.
1569  */
1571  htup, buffer,
1572  &cmin, &cmax);
1573 
1574  if (!resolved)
1575  elog(ERROR, "could not resolve cmin/cmax of catalog tuple");
1576 
1577  Assert(cmin != InvalidCommandId);
1578 
1579  if (cmin >= snapshot->curcid)
1580  return false; /* inserted after scan started */
1581  /* fall through */
1582  }
1583  /* committed before our xmin horizon. Do a normal visibility check. */
1584  else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1585  {
1587  !TransactionIdDidCommit(xmin)));
1588 
1589  /* check for hint bit first, consult clog afterwards */
1590  if (!HeapTupleHeaderXminCommitted(tuple) &&
1591  !TransactionIdDidCommit(xmin))
1592  return false;
1593  /* fall through */
1594  }
1595  /* beyond our xmax horizon, i.e. invisible */
1596  else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1597  {
1598  return false;
1599  }
1600  /* check if it's a committed transaction in [xmin, xmax) */
1601  else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1602  {
1603  /* fall through */
1604  }
1605 
1606  /*
1607  * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1608  * invisible.
1609  */
1610  else
1611  {
1612  return false;
1613  }
1614 
1615  /* at this point we know xmin is visible, go on to check xmax */
1616 
1617  /* xid invalid or aborted */
1618  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1619  return true;
1620  /* locked tuples are always visible */
1621  else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1622  return true;
1623 
1624  /*
1625  * We can see multis here if we're looking at user tables or if somebody
1626  * SELECT ... FOR SHARE/UPDATE a system table.
1627  */
1628  else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1629  {
1630  xmax = HeapTupleGetUpdateXid(tuple);
1631  }
1632 
1633  /* check if it's one of our txids, toplevel is also in there */
1634  if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1635  {
1636  bool resolved;
1637  CommandId cmin;
1639 
1640  /* Lookup actual cmin/cmax values */
1642  htup, buffer,
1643  &cmin, &cmax);
1644 
1645  if (!resolved)
1646  elog(ERROR, "could not resolve combocid to cmax");
1647 
1648  Assert(cmax != InvalidCommandId);
1649 
1650  if (cmax >= snapshot->curcid)
1651  return true; /* deleted after scan started */
1652  else
1653  return false; /* deleted before scan started */
1654  }
1655  /* below xmin horizon, normal transaction state is valid */
1656  else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1657  {
1658  Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
1659  !TransactionIdDidCommit(xmax)));
1660 
1661  /* check hint bit first */
1662  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1663  return false;
1664 
1665  /* check clog */
1666  return !TransactionIdDidCommit(xmax);
1667  }
1668  /* above xmax horizon, we cannot possibly see the deleting transaction */
1669  else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1670  return true;
1671  /* xmax is between [xmin, xmax), check known committed array */
1672  else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1673  return false;
1674  /* xmax is between [xmin, xmax), but known not to have committed yet */
1675  else
1676  return true;
1677 }
1678 
1679 /*
1680  * HeapTupleSatisfiesVisibility
1681  * True iff heap tuple satisfies a time qual.
1682  *
1683  * Notes:
1684  * Assumes heap tuple is valid, and buffer at least share locked.
1685  *
1686  * Hint bits in the HeapTuple's t_infomask may be updated as a side effect;
1687  * if so, the indicated buffer is marked dirty.
1688  */
1689 bool
1691 {
1692  switch (snapshot->snapshot_type)
1693  {
1694  case SNAPSHOT_MVCC:
1695  return HeapTupleSatisfiesMVCC(tup, snapshot, buffer);
1696  break;
1697  case SNAPSHOT_SELF:
1698  return HeapTupleSatisfiesSelf(tup, snapshot, buffer);
1699  break;
1700  case SNAPSHOT_ANY:
1701  return HeapTupleSatisfiesAny(tup, snapshot, buffer);
1702  break;
1703  case SNAPSHOT_TOAST:
1704  return HeapTupleSatisfiesToast(tup, snapshot, buffer);
1705  break;
1706  case SNAPSHOT_DIRTY:
1707  return HeapTupleSatisfiesDirty(tup, snapshot, buffer);
1708  break;
1710  return HeapTupleSatisfiesHistoricMVCC(tup, snapshot, buffer);
1711  break;
1713  return HeapTupleSatisfiesNonVacuumable(tup, snapshot, buffer);
1714  break;
1715  }
1716 
1717  return false; /* keep compiler quiet */
1718 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
uint32 CommandId
Definition: c.h:521
bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
Definition: snapmgr.c:2241
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:196
#define HeapTupleHeaderGetSpeculativeToken(tup)
Definition: htup_details.h:434
uint32 TransactionId
Definition: c.h:507
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:3435
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:854
bool XLogNeedsFlush(XLogRecPtr record)
Definition: xlog.c:3119
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:985
TransactionId HeapTupleGetUpdateXid(HeapTupleHeader tuple)
Definition: heapam.c:6532
CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup)
Definition: combocid.c:105
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)
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:312
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:375
unsigned short uint16
Definition: c.h:357
#define ERROR
Definition: elog.h:43
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:2876
#define InvalidTransactionId
Definition: transam.h:31
#define HeapTupleHeaderGetXvac(tup)
Definition: htup_details.h:415
static TransactionId OldestXmin
Definition: vacuumlazy.c:145
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:2846
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
static bool HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot, Buffer buffer)
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:68
static bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
Definition: transam.c:402
#define InvalidCommandId
Definition: c.h:524
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:230
#define HeapTupleHeaderXminFrozen(tup)
Definition: htup_details.h:335
bool HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin)
#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:732
CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup)
Definition: combocid.c:119
void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
Definition: tableam.h:74
static bool HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot, Buffer buffer)
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
size_t Size
Definition: c.h:466
#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:2064
uint32 xcnt
Definition: snapshot.h:169
#define elog(elevel,...)
Definition: elog.h:226
HTSV_Result
Definition: heapam.h:86
#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:138
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)