tqual.c 39.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * tqual.c
4
 *	  POSTGRES "time qualification" code, ie, tuple visibility rules.
5
 *
6 7
 * NOTE: all the HeapTupleSatisfies routines will update the tuple's
 * "hint" status bits if we see that the inserting or deleting transaction
8 9 10 11
 * has now committed or aborted (and it is safe to set the hint bits).
 * If the hint bits are changed, SetBufferCommitInfoNeedsSave is called on
 * the passed-in buffer.  The caller must hold not only a pin, but at least
 * shared buffer content lock on the buffer containing the tuple.
12
 *
13 14 15 16 17 18 19 20 21 22
 * NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array)
 * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
 * pg_clog).  Otherwise we have a race condition: we might decide that a
 * just-committed transaction crashed, because none of the tests succeed.
 * xact.c is careful to record commit/abort in pg_clog before it unsets
 * MyProc->xid in PGPROC array.  That fixes that problem, but it also
 * means there is a window where TransactionIdIsInProgress and
 * TransactionIdDidCommit will both return true.  If we check only
 * TransactionIdDidCommit, we could consider a tuple committed when a
 * later GetSnapshotData call will still think the originating transaction
B
Bruce Momjian 已提交
23
 * is in progress, which leads to application-level inconsistency.	The
24 25 26 27 28
 * upshot is that we gotta check TransactionIdIsInProgress first in all
 * code paths, except for a few cases where we are looking at
 * subtransactions of our own main transaction and so there can't be any
 * race condition.
 *
29 30
 * Summary of visibility functions:
 *
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
 *	 HeapTupleSatisfiesMVCC()
 *		  visible to supplied snapshot, excludes current command
 *	 HeapTupleSatisfiesNow()
 *		  visible to instant snapshot, excludes current command
 *	 HeapTupleSatisfiesUpdate()
 *		  like HeapTupleSatisfiesNow(), but with user-supplied command
 *		  counter and more complex result
 *	 HeapTupleSatisfiesSelf()
 *		  visible to instant snapshot and current command
 *	 HeapTupleSatisfiesDirty()
 *		  like HeapTupleSatisfiesSelf(), but includes open transactions
 *	 HeapTupleSatisfiesVacuum()
 *		  visible to any running transaction, used by VACUUM
 *	 HeapTupleSatisfiesToast()
 *		  visible unless part of interrupted vacuum, used for TOAST
 *	 HeapTupleSatisfiesAny()
 *		  all tuples are visible
48
 *
49
 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
50
 * Portions Copyright (c) 1994, Regents of the University of California
51 52
 *
 * IDENTIFICATION
53
 *	  $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.116 2010/02/08 04:33:54 tgl Exp $
54 55 56 57 58 59
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

60
#include "access/multixact.h"
61
#include "access/subtrans.h"
62 63
#include "access/transam.h"
#include "access/xact.h"
B
Bruce Momjian 已提交
64
#include "storage/bufmgr.h"
65
#include "storage/procarray.h"
66 67
#include "utils/tqual.h"

68 69 70 71 72 73 74

/* Static variables representing various special snapshot semantics */
SnapshotData SnapshotNowData = {HeapTupleSatisfiesNow};
SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf};
SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny};
SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast};

75
/* local functions */
76
static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
77

78

79
/*
80
 * SetHintBits()
81 82 83
 *
 * Set commit/abort hint bits on a tuple, if appropriate at this time.
 *
84 85 86 87 88
 * It is only safe to set a transaction-committed hint bit if we know the
 * transaction's commit record has been flushed to disk.  We cannot change
 * the LSN of the page here because we may hold only a share lock on the
 * buffer, so we can't use the LSN to interlock this; we have to just refrain
 * from setting the hint bit until some future re-examination of the tuple.
89
 *
B
Bruce Momjian 已提交
90
 * We can always set hint bits when marking a transaction aborted.	(Some
91 92 93
 * code in heapam.c relies on that!)
 *
 * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
94 95 96 97 98 99
 * we can always set the hint bits, since old-style VACUUM FULL always used
 * synchronous commits and didn't move tuples that weren't previously
 * hinted.  (This is not known by this subroutine, but is applied by its
 * callers.)  Note: old-style VACUUM FULL is gone, but we have to keep this
 * module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
 * support in-place update from pre-9.0 databases.
100 101 102 103 104 105 106 107
 *
 * Normal commits may be asynchronous, so for those we need to get the LSN
 * of the transaction and then check whether this is flushed.
 *
 * The caller should pass xid as the XID of the transaction to check, or
 * InvalidTransactionId if no check is needed.
 */
static inline void
108 109
SetHintBits(HeapTupleHeader tuple, Buffer buffer,
			uint16 infomask, TransactionId xid)
110 111 112 113
{
	if (TransactionIdIsValid(xid))
	{
		/* NB: xid must be known committed here! */
B
Bruce Momjian 已提交
114
		XLogRecPtr	commitLSN = TransactionIdGetCommitLSN(xid);
115 116 117 118 119 120 121 122 123

		if (XLogNeedsFlush(commitLSN))
			return;				/* not flushed yet, so don't set hint */
	}

	tuple->t_infomask |= infomask;
	SetBufferCommitInfoNeedsSave(buffer);
}

124 125 126 127 128 129 130 131 132 133 134 135 136
/*
 * HeapTupleSetHintBits --- exported version of SetHintBits()
 *
 * This must be separate because of C99's brain-dead notions about how to
 * implement inline functions.
 */
void
HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
					 uint16 infomask, TransactionId xid)
{
	SetHintBits(tuple, buffer, infomask, xid);
}

137

