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
SetHintBits(HeapTupleHeader tuple,Buffer buffer,uint16 infomask,TransactionId xid)113 SetHintBits(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 */
139 void
HeapTupleSetHintBits(HeapTupleHeader tuple,Buffer buffer,uint16 infomask,TransactionId xid)140 HeapTupleSetHintBits(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 */
168 static bool
HeapTupleSatisfiesSelf(HeapTuple htup,Snapshot snapshot,Buffer buffer)169 HeapTupleSatisfiesSelf(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 */
338 static bool
HeapTupleSatisfiesAny(HeapTuple htup,Snapshot snapshot,Buffer buffer)339 HeapTupleSatisfiesAny(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 */
360 static bool
HeapTupleSatisfiesToast(HeapTuple htup,Snapshot snapshot,Buffer buffer)361 HeapTupleSatisfiesToast(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 */
456 TM_Result
HeapTupleSatisfiesUpdate(HeapTuple htup,CommandId curcid,Buffer buffer)457 HeapTupleSatisfiesUpdate(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 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
623 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
624 {
625 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), true))
626 return TM_BeingModified;
627
628 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
629 return TM_Ok;
630 }
631
632 xmax = HeapTupleGetUpdateXid(tuple);
633 if (!TransactionIdIsValid(xmax))
634 {
635 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
636 return TM_BeingModified;
637 }
638
639 /* not LOCKED_ONLY, so it has to have an xmax */
640 Assert(TransactionIdIsValid(xmax));
641
642 if (TransactionIdIsCurrentTransactionId(xmax))
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
650 if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
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
666 if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
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,
673 InvalidTransactionId);
674 return TM_Ok;
675 }
676 else
677 {
678 /* There are lockers running */
679 return TM_BeingModified;
680 }
681 }
682
683 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
684 {
685 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
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
693 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
694 return TM_BeingModified;
695
696 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
697 {
698 /* it must have aborted or crashed */
699 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
700 InvalidTransactionId);
701 return TM_Ok;
702 }
703
704 /* xmax transaction committed */
705
706 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
707 {
708 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
709 InvalidTransactionId);
710 return TM_Ok;
711 }
712
713 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
714 HeapTupleHeaderGetRawXmax(tuple));
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
HeapTupleSatisfiesDirty(HeapTuple htup,Snapshot snapshot,Buffer buffer)742 HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
743 Buffer buffer)
744 {
745 HeapTupleHeader tuple = htup->t_data;
746
747 Assert(ItemPointerIsValid(&htup->t_self));
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 {
761 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
762
763 if (TransactionIdIsCurrentTransactionId(xvac))
764 return false;
765 if (!TransactionIdIsInProgress(xvac))
766 {
767 if (TransactionIdDidCommit(xvac))
768 {
769 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
770 InvalidTransactionId);
771 return false;
772 }
773 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
774 InvalidTransactionId);
775 }
776 }
777 /* Used by pre-9.0 binary upgrades */
778 else if (tuple->t_infomask & HEAP_MOVED_IN)
779 {
780 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
781
782 if (!TransactionIdIsCurrentTransactionId(xvac))
783 {
784 if (TransactionIdIsInProgress(xvac))
785 return false;
786 if (TransactionIdDidCommit(xvac))
787 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
788 InvalidTransactionId);
789 else
790 {
791 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
792 InvalidTransactionId);
793 return false;
794 }
795 }
796 }
797 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
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 */
812 Assert(TransactionIdIsValid(xmax));
813
814 /* updating subtransaction must have aborted */
815 if (!TransactionIdIsCurrentTransactionId(xmax))
816 return true;
817 else
818 return false;
819 }
820
821 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
822 {
823 /* deleting subtransaction must have aborted */
824 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
825 InvalidTransactionId);
826 return true;
827 }
828
829 return false;
830 }
831 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
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 =
842 HeapTupleHeaderGetSpeculativeToken(tuple);
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 }
851 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
852 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
853 HeapTupleHeaderGetRawXmin(tuple));
854 else
855 {
856 /* it must have aborted or crashed */
857 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
858 InvalidTransactionId);
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 {
870 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
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
879 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
880 return true;
881
882 xmax = HeapTupleGetUpdateXid(tuple);
883
884 /* not LOCKED_ONLY, so it has to have an xmax */
885 Assert(TransactionIdIsValid(xmax));
886
887 if (TransactionIdIsCurrentTransactionId(xmax))
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
900 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
901 {
902 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
903 return true;
904 return false;
905 }
906
907 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
908 {
909 if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
910 snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
911 return true;
912 }
913
914 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
915 {
916 /* it must have aborted or crashed */
917 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
918 InvalidTransactionId);
919 return true;
920 }
921
922 /* xmax transaction committed */
923
924 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
925 {
926 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
927 InvalidTransactionId);
928 return true;
929 }
930
931 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
932 HeapTupleHeaderGetRawXmax(tuple));
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
HeapTupleSatisfiesMVCC(HeapTuple htup,Snapshot snapshot,Buffer buffer)959 HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
960 Buffer buffer)
961 {
962 HeapTupleHeader tuple = htup->t_data;
963
964 Assert(ItemPointerIsValid(&htup->t_self));
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 {
975 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
976
977 if (TransactionIdIsCurrentTransactionId(xvac))
978 return false;
979 if (!XidInMVCCSnapshot(xvac, snapshot))
980 {
981 if (TransactionIdDidCommit(xvac))
982 {
983 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
984 InvalidTransactionId);
985 return false;
986 }
987 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
988 InvalidTransactionId);
989 }
990 }
991 /* Used by pre-9.0 binary upgrades */
992 else if (tuple->t_infomask & HEAP_MOVED_IN)
993 {
994 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
995
996 if (!TransactionIdIsCurrentTransactionId(xvac))
997 {
998 if (XidInMVCCSnapshot(xvac, snapshot))
999 return false;
1000 if (TransactionIdDidCommit(xvac))
1001 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1002 InvalidTransactionId);
1003 else
1004 {
1005 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1006 InvalidTransactionId);
1007 return false;
1008 }
1009 }
1010 }
1011 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
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 */
1029 Assert(TransactionIdIsValid(xmax));
1030
1031 /* updating subtransaction must have aborted */
1032 if (!TransactionIdIsCurrentTransactionId(xmax))
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
1040 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
1041 {
1042 /* deleting subtransaction must have aborted */
1043 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1044 InvalidTransactionId);
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;
1055 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
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,
1062 InvalidTransactionId);
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
1079 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1080 return true;
1081
1082 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1083 {
1084 TransactionId xmax;
1085
1086 /* already checked above */
1087 Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
1088
1089 xmax = HeapTupleGetUpdateXid(tuple);
1090
1091 /* not LOCKED_ONLY, so it has to have an xmax */
1092 Assert(TransactionIdIsValid(xmax));
1093
1094 if (TransactionIdIsCurrentTransactionId(xmax))
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 {
1111 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
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
1122 if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
1123 {
1124 /* it must have aborted or crashed */
1125 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1126 InvalidTransactionId);
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 */
1160 HTSV_Result
HeapTupleSatisfiesVacuum(HeapTuple htup,TransactionId OldestXmin,Buffer buffer)1161 HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
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 */
1194 HTSV_Result
HeapTupleSatisfiesVacuumHorizon(HeapTuple htup,Buffer buffer,TransactionId * dead_after)1195 HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after)
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
1220 if (TransactionIdIsCurrentTransactionId(xvac))
1221 return HEAPTUPLE_DELETE_IN_PROGRESS;
1222 if (TransactionIdIsInProgress(xvac))
1223 return HEAPTUPLE_DELETE_IN_PROGRESS;
1224 if (TransactionIdDidCommit(xvac))
1225 {
1226 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1227 InvalidTransactionId);
1228 return HEAPTUPLE_DEAD;
1229 }
1230 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1231 InvalidTransactionId);
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
1238 if (TransactionIdIsCurrentTransactionId(xvac))
1239 return HEAPTUPLE_INSERT_IN_PROGRESS;
1240 if (TransactionIdIsInProgress(xvac))
1241 return HEAPTUPLE_INSERT_IN_PROGRESS;
1242 if (TransactionIdDidCommit(xvac))
1243 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1244 InvalidTransactionId);
1245 else
1246 {
1247 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1248 InvalidTransactionId);
1249 return HEAPTUPLE_DEAD;
1250 }
1251 }
1252 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
1253 {
1254 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1255 return HEAPTUPLE_INSERT_IN_PROGRESS;
1256 /* only locked? run infomask-only check first, for performance */
1257 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
1258 HeapTupleHeaderIsOnlyLocked(tuple))
1259 return HEAPTUPLE_INSERT_IN_PROGRESS;
1260 /* inserted and then deleted by same xact */
1261 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
1262 return HEAPTUPLE_DELETE_IN_PROGRESS;
1263 /* deleting subtransaction must have aborted */
1264 return HEAPTUPLE_INSERT_IN_PROGRESS;
1265 }
1266 else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
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 */
1276 return HEAPTUPLE_INSERT_IN_PROGRESS;
1277 }
1278 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
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,
1287 InvalidTransactionId);
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
1305 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
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) &&
1322 MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
1323 true))
1324 return HEAPTUPLE_LIVE;
1325 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1326 }
1327 else
1328 {
1329 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1330 return HEAPTUPLE_LIVE;
1331 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1332 InvalidTransactionId);
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 */
1350 Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
1351
1352 /* not LOCKED_ONLY, so it has to have an xmax */
1353 Assert(TransactionIdIsValid(xmax));
1354
1355 if (TransactionIdIsInProgress(xmax))
1356 return HEAPTUPLE_DELETE_IN_PROGRESS;
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 */
1376 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1377 }
1378
1379 return HEAPTUPLE_LIVE;
1380 }
1381
1382 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1383 {
1384 if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1385 return HEAPTUPLE_DELETE_IN_PROGRESS;
1386 else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
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,
1395 InvalidTransactionId);
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
HeapTupleSatisfiesNonVacuumable(HeapTuple htup,Snapshot snapshot,Buffer buffer)1428 HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot,
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
HeapTupleIsSurelyDead(HeapTuple htup,GlobalVisState * vistest)1464 HeapTupleIsSurelyDead(HeapTuple htup, GlobalVisState *vistest)
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 */
1490 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
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
HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)1519 HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
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 */
1531 if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
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 */
1545 Assert(TransactionIdIsValid(xmax));
1546
1547 if (TransactionIdIsCurrentTransactionId(xmax))
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
TransactionIdInArray(TransactionId xid,TransactionId * xip,Size num)1565 TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
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
HeapTupleSatisfiesHistoricMVCC(HeapTuple htup,Snapshot snapshot,Buffer buffer)1586 HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
1587 Buffer buffer)
1588 {
1589 HeapTupleHeader tuple = htup->t_data;
1590 TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
1591 TransactionId xmax = HeapTupleHeaderGetRawXmax(tuple);
1592
1593 Assert(ItemPointerIsValid(&htup->t_self));
1594 Assert(htup->t_tableOid != InvalidOid);
1595
1596 /* inserting transaction aborted */
1597 if (HeapTupleHeaderXminInvalid(tuple))
1598 {
1599 Assert(!TransactionIdDidCommit(xmin));
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;
1606 CommandId cmin = HeapTupleHeaderGetRawCommandId(tuple);
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 */
1614 resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
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 {
1647 Assert(!(HeapTupleHeaderXminCommitted(tuple) &&
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;
1699 CommandId cmax = HeapTupleHeaderGetRawCommandId(tuple);
1700
1701 /* Lookup actual cmin/cmax values */
1702 resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
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
HeapTupleSatisfiesVisibility(HeapTuple tup,Snapshot snapshot,Buffer buffer)1766 HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)
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;
1785 case SNAPSHOT_HISTORIC_MVCC:
1786 return HeapTupleSatisfiesHistoricMVCC(tup, snapshot, buffer);
1787 break;
1788 case SNAPSHOT_NON_VACUUMABLE:
1789 return HeapTupleSatisfiesNonVacuumable(tup, snapshot, buffer);
1790 break;
1791 }
1792
1793 return false; /* keep compiler quiet */
1794 }
1795