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