138
/*
139
 * HeapTupleSatisfiesSelf
T
Tom Lane 已提交
140
 *		True iff heap tuple is valid "for itself".
141
 *
T
Tom Lane 已提交
142 143
 *	Here, we consider the effects of:
 *		all committed transactions (as of the current instant)
144 145
 *		previous commands of this transaction
 *		changes made by the current command
146 147
 *
 * Note:
148
 *		Assumes heap tuple is valid.
149
 *
150 151
 * The satisfaction of "itself" requires the following:
 *
152 153 154
 * ((Xmin == my-transaction &&				the row was updated by the current transaction, and
 *		(Xmax is null						it was not deleted
 *		 [|| Xmax != my-transaction)])			[or it was deleted by another transaction]
155 156
 * ||
 *
157 158 159 160
 * (Xmin is committed &&					the row was modified by a committed transaction, and
 *		(Xmax is null ||					the row has not been deleted, or
 *			(Xmax != my-transaction &&			the row was deleted by another transaction
 *			 Xmax is not committed)))			that has not been committed
161
 */
162
bool
163
HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
164
{
V
Vadim B. Mikheev 已提交
165
	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
166
	{
167
		if (tuple->t_infomask & HEAP_XMIN_INVALID)
168
			return false;
169

170 171
		if (tuple->t_infomask & HEAP_MOVED_OFF)
		{
172
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
173

174
			if (TransactionIdIsCurrentTransactionId(xvac))
175
				return false;
176
			if (!TransactionIdIsInProgress(xvac))
177
			{
178
				if (TransactionIdDidCommit(xvac))
179
				{
180 181
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
182 183
					return false;
				}
184 185
				SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
							InvalidTransactionId);
186 187 188 189
			}
		}
		else if (tuple->t_infomask & HEAP_MOVED_IN)
		{
190
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
191

192
			if (!TransactionIdIsCurrentTransactionId(xvac))
193
			{
194
				if (TransactionIdIsInProgress(xvac))
195
					return false;
196
				if (TransactionIdDidCommit(xvac))
197 198
					SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
								InvalidTransactionId);
199 200
				else
				{
201 202
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
203 204
					return false;
				}
205 206
			}
		}
207
		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
208
		{
V
Vadim B. Mikheev 已提交
209
			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
210
				return true;
211

212 213 214 215 216
			if (tuple->t_infomask & HEAP_IS_LOCKED)		/* not deleter */
				return true;

			Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));

217
			if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
218
			{
219
				/* deleting subtransaction must have aborted */
220 221
				SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
							InvalidTransactionId);
222
				return true;
223
			}
224

V
Vadim B. Mikheev 已提交
225
			return false;
226
		}
227
		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
228
			return false;
229
		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
230 231
			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
						HeapTupleHeaderGetXmin(tuple));
232
		else
233
		{
234
			/* it must have aborted or crashed */
235 236
			SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
						InvalidTransactionId);
237
			return false;
238
		}
239
	}
240 241

	/* by here, the inserting transaction has committed */
242

V
Vadim B. Mikheev 已提交
243
	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
244
		return true;
245

V
Vadim B. Mikheev 已提交
246
	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
V
Vadim B. Mikheev 已提交
247
	{
248
		if (tuple->t_infomask & HEAP_IS_LOCKED)
V
Vadim B. Mikheev 已提交
249
			return true;
B
Bruce Momjian 已提交
250
		return false;			/* updated by other */
V
Vadim B. Mikheev 已提交
251
	}
V
Vadim B. Mikheev 已提交
252

253 254 255 256 257 258 259
	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
	{
		/* MultiXacts are currently only allowed to lock tuples */
		Assert(tuple->t_infomask & HEAP_IS_LOCKED);
		return true;
	}

260
	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
V
Vadim B. Mikheev 已提交
261
	{
262
		if (tuple->t_infomask & HEAP_IS_LOCKED)
V
Vadim B. Mikheev 已提交
263
			return true;
264
		return false;
V
Vadim B. Mikheev 已提交
265
	}
266

267 268 269
	if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
		return true;

270
	if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
271
	{
272
		/* it must have aborted or crashed */
273 274
		SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
					InvalidTransactionId);
275
		return true;
276 277
	}

278
	/* xmax transaction committed */
279

280
	if (tuple->t_infomask & HEAP_IS_LOCKED)
281
	{
282 283
		SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
					InvalidTransactionId);
V
Vadim B. Mikheev 已提交
284
		return true;
285
	}
V
Vadim B. Mikheev 已提交
286

287 288
	SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
				HeapTupleHeaderGetXmax(tuple));
289
	return false;
290 291 292
}

/*
B
Bruce Momjian 已提交
293
 * HeapTupleSatisfiesNow
T
Tom Lane 已提交
294
 *		True iff heap tuple is valid "now".
295
 *
T
Tom Lane 已提交
296 297
 *	Here, we consider the effects of:
 *		all committed transactions (as of the current instant)
298 299
 *		previous commands of this transaction
 *
T
Tom Lane 已提交
300 301
 * Note we do _not_ include changes made by the current command.  This
 * solves the "Halloween problem" wherein an UPDATE might try to re-update
302
 * its own output tuples, http://en.wikipedia.org/wiki/Halloween_Problem.
303 304
 *
 * Note:
305
 *		Assumes heap tuple is valid.
306
 *
307 308
 * The satisfaction of "now" requires the following:
 *
309 310 311 312 313
 * ((Xmin == my-transaction &&				inserted by the current transaction
 *	 Cmin < my-command &&					before this command, and
 *	 (Xmax is null ||						the row has not been deleted, or
 *	  (Xmax == my-transaction &&			it was deleted by the current transaction
 *	   Cmax >= my-command)))				but not before this command,
314
 * ||										or
315
 *	(Xmin is committed &&					the row was inserted by a committed transaction, and
316
 *		(Xmax is null ||					the row has not been deleted, or
317 318 319 320
 *		 (Xmax == my-transaction &&			the row is being deleted by this transaction
 *		  Cmax >= my-command) ||			but it's not deleted "yet", or
 *		 (Xmax != my-transaction &&			the row was deleted by another transaction
 *		  Xmax is not committed))))			that has not been committed
321
 *
322 323 324 325 326 327 328 329 330 331
 *		mao says 17 march 1993:  the tests in this routine are correct;
 *		if you think they're not, you're wrong, and you should think
 *		about it again.  i know, it happened to me.  we don't need to
 *		check commit time against the start time of this transaction
 *		because 2ph locking protects us from doing the wrong thing.
 *		if you mess around here, you'll break serializability.  the only
 *		problem with this code is that it does the wrong thing for system
 *		catalog updates, because the catalogs aren't subject to 2ph, so
 *		the serializability guarantees we provide don't extend to xacts
 *		that do catalog accesses.  this is unfortunate, but not critical.
332
 */
