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