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) before
15  * TransactionIdDidCommit (which look in pg_xact). Otherwise we have a race
16  * condition: we might decide that a just-committed transaction crashed,
17  * because none of the tests succeed. xact.c is careful to record
18  * commit/abort in pg_xact before it unsets MyProc->xid in the PGPROC array.
19  * That fixes that problem, but it also means there is a window where
20  * TransactionIdIsInProgress and TransactionIdDidCommit will both return true.
21  * If we check only TransactionIdDidCommit, we could consider a tuple
22  * committed when a later GetSnapshotData call will still think the
23  * originating transaction is in progress, which leads to application-level
24  * inconsistency. The upshot is that we gotta check TransactionIdIsInProgress
25  * first in all code paths, except for a few cases where we are looking at
26  * subtransactions of our own main transaction and so there can't be any race
27  * condition.
28  *
29  * We can't use TransactionIdDidAbort here because it won't treat transactions
30  * that were in progress during a crash as aborted. We determine that
31  * transactions aborted/crashed through process of elimination instead.
32  *
33  * When using an MVCC snapshot, we rely on XidInMVCCSnapshot rather than
34  * TransactionIdIsInProgress, but the logic is otherwise the same: do not
35  * check pg_xact until after deciding that the xact is no longer in progress.
36  *
37  *
38  * Summary of visibility functions:
39  *
40  * HeapTupleSatisfiesMVCC()
41  * visible to supplied snapshot, excludes current command
42  * HeapTupleSatisfiesUpdate()
43  * visible to instant snapshot, with user-supplied command
44  * counter and more complex result
45  * HeapTupleSatisfiesSelf()
46  * visible to instant snapshot and current command
47  * HeapTupleSatisfiesDirty()
48  * like HeapTupleSatisfiesSelf(), but includes open transactions
49  * HeapTupleSatisfiesVacuum()
50  * visible to any running transaction, used by VACUUM
51  * HeapTupleSatisfiesNonVacuumable()
52  * Snapshot-style API for HeapTupleSatisfiesVacuum
53  * HeapTupleSatisfiesToast()
54  * visible unless part of interrupted vacuum, used for TOAST
55  * HeapTupleSatisfiesAny()
56  * all tuples are visible
57  *
58  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
59  * Portions Copyright (c) 1994, Regents of the University of California
60  *
61  * IDENTIFICATION
62  * src/backend/access/heap/heapam_visibility.c
63  *
64  *-------------------------------------------------------------------------
65  */
66 
67 #include "postgres.h"
68 
69 #include "access/heapam.h"
70 #include "access/htup_details.h"
71 #include "access/multixact.h"
72 #include "access/subtrans.h"
73 #include "access/tableam.h"
74 #include "access/transam.h"
75 #include "access/xact.h"
76 #include "access/xlog.h"
77 #include "storage/bufmgr.h"
78 #include "storage/procarray.h"
79 #include "utils/builtins.h"
80 #include "utils/combocid.h"
81 #include "utils/snapmgr.h"
82 
83 
84 /*
85  * SetHintBits()
86  *
87  * Set commit/abort hint bits on a tuple, if appropriate at this time.
88  *
89  * It is only safe to set a transaction-committed hint bit if we know the
90  * transaction's commit record is guaranteed to be flushed to disk before the
91  * buffer, or if the table is temporary or unlogged and will be obliterated by
92  * a crash anyway. We cannot change the LSN of the page here, because we may
93  * hold only a share lock on the buffer, so we can only use the LSN to
94  * interlock this if the buffer's LSN already is newer than the commit LSN;
95  * otherwise we have to just refrain from setting the hint bit until some
96  * future re-examination of the tuple.
97  *
98  * We can always set hint bits when marking a transaction aborted. (Some
99  * code in heapam.c relies on that!)
100  *
101  * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
102  * we can always set the hint bits, since pre-9.0 VACUUM FULL always used
103  * synchronous commits and didn't move tuples that weren't previously
104  * hinted. (This is not known by this subroutine, but is applied by its
105  * callers.) Note: old-style VACUUM FULL is gone, but we have to keep this
106  * module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
107  * support in-place update from pre-9.0 databases.
108  *
109  * Normal commits may be asynchronous, so for those we need to get the LSN
110  * of the transaction and then check whether this is flushed.
111  *
112  * The caller should pass xid as the XID of the transaction to check, or
113  * InvalidTransactionId if no check is needed.
114  */
115 static inline void
117  uint16 infomask, TransactionId xid)
118 {
119  if (TransactionIdIsValid(xid))
120  {
121  /* NB: xid must be known committed here! */
122  XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
123 
124  if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
125  BufferGetLSNAtomic(buffer) < commitLSN)
126  {
127  /* not flushed and no LSN interlock, so don't set hint */
128  return;
129  }
130  }
131 
132  tuple->t_infomask |= infomask;
133  MarkBufferDirtyHint(buffer, true);
134 }
135 
136 /*
137  * HeapTupleSetHintBits --- exported version of SetHintBits()
138  *
139  * This must be separate because of C99's brain-dead notions about how to
140  * implement inline functions.
141  */
142 void
144  uint16 infomask, TransactionId xid)
145 {
146  SetHintBits(tuple, buffer, infomask, xid);
147 }
148 
149 
150 /*
151  * HeapTupleSatisfiesSelf
152  * True iff heap tuple is valid "for itself".
153  *
154  * See SNAPSHOT_MVCC's definition for the intended behaviour.
155  *
156  * Note:
157  * Assumes heap tuple is valid.
158  *
159  * The satisfaction of "itself" requires the following:
160  *
161  * ((Xmin == my-transaction && the row was updated by the current transaction, and
162  * (Xmax is null it was not deleted
163  * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
164  * ||
165  *
166  * (Xmin is committed && the row was modified by a committed transaction, and
167  * (Xmax is null || the row has not been deleted, or
168  * (Xmax != my-transaction && the row was deleted by another transaction
169  * Xmax is not committed))) that has not been committed
170  */
171 static bool
173 {
174  HeapTupleHeader tuple = htup->t_data;
175 
177  Assert(htup->t_tableOid != InvalidOid);
178 
179  if (!HeapTupleHeaderXminCommitted(tuple))
180  {
181  if (HeapTupleHeaderXminInvalid(tuple))
182  return false;
183 
184  /* Used by pre-9.0 binary upgrades */
185  if (tuple->t_infomask & HEAP_MOVED_OFF)
186  {
188 
190  return false;
191  if (!TransactionIdIsInProgress(xvac))
192  {
193  if (TransactionIdDidCommit(xvac))
194  {
195  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
197  return false;
198  }
199  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
201  }
202  }
203  /* Used by pre-9.0 binary upgrades */
204  else if (tuple->t_infomask & HEAP_MOVED_IN)
205  {
207 
209  {
210  if (TransactionIdIsInProgress(xvac))
211  return false;
212  if (TransactionIdDidCommit(xvac))
213  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
215  else
216  {
217  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
219  return false;
220  }
221  }
222  }
224  {
225  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
226  return true;
227 
228  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
229  return true;
230 
231  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
232  {
233  TransactionId xmax;
234 
235  xmax = HeapTupleGetUpdateXid(tuple);
236 
237  /* not LOCKED_ONLY, so it has to have an xmax */
239 
240  /* updating subtransaction must have aborted */
242  return true;
243  else
244  return false;
245  }
246 
248  {
249  /* deleting subtransaction must have aborted */
250  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
252  return true;
253  }
254 
255  return false;
256  }
258  return false;
260  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
262  else
263  {
264  /* it must have aborted or crashed */
265  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
267  return false;
268  }
269  }
270 
271  /* by here, the inserting transaction has committed */
272 
273  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
274  return true;
275 
276  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
277  {
279  return true;
280  return false; /* updated by other */
281  }
282 
283  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
284  {
285  TransactionId xmax;
286 
288  return true;
289 
290  xmax = HeapTupleGetUpdateXid(tuple);
291 
292  /* not LOCKED_ONLY, so it has to have an xmax */
294 
296  return false;
297  if (TransactionIdIsInProgress(xmax))
298  return true;
299  if (TransactionIdDidCommit(xmax))
300  return false;
301  /* it must have aborted or crashed */
302  return true;
303  }
304 
306  {
308  return true;
309  return false;
310  }
311 
313  return true;
314 
316  {
317  /* it must have aborted or crashed */
318  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
320  return true;
321  }
322 
323  /* xmax transaction committed */
324 
326  {
327  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
329  return true;
330  }
331 
332  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
334  return false;
335 }
336 
337 /*
338  * HeapTupleSatisfiesAny
339  * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
340  */
341 static bool
343 {
344  return true;
345 }
346 
347 /*
348  * HeapTupleSatisfiesToast
349  * True iff heap tuple is valid as a TOAST row.
350  *
351  * See SNAPSHOT_TOAST's definition for the intended behaviour.
352  *
353  * This is a simplified version that only checks for VACUUM moving conditions.
354  * It's appropriate for TOAST usage because TOAST really doesn't want to do
355  * its own time qual checks; if you can see the main table row that contains
356  * a TOAST reference, you should be able to see the TOASTed value. However,
357  * vacuuming a TOAST table is independent of the main table, and in case such
358  * a vacuum fails partway through, we'd better do this much checking.
359  *
360  * Among other things, this means you can't do UPDATEs of rows in a TOAST
361  * table.
362  */
363 static bool
365  Buffer buffer)
366 {
367  HeapTupleHeader tuple = htup->t_data;
368 
370  Assert(htup->t_tableOid != InvalidOid);
371 
372  if (!HeapTupleHeaderXminCommitted(tuple))
373  {
374  if (HeapTupleHeaderXminInvalid(tuple))
375  return false;
376 
377  /* Used by pre-9.0 binary upgrades */
378  if (tuple->t_infomask & HEAP_MOVED_OFF)
379  {
381 
383  return false;
384  if (!TransactionIdIsInProgress(xvac))
385  {
386  if (TransactionIdDidCommit(xvac))
387  {
388  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
390  return false;
391  }
392  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
394  }
395  }
396  /* Used by pre-9.0 binary upgrades */
397  else if (tuple->t_infomask & HEAP_MOVED_IN)
398  {
400 
402  {
403  if (TransactionIdIsInProgress(xvac))
404  return false;
405  if (TransactionIdDidCommit(xvac))
406  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
408  else
409  {
410  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
412  return false;
413  }
414  }
415  }
416 
417  /*
418  * An invalid Xmin can be left behind by a speculative insertion that
419  * is canceled by super-deleting the tuple. This also applies to
420  * TOAST tuples created during speculative insertion.
421  */
423  return false;
424  }
425 
426  /* otherwise assume the tuple is valid for TOAST. */
427  return true;
428 }
429 
430 /*
431  * HeapTupleSatisfiesUpdate
432  *
433  * This function returns a more detailed result code than most of the
434  * functions in this file, since UPDATE needs to know more than "is it
435  * visible?". It also allows for user-supplied CommandId rather than
436  * relying on CurrentCommandId.
437  *
438  * The possible return codes are:
439  *
440  * TM_Invisible: the tuple didn't exist at all when the scan started, e.g. it
441  * was created by a later CommandId.
442  *
443  * TM_Ok: The tuple is valid and visible, so it may be updated.
444  *
445  * TM_SelfModified: The tuple was updated by the current transaction, after
446  * the current scan started.
447  *
448  * TM_Updated: The tuple was updated by a committed transaction (including
449  * the case where the tuple was moved into a different partition).
450  *
451  * TM_Deleted: The tuple was deleted by a committed transaction.
452  *
453  * TM_BeingModified: The tuple is being updated by an in-progress transaction
454  * other than the current transaction. (Note: this includes the case where
455  * the tuple is share-locked by a MultiXact, even if the MultiXact includes
456  * the current transaction. Callers that want to distinguish that case must
457  * test for it themselves.)
458  */
459 TM_Result
461  Buffer buffer)
462 {
463  HeapTupleHeader tuple = htup->t_data;
464 
466  Assert(htup->t_tableOid != InvalidOid);
467 
468  if (!HeapTupleHeaderXminCommitted(tuple))
469  {
470  if (HeapTupleHeaderXminInvalid(tuple))
471  return TM_Invisible;
472 
473  /* Used by pre-9.0 binary upgrades */
474  if (tuple->t_infomask & HEAP_MOVED_OFF)
475  {
477 
479  return TM_Invisible;
480  if (!TransactionIdIsInProgress(xvac))
481  {
482  if (TransactionIdDidCommit(xvac))
483  {
484  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
486  return TM_Invisible;
487  }
488  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
490  }
491  }
492  /* Used by pre-9.0 binary upgrades */
493  else if (tuple->t_infomask & HEAP_MOVED_IN)
494  {
496 
498  {
499  if (TransactionIdIsInProgress(xvac))
500  return TM_Invisible;
501  if (TransactionIdDidCommit(xvac))
502  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
504  else
505  {
506  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
508  return TM_Invisible;
509  }
510  }
511  }
513  {
514  if (HeapTupleHeaderGetCmin(tuple) >= curcid)
515  return TM_Invisible; /* inserted after scan started */
516 
517  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
518  return TM_Ok;
519 
521  {
522  TransactionId xmax;
523 
524  xmax = HeapTupleHeaderGetRawXmax(tuple);
525 
526  /*
527  * Careful here: even though this tuple was created by our own
528  * transaction, it might be locked by other transactions, if
529  * the original version was key-share locked when we updated
530  * it.
531  */
532 
533  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
534  {
535  if (MultiXactIdIsRunning(xmax, true))
536  return TM_BeingModified;
537  else
538  return TM_Ok;
539  }
540 
541  /*
542  * If the locker is gone, then there is nothing of interest
543  * left in this Xmax; otherwise, report the tuple as
544  * locked/updated.
545  */
546  if (!TransactionIdIsInProgress(xmax))
547  return TM_Ok;
548  return TM_BeingModified;
549  }
550 
551  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
552  {
553  TransactionId xmax;
554 
555  xmax = HeapTupleGetUpdateXid(tuple);
556 
557  /* not LOCKED_ONLY, so it has to have an xmax */
559 
560  /* deleting subtransaction must have aborted */
562  {
564  false))
565  return TM_BeingModified;
566  return TM_Ok;
567  }
568  else
569  {
570  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
571  return TM_SelfModified; /* updated after scan started */
572  else
573  return TM_Invisible; /* updated before scan started */
574  }
575  }
576 
578  {
579  /* deleting subtransaction must have aborted */
580  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
582  return TM_Ok;
583  }
584 
585  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
586  return TM_SelfModified; /* updated after scan started */
587  else
588  return TM_Invisible; /* updated before scan started */
589  }
591  return TM_Invisible;
593  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
595  else
596  {
597  /* it must have aborted or crashed */
598  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
600  return TM_Invisible;
601  }
602  }
603 
604  /* by here, the inserting transaction has committed */
605 
606  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
607  return TM_Ok;
608 
609  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
610  {
612  return TM_Ok;
613  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
614  return TM_Updated; /* updated by other */
615  else
616  return TM_Deleted; /* deleted by other */
617  }
618 
619  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
620  {
621  TransactionId xmax;
622 
623  if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
624  return TM_Ok;
625 
627  {
629  return TM_BeingModified;
630 
632  return TM_Ok;
633  }
634 
635  xmax = HeapTupleGetUpdateXid(tuple);
636  if (!TransactionIdIsValid(xmax))
637  {
639  return TM_BeingModified;
640  }
641 
642  /* not LOCKED_ONLY, so it has to have an xmax */
644 
646  {
647  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
648  return TM_SelfModified; /* updated after scan started */
649  else
650  return TM_Invisible; /* updated before scan started */
651  }
652 
654  return TM_BeingModified;
655 
656  if (TransactionIdDidCommit(xmax))
657  {
658  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
659  return TM_Updated;
660  else
661  return TM_Deleted;
662  }
663 
664  /*
665  * By here, the update in the Xmax is either aborted or crashed, but
666  * what about the other members?
667  */
668 
670  {
671  /*
672  * There's no member, even just a locker, alive anymore, so we can
673  * mark the Xmax as invalid.
674  */
675  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
677  return TM_Ok;
678  }
679  else
680  {
681  /* There are lockers running */
682  return TM_BeingModified;
683  }
684  }
685 
687  {
689  return TM_BeingModified;
690  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
691  return TM_SelfModified; /* updated after scan started */
692  else
693  return TM_Invisible; /* updated before scan started */
694  }
695 
697  return TM_BeingModified;
698 
700  {
701  /* it must have aborted or crashed */
702  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
704  return TM_Ok;
705  }
706 
707  /* xmax transaction committed */
708 
710  {
711  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
713  return TM_Ok;
714  }
715 
716  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
718  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 
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 
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);
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 num > 0 &&
1571  bsearch(&xid, xip, num, 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 combo CID. So we need to lookup the
1615  * actual values externally.
1616  */
1618  htup, buffer,
1619  &cmin, &cmax);
1620 
1621  /*
1622  * If we haven't resolved the combo CID to cmin/cmax, that means we
1623  * have not decoded the combo CID 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 combo CIDs. 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 combo CID
1635  * assigned, and error out based on this (when unable to resolve combo
1636  * CID 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 combo CID to cmin/cmax, that means we
1711  * have not decoded the combo CID 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 combo CIDs. 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 combo CID
1723  * assigned, and error out based on this (when unable to resolve combo
1724  * CID 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(htup, snapshot, buffer);
1775  case SNAPSHOT_SELF:
1776  return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
1777  case SNAPSHOT_ANY:
1778  return HeapTupleSatisfiesAny(htup, snapshot, buffer);
1779  case SNAPSHOT_TOAST:
1780  return HeapTupleSatisfiesToast(htup, snapshot, buffer);
1781  case SNAPSHOT_DIRTY:
1782  return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
1784  return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
1786  return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
1787  }
1788 
1789  return false; /* keep compiler quiet */
1790 }
int Buffer
Definition: buf.h:23
bool BufferIsPermanent(Buffer buffer)
Definition: bufmgr.c:3617
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3647
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:4637
#define InvalidCommandId
Definition: c.h:658
unsigned short uint16
Definition: c.h:494
uint32 CommandId
Definition: c.h:655
uint32 TransactionId
Definition: c.h:641
size_t Size
Definition: c.h:594
CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup)
Definition: combocid.c:104
CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup)
Definition: combocid.c:118
TransactionId HeapTupleGetUpdateXid(HeapTupleHeader tuple)
Definition: heapam.c:7110
HTSV_Result
Definition: heapam.h:95
@ HEAPTUPLE_RECENTLY_DEAD
Definition: heapam.h:98
@ HEAPTUPLE_INSERT_IN_PROGRESS
Definition: heapam.h:99
@ HEAPTUPLE_LIVE
Definition: heapam.h:97
@ HEAPTUPLE_DELETE_IN_PROGRESS
Definition: heapam.h:100
@ HEAPTUPLE_DEAD
Definition: heapam.h:96
static void SetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
bool HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, Buffer buffer)
HTSV_Result HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after)
static bool HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot, Buffer buffer)
bool HeapTupleIsSurelyDead(HeapTuple htup, GlobalVisState *vistest)
static bool HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot, Buffer buffer)
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
static bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
TM_Result HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer)
static bool HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
#define HEAP_MOVED_OFF
Definition: htup_details.h:211
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:227
#define HEAP_XMIN_COMMITTED
Definition: htup_details.h:204
#define HeapTupleHeaderGetXvac(tup)
Definition: htup_details.h:411
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:197
#define HEAP_MOVED_IN
Definition: htup_details.h:212
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:309
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:209
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:207
#define HeapTupleHeaderGetSpeculativeToken(tup)
Definition: htup_details.h:433
#define HEAP_XMIN_INVALID
Definition: htup_details.h:205
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:304
#define HeapTupleHeaderXminFrozen(tup)
Definition: htup_details.h:331
#define HEAP_XMAX_INVALID
Definition: htup_details.h:208
#define HeapTupleHeaderXminCommitted(tup)
Definition: htup_details.h:320
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:371
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:361
#define HeapTupleHeaderGetRawCommandId(tup)
Definition: htup_details.h:387
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:249
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:428
#define HeapTupleHeaderXminInvalid(tup)
Definition: htup_details.h:325
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:35
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition: itemptr.h:83
Assert(fmt[strlen(fmt) - 1] !='\n')
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:552
#define InvalidOid
Definition: postgres_ext.h:36
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4167
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1383
bool ResolveCminCmaxDuringDecoding(HTAB *tuplecid_data, Snapshot snapshot, HeapTuple htup, Buffer buffer, CommandId *cmin, CommandId *cmax)
bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
Definition: snapmgr.c:1862
HTAB * HistoricSnapshotGetTupleCids(void)
Definition: snapmgr.c:1684
@ SNAPSHOT_TOAST
Definition: snapshot.h:74
@ SNAPSHOT_SELF
Definition: snapshot.h:64
@ SNAPSHOT_NON_VACUUMABLE
Definition: snapshot.h:118
@ SNAPSHOT_MVCC
Definition: snapshot.h:50
@ SNAPSHOT_ANY
Definition: snapshot.h:69
@ SNAPSHOT_HISTORIC_MVCC
Definition: snapshot.h:109
@ SNAPSHOT_DIRTY
Definition: snapshot.h:102
ItemPointerData t_self
Definition: htup.h:65
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
ItemPointerData t_ctid
Definition: htup_details.h:161
TransactionId xmin
Definition: snapshot.h:157
int32 subxcnt
Definition: snapshot.h:181
CommandId curcid
Definition: snapshot.h:187
struct GlobalVisState * vistest
Definition: snapshot.h:199
uint32 xcnt
Definition: snapshot.h:169
TransactionId * subxip
Definition: snapshot.h:180
TransactionId xmax
Definition: snapshot.h:158
uint32 speculativeToken
Definition: snapshot.h:193
SnapshotType snapshot_type
Definition: snapshot.h:144
TransactionId * xip
Definition: snapshot.h:168
TM_Result
Definition: tableam.h:72
@ TM_Ok
Definition: tableam.h:77
@ TM_BeingModified
Definition: tableam.h:99
@ TM_Deleted
Definition: tableam.h:92
@ TM_Updated
Definition: tableam.h:89
@ TM_SelfModified
Definition: tableam.h:83
@ TM_Invisible
Definition: tableam.h:80
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
Definition: transam.c:382
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:329
#define InvalidTransactionId
Definition: transam.h:31
#define TransactionIdIsValid(xid)
Definition: transam.h:41
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:926
int xidComparator(const void *arg1, const void *arg2)
Definition: xid.c:138
bool XLogNeedsFlush(XLogRecPtr record)
Definition: xlog.c:2952
uint64 XLogRecPtr
Definition: xlogdefs.h:21