333
bool
334
HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
335
{
V
Vadim B. Mikheev 已提交
336
	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
337
	{
338
		if (tuple->t_infomask & HEAP_XMIN_INVALID)
339
			return false;
340

341 342
		if (tuple->t_infomask & HEAP_MOVED_OFF)
		{
343
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
344

345
			if (TransactionIdIsCurrentTransactionId(xvac))
346
				return false;
347
			if (!TransactionIdIsInProgress(xvac))
348
			{
349
				if (TransactionIdDidCommit(xvac))
350
				{
351 352
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
353 354
					return false;
				}
355 356
				SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
							InvalidTransactionId);
357 358 359 360
			}
		}
		else if (tuple->t_infomask & HEAP_MOVED_IN)
		{
361
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
362

363
			if (!TransactionIdIsCurrentTransactionId(xvac))
364
			{
365
				if (TransactionIdIsInProgress(xvac))
366
					return false;
367
				if (TransactionIdDidCommit(xvac))
368 369
					SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
								InvalidTransactionId);
370 371
				else
				{
372 373
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
374 375
					return false;
				}
376 377
			}
		}
378
		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
379
		{
380
			if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId(false))
381
				return false;	/* inserted after scan started */
382

V
Vadim B. Mikheev 已提交
383
			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
384
				return true;
385

386 387 388 389 390
			if (tuple->t_infomask & HEAP_IS_LOCKED)		/* not deleter */
				return true;

			Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));

391
			if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
392
			{
393
				/* deleting subtransaction must have aborted */
394 395
				SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
							InvalidTransactionId);
396
				return true;
397
			}
398

399
			if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
400
				return true;	/* deleted after scan started */
V
Vadim B. Mikheev 已提交
401
			else
402
				return false;	/* deleted before scan started */
403
		}
404
		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
405
			return false;
406
		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
407 408
			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
						HeapTupleHeaderGetXmin(tuple));
409
		else
410
		{
411
			/* it must have aborted or crashed */
412 413
			SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
						InvalidTransactionId);
414
			return false;
415
		}
416
	}
417

418
	/* by here, the inserting transaction has committed */
419

V
Vadim B. Mikheev 已提交
420
	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
421
		return true;
422

V
Vadim B. Mikheev 已提交
423
	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
V
Vadim B. Mikheev 已提交
424
	{
425
		if (tuple->t_infomask & HEAP_IS_LOCKED)
V
Vadim B. Mikheev 已提交
426
			return true;
427
		return false;
V
Vadim B. Mikheev 已提交
428
	}
429

430 431 432 433 434 435 436
	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
	{
		/* MultiXacts are currently only allowed to lock tuples */
		Assert(tuple->t_infomask & HEAP_IS_LOCKED);
		return true;
	}

437
	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
438
	{
439
		if (tuple->t_infomask & HEAP_IS_LOCKED)
V
Vadim B. Mikheev 已提交
440
			return true;
441
		if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false))
442
			return true;		/* deleted after scan started */
V
Vadim B. Mikheev 已提交
443
		else
444
			return false;		/* deleted before scan started */
445 446
	}

447 448 449
	if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
		return true;

450
	if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
451
	{
452
		/* it must have aborted or crashed */
453 454
		SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
					InvalidTransactionId);
455
		return true;
456 457
	}

V
Vadim B. Mikheev 已提交
458
	/* xmax transaction committed */
459

460
	if (tuple->t_infomask & HEAP_IS_LOCKED)
461
	{
462 463
		SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
					InvalidTransactionId);
V
Vadim B. Mikheev 已提交
464
		return true;
465
	}
V
Vadim B. Mikheev 已提交
466

467 468
	SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
				HeapTupleHeaderGetXmax(tuple));
469
	return false;
470
}
V
Vadim B. Mikheev 已提交
471

472 473 474 475 476 477 478 479 480 481
/*
 * HeapTupleSatisfiesAny
 *		Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
 */
bool
HeapTupleSatisfiesAny(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
{
	return true;
}

482 483
/*
 * HeapTupleSatisfiesToast
T
Tom Lane 已提交
484
 *		True iff heap tuple is valid as a TOAST row.
485 486 487
 *
 * This is a simplified version that only checks for VACUUM moving conditions.
 * It's appropriate for TOAST usage because TOAST really doesn't want to do
488
 * its own time qual checks; if you can see the main table row that contains
B
Bruce Momjian 已提交
489
 * a TOAST reference, you should be able to see the TOASTed value.	However,
490 491 492 493 494 495 496
 * vacuuming a TOAST table is independent of the main table, and in case such
 * a vacuum fails partway through, we'd better do this much checking.
 *
 * Among other things, this means you can't do UPDATEs of rows in a TOAST
 * table.
 */
bool
497 498
HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot,
						Buffer buffer)
