Line data Source code
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 : * HeapTupleSatisfiesToast()
49 : * visible unless part of interrupted vacuum, used for TOAST
50 : * HeapTupleSatisfiesAny()
51 : * all tuples are visible
52 : *
53 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
54 : * Portions Copyright (c) 1994, Regents of the University of California
55 : *
56 : * IDENTIFICATION
57 : * src/backend/utils/time/tqual.c
58 : *
59 : *-------------------------------------------------------------------------
60 : */
61 :
62 : #include "postgres.h"
63 :
64 : #include "access/htup_details.h"
65 : #include "access/multixact.h"
66 : #include "access/subtrans.h"
67 : #include "access/transam.h"
68 : #include "access/xact.h"
69 : #include "access/xlog.h"
70 : #include "storage/bufmgr.h"
71 : #include "storage/procarray.h"
72 : #include "utils/builtins.h"
73 : #include "utils/combocid.h"
74 : #include "utils/snapmgr.h"
75 : #include "utils/tqual.h"
76 :
77 :
78 : /* Static variables representing various special snapshot semantics */
79 : SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf};
80 : SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny};
81 :
82 : /* local functions */
83 : static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
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
117 740875 : SetHintBits(HeapTupleHeader tuple, Buffer buffer,
118 : uint16 infomask, TransactionId xid)
119 : {
120 740875 : if (TransactionIdIsValid(xid))
121 : {
122 : /* NB: xid must be known committed here! */
123 735990 : XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
124 :
125 741750 : if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
126 5760 : BufferGetLSNAtomic(buffer) < commitLSN)
127 : {
128 : /* not flushed and no LSN interlock, so don't set hint */
129 745944 : return;
130 : }
131 : }
132 :
133 735806 : tuple->t_infomask |= infomask;
134 735806 : 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
144 0 : HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
145 : uint16 infomask, TransactionId xid)
146 : {
147 0 : SetHintBits(tuple, buffer, infomask, xid);
148 0 : }
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
176 336 : HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
177 : {
178 336 : HeapTupleHeader tuple = htup->t_data;
179 :
180 336 : Assert(ItemPointerIsValid(&htup->t_self));
181 336 : Assert(htup->t_tableOid != InvalidOid);
182 :
183 336 : if (!HeapTupleHeaderXminCommitted(tuple))
184 : {
185 336 : if (HeapTupleHeaderXminInvalid(tuple))
186 0 : return false;
187 :
188 : /* Used by pre-9.0 binary upgrades */
189 336 : if (tuple->t_infomask & HEAP_MOVED_OFF)
190 : {
191 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
192 :
193 0 : if (TransactionIdIsCurrentTransactionId(xvac))
194 0 : return false;
195 0 : if (!TransactionIdIsInProgress(xvac))
196 : {
197 0 : if (TransactionIdDidCommit(xvac))
198 : {
199 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
200 : InvalidTransactionId);
201 0 : return false;
202 : }
203 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
204 : InvalidTransactionId);
205 : }
206 : }
207 : /* Used by pre-9.0 binary upgrades */
208 336 : else if (tuple->t_infomask & HEAP_MOVED_IN)
209 : {
210 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
211 :
212 0 : if (!TransactionIdIsCurrentTransactionId(xvac))
213 : {
214 0 : if (TransactionIdIsInProgress(xvac))
215 0 : return false;
216 0 : if (TransactionIdDidCommit(xvac))
217 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
218 : InvalidTransactionId);
219 : else
220 : {
221 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
222 : InvalidTransactionId);
223 0 : return false;
224 : }
225 : }
226 : }
227 336 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
228 : {
229 336 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
230 316 : return true;
231 :
232 20 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
233 3 : return true;
234 :
235 17 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
236 : {
237 : TransactionId xmax;
238 :
239 0 : xmax = HeapTupleGetUpdateXid(tuple);
240 :
241 : /* not LOCKED_ONLY, so it has to have an xmax */
242 0 : Assert(TransactionIdIsValid(xmax));
243 :
244 : /* updating subtransaction must have aborted */
245 0 : if (!TransactionIdIsCurrentTransactionId(xmax))
246 0 : return true;
247 : else
248 0 : return false;
249 : }
250 :
251 17 : if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
252 : {
253 : /* deleting subtransaction must have aborted */
254 3 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
255 : InvalidTransactionId);
256 3 : return true;
257 : }
258 :
259 14 : return false;
260 : }
261 0 : else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
262 0 : return false;
263 0 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
264 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
265 : HeapTupleHeaderGetRawXmin(tuple));
266 : else
267 : {
268 : /* it must have aborted or crashed */
269 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
270 : InvalidTransactionId);
271 0 : return false;
272 : }
273 : }
274 :
275 : /* by here, the inserting transaction has committed */
276 :
277 0 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
278 0 : return true;
279 :
280 0 : if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
281 : {
282 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
283 0 : return true;
284 0 : return false; /* updated by other */
285 : }
286 :
287 0 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
288 : {
289 : TransactionId xmax;
290 :
291 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
292 0 : return true;
293 :
294 0 : xmax = HeapTupleGetUpdateXid(tuple);
295 :
296 : /* not LOCKED_ONLY, so it has to have an xmax */
297 0 : Assert(TransactionIdIsValid(xmax));
298 :
299 0 : if (TransactionIdIsCurrentTransactionId(xmax))
300 0 : return false;
301 0 : if (TransactionIdIsInProgress(xmax))
302 0 : return true;
303 0 : if (TransactionIdDidCommit(xmax))
304 0 : return false;
305 : /* it must have aborted or crashed */
306 0 : return true;
307 : }
308 :
309 0 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
310 : {
311 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
312 0 : return true;
313 0 : return false;
314 : }
315 :
316 0 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
317 0 : return true;
318 :
319 0 : if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
320 : {
321 : /* it must have aborted or crashed */
322 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
323 : InvalidTransactionId);
324 0 : return true;
325 : }
326 :
327 : /* xmax transaction committed */
328 :
329 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
330 : {
331 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
332 : InvalidTransactionId);
333 0 : return true;
334 : }
335 :
336 0 : SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
337 : HeapTupleHeaderGetRawXmax(tuple));
338 0 : return false;
339 : }
340 :
341 : /*
342 : * HeapTupleSatisfiesAny
343 : * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
344 : */
345 : bool
346 766602 : HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
347 : {
348 766602 : 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
366 1632 : HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot,
367 : Buffer buffer)
368 : {
369 1632 : HeapTupleHeader tuple = htup->t_data;
370 :
371 1632 : Assert(ItemPointerIsValid(&htup->t_self));
372 1632 : Assert(htup->t_tableOid != InvalidOid);
373 :
374 1632 : if (!HeapTupleHeaderXminCommitted(tuple))
375 : {
376 1121 : if (HeapTupleHeaderXminInvalid(tuple))
377 0 : return false;
378 :
379 : /* Used by pre-9.0 binary upgrades */
380 1121 : if (tuple->t_infomask & HEAP_MOVED_OFF)
381 : {
382 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
383 :
384 0 : if (TransactionIdIsCurrentTransactionId(xvac))
385 0 : return false;
386 0 : if (!TransactionIdIsInProgress(xvac))
387 : {
388 0 : if (TransactionIdDidCommit(xvac))
389 : {
390 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
391 : InvalidTransactionId);
392 0 : return false;
393 : }
394 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
395 : InvalidTransactionId);
396 : }
397 : }
398 : /* Used by pre-9.0 binary upgrades */
399 1121 : else if (tuple->t_infomask & HEAP_MOVED_IN)
400 : {
401 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
402 :
403 0 : if (!TransactionIdIsCurrentTransactionId(xvac))
404 : {
405 0 : if (TransactionIdIsInProgress(xvac))
406 0 : return false;
407 0 : if (TransactionIdDidCommit(xvac))
408 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
409 : InvalidTransactionId);
410 : else
411 : {
412 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
413 : InvalidTransactionId);
414 0 : 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 1121 : else if (!TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple)))
425 0 : return false;
426 : }
427 :
428 : /* otherwise assume the tuple is valid for TOAST. */
429 1632 : 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
460 119122 : HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
461 : Buffer buffer)
462 : {
463 119122 : HeapTupleHeader tuple = htup->t_data;
464 :
465 119122 : Assert(ItemPointerIsValid(&htup->t_self));
466 119122 : Assert(htup->t_tableOid != InvalidOid);
467 :
468 119122 : if (!HeapTupleHeaderXminCommitted(tuple))
469 : {
470 5207 : if (HeapTupleHeaderXminInvalid(tuple))
471 0 : return HeapTupleInvisible;
472 :
473 : /* Used by pre-9.0 binary upgrades */
474 5207 : if (tuple->t_infomask & HEAP_MOVED_OFF)
475 : {
476 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
477 :
478 0 : if (TransactionIdIsCurrentTransactionId(xvac))
479 0 : return HeapTupleInvisible;
480 0 : if (!TransactionIdIsInProgress(xvac))
481 : {
482 0 : if (TransactionIdDidCommit(xvac))
483 : {
484 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
485 : InvalidTransactionId);
486 0 : return HeapTupleInvisible;
487 : }
488 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
489 : InvalidTransactionId);
490 : }
491 : }
492 : /* Used by pre-9.0 binary upgrades */
493 5207 : else if (tuple->t_infomask & HEAP_MOVED_IN)
494 : {
495 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
496 :
497 0 : if (!TransactionIdIsCurrentTransactionId(xvac))
498 : {
499 0 : if (TransactionIdIsInProgress(xvac))
500 0 : return HeapTupleInvisible;
501 0 : if (TransactionIdDidCommit(xvac))
502 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
503 : InvalidTransactionId);
504 : else
505 : {
506 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
507 : InvalidTransactionId);
508 0 : return HeapTupleInvisible;
509 : }
510 : }
511 : }
512 5207 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
513 : {
514 4998 : if (HeapTupleHeaderGetCmin(tuple) >= curcid)
515 4 : return HeapTupleInvisible; /* inserted after scan started */
516 :
517 4994 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
518 4973 : return HeapTupleMayBeUpdated;
519 :
520 21 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
521 : {
522 : TransactionId xmax;
523 :
524 19 : 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 19 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
534 : {
535 0 : if (MultiXactIdIsRunning(xmax, true))
536 0 : return HeapTupleBeingUpdated;
537 : else
538 0 : 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 19 : if (!TransactionIdIsInProgress(xmax))
547 0 : return HeapTupleMayBeUpdated;
548 19 : return HeapTupleBeingUpdated;
549 : }
550 :
551 2 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
552 : {
553 : TransactionId xmax;
554 :
555 1 : xmax = HeapTupleGetUpdateXid(tuple);
556 :
557 : /* not LOCKED_ONLY, so it has to have an xmax */
558 1 : Assert(TransactionIdIsValid(xmax));
559 :
560 : /* deleting subtransaction must have aborted */
561 1 : if (!TransactionIdIsCurrentTransactionId(xmax))
562 : {
563 1 : if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
564 : false))
565 1 : return HeapTupleBeingUpdated;
566 0 : return HeapTupleMayBeUpdated;
567 : }
568 : else
569 : {
570 0 : if (HeapTupleHeaderGetCmax(tuple) >= curcid)
571 0 : return HeapTupleSelfUpdated; /* updated after scan
572 : * started */
573 : else
574 0 : return HeapTupleInvisible; /* updated before scan
575 : * started */
576 : }
577 : }
578 :
579 1 : if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
580 : {
581 : /* deleting subtransaction must have aborted */
582 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
583 : InvalidTransactionId);
584 0 : return HeapTupleMayBeUpdated;
585 : }
586 :
587 1 : if (HeapTupleHeaderGetCmax(tuple) >= curcid)
588 1 : return HeapTupleSelfUpdated; /* updated after scan started */
589 : else
590 0 : return HeapTupleInvisible; /* updated before scan started */
591 : }
592 209 : else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
593 0 : return HeapTupleInvisible;
594 209 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
595 209 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
596 : HeapTupleHeaderGetRawXmin(tuple));
597 : else
598 : {
599 : /* it must have aborted or crashed */
600 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
601 : InvalidTransactionId);
602 0 : return HeapTupleInvisible;
603 : }
604 : }
605 :
606 : /* by here, the inserting transaction has committed */
607 :
608 114124 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
609 113644 : return HeapTupleMayBeUpdated;
610 :
611 480 : if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
612 : {
613 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
614 0 : return HeapTupleMayBeUpdated;
615 0 : return HeapTupleUpdated; /* updated by other */
616 : }
617 :
618 480 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
619 : {
620 : TransactionId xmax;
621 :
622 0 : if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
623 0 : return HeapTupleMayBeUpdated;
624 :
625 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
626 : {
627 0 : if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), true))
628 0 : return HeapTupleBeingUpdated;
629 :
630 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
631 0 : return HeapTupleMayBeUpdated;
632 : }
633 :
634 0 : xmax = HeapTupleGetUpdateXid(tuple);
635 0 : if (!TransactionIdIsValid(xmax))
636 : {
637 0 : if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
638 0 : return HeapTupleBeingUpdated;
639 : }
640 :
641 : /* not LOCKED_ONLY, so it has to have an xmax */
642 0 : Assert(TransactionIdIsValid(xmax));
643 :
644 0 : if (TransactionIdIsCurrentTransactionId(xmax))
645 : {
646 0 : if (HeapTupleHeaderGetCmax(tuple) >= curcid)
647 0 : return HeapTupleSelfUpdated; /* updated after scan started */
648 : else
649 0 : return HeapTupleInvisible; /* updated before scan started */
650 : }
651 :
652 0 : if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
653 0 : return HeapTupleBeingUpdated;
654 :
655 0 : if (TransactionIdDidCommit(xmax))
656 0 : 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 0 : 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 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
670 : InvalidTransactionId);
671 0 : return HeapTupleMayBeUpdated;
672 : }
673 : else
674 : {
675 : /* There are lockers running */
676 0 : return HeapTupleBeingUpdated;
677 : }
678 : }
679 :
680 480 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
681 : {
682 292 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
683 279 : return HeapTupleBeingUpdated;
684 13 : if (HeapTupleHeaderGetCmax(tuple) >= curcid)
685 13 : return HeapTupleSelfUpdated; /* updated after scan started */
686 : else
687 0 : return HeapTupleInvisible; /* updated before scan started */
688 : }
689 :
690 188 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
691 0 : return HeapTupleBeingUpdated;
692 :
693 188 : if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
694 : {
695 : /* it must have aborted or crashed */
696 12 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
697 : InvalidTransactionId);
698 12 : return HeapTupleMayBeUpdated;
699 : }
700 :
701 : /* xmax transaction committed */
702 :
703 176 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
704 : {
705 176 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
706 : InvalidTransactionId);
707 176 : return HeapTupleMayBeUpdated;
708 : }
709 :
710 0 : SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
711 : HeapTupleHeaderGetRawXmax(tuple));
712 0 : 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
739 9302 : HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
740 : Buffer buffer)
741 : {
742 9302 : HeapTupleHeader tuple = htup->t_data;
743 :
744 9302 : Assert(ItemPointerIsValid(&htup->t_self));
745 9302 : Assert(htup->t_tableOid != InvalidOid);
746 :
747 9302 : snapshot->xmin = snapshot->xmax = InvalidTransactionId;
748 9302 : snapshot->speculativeToken = 0;
749 :
750 9302 : if (!HeapTupleHeaderXminCommitted(tuple))
751 : {
752 1017 : if (HeapTupleHeaderXminInvalid(tuple))
753 26 : return false;
754 :
755 : /* Used by pre-9.0 binary upgrades */
756 991 : if (tuple->t_infomask & HEAP_MOVED_OFF)
757 : {
758 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
759 :
760 0 : if (TransactionIdIsCurrentTransactionId(xvac))
761 0 : return false;
762 0 : if (!TransactionIdIsInProgress(xvac))
763 : {
764 0 : if (TransactionIdDidCommit(xvac))
765 : {
766 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
767 : InvalidTransactionId);
768 0 : return false;
769 : }
770 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
771 : InvalidTransactionId);
772 : }
773 : }
774 : /* Used by pre-9.0 binary upgrades */
775 991 : else if (tuple->t_infomask & HEAP_MOVED_IN)
776 : {
777 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
778 :
779 0 : if (!TransactionIdIsCurrentTransactionId(xvac))
780 : {
781 0 : if (TransactionIdIsInProgress(xvac))
782 0 : return false;
783 0 : if (TransactionIdDidCommit(xvac))
784 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
785 : InvalidTransactionId);
786 : else
787 : {
788 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
789 : InvalidTransactionId);
790 0 : return false;
791 : }
792 : }
793 : }
794 991 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
795 : {
796 856 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
797 57 : return true;
798 :
799 799 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
800 1 : return true;
801 :
802 798 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
803 : {
804 : TransactionId xmax;
805 :
806 0 : xmax = HeapTupleGetUpdateXid(tuple);
807 :
808 : /* not LOCKED_ONLY, so it has to have an xmax */
809 0 : Assert(TransactionIdIsValid(xmax));
810 :
811 : /* updating subtransaction must have aborted */
812 0 : if (!TransactionIdIsCurrentTransactionId(xmax))
813 0 : return true;
814 : else
815 0 : return false;
816 : }
817 :
818 798 : if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
819 : {
820 : /* deleting subtransaction must have aborted */
821 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
822 : InvalidTransactionId);
823 0 : return true;
824 : }
825 :
826 798 : return false;
827 : }
828 135 : 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 0 : if (HeapTupleHeaderIsSpeculative(tuple))
837 : {
838 0 : snapshot->speculativeToken =
839 0 : HeapTupleHeaderGetSpeculativeToken(tuple);
840 :
841 0 : Assert(snapshot->speculativeToken != 0);
842 : }
843 :
844 0 : snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
845 : /* XXX shouldn't we fall through to look at xmax? */
846 0 : return true; /* in insertion by other */
847 : }
848 135 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
849 112 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
850 : HeapTupleHeaderGetRawXmin(tuple));
851 : else
852 : {
853 : /* it must have aborted or crashed */
854 23 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
855 : InvalidTransactionId);
856 23 : return false;
857 : }
858 : }
859 :
860 : /* by here, the inserting transaction has committed */
861 :
862 8397 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
863 661 : return true;
864 :
865 7736 : if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
866 : {
867 5173 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
868 0 : return true;
869 5173 : return false; /* updated by other */
870 : }
871 :
872 2563 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
873 : {
874 : TransactionId xmax;
875 :
876 0 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
877 0 : return true;
878 :
879 0 : xmax = HeapTupleGetUpdateXid(tuple);
880 :
881 : /* not LOCKED_ONLY, so it has to have an xmax */
882 0 : Assert(TransactionIdIsValid(xmax));
883 :
884 0 : if (TransactionIdIsCurrentTransactionId(xmax))
885 0 : return false;
886 0 : if (TransactionIdIsInProgress(xmax))
887 : {
888 0 : snapshot->xmax = xmax;
889 0 : return true;
890 : }
891 0 : if (TransactionIdDidCommit(xmax))
892 0 : return false;
893 : /* it must have aborted or crashed */
894 0 : return true;
895 : }
896 :
897 2563 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
898 : {
899 2362 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
900 1 : return true;
901 2361 : return false;
902 : }
903 :
904 201 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
905 : {
906 0 : if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
907 0 : snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
908 0 : return true;
909 : }
910 :
911 201 : if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
912 : {
913 : /* it must have aborted or crashed */
914 1 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
915 : InvalidTransactionId);
916 1 : return true;
917 : }
918 :
919 : /* xmax transaction committed */
920 :
921 200 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
922 : {
923 25 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
924 : InvalidTransactionId);
925 25 : return true;
926 : }
927 :
928 175 : SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
929 : HeapTupleHeaderGetRawXmax(tuple));
930 175 : 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
963 2636921 : HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
964 : Buffer buffer)
965 : {
966 2636921 : HeapTupleHeader tuple = htup->t_data;
967 :
968 2636921 : Assert(ItemPointerIsValid(&htup->t_self));
969 2636921 : Assert(htup->t_tableOid != InvalidOid);
970 :
971 2636921 : if (!HeapTupleHeaderXminCommitted(tuple))
972 : {
973 321278 : if (HeapTupleHeaderXminInvalid(tuple))
974 5370 : return false;
975 :
976 : /* Used by pre-9.0 binary upgrades */
977 315908 : if (tuple->t_infomask & HEAP_MOVED_OFF)
978 : {
979 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
980 :
981 0 : if (TransactionIdIsCurrentTransactionId(xvac))
982 0 : return false;
983 0 : if (!XidInMVCCSnapshot(xvac, snapshot))
984 : {
985 0 : if (TransactionIdDidCommit(xvac))
986 : {
987 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
988 : InvalidTransactionId);
989 0 : return false;
990 : }
991 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
992 : InvalidTransactionId);
993 : }
994 : }
995 : /* Used by pre-9.0 binary upgrades */
996 315908 : else if (tuple->t_infomask & HEAP_MOVED_IN)
997 : {
998 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
999 :
1000 0 : if (!TransactionIdIsCurrentTransactionId(xvac))
1001 : {
1002 0 : if (XidInMVCCSnapshot(xvac, snapshot))
1003 0 : return false;
1004 0 : if (TransactionIdDidCommit(xvac))
1005 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1006 : InvalidTransactionId);
1007 : else
1008 : {
1009 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1010 : InvalidTransactionId);
1011 0 : return false;
1012 : }
1013 : }
1014 : }
1015 315908 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
1016 : {
1017 161913 : if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
1018 6860 : return false; /* inserted after scan started */
1019 :
1020 155053 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1021 151011 : return true;
1022 :
1023 4042 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
1024 51 : return true;
1025 :
1026 3991 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1027 : {
1028 : TransactionId xmax;
1029 :
1030 1 : xmax = HeapTupleGetUpdateXid(tuple);
1031 :
1032 : /* not LOCKED_ONLY, so it has to have an xmax */
1033 1 : Assert(TransactionIdIsValid(xmax));
1034 :
1035 : /* updating subtransaction must have aborted */
1036 1 : if (!TransactionIdIsCurrentTransactionId(xmax))
1037 1 : return true;
1038 0 : else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1039 0 : return true; /* updated after scan started */
1040 : else
1041 0 : return false; /* updated before scan started */
1042 : }
1043 :
1044 3990 : if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
1045 : {
1046 : /* deleting subtransaction must have aborted */
1047 4 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1048 : InvalidTransactionId);
1049 4 : return true;
1050 : }
1051 :
1052 3986 : if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1053 72 : return true; /* deleted after scan started */
1054 : else
1055 3914 : return false; /* deleted before scan started */
1056 : }
1057 153995 : else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1058 585 : return false;
1059 153410 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
1060 152238 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1061 : HeapTupleHeaderGetRawXmin(tuple));
1062 : else
1063 : {
1064 : /* it must have aborted or crashed */
1065 1172 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1066 : InvalidTransactionId);
1067 1172 : return false;
1068 : }
1069 : }
1070 : else
1071 : {
1072 : /* xmin is committed, but maybe not according to our snapshot */
1073 4414063 : if (!HeapTupleHeaderXminFrozen(tuple) &&
1074 2098420 : XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1075 58 : return false; /* treat as still in progress */
1076 : }
1077 :
1078 : /* by here, the inserting transaction has committed */
1079 :
1080 2467823 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1081 2287260 : return true;
1082 :
1083 180563 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1084 1231 : return true;
1085 :
1086 179332 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1087 : {
1088 : TransactionId xmax;
1089 :
1090 : /* already checked above */
1091 0 : Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
1092 :
1093 0 : xmax = HeapTupleGetUpdateXid(tuple);
1094 :
1095 : /* not LOCKED_ONLY, so it has to have an xmax */
1096 0 : Assert(TransactionIdIsValid(xmax));
1097 :
1098 0 : if (TransactionIdIsCurrentTransactionId(xmax))
1099 : {
1100 0 : if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1101 0 : return true; /* deleted after scan started */
1102 : else
1103 0 : return false; /* deleted before scan started */
1104 : }
1105 0 : if (XidInMVCCSnapshot(xmax, snapshot))
1106 0 : return true;
1107 0 : if (TransactionIdDidCommit(xmax))
1108 0 : return false; /* updating transaction committed */
1109 : /* it must have aborted or crashed */
1110 0 : return true;
1111 : }
1112 :
1113 179332 : if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1114 : {
1115 37218 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
1116 : {
1117 6509 : if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1118 361 : return true; /* deleted after scan started */
1119 : else
1120 6148 : return false; /* deleted before scan started */
1121 : }
1122 :
1123 30709 : if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1124 299 : return true;
1125 :
1126 30410 : if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
1127 : {
1128 : /* it must have aborted or crashed */
1129 516 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1130 : InvalidTransactionId);
1131 516 : return true;
1132 : }
1133 :
1134 : /* xmax transaction committed */
1135 29894 : 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 142114 : if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1142 7 : return true; /* treat as still in progress */
1143 : }
1144 :
1145 : /* xmax transaction committed */
1146 :
1147 172001 : 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
1164 2176975 : HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
1165 : Buffer buffer)
1166 : {
1167 2176975 : HeapTupleHeader tuple = htup->t_data;
1168 :
1169 2176975 : Assert(ItemPointerIsValid(&htup->t_self));
1170 2176975 : 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 2176975 : if (!HeapTupleHeaderXminCommitted(tuple))
1179 : {
1180 589556 : if (HeapTupleHeaderXminInvalid(tuple))
1181 964 : return HEAPTUPLE_DEAD;
1182 : /* Used by pre-9.0 binary upgrades */
1183 588592 : else if (tuple->t_infomask & HEAP_MOVED_OFF)
1184 : {
1185 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1186 :
1187 0 : if (TransactionIdIsCurrentTransactionId(xvac))
1188 0 : return HEAPTUPLE_DELETE_IN_PROGRESS;
1189 0 : if (TransactionIdIsInProgress(xvac))
1190 0 : return HEAPTUPLE_DELETE_IN_PROGRESS;
1191 0 : if (TransactionIdDidCommit(xvac))
1192 : {
1193 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1194 : InvalidTransactionId);
1195 0 : return HEAPTUPLE_DEAD;
1196 : }
1197 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1198 : InvalidTransactionId);
1199 : }
1200 : /* Used by pre-9.0 binary upgrades */
1201 588592 : else if (tuple->t_infomask & HEAP_MOVED_IN)
1202 : {
1203 0 : TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1204 :
1205 0 : if (TransactionIdIsCurrentTransactionId(xvac))
1206 0 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1207 0 : if (TransactionIdIsInProgress(xvac))
1208 0 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1209 0 : if (TransactionIdDidCommit(xvac))
1210 0 : SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1211 : InvalidTransactionId);
1212 : else
1213 : {
1214 0 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1215 : InvalidTransactionId);
1216 0 : return HEAPTUPLE_DEAD;
1217 : }
1218 : }
1219 588592 : else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
1220 : {
1221 116304 : if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1222 116093 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1223 : /* only locked? run infomask-only check first, for performance */
1224 421 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
1225 210 : HeapTupleHeaderIsOnlyLocked(tuple))
1226 1 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1227 : /* inserted and then deleted by same xact */
1228 210 : if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
1229 201 : return HEAPTUPLE_DELETE_IN_PROGRESS;
1230 : /* deleting subtransaction must have aborted */
1231 9 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1232 : }
1233 472288 : 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 109 : return HEAPTUPLE_INSERT_IN_PROGRESS;
1244 : }
1245 472179 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
1246 469710 : 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 2469 : SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1254 : InvalidTransactionId);
1255 2469 : 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 2057129 : if (tuple->t_infomask & HEAP_XMAX_INVALID)
1270 1834905 : return HEAPTUPLE_LIVE;
1271 :
1272 222224 : 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 67 : if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1281 : {
1282 67 : 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 0 : if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
1289 0 : MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
1290 : true))
1291 0 : return HEAPTUPLE_LIVE;
1292 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1293 : }
1294 : else
1295 : {
1296 67 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1297 0 : return HEAPTUPLE_LIVE;
1298 67 : 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 67 : return HEAPTUPLE_LIVE;
1310 : }
1311 :
1312 222157 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1313 : {
1314 : TransactionId xmax;
1315 :
1316 0 : if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1317 : {
1318 : /* already checked above */
1319 0 : Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
1320 :
1321 0 : xmax = HeapTupleGetUpdateXid(tuple);
1322 :
1323 : /* not LOCKED_ONLY, so it has to have an xmax */
1324 0 : Assert(TransactionIdIsValid(xmax));
1325 :
1326 0 : if (TransactionIdIsInProgress(xmax))
1327 0 : return HEAPTUPLE_DELETE_IN_PROGRESS;
1328 0 : else if (TransactionIdDidCommit(xmax))
1329 : /* there are still lockers around -- can't return DEAD here */
1330 0 : return HEAPTUPLE_RECENTLY_DEAD;
1331 : /* updating transaction aborted */
1332 0 : return HEAPTUPLE_LIVE;
1333 : }
1334 :
1335 0 : Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED));
1336 :
1337 0 : xmax = HeapTupleGetUpdateXid(tuple);
1338 :
1339 : /* not LOCKED_ONLY, so it has to have an xmax */
1340 0 : Assert(TransactionIdIsValid(xmax));
1341 :
1342 : /* multi is not running -- updating xact cannot be */
1343 0 : Assert(!TransactionIdIsInProgress(xmax));
1344 0 : if (TransactionIdDidCommit(xmax))
1345 : {
1346 0 : if (!TransactionIdPrecedes(xmax, OldestXmin))
1347 0 : return HEAPTUPLE_RECENTLY_DEAD;
1348 : else
1349 0 : return HEAPTUPLE_DEAD;
1350 : }
1351 :
1352 : /*
1353 : * Not in Progress, Not Committed, so either Aborted or crashed.
1354 : * Remove the Xmax.
1355 : */
1356 0 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);
1357 0 : return HEAPTUPLE_LIVE;
1358 : }
1359 :
1360 222157 : if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1361 : {
1362 84424 : if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
1363 355 : return HEAPTUPLE_DELETE_IN_PROGRESS;
1364 84069 : else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
1365 83652 : SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1366 : HeapTupleHeaderGetRawXmax(tuple));
1367 : else
1368 : {
1369 : /*
1370 : * Not in Progress, Not Committed, so either Aborted or crashed
1371 : */
1372 417 : SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1373 : InvalidTransactionId);
1374 417 : return HEAPTUPLE_LIVE;
1375 : }
1376 :
1377 : /*
1378 : * At this point the xmax is known committed, but we might not have
1379 : * been able to set the hint bit yet; so we can no longer Assert that
1380 : * it's set.
1381 : */
1382 : }
1383 :
1384 : /*
1385 : * Deleter committed, but perhaps it was recent enough that some open
1386 : * transactions could still see the tuple.
1387 : */
1388 221385 : if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin))
1389 100113 : return HEAPTUPLE_RECENTLY_DEAD;
1390 :
1391 : /* Otherwise, it's dead and removable */
1392 121272 : return HEAPTUPLE_DEAD;
1393 : }
1394 :
1395 : /*
1396 : * HeapTupleIsSurelyDead
1397 : *
1398 : * Cheaply determine whether a tuple is surely dead to all onlookers.
1399 : * We sometimes use this in lieu of HeapTupleSatisfiesVacuum when the
1400 : * tuple has just been tested by another visibility routine (usually
1401 : * HeapTupleSatisfiesMVCC) and, therefore, any hint bits that can be set
1402 : * should already be set. We assume that if no hint bits are set, the xmin
1403 : * or xmax transaction is still running. This is therefore faster than
1404 : * HeapTupleSatisfiesVacuum, because we don't consult PGXACT nor CLOG.
1405 : * It's okay to return FALSE when in doubt, but we must return TRUE only
1406 : * if the tuple is removable.
1407 : */
1408 : bool
1409 49223 : HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin)
1410 : {
1411 49223 : HeapTupleHeader tuple = htup->t_data;
1412 :
1413 49223 : Assert(ItemPointerIsValid(&htup->t_self));
1414 49223 : Assert(htup->t_tableOid != InvalidOid);
1415 :
1416 : /*
1417 : * If the inserting transaction is marked invalid, then it aborted, and
1418 : * the tuple is definitely dead. If it's marked neither committed nor
1419 : * invalid, then we assume it's still alive (since the presumption is that
1420 : * all relevant hint bits were just set moments ago).
1421 : */
1422 49223 : if (!HeapTupleHeaderXminCommitted(tuple))
1423 8481 : return HeapTupleHeaderXminInvalid(tuple) ? true : false;
1424 :
1425 : /*
1426 : * If the inserting transaction committed, but any deleting transaction
1427 : * aborted, the tuple is still alive.
1428 : */
1429 40742 : if (tuple->t_infomask & HEAP_XMAX_INVALID)
1430 2 : return false;
1431 :
1432 : /*
1433 : * If the XMAX is just a lock, the tuple is still alive.
1434 : */
1435 40740 : if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1436 0 : return false;
1437 :
1438 : /*
1439 : * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1440 : * know without checking pg_multixact.
1441 : */
1442 40740 : if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1443 0 : return false;
1444 :
1445 : /* If deleter isn't known to have committed, assume it's still running. */
1446 40740 : if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1447 6697 : return false;
1448 :
1449 : /* Deleter committed, so tuple is dead if the XID is old enough. */
1450 34043 : return TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin);
1451 : }
1452 :
1453 : /*
1454 : * XidInMVCCSnapshot
1455 : * Is the given XID still-in-progress according to the snapshot?
1456 : *
1457 : * Note: GetSnapshotData never stores either top xid or subxids of our own
1458 : * backend into a snapshot, so these xids will not be reported as "running"
1459 : * by this function. This is OK for current uses, because we always check
1460 : * TransactionIdIsCurrentTransactionId first, except for known-committed
1461 : * XIDs which could not be ours anyway.
1462 : */
1463 : static bool
1464 2425238 : XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
1465 : {
1466 : uint32 i;
1467 :
1468 : /*
1469 : * Make a quick range check to eliminate most XIDs without looking at the
1470 : * xip arrays. Note that this is OK even if we convert a subxact XID to
1471 : * its parent below, because a subxact with XID < xmin has surely also got
1472 : * a parent with XID < xmin, while one with XID >= xmax must belong to a
1473 : * parent that was not yet committed at the time of this snapshot.
1474 : */
1475 :
1476 : /* Any xid < xmin is not in-progress */
1477 2425238 : if (TransactionIdPrecedes(xid, snapshot->xmin))
1478 2266775 : return false;
1479 : /* Any xid >= xmax is in-progress */
1480 158463 : if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
1481 436 : return true;
1482 :
1483 : /*
1484 : * Snapshot information is stored slightly differently in snapshots taken
1485 : * during recovery.
1486 : */
1487 158027 : if (!snapshot->takenDuringRecovery)
1488 : {
1489 : /*
1490 : * If the snapshot contains full subxact data, the fastest way to
1491 : * check things is just to compare the given XID against both subxact
1492 : * XIDs and top-level XIDs. If the snapshot overflowed, we have to
1493 : * use pg_subtrans to convert a subxact XID to its parent XID, but
1494 : * then we need only look at top-level XIDs not subxacts.
1495 : */
1496 158027 : if (!snapshot->suboverflowed)
1497 : {
1498 : /* we have full data, so search subxip */
1499 : int32 j;
1500 :
1501 201733 : for (j = 0; j < snapshot->subxcnt; j++)
1502 : {
1503 43706 : if (TransactionIdEquals(xid, snapshot->subxip[j]))
1504 0 : return true;
1505 : }
1506 :
1507 : /* not there, fall through to search xip[] */
1508 : }
1509 : else
1510 : {
1511 : /*
1512 : * Snapshot overflowed, so convert xid to top-level. This is safe
1513 : * because we eliminated too-old XIDs above.
1514 : */
1515 0 : xid = SubTransGetTopmostTransaction(xid);
1516 :
1517 : /*
1518 : * If xid was indeed a subxact, we might now have an xid < xmin,
1519 : * so recheck to avoid an array scan. No point in rechecking
1520 : * xmax.
1521 : */
1522 0 : if (TransactionIdPrecedes(xid, snapshot->xmin))
1523 0 : return false;
1524 : }
1525 :
1526 483639 : for (i = 0; i < snapshot->xcnt; i++)
1527 : {
1528 326125 : if (TransactionIdEquals(xid, snapshot->xip[i]))
1529 513 : return true;
1530 : }
1531 : }
1532 : else
1533 : {
1534 : int32 j;
1535 :
1536 : /*
1537 : * In recovery we store all xids in the subxact array because it is by
1538 : * far the bigger array, and we mostly don't know which xids are
1539 : * top-level and which are subxacts. The xip array is empty.
1540 : *
1541 : * We start by searching subtrans, if we overflowed.
1542 : */
1543 0 : if (snapshot->suboverflowed)
1544 : {
1545 : /*
1546 : * Snapshot overflowed, so convert xid to top-level. This is safe
1547 : * because we eliminated too-old XIDs above.
1548 : */
1549 0 : xid = SubTransGetTopmostTransaction(xid);
1550 :
1551 : /*
1552 : * If xid was indeed a subxact, we might now have an xid < xmin,
1553 : * so recheck to avoid an array scan. No point in rechecking
1554 : * xmax.
1555 : */
1556 0 : if (TransactionIdPrecedes(xid, snapshot->xmin))
1557 0 : return false;
1558 : }
1559 :
1560 : /*
1561 : * We now have either a top-level xid higher than xmin or an
1562 : * indeterminate xid. We don't know whether it's top level or subxact
1563 : * but it doesn't matter. If it's present, the xid is visible.
1564 : */
1565 0 : for (j = 0; j < snapshot->subxcnt; j++)
1566 : {
1567 0 : if (TransactionIdEquals(xid, snapshot->subxip[j]))
1568 0 : return true;
1569 : }
1570 : }
1571 :
1572 157514 : return false;
1573 : }
1574 :
1575 : /*
1576 : * Is the tuple really only locked? That is, is it not updated?
1577 : *
1578 : * It's easy to check just infomask bits if the locker is not a multi; but
1579 : * otherwise we need to verify that the updating transaction has not aborted.
1580 : *
1581 : * This function is here because it follows the same time qualification rules
1582 : * laid out at the top of this file.
1583 : */
1584 : bool
1585 2299 : HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
1586 : {
1587 : TransactionId xmax;
1588 :
1589 : /* if there's no valid Xmax, then there's obviously no update either */
1590 2299 : if (tuple->t_infomask & HEAP_XMAX_INVALID)
1591 0 : return true;
1592 :
1593 2299 : if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1594 8 : return true;
1595 :
1596 : /* invalid xmax means no update */
1597 2291 : if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
1598 0 : return true;
1599 :
1600 : /*
1601 : * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1602 : * necessarily have been updated
1603 : */
1604 2291 : if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1605 2290 : return false;
1606 :
1607 : /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1608 1 : xmax = HeapTupleGetUpdateXid(tuple);
1609 :
1610 : /* not LOCKED_ONLY, so it has to have an xmax */
1611 1 : Assert(TransactionIdIsValid(xmax));
1612 :
1613 1 : if (TransactionIdIsCurrentTransactionId(xmax))
1614 0 : return false;
1615 1 : if (TransactionIdIsInProgress(xmax))
1616 0 : return false;
1617 1 : if (TransactionIdDidCommit(xmax))
1618 0 : return false;
1619 :
1620 : /*
1621 : * not current, not in progress, not committed -- must have aborted or
1622 : * crashed
1623 : */
1624 1 : return true;
1625 : }
1626 :
1627 : /*
1628 : * check whether the transaction id 'xid' is in the pre-sorted array 'xip'.
1629 : */
1630 : static bool
1631 0 : TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
1632 : {
1633 0 : return bsearch(&xid, xip, num,
1634 0 : sizeof(TransactionId), xidComparator) != NULL;
1635 : }
1636 :
1637 : /*
1638 : * See the comments for HeapTupleSatisfiesMVCC for the semantics this function
1639 : * obeys.
1640 : *
1641 : * Only usable on tuples from catalog tables!
1642 : *
1643 : * We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
1644 : * reading catalog pages which couldn't have been created in an older version.
1645 : *
1646 : * We don't set any hint bits in here as it seems unlikely to be beneficial as
1647 : * those should already be set by normal access and it seems to be too
1648 : * dangerous to do so as the semantics of doing so during timetravel are more
1649 : * complicated than when dealing "only" with the present.
1650 : */
1651 : bool
1652 0 : HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
1653 : Buffer buffer)
1654 : {
1655 0 : HeapTupleHeader tuple = htup->t_data;
1656 0 : TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
1657 0 : TransactionId xmax = HeapTupleHeaderGetRawXmax(tuple);
1658 :
1659 0 : Assert(ItemPointerIsValid(&htup->t_self));
1660 0 : Assert(htup->t_tableOid != InvalidOid);
1661 :
1662 : /* inserting transaction aborted */
1663 0 : if (HeapTupleHeaderXminInvalid(tuple))
1664 : {
1665 0 : Assert(!TransactionIdDidCommit(xmin));
1666 0 : return false;
1667 : }
1668 : /* check if it's one of our txids, toplevel is also in there */
1669 0 : else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1670 : {
1671 : bool resolved;
1672 0 : CommandId cmin = HeapTupleHeaderGetRawCommandId(tuple);
1673 0 : CommandId cmax = InvalidCommandId;
1674 :
1675 : /*
1676 : * another transaction might have (tried to) delete this tuple or
1677 : * cmin/cmax was stored in a combocid. So we need to lookup the actual
1678 : * values externally.
1679 : */
1680 0 : resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
1681 : htup, buffer,
1682 : &cmin, &cmax);
1683 :
1684 0 : if (!resolved)
1685 0 : elog(ERROR, "could not resolve cmin/cmax of catalog tuple");
1686 :
1687 0 : Assert(cmin != InvalidCommandId);
1688 :
1689 0 : if (cmin >= snapshot->curcid)
1690 0 : return false; /* inserted after scan started */
1691 : /* fall through */
1692 : }
1693 : /* committed before our xmin horizon. Do a normal visibility check. */
1694 0 : else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1695 : {
1696 0 : Assert(!(HeapTupleHeaderXminCommitted(tuple) &&
1697 : !TransactionIdDidCommit(xmin)));
1698 :
1699 : /* check for hint bit first, consult clog afterwards */
1700 0 : if (!HeapTupleHeaderXminCommitted(tuple) &&
1701 0 : !TransactionIdDidCommit(xmin))
1702 0 : return false;
1703 : /* fall through */
1704 : }
1705 : /* beyond our xmax horizon, i.e. invisible */
1706 0 : else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1707 : {
1708 0 : return false;
1709 : }
1710 : /* check if it's a committed transaction in [xmin, xmax) */
1711 0 : else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1712 : {
1713 : /* fall through */
1714 : }
1715 :
1716 : /*
1717 : * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1718 : * invisible.
1719 : */
1720 : else
1721 : {
1722 0 : return false;
1723 : }
1724 :
1725 : /* at this point we know xmin is visible, go on to check xmax */
1726 :
1727 : /* xid invalid or aborted */
1728 0 : if (tuple->t_infomask & HEAP_XMAX_INVALID)
1729 0 : return true;
1730 : /* locked tuples are always visible */
1731 0 : else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1732 0 : return true;
1733 :
1734 : /*
1735 : * We can see multis here if we're looking at user tables or if somebody
1736 : * SELECT ... FOR SHARE/UPDATE a system table.
1737 : */
1738 0 : else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1739 : {
1740 0 : xmax = HeapTupleGetUpdateXid(tuple);
1741 : }
1742 :
1743 : /* check if it's one of our txids, toplevel is also in there */
1744 0 : if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1745 : {
1746 : bool resolved;
1747 : CommandId cmin;
1748 0 : CommandId cmax = HeapTupleHeaderGetRawCommandId(tuple);
1749 :
1750 : /* Lookup actual cmin/cmax values */
1751 0 : resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
1752 : htup, buffer,
1753 : &cmin, &cmax);
1754 :
1755 0 : if (!resolved)
1756 0 : elog(ERROR, "could not resolve combocid to cmax");
1757 :
1758 0 : Assert(cmax != InvalidCommandId);
1759 :
1760 0 : if (cmax >= snapshot->curcid)
1761 0 : return true; /* deleted after scan started */
1762 : else
1763 0 : return false; /* deleted before scan started */
1764 : }
1765 : /* below xmin horizon, normal transaction state is valid */
1766 0 : else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1767 : {
1768 0 : Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
1769 : !TransactionIdDidCommit(xmax)));
1770 :
1771 : /* check hint bit first */
1772 0 : if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1773 0 : return false;
1774 :
1775 : /* check clog */
1776 0 : return !TransactionIdDidCommit(xmax);
1777 : }
1778 : /* above xmax horizon, we cannot possibly see the deleting transaction */
1779 0 : else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1780 0 : return true;
1781 : /* xmax is between [xmin, xmax), check known committed array */
1782 0 : else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1783 0 : return false;
1784 : /* xmax is between [xmin, xmax), but known not to have committed yet */
1785 : else
1786 0 : return true;
1787 : }
|