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