499 500 501 502 503 504 505 506
{
	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
	{
		if (tuple->t_infomask & HEAP_XMIN_INVALID)
			return false;

		if (tuple->t_infomask & HEAP_MOVED_OFF)
		{
507
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
508

509
			if (TransactionIdIsCurrentTransactionId(xvac))
510
				return false;
511
			if (!TransactionIdIsInProgress(xvac))
512
			{
513
				if (TransactionIdDidCommit(xvac))
514
				{
515 516
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
517 518
					return false;
				}
519 520
				SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
							InvalidTransactionId);
521 522 523 524
			}
		}
		else if (tuple->t_infomask & HEAP_MOVED_IN)
		{
525
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
526

527
			if (!TransactionIdIsCurrentTransactionId(xvac))
528
			{
529
				if (TransactionIdIsInProgress(xvac))
530
					return false;
531
				if (TransactionIdDidCommit(xvac))
532 533
					SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
								InvalidTransactionId);
534 535
				else
				{
536 537
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
538 539 540 541 542 543 544 545 546 547 548 549 550
					return false;
				}
			}
		}
	}

	/* otherwise assume the tuple is valid for TOAST. */
	return true;
}

/*
 * HeapTupleSatisfiesUpdate
 *
T
Tom Lane 已提交
551
 *	Same logic as HeapTupleSatisfiesNow, but returns a more detailed result
552 553 554
 *	code, since UPDATE needs to know more than "is it visible?".  Also,
 *	tuples of my own xact are tested against the passed CommandId not
 *	CurrentCommandId.
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
 *
 *	The possible return codes are:
 *
 *	HeapTupleInvisible: the tuple didn't exist at all when the scan started,
 *	e.g. it was created by a later CommandId.
 *
 *	HeapTupleMayBeUpdated: The tuple is valid and visible, so it may be
 *	updated.
 *
 *	HeapTupleSelfUpdated: The tuple was updated by the current transaction,
 *	after the current scan started.
 *
 *	HeapTupleUpdated: The tuple was updated by a committed transaction.
 *
 *	HeapTupleBeingUpdated: The tuple is being updated by an in-progress
570 571 572 573
 *	transaction other than the current transaction.  (Note: this includes
 *	the case where the tuple is share-locked by a MultiXact, even if the
 *	MultiXact includes the current transaction.  Callers that want to
 *	distinguish that case must test for it themselves.)
574
 */
575
HTSU_Result
576 577
HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
						 Buffer buffer)
V
Vadim B. Mikheev 已提交
578
{
579
	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
V
Vadim B. Mikheev 已提交
580
	{
581
		if (tuple->t_infomask & HEAP_XMIN_INVALID)
V
Vadim B. Mikheev 已提交
582 583
			return HeapTupleInvisible;

584
		if (tuple->t_infomask & HEAP_MOVED_OFF)
585
		{
586
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
587

588
			if (TransactionIdIsCurrentTransactionId(xvac))
589
				return HeapTupleInvisible;
590
			if (!TransactionIdIsInProgress(xvac))
591
			{
592
				if (TransactionIdDidCommit(xvac))
593
				{
594 595
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
596 597
					return HeapTupleInvisible;
				}
598 599
				SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
							InvalidTransactionId);
600 601
			}
		}
602
		else if (tuple->t_infomask & HEAP_MOVED_IN)
603
		{
604
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
605

606
			if (!TransactionIdIsCurrentTransactionId(xvac))
607
			{
608
				if (TransactionIdIsInProgress(xvac))
609
					return HeapTupleInvisible;
610
				if (TransactionIdDidCommit(xvac))
611 612
					SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
								InvalidTransactionId);
613 614
				else
				{
615 616
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
617 618
					return HeapTupleInvisible;
				}
619 620
			}
		}
621
		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
V
Vadim B. Mikheev 已提交
622
		{
623
			if (HeapTupleHeaderGetCmin(tuple) >= curcid)
B
Bruce Momjian 已提交
624
				return HeapTupleInvisible;		/* inserted after scan started */
V
Vadim B. Mikheev 已提交
625

B
Bruce Momjian 已提交
626
			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
V
Vadim B. Mikheev 已提交
627 628
				return HeapTupleMayBeUpdated;

629 630 631 632 633
			if (tuple->t_infomask & HEAP_IS_LOCKED)		/* not deleter */
				return HeapTupleMayBeUpdated;

			Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));

634
			if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
635
			{
636
				/* deleting subtransaction must have aborted */
637 638
				SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
							InvalidTransactionId);
639
				return HeapTupleMayBeUpdated;
640
			}
641

642
			if (HeapTupleHeaderGetCmax(tuple) >= curcid)
B
Bruce Momjian 已提交
643
				return HeapTupleSelfUpdated;	/* updated after scan started */
V
Vadim B. Mikheev 已提交
644
			else
B
Bruce Momjian 已提交
645
				return HeapTupleInvisible;		/* updated before scan started */
V
Vadim B. Mikheev 已提交
646
		}
647
		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
V
Vadim B. Mikheev 已提交
648
			return HeapTupleInvisible;
649
		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
650 651
			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
						HeapTupleHeaderGetXmin(tuple));
652
		else
653
		{
654
			/* it must have aborted or crashed */
655 656
			SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
						InvalidTransactionId);
657
			return HeapTupleInvisible;
658
		}
V
Vadim B. Mikheev 已提交
659 660 661 662
	}

	/* by here, the inserting transaction has committed */

B
Bruce Momjian 已提交
663
	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
V
Vadim B. Mikheev 已提交
664 665
		return HeapTupleMayBeUpdated;

666
	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
V
Vadim B. Mikheev 已提交
667
	{
668
		if (tuple->t_infomask & HEAP_IS_LOCKED)
V
Vadim B. Mikheev 已提交
669
			return HeapTupleMayBeUpdated;
670
		return HeapTupleUpdated;	/* updated by other */
V
Vadim B. Mikheev 已提交
671 672
	}

673 674 675 676 677 678 679
	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
	{
		/* MultiXacts are currently only allowed to lock tuples */
		Assert(tuple->t_infomask & HEAP_IS_LOCKED);

		if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
			return HeapTupleBeingUpdated;
680 681
		SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
					InvalidTransactionId);
