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-2024, 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/tableam.h"
73 #include "access/transam.h"
74 #include "access/xact.h"
75 #include "access/xlog.h"
76 #include "storage/bufmgr.h"
77 #include "storage/procarray.h"
78 #include "utils/builtins.h"
79 #include "utils/snapmgr.h"
80 
81 
82 /*
83  * SetHintBits()
84  *
85  * Set commit/abort hint bits on a tuple, if appropriate at this time.
86  *
87  * It is only safe to set a transaction-committed hint bit if we know the
88  * transaction's commit record is guaranteed to be flushed to disk before the
89  * buffer, or if the table is temporary or unlogged and will be obliterated by
90  * a crash anyway. We cannot change the LSN of the page here, because we may
91  * hold only a share lock on the buffer, so we can only use the LSN to
92  * interlock this if the buffer's LSN already is newer than the commit LSN;
93  * otherwise we have to just refrain from setting the hint bit until some
94  * future re-examination of the tuple.
95  *
96  * We can always set hint bits when marking a transaction aborted. (Some
97  * code in heapam.c relies on that!)
98  *
99  * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
100  * we can always set the hint bits, since pre-9.0 VACUUM FULL always used
101  * synchronous commits and didn't move tuples that weren't previously
102  * hinted. (This is not known by this subroutine, but is applied by its
103  * callers.) Note: old-style VACUUM FULL is gone, but we have to keep this
104  * module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
105  * support in-place update from pre-9.0 databases.
106  *
107  * Normal commits may be asynchronous, so for those we need to get the LSN
108  * of the transaction and then check whether this is flushed.
109  *
110  * The caller should pass xid as the XID of the transaction to check, or
111  * InvalidTransactionId if no check is needed.
112  */
113 static inline void
115  uint16 infomask, TransactionId xid)
116 {
117  if (TransactionIdIsValid(xid))
118  {
119  /* NB: xid must be known committed here! */
120  XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
121 
122  if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
123  BufferGetLSNAtomic(buffer) < commitLSN)
124  {
125  /* not flushed and no LSN interlock, so don't set hint */
126  return;
127  }
128  }
129 
130  tuple->t_infomask |= infomask;
131  MarkBufferDirtyHint(buffer, true);
132 }
133 
134 /*
135  * HeapTupleSetHintBits --- exported version of SetHintBits()
136  *
137  * This must be separate because of C99's brain-dead notions about how to
138  * implement inline functions.
139  */
140 void
142  uint16 infomask, TransactionId xid)
143 {
144  SetHintBits(tuple, buffer, infomask, xid);
145 }
146 
147 
148 /*
149  * HeapTupleSatisfiesSelf
150  * True iff heap tuple is valid "for itself".
151  *
152  * See SNAPSHOT_MVCC's definition for the intended behaviour.
153  *
154  * Note:
155  * Assumes heap tuple is valid.
156  *
157  * The satisfaction of "itself" requires the following:
158  *
159  * ((Xmin == my-transaction && the row was updated by the current transaction, and
160  * (Xmax is null it was not deleted
161  * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
162  * ||
163  *
164  * (Xmin is committed && the row was modified by a committed transaction, and
165  * (Xmax is null || the row has not been deleted, or
166  * (Xmax != my-transaction && the row was deleted by another transaction
167  * Xmax is not committed))) that has not been committed
168  */
169 static bool
171 {
172  HeapTupleHeader tuple = htup->t_data;
173 
175  Assert(htup->t_tableOid != InvalidOid);
176 
177  if (!HeapTupleHeaderXminCommitted(tuple))
178  {
179  if (HeapTupleHeaderXminInvalid(tuple))
180  return false;
181 
182  /* Used by pre-9.0 binary upgrades */
183  if (tuple->t_infomask & HEAP_MOVED_OFF)
184  {
186 
188  return false;
189  if (!TransactionIdIsInProgress(xvac))
190  {
191  if (TransactionIdDidCommit(xvac))
192  {
193  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
195  return false;
196  }
197  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
199  }
200  }
201  /* Used by pre-9.0 binary upgrades */
202  else if (tuple->t_infomask & HEAP_MOVED_IN)
203  {
205 
207  {
208  if (TransactionIdIsInProgress(xvac))
209  return false;
210  if (TransactionIdDidCommit(xvac))
211  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
213  else
214  {
215  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
217  return false;
218  }
219  }
220  }
222  {
223  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
224  return true;
225 
226  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
227  return true;
228 
229  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
230  {
231  TransactionId xmax;
232 
233  xmax = HeapTupleGetUpdateXid(tuple);
234 
235  /* not LOCKED_ONLY, so it has to have an xmax */
237 
238  /* updating subtransaction must have aborted */
240  return true;
241  else
242  return false;
243  }
244 
246  {
247  /* deleting subtransaction must have aborted */
248  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
250  return true;
251  }
252 
253  return false;
254  }
256  return false;
258  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
260  else
261  {
262  /* it must have aborted or crashed */
263  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
265  return false;
266  }
267  }
268 
269  /* by here, the inserting transaction has committed */
270 
271  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
272  return true;
273 
274  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
275  {
277  return true;
278  return false; /* updated by other */
279  }
280 
281  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
282  {
283  TransactionId xmax;
284 
286  return true;
287 
288  xmax = HeapTupleGetUpdateXid(tuple);
289 
290  /* not LOCKED_ONLY, so it has to have an xmax */
292 
294  return false;
295  if (TransactionIdIsInProgress(xmax))
296  return true;
297  if (TransactionIdDidCommit(xmax))
298  return false;
299  /* it must have aborted or crashed */
300  return true;
301  }
302 
304  {
306  return true;
307  return false;
308  }
309 
311  return true;
312 
314  {
315  /* it must have aborted or crashed */
316  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
318  return true;
319  }
320 
321  /* xmax transaction committed */
322 
324  {
325  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
327  return true;
328  }
329 
330  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
332  return false;
333 }
334 
335 /*
336  * HeapTupleSatisfiesAny
337  * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
338  */
339 static bool
341 {
342  return true;
343 }
344 
345 /*
346  * HeapTupleSatisfiesToast
347  * True iff heap tuple is valid as a TOAST row.
348  *
349  * See SNAPSHOT_TOAST's definition for the intended behaviour.
350  *
351  * This is a simplified version that only checks for VACUUM moving conditions.
352  * It's appropriate for TOAST usage because TOAST really doesn't want to do
353  * its own time qual checks; if you can see the main table row that contains
354  * a TOAST reference, you should be able to see the TOASTed value. However,
355  * vacuuming a TOAST table is independent of the main table, and in case such
356  * a vacuum fails partway through, we'd better do this much checking.
357  *
358  * Among other things, this means you can't do UPDATEs of rows in a TOAST
359  * table.
360  */
361 static bool
363  Buffer buffer)
364 {
365  HeapTupleHeader tuple = htup->t_data;
366 
368  Assert(htup->t_tableOid != InvalidOid);
369 
370  if (!HeapTupleHeaderXminCommitted(tuple))
371  {
372  if (HeapTupleHeaderXminInvalid(tuple))
373  return false;
374 
375  /* Used by pre-9.0 binary upgrades */
376  if (tuple->t_infomask & HEAP_MOVED_OFF)
377  {
379 
381  return false;
382  if (!TransactionIdIsInProgress(xvac))
383  {
384  if (TransactionIdDidCommit(xvac))
385  {
386  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
388  return false;
389  }
390  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
392  }
393  }
394  /* Used by pre-9.0 binary upgrades */
395  else if (tuple->t_infomask & HEAP_MOVED_IN)
396  {
398 
400  {
401  if (TransactionIdIsInProgress(xvac))
402  return false;
403  if (TransactionIdDidCommit(xvac))
404  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
406  else
407  {
408  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
410  return false;
411  }
412  }
413  }
414 
415  /*
416  * An invalid Xmin can be left behind by a speculative insertion that
417  * is canceled by super-deleting the tuple. This also applies to
418  * TOAST tuples created during speculative insertion.
419  */
421  return false;
422  }
423 
424  /* otherwise assume the tuple is valid for TOAST. */
425  return true;
426 }
427 
428 /*
429  * HeapTupleSatisfiesUpdate
430  *
431  * This function returns a more detailed result code than most of the
432  * functions in this file, since UPDATE needs to know more than "is it
433  * visible?". It also allows for user-supplied CommandId rather than
434  * relying on CurrentCommandId.
435  *
436  * The possible return codes are:
437  *
438  * TM_Invisible: the tuple didn't exist at all when the scan started, e.g. it
439  * was created by a later CommandId.
440  *
441  * TM_Ok: The tuple is valid and visible, so it may be updated.
442  *
443  * TM_SelfModified: The tuple was updated by the current transaction, after
444  * the current scan started.
445  *
446  * TM_Updated: The tuple was updated by a committed transaction (including
447  * the case where the tuple was moved into a different partition).
448  *
449  * TM_Deleted: The tuple was deleted by a committed transaction.
450  *
451  * TM_BeingModified: The tuple is being updated by an in-progress transaction
452  * other than the current transaction. (Note: this includes the case where
453  * the tuple is share-locked by a MultiXact, even if the MultiXact includes
454  * the current transaction. Callers that want to distinguish that case must
455  * test for it themselves.)
456  */
457 TM_Result
459  Buffer buffer)
460 {
461  HeapTupleHeader tuple = htup->t_data;
462 
464  Assert(htup->t_tableOid != InvalidOid);
465 
466  if (!HeapTupleHeaderXminCommitted(tuple))
467  {
468  if (HeapTupleHeaderXminInvalid(tuple))
469  return TM_Invisible;
470 
471  /* Used by pre-9.0 binary upgrades */
472  if (tuple->t_infomask & HEAP_MOVED_OFF)
473  {
475 
477  return TM_Invisible;
478  if (!TransactionIdIsInProgress(xvac))
479  {
480  if (TransactionIdDidCommit(xvac))
481  {
482  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
484  return TM_Invisible;
485  }
486  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
488  }
489  }
490  /* Used by pre-9.0 binary upgrades */
491  else if (tuple->t_infomask & HEAP_MOVED_IN)
492  {
494 
496  {
497  if (TransactionIdIsInProgress(xvac))
498  return TM_Invisible;
499  if (TransactionIdDidCommit(xvac))
500  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
502  else
503  {
504  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
506  return TM_Invisible;
507  }
508  }
509  }
511  {
512  if (HeapTupleHeaderGetCmin(tuple) >= curcid)
513  return TM_Invisible; /* inserted after scan started */
514 
515  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
516  return TM_Ok;
517 
519  {
520  TransactionId xmax;
521 
522  xmax = HeapTupleHeaderGetRawXmax(tuple);
523 
524  /*
525  * Careful here: even though this tuple was created by our own
526  * transaction, it might be locked by other transactions, if
527  * the original version was key-share locked when we updated
528  * it.
529  */
530 
531  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
532  {
533  if (MultiXactIdIsRunning(xmax, true))
534  return TM_BeingModified;
535  else
536  return TM_Ok;
537  }
538 
539  /*
540  * If the locker is gone, then there is nothing of interest
541  * left in this Xmax; otherwise, report the tuple as
542  * locked/updated.
543  */
544  if (!TransactionIdIsInProgress(xmax))
545  return TM_Ok;
546  return TM_BeingModified;
547  }
548 
549  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
550  {
551  TransactionId xmax;
552 
553  xmax = HeapTupleGetUpdateXid(tuple);
554 
555  /* not LOCKED_ONLY, so it has to have an xmax */
557 
558  /* deleting subtransaction must have aborted */
560  {
562  false))
563  return TM_BeingModified;
564  return TM_Ok;
565  }
566  else
567  {
568  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
569  return TM_SelfModified; /* updated after scan started */
570  else
571  return TM_Invisible; /* updated before scan started */
572  }
573  }
574 
576  {
577  /* deleting subtransaction must have aborted */
578  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
580  return TM_Ok;
581  }
582 
583  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
584  return TM_SelfModified; /* updated after scan started */
585  else
586  return TM_Invisible; /* updated before scan started */
587  }
589  return TM_Invisible;
591  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
593  else
594  {
595  /* it must have aborted or crashed */
596  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
598  return TM_Invisible;
599  }
600  }
601 
602  /* by here, the inserting transaction has committed */
603 
604  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
605  return TM_Ok;
606 
607  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
608  {
610  return TM_Ok;
611  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))
657  return TM_Updated;
658  else
659  return TM_Deleted;
660  }
661 
662  /*
663  * By here, the update in the Xmax is either aborted or crashed, but
664  * what about the other members?
665  */
666 
668  {
669  /*
670  * There's no member, even just a locker, alive anymore, so we can
671  * mark the Xmax as invalid.
672  */
673  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
675  return TM_Ok;
676  }
677  else
678  {
679  /* There are lockers running */
680  return TM_BeingModified;
681  }
682  }
683 
685  {
687  return TM_BeingModified;
688  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
689  return TM_SelfModified; /* updated after scan started */
690  else
691  return TM_Invisible; /* updated before scan started */
692  }
693 
695  return TM_BeingModified;
696 
698  {
699  /* it must have aborted or crashed */
700  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
702  return TM_Ok;
703  }
704 
705  /* xmax transaction committed */
706 
708  {
709  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
711  return TM_Ok;
712  }
713 
714  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
716  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
717  return TM_Updated; /* updated by other */
718  else
719  return TM_Deleted; /* deleted by other */
720 }
721 
722 /*
723  * HeapTupleSatisfiesDirty
724  * True iff heap tuple is valid including effects of open transactions.
725  *
726  * See SNAPSHOT_DIRTY's definition for the intended behaviour.
727  *
728  * This is essentially like HeapTupleSatisfiesSelf as far as effects of
729  * the current transaction and committed/aborted xacts are concerned.
730  * However, we also include the effects of other xacts still in progress.
731  *
732  * A special hack is that the passed-in snapshot struct is used as an
733  * output argument to return the xids of concurrent xacts that affected the
734  * tuple. snapshot->xmin is set to the tuple's xmin if that is another
735  * transaction that's still in progress; or to InvalidTransactionId if the
736  * tuple's xmin is committed good, committed dead, or my own xact.
737  * Similarly for snapshot->xmax and the tuple's xmax. If the tuple was
738  * inserted speculatively, meaning that the inserter might still back down
739  * on the insertion without aborting the whole transaction, the associated
740  * token is also returned in snapshot->speculativeToken.
741  */
742 static bool
744  Buffer buffer)
745 {
746  HeapTupleHeader tuple = htup->t_data;
747 
749  Assert(htup->t_tableOid != InvalidOid);
750 
751  snapshot->xmin = snapshot->xmax = InvalidTransactionId;
752  snapshot->speculativeToken = 0;
753 
754  if (!HeapTupleHeaderXminCommitted(tuple))
755  {
756  if (HeapTupleHeaderXminInvalid(tuple))
757  return false;
758 
759  /* Used by pre-9.0 binary upgrades */
760  if (tuple->t_infomask & HEAP_MOVED_OFF)
761  {
763 
765  return false;
766  if (!TransactionIdIsInProgress(xvac))
767  {
768  if (TransactionIdDidCommit(xvac))
769  {
770  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
772  return false;
773  }
774  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
776  }
777  }
778  /* Used by pre-9.0 binary upgrades */
779  else if (tuple->t_infomask & HEAP_MOVED_IN)
780  {
782 
784  {
785  if (TransactionIdIsInProgress(xvac))
786  return false;
787  if (TransactionIdDidCommit(xvac))
788  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
790  else
791  {
792  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
794  return false;
795  }
796  }
797  }
799  {
800  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
801  return true;
802 
803  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
804  return true;
805 
806  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
807  {
808  TransactionId xmax;
809 
810  xmax = HeapTupleGetUpdateXid(tuple);
811 
812  /* not LOCKED_ONLY, so it has to have an xmax */
814 
815  /* updating subtransaction must have aborted */
817  return true;
818  else
819  return false;
820  }
821 
823  {
824  /* deleting subtransaction must have aborted */
825  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
827  return true;
828  }
829 
830  return false;
831  }
833  {
834  /*
835  * Return the speculative token to caller. Caller can worry about
836  * xmax, since it requires a conclusively locked row version, and
837  * a concurrent update to this tuple is a conflict of its
838  * purposes.
839  */
840  if (HeapTupleHeaderIsSpeculative(tuple))
841  {
842  snapshot->speculativeToken =
844 
845  Assert(snapshot->speculativeToken != 0);
846  }
847 
848  snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
849  /* XXX shouldn't we fall through to look at xmax? */
850  return true; /* in insertion by other */
851  }
853  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
855  else
856  {
857  /* it must have aborted or crashed */
858  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
860  return false;
861  }
862  }
863 
864  /* by here, the inserting transaction has committed */
865 
866  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
867  return true;
868 
869  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
870  {
872  return true;
873  return false; /* updated by other */
874  }
875 
876  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
877  {
878  TransactionId xmax;
879 
881  return true;
882 
883  xmax = HeapTupleGetUpdateXid(tuple);
884 
885  /* not LOCKED_ONLY, so it has to have an xmax */
887 
889  return false;
890  if (TransactionIdIsInProgress(xmax))
891  {
892  snapshot->xmax = xmax;
893  return true;
894  }
895  if (TransactionIdDidCommit(xmax))
896  return false;
897  /* it must have aborted or crashed */
898  return true;
899  }
900 
902  {
904  return true;
905  return false;
906  }
907 
909  {
911  snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
912  return true;
913  }
914 
916  {
917  /* it must have aborted or crashed */
918  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
920  return true;
921  }
922 
923  /* xmax transaction committed */
924 
926  {
927  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
929  return true;
930  }
931 
932  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
934  return false; /* updated by other */
935 }
936 
937 /*
938  * HeapTupleSatisfiesMVCC
939  * True iff heap tuple is valid for the given MVCC snapshot.
940  *
941  * See SNAPSHOT_MVCC's definition for the intended behaviour.
942  *
943  * Notice that here, we will not update the tuple status hint bits if the
944  * inserting/deleting transaction is still running according to our snapshot,
945  * even if in reality it's committed or aborted by now. This is intentional.
946  * Checking the true transaction state would require access to high-traffic
947  * shared data structures, creating contention we'd rather do without, and it
948  * would not change the result of our visibility check anyway. The hint bits
949  * will be updated by the first visitor that has a snapshot new enough to see
950  * the inserting/deleting transaction as done. In the meantime, the cost of
951  * leaving the hint bits unset is basically that each HeapTupleSatisfiesMVCC
952  * call will need to run TransactionIdIsCurrentTransactionId in addition to
953  * XidInMVCCSnapshot (but it would have to do the latter anyway). In the old
954  * coding where we tried to set the hint bits as soon as possible, we instead
955  * did TransactionIdIsInProgress in each call --- to no avail, as long as the
956  * inserting/deleting transaction was still running --- which was more cycles
957  * and more contention on ProcArrayLock.
958  */
959 static bool
961  Buffer buffer)
962 {
963  HeapTupleHeader tuple = htup->t_data;
964 
966  Assert(htup->t_tableOid != InvalidOid);
967 
968  if (!HeapTupleHeaderXminCommitted(tuple))
969  {
970  if (HeapTupleHeaderXminInvalid(tuple))
971  return false;
972 
973  /* Used by pre-9.0 binary upgrades */
974  if (tuple->t_infomask & HEAP_MOVED_OFF)
975  {
977 
979  return false;
980  if (!XidInMVCCSnapshot(xvac, snapshot))
981  {
982  if (TransactionIdDidCommit(xvac))
983  {
984  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
986  return false;
987  }
988  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
990  }
991  }
992  /* Used by pre-9.0 binary upgrades */
993  else if (tuple->t_infomask & HEAP_MOVED_IN)
994  {
996 
998  {
999  if (XidInMVCCSnapshot(xvac, snapshot))
1000  return false;
1001  if (TransactionIdDidCommit(xvac))
1002  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1004  else
1005  {
1006  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1008  return false;
1009  }
1010  }
1011  }
1013  {
1014  if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
1015  return false; /* inserted after scan started */
1016 
1017  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1018  return true;
1019 
1020  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
1021  return true;
1022 
1023  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1024  {
1025  TransactionId xmax;
1026 
1027  xmax = HeapTupleGetUpdateXid(tuple);
1028 
1029  /* not LOCKED_ONLY, so it has to have an xmax */
1031 
1032  /* updating subtransaction must have aborted */
1034  return true;
1035  else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1036  return true; /* updated after scan started */
1037  else
1038  return false; /* updated before scan started */
1039  }
1040 
1042  {
1043  /* deleting subtransaction must have aborted */
1044  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1046  return true;
1047  }
1048 
1049  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1050  return true; /* deleted after scan started */
1051  else
1052  return false; /* deleted before scan started */
1053  }
1054  else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1055  return false;
1057  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1058  HeapTupleHeaderGetRawXmin(tuple));
1059  else
1060  {
1061  /* it must have aborted or crashed */
1062  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1064  return false;
1065  }
1066  }
1067  else
1068  {
1069  /* xmin is committed, but maybe not according to our snapshot */
1070  if (!HeapTupleHeaderXminFrozen(tuple) &&
1071  XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1072  return false; /* treat as still in progress */
1073  }
1074 
1075  /* by here, the inserting transaction has committed */
1076 
1077  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1078  return true;
1079 
1081  return true;
1082 
1083  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1084  {
1085  TransactionId xmax;
1086 
1087  /* already checked above */
1089 
1090  xmax = HeapTupleGetUpdateXid(tuple);
1091 
1092  /* not LOCKED_ONLY, so it has to have an xmax */
1094 
1096  {
1097  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1098  return true; /* deleted after scan started */
1099  else
1100  return false; /* deleted before scan started */
1101  }
1102  if (XidInMVCCSnapshot(xmax, snapshot))
1103  return true;
1104  if (TransactionIdDidCommit(xmax))
1105  return false; /* updating transaction committed */
1106  /* it must have aborted or crashed */
1107  return true;
1108  }
1109 
1110  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1111  {
1113  {
1114  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1115  return true; /* deleted after scan started */
1116  else
1117  return false; /* deleted before scan started */
1118  }
1119 
1120  if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1121  return true;
1122 
1124  {
1125  /* it must have aborted or crashed */
1126  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1128  return true;
1129  }
1130 
1131  /* xmax transaction committed */
1132  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1133  HeapTupleHeaderGetRawXmax(tuple));
1134  }
1135  else
1136  {
1137  /* xmax is committed, but maybe not according to our snapshot */
1138  if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1139  return true; /* treat as still in progress */
1140  }
1141 
1142  /* xmax transaction committed */
1143 
1144  return false;
1145 }
1146 
1147 
1148 /*
1149  * HeapTupleSatisfiesVacuum
1150  *
1151  * Determine the status of tuples for VACUUM purposes. Here, what
1152  * we mainly want to know is if a tuple is potentially visible to *any*
1153  * running transaction. If so, it can't be removed yet by VACUUM.
1154  *
1155  * OldestXmin is a cutoff XID (obtained from
1156  * GetOldestNonRemovableTransactionId()). Tuples deleted by XIDs >=
1157  * OldestXmin are deemed "recently dead"; they might still be visible to some
1158  * open transaction, so we can't remove them, even if we see that the deleting
1159  * transaction has committed.
1160  */
1163  Buffer buffer)
1164 {
1165  TransactionId dead_after = InvalidTransactionId;
1166  HTSV_Result res;
1167 
1168  res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1169 
1171  {
1172  Assert(TransactionIdIsValid(dead_after));
1173 
1174  if (TransactionIdPrecedes(dead_after, OldestXmin))
1175  res = HEAPTUPLE_DEAD;
1176  }
1177  else
1178  Assert(!TransactionIdIsValid(dead_after));
1179 
1180  return res;
1181 }
1182 
1183 /*
1184  * Work horse for HeapTupleSatisfiesVacuum and similar routines.
1185  *
1186  * In contrast to HeapTupleSatisfiesVacuum this routine, when encountering a
1187  * tuple that could still be visible to some backend, stores the xid that
1188  * needs to be compared with the horizon in *dead_after, and returns
1189  * HEAPTUPLE_RECENTLY_DEAD. The caller then can perform the comparison with
1190  * the horizon. This is e.g. useful when comparing with different horizons.
1191  *
1192  * Note: HEAPTUPLE_DEAD can still be returned here, e.g. if the inserting
1193  * transaction aborted.
1194  */
1197 {
1198  HeapTupleHeader tuple = htup->t_data;
1199 
1200  Assert(ItemPointerIsValid(&htup->t_self));
1201  Assert(htup->t_tableOid != InvalidOid);
1202  Assert(dead_after != NULL);
1203 
1204  *dead_after = InvalidTransactionId;
1205 
1206  /*
1207  * Has inserting transaction committed?
1208  *
1209  * If the inserting transaction aborted, then the tuple was never visible
1210  * to any other transaction, so we can delete it immediately.
1211  */
1212  if (!HeapTupleHeaderXminCommitted(tuple))
1213  {
1214  if (HeapTupleHeaderXminInvalid(tuple))
1215  return HEAPTUPLE_DEAD;
1216  /* Used by pre-9.0 binary upgrades */
1217  else if (tuple->t_infomask & HEAP_MOVED_OFF)
1218  {
1219  TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1220 
1223  if (TransactionIdIsInProgress(xvac))
1225  if (TransactionIdDidCommit(xvac))
1226  {
1227  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1229  return HEAPTUPLE_DEAD;
1230  }
1231  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1233  }
1234  /* Used by pre-9.0 binary upgrades */
1235  else if (tuple->t_infomask & HEAP_MOVED_IN)
1236  {
1237  TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1238 
1241  if (TransactionIdIsInProgress(xvac))
1243  if (TransactionIdDidCommit(xvac))
1244  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1246  else
1247  {
1248  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1250  return HEAPTUPLE_DEAD;
1251  }
1252  }
1254  {
1255  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1257  /* only locked? run infomask-only check first, for performance */
1258  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
1261  /* inserted and then deleted by same xact */
1264  /* deleting subtransaction must have aborted */
1266  }
1268  {
1269  /*
1270  * It'd be possible to discern between INSERT/DELETE in progress
1271  * here by looking at xmax - but that doesn't seem beneficial for
1272  * the majority of callers and even detrimental for some. We'd
1273  * rather have callers look at/wait for xmin than xmax. It's
1274  * always correct to return INSERT_IN_PROGRESS because that's
1275  * what's happening from the view of other backends.
1276  */
1278  }
1280  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1281  HeapTupleHeaderGetRawXmin(tuple));
1282  else
1283  {
1284  /*
1285  * Not in Progress, Not Committed, so either Aborted or crashed
1286  */
1287  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1289  return HEAPTUPLE_DEAD;
1290  }
1291 
1292  /*
1293  * At this point the xmin is known committed, but we might not have
1294  * been able to set the hint bit yet; so we can no longer Assert that
1295  * it's set.
1296  */
1297  }
1298 
1299  /*
1300  * Okay, the inserter committed, so it was good at some point. Now what
1301  * about the deleting transaction?
1302  */
1303  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1304  return HEAPTUPLE_LIVE;
1305 
1307  {
1308  /*
1309  * "Deleting" xact really only locked it, so the tuple is live in any
1310  * case. However, we should make sure that either XMAX_COMMITTED or
1311  * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1312  * examining the tuple for future xacts.
1313  */
1314  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1315  {
1316  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1317  {
1318  /*
1319  * If it's a pre-pg_upgrade tuple, the multixact cannot
1320  * possibly be running; otherwise have to check.
1321  */
1322  if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
1324  true))
1325  return HEAPTUPLE_LIVE;
1327  }
1328  else
1329  {
1331  return HEAPTUPLE_LIVE;
1332  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1334  }
1335  }
1336 
1337  /*
1338  * We don't really care whether xmax did commit, abort or crash. We
1339  * know that xmax did lock the tuple, but it did not and will never
1340  * actually update it.
1341  */
1342 
1343  return HEAPTUPLE_LIVE;
1344  }
1345 
1346  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1347  {
1348  TransactionId xmax = HeapTupleGetUpdateXid(tuple);
1349 
1350  /* already checked above */
1352 
1353  /* not LOCKED_ONLY, so it has to have an xmax */
1355 
1356  if (TransactionIdIsInProgress(xmax))
1358  else if (TransactionIdDidCommit(xmax))
1359  {
1360  /*
1361  * The multixact might still be running due to lockers. Need to
1362  * allow for pruning if below the xid horizon regardless --
1363  * otherwise we could end up with a tuple where the updater has to
1364  * be removed due to the horizon, but is not pruned away. It's
1365  * not a problem to prune that tuple, because any remaining
1366  * lockers will also be present in newer tuple versions.
1367  */
1368  *dead_after = xmax;
1369  return HEAPTUPLE_RECENTLY_DEAD;
1370  }
1371  else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1372  {
1373  /*
1374  * Not in Progress, Not Committed, so either Aborted or crashed.
1375  * Mark the Xmax as invalid.
1376  */
1378  }
1379 
1380  return HEAPTUPLE_LIVE;
1381  }
1382 
1383  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1384  {
1388  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1389  HeapTupleHeaderGetRawXmax(tuple));
1390  else
1391  {
1392  /*
1393  * Not in Progress, Not Committed, so either Aborted or crashed
1394  */
1395  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1397  return HEAPTUPLE_LIVE;
1398  }
1399 
1400  /*
1401  * At this point the xmax is known committed, but we might not have
1402  * been able to set the hint bit yet; so we can no longer Assert that
1403  * it's set.
1404  */
1405  }
1406 
1407  /*
1408  * Deleter committed, allow caller to check if it was recent enough that
1409  * some open transactions could still see the tuple.
1410  */
1411  *dead_after = HeapTupleHeaderGetRawXmax(tuple);
1412  return HEAPTUPLE_RECENTLY_DEAD;
1413 }
1414 
1415 
1416 /*
1417  * HeapTupleSatisfiesNonVacuumable
1418  *
1419  * True if tuple might be visible to some transaction; false if it's
1420  * surely dead to everyone, ie, vacuumable.
1421  *
1422  * See SNAPSHOT_NON_VACUUMABLE's definition for the intended behaviour.
1423  *
1424  * This is an interface to HeapTupleSatisfiesVacuum that's callable via
1425  * HeapTupleSatisfiesSnapshot, so it can be used through a Snapshot.
1426  * snapshot->vistest must have been set up with the horizon to use.
1427  */
1428 static bool
1430  Buffer buffer)
1431 {
1432  TransactionId dead_after = InvalidTransactionId;
1433  HTSV_Result res;
1434 
1435  res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1436 
1438  {
1439  Assert(TransactionIdIsValid(dead_after));
1440 
1441  if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after))
1442  res = HEAPTUPLE_DEAD;
1443  }
1444  else
1445  Assert(!TransactionIdIsValid(dead_after));
1446 
1447  return res != HEAPTUPLE_DEAD;
1448 }
1449 
1450 
1451 /*
1452  * HeapTupleIsSurelyDead
1453  *
1454  * Cheaply determine whether a tuple is surely dead to all onlookers.
1455  * We sometimes use this in lieu of HeapTupleSatisfiesVacuum when the
1456  * tuple has just been tested by another visibility routine (usually
1457  * HeapTupleSatisfiesMVCC) and, therefore, any hint bits that can be set
1458  * should already be set. We assume that if no hint bits are set, the xmin
1459  * or xmax transaction is still running. This is therefore faster than
1460  * HeapTupleSatisfiesVacuum, because we consult neither procarray nor CLOG.
1461  * It's okay to return false when in doubt, but we must return true only
1462  * if the tuple is removable.
1463  */
1464 bool
1466 {
1467  HeapTupleHeader tuple = htup->t_data;
1468 
1469  Assert(ItemPointerIsValid(&htup->t_self));
1470  Assert(htup->t_tableOid != InvalidOid);
1471 
1472  /*
1473  * If the inserting transaction is marked invalid, then it aborted, and
1474  * the tuple is definitely dead. If it's marked neither committed nor
1475  * invalid, then we assume it's still alive (since the presumption is that
1476  * all relevant hint bits were just set moments ago).
1477  */
1478  if (!HeapTupleHeaderXminCommitted(tuple))
1479  return HeapTupleHeaderXminInvalid(tuple);
1480 
1481  /*
1482  * If the inserting transaction committed, but any deleting transaction
1483  * aborted, the tuple is still alive.
1484  */
1485  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1486  return false;
1487 
1488  /*
1489  * If the XMAX is just a lock, the tuple is still alive.
1490  */
1492  return false;
1493 
1494  /*
1495  * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1496  * know without checking pg_multixact.
1497  */
1498  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1499  return false;
1500 
1501  /* If deleter isn't known to have committed, assume it's still running. */
1502  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1503  return false;
1504 
1505  /* Deleter committed, so tuple is dead if the XID is old enough. */
1506  return GlobalVisTestIsRemovableXid(vistest,
1507  HeapTupleHeaderGetRawXmax(tuple));
1508 }
1509 
1510 /*
1511  * Is the tuple really only locked? That is, is it not updated?
1512  *
1513  * It's easy to check just infomask bits if the locker is not a multi; but
1514  * otherwise we need to verify that the updating transaction has not aborted.
1515  *
1516  * This function is here because it follows the same visibility rules laid out
1517  * at the top of this file.
1518  */
1519 bool
1521 {
1522  TransactionId xmax;
1523 
1524  /* if there's no valid Xmax, then there's obviously no update either */
1525  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1526  return true;
1527 
1528  if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1529  return true;
1530 
1531  /* invalid xmax means no update */
1533  return true;
1534 
1535  /*
1536  * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1537  * necessarily have been updated
1538  */
1539  if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1540  return false;
1541 
1542  /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1543  xmax = HeapTupleGetUpdateXid(tuple);
1544 
1545  /* not LOCKED_ONLY, so it has to have an xmax */
1547 
1549  return false;
1550  if (TransactionIdIsInProgress(xmax))
1551  return false;
1552  if (TransactionIdDidCommit(xmax))
1553  return false;
1554 
1555  /*
1556  * not current, not in progress, not committed -- must have aborted or
1557  * crashed
1558  */
1559  return true;
1560 }
1561 
1562 /*
1563  * check whether the transaction id 'xid' is in the pre-sorted array 'xip'.
1564  */
1565 static bool
1567 {
1568  return num > 0 &&
1569  bsearch(&xid, xip, num, sizeof(TransactionId), xidComparator) != NULL;
1570 }
1571 
1572 /*
1573  * See the comments for HeapTupleSatisfiesMVCC for the semantics this function
1574  * obeys.
1575  *
1576  * Only usable on tuples from catalog tables!
1577  *
1578  * We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
1579  * reading catalog pages which couldn't have been created in an older version.
1580  *
1581  * We don't set any hint bits in here as it seems unlikely to be beneficial as
1582  * those should already be set by normal access and it seems to be too
1583  * dangerous to do so as the semantics of doing so during timetravel are more
1584  * complicated than when dealing "only" with the present.
1585  */
1586 static bool
1588  Buffer buffer)
1589 {
1590  HeapTupleHeader tuple = htup->t_data;
1591  TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
1593 
1594  Assert(ItemPointerIsValid(&htup->t_self));
1595  Assert(htup->t_tableOid != InvalidOid);
1596 
1597  /* inserting transaction aborted */
1598  if (HeapTupleHeaderXminInvalid(tuple))
1599  {
1601  return false;
1602  }
1603  /* check if it's one of our txids, toplevel is also in there */
1604  else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1605  {
1606  bool resolved;
1608  CommandId cmax = InvalidCommandId;
1609 
1610  /*
1611  * another transaction might have (tried to) delete this tuple or
1612  * cmin/cmax was stored in a combo CID. So we need to lookup the
1613  * actual values externally.
1614  */
1616  htup, buffer,
1617  &cmin, &cmax);
1618 
1619  /*
1620  * If we haven't resolved the combo CID to cmin/cmax, that means we
1621  * have not decoded the combo CID yet. That means the cmin is
1622  * definitely in the future, and we're not supposed to see the tuple
1623  * yet.
1624  *
1625  * XXX This only applies to decoding of in-progress transactions. In
1626  * regular logical decoding we only execute this code at commit time,
1627  * at which point we should have seen all relevant combo CIDs. So
1628  * ideally, we should error out in this case but in practice, this
1629  * won't happen. If we are too worried about this then we can add an
1630  * elog inside ResolveCminCmaxDuringDecoding.
1631  *
1632  * XXX For the streaming case, we can track the largest combo CID
1633  * assigned, and error out based on this (when unable to resolve combo
1634  * CID below that observed maximum value).
1635  */
1636  if (!resolved)
1637  return false;
1638 
1639  Assert(cmin != InvalidCommandId);
1640 
1641  if (cmin >= snapshot->curcid)
1642  return false; /* inserted after scan started */
1643  /* fall through */
1644  }
1645  /* committed before our xmin horizon. Do a normal visibility check. */
1646  else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1647  {
1649  !TransactionIdDidCommit(xmin)));
1650 
1651  /* check for hint bit first, consult clog afterwards */
1652  if (!HeapTupleHeaderXminCommitted(tuple) &&
1653  !TransactionIdDidCommit(xmin))
1654  return false;
1655  /* fall through */
1656  }
1657  /* beyond our xmax horizon, i.e. invisible */
1658  else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1659  {
1660  return false;
1661  }
1662  /* check if it's a committed transaction in [xmin, xmax) */
1663  else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1664  {
1665  /* fall through */
1666  }
1667 
1668  /*
1669  * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1670  * invisible.
1671  */
1672  else
1673  {
1674  return false;
1675  }
1676 
1677  /* at this point we know xmin is visible, go on to check xmax */
1678 
1679  /* xid invalid or aborted */
1680  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1681  return true;
1682  /* locked tuples are always visible */
1683  else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1684  return true;
1685 
1686  /*
1687  * We can see multis here if we're looking at user tables or if somebody
1688  * SELECT ... FOR SHARE/UPDATE a system table.
1689  */
1690  else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1691  {
1692  xmax = HeapTupleGetUpdateXid(tuple);
1693  }
1694 
1695  /* check if it's one of our txids, toplevel is also in there */
1696  if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1697  {
1698  bool resolved;
1699  CommandId cmin;
1701 
1702  /* Lookup actual cmin/cmax values */
1704  htup, buffer,
1705  &cmin, &cmax);
1706 
1707  /*
1708  * If we haven't resolved the combo CID to cmin/cmax, that means we
1709  * have not decoded the combo CID yet. That means the cmax is
1710  * definitely in the future, and we're still supposed to see the
1711  * tuple.
1712  *
1713  * XXX This only applies to decoding of in-progress transactions. In
1714  * regular logical decoding we only execute this code at commit time,
1715  * at which point we should have seen all relevant combo CIDs. So
1716  * ideally, we should error out in this case but in practice, this
1717  * won't happen. If we are too worried about this then we can add an
1718  * elog inside ResolveCminCmaxDuringDecoding.
1719  *
1720  * XXX For the streaming case, we can track the largest combo CID
1721  * assigned, and error out based on this (when unable to resolve combo
1722  * CID below that observed maximum value).
1723  */
1724  if (!resolved || cmax == InvalidCommandId)
1725  return true;
1726 
1727  if (cmax >= snapshot->curcid)
1728  return true; /* deleted after scan started */
1729  else
1730  return false; /* deleted before scan started */
1731  }
1732  /* below xmin horizon, normal transaction state is valid */
1733  else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1734  {
1735  Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
1736  !TransactionIdDidCommit(xmax)));
1737 
1738  /* check hint bit first */
1739  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1740  return false;
1741 
1742  /* check clog */
1743  return !TransactionIdDidCommit(xmax);
1744  }
1745  /* above xmax horizon, we cannot possibly see the deleting transaction */
1746  else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1747  return true;
1748  /* xmax is between [xmin, xmax), check known committed array */
1749  else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1750  return false;
1751  /* xmax is between [xmin, xmax), but known not to have committed yet */
1752  else
1753  return true;
1754 }
1755 
1756 /*
1757  * HeapTupleSatisfiesVisibility
1758  * True iff heap tuple satisfies a time qual.
1759  *
1760  * Notes:
1761  * Assumes heap tuple is valid, and buffer at least share locked.
1762  *
1763  * Hint bits in the HeapTuple's t_infomask may be updated as a side effect;
1764  * if so, the indicated buffer is marked dirty.
1765  */
1766 bool
1768 {
1769  switch (snapshot->snapshot_type)
1770  {
1771  case SNAPSHOT_MVCC:
1772  return HeapTupleSatisfiesMVCC(htup, snapshot, buffer);
1773  case SNAPSHOT_SELF:
1774  return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
1775  case SNAPSHOT_ANY:
1776  return HeapTupleSatisfiesAny(htup, snapshot, buffer);
1777  case SNAPSHOT_TOAST:
1778  return HeapTupleSatisfiesToast(htup, snapshot, buffer);
1779  case SNAPSHOT_DIRTY:
1780  return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
1782  return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
1784  return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
1785  }
1786 
1787  return false; /* keep compiler quiet */
1788 }
int Buffer
Definition: buf.h:23
bool BufferIsPermanent(Buffer buffer)
Definition: bufmgr.c:3898
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3928
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:4914
#define InvalidCommandId
Definition: c.h:669
unsigned short uint16
Definition: c.h:505
#define Assert(condition)
Definition: c.h:858
uint32 CommandId
Definition: c.h:666
uint32 TransactionId
Definition: c.h:652
size_t Size
Definition: c.h:605
CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup)
Definition: combocid.c:104
CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup)
Definition: combocid.c:118
TransactionId HeapTupleGetUpdateXid(HeapTupleHeader tuple)
Definition: heapam.c:7097
HTSV_Result
Definition: heapam.h:124
@ HEAPTUPLE_RECENTLY_DEAD
Definition: heapam.h:127
@ HEAPTUPLE_INSERT_IN_PROGRESS
Definition: heapam.h:128
@ HEAPTUPLE_LIVE
Definition: heapam.h:126
@ HEAPTUPLE_DELETE_IN_PROGRESS
Definition: heapam.h:129
@ HEAPTUPLE_DEAD
Definition: heapam.h:125
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
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:557
#define InvalidOid
Definition: postgres_ext.h:36
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4251
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1390
bool ResolveCminCmaxDuringDecoding(HTAB *tuplecid_data, Snapshot snapshot, HeapTuple htup, Buffer buffer, CommandId *cmin, CommandId *cmax)
bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
Definition: snapmgr.c:1856
HTAB * HistoricSnapshotGetTupleCids(void)
Definition: snapmgr.c:1678
@ 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:80
@ TM_Ok
Definition: tableam.h:85
@ TM_BeingModified
Definition: tableam.h:107
@ TM_Deleted
Definition: tableam.h:100
@ TM_Updated
Definition: tableam.h:97
@ TM_SelfModified
Definition: tableam.h:91
@ TM_Invisible
Definition: tableam.h:88
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:938
int xidComparator(const void *arg1, const void *arg2)
Definition: xid.c:139
bool XLogNeedsFlush(XLogRecPtr record)
Definition: xlog.c:3122
uint64 XLogRecPtr
Definition: xlogdefs.h:21