Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * heapam_visibility.c
4 : * Tuple visibility rules for tuples stored in heap.
5 : *
6 : * NOTE: all the HeapTupleSatisfies routines will update the tuple's
7 : * "hint" status bits if we see that the inserting or deleting transaction
8 : * has now committed or aborted (and it is safe to set the hint bits).
9 : * If the hint bits are changed, MarkBufferDirtyHint is called on
10 : * the passed-in buffer. The caller must hold not only a pin, but at least
11 : * shared buffer content lock on the buffer containing the tuple.
12 : *
13 : * NOTE: When using a non-MVCC snapshot, we must check
14 : * TransactionIdIsInProgress (which looks in the PGPROC array) before
15 : * TransactionIdDidCommit (which look in pg_xact). Otherwise we have a race
16 : * condition: we might decide that a just-committed transaction crashed,
17 : * because none of the tests succeed. xact.c is careful to record
18 : * commit/abort in pg_xact before it unsets MyProc->xid in the PGPROC array.
19 : * That fixes that problem, but it also means there is a window where
20 : * TransactionIdIsInProgress and TransactionIdDidCommit will both return true.
21 : * If we check only TransactionIdDidCommit, we could consider a tuple
22 : * committed when a later GetSnapshotData call will still think the
23 : * originating transaction is in progress, which leads to application-level
24 : * inconsistency. The upshot is that we gotta check TransactionIdIsInProgress
25 : * first in all code paths, except for a few cases where we are looking at
26 : * subtransactions of our own main transaction and so there can't be any race
27 : * condition.
28 : *
29 : * We can't use TransactionIdDidAbort here because it won't treat transactions
30 : * that were in progress during a crash as aborted. We determine that
31 : * transactions aborted/crashed through process of elimination instead.
32 : *
33 : * When using an MVCC snapshot, we rely on XidInMVCCSnapshot rather than
34 : * TransactionIdIsInProgress, but the logic is otherwise the same: do not
35 : * check pg_xact until after deciding that the xact is no longer in progress.
36 : *
37 : *
38 : * Summary of visibility functions:
39 : *
40 : * HeapTupleSatisfiesMVCC()
41 : * visible to supplied snapshot, excludes current command
42 : * HeapTupleSatisfiesUpdate()
43 : * visible to instant snapshot, with user-supplied command
44 : * counter and more complex result
45 : * HeapTupleSatisfiesSelf()
46 : * visible to instant snapshot and current command
47 : * HeapTupleSatisfiesDirty()
48 : * like HeapTupleSatisfiesSelf(), but includes open transactions
49 : * HeapTupleSatisfiesVacuum()
50 : * visible to any running transaction, used by VACUUM
51 : * HeapTupleSatisfiesNonVacuumable()
52 : * Snapshot-style API for HeapTupleSatisfiesVacuum
53 : * HeapTupleSatisfiesToast()
54 : * visible unless part of interrupted vacuum, used for TOAST
55 : * HeapTupleSatisfiesAny()
56 : * all tuples are visible
57 : *
58 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
59 : * Portions Copyright (c) 1994, Regents of the University of California
60 : *
61 : * IDENTIFICATION
62 : * src/backend/access/heap/heapam_visibility.c
63 : *
64 : *-------------------------------------------------------------------------
65 : */
66 :
67 : #include "postgres.h"
68 :
69 : #include "access/heapam.h"
70 : #include "access/htup_details.h"
71 : #include "access/multixact.h"
72 : #include "access/tableam.h"
73 : #include "access/transam.h"
74 : #include "access/xact.h"
75 : #include "access/xlog.h"
76 : #include "storage/bufmgr.h"
77 : #include "storage/procarray.h"
78 : #include "utils/builtins.h"
79 : #include "utils/snapmgr.h"
80 :
81 :
82 : /*
83 : * SetHintBits()
84 : *
85 : * Set commit/abort hint bits on a tuple, if appropriate at this time.
86 : *
87 : * It is only safe to set a transaction-committed hint bit if we know the
88 : * transaction's commit record is guaranteed to be flushed to disk before the
89 : * buffer, or if the table is temporary or unlogged and will be obliterated by
90 : * a crash anyway. We cannot change the LSN of the page here, because we may
91 : * hold only a share lock on the buffer, so we can only use the LSN to
92 : * interlock this if the buffer's LSN already is newer than the commit LSN;
93 : * otherwise we have to just refrain from setting the hint bit until some
94 : * future re-examination of the tuple.
95 : *
96 : * We can always set hint bits when marking a transaction aborted. (Some
97 : * code in heapam.c relies on that!)
98 : *
99 : * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
100 : * we can always set the hint bits, since pre-9.0 VACUUM FULL always used
101 : * synchronous commits and didn't move tuples that weren't previously
102 : * hinted. (This is not known by this subroutine, but is applied by its
103 : * callers.) Note: old-style VACUUM FULL is gone, but we have to keep this
104 : * module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
105 : * support in-place update from pre-9.0 databases.
106 : *
107 : * Normal commits may be asynchronous, so for those we need to get the LSN
108 : * of the transaction and then check whether this is flushed.
109 : *
110 : * The caller should pass xid as the XID of the transaction to check, or
111 : * InvalidTransactionId if no check is needed.
112 : */
113 : static inline void
114 19363114 : SetHintBits(HeapTupleHeader tuple, Buffer buffer,
115 : uint16 infomask, TransactionId xid)
116 : {
117 19363114 : if (TransactionIdIsValid(xid))
118 : {
119 : /* NB: xid must be known committed here! */
120 19103984 : XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
121 :
122 19613470 : if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
123 509486 : BufferGetLSNAtomic(buffer) < commitLSN)
124 : {
125 : /* not flushed and no LSN interlock, so don't set hint */
126 439600 : return;
127 : }
128 : }
129 :
130 18923514 : tuple->t_infomask |= infomask;
131 18923514 : MarkBufferDirtyHint(buffer, true);
132 : }
133 :
134 : /*
135 : * HeapTupleSetHintBits --- exported version of SetHintBits()
136 : *
137 : * This must be separate because of C99's brain-dead notions about how to
138 : * implement inline functions.
139 : */
140 : void
141 438 : HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
142 : uint16 infomask, TransactionId xid)
143 : {
144 438 : SetHintBits(tuple, buffer, infomask, xid);
145 438 : }
146 :
147 : /*
148 : * If HEAP_MOVED_OFF or HEAP_MOVED_IN are set on the tuple, remove them and
149 : * adjust hint bits. See the comment for SetHintBits() for more background.
150 : *
151 : * This helper returns false if the row ought to be invisible, true otherwise.
152 : */
153 : static inline bool
154 53990314 : HeapTupleCleanMoved(HeapTupleHeader tuple, Buffer buffer)
155 : {
156 : TransactionId xvac;
157 :
158 : /* only used by pre-9.0 binary upgrades */
159 53990314 : if (likely(!(tuple->t_infomask & (HEAP_MOVED_OFF | HEAP_MOVED_IN))))
160 53990314 : return true;
161 :
162 0 : xvac = HeapTupleHeaderGetXvac(tuple);
163 :
164 0 : if (TransactionIdIsCurrentTransactionId(xvac))
165 0 : elog(ERROR, "encountered tuple with HEAP_MOVED considered current");
166 :
167 0 : if (TransactionIdIsInProgress(xvac))
168 0 : elog(ERROR, "encountered tuple with HEAP_MOVED considered in-progress");
169 :
170 0 : if (tuple->t_infomask & HEAP_MOVED_OFF)
171 : {
172 0 : if (TransactionIdDidCommit(xvac))
173 : {
174 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
175 : InvalidTransactionId);
176 0 : return false;
177 : }
178 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
179 : InvalidTransactionId);
180 : }
181 0 : else if (tuple->t_infomask & HEAP_MOVED_IN)
182 : {
183 0 : if (TransactionIdDidCommit(xvac))
184 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
185 : InvalidTransactionId);
186 : else
187 : {
188 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
189 : InvalidTransactionId);
190 0 : return false;
191 : }
192 : }
193 :
194 0 : return true;
195 : }
196 :
197 : /*
198 : * HeapTupleSatisfiesSelf
199 : * True iff heap tuple is valid "for itself".
200 : *
201 : * See SNAPSHOT_MVCC's definition for the intended behaviour.
202 : *
203 : * Note:
204 : * Assumes heap tuple is valid.
205 : *
206 : * The satisfaction of "itself" requires the following:
207 : *
208 : * ((Xmin == my-transaction && the row was updated by the current transaction, and
209 : * (Xmax is null it was not deleted
210 : * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
211 : * ||
212 : *
213 : * (Xmin is committed && the row was modified by a committed transaction, and
214 : * (Xmax is null || the row has not been deleted, or
215 : * (Xmax != my-transaction && the row was deleted by another transaction
216 : * Xmax is not committed))) that has not been committed
217 : */
218 : static bool
219 5322 : HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
220 : {
221 5322 : HeapTupleHeader tuple = htup->t_data;
222 :
223 : Assert(ItemPointerIsValid(&htup->t_self));
224 : Assert(htup->t_tableOid != InvalidOid);
225 :
226 5322 : if (!HeapTupleHeaderXminCommitted(tuple))
227 : {
228 5220 : if (HeapTupleHeaderXminInvalid(tuple))
229 0 : return false;
230 :
231 5220 : if (!HeapTupleCleanMoved(tuple, buffer))
232 0 : return false;
233 5220 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
234 : {
235 5220 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
236 5098 : return true;
237 :
238 122 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
239 20 : return true;
240 :
241 102 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
242 : {
243 : TransactionId xmax;
244 :
245 0 : xmax = HeapTupleGetUpdateXid(tuple);
246 :
247 : /* not LOCKED_ONLY, so it has to have an xmax */
248 : Assert(TransactionIdIsValid(xmax));
249 :
250 : /* updating subtransaction must have aborted */
251 0 : if (!TransactionIdIsCurrentTransactionId(xmax))
252 0 : return true;
253 : else
254 0 : return false;
255 : }
256 :
257 102 : if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
258 : {
259 : /* deleting subtransaction must have aborted */
260 18 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
261 : InvalidTransactionId);
262 18 : return true;
263 : }
264 :
265 84 : return false;
266 : }
267 0 : else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
268 0 : return false;
269 0 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
270 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
271 : HeapTupleHeaderGetRawXmin(tuple));
272 : else
273 : {
274 : /* it must have aborted or crashed */
275 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
276 : InvalidTransactionId);
277 0 : return false;
278 : }
279 : }
280 :
281 : /* by here, the inserting transaction has committed */
282 :
283 102 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
284 102 : return true;
285 :
286 0 : if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
287 : {
288 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
289 0 : return true;
290 0 : return false; /* updated by other */
291 : }
292 :
293 0 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
294 : {
295 : TransactionId xmax;
296 :
297 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
298 0 : return true;
299 :
300 0 : xmax = HeapTupleGetUpdateXid(tuple);
301 :
302 : /* not LOCKED_ONLY, so it has to have an xmax */
303 : Assert(TransactionIdIsValid(xmax));
304 :
305 0 : if (TransactionIdIsCurrentTransactionId(xmax))
306 0 : return false;
307 0 : if (TransactionIdIsInProgress(xmax))
308 0 : return true;
309 0 : if (TransactionIdDidCommit(xmax))
310 0 : return false;
311 : /* it must have aborted or crashed */
312 0 : return true;
313 : }
314 :
315 0 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
316 : {
317 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
318 0 : return true;
319 0 : return false;
320 : }
321 :
322 0 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
323 0 : return true;
324 :
325 0 : if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
326 : {
327 : /* it must have aborted or crashed */
328 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
329 : InvalidTransactionId);
330 0 : return true;
331 : }
332 :
333 : /* xmax transaction committed */
334 :
335 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
336 : {
337 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
338 : InvalidTransactionId);
339 0 : return true;
340 : }
341 :
342 0 : SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
343 : HeapTupleHeaderGetRawXmax(tuple));
344 0 : return false;
345 : }
346 :
347 : /*
348 : * HeapTupleSatisfiesAny
349 : * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
350 : */
351 : static bool
352 15132396 : HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
353 : {
354 15132396 : return true;
355 : }
356 :
357 : /*
358 : * HeapTupleSatisfiesToast
359 : * True iff heap tuple is valid as a TOAST row.
360 : *
361 : * See SNAPSHOT_TOAST's definition for the intended behaviour.
362 : *
363 : * This is a simplified version that only checks for VACUUM moving conditions.
364 : * It's appropriate for TOAST usage because TOAST really doesn't want to do
365 : * its own time qual checks; if you can see the main table row that contains
366 : * a TOAST reference, you should be able to see the TOASTed value. However,
367 : * vacuuming a TOAST table is independent of the main table, and in case such
368 : * a vacuum fails partway through, we'd better do this much checking.
369 : *
370 : * Among other things, this means you can't do UPDATEs of rows in a TOAST
371 : * table.
372 : */
373 : static bool
374 170948 : HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot,
375 : Buffer buffer)
376 : {
377 170948 : HeapTupleHeader tuple = htup->t_data;
378 :
379 : Assert(ItemPointerIsValid(&htup->t_self));
380 : Assert(htup->t_tableOid != InvalidOid);
381 :
382 170948 : if (!HeapTupleHeaderXminCommitted(tuple))
383 : {
384 127480 : if (HeapTupleHeaderXminInvalid(tuple))
385 0 : return false;
386 :
387 127480 : if (!HeapTupleCleanMoved(tuple, buffer))
388 0 : return false;
389 :
390 : /*
391 : * An invalid Xmin can be left behind by a speculative insertion that
392 : * is canceled by super-deleting the tuple. This also applies to
393 : * TOAST tuples created during speculative insertion.
394 : */
395 127480 : else if (!TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple)))
396 0 : return false;
397 : }
398 :
399 : /* otherwise assume the tuple is valid for TOAST. */
400 170948 : return true;
401 : }
402 :
403 : /*
404 : * HeapTupleSatisfiesUpdate
405 : *
406 : * This function returns a more detailed result code than most of the
407 : * functions in this file, since UPDATE needs to know more than "is it
408 : * visible?". It also allows for user-supplied CommandId rather than
409 : * relying on CurrentCommandId.
410 : *
411 : * The possible return codes are:
412 : *
413 : * TM_Invisible: the tuple didn't exist at all when the scan started, e.g. it
414 : * was created by a later CommandId.
415 : *
416 : * TM_Ok: The tuple is valid and visible, so it may be updated.
417 : *
418 : * TM_SelfModified: The tuple was updated by the current transaction, after
419 : * the current scan started.
420 : *
421 : * TM_Updated: The tuple was updated by a committed transaction (including
422 : * the case where the tuple was moved into a different partition).
423 : *
424 : * TM_Deleted: The tuple was deleted by a committed transaction.
425 : *
426 : * TM_BeingModified: The tuple is being updated by an in-progress transaction
427 : * other than the current transaction. (Note: this includes the case where
428 : * the tuple is share-locked by a MultiXact, even if the MultiXact includes
429 : * the current transaction. Callers that want to distinguish that case must
430 : * test for it themselves.)
431 : */
432 : TM_Result
433 4339652 : HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
434 : Buffer buffer)
435 : {
436 4339652 : HeapTupleHeader tuple = htup->t_data;
437 :
438 : Assert(ItemPointerIsValid(&htup->t_self));
439 : Assert(htup->t_tableOid != InvalidOid);
440 :
441 4339652 : if (!HeapTupleHeaderXminCommitted(tuple))
442 : {
443 501444 : if (HeapTupleHeaderXminInvalid(tuple))
444 0 : return TM_Invisible;
445 :
446 501444 : else if (!HeapTupleCleanMoved(tuple, buffer))
447 0 : return TM_Invisible;
448 501444 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
449 : {
450 493326 : if (HeapTupleHeaderGetCmin(tuple) >= curcid)
451 24 : return TM_Invisible; /* inserted after scan started */
452 :
453 493302 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
454 412856 : return TM_Ok;
455 :
456 80446 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
457 : {
458 : TransactionId xmax;
459 :
460 80426 : xmax = HeapTupleHeaderGetRawXmax(tuple);
461 :
462 : /*
463 : * Careful here: even though this tuple was created by our own
464 : * transaction, it might be locked by other transactions, if
465 : * the original version was key-share locked when we updated
466 : * it.
467 : */
468 :
469 80426 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
470 : {
471 62 : if (MultiXactIdIsRunning(xmax, true))
472 62 : return TM_BeingModified;
473 : else
474 0 : return TM_Ok;
475 : }
476 :
477 : /*
478 : * If the locker is gone, then there is nothing of interest
479 : * left in this Xmax; otherwise, report the tuple as
480 : * locked/updated.
481 : */
482 80364 : if (!TransactionIdIsInProgress(xmax))
483 0 : return TM_Ok;
484 80364 : return TM_BeingModified;
485 : }
486 :
487 20 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
488 : {
489 : TransactionId xmax;
490 :
491 14 : xmax = HeapTupleGetUpdateXid(tuple);
492 :
493 : /* not LOCKED_ONLY, so it has to have an xmax */
494 : Assert(TransactionIdIsValid(xmax));
495 :
496 : /* deleting subtransaction must have aborted */
497 14 : if (!TransactionIdIsCurrentTransactionId(xmax))
498 : {
499 14 : if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
500 : false))
501 14 : return TM_BeingModified;
502 0 : return TM_Ok;
503 : }
504 : else
505 : {
506 0 : if (HeapTupleHeaderGetCmax(tuple) >= curcid)
507 0 : return TM_SelfModified; /* updated after scan started */
508 : else
509 0 : return TM_Invisible; /* updated before scan started */
510 : }
511 : }
512 :
513 6 : if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
514 : {
515 : /* deleting subtransaction must have aborted */
516 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
517 : InvalidTransactionId);
518 0 : return TM_Ok;
519 : }
520 :
521 6 : if (HeapTupleHeaderGetCmax(tuple) >= curcid)
522 6 : return TM_SelfModified; /* updated after scan started */
523 : else
524 0 : return TM_Invisible; /* updated before scan started */
525 : }
526 8118 : else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
527 0 : return TM_Invisible;
528 8118 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
529 8118 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
530 : HeapTupleHeaderGetRawXmin(tuple));
531 : else
532 : {
533 : /* it must have aborted or crashed */
534 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
535 : InvalidTransactionId);
536 0 : return TM_Invisible;
537 : }
538 : }
539 :
540 : /* by here, the inserting transaction has committed */
541 :
542 3846326 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
543 3602544 : return TM_Ok;
544 :
545 243782 : if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
546 : {
547 312 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
548 0 : return TM_Ok;
549 312 : if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
550 312 : return TM_Updated; /* updated by other */
551 : else
552 0 : return TM_Deleted; /* deleted by other */
553 : }
554 :
555 243470 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
556 : {
557 : TransactionId xmax;
558 :
559 147934 : if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
560 0 : return TM_Ok;
561 :
562 147934 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
563 : {
564 143622 : if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), true))
565 142624 : return TM_BeingModified;
566 :
567 998 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
568 998 : return TM_Ok;
569 : }
570 :
571 4312 : xmax = HeapTupleGetUpdateXid(tuple);
572 4312 : if (!TransactionIdIsValid(xmax))
573 : {
574 0 : if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
575 0 : return TM_BeingModified;
576 : }
577 :
578 : /* not LOCKED_ONLY, so it has to have an xmax */
579 : Assert(TransactionIdIsValid(xmax));
580 :
581 4312 : if (TransactionIdIsCurrentTransactionId(xmax))
582 : {
583 0 : if (HeapTupleHeaderGetCmax(tuple) >= curcid)
584 0 : return TM_SelfModified; /* updated after scan started */
585 : else
586 0 : return TM_Invisible; /* updated before scan started */
587 : }
588 :
589 4312 : if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
590 4300 : return TM_BeingModified;
591 :
592 12 : if (TransactionIdDidCommit(xmax))
593 : {
594 2 : if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
595 0 : return TM_Updated;
596 : else
597 2 : return TM_Deleted;
598 : }
599 :
600 : /*
601 : * By here, the update in the Xmax is either aborted or crashed, but
602 : * what about the other members?
603 : */
604 :
605 10 : if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
606 : {
607 : /*
608 : * There's no member, even just a locker, alive anymore, so we can
609 : * mark the Xmax as invalid.
610 : */
611 10 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
612 : InvalidTransactionId);
613 10 : return TM_Ok;
614 : }
615 : else
616 : {
617 : /* There are lockers running */
618 0 : return TM_BeingModified;
619 : }
620 : }
621 :
622 95536 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
623 : {
624 85588 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
625 85436 : return TM_BeingModified;
626 152 : if (HeapTupleHeaderGetCmax(tuple) >= curcid)
627 152 : return TM_SelfModified; /* updated after scan started */
628 : else
629 0 : return TM_Invisible; /* updated before scan started */
630 : }
631 :
632 9948 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
633 2696 : return TM_BeingModified;
634 :
635 7252 : if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
636 : {
637 : /* it must have aborted or crashed */
638 386 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
639 : InvalidTransactionId);
640 386 : return TM_Ok;
641 : }
642 :
643 : /* xmax transaction committed */
644 :
645 6866 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
646 : {
647 6734 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
648 : InvalidTransactionId);
649 6734 : return TM_Ok;
650 : }
651 :
652 132 : SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
653 : HeapTupleHeaderGetRawXmax(tuple));
654 132 : if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
655 132 : return TM_Updated; /* updated by other */
656 : else
657 0 : return TM_Deleted; /* deleted by other */
658 : }
659 :
660 : /*
661 : * HeapTupleSatisfiesDirty
662 : * True iff heap tuple is valid including effects of open transactions.
663 : *
664 : * See SNAPSHOT_DIRTY's definition for the intended behaviour.
665 : *
666 : * This is essentially like HeapTupleSatisfiesSelf as far as effects of
667 : * the current transaction and committed/aborted xacts are concerned.
668 : * However, we also include the effects of other xacts still in progress.
669 : *
670 : * A special hack is that the passed-in snapshot struct is used as an
671 : * output argument to return the xids of concurrent xacts that affected the
672 : * tuple. snapshot->xmin is set to the tuple's xmin if that is another
673 : * transaction that's still in progress; or to InvalidTransactionId if the
674 : * tuple's xmin is committed good, committed dead, or my own xact.
675 : * Similarly for snapshot->xmax and the tuple's xmax. If the tuple was
676 : * inserted speculatively, meaning that the inserter might still back down
677 : * on the insertion without aborting the whole transaction, the associated
678 : * token is also returned in snapshot->speculativeToken.
679 : */
680 : static bool
681 11876830 : HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
682 : Buffer buffer)
683 : {
684 11876830 : HeapTupleHeader tuple = htup->t_data;
685 :
686 : Assert(ItemPointerIsValid(&htup->t_self));
687 : Assert(htup->t_tableOid != InvalidOid);
688 :
689 11876830 : snapshot->xmin = snapshot->xmax = InvalidTransactionId;
690 11876830 : snapshot->speculativeToken = 0;
691 :
692 11876830 : if (!HeapTupleHeaderXminCommitted(tuple))
693 : {
694 11168854 : if (HeapTupleHeaderXminInvalid(tuple))
695 964 : return false;
696 :
697 11167890 : if (!HeapTupleCleanMoved(tuple, buffer))
698 0 : return false;
699 11167890 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
700 : {
701 11116924 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
702 62054 : return true;
703 :
704 11054870 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
705 10080 : return true;
706 :
707 11044790 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
708 : {
709 : TransactionId xmax;
710 :
711 32 : xmax = HeapTupleGetUpdateXid(tuple);
712 :
713 : /* not LOCKED_ONLY, so it has to have an xmax */
714 : Assert(TransactionIdIsValid(xmax));
715 :
716 : /* updating subtransaction must have aborted */
717 32 : if (!TransactionIdIsCurrentTransactionId(xmax))
718 0 : return true;
719 : else
720 32 : return false;
721 : }
722 :
723 11044758 : if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
724 : {
725 : /* deleting subtransaction must have aborted */
726 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
727 : InvalidTransactionId);
728 0 : return true;
729 : }
730 :
731 11044758 : return false;
732 : }
733 50966 : else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
734 : {
735 : /*
736 : * Return the speculative token to caller. Caller can worry about
737 : * xmax, since it requires a conclusively locked row version, and
738 : * a concurrent update to this tuple is a conflict of its
739 : * purposes.
740 : */
741 90 : if (HeapTupleHeaderIsSpeculative(tuple))
742 : {
743 4 : snapshot->speculativeToken =
744 4 : HeapTupleHeaderGetSpeculativeToken(tuple);
745 :
746 : Assert(snapshot->speculativeToken != 0);
747 : }
748 :
749 90 : snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
750 : /* XXX shouldn't we fall through to look at xmax? */
751 90 : return true; /* in insertion by other */
752 : }
753 50876 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
754 50104 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
755 : HeapTupleHeaderGetRawXmin(tuple));
756 : else
757 : {
758 : /* it must have aborted or crashed */
759 772 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
760 : InvalidTransactionId);
761 772 : return false;
762 : }
763 : }
764 :
765 : /* by here, the inserting transaction has committed */
766 :
767 758080 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
768 266302 : return true;
769 :
770 491778 : if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
771 : {
772 173364 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
773 0 : return true;
774 173364 : return false; /* updated by other */
775 : }
776 :
777 318414 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
778 : {
779 : TransactionId xmax;
780 :
781 60 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
782 26 : return true;
783 :
784 34 : xmax = HeapTupleGetUpdateXid(tuple);
785 :
786 : /* not LOCKED_ONLY, so it has to have an xmax */
787 : Assert(TransactionIdIsValid(xmax));
788 :
789 34 : if (TransactionIdIsCurrentTransactionId(xmax))
790 2 : return false;
791 32 : if (TransactionIdIsInProgress(xmax))
792 : {
793 0 : snapshot->xmax = xmax;
794 0 : return true;
795 : }
796 32 : if (TransactionIdDidCommit(xmax))
797 32 : return false;
798 : /* it must have aborted or crashed */
799 0 : return true;
800 : }
801 :
802 318354 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
803 : {
804 240590 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
805 100 : return true;
806 240490 : return false;
807 : }
808 :
809 77764 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
810 : {
811 28 : if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
812 24 : snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
813 28 : return true;
814 : }
815 :
816 77736 : if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
817 : {
818 : /* it must have aborted or crashed */
819 66 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
820 : InvalidTransactionId);
821 66 : return true;
822 : }
823 :
824 : /* xmax transaction committed */
825 :
826 77670 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
827 : {
828 26878 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
829 : InvalidTransactionId);
830 26878 : return true;
831 : }
832 :
833 50792 : SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
834 : HeapTupleHeaderGetRawXmax(tuple));
835 50792 : return false; /* updated by other */
836 : }
837 :
838 : /*
839 : * HeapTupleSatisfiesMVCC
840 : * True iff heap tuple is valid for the given MVCC snapshot.
841 : *
842 : * See SNAPSHOT_MVCC's definition for the intended behaviour.
843 : *
844 : * Notice that here, we will not update the tuple status hint bits if the
845 : * inserting/deleting transaction is still running according to our snapshot,
846 : * even if in reality it's committed or aborted by now. This is intentional.
847 : * Checking the true transaction state would require access to high-traffic
848 : * shared data structures, creating contention we'd rather do without, and it
849 : * would not change the result of our visibility check anyway. The hint bits
850 : * will be updated by the first visitor that has a snapshot new enough to see
851 : * the inserting/deleting transaction as done. In the meantime, the cost of
852 : * leaving the hint bits unset is basically that each HeapTupleSatisfiesMVCC
853 : * call will need to run TransactionIdIsCurrentTransactionId in addition to
854 : * XidInMVCCSnapshot (but it would have to do the latter anyway). In the old
855 : * coding where we tried to set the hint bits as soon as possible, we instead
856 : * did TransactionIdIsInProgress in each call --- to no avail, as long as the
857 : * inserting/deleting transaction was still running --- which was more cycles
858 : * and more contention on ProcArrayLock.
859 : */
860 : static bool
861 168241976 : HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
862 : Buffer buffer)
863 : {
864 168241976 : HeapTupleHeader tuple = htup->t_data;
865 :
866 : /*
867 : * Assert that the caller has registered the snapshot. This function
868 : * doesn't care about the registration as such, but in general you
869 : * shouldn't try to use a snapshot without registration because it might
870 : * get invalidated while it's still in use, and this is a convenient place
871 : * to check for that.
872 : */
873 : Assert(snapshot->regd_count > 0 || snapshot->active_count > 0);
874 :
875 : Assert(ItemPointerIsValid(&htup->t_self));
876 : Assert(htup->t_tableOid != InvalidOid);
877 :
878 168241976 : if (!HeapTupleHeaderXminCommitted(tuple))
879 : {
880 30533852 : if (HeapTupleHeaderXminInvalid(tuple))
881 428222 : return false;
882 :
883 30105630 : if (!HeapTupleCleanMoved(tuple, buffer))
884 0 : return false;
885 30105630 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
886 : {
887 21996714 : if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
888 15010 : return false; /* inserted after scan started */
889 :
890 21981704 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
891 16086754 : return true;
892 :
893 5894950 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
894 4314 : return true;
895 :
896 5890636 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
897 : {
898 : TransactionId xmax;
899 :
900 14 : xmax = HeapTupleGetUpdateXid(tuple);
901 :
902 : /* not LOCKED_ONLY, so it has to have an xmax */
903 : Assert(TransactionIdIsValid(xmax));
904 :
905 : /* updating subtransaction must have aborted */
906 14 : if (!TransactionIdIsCurrentTransactionId(xmax))
907 14 : return true;
908 0 : else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
909 0 : return true; /* updated after scan started */
910 : else
911 0 : return false; /* updated before scan started */
912 : }
913 :
914 5890622 : if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
915 : {
916 : /* deleting subtransaction must have aborted */
917 70 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
918 : InvalidTransactionId);
919 70 : return true;
920 : }
921 :
922 5890552 : if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
923 1680 : return true; /* deleted after scan started */
924 : else
925 5888872 : return false; /* deleted before scan started */
926 : }
927 8108916 : else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
928 46056 : return false;
929 8062860 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
930 7954342 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
931 : HeapTupleHeaderGetRawXmin(tuple));
932 : else
933 : {
934 : /* it must have aborted or crashed */
935 108518 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
936 : InvalidTransactionId);
937 108518 : return false;
938 : }
939 : }
940 : else
941 : {
942 : /* xmin is committed, but maybe not according to our snapshot */
943 266940980 : if (!HeapTupleHeaderXminFrozen(tuple) &&
944 129232856 : XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
945 6216 : return false; /* treat as still in progress */
946 : }
947 :
948 : /* by here, the inserting transaction has committed */
949 :
950 145656250 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
951 133162120 : return true;
952 :
953 12494130 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
954 233002 : return true;
955 :
956 12261128 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
957 : {
958 : TransactionId xmax;
959 :
960 : /* already checked above */
961 : Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
962 :
963 157296 : xmax = HeapTupleGetUpdateXid(tuple);
964 :
965 : /* not LOCKED_ONLY, so it has to have an xmax */
966 : Assert(TransactionIdIsValid(xmax));
967 :
968 157296 : if (TransactionIdIsCurrentTransactionId(xmax))
969 : {
970 46 : if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
971 0 : return true; /* deleted after scan started */
972 : else
973 46 : return false; /* deleted before scan started */
974 : }
975 157250 : if (XidInMVCCSnapshot(xmax, snapshot))
976 4252 : return true;
977 152998 : if (TransactionIdDidCommit(xmax))
978 152966 : return false; /* updating transaction committed */
979 : /* it must have aborted or crashed */
980 32 : return true;
981 : }
982 :
983 12103832 : if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
984 : {
985 1001098 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
986 : {
987 290696 : if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
988 2724 : return true; /* deleted after scan started */
989 : else
990 287972 : return false; /* deleted before scan started */
991 : }
992 :
993 710402 : if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
994 22226 : return true;
995 :
996 688176 : if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
997 : {
998 : /* it must have aborted or crashed */
999 13698 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1000 : InvalidTransactionId);
1001 13698 : return true;
1002 : }
1003 :
1004 : /* xmax transaction committed */
1005 674478 : SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1006 : HeapTupleHeaderGetRawXmax(tuple));
1007 : }
1008 : else
1009 : {
1010 : /* xmax is committed, but maybe not according to our snapshot */
1011 11102734 : if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1012 1402 : return true; /* treat as still in progress */
1013 : }
1014 :
1015 : /* xmax transaction committed */
1016 :
1017 11775810 : return false;
1018 : }
1019 :
1020 :
1021 : /*
1022 : * HeapTupleSatisfiesVacuum
1023 : *
1024 : * Determine the status of tuples for VACUUM purposes. Here, what
1025 : * we mainly want to know is if a tuple is potentially visible to *any*
1026 : * running transaction. If so, it can't be removed yet by VACUUM.
1027 : *
1028 : * OldestXmin is a cutoff XID (obtained from
1029 : * GetOldestNonRemovableTransactionId()). Tuples deleted by XIDs >=
1030 : * OldestXmin are deemed "recently dead"; they might still be visible to some
1031 : * open transaction, so we can't remove them, even if we see that the deleting
1032 : * transaction has committed.
1033 : */
1034 : HTSV_Result
1035 27471888 : HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
1036 : Buffer buffer)
1037 : {
1038 27471888 : TransactionId dead_after = InvalidTransactionId;
1039 : HTSV_Result res;
1040 :
1041 27471888 : res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1042 :
1043 27471888 : if (res == HEAPTUPLE_RECENTLY_DEAD)
1044 : {
1045 : Assert(TransactionIdIsValid(dead_after));
1046 :
1047 504908 : if (TransactionIdPrecedes(dead_after, OldestXmin))
1048 49492 : res = HEAPTUPLE_DEAD;
1049 : }
1050 : else
1051 : Assert(!TransactionIdIsValid(dead_after));
1052 :
1053 27471888 : return res;
1054 : }
1055 :
1056 : /*
1057 : * Work horse for HeapTupleSatisfiesVacuum and similar routines.
1058 : *
1059 : * In contrast to HeapTupleSatisfiesVacuum this routine, when encountering a
1060 : * tuple that could still be visible to some backend, stores the xid that
1061 : * needs to be compared with the horizon in *dead_after, and returns
1062 : * HEAPTUPLE_RECENTLY_DEAD. The caller then can perform the comparison with
1063 : * the horizon. This is e.g. useful when comparing with different horizons.
1064 : *
1065 : * Note: HEAPTUPLE_DEAD can still be returned here, e.g. if the inserting
1066 : * transaction aborted.
1067 : */
1068 : HTSV_Result
1069 66924642 : HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after)
1070 : {
1071 66924642 : HeapTupleHeader tuple = htup->t_data;
1072 :
1073 : Assert(ItemPointerIsValid(&htup->t_self));
1074 : Assert(htup->t_tableOid != InvalidOid);
1075 : Assert(dead_after != NULL);
1076 :
1077 66924642 : *dead_after = InvalidTransactionId;
1078 :
1079 : /*
1080 : * Has inserting transaction committed?
1081 : *
1082 : * If the inserting transaction aborted, then the tuple was never visible
1083 : * to any other transaction, so we can delete it immediately.
1084 : */
1085 66924642 : if (!HeapTupleHeaderXminCommitted(tuple))
1086 : {
1087 12113698 : if (HeapTupleHeaderXminInvalid(tuple))
1088 31048 : return HEAPTUPLE_DEAD;
1089 12082650 : else if (!HeapTupleCleanMoved(tuple, buffer))
1090 0 : return HEAPTUPLE_DEAD;
1091 12082650 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
1092 : {
1093 4194188 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1094 4121490 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1095 : /* only locked? run infomask-only check first, for performance */
1096 129060 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
1097 56362 : HeapTupleHeaderIsOnlyLocked(tuple))
1098 16336 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1099 : /* inserted and then deleted by same xact */
1100 56362 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
1101 56362 : return HEAPTUPLE_DELETE_IN_PROGRESS;
1102 : /* deleting subtransaction must have aborted */
1103 0 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1104 : }
1105 7888462 : else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
1106 : {
1107 : /*
1108 : * It'd be possible to discern between INSERT/DELETE in progress
1109 : * here by looking at xmax - but that doesn't seem beneficial for
1110 : * the majority of callers and even detrimental for some. We'd
1111 : * rather have callers look at/wait for xmin than xmax. It's
1112 : * always correct to return INSERT_IN_PROGRESS because that's
1113 : * what's happening from the view of other backends.
1114 : */
1115 7322 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1116 : }
1117 7881140 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
1118 7810754 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1119 : HeapTupleHeaderGetRawXmin(tuple));
1120 : else
1121 : {
1122 : /*
1123 : * Not in Progress, Not Committed, so either Aborted or crashed
1124 : */
1125 70386 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1126 : InvalidTransactionId);
1127 70386 : return HEAPTUPLE_DEAD;
1128 : }
1129 :
1130 : /*
1131 : * At this point the xmin is known committed, but we might not have
1132 : * been able to set the hint bit yet; so we can no longer Assert that
1133 : * it's set.
1134 : */
1135 : }
1136 :
1137 : /*
1138 : * Okay, the inserter committed, so it was good at some point. Now what
1139 : * about the deleting transaction?
1140 : */
1141 62621698 : if (tuple->t_infomask & HEAP_XMAX_INVALID)
1142 50775632 : return HEAPTUPLE_LIVE;
1143 :
1144 11846066 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1145 : {
1146 : /*
1147 : * "Deleting" xact really only locked it, so the tuple is live in any
1148 : * case. However, we should make sure that either XMAX_COMMITTED or
1149 : * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1150 : * examining the tuple for future xacts.
1151 : */
1152 27000 : if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1153 : {
1154 27000 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1155 : {
1156 : /*
1157 : * If it's a pre-pg_upgrade tuple, the multixact cannot
1158 : * possibly be running; otherwise have to check.
1159 : */
1160 964 : if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
1161 482 : MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
1162 : true))
1163 38 : return HEAPTUPLE_LIVE;
1164 444 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1165 : }
1166 : else
1167 : {
1168 26518 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1169 8 : return HEAPTUPLE_LIVE;
1170 26510 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1171 : InvalidTransactionId);
1172 : }
1173 : }
1174 :
1175 : /*
1176 : * We don't really care whether xmax did commit, abort or crash. We
1177 : * know that xmax did lock the tuple, but it did not and will never
1178 : * actually update it.
1179 : */
1180 :
1181 26954 : return HEAPTUPLE_LIVE;
1182 : }
1183 :
1184 11819066 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1185 : {
1186 204 : TransactionId xmax = HeapTupleGetUpdateXid(tuple);
1187 :
1188 : /* already checked above */
1189 : Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
1190 :
1191 : /* not LOCKED_ONLY, so it has to have an xmax */
1192 : Assert(TransactionIdIsValid(xmax));
1193 :
1194 204 : if (TransactionIdIsInProgress(xmax))
1195 2 : return HEAPTUPLE_DELETE_IN_PROGRESS;
1196 202 : else if (TransactionIdDidCommit(xmax))
1197 : {
1198 : /*
1199 : * The multixact might still be running due to lockers. Need to
1200 : * allow for pruning if below the xid horizon regardless --
1201 : * otherwise we could end up with a tuple where the updater has to
1202 : * be removed due to the horizon, but is not pruned away. It's
1203 : * not a problem to prune that tuple, because any remaining
1204 : * lockers will also be present in newer tuple versions.
1205 : */
1206 202 : *dead_after = xmax;
1207 202 : return HEAPTUPLE_RECENTLY_DEAD;
1208 : }
1209 0 : else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1210 : {
1211 : /*
1212 : * Not in Progress, Not Committed, so either Aborted or crashed.
1213 : * Mark the Xmax as invalid.
1214 : */
1215 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1216 : }
1217 :
1218 0 : return HEAPTUPLE_LIVE;
1219 : }
1220 :
1221 11818862 : if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1222 : {
1223 10355622 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1224 7797154 : return HEAPTUPLE_DELETE_IN_PROGRESS;
1225 2558468 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
1226 2554970 : SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1227 : HeapTupleHeaderGetRawXmax(tuple));
1228 : else
1229 : {
1230 : /*
1231 : * Not in Progress, Not Committed, so either Aborted or crashed
1232 : */
1233 3498 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1234 : InvalidTransactionId);
1235 3498 : return HEAPTUPLE_LIVE;
1236 : }
1237 :
1238 : /*
1239 : * At this point the xmax is known committed, but we might not have
1240 : * been able to set the hint bit yet; so we can no longer Assert that
1241 : * it's set.
1242 : */
1243 : }
1244 :
1245 : /*
1246 : * Deleter committed, allow caller to check if it was recent enough that
1247 : * some open transactions could still see the tuple.
1248 : */
1249 4018210 : *dead_after = HeapTupleHeaderGetRawXmax(tuple);
1250 4018210 : return HEAPTUPLE_RECENTLY_DEAD;
1251 : }
1252 :
1253 :
1254 : /*
1255 : * HeapTupleSatisfiesNonVacuumable
1256 : *
1257 : * True if tuple might be visible to some transaction; false if it's
1258 : * surely dead to everyone, ie, vacuumable.
1259 : *
1260 : * See SNAPSHOT_NON_VACUUMABLE's definition for the intended behaviour.
1261 : *
1262 : * This is an interface to HeapTupleSatisfiesVacuum that's callable via
1263 : * HeapTupleSatisfiesSnapshot, so it can be used through a Snapshot.
1264 : * snapshot->vistest must have been set up with the horizon to use.
1265 : */
1266 : static bool
1267 723556 : HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot,
1268 : Buffer buffer)
1269 : {
1270 723556 : TransactionId dead_after = InvalidTransactionId;
1271 : HTSV_Result res;
1272 :
1273 723556 : res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1274 :
1275 723556 : if (res == HEAPTUPLE_RECENTLY_DEAD)
1276 : {
1277 : Assert(TransactionIdIsValid(dead_after));
1278 :
1279 167262 : if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after))
1280 135830 : res = HEAPTUPLE_DEAD;
1281 : }
1282 : else
1283 : Assert(!TransactionIdIsValid(dead_after));
1284 :
1285 723556 : return res != HEAPTUPLE_DEAD;
1286 : }
1287 :
1288 :
1289 : /*
1290 : * HeapTupleIsSurelyDead
1291 : *
1292 : * Cheaply determine whether a tuple is surely dead to all onlookers.
1293 : * We sometimes use this in lieu of HeapTupleSatisfiesVacuum when the
1294 : * tuple has just been tested by another visibility routine (usually
1295 : * HeapTupleSatisfiesMVCC) and, therefore, any hint bits that can be set
1296 : * should already be set. We assume that if no hint bits are set, the xmin
1297 : * or xmax transaction is still running. This is therefore faster than
1298 : * HeapTupleSatisfiesVacuum, because we consult neither procarray nor CLOG.
1299 : * It's okay to return false when in doubt, but we must return true only
1300 : * if the tuple is removable.
1301 : */
1302 : bool
1303 12929780 : HeapTupleIsSurelyDead(HeapTuple htup, GlobalVisState *vistest)
1304 : {
1305 12929780 : HeapTupleHeader tuple = htup->t_data;
1306 :
1307 : Assert(ItemPointerIsValid(&htup->t_self));
1308 : Assert(htup->t_tableOid != InvalidOid);
1309 :
1310 : /*
1311 : * If the inserting transaction is marked invalid, then it aborted, and
1312 : * the tuple is definitely dead. If it's marked neither committed nor
1313 : * invalid, then we assume it's still alive (since the presumption is that
1314 : * all relevant hint bits were just set moments ago).
1315 : */
1316 12929780 : if (!HeapTupleHeaderXminCommitted(tuple))
1317 11296458 : return HeapTupleHeaderXminInvalid(tuple);
1318 :
1319 : /*
1320 : * If the inserting transaction committed, but any deleting transaction
1321 : * aborted, the tuple is still alive.
1322 : */
1323 1633322 : if (tuple->t_infomask & HEAP_XMAX_INVALID)
1324 70 : return false;
1325 :
1326 : /*
1327 : * If the XMAX is just a lock, the tuple is still alive.
1328 : */
1329 1633252 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1330 4 : return false;
1331 :
1332 : /*
1333 : * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1334 : * know without checking pg_multixact.
1335 : */
1336 1633248 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1337 290 : return false;
1338 :
1339 : /* If deleter isn't known to have committed, assume it's still running. */
1340 1632958 : if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1341 446642 : return false;
1342 :
1343 : /* Deleter committed, so tuple is dead if the XID is old enough. */
1344 1186316 : return GlobalVisTestIsRemovableXid(vistest,
1345 : HeapTupleHeaderGetRawXmax(tuple));
1346 : }
1347 :
1348 : /*
1349 : * Is the tuple really only locked? That is, is it not updated?
1350 : *
1351 : * It's easy to check just infomask bits if the locker is not a multi; but
1352 : * otherwise we need to verify that the updating transaction has not aborted.
1353 : *
1354 : * This function is here because it follows the same visibility rules laid out
1355 : * at the top of this file.
1356 : */
1357 : bool
1358 242494 : HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
1359 : {
1360 : TransactionId xmax;
1361 :
1362 : /* if there's no valid Xmax, then there's obviously no update either */
1363 242494 : if (tuple->t_infomask & HEAP_XMAX_INVALID)
1364 0 : return true;
1365 :
1366 242494 : if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1367 143324 : return true;
1368 :
1369 : /* invalid xmax means no update */
1370 99170 : if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
1371 0 : return true;
1372 :
1373 : /*
1374 : * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1375 : * necessarily have been updated
1376 : */
1377 99170 : if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1378 94880 : return false;
1379 :
1380 : /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1381 4290 : xmax = HeapTupleGetUpdateXid(tuple);
1382 :
1383 : /* not LOCKED_ONLY, so it has to have an xmax */
1384 : Assert(TransactionIdIsValid(xmax));
1385 :
1386 4290 : if (TransactionIdIsCurrentTransactionId(xmax))
1387 0 : return false;
1388 4290 : if (TransactionIdIsInProgress(xmax))
1389 4224 : return false;
1390 66 : if (TransactionIdDidCommit(xmax))
1391 22 : return false;
1392 :
1393 : /*
1394 : * not current, not in progress, not committed -- must have aborted or
1395 : * crashed
1396 : */
1397 44 : return true;
1398 : }
1399 :
1400 : /*
1401 : * check whether the transaction id 'xid' is in the pre-sorted array 'xip'.
1402 : */
1403 : static bool
1404 89024 : TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
1405 : {
1406 123692 : return num > 0 &&
1407 34668 : bsearch(&xid, xip, num, sizeof(TransactionId), xidComparator) != NULL;
1408 : }
1409 :
1410 : /*
1411 : * See the comments for HeapTupleSatisfiesMVCC for the semantics this function
1412 : * obeys.
1413 : *
1414 : * Only usable on tuples from catalog tables!
1415 : *
1416 : * We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
1417 : * reading catalog pages which couldn't have been created in an older version.
1418 : *
1419 : * We don't set any hint bits in here as it seems unlikely to be beneficial as
1420 : * those should already be set by normal access and it seems to be too
1421 : * dangerous to do so as the semantics of doing so during timetravel are more
1422 : * complicated than when dealing "only" with the present.
1423 : */
1424 : static bool
1425 73290 : HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
1426 : Buffer buffer)
1427 : {
1428 73290 : HeapTupleHeader tuple = htup->t_data;
1429 73290 : TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
1430 73290 : TransactionId xmax = HeapTupleHeaderGetRawXmax(tuple);
1431 :
1432 : Assert(ItemPointerIsValid(&htup->t_self));
1433 : Assert(htup->t_tableOid != InvalidOid);
1434 :
1435 : /* inserting transaction aborted */
1436 73290 : if (HeapTupleHeaderXminInvalid(tuple))
1437 : {
1438 : Assert(!TransactionIdDidCommit(xmin));
1439 150 : return false;
1440 : }
1441 : /* check if it's one of our txids, toplevel is also in there */
1442 73140 : else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1443 : {
1444 : bool resolved;
1445 1002 : CommandId cmin = HeapTupleHeaderGetRawCommandId(tuple);
1446 1002 : CommandId cmax = InvalidCommandId;
1447 :
1448 : /*
1449 : * another transaction might have (tried to) delete this tuple or
1450 : * cmin/cmax was stored in a combo CID. So we need to lookup the
1451 : * actual values externally.
1452 : */
1453 1002 : resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
1454 : htup, buffer,
1455 : &cmin, &cmax);
1456 :
1457 : /*
1458 : * If we haven't resolved the combo CID to cmin/cmax, that means we
1459 : * have not decoded the combo CID yet. That means the cmin is
1460 : * definitely in the future, and we're not supposed to see the tuple
1461 : * yet.
1462 : *
1463 : * XXX This only applies to decoding of in-progress transactions. In
1464 : * regular logical decoding we only execute this code at commit time,
1465 : * at which point we should have seen all relevant combo CIDs. So
1466 : * ideally, we should error out in this case but in practice, this
1467 : * won't happen. If we are too worried about this then we can add an
1468 : * elog inside ResolveCminCmaxDuringDecoding.
1469 : *
1470 : * XXX For the streaming case, we can track the largest combo CID
1471 : * assigned, and error out based on this (when unable to resolve combo
1472 : * CID below that observed maximum value).
1473 : */
1474 1002 : if (!resolved)
1475 118 : return false;
1476 :
1477 : Assert(cmin != InvalidCommandId);
1478 :
1479 992 : if (cmin >= snapshot->curcid)
1480 108 : return false; /* inserted after scan started */
1481 : /* fall through */
1482 : }
1483 : /* committed before our xmin horizon. Do a normal visibility check. */
1484 72138 : else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1485 : {
1486 : Assert(!(HeapTupleHeaderXminCommitted(tuple) &&
1487 : !TransactionIdDidCommit(xmin)));
1488 :
1489 : /* check for hint bit first, consult clog afterwards */
1490 66318 : if (!HeapTupleHeaderXminCommitted(tuple) &&
1491 104 : !TransactionIdDidCommit(xmin))
1492 0 : return false;
1493 : /* fall through */
1494 : }
1495 : /* beyond our xmax horizon, i.e. invisible */
1496 5820 : else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1497 : {
1498 246 : return false;
1499 : }
1500 : /* check if it's a committed transaction in [xmin, xmax) */
1501 5574 : else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1502 : {
1503 : /* fall through */
1504 : }
1505 :
1506 : /*
1507 : * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1508 : * invisible.
1509 : */
1510 : else
1511 : {
1512 0 : return false;
1513 : }
1514 :
1515 : /* at this point we know xmin is visible, go on to check xmax */
1516 :
1517 : /* xid invalid or aborted */
1518 72776 : if (tuple->t_infomask & HEAP_XMAX_INVALID)
1519 63476 : return true;
1520 : /* locked tuples are always visible */
1521 9300 : else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1522 1632 : return true;
1523 :
1524 : /*
1525 : * We can see multis here if we're looking at user tables or if somebody
1526 : * SELECT ... FOR SHARE/UPDATE a system table.
1527 : */
1528 7668 : else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1529 : {
1530 76 : xmax = HeapTupleGetUpdateXid(tuple);
1531 : }
1532 :
1533 : /* check if it's one of our txids, toplevel is also in there */
1534 7668 : if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1535 : {
1536 : bool resolved;
1537 : CommandId cmin;
1538 616 : CommandId cmax = HeapTupleHeaderGetRawCommandId(tuple);
1539 :
1540 : /* Lookup actual cmin/cmax values */
1541 616 : resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
1542 : htup, buffer,
1543 : &cmin, &cmax);
1544 :
1545 : /*
1546 : * If we haven't resolved the combo CID to cmin/cmax, that means we
1547 : * have not decoded the combo CID yet. That means the cmax is
1548 : * definitely in the future, and we're still supposed to see the
1549 : * tuple.
1550 : *
1551 : * XXX This only applies to decoding of in-progress transactions. In
1552 : * regular logical decoding we only execute this code at commit time,
1553 : * at which point we should have seen all relevant combo CIDs. So
1554 : * ideally, we should error out in this case but in practice, this
1555 : * won't happen. If we are too worried about this then we can add an
1556 : * elog inside ResolveCminCmaxDuringDecoding.
1557 : *
1558 : * XXX For the streaming case, we can track the largest combo CID
1559 : * assigned, and error out based on this (when unable to resolve combo
1560 : * CID below that observed maximum value).
1561 : */
1562 616 : if (!resolved || cmax == InvalidCommandId)
1563 40 : return true;
1564 :
1565 576 : if (cmax >= snapshot->curcid)
1566 170 : return true; /* deleted after scan started */
1567 : else
1568 406 : return false; /* deleted before scan started */
1569 : }
1570 : /* below xmin horizon, normal transaction state is valid */
1571 7052 : else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1572 : {
1573 : Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
1574 : !TransactionIdDidCommit(xmax)));
1575 :
1576 : /* check hint bit first */
1577 3878 : if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1578 3752 : return false;
1579 :
1580 : /* check clog */
1581 126 : return !TransactionIdDidCommit(xmax);
1582 : }
1583 : /* above xmax horizon, we cannot possibly see the deleting transaction */
1584 3174 : else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1585 532 : return true;
1586 : /* xmax is between [xmin, xmax), check known committed array */
1587 2642 : else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1588 2642 : return false;
1589 : /* xmax is between [xmin, xmax), but known not to have committed yet */
1590 : else
1591 0 : return true;
1592 : }
1593 :
1594 : /*
1595 : * HeapTupleSatisfiesVisibility
1596 : * True iff heap tuple satisfies a time qual.
1597 : *
1598 : * Notes:
1599 : * Assumes heap tuple is valid, and buffer at least share locked.
1600 : *
1601 : * Hint bits in the HeapTuple's t_infomask may be updated as a side effect;
1602 : * if so, the indicated buffer is marked dirty.
1603 : */
1604 : bool
1605 196224318 : HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, Buffer buffer)
1606 : {
1607 196224318 : switch (snapshot->snapshot_type)
1608 : {
1609 168241976 : case SNAPSHOT_MVCC:
1610 168241976 : return HeapTupleSatisfiesMVCC(htup, snapshot, buffer);
1611 5322 : case SNAPSHOT_SELF:
1612 5322 : return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
1613 15132396 : case SNAPSHOT_ANY:
1614 15132396 : return HeapTupleSatisfiesAny(htup, snapshot, buffer);
1615 170948 : case SNAPSHOT_TOAST:
1616 170948 : return HeapTupleSatisfiesToast(htup, snapshot, buffer);
1617 11876830 : case SNAPSHOT_DIRTY:
1618 11876830 : return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
1619 73290 : case SNAPSHOT_HISTORIC_MVCC:
1620 73290 : return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
1621 723556 : case SNAPSHOT_NON_VACUUMABLE:
1622 723556 : return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
1623 : }
1624 :
1625 0 : return false; /* keep compiler quiet */
1626 : }
|