682 683 684
		return HeapTupleMayBeUpdated;
	}

685
	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
V
Vadim B. Mikheev 已提交
686
	{
687
		if (tuple->t_infomask & HEAP_IS_LOCKED)
V
Vadim B. Mikheev 已提交
688
			return HeapTupleMayBeUpdated;
689
		if (HeapTupleHeaderGetCmax(tuple) >= curcid)
B
Bruce Momjian 已提交
690
			return HeapTupleSelfUpdated;		/* updated after scan started */
V
Vadim B. Mikheev 已提交
691 692 693 694
		else
			return HeapTupleInvisible;	/* updated before scan started */
	}

695 696 697
	if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
		return HeapTupleBeingUpdated;

698
	if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
V
Vadim B. Mikheev 已提交
699
	{
700
		/* it must have aborted or crashed */
701 702
		SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
					InvalidTransactionId);
703
		return HeapTupleMayBeUpdated;
V
Vadim B. Mikheev 已提交
704 705 706 707
	}

	/* xmax transaction committed */

708
	if (tuple->t_infomask & HEAP_IS_LOCKED)
709
	{
710 711
		SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
					InvalidTransactionId);
V
Vadim B. Mikheev 已提交
712
		return HeapTupleMayBeUpdated;
713
	}
V
Vadim B. Mikheev 已提交
714

715 716
	SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
				HeapTupleHeaderGetXmax(tuple));
B
Bruce Momjian 已提交
717
	return HeapTupleUpdated;	/* updated by other */
V
Vadim B. Mikheev 已提交
718 719
}

T
Tom Lane 已提交
720 721 722
/*
 * HeapTupleSatisfiesDirty
 *		True iff heap tuple is valid including effects of open transactions.
723
 *
T
Tom Lane 已提交
724 725
 *	Here, we consider the effects of:
 *		all committed and in-progress transactions (as of the current instant)
726
 *		previous commands of this transaction
T
Tom Lane 已提交
727
 *		changes made by the current command
728
 *
729
 * This is essentially like HeapTupleSatisfiesSelf as far as effects of
730 731 732
 * the current transaction and committed/aborted xacts are concerned.
 * However, we also include the effects of other xacts still in progress.
 *
733 734 735 736 737 738
 * A special hack is that the passed-in snapshot struct is used as an
 * output argument to return the xids of concurrent xacts that affected the
 * tuple.  snapshot->xmin is set to the tuple's xmin if that is another
 * transaction that's still in progress; or to InvalidTransactionId if the
 * tuple's xmin is committed good, committed dead, or my own xact.  Similarly
 * for snapshot->xmax and the tuple's xmax.
739
 */
V
Vadim B. Mikheev 已提交
740
bool
741 742
HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
						Buffer buffer)
V
Vadim B. Mikheev 已提交
743
{
744
	snapshot->xmin = snapshot->xmax = InvalidTransactionId;
V
Vadim B. Mikheev 已提交
745 746 747

	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
	{
748
		if (tuple->t_infomask & HEAP_XMIN_INVALID)
V
Vadim B. Mikheev 已提交
749 750
			return false;

751 752
		if (tuple->t_infomask & HEAP_MOVED_OFF)
		{
753
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
754

755
			if (TransactionIdIsCurrentTransactionId(xvac))
756
				return false;
757
			if (!TransactionIdIsInProgress(xvac))
758
			{
759
				if (TransactionIdDidCommit(xvac))
760
				{
761 762
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
763 764
					return false;
				}
765 766
				SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
							InvalidTransactionId);
767 768 769 770
			}
		}
		else if (tuple->t_infomask & HEAP_MOVED_IN)
		{
771
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
772

773
			if (!TransactionIdIsCurrentTransactionId(xvac))
774
			{
775
				if (TransactionIdIsInProgress(xvac))
776
					return false;
777
				if (TransactionIdDidCommit(xvac))
778 779
					SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
								InvalidTransactionId);
780 781
				else
				{
782 783
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
784 785
					return false;
				}
786 787
			}
		}
788
		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
V
Vadim B. Mikheev 已提交
789 790 791 792
		{
			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
				return true;

793 794 795 796 797
			if (tuple->t_infomask & HEAP_IS_LOCKED)		/* not deleter */
				return true;

			Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));

798
			if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
799
			{
800
				/* deleting subtransaction must have aborted */
801 802
				SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
							InvalidTransactionId);
803
				return true;
804
			}
805

V
Vadim B. Mikheev 已提交
806 807
			return false;
		}
808
		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
V
Vadim B. Mikheev 已提交
809
		{
810
			snapshot->xmin = HeapTupleHeaderGetXmin(tuple);
811
			/* XXX shouldn't we fall through to look at xmax? */
B
Bruce Momjian 已提交
812
			return true;		/* in insertion by other */
V
Vadim B. Mikheev 已提交
813
		}
814
		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
815 816
			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
						HeapTupleHeaderGetXmin(tuple));
817 818 819
		else
		{
			/* it must have aborted or crashed */
820 821
			SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
						InvalidTransactionId);
822 823
			return false;
		}
V
Vadim B. Mikheev 已提交
824 825 826 827 828 829 830 831 832
	}

	/* by here, the inserting transaction has committed */

	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
		return true;

	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
	{
833
		if (tuple->t_infomask & HEAP_IS_LOCKED)
V
Vadim B. Mikheev 已提交
834
			return true;
B
Bruce Momjian 已提交
835
		return false;			/* updated by other */
V
Vadim B. Mikheev 已提交
836 837
	}

838 839 840 841 842 843 844
	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
	{
		/* MultiXacts are currently only allowed to lock tuples */
		Assert(tuple->t_infomask & HEAP_IS_LOCKED);
		return true;
	}

845
	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
846
	{
847
		if (tuple->t_infomask & HEAP_IS_LOCKED)
848
			return true;
V
Vadim B. Mikheev 已提交
849
		return false;
850
	}
