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