Fix oversight in previous error-reporting patch; mustn't pfree path string
[PostgreSQL.git] / src / backend / utils / time / tqual.c
bloba891caa6085f57be8985d77dfab95e2cf994e0d7
1 /*-------------------------------------------------------------------------
3 * tqual.c
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
27 * race condition.
30 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
31 * Portions Copyright (c) 1994, Regents of the University of California
33 * IDENTIFICATION
34 * $PostgreSQL$
36 *-------------------------------------------------------------------------
39 #include "postgres.h"
41 #include "access/multixact.h"
42 #include "access/subtrans.h"
43 #include "access/transam.h"
44 #include "access/xact.h"
45 #include "storage/bufmgr.h"
46 #include "storage/procarray.h"
47 #include "utils/tqual.h"
50 /* Static variables representing various special snapshot semantics */
51 SnapshotData SnapshotNowData = {HeapTupleSatisfiesNow};
52 SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf};
53 SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny};
54 SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast};
56 /* local functions */
57 static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
61 * SetHintBits()
63 * Set commit/abort hint bits on a tuple, if appropriate at this time.
65 * It is only safe to set a transaction-committed hint bit if we know the
66 * transaction's commit record has been flushed to disk. We cannot change
67 * the LSN of the page here because we may hold only a share lock on the
68 * buffer, so we can't use the LSN to interlock this; we have to just refrain
69 * from setting the hint bit until some future re-examination of the tuple.
71 * We can always set hint bits when marking a transaction aborted. (Some
72 * code in heapam.c relies on that!)
74 * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
75 * we can always set the hint bits, since VACUUM FULL always uses synchronous
76 * commits and doesn't move tuples that weren't previously hinted. (This is
77 * not known by this subroutine, but is applied by its callers.)
79 * Normal commits may be asynchronous, so for those we need to get the LSN
80 * of the transaction and then check whether this is flushed.
82 * The caller should pass xid as the XID of the transaction to check, or
83 * InvalidTransactionId if no check is needed.
85 static inline void
86 SetHintBits(HeapTupleHeader tuple, Buffer buffer,
87 uint16 infomask, TransactionId xid)
89 if (TransactionIdIsValid(xid))
91 /* NB: xid must be known committed here! */
92 XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
94 if (XLogNeedsFlush(commitLSN))
95 return; /* not flushed yet, so don't set hint */
98 tuple->t_infomask |= infomask;
99 SetBufferCommitInfoNeedsSave(buffer);
103 * HeapTupleSetHintBits --- exported version of SetHintBits()
105 * This must be separate because of C99's brain-dead notions about how to
106 * implement inline functions.
108 void
109 HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
110 uint16 infomask, TransactionId xid)
112 SetHintBits(tuple, buffer, infomask, xid);
117 * HeapTupleSatisfiesSelf
118 * True iff heap tuple is valid "for itself".
120 * Here, we consider the effects of:
121 * all committed transactions (as of the current instant)
122 * previous commands of this transaction
123 * changes made by the current command
125 * Note:
126 * Assumes heap tuple is valid.
128 * The satisfaction of "itself" requires the following:
130 * ((Xmin == my-transaction && the row was updated by the current transaction, and
131 * (Xmax is null it was not deleted
132 * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
133 * ||
135 * (Xmin is committed && the row was modified by a committed transaction, and
136 * (Xmax is null || the row has not been deleted, or
137 * (Xmax != my-transaction && the row was deleted by another transaction
138 * Xmax is not committed))) that has not been committed
140 bool
141 HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
143 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
145 if (tuple->t_infomask & HEAP_XMIN_INVALID)
146 return false;
148 if (tuple->t_infomask & HEAP_MOVED_OFF)
150 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
152 if (TransactionIdIsCurrentTransactionId(xvac))
153 return false;
154 if (!TransactionIdIsInProgress(xvac))
156 if (TransactionIdDidCommit(xvac))
158 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
159 InvalidTransactionId);
160 return false;
162 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
163 InvalidTransactionId);
166 else if (tuple->t_infomask & HEAP_MOVED_IN)
168 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
170 if (!TransactionIdIsCurrentTransactionId(xvac))
172 if (TransactionIdIsInProgress(xvac))
173 return false;
174 if (TransactionIdDidCommit(xvac))
175 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
176 InvalidTransactionId);
177 else
179 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
180 InvalidTransactionId);
181 return false;
185 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
187 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
188 return true;
190 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
191 return true;
193 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
195 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
197 /* deleting subtransaction must have aborted */
198 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
199 InvalidTransactionId);
200 return true;
203 return false;
205 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
206 return false;
207 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
208 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
209 HeapTupleHeaderGetXmin(tuple));
210 else
212 /* it must have aborted or crashed */
213 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
214 InvalidTransactionId);
215 return false;
219 /* by here, the inserting transaction has committed */
221 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
222 return true;
224 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
226 if (tuple->t_infomask & HEAP_IS_LOCKED)
227 return true;
228 return false; /* updated by other */
231 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
233 /* MultiXacts are currently only allowed to lock tuples */
234 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
235 return true;
238 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
240 if (tuple->t_infomask & HEAP_IS_LOCKED)
241 return true;
242 return false;
245 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
246 return true;
248 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
250 /* it must have aborted or crashed */
251 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
252 InvalidTransactionId);
253 return true;
256 /* xmax transaction committed */
258 if (tuple->t_infomask & HEAP_IS_LOCKED)
260 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
261 InvalidTransactionId);
262 return true;
265 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
266 HeapTupleHeaderGetXmax(tuple));
267 return false;
271 * HeapTupleSatisfiesNow
272 * True iff heap tuple is valid "now".
274 * Here, we consider the effects of:
275 * all committed transactions (as of the current instant)
276 * previous commands of this transaction
278 * Note we do _not_ include changes made by the current command. This
279 * solves the "Halloween problem" wherein an UPDATE might try to re-update
280 * its own output tuples.
282 * Note:
283 * Assumes heap tuple is valid.
285 * The satisfaction of "now" requires the following:
287 * ((Xmin == my-transaction && inserted by the current transaction
288 * Cmin < my-command && before this command, and
289 * (Xmax is null || the row has not been deleted, or
290 * (Xmax == my-transaction && it was deleted by the current transaction
291 * Cmax >= my-command))) but not before this command,
292 * || or
293 * (Xmin is committed && the row was inserted by a committed transaction, and
294 * (Xmax is null || the row has not been deleted, or
295 * (Xmax == my-transaction && the row is being deleted by this transaction
296 * Cmax >= my-command) || but it's not deleted "yet", or
297 * (Xmax != my-transaction && the row was deleted by another transaction
298 * Xmax is not committed)))) that has not been committed
300 * mao says 17 march 1993: the tests in this routine are correct;
301 * if you think they're not, you're wrong, and you should think
302 * about it again. i know, it happened to me. we don't need to
303 * check commit time against the start time of this transaction
304 * because 2ph locking protects us from doing the wrong thing.
305 * if you mess around here, you'll break serializability. the only
306 * problem with this code is that it does the wrong thing for system
307 * catalog updates, because the catalogs aren't subject to 2ph, so
308 * the serializability guarantees we provide don't extend to xacts
309 * that do catalog accesses. this is unfortunate, but not critical.
311 bool
312 HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
314 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
316 if (tuple->t_infomask & HEAP_XMIN_INVALID)
317 return false;
319 if (tuple->t_infomask & HEAP_MOVED_OFF)
321 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
323 if (TransactionIdIsCurrentTransactionId(xvac))
324 return false;
325 if (!TransactionIdIsInProgress(xvac))
327 if (TransactionIdDidCommit(xvac))
329 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
330 InvalidTransactionId);
331 return false;
333 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
334 InvalidTransactionId);
337 else if (tuple->t_infomask & HEAP_MOVED_IN)
339 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
341 if (!TransactionIdIsCurrentTransactionId(xvac))
343 if (TransactionIdIsInProgress(xvac))
344 return false;
345 if (TransactionIdDidCommit(xvac))
346 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
347 InvalidTransactionId);
348 else
350 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
351 InvalidTransactionId);
352 return false;
356 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
358 if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId(false))
359 return false; /* inserted after scan started */
361 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
362 return true;
364 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
365 return true;
367 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
369 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
371 /* deleting subtransaction must have aborted */
372 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
373 InvalidTransactionId);
374 return true;
377 if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
378 return true; /* deleted after scan started */
379 else
380 return false; /* deleted before scan started */
382 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
383 return false;
384 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
385 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
386 HeapTupleHeaderGetXmin(tuple));
387 else
389 /* it must have aborted or crashed */
390 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
391 InvalidTransactionId);
392 return false;
396 /* by here, the inserting transaction has committed */
398 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
399 return true;
401 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
403 if (tuple->t_infomask & HEAP_IS_LOCKED)
404 return true;
405 return false;
408 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
410 /* MultiXacts are currently only allowed to lock tuples */
411 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
412 return true;
415 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
417 if (tuple->t_infomask & HEAP_IS_LOCKED)
418 return true;
419 if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
420 return true; /* deleted after scan started */
421 else
422 return false; /* deleted before scan started */
425 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
426 return true;
428 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
430 /* it must have aborted or crashed */
431 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
432 InvalidTransactionId);
433 return true;
436 /* xmax transaction committed */
438 if (tuple->t_infomask & HEAP_IS_LOCKED)
440 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
441 InvalidTransactionId);
442 return true;
445 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
446 HeapTupleHeaderGetXmax(tuple));
447 return false;
451 * HeapTupleSatisfiesAny
452 * Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
454 bool
455 HeapTupleSatisfiesAny(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
457 return true;
461 * HeapTupleSatisfiesToast
462 * True iff heap tuple is valid as a TOAST row.
464 * This is a simplified version that only checks for VACUUM moving conditions.
465 * It's appropriate for TOAST usage because TOAST really doesn't want to do
466 * its own time qual checks; if you can see the main table row that contains
467 * a TOAST reference, you should be able to see the TOASTed value. However,
468 * vacuuming a TOAST table is independent of the main table, and in case such
469 * a vacuum fails partway through, we'd better do this much checking.
471 * Among other things, this means you can't do UPDATEs of rows in a TOAST
472 * table.
474 bool
475 HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot,
476 Buffer buffer)
478 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
480 if (tuple->t_infomask & HEAP_XMIN_INVALID)
481 return false;
483 if (tuple->t_infomask & HEAP_MOVED_OFF)
485 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
487 if (TransactionIdIsCurrentTransactionId(xvac))
488 return false;
489 if (!TransactionIdIsInProgress(xvac))
491 if (TransactionIdDidCommit(xvac))
493 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
494 InvalidTransactionId);
495 return false;
497 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
498 InvalidTransactionId);
501 else if (tuple->t_infomask & HEAP_MOVED_IN)
503 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
505 if (!TransactionIdIsCurrentTransactionId(xvac))
507 if (TransactionIdIsInProgress(xvac))
508 return false;
509 if (TransactionIdDidCommit(xvac))
510 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
511 InvalidTransactionId);
512 else
514 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
515 InvalidTransactionId);
516 return false;
522 /* otherwise assume the tuple is valid for TOAST. */
523 return true;
527 * HeapTupleSatisfiesUpdate
529 * Same logic as HeapTupleSatisfiesNow, but returns a more detailed result
530 * code, since UPDATE needs to know more than "is it visible?". Also,
531 * tuples of my own xact are tested against the passed CommandId not
532 * CurrentCommandId.
534 * The possible return codes are:
536 * HeapTupleInvisible: the tuple didn't exist at all when the scan started,
537 * e.g. it was created by a later CommandId.
539 * HeapTupleMayBeUpdated: The tuple is valid and visible, so it may be
540 * updated.
542 * HeapTupleSelfUpdated: The tuple was updated by the current transaction,
543 * after the current scan started.
545 * HeapTupleUpdated: The tuple was updated by a committed transaction.
547 * HeapTupleBeingUpdated: The tuple is being updated by an in-progress
548 * transaction other than the current transaction. (Note: this includes
549 * the case where the tuple is share-locked by a MultiXact, even if the
550 * MultiXact includes the current transaction. Callers that want to
551 * distinguish that case must test for it themselves.)
553 HTSU_Result
554 HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
555 Buffer buffer)
557 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
559 if (tuple->t_infomask & HEAP_XMIN_INVALID)
560 return HeapTupleInvisible;
562 if (tuple->t_infomask & HEAP_MOVED_OFF)
564 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
566 if (TransactionIdIsCurrentTransactionId(xvac))
567 return HeapTupleInvisible;
568 if (!TransactionIdIsInProgress(xvac))
570 if (TransactionIdDidCommit(xvac))
572 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
573 InvalidTransactionId);
574 return HeapTupleInvisible;
576 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
577 InvalidTransactionId);
580 else if (tuple->t_infomask & HEAP_MOVED_IN)
582 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
584 if (!TransactionIdIsCurrentTransactionId(xvac))
586 if (TransactionIdIsInProgress(xvac))
587 return HeapTupleInvisible;
588 if (TransactionIdDidCommit(xvac))
589 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
590 InvalidTransactionId);
591 else
593 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
594 InvalidTransactionId);
595 return HeapTupleInvisible;
599 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
601 if (HeapTupleHeaderGetCmin(tuple) >= curcid)
602 return HeapTupleInvisible; /* inserted after scan started */
604 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
605 return HeapTupleMayBeUpdated;
607 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
608 return HeapTupleMayBeUpdated;
610 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
612 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
614 /* deleting subtransaction must have aborted */
615 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
616 InvalidTransactionId);
617 return HeapTupleMayBeUpdated;
620 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
621 return HeapTupleSelfUpdated; /* updated after scan started */
622 else
623 return HeapTupleInvisible; /* updated before scan started */
625 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
626 return HeapTupleInvisible;
627 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
628 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
629 HeapTupleHeaderGetXmin(tuple));
630 else
632 /* it must have aborted or crashed */
633 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
634 InvalidTransactionId);
635 return HeapTupleInvisible;
639 /* by here, the inserting transaction has committed */
641 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
642 return HeapTupleMayBeUpdated;
644 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
646 if (tuple->t_infomask & HEAP_IS_LOCKED)
647 return HeapTupleMayBeUpdated;
648 return HeapTupleUpdated; /* updated by other */
651 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
653 /* MultiXacts are currently only allowed to lock tuples */
654 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
656 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
657 return HeapTupleBeingUpdated;
658 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
659 InvalidTransactionId);
660 return HeapTupleMayBeUpdated;
663 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
665 if (tuple->t_infomask & HEAP_IS_LOCKED)
666 return HeapTupleMayBeUpdated;
667 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
668 return HeapTupleSelfUpdated; /* updated after scan started */
669 else
670 return HeapTupleInvisible; /* updated before scan started */
673 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
674 return HeapTupleBeingUpdated;
676 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
678 /* it must have aborted or crashed */
679 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
680 InvalidTransactionId);
681 return HeapTupleMayBeUpdated;
684 /* xmax transaction committed */
686 if (tuple->t_infomask & HEAP_IS_LOCKED)
688 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
689 InvalidTransactionId);
690 return HeapTupleMayBeUpdated;
693 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
694 HeapTupleHeaderGetXmax(tuple));
695 return HeapTupleUpdated; /* updated by other */
699 * HeapTupleSatisfiesDirty
700 * True iff heap tuple is valid including effects of open transactions.
702 * Here, we consider the effects of:
703 * all committed and in-progress transactions (as of the current instant)
704 * previous commands of this transaction
705 * changes made by the current command
707 * This is essentially like HeapTupleSatisfiesSelf as far as effects of
708 * the current transaction and committed/aborted xacts are concerned.
709 * However, we also include the effects of other xacts still in progress.
711 * A special hack is that the passed-in snapshot struct is used as an
712 * output argument to return the xids of concurrent xacts that affected the
713 * tuple. snapshot->xmin is set to the tuple's xmin if that is another
714 * transaction that's still in progress; or to InvalidTransactionId if the
715 * tuple's xmin is committed good, committed dead, or my own xact. Similarly
716 * for snapshot->xmax and the tuple's xmax.
718 bool
719 HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
720 Buffer buffer)
722 snapshot->xmin = snapshot->xmax = InvalidTransactionId;
724 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
726 if (tuple->t_infomask & HEAP_XMIN_INVALID)
727 return false;
729 if (tuple->t_infomask & HEAP_MOVED_OFF)
731 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
733 if (TransactionIdIsCurrentTransactionId(xvac))
734 return false;
735 if (!TransactionIdIsInProgress(xvac))
737 if (TransactionIdDidCommit(xvac))
739 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
740 InvalidTransactionId);
741 return false;
743 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
744 InvalidTransactionId);
747 else if (tuple->t_infomask & HEAP_MOVED_IN)
749 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
751 if (!TransactionIdIsCurrentTransactionId(xvac))
753 if (TransactionIdIsInProgress(xvac))
754 return false;
755 if (TransactionIdDidCommit(xvac))
756 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
757 InvalidTransactionId);
758 else
760 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
761 InvalidTransactionId);
762 return false;
766 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
768 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
769 return true;
771 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
772 return true;
774 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
776 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
778 /* deleting subtransaction must have aborted */
779 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
780 InvalidTransactionId);
781 return true;
784 return false;
786 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
788 snapshot->xmin = HeapTupleHeaderGetXmin(tuple);
789 /* XXX shouldn't we fall through to look at xmax? */
790 return true; /* in insertion by other */
792 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
793 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
794 HeapTupleHeaderGetXmin(tuple));
795 else
797 /* it must have aborted or crashed */
798 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
799 InvalidTransactionId);
800 return false;
804 /* by here, the inserting transaction has committed */
806 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
807 return true;
809 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
811 if (tuple->t_infomask & HEAP_IS_LOCKED)
812 return true;
813 return false; /* updated by other */
816 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
818 /* MultiXacts are currently only allowed to lock tuples */
819 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
820 return true;
823 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
825 if (tuple->t_infomask & HEAP_IS_LOCKED)
826 return true;
827 return false;
830 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
832 snapshot->xmax = HeapTupleHeaderGetXmax(tuple);
833 return true;
836 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
838 /* it must have aborted or crashed */
839 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
840 InvalidTransactionId);
841 return true;
844 /* xmax transaction committed */
846 if (tuple->t_infomask & HEAP_IS_LOCKED)
848 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
849 InvalidTransactionId);
850 return true;
853 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
854 HeapTupleHeaderGetXmax(tuple));
855 return false; /* updated by other */
859 * HeapTupleSatisfiesMVCC
860 * True iff heap tuple is valid for the given MVCC snapshot.
862 * Here, we consider the effects of:
863 * all transactions committed as of the time of the given snapshot
864 * previous commands of this transaction
866 * Does _not_ include:
867 * transactions shown as in-progress by the snapshot
868 * transactions started after the snapshot was taken
869 * changes made by the current command
871 * This is the same as HeapTupleSatisfiesNow, except that transactions that
872 * were in progress or as yet unstarted when the snapshot was taken will
873 * be treated as uncommitted, even if they have committed by now.
875 * (Notice, however, that the tuple status hint bits will be updated on the
876 * basis of the true state of the transaction, even if we then pretend we
877 * can't see it.)
879 bool
880 HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
881 Buffer buffer)
883 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
885 if (tuple->t_infomask & HEAP_XMIN_INVALID)
886 return false;
888 if (tuple->t_infomask & HEAP_MOVED_OFF)
890 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
892 if (TransactionIdIsCurrentTransactionId(xvac))
893 return false;
894 if (!TransactionIdIsInProgress(xvac))
896 if (TransactionIdDidCommit(xvac))
898 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
899 InvalidTransactionId);
900 return false;
902 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
903 InvalidTransactionId);
906 else if (tuple->t_infomask & HEAP_MOVED_IN)
908 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
910 if (!TransactionIdIsCurrentTransactionId(xvac))
912 if (TransactionIdIsInProgress(xvac))
913 return false;
914 if (TransactionIdDidCommit(xvac))
915 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
916 InvalidTransactionId);
917 else
919 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
920 InvalidTransactionId);
921 return false;
925 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
927 if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
928 return false; /* inserted after scan started */
930 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
931 return true;
933 if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */
934 return true;
936 Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
938 if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
940 /* deleting subtransaction must have aborted */
941 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
942 InvalidTransactionId);
943 return true;
946 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
947 return true; /* deleted after scan started */
948 else
949 return false; /* deleted before scan started */
951 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
952 return false;
953 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
954 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
955 HeapTupleHeaderGetXmin(tuple));
956 else
958 /* it must have aborted or crashed */
959 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
960 InvalidTransactionId);
961 return false;
966 * By here, the inserting transaction has committed - have to check
967 * when...
969 if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot))
970 return false; /* treat as still in progress */
972 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
973 return true;
975 if (tuple->t_infomask & HEAP_IS_LOCKED)
976 return true;
978 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
980 /* MultiXacts are currently only allowed to lock tuples */
981 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
982 return true;
985 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
987 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
989 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
990 return true; /* deleted after scan started */
991 else
992 return false; /* deleted before scan started */
995 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
996 return true;
998 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
1000 /* it must have aborted or crashed */
1001 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1002 InvalidTransactionId);
1003 return true;
1006 /* xmax transaction committed */
1007 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1008 HeapTupleHeaderGetXmax(tuple));
1012 * OK, the deleting transaction committed too ... but when?
1014 if (XidInMVCCSnapshot(HeapTupleHeaderGetXmax(tuple), snapshot))
1015 return true; /* treat as still in progress */
1017 return false;
1022 * HeapTupleSatisfiesVacuum
1024 * Determine the status of tuples for VACUUM purposes. Here, what
1025 * we mainly want to know is if a tuple is potentially visible to *any*
1026 * running transaction. If so, it can't be removed yet by VACUUM.
1028 * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples
1029 * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
1030 * still be visible to some open transaction, so we can't remove them,
1031 * even if we see that the deleting transaction has committed.
1033 HTSV_Result
1034 HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
1035 Buffer buffer)
1038 * Has inserting transaction committed?
1040 * If the inserting transaction aborted, then the tuple was never visible
1041 * to any other transaction, so we can delete it immediately.
1043 if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
1045 if (tuple->t_infomask & HEAP_XMIN_INVALID)
1046 return HEAPTUPLE_DEAD;
1047 else if (tuple->t_infomask & HEAP_MOVED_OFF)
1049 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1051 if (TransactionIdIsCurrentTransactionId(xvac))
1052 return HEAPTUPLE_DELETE_IN_PROGRESS;
1053 if (TransactionIdIsInProgress(xvac))
1054 return HEAPTUPLE_DELETE_IN_PROGRESS;
1055 if (TransactionIdDidCommit(xvac))
1057 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1058 InvalidTransactionId);
1059 return HEAPTUPLE_DEAD;
1061 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1062 InvalidTransactionId);
1064 else if (tuple->t_infomask & HEAP_MOVED_IN)
1066 TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1068 if (TransactionIdIsCurrentTransactionId(xvac))
1069 return HEAPTUPLE_INSERT_IN_PROGRESS;
1070 if (TransactionIdIsInProgress(xvac))
1071 return HEAPTUPLE_INSERT_IN_PROGRESS;
1072 if (TransactionIdDidCommit(xvac))
1073 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1074 InvalidTransactionId);
1075 else
1077 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1078 InvalidTransactionId);
1079 return HEAPTUPLE_DEAD;
1082 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
1084 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1085 return HEAPTUPLE_INSERT_IN_PROGRESS;
1086 if (tuple->t_infomask & HEAP_IS_LOCKED)
1087 return HEAPTUPLE_INSERT_IN_PROGRESS;
1088 /* inserted and then deleted by same xact */
1089 return HEAPTUPLE_DELETE_IN_PROGRESS;
1091 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
1092 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1093 HeapTupleHeaderGetXmin(tuple));
1094 else
1097 * Not in Progress, Not Committed, so either Aborted or crashed
1099 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1100 InvalidTransactionId);
1101 return HEAPTUPLE_DEAD;
1105 * At this point the xmin is known committed, but we might not have
1106 * been able to set the hint bit yet; so we can no longer Assert that
1107 * it's set.
1112 * Okay, the inserter committed, so it was good at some point. Now what
1113 * about the deleting transaction?
1115 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1116 return HEAPTUPLE_LIVE;
1118 if (tuple->t_infomask & HEAP_IS_LOCKED)
1121 * "Deleting" xact really only locked it, so the tuple is live in any
1122 * case. However, we should make sure that either XMAX_COMMITTED or
1123 * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1124 * examining the tuple for future xacts. Also, marking dead
1125 * MultiXacts as invalid here provides defense against MultiXactId
1126 * wraparound (see also comments in heap_freeze_tuple()).
1128 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1130 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1132 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
1133 return HEAPTUPLE_LIVE;
1135 else
1137 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1138 return HEAPTUPLE_LIVE;
1142 * We don't really care whether xmax did commit, abort or crash.
1143 * We know that xmax did lock the tuple, but it did not and will
1144 * never actually update it.
1146 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1147 InvalidTransactionId);
1149 return HEAPTUPLE_LIVE;
1152 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1154 /* MultiXacts are currently only allowed to lock tuples */
1155 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
1156 return HEAPTUPLE_LIVE;
1159 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1161 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1162 return HEAPTUPLE_DELETE_IN_PROGRESS;
1163 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
1164 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1165 HeapTupleHeaderGetXmax(tuple));
1166 else
1169 * Not in Progress, Not Committed, so either Aborted or crashed
1171 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1172 InvalidTransactionId);
1173 return HEAPTUPLE_LIVE;
1177 * At this point the xmax is known committed, but we might not have
1178 * been able to set the hint bit yet; so we can no longer Assert that
1179 * it's set.
1184 * Deleter committed, but check special cases.
1187 if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),
1188 HeapTupleHeaderGetXmax(tuple)))
1191 * Inserter also deleted it, so it was never visible to anyone else.
1192 * However, we can only remove it early if it's not an updated tuple;
1193 * else its parent tuple is linking to it via t_ctid, and this tuple
1194 * mustn't go away before the parent does.
1196 if (!(tuple->t_infomask & HEAP_UPDATED))
1197 return HEAPTUPLE_DEAD;
1200 if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin))
1202 /* deleting xact is too recent, tuple could still be visible */
1203 return HEAPTUPLE_RECENTLY_DEAD;
1206 /* Otherwise, it's dead and removable */
1207 return HEAPTUPLE_DEAD;
1212 * XidInMVCCSnapshot
1213 * Is the given XID still-in-progress according to the snapshot?
1215 * Note: GetSnapshotData never stores either top xid or subxids of our own
1216 * backend into a snapshot, so these xids will not be reported as "running"
1217 * by this function. This is OK for current uses, because we actually only
1218 * apply this for known-committed XIDs.
1220 static bool
1221 XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
1223 uint32 i;
1226 * Make a quick range check to eliminate most XIDs without looking at the
1227 * xip arrays. Note that this is OK even if we convert a subxact XID to
1228 * its parent below, because a subxact with XID < xmin has surely also got
1229 * a parent with XID < xmin, while one with XID >= xmax must belong to a
1230 * parent that was not yet committed at the time of this snapshot.
1233 /* Any xid < xmin is not in-progress */
1234 if (TransactionIdPrecedes(xid, snapshot->xmin))
1235 return false;
1236 /* Any xid >= xmax is in-progress */
1237 if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
1238 return true;
1241 * If the snapshot contains full subxact data, the fastest way to check
1242 * things is just to compare the given XID against both subxact XIDs and
1243 * top-level XIDs. If the snapshot overflowed, we have to use pg_subtrans
1244 * to convert a subxact XID to its parent XID, but then we need only look
1245 * at top-level XIDs not subxacts.
1247 if (snapshot->subxcnt >= 0)
1249 /* full data, so search subxip */
1250 int32 j;
1252 for (j = 0; j < snapshot->subxcnt; j++)
1254 if (TransactionIdEquals(xid, snapshot->subxip[j]))
1255 return true;
1258 /* not there, fall through to search xip[] */
1260 else
1262 /* overflowed, so convert xid to top-level */
1263 xid = SubTransGetTopmostTransaction(xid);
1266 * If xid was indeed a subxact, we might now have an xid < xmin, so
1267 * recheck to avoid an array scan. No point in rechecking xmax.
1269 if (TransactionIdPrecedes(xid, snapshot->xmin))
1270 return false;
1273 for (i = 0; i < snapshot->xcnt; i++)
1275 if (TransactionIdEquals(xid, snapshot->xip[i]))
1276 return true;
1279 return false;