V
Vadim B. Mikheev 已提交
851

852
	if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
V
Vadim B. Mikheev 已提交
853
	{
854
		snapshot->xmax = HeapTupleHeaderGetXmax(tuple);
855 856 857 858 859 860
		return true;
	}

	if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
	{
		/* it must have aborted or crashed */
861 862
		SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
					InvalidTransactionId);
863
		return true;
V
Vadim B. Mikheev 已提交
864 865 866 867
	}

	/* xmax transaction committed */

868
	if (tuple->t_infomask & HEAP_IS_LOCKED)
869
	{
870 871
		SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
					InvalidTransactionId);
V
Vadim B. Mikheev 已提交
872
		return true;
873
	}
V
Vadim B. Mikheev 已提交
874

875 876
	SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
				HeapTupleHeaderGetXmax(tuple));
B
Bruce Momjian 已提交
877
	return false;				/* updated by other */
V
Vadim B. Mikheev 已提交
878
}
V
Vadim B. Mikheev 已提交
879

880
/*
881 882
 * HeapTupleSatisfiesMVCC
 *		True iff heap tuple is valid for the given MVCC snapshot.
883
 *
T
Tom Lane 已提交
884 885
 *	Here, we consider the effects of:
 *		all transactions committed as of the time of the given snapshot
886 887 888
 *		previous commands of this transaction
 *
 *	Does _not_ include:
T
Tom Lane 已提交
889 890
 *		transactions shown as in-progress by the snapshot
 *		transactions started after the snapshot was taken
891
 *		changes made by the current command
892 893 894
 *
 * This is the same as HeapTupleSatisfiesNow, except that transactions that
 * were in progress or as yet unstarted when the snapshot was taken will
895
 * be treated as uncommitted, even if they have committed by now.
896 897 898 899 900
 *
 * (Notice, however, that the tuple status hint bits will be updated on the
 * basis of the true state of the transaction, even if we then pretend we
 * can't see it.)
 */
V
Vadim B. Mikheev 已提交
901
bool
902 903
HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
					   Buffer buffer)
V
Vadim B. Mikheev 已提交
904 905 906
{
	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
	{
907
		if (tuple->t_infomask & HEAP_XMIN_INVALID)
V
Vadim B. Mikheev 已提交
908 909
			return false;

910 911
		if (tuple->t_infomask & HEAP_MOVED_OFF)
		{
912
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
913

914
			if (TransactionIdIsCurrentTransactionId(xvac))
915
				return false;
916
			if (!TransactionIdIsInProgress(xvac))
917
			{
918
				if (TransactionIdDidCommit(xvac))
919
				{
920 921
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
922 923
					return false;
				}
924 925
				SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
							InvalidTransactionId);
926 927 928 929
			}
		}
		else if (tuple->t_infomask & HEAP_MOVED_IN)
		{
930
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
931

932
			if (!TransactionIdIsCurrentTransactionId(xvac))
933
			{
934
				if (TransactionIdIsInProgress(xvac))
935
					return false;
936
				if (TransactionIdDidCommit(xvac))
937 938
					SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
								InvalidTransactionId);
939 940
				else
				{
941 942
					SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
								InvalidTransactionId);
943 944
					return false;
				}
945 946
			}
		}
947
		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
V
Vadim B. Mikheev 已提交
948
		{
949
			if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
V
Vadim B. Mikheev 已提交
950 951 952 953 954
				return false;	/* inserted after scan started */

			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
				return true;

955 956 957 958 959
			if (tuple->t_infomask & HEAP_IS_LOCKED)		/* not deleter */
				return true;

			Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));

960
			if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
961
			{
962
				/* deleting subtransaction must have aborted */
963 964
				SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
							InvalidTransactionId);
965
				return true;
966
			}
967

968
			if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
V
Vadim B. Mikheev 已提交
969 970 971 972
				return true;	/* deleted after scan started */
			else
				return false;	/* deleted before scan started */
		}
973
		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
V
Vadim B. Mikheev 已提交
974
			return false;
975
		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
976 977
			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
						HeapTupleHeaderGetXmin(tuple));
978
		else
979
		{
980
			/* it must have aborted or crashed */
981 982
			SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
						InvalidTransactionId);
983
			return false;
984
		}
V
Vadim B. Mikheev 已提交
985 986
	}

B
Bruce Momjian 已提交
987 988 989
	/*
	 * By here, the inserting transaction has committed - have to check
	 * when...
V
Vadim B. Mikheev 已提交
990
	 */
991
	if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot))
992
		return false;			/* treat as still in progress */
V
Vadim B. Mikheev 已提交
993 994 995 996

	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
		return true;

997 998 999 1000 1001 1002 1003
	if (tuple->t_infomask & HEAP_IS_LOCKED)
		return true;

	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
	{
		/* MultiXacts are currently only allowed to lock tuples */
		Assert(tuple->t_infomask & HEAP_IS_LOCKED);
V
Vadim B. Mikheev 已提交
1004
		return true;
1005
	}
V
Vadim B. Mikheev 已提交
1006 1007 1008

	if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
	{
1009
		if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
V
Vadim B. Mikheev 已提交
1010
		{
1011
			if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
B
Bruce Momjian 已提交
1012
				return true;	/* deleted after scan started */
V
Vadim B. Mikheev 已提交
1013
			else
B
Bruce Momjian 已提交
1014
				return false;	/* deleted before scan started */
V
Vadim B. Mikheev 已提交
1015 1016
		}

1017 1018 1019
		if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
			return true;

1020
		if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
V
Vadim B. Mikheev 已提交
1021
		{
1022
			/* it must have aborted or crashed */
1023 1024
			SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
						InvalidTransactionId);
V
Vadim B. Mikheev 已提交
1025 1026 1027 1028
			return true;
		}

		/* xmax transaction committed */
