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