1/*-------------------------------------------------------------------------
2 *
3 * heapam_visibility.c
4 * Tuple visibility rules for tuples stored in heap.
5 *
6 * NOTE: all the HeapTupleSatisfies routines will update the tuple's
7 * "hint" status bits if we see that the inserting or deleting transaction
8 * has now committed or aborted (and it is safe to set the hint bits).
9 * If the hint bits are changed, MarkBufferDirtyHint is called on
10 * the passed-in buffer. The caller must hold not only a pin, but at least
11 * shared buffer content lock on the buffer containing the tuple.
12 *
13 * NOTE: When using a non-MVCC snapshot, we must check
14 * TransactionIdIsInProgress (which looks in the PGXACT array)
15 * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
16 * pg_xact). Otherwise we have a race condition: we might decide that a
17 * just-committed transaction crashed, because none of the tests succeed.
18 * xact.c is careful to record commit/abort in pg_xact before it unsets
19 * MyPgXact->xid in the PGXACT array. That fixes that problem, but it
20 * also means there is a window where TransactionIdIsInProgress and
21 * TransactionIdDidCommit will both return true. If we check only
22 * TransactionIdDidCommit, we could consider a tuple committed when a
23 * later GetSnapshotData call will still think the originating transaction
24 * is in progress, which leads to application-level inconsistency. The
25 * upshot is that we gotta check TransactionIdIsInProgress first in all
26 * code paths, except for a few cases where we are looking at
27 * subtransactions of our own main transaction and so there can't be any
28 * race condition.
29 *
30 * When using an MVCC snapshot, we rely on XidInMVCCSnapshot rather than
31 * TransactionIdIsInProgress, but the logic is otherwise the same: do not
32 * check pg_xact until after deciding that the xact is no longer in progress.
33 *
34 *
35 * Summary of visibility functions:
36 *
37 * HeapTupleSatisfiesMVCC()
38 * visible to supplied snapshot, excludes current command
39 * HeapTupleSatisfiesUpdate()
40 * visible to instant snapshot, with user-supplied command
41 * counter and more complex result
42 * HeapTupleSatisfiesSelf()
43 * visible to instant snapshot and current command
44 * HeapTupleSatisfiesDirty()
45 * like HeapTupleSatisfiesSelf(), but includes open transactions
46 * HeapTupleSatisfiesVacuum()
47 * visible to any running transaction, used by VACUUM
48 * HeapTupleSatisfiesNonVacuumable()
49 * Snapshot-style API for HeapTupleSatisfiesVacuum
50 * HeapTupleSatisfiesToast()
51 * visible unless part of interrupted vacuum, used for TOAST
52 * HeapTupleSatisfiesAny()
53 * all tuples are visible
54 *
55 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
56 * Portions Copyright (c) 1994, Regents of the University of California
57 *
58 * IDENTIFICATION
59 * src/backend/access/heap/heapam_visibility.c
60 *
61 *-------------------------------------------------------------------------
62 */
63
64#include "postgres.h"
65
66#include "access/heapam.h"
67#include "access/htup_details.h"
68#include "access/multixact.h"
69#include "access/subtrans.h"
70#include "access/tableam.h"
71#include "access/transam.h"
72#include "access/xact.h"
73#include "access/xlog.h"
74#include "storage/bufmgr.h"
75#include "storage/procarray.h"
76#include "utils/builtins.h"
77#include "utils/combocid.h"
78#include "utils/snapmgr.h"
79
80
81/*
82 * SetHintBits()
83 *
84 * Set commit/abort hint bits on a tuple, if appropriate at this time.
85 *
86 * It is only safe to set a transaction-committed hint bit if we know the
87 * transaction's commit record is guaranteed to be flushed to disk before the
88 * buffer, or if the table is temporary or unlogged and will be obliterated by
89 * a crash anyway. We cannot change the LSN of the page here, because we may
90 * hold only a share lock on the buffer, so we can only use the LSN to
91 * interlock this if the buffer's LSN already is newer than the commit LSN;
92 * otherwise we have to just refrain from setting the hint bit until some
93 * future re-examination of the tuple.
94 *
95 * We can always set hint bits when marking a transaction aborted. (Some
96 * code in heapam.c relies on that!)
97 *
98 * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
99 * we can always set the hint bits, since pre-9.0 VACUUM FULL always used
100 * synchronous commits and didn't move tuples that weren't previously
101 * hinted. (This is not known by this subroutine, but is applied by its
102 * callers.) Note: old-style VACUUM FULL is gone, but we have to keep this
103 * module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
104 * support in-place update from pre-9.0 databases.
105 *
106 * Normal commits may be asynchronous, so for those we need to get the LSN
107 * of the transaction and then check whether this is flushed.
108 *
109 * The caller should pass xid as the XID of the transaction to check, or
110 * InvalidTransactionId if no check is needed.
111 */
112static inline void
113SetHintBits(HeapTupleHeader tuple, Buffer buffer,
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 */
139void
140HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
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 */
168static bool
169HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
170{
171 HeapTupleHeader tuple = htup->t_data;
172
173 Assert(ItemPointerIsValid(&htup->t_self));
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 {
184 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
185
186 if (TransactionIdIsCurrentTransactionId(xvac))
187 return false;
188 if (!TransactionIdIsInProgress(xvac))
189 {
190 if (TransactionIdDidCommit(xvac))
191 {
192 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
193 InvalidTransactionId);
194 return false;
195 }
196 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
197 InvalidTransactionId);
198 }
199 }
200 /* Used by pre-9.0 binary upgrades */
201 else if (tuple->t_infomask & HEAP_MOVED_IN)
202 {
203 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
204
205 if (!TransactionIdIsCurrentTransactionId(xvac))
206 {
207 if (TransactionIdIsInProgress(xvac))
208 return false;
209 if (TransactionIdDidCommit(xvac))
210 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
211 InvalidTransactionId);
212 else
213 {
214 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
215 InvalidTransactionId);
216 return false;
217 }
218 }
219 }
220 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
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 */
235 Assert(TransactionIdIsValid(xmax));
236
237 /* updating subtransaction must have aborted */
238 if (!TransactionIdIsCurrentTransactionId(xmax))
239 return true;
240 else
241 return false;
242 }
243
244 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
245 {
246 /* deleting subtransaction must have aborted */
247 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
248 InvalidTransactionId);
249 return true;
250 }
251
252 return false;
253 }
254 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
255 return false;
256 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
257 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
258 HeapTupleHeaderGetRawXmin(tuple));
259 else
260 {
261 /* it must have aborted or crashed */
262 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
263 InvalidTransactionId);
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 {
275 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
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
284 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
285 return true;
286
287 xmax = HeapTupleGetUpdateXid(tuple);
288
289 /* not LOCKED_ONLY, so it has to have an xmax */
290 Assert(TransactionIdIsValid(xmax));
291
292 if (TransactionIdIsCurrentTransactionId(xmax))
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
302 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
303 {
304 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
305 return true;
306 return false;
307 }
308
309 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
310 return true;
311
312 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
313 {
314 /* it must have aborted or crashed */
315 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
316 InvalidTransactionId);
317 return true;
318 }
319
320 /* xmax transaction committed */
321
322 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
323 {
324 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
325 InvalidTransactionId);
326 return true;
327 }
328
329 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
330 HeapTupleHeaderGetRawXmax(tuple));
331 return false;
332}
333
334/*
335 * HeapTupleSatisfiesAny
336 * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
337 */
338static bool
339HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
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 */
360static bool
361HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot,
362 Buffer buffer)
363{
364 HeapTupleHeader tuple = htup->t_data;
365
366 Assert(ItemPointerIsValid(&htup->t_self));
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 {
377 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
378
379 if (TransactionIdIsCurrentTransactionId(xvac))
380 return false;
381 if (!TransactionIdIsInProgress(xvac))
382 {
383 if (TransactionIdDidCommit(xvac))
384 {
385 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
386 InvalidTransactionId);
387 return false;
388 }
389 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
390 InvalidTransactionId);
391 }
392 }
393 /* Used by pre-9.0 binary upgrades */
394 else if (tuple->t_infomask & HEAP_MOVED_IN)
395 {
396 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
397
398 if (!TransactionIdIsCurrentTransactionId(xvac))
399 {
400 if (TransactionIdIsInProgress(xvac))
401 return false;
402 if (TransactionIdDidCommit(xvac))
403 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
404 InvalidTransactionId);
405 else
406 {
407 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
408 InvalidTransactionId);
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 */
419 else if (!TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple)))
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 */
456TM_Result
457HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
458 Buffer buffer)
459{
460 HeapTupleHeader tuple = htup->t_data;
461
462 Assert(ItemPointerIsValid(&htup->t_self));
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 {
473 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
474
475 if (TransactionIdIsCurrentTransactionId(xvac))
476 return TM_Invisible;
477 if (!TransactionIdIsInProgress(xvac))
478 {
479 if (TransactionIdDidCommit(xvac))
480 {
481 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
482 InvalidTransactionId);
483 return TM_Invisible;
484 }
485 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
486 InvalidTransactionId);
487 }
488 }
489 /* Used by pre-9.0 binary upgrades */
490 else if (tuple->t_infomask & HEAP_MOVED_IN)
491 {
492 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
493
494 if (!TransactionIdIsCurrentTransactionId(xvac))
495 {
496 if (TransactionIdIsInProgress(xvac))
497 return TM_Invisible;
498 if (TransactionIdDidCommit(xvac))
499 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
500 InvalidTransactionId);
501 else
502 {
503 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
504 InvalidTransactionId);
505 return TM_Invisible;
506 }
507 }
508 }
509 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
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
517 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
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 */
555 Assert(TransactionIdIsValid(xmax));
556
557 /* deleting subtransaction must have aborted */
558 if (!TransactionIdIsCurrentTransactionId(xmax))
559 {
560 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
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
574 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
575 {
576 /* deleting subtransaction must have aborted */
577 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
578 InvalidTransactionId);
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 }
587 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
588 return TM_Invisible;
589 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
590 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
591 HeapTupleHeaderGetRawXmin(tuple));
592 else
593 {
594 /* it must have aborted or crashed */
595 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
596 InvalidTransactionId);
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 {
608 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
609 return TM_Ok;
610 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid) ||
611 HeapTupleHeaderIndicatesMovedPartitions(tuple))
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
624 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
625 {
626 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), true))
627 return TM_BeingModified;
628
629 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
630 return TM_Ok;
631 }
632
633 xmax = HeapTupleGetUpdateXid(tuple);
634 if (!TransactionIdIsValid(xmax))
635 {
636 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
637 return TM_BeingModified;
638 }
639
640 /* not LOCKED_ONLY, so it has to have an xmax */
641 Assert(TransactionIdIsValid(xmax));
642
643 if (TransactionIdIsCurrentTransactionId(xmax))
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
651 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
652 return TM_BeingModified;
653
654 if (TransactionIdDidCommit(xmax))
655 {
656 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid) ||
657 HeapTupleHeaderIndicatesMovedPartitions(tuple))
658 return TM_Updated;
659 else
660 return TM_Deleted;
661 }
662
663 /*
664 * By here, the update in the Xmax is either aborted or crashed, but
665 * what about the other members?
666 */
667
668 if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
669 {
670 /*
671 * There's no member, even just a locker, alive anymore, so we can
672 * mark the Xmax as invalid.
673 */
674 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
675 InvalidTransactionId);
676 return TM_Ok;
677 }
678 else
679 {
680 /* There are lockers running */
681 return TM_BeingModified;
682 }
683 }
684
685 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
686 {
687 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
688 return TM_BeingModified;
689 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
690 return TM_SelfModified; /* updated after scan started */
691 else
692 return TM_Invisible; /* updated before scan started */
693 }
694
695 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
696 return TM_BeingModified;
697
698 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
699 {
700 /* it must have aborted or crashed */
701 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
702 InvalidTransactionId);
703 return TM_Ok;
704 }
705
706 /* xmax transaction committed */
707
708 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
709 {
710 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
711 InvalidTransactionId);
712 return TM_Ok;
713 }
714
715 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
716 HeapTupleHeaderGetRawXmax(tuple));
717 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid) ||
718 HeapTupleHeaderIndicatesMovedPartitions(tuple))
719 return TM_Updated; /* updated by other */
720 else
721 return TM_Deleted; /* deleted by other */
722}
723
724/*
725 * HeapTupleSatisfiesDirty
726 * True iff heap tuple is valid including effects of open transactions.
727 *
728 * See SNAPSHOT_DIRTY's definition for the intended behaviour.
729 *
730 * This is essentially like HeapTupleSatisfiesSelf as far as effects of
731 * the current transaction and committed/aborted xacts are concerned.
732 * However, we also include the effects of other xacts still in progress.
733 *
734 * A special hack is that the passed-in snapshot struct is used as an
735 * output argument to return the xids of concurrent xacts that affected the
736 * tuple. snapshot->xmin is set to the tuple's xmin if that is another
737 * transaction that's still in progress; or to InvalidTransactionId if the
738 * tuple's xmin is committed good, committed dead, or my own xact.
739 * Similarly for snapshot->xmax and the tuple's xmax. If the tuple was
740 * inserted speculatively, meaning that the inserter might still back down
741 * on the insertion without aborting the whole transaction, the associated
742 * token is also returned in snapshot->speculativeToken.
743 */
744static bool
745HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
746 Buffer buffer)
747{
748 HeapTupleHeader tuple = htup->t_data;
749
750 Assert(ItemPointerIsValid(&htup->t_self));
751 Assert(htup->t_tableOid != InvalidOid);
752
753 snapshot->xmin = snapshot->xmax = InvalidTransactionId;
754 snapshot->speculativeToken = 0;
755
756 if (!HeapTupleHeaderXminCommitted(tuple))
757 {
758 if (HeapTupleHeaderXminInvalid(tuple))
759 return false;
760
761 /* Used by pre-9.0 binary upgrades */
762 if (tuple->t_infomask & HEAP_MOVED_OFF)
763 {
764 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
765
766 if (TransactionIdIsCurrentTransactionId(xvac))
767 return false;
768 if (!TransactionIdIsInProgress(xvac))
769 {
770 if (TransactionIdDidCommit(xvac))
771 {
772 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
773 InvalidTransactionId);
774 return false;
775 }
776 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
777 InvalidTransactionId);
778 }
779 }
780 /* Used by pre-9.0 binary upgrades */
781 else if (tuple->t_infomask & HEAP_MOVED_IN)
782 {
783 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
784
785 if (!TransactionIdIsCurrentTransactionId(xvac))
786 {
787 if (TransactionIdIsInProgress(xvac))
788 return false;
789 if (TransactionIdDidCommit(xvac))
790 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
791 InvalidTransactionId);
792 else
793 {
794 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
795 InvalidTransactionId);
796 return false;
797 }
798 }
799 }
800 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
801 {
802 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
803 return true;
804
805 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
806 return true;
807
808 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
809 {
810 TransactionId xmax;
811
812 xmax = HeapTupleGetUpdateXid(tuple);
813
814 /* not LOCKED_ONLY, so it has to have an xmax */
815 Assert(TransactionIdIsValid(xmax));
816
817 /* updating subtransaction must have aborted */
818 if (!TransactionIdIsCurrentTransactionId(xmax))
819 return true;
820 else
821 return false;
822 }
823
824 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
825 {
826 /* deleting subtransaction must have aborted */
827 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
828 InvalidTransactionId);
829 return true;
830 }
831
832 return false;
833 }
834 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
835 {
836 /*
837 * Return the speculative token to caller. Caller can worry about
838 * xmax, since it requires a conclusively locked row version, and
839 * a concurrent update to this tuple is a conflict of its
840 * purposes.
841 */
842 if (HeapTupleHeaderIsSpeculative(tuple))
843 {
844 snapshot->speculativeToken =
845 HeapTupleHeaderGetSpeculativeToken(tuple);
846
847 Assert(snapshot->speculativeToken != 0);
848 }
849
850 snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
851 /* XXX shouldn't we fall through to look at xmax? */
852 return true; /* in insertion by other */
853 }
854 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
855 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
856 HeapTupleHeaderGetRawXmin(tuple));
857 else
858 {
859 /* it must have aborted or crashed */
860 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
861 InvalidTransactionId);
862 return false;
863 }
864 }
865
866 /* by here, the inserting transaction has committed */
867
868 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
869 return true;
870
871 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
872 {
873 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
874 return true;
875 return false; /* updated by other */
876 }
877
878 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
879 {
880 TransactionId xmax;
881
882 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
883 return true;
884
885 xmax = HeapTupleGetUpdateXid(tuple);
886
887 /* not LOCKED_ONLY, so it has to have an xmax */
888 Assert(TransactionIdIsValid(xmax));
889
890 if (TransactionIdIsCurrentTransactionId(xmax))
891 return false;
892 if (TransactionIdIsInProgress(xmax))
893 {
894 snapshot->xmax = xmax;
895 return true;
896 }
897 if (TransactionIdDidCommit(xmax))
898 return false;
899 /* it must have aborted or crashed */
900 return true;
901 }
902
903 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
904 {
905 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
906 return true;
907 return false;
908 }
909
910 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
911 {
912 if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
913 snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
914 return true;
915 }
916
917 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
918 {
919 /* it must have aborted or crashed */
920 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
921 InvalidTransactionId);
922 return true;
923 }
924
925 /* xmax transaction committed */
926
927 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
928 {
929 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
930 InvalidTransactionId);
931 return true;
932 }
933
934 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
935 HeapTupleHeaderGetRawXmax(tuple));
936 return false; /* updated by other */
937}
938
939/*
940 * HeapTupleSatisfiesMVCC
941 * True iff heap tuple is valid for the given MVCC snapshot.
942 *
943 * See SNAPSHOT_MVCC's definition for the intended behaviour.
944 *
945 * Notice that here, we will not update the tuple status hint bits if the
946 * inserting/deleting transaction is still running according to our snapshot,
947 * even if in reality it's committed or aborted by now. This is intentional.
948 * Checking the true transaction state would require access to high-traffic
949 * shared data structures, creating contention we'd rather do without, and it
950 * would not change the result of our visibility check anyway. The hint bits
951 * will be updated by the first visitor that has a snapshot new enough to see
952 * the inserting/deleting transaction as done. In the meantime, the cost of
953 * leaving the hint bits unset is basically that each HeapTupleSatisfiesMVCC
954 * call will need to run TransactionIdIsCurrentTransactionId in addition to
955 * XidInMVCCSnapshot (but it would have to do the latter anyway). In the old
956 * coding where we tried to set the hint bits as soon as possible, we instead
957 * did TransactionIdIsInProgress in each call --- to no avail, as long as the
958 * inserting/deleting transaction was still running --- which was more cycles
959 * and more contention on the PGXACT array.
960 */
961static bool
962HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
963 Buffer buffer)
964{
965 HeapTupleHeader tuple = htup->t_data;
966
967 Assert(ItemPointerIsValid(&htup->t_self));
968 Assert(htup->t_tableOid != InvalidOid);
969
970 if (!HeapTupleHeaderXminCommitted(tuple))
971 {
972 if (HeapTupleHeaderXminInvalid(tuple))
973 return false;
974
975 /* Used by pre-9.0 binary upgrades */
976 if (tuple->t_infomask & HEAP_MOVED_OFF)
977 {
978 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
979
980 if (TransactionIdIsCurrentTransactionId(xvac))
981 return false;
982 if (!XidInMVCCSnapshot(xvac, snapshot))
983 {
984 if (TransactionIdDidCommit(xvac))
985 {
986 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
987 InvalidTransactionId);
988 return false;
989 }
990 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
991 InvalidTransactionId);
992 }
993 }
994 /* Used by pre-9.0 binary upgrades */
995 else if (tuple->t_infomask & HEAP_MOVED_IN)
996 {
997 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
998
999 if (!TransactionIdIsCurrentTransactionId(xvac))
1000 {
1001 if (XidInMVCCSnapshot(xvac, snapshot))
1002 return false;
1003 if (TransactionIdDidCommit(xvac))
1004 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1005 InvalidTransactionId);
1006 else
1007 {
1008 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1009 InvalidTransactionId);
1010 return false;
1011 }
1012 }
1013 }
1014 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
1015 {
1016 if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
1017 return false; /* inserted after scan started */
1018
1019 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1020 return true;
1021
1022 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
1023 return true;
1024
1025 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1026 {
1027 TransactionId xmax;
1028
1029 xmax = HeapTupleGetUpdateXid(tuple);
1030
1031 /* not LOCKED_ONLY, so it has to have an xmax */
1032 Assert(TransactionIdIsValid(xmax));
1033
1034 /* updating subtransaction must have aborted */
1035 if (!TransactionIdIsCurrentTransactionId(xmax))
1036 return true;
1037 else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1038 return true; /* updated after scan started */
1039 else
1040 return false; /* updated before scan started */
1041 }
1042
1043 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
1044 {
1045 /* deleting subtransaction must have aborted */
1046 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1047 InvalidTransactionId);
1048 return true;
1049 }
1050
1051 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1052 return true; /* deleted after scan started */
1053 else
1054 return false; /* deleted before scan started */
1055 }
1056 else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1057 return false;
1058 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
1059 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1060 HeapTupleHeaderGetRawXmin(tuple));
1061 else
1062 {
1063 /* it must have aborted or crashed */
1064 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1065 InvalidTransactionId);
1066 return false;
1067 }
1068 }
1069 else
1070 {
1071 /* xmin is committed, but maybe not according to our snapshot */
1072 if (!HeapTupleHeaderXminFrozen(tuple) &&
1073 XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1074 return false; /* treat as still in progress */
1075 }
1076
1077 /* by here, the inserting transaction has committed */
1078
1079 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1080 return true;
1081
1082 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1083 return true;
1084
1085 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1086 {
1087 TransactionId xmax;
1088
1089 /* already checked above */
1090 Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
1091
1092 xmax = HeapTupleGetUpdateXid(tuple);
1093
1094 /* not LOCKED_ONLY, so it has to have an xmax */
1095 Assert(TransactionIdIsValid(xmax));
1096
1097 if (TransactionIdIsCurrentTransactionId(xmax))
1098 {
1099 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1100 return true; /* deleted after scan started */
1101 else
1102 return false; /* deleted before scan started */
1103 }
1104 if (XidInMVCCSnapshot(xmax, snapshot))
1105 return true;
1106 if (TransactionIdDidCommit(xmax))
1107 return false; /* updating transaction committed */
1108 /* it must have aborted or crashed */
1109 return true;
1110 }
1111
1112 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1113 {
1114 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
1115 {
1116 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1117 return true; /* deleted after scan started */
1118 else
1119 return false; /* deleted before scan started */
1120 }
1121
1122 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1123 return true;
1124
1125 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
1126 {
1127 /* it must have aborted or crashed */
1128 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1129 InvalidTransactionId);
1130 return true;
1131 }
1132
1133 /* xmax transaction committed */
1134 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1135 HeapTupleHeaderGetRawXmax(tuple));
1136 }
1137 else
1138 {
1139 /* xmax is committed, but maybe not according to our snapshot */
1140 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1141 return true; /* treat as still in progress */
1142 }
1143
1144 /* xmax transaction committed */
1145
1146 return false;
1147}
1148
1149
1150/*
1151 * HeapTupleSatisfiesVacuum
1152 *
1153 * Determine the status of tuples for VACUUM purposes. Here, what
1154 * we mainly want to know is if a tuple is potentially visible to *any*
1155 * running transaction. If so, it can't be removed yet by VACUUM.
1156 *
1157 * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples
1158 * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
1159 * still be visible to some open transaction, so we can't remove them,
1160 * even if we see that the deleting transaction has committed.
1161 */
1162HTSV_Result
1163HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
1164 Buffer buffer)
1165{
1166 HeapTupleHeader tuple = htup->t_data;
1167
1168 Assert(ItemPointerIsValid(&htup->t_self));
1169 Assert(htup->t_tableOid != InvalidOid);
1170
1171 /*
1172 * Has inserting transaction committed?
1173 *
1174 * If the inserting transaction aborted, then the tuple was never visible
1175 * to any other transaction, so we can delete it immediately.
1176 */
1177 if (!HeapTupleHeaderXminCommitted(tuple))
1178 {
1179 if (HeapTupleHeaderXminInvalid(tuple))
1180 return HEAPTUPLE_DEAD;
1181 /* Used by pre-9.0 binary upgrades */
1182 else if (tuple->t_infomask & HEAP_MOVED_OFF)
1183 {
1184 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1185
1186 if (TransactionIdIsCurrentTransactionId(xvac))
1187 return HEAPTUPLE_DELETE_IN_PROGRESS;
1188 if (TransactionIdIsInProgress(xvac))
1189 return HEAPTUPLE_DELETE_IN_PROGRESS;
1190 if (TransactionIdDidCommit(xvac))
1191 {
1192 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1193 InvalidTransactionId);
1194 return HEAPTUPLE_DEAD;
1195 }
1196 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1197 InvalidTransactionId);
1198 }
1199 /* Used by pre-9.0 binary upgrades */
1200 else if (tuple->t_infomask & HEAP_MOVED_IN)
1201 {
1202 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1203
1204 if (TransactionIdIsCurrentTransactionId(xvac))
1205 return HEAPTUPLE_INSERT_IN_PROGRESS;
1206 if (TransactionIdIsInProgress(xvac))
1207 return HEAPTUPLE_INSERT_IN_PROGRESS;
1208 if (TransactionIdDidCommit(xvac))
1209 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1210 InvalidTransactionId);
1211 else
1212 {
1213 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1214 InvalidTransactionId);
1215 return HEAPTUPLE_DEAD;
1216 }
1217 }
1218 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
1219 {
1220 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1221 return HEAPTUPLE_INSERT_IN_PROGRESS;
1222 /* only locked? run infomask-only check first, for performance */
1223 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
1224 HeapTupleHeaderIsOnlyLocked(tuple))
1225 return HEAPTUPLE_INSERT_IN_PROGRESS;
1226 /* inserted and then deleted by same xact */
1227 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
1228 return HEAPTUPLE_DELETE_IN_PROGRESS;
1229 /* deleting subtransaction must have aborted */
1230 return HEAPTUPLE_INSERT_IN_PROGRESS;
1231 }
1232 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
1233 {
1234 /*
1235 * It'd be possible to discern between INSERT/DELETE in progress
1236 * here by looking at xmax - but that doesn't seem beneficial for
1237 * the majority of callers and even detrimental for some. We'd
1238 * rather have callers look at/wait for xmin than xmax. It's
1239 * always correct to return INSERT_IN_PROGRESS because that's
1240 * what's happening from the view of other backends.
1241 */
1242 return HEAPTUPLE_INSERT_IN_PROGRESS;
1243 }
1244 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
1245 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1246 HeapTupleHeaderGetRawXmin(tuple));
1247 else
1248 {
1249 /*
1250 * Not in Progress, Not Committed, so either Aborted or crashed
1251 */
1252 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1253 InvalidTransactionId);
1254 return HEAPTUPLE_DEAD;
1255 }
1256
1257 /*
1258 * At this point the xmin is known committed, but we might not have
1259 * been able to set the hint bit yet; so we can no longer Assert that
1260 * it's set.
1261 */
1262 }
1263
1264 /*
1265 * Okay, the inserter committed, so it was good at some point. Now what
1266 * about the deleting transaction?
1267 */
1268 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1269 return HEAPTUPLE_LIVE;
1270
1271 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1272 {
1273 /*
1274 * "Deleting" xact really only locked it, so the tuple is live in any
1275 * case. However, we should make sure that either XMAX_COMMITTED or
1276 * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1277 * examining the tuple for future xacts.
1278 */
1279 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1280 {
1281 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1282 {
1283 /*
1284 * If it's a pre-pg_upgrade tuple, the multixact cannot
1285 * possibly be running; otherwise have to check.
1286 */
1287 if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
1288 MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
1289 true))
1290 return HEAPTUPLE_LIVE;
1291 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1292 }
1293 else
1294 {
1295 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1296 return HEAPTUPLE_LIVE;
1297 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1298 InvalidTransactionId);
1299 }
1300 }
1301
1302 /*
1303 * We don't really care whether xmax did commit, abort or crash. We
1304 * know that xmax did lock the tuple, but it did not and will never
1305 * actually update it.
1306 */
1307
1308 return HEAPTUPLE_LIVE;
1309 }
1310
1311 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1312 {
1313 TransactionId xmax = HeapTupleGetUpdateXid(tuple);
1314
1315 /* already checked above */
1316 Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
1317
1318 /* not LOCKED_ONLY, so it has to have an xmax */
1319 Assert(TransactionIdIsValid(xmax));
1320
1321 if (TransactionIdIsInProgress(xmax))
1322 return HEAPTUPLE_DELETE_IN_PROGRESS;
1323 else if (TransactionIdDidCommit(xmax))
1324 {
1325 /*
1326 * The multixact might still be running due to lockers. If the
1327 * updater is below the xid horizon, we have to return DEAD
1328 * regardless -- otherwise we could end up with a tuple where the
1329 * updater has to be removed due to the horizon, but is not pruned
1330 * away. It's not a problem to prune that tuple, because any
1331 * remaining lockers will also be present in newer tuple versions.
1332 */
1333 if (!TransactionIdPrecedes(xmax, OldestXmin))
1334 return HEAPTUPLE_RECENTLY_DEAD;
1335
1336 return HEAPTUPLE_DEAD;
1337 }
1338 else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1339 {
1340 /*
1341 * Not in Progress, Not Committed, so either Aborted or crashed.
1342 * Mark the Xmax as invalid.
1343 */
1344 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1345 }
1346
1347 return HEAPTUPLE_LIVE;
1348 }
1349
1350 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1351 {
1352 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1353 return HEAPTUPLE_DELETE_IN_PROGRESS;
1354 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
1355 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1356 HeapTupleHeaderGetRawXmax(tuple));
1357 else
1358 {
1359 /*
1360 * Not in Progress, Not Committed, so either Aborted or crashed
1361 */
1362 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1363 InvalidTransactionId);
1364 return HEAPTUPLE_LIVE;
1365 }
1366
1367 /*
1368 * At this point the xmax is known committed, but we might not have
1369 * been able to set the hint bit yet; so we can no longer Assert that
1370 * it's set.
1371 */
1372 }
1373
1374 /*
1375 * Deleter committed, but perhaps it was recent enough that some open
1376 * transactions could still see the tuple.
1377 */
1378 if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin))
1379 return HEAPTUPLE_RECENTLY_DEAD;
1380
1381 /* Otherwise, it's dead and removable */
1382 return HEAPTUPLE_DEAD;
1383}
1384
1385
1386/*
1387 * HeapTupleSatisfiesNonVacuumable
1388 *
1389 * True if tuple might be visible to some transaction; false if it's
1390 * surely dead to everyone, ie, vacuumable.
1391 *
1392 * See SNAPSHOT_TOAST's definition for the intended behaviour.
1393 *
1394 * This is an interface to HeapTupleSatisfiesVacuum that's callable via
1395 * HeapTupleSatisfiesSnapshot, so it can be used through a Snapshot.
1396 * snapshot->xmin must have been set up with the xmin horizon to use.
1397 */
1398static bool
1399HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot,
1400 Buffer buffer)
1401{
1402 return HeapTupleSatisfiesVacuum(htup, snapshot->xmin, buffer)
1403 != HEAPTUPLE_DEAD;
1404}
1405
1406
1407/*
1408 * HeapTupleIsSurelyDead
1409 *
1410 * Cheaply determine whether a tuple is surely dead to all onlookers.
1411 * We sometimes use this in lieu of HeapTupleSatisfiesVacuum when the
1412 * tuple has just been tested by another visibility routine (usually
1413 * HeapTupleSatisfiesMVCC) and, therefore, any hint bits that can be set
1414 * should already be set. We assume that if no hint bits are set, the xmin
1415 * or xmax transaction is still running. This is therefore faster than
1416 * HeapTupleSatisfiesVacuum, because we don't consult PGXACT nor CLOG.
1417 * It's okay to return false when in doubt, but we must return true only
1418 * if the tuple is removable.
1419 */
1420bool
1421HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin)
1422{
1423 HeapTupleHeader tuple = htup->t_data;
1424
1425 Assert(ItemPointerIsValid(&htup->t_self));
1426 Assert(htup->t_tableOid != InvalidOid);
1427
1428 /*
1429 * If the inserting transaction is marked invalid, then it aborted, and
1430 * the tuple is definitely dead. If it's marked neither committed nor
1431 * invalid, then we assume it's still alive (since the presumption is that
1432 * all relevant hint bits were just set moments ago).
1433 */
1434 if (!HeapTupleHeaderXminCommitted(tuple))
1435 return HeapTupleHeaderXminInvalid(tuple) ? true : false;
1436
1437 /*
1438 * If the inserting transaction committed, but any deleting transaction
1439 * aborted, the tuple is still alive.
1440 */
1441 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1442 return false;
1443
1444 /*
1445 * If the XMAX is just a lock, the tuple is still alive.
1446 */
1447 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1448 return false;
1449
1450 /*
1451 * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1452 * know without checking pg_multixact.
1453 */
1454 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1455 return false;
1456
1457 /* If deleter isn't known to have committed, assume it's still running. */
1458 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1459 return false;
1460
1461 /* Deleter committed, so tuple is dead if the XID is old enough. */
1462 return TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin);
1463}
1464
1465/*
1466 * Is the tuple really only locked? That is, is it not updated?
1467 *
1468 * It's easy to check just infomask bits if the locker is not a multi; but
1469 * otherwise we need to verify that the updating transaction has not aborted.
1470 *
1471 * This function is here because it follows the same visibility rules laid out
1472 * at the top of this file.
1473 */
1474bool
1475HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
1476{
1477 TransactionId xmax;
1478
1479 /* if there's no valid Xmax, then there's obviously no update either */
1480 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1481 return true;
1482
1483 if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1484 return true;
1485
1486 /* invalid xmax means no update */
1487 if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
1488 return true;
1489
1490 /*
1491 * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1492 * necessarily have been updated
1493 */
1494 if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1495 return false;
1496
1497 /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1498 xmax = HeapTupleGetUpdateXid(tuple);
1499
1500 /* not LOCKED_ONLY, so it has to have an xmax */
1501 Assert(TransactionIdIsValid(xmax));
1502
1503 if (TransactionIdIsCurrentTransactionId(xmax))
1504 return false;
1505 if (TransactionIdIsInProgress(xmax))
1506 return false;
1507 if (TransactionIdDidCommit(xmax))
1508 return false;
1509
1510 /*
1511 * not current, not in progress, not committed -- must have aborted or
1512 * crashed
1513 */
1514 return true;
1515}
1516
1517/*
1518 * check whether the transaction id 'xid' is in the pre-sorted array 'xip'.
1519 */
1520static bool
1521TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
1522{
1523 return bsearch(&xid, xip, num,
1524 sizeof(TransactionId), xidComparator) != NULL;
1525}
1526
1527/*
1528 * See the comments for HeapTupleSatisfiesMVCC for the semantics this function
1529 * obeys.
1530 *
1531 * Only usable on tuples from catalog tables!
1532 *
1533 * We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
1534 * reading catalog pages which couldn't have been created in an older version.
1535 *
1536 * We don't set any hint bits in here as it seems unlikely to be beneficial as
1537 * those should already be set by normal access and it seems to be too
1538 * dangerous to do so as the semantics of doing so during timetravel are more
1539 * complicated than when dealing "only" with the present.
1540 */
1541static bool
1542HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
1543 Buffer buffer)
1544{
1545 HeapTupleHeader tuple = htup->t_data;
1546 TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
1547 TransactionId xmax = HeapTupleHeaderGetRawXmax(tuple);
1548
1549 Assert(ItemPointerIsValid(&htup->t_self));
1550 Assert(htup->t_tableOid != InvalidOid);
1551
1552 /* inserting transaction aborted */
1553 if (HeapTupleHeaderXminInvalid(tuple))
1554 {
1555 Assert(!TransactionIdDidCommit(xmin));
1556 return false;
1557 }
1558 /* check if it's one of our txids, toplevel is also in there */
1559 else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1560 {
1561 bool resolved;
1562 CommandId cmin = HeapTupleHeaderGetRawCommandId(tuple);
1563 CommandId cmax = InvalidCommandId;
1564
1565 /*
1566 * another transaction might have (tried to) delete this tuple or
1567 * cmin/cmax was stored in a combocid. So we need to lookup the actual
1568 * values externally.
1569 */
1570 resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
1571 htup, buffer,
1572 &cmin, &cmax);
1573
1574 if (!resolved)
1575 elog(ERROR, "could not resolve cmin/cmax of catalog tuple");
1576
1577 Assert(cmin != InvalidCommandId);
1578
1579 if (cmin >= snapshot->curcid)
1580 return false; /* inserted after scan started */
1581 /* fall through */
1582 }
1583 /* committed before our xmin horizon. Do a normal visibility check. */
1584 else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1585 {
1586 Assert(!(HeapTupleHeaderXminCommitted(tuple) &&
1587 !TransactionIdDidCommit(xmin)));
1588
1589 /* check for hint bit first, consult clog afterwards */
1590 if (!HeapTupleHeaderXminCommitted(tuple) &&
1591 !TransactionIdDidCommit(xmin))
1592 return false;
1593 /* fall through */
1594 }
1595 /* beyond our xmax horizon, i.e. invisible */
1596 else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1597 {
1598 return false;
1599 }
1600 /* check if it's a committed transaction in [xmin, xmax) */
1601 else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1602 {
1603 /* fall through */
1604 }
1605
1606 /*
1607 * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1608 * invisible.
1609 */
1610 else
1611 {
1612 return false;
1613 }
1614
1615 /* at this point we know xmin is visible, go on to check xmax */
1616
1617 /* xid invalid or aborted */
1618 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1619 return true;
1620 /* locked tuples are always visible */
1621 else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1622 return true;
1623
1624 /*
1625 * We can see multis here if we're looking at user tables or if somebody
1626 * SELECT ... FOR SHARE/UPDATE a system table.
1627 */
1628 else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1629 {
1630 xmax = HeapTupleGetUpdateXid(tuple);
1631 }
1632
1633 /* check if it's one of our txids, toplevel is also in there */
1634 if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1635 {
1636 bool resolved;
1637 CommandId cmin;
1638 CommandId cmax = HeapTupleHeaderGetRawCommandId(tuple);
1639
1640 /* Lookup actual cmin/cmax values */
1641 resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
1642 htup, buffer,
1643 &cmin, &cmax);
1644
1645 if (!resolved)
1646 elog(ERROR, "could not resolve combocid to cmax");
1647
1648 Assert(cmax != InvalidCommandId);
1649
1650 if (cmax >= snapshot->curcid)
1651 return true; /* deleted after scan started */
1652 else
1653 return false; /* deleted before scan started */
1654 }
1655 /* below xmin horizon, normal transaction state is valid */
1656 else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1657 {
1658 Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
1659 !TransactionIdDidCommit(xmax)));
1660
1661 /* check hint bit first */
1662 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1663 return false;
1664
1665 /* check clog */
1666 return !TransactionIdDidCommit(xmax);
1667 }
1668 /* above xmax horizon, we cannot possibly see the deleting transaction */
1669 else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1670 return true;
1671 /* xmax is between [xmin, xmax), check known committed array */
1672 else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1673 return false;
1674 /* xmax is between [xmin, xmax), but known not to have committed yet */
1675 else
1676 return true;
1677}
1678
1679/*
1680 * HeapTupleSatisfiesVisibility
1681 * True iff heap tuple satisfies a time qual.
1682 *
1683 * Notes:
1684 * Assumes heap tuple is valid, and buffer at least share locked.
1685 *
1686 * Hint bits in the HeapTuple's t_infomask may be updated as a side effect;
1687 * if so, the indicated buffer is marked dirty.
1688 */
1689bool
1690HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)
1691{
1692 switch (snapshot->snapshot_type)
1693 {
1694 case SNAPSHOT_MVCC:
1695 return HeapTupleSatisfiesMVCC(tup, snapshot, buffer);
1696 break;
1697 case SNAPSHOT_SELF:
1698 return HeapTupleSatisfiesSelf(tup, snapshot, buffer);
1699 break;
1700 case SNAPSHOT_ANY:
1701 return HeapTupleSatisfiesAny(tup, snapshot, buffer);
1702 break;
1703 case SNAPSHOT_TOAST:
1704 return HeapTupleSatisfiesToast(tup, snapshot, buffer);
1705 break;
1706 case SNAPSHOT_DIRTY:
1707 return HeapTupleSatisfiesDirty(tup, snapshot, buffer);
1708 break;
1709 case SNAPSHOT_HISTORIC_MVCC:
1710 return HeapTupleSatisfiesHistoricMVCC(tup, snapshot, buffer);
1711 break;
1712 case SNAPSHOT_NON_VACUUMABLE:
1713 return HeapTupleSatisfiesNonVacuumable(tup, snapshot, buffer);
1714 break;
1715 }
1716
1717 return false; /* keep compiler quiet */
1718}
1719