1 /*-------------------------------------------------------------------------
4 * POSTGRES "time qualification" code, ie, tuple visibility rules.
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, SetBufferCommitInfoNeedsSave 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.
13 * NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array)
14 * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
15 * pg_clog). Otherwise we have a race condition: we might decide that a
16 * just-committed transaction crashed, because none of the tests succeed.
17 * xact.c is careful to record commit/abort in pg_clog before it unsets
18 * MyProc->xid in PGPROC array. That fixes that problem, but it also
19 * means there is a window where TransactionIdIsInProgress and
20 * TransactionIdDidCommit will both return true. If we check only
21 * TransactionIdDidCommit, we could consider a tuple committed when a
22 * later GetSnapshotData call will still think the originating transaction
23 * is in progress, which leads to application-level inconsistency. The
24 * upshot is that we gotta check TransactionIdIsInProgress first in all
25 * 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
29 * Summary of visibility functions:
31 * HeapTupleSatisfiesMVCC()
32 * visible to supplied snapshot, excludes current command
33 * HeapTupleSatisfiesNow()
34 * visible to instant snapshot, excludes current command
35 * HeapTupleSatisfiesUpdate()
36 * like HeapTupleSatisfiesNow(), but with user-supplied command
37 * counter and more complex result
38 * HeapTupleSatisfiesSelf()
39 * visible to instant snapshot and current command
40 * HeapTupleSatisfiesDirty()
41 * like HeapTupleSatisfiesSelf(), but includes open transactions
42 * HeapTupleSatisfiesVacuum()
43 * visible to any running transaction, used by VACUUM
44 * HeapTupleSatisfiesToast()
45 * visible unless part of interrupted vacuum, used for TOAST
46 * HeapTupleSatisfiesAny()
47 * all tuples are visible
49 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
50 * Portions Copyright (c) 1994, Regents of the University of California
55 *-------------------------------------------------------------------------
60 #include "access/multixact.h"
61 #include "access/subtrans.h"
62 #include "access/transam.h"
63 #include "access/xact.h"
64 #include "storage/bufmgr.h"
65 #include "storage/procarray.h"
66 #include "utils/tqual.h"
69 /* Static variables representing various special snapshot semantics */
70 SnapshotData SnapshotNowData
= {HeapTupleSatisfiesNow
};
71 SnapshotData SnapshotSelfData
= {HeapTupleSatisfiesSelf
};
72 SnapshotData SnapshotAnyData
= {HeapTupleSatisfiesAny
};
73 SnapshotData SnapshotToastData
= {HeapTupleSatisfiesToast
};
76 static bool XidInMVCCSnapshot(TransactionId xid
, Snapshot snapshot
);
82 * Set commit/abort hint bits on a tuple, if appropriate at this time.
84 * It is only safe to set a transaction-committed hint bit if we know the
85 * transaction's commit record has been flushed to disk. We cannot change
86 * the LSN of the page here because we may hold only a share lock on the
87 * buffer, so we can't use the LSN to interlock this; we have to just refrain
88 * from setting the hint bit until some future re-examination of the tuple.
90 * We can always set hint bits when marking a transaction aborted. (Some
91 * code in heapam.c relies on that!)
93 * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
94 * we can always set the hint bits, since VACUUM FULL always uses synchronous
95 * commits and doesn't move tuples that weren't previously hinted. (This is
96 * not known by this subroutine, but is applied by its callers.)
98 * Normal commits may be asynchronous, so for those we need to get the LSN
99 * of the transaction and then check whether this is flushed.
101 * The caller should pass xid as the XID of the transaction to check, or
102 * InvalidTransactionId if no check is needed.
105 SetHintBits(HeapTupleHeader tuple
, Buffer buffer
,
106 uint16 infomask
, TransactionId xid
)
108 if (TransactionIdIsValid(xid
))
110 /* NB: xid must be known committed here! */
111 XLogRecPtr commitLSN
= TransactionIdGetCommitLSN(xid
);
113 if (XLogNeedsFlush(commitLSN
))
114 return; /* not flushed yet, so don't set hint */
117 tuple
->t_infomask
|= infomask
;
118 SetBufferCommitInfoNeedsSave(buffer
);
122 * HeapTupleSetHintBits --- exported version of SetHintBits()
124 * This must be separate because of C99's brain-dead notions about how to
125 * implement inline functions.
128 HeapTupleSetHintBits(HeapTupleHeader tuple
, Buffer buffer
,
129 uint16 infomask
, TransactionId xid
)
131 SetHintBits(tuple
, buffer
, infomask
, xid
);
136 * HeapTupleSatisfiesSelf
137 * True iff heap tuple is valid "for itself".
139 * Here, we consider the effects of:
140 * all committed transactions (as of the current instant)
141 * previous commands of this transaction
142 * changes made by the current command
145 * Assumes heap tuple is valid.
147 * The satisfaction of "itself" requires the following:
149 * ((Xmin == my-transaction && the row was updated by the current transaction, and
150 * (Xmax is null it was not deleted
151 * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
154 * (Xmin is committed && the row was modified by a committed transaction, and
155 * (Xmax is null || the row has not been deleted, or
156 * (Xmax != my-transaction && the row was deleted by another transaction
157 * Xmax is not committed))) that has not been committed
160 HeapTupleSatisfiesSelf(HeapTupleHeader tuple
, Snapshot snapshot
, Buffer buffer
)
162 if (!(tuple
->t_infomask
& HEAP_XMIN_COMMITTED
))
164 if (tuple
->t_infomask
& HEAP_XMIN_INVALID
)
167 if (tuple
->t_infomask
& HEAP_MOVED_OFF
)
169 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
171 if (TransactionIdIsCurrentTransactionId(xvac
))
173 if (!TransactionIdIsInProgress(xvac
))
175 if (TransactionIdDidCommit(xvac
))
177 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
178 InvalidTransactionId
);
181 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
182 InvalidTransactionId
);
185 else if (tuple
->t_infomask
& HEAP_MOVED_IN
)
187 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
189 if (!TransactionIdIsCurrentTransactionId(xvac
))
191 if (TransactionIdIsInProgress(xvac
))
193 if (TransactionIdDidCommit(xvac
))
194 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
195 InvalidTransactionId
);
198 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
199 InvalidTransactionId
);
204 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple
)))
206 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid */
209 if (tuple
->t_infomask
& HEAP_IS_LOCKED
) /* not deleter */
212 Assert(!(tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
));
214 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
216 /* deleting subtransaction must have aborted */
217 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
218 InvalidTransactionId
);
224 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple
)))
226 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple
)))
227 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
228 HeapTupleHeaderGetXmin(tuple
));
231 /* it must have aborted or crashed */
232 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
233 InvalidTransactionId
);
238 /* by here, the inserting transaction has committed */
240 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid or aborted */
243 if (tuple
->t_infomask
& HEAP_XMAX_COMMITTED
)
245 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
247 return false; /* updated by other */
250 if (tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
)
252 /* MultiXacts are currently only allowed to lock tuples */
253 Assert(tuple
->t_infomask
& HEAP_IS_LOCKED
);
257 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
259 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
264 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple
)))
267 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple
)))
269 /* it must have aborted or crashed */
270 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
271 InvalidTransactionId
);
275 /* xmax transaction committed */
277 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
279 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
280 InvalidTransactionId
);
284 SetHintBits(tuple
, buffer
, HEAP_XMAX_COMMITTED
,
285 HeapTupleHeaderGetXmax(tuple
));
290 * HeapTupleSatisfiesNow
291 * True iff heap tuple is valid "now".
293 * Here, we consider the effects of:
294 * all committed transactions (as of the current instant)
295 * previous commands of this transaction
297 * Note we do _not_ include changes made by the current command. This
298 * solves the "Halloween problem" wherein an UPDATE might try to re-update
299 * its own output tuples, http://en.wikipedia.org/wiki/Halloween_Problem.
302 * Assumes heap tuple is valid.
304 * The satisfaction of "now" requires the following:
306 * ((Xmin == my-transaction && inserted by the current transaction
307 * Cmin < my-command && before this command, and
308 * (Xmax is null || the row has not been deleted, or
309 * (Xmax == my-transaction && it was deleted by the current transaction
310 * Cmax >= my-command))) but not before this command,
312 * (Xmin is committed && the row was inserted by a committed transaction, and
313 * (Xmax is null || the row has not been deleted, or
314 * (Xmax == my-transaction && the row is being deleted by this transaction
315 * Cmax >= my-command) || but it's not deleted "yet", or
316 * (Xmax != my-transaction && the row was deleted by another transaction
317 * Xmax is not committed)))) that has not been committed
319 * mao says 17 march 1993: the tests in this routine are correct;
320 * if you think they're not, you're wrong, and you should think
321 * about it again. i know, it happened to me. we don't need to
322 * check commit time against the start time of this transaction
323 * because 2ph locking protects us from doing the wrong thing.
324 * if you mess around here, you'll break serializability. the only
325 * problem with this code is that it does the wrong thing for system
326 * catalog updates, because the catalogs aren't subject to 2ph, so
327 * the serializability guarantees we provide don't extend to xacts
328 * that do catalog accesses. this is unfortunate, but not critical.
331 HeapTupleSatisfiesNow(HeapTupleHeader tuple
, Snapshot snapshot
, Buffer buffer
)
333 if (!(tuple
->t_infomask
& HEAP_XMIN_COMMITTED
))
335 if (tuple
->t_infomask
& HEAP_XMIN_INVALID
)
338 if (tuple
->t_infomask
& HEAP_MOVED_OFF
)
340 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
342 if (TransactionIdIsCurrentTransactionId(xvac
))
344 if (!TransactionIdIsInProgress(xvac
))
346 if (TransactionIdDidCommit(xvac
))
348 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
349 InvalidTransactionId
);
352 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
353 InvalidTransactionId
);
356 else if (tuple
->t_infomask
& HEAP_MOVED_IN
)
358 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
360 if (!TransactionIdIsCurrentTransactionId(xvac
))
362 if (TransactionIdIsInProgress(xvac
))
364 if (TransactionIdDidCommit(xvac
))
365 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
366 InvalidTransactionId
);
369 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
370 InvalidTransactionId
);
375 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple
)))
377 if (HeapTupleHeaderGetCmin(tuple
) >= GetCurrentCommandId(false))
378 return false; /* inserted after scan started */
380 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid */
383 if (tuple
->t_infomask
& HEAP_IS_LOCKED
) /* not deleter */
386 Assert(!(tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
));
388 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
390 /* deleting subtransaction must have aborted */
391 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
392 InvalidTransactionId
);
396 if (HeapTupleHeaderGetCmax(tuple
) >= GetCurrentCommandId(false))
397 return true; /* deleted after scan started */
399 return false; /* deleted before scan started */
401 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple
)))
403 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple
)))
404 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
405 HeapTupleHeaderGetXmin(tuple
));
408 /* it must have aborted or crashed */
409 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
410 InvalidTransactionId
);
415 /* by here, the inserting transaction has committed */
417 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid or aborted */
420 if (tuple
->t_infomask
& HEAP_XMAX_COMMITTED
)
422 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
427 if (tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
)
429 /* MultiXacts are currently only allowed to lock tuples */
430 Assert(tuple
->t_infomask
& HEAP_IS_LOCKED
);
434 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
436 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
438 if (HeapTupleHeaderGetCmax(tuple
) >= GetCurrentCommandId(false))
439 return true; /* deleted after scan started */
441 return false; /* deleted before scan started */
444 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple
)))
447 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple
)))
449 /* it must have aborted or crashed */
450 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
451 InvalidTransactionId
);
455 /* xmax transaction committed */
457 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
459 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
460 InvalidTransactionId
);
464 SetHintBits(tuple
, buffer
, HEAP_XMAX_COMMITTED
,
465 HeapTupleHeaderGetXmax(tuple
));
470 * HeapTupleSatisfiesAny
471 * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
474 HeapTupleSatisfiesAny(HeapTupleHeader tuple
, Snapshot snapshot
, Buffer buffer
)
480 * HeapTupleSatisfiesToast
481 * True iff heap tuple is valid as a TOAST row.
483 * This is a simplified version that only checks for VACUUM moving conditions.
484 * It's appropriate for TOAST usage because TOAST really doesn't want to do
485 * its own time qual checks; if you can see the main table row that contains
486 * a TOAST reference, you should be able to see the TOASTed value. However,
487 * vacuuming a TOAST table is independent of the main table, and in case such
488 * a vacuum fails partway through, we'd better do this much checking.
490 * Among other things, this means you can't do UPDATEs of rows in a TOAST
494 HeapTupleSatisfiesToast(HeapTupleHeader tuple
, Snapshot snapshot
,
497 if (!(tuple
->t_infomask
& HEAP_XMIN_COMMITTED
))
499 if (tuple
->t_infomask
& HEAP_XMIN_INVALID
)
502 if (tuple
->t_infomask
& HEAP_MOVED_OFF
)
504 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
506 if (TransactionIdIsCurrentTransactionId(xvac
))
508 if (!TransactionIdIsInProgress(xvac
))
510 if (TransactionIdDidCommit(xvac
))
512 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
513 InvalidTransactionId
);
516 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
517 InvalidTransactionId
);
520 else if (tuple
->t_infomask
& HEAP_MOVED_IN
)
522 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
524 if (!TransactionIdIsCurrentTransactionId(xvac
))
526 if (TransactionIdIsInProgress(xvac
))
528 if (TransactionIdDidCommit(xvac
))
529 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
530 InvalidTransactionId
);
533 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
534 InvalidTransactionId
);
541 /* otherwise assume the tuple is valid for TOAST. */
546 * HeapTupleSatisfiesUpdate
548 * Same logic as HeapTupleSatisfiesNow, but returns a more detailed result
549 * code, since UPDATE needs to know more than "is it visible?". Also,
550 * tuples of my own xact are tested against the passed CommandId not
553 * The possible return codes are:
555 * HeapTupleInvisible: the tuple didn't exist at all when the scan started,
556 * e.g. it was created by a later CommandId.
558 * HeapTupleMayBeUpdated: The tuple is valid and visible, so it may be
561 * HeapTupleSelfUpdated: The tuple was updated by the current transaction,
562 * after the current scan started.
564 * HeapTupleUpdated: The tuple was updated by a committed transaction.
566 * HeapTupleBeingUpdated: The tuple is being updated by an in-progress
567 * transaction other than the current transaction. (Note: this includes
568 * the case where the tuple is share-locked by a MultiXact, even if the
569 * MultiXact includes the current transaction. Callers that want to
570 * distinguish that case must test for it themselves.)
573 HeapTupleSatisfiesUpdate(HeapTupleHeader tuple
, CommandId curcid
,
576 if (!(tuple
->t_infomask
& HEAP_XMIN_COMMITTED
))
578 if (tuple
->t_infomask
& HEAP_XMIN_INVALID
)
579 return HeapTupleInvisible
;
581 if (tuple
->t_infomask
& HEAP_MOVED_OFF
)
583 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
585 if (TransactionIdIsCurrentTransactionId(xvac
))
586 return HeapTupleInvisible
;
587 if (!TransactionIdIsInProgress(xvac
))
589 if (TransactionIdDidCommit(xvac
))
591 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
592 InvalidTransactionId
);
593 return HeapTupleInvisible
;
595 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
596 InvalidTransactionId
);
599 else if (tuple
->t_infomask
& HEAP_MOVED_IN
)
601 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
603 if (!TransactionIdIsCurrentTransactionId(xvac
))
605 if (TransactionIdIsInProgress(xvac
))
606 return HeapTupleInvisible
;
607 if (TransactionIdDidCommit(xvac
))
608 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
609 InvalidTransactionId
);
612 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
613 InvalidTransactionId
);
614 return HeapTupleInvisible
;
618 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple
)))
620 if (HeapTupleHeaderGetCmin(tuple
) >= curcid
)
621 return HeapTupleInvisible
; /* inserted after scan started */
623 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid */
624 return HeapTupleMayBeUpdated
;
626 if (tuple
->t_infomask
& HEAP_IS_LOCKED
) /* not deleter */
627 return HeapTupleMayBeUpdated
;
629 Assert(!(tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
));
631 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
633 /* deleting subtransaction must have aborted */
634 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
635 InvalidTransactionId
);
636 return HeapTupleMayBeUpdated
;
639 if (HeapTupleHeaderGetCmax(tuple
) >= curcid
)
640 return HeapTupleSelfUpdated
; /* updated after scan started */
642 return HeapTupleInvisible
; /* updated before scan started */
644 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple
)))
645 return HeapTupleInvisible
;
646 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple
)))
647 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
648 HeapTupleHeaderGetXmin(tuple
));
651 /* it must have aborted or crashed */
652 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
653 InvalidTransactionId
);
654 return HeapTupleInvisible
;
658 /* by here, the inserting transaction has committed */
660 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid or aborted */
661 return HeapTupleMayBeUpdated
;
663 if (tuple
->t_infomask
& HEAP_XMAX_COMMITTED
)
665 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
666 return HeapTupleMayBeUpdated
;
667 return HeapTupleUpdated
; /* updated by other */
670 if (tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
)
672 /* MultiXacts are currently only allowed to lock tuples */
673 Assert(tuple
->t_infomask
& HEAP_IS_LOCKED
);
675 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple
)))
676 return HeapTupleBeingUpdated
;
677 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
678 InvalidTransactionId
);
679 return HeapTupleMayBeUpdated
;
682 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
684 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
685 return HeapTupleMayBeUpdated
;
686 if (HeapTupleHeaderGetCmax(tuple
) >= curcid
)
687 return HeapTupleSelfUpdated
; /* updated after scan started */
689 return HeapTupleInvisible
; /* updated before scan started */
692 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple
)))
693 return HeapTupleBeingUpdated
;
695 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple
)))
697 /* it must have aborted or crashed */
698 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
699 InvalidTransactionId
);
700 return HeapTupleMayBeUpdated
;
703 /* xmax transaction committed */
705 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
707 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
708 InvalidTransactionId
);
709 return HeapTupleMayBeUpdated
;
712 SetHintBits(tuple
, buffer
, HEAP_XMAX_COMMITTED
,
713 HeapTupleHeaderGetXmax(tuple
));
714 return HeapTupleUpdated
; /* updated by other */
718 * HeapTupleSatisfiesDirty
719 * True iff heap tuple is valid including effects of open transactions.
721 * Here, we consider the effects of:
722 * all committed and in-progress transactions (as of the current instant)
723 * previous commands of this transaction
724 * changes made by the current command
726 * This is essentially like HeapTupleSatisfiesSelf as far as effects of
727 * the current transaction and committed/aborted xacts are concerned.
728 * However, we also include the effects of other xacts still in progress.
730 * A special hack is that the passed-in snapshot struct is used as an
731 * output argument to return the xids of concurrent xacts that affected the
732 * tuple. snapshot->xmin is set to the tuple's xmin if that is another
733 * transaction that's still in progress; or to InvalidTransactionId if the
734 * tuple's xmin is committed good, committed dead, or my own xact. Similarly
735 * for snapshot->xmax and the tuple's xmax.
738 HeapTupleSatisfiesDirty(HeapTupleHeader tuple
, Snapshot snapshot
,
741 snapshot
->xmin
= snapshot
->xmax
= InvalidTransactionId
;
743 if (!(tuple
->t_infomask
& HEAP_XMIN_COMMITTED
))
745 if (tuple
->t_infomask
& HEAP_XMIN_INVALID
)
748 if (tuple
->t_infomask
& HEAP_MOVED_OFF
)
750 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
752 if (TransactionIdIsCurrentTransactionId(xvac
))
754 if (!TransactionIdIsInProgress(xvac
))
756 if (TransactionIdDidCommit(xvac
))
758 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
759 InvalidTransactionId
);
762 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
763 InvalidTransactionId
);
766 else if (tuple
->t_infomask
& HEAP_MOVED_IN
)
768 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
770 if (!TransactionIdIsCurrentTransactionId(xvac
))
772 if (TransactionIdIsInProgress(xvac
))
774 if (TransactionIdDidCommit(xvac
))
775 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
776 InvalidTransactionId
);
779 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
780 InvalidTransactionId
);
785 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple
)))
787 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid */
790 if (tuple
->t_infomask
& HEAP_IS_LOCKED
) /* not deleter */
793 Assert(!(tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
));
795 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
797 /* deleting subtransaction must have aborted */
798 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
799 InvalidTransactionId
);
805 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple
)))
807 snapshot
->xmin
= HeapTupleHeaderGetXmin(tuple
);
808 /* XXX shouldn't we fall through to look at xmax? */
809 return true; /* in insertion by other */
811 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple
)))
812 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
813 HeapTupleHeaderGetXmin(tuple
));
816 /* it must have aborted or crashed */
817 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
818 InvalidTransactionId
);
823 /* by here, the inserting transaction has committed */
825 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid or aborted */
828 if (tuple
->t_infomask
& HEAP_XMAX_COMMITTED
)
830 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
832 return false; /* updated by other */
835 if (tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
)
837 /* MultiXacts are currently only allowed to lock tuples */
838 Assert(tuple
->t_infomask
& HEAP_IS_LOCKED
);
842 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
844 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
849 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple
)))
851 snapshot
->xmax
= HeapTupleHeaderGetXmax(tuple
);
855 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple
)))
857 /* it must have aborted or crashed */
858 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
859 InvalidTransactionId
);
863 /* xmax transaction committed */
865 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
867 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
868 InvalidTransactionId
);
872 SetHintBits(tuple
, buffer
, HEAP_XMAX_COMMITTED
,
873 HeapTupleHeaderGetXmax(tuple
));
874 return false; /* updated by other */
878 * HeapTupleSatisfiesMVCC
879 * True iff heap tuple is valid for the given MVCC snapshot.
881 * Here, we consider the effects of:
882 * all transactions committed as of the time of the given snapshot
883 * previous commands of this transaction
885 * Does _not_ include:
886 * transactions shown as in-progress by the snapshot
887 * transactions started after the snapshot was taken
888 * changes made by the current command
890 * This is the same as HeapTupleSatisfiesNow, except that transactions that
891 * were in progress or as yet unstarted when the snapshot was taken will
892 * be treated as uncommitted, even if they have committed by now.
894 * (Notice, however, that the tuple status hint bits will be updated on the
895 * basis of the true state of the transaction, even if we then pretend we
899 HeapTupleSatisfiesMVCC(HeapTupleHeader tuple
, Snapshot snapshot
,
902 if (!(tuple
->t_infomask
& HEAP_XMIN_COMMITTED
))
904 if (tuple
->t_infomask
& HEAP_XMIN_INVALID
)
907 if (tuple
->t_infomask
& HEAP_MOVED_OFF
)
909 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
911 if (TransactionIdIsCurrentTransactionId(xvac
))
913 if (!TransactionIdIsInProgress(xvac
))
915 if (TransactionIdDidCommit(xvac
))
917 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
918 InvalidTransactionId
);
921 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
922 InvalidTransactionId
);
925 else if (tuple
->t_infomask
& HEAP_MOVED_IN
)
927 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
929 if (!TransactionIdIsCurrentTransactionId(xvac
))
931 if (TransactionIdIsInProgress(xvac
))
933 if (TransactionIdDidCommit(xvac
))
934 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
935 InvalidTransactionId
);
938 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
939 InvalidTransactionId
);
944 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple
)))
946 if (HeapTupleHeaderGetCmin(tuple
) >= snapshot
->curcid
)
947 return false; /* inserted after scan started */
949 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid */
952 if (tuple
->t_infomask
& HEAP_IS_LOCKED
) /* not deleter */
955 Assert(!(tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
));
957 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
959 /* deleting subtransaction must have aborted */
960 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
961 InvalidTransactionId
);
965 if (HeapTupleHeaderGetCmax(tuple
) >= snapshot
->curcid
)
966 return true; /* deleted after scan started */
968 return false; /* deleted before scan started */
970 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple
)))
972 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple
)))
973 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
974 HeapTupleHeaderGetXmin(tuple
));
977 /* it must have aborted or crashed */
978 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
979 InvalidTransactionId
);
985 * By here, the inserting transaction has committed - have to check
988 if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple
), snapshot
))
989 return false; /* treat as still in progress */
991 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid or aborted */
994 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
997 if (tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
)
999 /* MultiXacts are currently only allowed to lock tuples */
1000 Assert(tuple
->t_infomask
& HEAP_IS_LOCKED
);
1004 if (!(tuple
->t_infomask
& HEAP_XMAX_COMMITTED
))
1006 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple
)))
1008 if (HeapTupleHeaderGetCmax(tuple
) >= snapshot
->curcid
)
1009 return true; /* deleted after scan started */
1011 return false; /* deleted before scan started */
1014 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple
)))
1017 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple
)))
1019 /* it must have aborted or crashed */
1020 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
1021 InvalidTransactionId
);
1025 /* xmax transaction committed */
1026 SetHintBits(tuple
, buffer
, HEAP_XMAX_COMMITTED
,
1027 HeapTupleHeaderGetXmax(tuple
));
1031 * OK, the deleting transaction committed too ... but when?
1033 if (XidInMVCCSnapshot(HeapTupleHeaderGetXmax(tuple
), snapshot
))
1034 return true; /* treat as still in progress */
1041 * HeapTupleSatisfiesVacuum
1043 * Determine the status of tuples for VACUUM purposes. Here, what
1044 * we mainly want to know is if a tuple is potentially visible to *any*
1045 * running transaction. If so, it can't be removed yet by VACUUM.
1047 * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples
1048 * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
1049 * still be visible to some open transaction, so we can't remove them,
1050 * even if we see that the deleting transaction has committed.
1053 HeapTupleSatisfiesVacuum(HeapTupleHeader tuple
, TransactionId OldestXmin
,
1057 * Has inserting transaction committed?
1059 * If the inserting transaction aborted, then the tuple was never visible
1060 * to any other transaction, so we can delete it immediately.
1062 if (!(tuple
->t_infomask
& HEAP_XMIN_COMMITTED
))
1064 if (tuple
->t_infomask
& HEAP_XMIN_INVALID
)
1065 return HEAPTUPLE_DEAD
;
1066 else if (tuple
->t_infomask
& HEAP_MOVED_OFF
)
1068 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
1070 if (TransactionIdIsCurrentTransactionId(xvac
))
1071 return HEAPTUPLE_DELETE_IN_PROGRESS
;
1072 if (TransactionIdIsInProgress(xvac
))
1073 return HEAPTUPLE_DELETE_IN_PROGRESS
;
1074 if (TransactionIdDidCommit(xvac
))
1076 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
1077 InvalidTransactionId
);
1078 return HEAPTUPLE_DEAD
;
1080 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
1081 InvalidTransactionId
);
1083 else if (tuple
->t_infomask
& HEAP_MOVED_IN
)
1085 TransactionId xvac
= HeapTupleHeaderGetXvac(tuple
);
1087 if (TransactionIdIsCurrentTransactionId(xvac
))
1088 return HEAPTUPLE_INSERT_IN_PROGRESS
;
1089 if (TransactionIdIsInProgress(xvac
))
1090 return HEAPTUPLE_INSERT_IN_PROGRESS
;
1091 if (TransactionIdDidCommit(xvac
))
1092 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
1093 InvalidTransactionId
);
1096 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
1097 InvalidTransactionId
);
1098 return HEAPTUPLE_DEAD
;
1101 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple
)))
1103 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
) /* xid invalid */
1104 return HEAPTUPLE_INSERT_IN_PROGRESS
;
1105 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
1106 return HEAPTUPLE_INSERT_IN_PROGRESS
;
1107 /* inserted and then deleted by same xact */
1108 return HEAPTUPLE_DELETE_IN_PROGRESS
;
1110 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple
)))
1111 SetHintBits(tuple
, buffer
, HEAP_XMIN_COMMITTED
,
1112 HeapTupleHeaderGetXmin(tuple
));
1116 * Not in Progress, Not Committed, so either Aborted or crashed
1118 SetHintBits(tuple
, buffer
, HEAP_XMIN_INVALID
,
1119 InvalidTransactionId
);
1120 return HEAPTUPLE_DEAD
;
1124 * At this point the xmin is known committed, but we might not have
1125 * been able to set the hint bit yet; so we can no longer Assert that
1131 * Okay, the inserter committed, so it was good at some point. Now what
1132 * about the deleting transaction?
1134 if (tuple
->t_infomask
& HEAP_XMAX_INVALID
)
1135 return HEAPTUPLE_LIVE
;
1137 if (tuple
->t_infomask
& HEAP_IS_LOCKED
)
1140 * "Deleting" xact really only locked it, so the tuple is live in any
1141 * case. However, we should make sure that either XMAX_COMMITTED or
1142 * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1143 * examining the tuple for future xacts. Also, marking dead
1144 * MultiXacts as invalid here provides defense against MultiXactId
1145 * wraparound (see also comments in heap_freeze_tuple()).
1147 if (!(tuple
->t_infomask
& HEAP_XMAX_COMMITTED
))
1149 if (tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
)
1151 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple
)))
1152 return HEAPTUPLE_LIVE
;
1156 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple
)))
1157 return HEAPTUPLE_LIVE
;
1161 * We don't really care whether xmax did commit, abort or crash.
1162 * We know that xmax did lock the tuple, but it did not and will
1163 * never actually update it.
1165 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
1166 InvalidTransactionId
);
1168 return HEAPTUPLE_LIVE
;
1171 if (tuple
->t_infomask
& HEAP_XMAX_IS_MULTI
)
1173 /* MultiXacts are currently only allowed to lock tuples */
1174 Assert(tuple
->t_infomask
& HEAP_IS_LOCKED
);
1175 return HEAPTUPLE_LIVE
;
1178 if (!(tuple
->t_infomask
& HEAP_XMAX_COMMITTED
))
1180 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple
)))
1181 return HEAPTUPLE_DELETE_IN_PROGRESS
;
1182 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple
)))
1183 SetHintBits(tuple
, buffer
, HEAP_XMAX_COMMITTED
,
1184 HeapTupleHeaderGetXmax(tuple
));
1188 * Not in Progress, Not Committed, so either Aborted or crashed
1190 SetHintBits(tuple
, buffer
, HEAP_XMAX_INVALID
,
1191 InvalidTransactionId
);
1192 return HEAPTUPLE_LIVE
;
1196 * At this point the xmax is known committed, but we might not have
1197 * been able to set the hint bit yet; so we can no longer Assert that
1203 * Deleter committed, but check special cases.
1206 if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple
),
1207 HeapTupleHeaderGetXmax(tuple
)))
1210 * Inserter also deleted it, so it was never visible to anyone else.
1211 * However, we can only remove it early if it's not an updated tuple;
1212 * else its parent tuple is linking to it via t_ctid, and this tuple
1213 * mustn't go away before the parent does.
1215 if (!(tuple
->t_infomask
& HEAP_UPDATED
))
1216 return HEAPTUPLE_DEAD
;
1219 if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple
), OldestXmin
))
1221 /* deleting xact is too recent, tuple could still be visible */
1222 return HEAPTUPLE_RECENTLY_DEAD
;
1225 /* Otherwise, it's dead and removable */
1226 return HEAPTUPLE_DEAD
;
1232 * Is the given XID still-in-progress according to the snapshot?
1234 * Note: GetSnapshotData never stores either top xid or subxids of our own
1235 * backend into a snapshot, so these xids will not be reported as "running"
1236 * by this function. This is OK for current uses, because we actually only
1237 * apply this for known-committed XIDs.
1240 XidInMVCCSnapshot(TransactionId xid
, Snapshot snapshot
)
1245 * Make a quick range check to eliminate most XIDs without looking at the
1246 * xip arrays. Note that this is OK even if we convert a subxact XID to
1247 * its parent below, because a subxact with XID < xmin has surely also got
1248 * a parent with XID < xmin, while one with XID >= xmax must belong to a
1249 * parent that was not yet committed at the time of this snapshot.
1252 /* Any xid < xmin is not in-progress */
1253 if (TransactionIdPrecedes(xid
, snapshot
->xmin
))
1255 /* Any xid >= xmax is in-progress */
1256 if (TransactionIdFollowsOrEquals(xid
, snapshot
->xmax
))
1260 * If the snapshot contains full subxact data, the fastest way to check
1261 * things is just to compare the given XID against both subxact XIDs and
1262 * top-level XIDs. If the snapshot overflowed, we have to use pg_subtrans
1263 * to convert a subxact XID to its parent XID, but then we need only look
1264 * at top-level XIDs not subxacts.
1266 if (snapshot
->subxcnt
>= 0)
1268 /* full data, so search subxip */
1271 for (j
= 0; j
< snapshot
->subxcnt
; j
++)
1273 if (TransactionIdEquals(xid
, snapshot
->subxip
[j
]))
1277 /* not there, fall through to search xip[] */
1281 /* overflowed, so convert xid to top-level */
1282 xid
= SubTransGetTopmostTransaction(xid
);
1285 * If xid was indeed a subxact, we might now have an xid < xmin, so
1286 * recheck to avoid an array scan. No point in rechecking xmax.
1288 if (TransactionIdPrecedes(xid
, snapshot
->xmin
))
1292 for (i
= 0; i
< snapshot
->xcnt
; i
++)
1294 if (TransactionIdEquals(xid
, snapshot
->xip
[i
]))