1029 1030
		SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
					HeapTupleHeaderGetXmax(tuple));
V
Vadim B. Mikheev 已提交
1031 1032
	}

1033 1034 1035
	/*
	 * OK, the deleting transaction committed too ... but when?
	 */
1036
	if (XidInMVCCSnapshot(HeapTupleHeaderGetXmax(tuple), snapshot))
1037
		return true;			/* treat as still in progress */
B
Bruce Momjian 已提交
1038

V
Vadim B. Mikheev 已提交
1039 1040 1041
	return false;
}

1042 1043

/*
1044 1045
 * HeapTupleSatisfiesVacuum
 *
T
Tom Lane 已提交
1046 1047 1048
 *	Determine the status of tuples for VACUUM purposes.  Here, what
 *	we mainly want to know is if a tuple is potentially visible to *any*
 *	running transaction.  If so, it can't be removed yet by VACUUM.
1049
 *
1050
 * OldestXmin is a cutoff XID (obtained from GetOldestXmin()).	Tuples
1051
 * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
1052 1053 1054 1055
 * still be visible to some open transaction, so we can't remove them,
 * even if we see that the deleting transaction has committed.
 */
HTSV_Result
1056 1057
HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
						 Buffer buffer)
1058 1059 1060 1061
{
	/*
	 * Has inserting transaction committed?
	 *
1062 1063
	 * If the inserting transaction aborted, then the tuple was never visible
	 * to any other transaction, so we can delete it immediately.
1064 1065 1066 1067 1068 1069 1070
	 */
	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
	{
		if (tuple->t_infomask & HEAP_XMIN_INVALID)
			return HEAPTUPLE_DEAD;
		else if (tuple->t_infomask & HEAP_MOVED_OFF)
		{
1071
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
1072

1073
			if (TransactionIdIsCurrentTransactionId(xvac))
1074
				return HEAPTUPLE_DELETE_IN_PROGRESS;
1075
			if (TransactionIdIsInProgress(xvac))
1076
				return HEAPTUPLE_DELETE_IN_PROGRESS;
1077
			if (TransactionIdDidCommit(xvac))
1078
			{
1079 1080
				SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
							InvalidTransactionId);
1081 1082
				return HEAPTUPLE_DEAD;
			}
1083 1084
			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
						InvalidTransactionId);
1085 1086 1087
		}
		else if (tuple->t_infomask & HEAP_MOVED_IN)
		{
1088
			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
B
Bruce Momjian 已提交
1089

1090
			if (TransactionIdIsCurrentTransactionId(xvac))
1091
				return HEAPTUPLE_INSERT_IN_PROGRESS;
1092
			if (TransactionIdIsInProgress(xvac))
1093
				return HEAPTUPLE_INSERT_IN_PROGRESS;
1094
			if (TransactionIdDidCommit(xvac))
1095 1096
				SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
							InvalidTransactionId);
1097
			else
1098
			{
1099 1100
				SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
							InvalidTransactionId);
1101 1102 1103
				return HEAPTUPLE_DEAD;
			}
		}
1104
		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
1105 1106 1107
		{
			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
				return HEAPTUPLE_INSERT_IN_PROGRESS;
1108
			if (tuple->t_infomask & HEAP_IS_LOCKED)
1109 1110 1111 1112
				return HEAPTUPLE_INSERT_IN_PROGRESS;
			/* inserted and then deleted by same xact */
			return HEAPTUPLE_DELETE_IN_PROGRESS;
		}
1113
		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
1114 1115
			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
						HeapTupleHeaderGetXmin(tuple));
1116 1117 1118
		else
		{
			/*
B
Bruce Momjian 已提交
1119
			 * Not in Progress, Not Committed, so either Aborted or crashed
1120
			 */
1121 1122
			SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
						InvalidTransactionId);
1123 1124
			return HEAPTUPLE_DEAD;
		}
B
Bruce Momjian 已提交
1125

1126 1127
		/*
		 * At this point the xmin is known committed, but we might not have
B
Bruce Momjian 已提交
1128 1129
		 * been able to set the hint bit yet; so we can no longer Assert that
		 * it's set.
1130
		 */
1131 1132 1133
	}

	/*
B
Bruce Momjian 已提交
1134 1135
	 * Okay, the inserter committed, so it was good at some point.	Now what
	 * about the deleting transaction?
1136 1137 1138 1139
	 */
	if (tuple->t_infomask & HEAP_XMAX_INVALID)
		return HEAPTUPLE_LIVE;

1140
	if (tuple->t_infomask & HEAP_IS_LOCKED)
1141
	{
1142
		/*
B
Bruce Momjian 已提交
1143
		 * "Deleting" xact really only locked it, so the tuple is live in any
1144
		 * case.  However, we should make sure that either XMAX_COMMITTED or
B
Bruce Momjian 已提交
1145 1146
		 * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
		 * examining the tuple for future xacts.  Also, marking dead
1147 1148
		 * MultiXacts as invalid here provides defense against MultiXactId
		 * wraparound (see also comments in heap_freeze_tuple()).
1149 1150 1151
		 */
		if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
		{
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
			if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
			{
				if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
					return HEAPTUPLE_LIVE;
			}
			else
			{
				if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
					return HEAPTUPLE_LIVE;
			}
B
Bruce Momjian 已提交
1162

1163
			/*
B
Bruce Momjian 已提交
1164 1165 1166
			 * We don't really care whether xmax did commit, abort or crash.
			 * We know that xmax did lock the tuple, but it did not and will
			 * never actually update it.
1167
			 */
1168 1169
			SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
						InvalidTransactionId);
1170
		}
1171 1172 1173
		return HEAPTUPLE_LIVE;
	}

1174 1175 1176 1177 1178 1179 1180
	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
	{
		/* MultiXacts are currently only allowed to lock tuples */
		Assert(tuple->t_infomask & HEAP_IS_LOCKED);
		return HEAPTUPLE_LIVE;
	}

