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