1181 1182
	if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
	{
1183
		if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1184
			return HEAPTUPLE_DELETE_IN_PROGRESS;
1185
		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
1186 1187
			SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
						HeapTupleHeaderGetXmax(tuple));
1188 1189 1190
		else
		{
			/*
B
Bruce Momjian 已提交
1191
			 * Not in Progress, Not Committed, so either Aborted or crashed
1192
			 */
1193 1194
			SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
						InvalidTransactionId);
1195 1196
			return HEAPTUPLE_LIVE;
		}
B
Bruce Momjian 已提交
1197

1198 1199
		/*
		 * At this point the xmax is known committed, but we might not have
B
Bruce Momjian 已提交
1200 1201
		 * been able to set the hint bit yet; so we can no longer Assert that
		 * it's set.
1202
		 */
1203 1204 1205 1206 1207 1208
	}

	/*
	 * Deleter committed, but check special cases.
	 */

1209
	if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),
B
Bruce Momjian 已提交
1210
							HeapTupleHeaderGetXmax(tuple)))
1211
	{
1212
		/*
B
Bruce Momjian 已提交
1213 1214 1215 1216
		 * Inserter also deleted it, so it was never visible to anyone else.
		 * However, we can only remove it early if it's not an updated tuple;
		 * else its parent tuple is linking to it via t_ctid, and this tuple
		 * mustn't go away before the parent does.
1217
		 */
1218 1219
		if (!(tuple->t_infomask & HEAP_UPDATED))
			return HEAPTUPLE_DEAD;
1220 1221
	}

1222
	if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin))
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
	{
		/* deleting xact is too recent, tuple could still be visible */
		return HEAPTUPLE_RECENTLY_DEAD;
	}

	/* Otherwise, it's dead and removable */
	return HEAPTUPLE_DEAD;
}


1233
/*
1234
 * XidInMVCCSnapshot
1235 1236 1237 1238 1239 1240 1241 1242
 *		Is the given XID still-in-progress according to the snapshot?
 *
 * Note: GetSnapshotData never stores either top xid or subxids of our own
 * backend into a snapshot, so these xids will not be reported as "running"
 * by this function.  This is OK for current uses, because we actually only
 * apply this for known-committed XIDs.
 */
static bool
1243
XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
1244 1245 1246 1247 1248
{
	uint32		i;

	/*
	 * Make a quick range check to eliminate most XIDs without looking at the
B
Bruce Momjian 已提交
1249
	 * xip arrays.	Note that this is OK even if we convert a subxact XID to
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
	 * its parent below, because a subxact with XID < xmin has surely also got
	 * a parent with XID < xmin, while one with XID >= xmax must belong to a
	 * parent that was not yet committed at the time of this snapshot.
	 */

	/* Any xid < xmin is not in-progress */
	if (TransactionIdPrecedes(xid, snapshot->xmin))
		return false;
	/* Any xid >= xmax is in-progress */
	if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
		return true;

	/*
1263 1264
	 * Snapshot information is stored slightly differently in snapshots
	 * taken during recovery.
1265
	 */
1266
	if (!snapshot->takenDuringRecovery)
1267
	{
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278
		/*
		 * If the snapshot contains full subxact data, the fastest way to check
		 * things is just to compare the given XID against both subxact XIDs and
		 * top-level XIDs.	If the snapshot overflowed, we have to use pg_subtrans
		 * to convert a subxact XID to its parent XID, but then we need only look
		 * at top-level XIDs not subxacts.
		 */
		if (!snapshot->suboverflowed)
		{
			/* full data, so search subxip */
			int32		j;
1279

1280 1281 1282 1283 1284 1285 1286 1287 1288
			for (j = 0; j < snapshot->subxcnt; j++)
			{
				if (TransactionIdEquals(xid, snapshot->subxip[j]))
					return true;
			}

			/* not there, fall through to search xip[] */
		}
		else
1289
		{
1290 1291 1292 1293 1294 1295 1296 1297 1298
			/* overflowed, so convert xid to top-level */
			xid = SubTransGetTopmostTransaction(xid);

			/*
			 * If xid was indeed a subxact, we might now have an xid < xmin, so
			 * recheck to avoid an array scan.	No point in rechecking xmax.
			 */
			if (TransactionIdPrecedes(xid, snapshot->xmin))
				return false;
1299 1300
		}

1301 1302 1303 1304 1305
		for (i = 0; i < snapshot->xcnt; i++)
		{
			if (TransactionIdEquals(xid, snapshot->xip[i]))
				return true;
		}
1306 1307 1308
	}
	else
	{
1309
		int32		j;
1310 1311

		/*
1312 1313 1314 1315 1316
		 * In recovery we store all xids in the subxact array because it
		 * is by far the bigger array, and we mostly don't know which xids
		 * are top-level and which are subxacts. The xip array is empty.
		 *
		 * We start by searching subtrans, if we overflowed.
1317
		 */
1318 1319 1320 1321
		if (snapshot->suboverflowed)
		{
			/* overflowed, so convert xid to top-level */
			xid = SubTransGetTopmostTransaction(xid);
1322

1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
			/*
			 * If xid was indeed a subxact, we might now have an xid < xmin, so
			 * recheck to avoid an array scan.	No point in rechecking xmax.
			 */
			if (TransactionIdPrecedes(xid, snapshot->xmin))
				return false;
		}

		/*
		 * We now have either a top-level xid higher than xmin or an
		 * indeterminate xid. We don't know whether it's top level or subxact
		 * but it doesn't matter. If it's present, the xid is visible.
		 */
		for (j = 0; j < snapshot->subxcnt; j++)
		{
			if (TransactionIdEquals(xid, snapshot->subxip[j]))
				return true;
		}
1341 1342 1343 1344
	}

	return false;
}