OSDN Git Service

e5401861455af67bf42d675618f30d280d4951ff
[pg-rex/syncrep.git] / src / backend / utils / time / tqual.c
1 /*-------------------------------------------------------------------------
2  *
3  * tqual.c
4  *        POSTGRES "time qualification" code, ie, tuple visibility rules.
5  *
6  * NOTE: all the HeapTupleSatisfies routines will update the tuple's
7  * "hint" status bits if we see that the inserting or deleting transaction
8  * has now committed or aborted (and it is safe to set the hint bits).
9  * If the hint bits are changed, SetBufferCommitInfoNeedsSave is called on
10  * the passed-in buffer.  The caller must hold not only a pin, but at least
11  * shared buffer content lock on the buffer containing the tuple.
12  *
13  * NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array)
14  * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
15  * pg_clog).  Otherwise we have a race condition: we might decide that a
16  * just-committed transaction crashed, because none of the tests succeed.
17  * xact.c is careful to record commit/abort in pg_clog before it unsets
18  * MyProc->xid in PGPROC array.  That fixes that problem, but it also
19  * means there is a window where TransactionIdIsInProgress and
20  * TransactionIdDidCommit will both return true.  If we check only
21  * TransactionIdDidCommit, we could consider a tuple committed when a
22  * later GetSnapshotData call will still think the originating transaction
23  * is in progress, which leads to application-level inconsistency.      The
24  * upshot is that we gotta check TransactionIdIsInProgress first in all
25  * code paths, except for a few cases where we are looking at
26  * subtransactions of our own main transaction and so there can't be any
27  * race condition.
28  *
29  *
30  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
31  * Portions Copyright (c) 1994, Regents of the University of California
32  *
33  * IDENTIFICATION
34  *        $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.106 2007/09/21 18:24:28 tgl Exp $
35  *
36  *-------------------------------------------------------------------------
37  */
38
39 #include "postgres.h"
40
41 #include "access/multixact.h"
42 #include "access/subtrans.h"
43 #include "access/transam.h"
44 #include "access/xact.h"
45 #include "storage/bufmgr.h"
46 #include "storage/procarray.h"
47 #include "utils/tqual.h"
48
49
50 /* Static variables representing various special snapshot semantics */
51 SnapshotData SnapshotNowData = {HeapTupleSatisfiesNow};
52 SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf};
53 SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny};
54 SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast};
55
56 /*
57  * These SnapshotData structs are static to simplify memory allocation
58  * (see the hack in GetSnapshotData to avoid repeated malloc/free).
59  */
60 static SnapshotData SerializableSnapshotData = {HeapTupleSatisfiesMVCC};
61 static SnapshotData LatestSnapshotData = {HeapTupleSatisfiesMVCC};
62
63 /* Externally visible pointers to valid snapshots: */
64 Snapshot        SerializableSnapshot = NULL;
65 Snapshot        LatestSnapshot = NULL;
66
67 /*
68  * This pointer is not maintained by this module, but it's convenient
69  * to declare it here anyway.  Callers typically assign a copy of
70  * GetTransactionSnapshot's result to ActiveSnapshot.
71  */
72 Snapshot        ActiveSnapshot = NULL;
73
74 /*
75  * These are updated by GetSnapshotData.  We initialize them this way
76  * for the convenience of TransactionIdIsInProgress: even in bootstrap
77  * mode, we don't want it to say that BootstrapTransactionId is in progress.
78  */
79 TransactionId TransactionXmin = FirstNormalTransactionId;
80 TransactionId RecentXmin = FirstNormalTransactionId;
81 TransactionId RecentGlobalXmin = FirstNormalTransactionId;
82
83 /* local functions */
84 static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
85
86
87 /*
88  * SetHintBits()
89  *
90  * Set commit/abort hint bits on a tuple, if appropriate at this time.
91  *
92  * It is only safe to set a transaction-committed hint bit if we know the
93  * transaction's commit record has been flushed to disk.  We cannot change
94  * the LSN of the page here because we may hold only a share lock on the
95  * buffer, so we can't use the LSN to interlock this; we have to just refrain
96  * from setting the hint bit until some future re-examination of the tuple.
97  *
98  * We can always set hint bits when marking a transaction aborted.  (Some
99  * code in heapam.c relies on that!)
100  *
101  * Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
102  * we can always set the hint bits, since VACUUM FULL always uses synchronous
103  * commits and doesn't move tuples that weren't previously hinted.  (This is
104  * not known by this subroutine, but is applied by its callers.)
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
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 (XLogNeedsFlush(commitLSN))
122                         return;                         /* not flushed yet, so don't set hint */
123         }
124
125         tuple->t_infomask |= infomask;
126         SetBufferCommitInfoNeedsSave(buffer);
127 }
128
129 /*
130  * HeapTupleSetHintBits --- exported version of SetHintBits()
131  *
132  * This must be separate because of C99's brain-dead notions about how to
133  * implement inline functions.
134  */
135 void
136 HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
137                                          uint16 infomask, TransactionId xid)
138 {
139         SetHintBits(tuple, buffer, infomask, xid);
140 }
141
142
143 /*
144  * HeapTupleSatisfiesSelf
145  *              True iff heap tuple is valid "for itself".
146  *
147  *      Here, we consider the effects of:
148  *              all committed transactions (as of the current instant)
149  *              previous commands of this transaction
150  *              changes made by the current command
151  *
152  * Note:
153  *              Assumes heap tuple is valid.
154  *
155  * The satisfaction of "itself" requires the following:
156  *
157  * ((Xmin == my-transaction &&                          the row was updated by the current transaction, and
158  *              (Xmax is null                                           it was not deleted
159  *               [|| Xmax != my-transaction)])                  [or it was deleted by another transaction]
160  * ||
161  *
162  * (Xmin is committed &&                                        the row was modified by a committed transaction, and
163  *              (Xmax is null ||                                        the row has not been deleted, or
164  *                      (Xmax != my-transaction &&                      the row was deleted by another transaction
165  *                       Xmax is not committed)))                       that has not been committed
166  */
167 bool
168 HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
169 {
170         if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
171         {
172                 if (tuple->t_infomask & HEAP_XMIN_INVALID)
173                         return false;
174
175                 if (tuple->t_infomask & HEAP_MOVED_OFF)
176                 {
177                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
178
179                         if (TransactionIdIsCurrentTransactionId(xvac))
180                                 return false;
181                         if (!TransactionIdIsInProgress(xvac))
182                         {
183                                 if (TransactionIdDidCommit(xvac))
184                                 {
185                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
186                                                                 InvalidTransactionId);
187                                         return false;
188                                 }
189                                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
190                                                         InvalidTransactionId);
191                         }
192                 }
193                 else if (tuple->t_infomask & HEAP_MOVED_IN)
194                 {
195                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
196
197                         if (!TransactionIdIsCurrentTransactionId(xvac))
198                         {
199                                 if (TransactionIdIsInProgress(xvac))
200                                         return false;
201                                 if (TransactionIdDidCommit(xvac))
202                                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
203                                                                 InvalidTransactionId);
204                                 else
205                                 {
206                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
207                                                                 InvalidTransactionId);
208                                         return false;
209                                 }
210                         }
211                 }
212                 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
213                 {
214                         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid */
215                                 return true;
216
217                         if (tuple->t_infomask & HEAP_IS_LOCKED)         /* not deleter */
218                                 return true;
219
220                         Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
221
222                         if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
223                         {
224                                 /* deleting subtransaction must have aborted */
225                                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
226                                                         InvalidTransactionId);
227                                 return true;
228                         }
229
230                         return false;
231                 }
232                 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
233                         return false;
234                 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
235                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
236                                                 HeapTupleHeaderGetXmin(tuple));
237                 else
238                 {
239                         /* it must have aborted or crashed */
240                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
241                                                 InvalidTransactionId);
242                         return false;
243                 }
244         }
245
246         /* by here, the inserting transaction has committed */
247
248         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid or aborted */
249                 return true;
250
251         if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
252         {
253                 if (tuple->t_infomask & HEAP_IS_LOCKED)
254                         return true;
255                 return false;                   /* updated by other */
256         }
257
258         if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
259         {
260                 /* MultiXacts are currently only allowed to lock tuples */
261                 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
262                 return true;
263         }
264
265         if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
266         {
267                 if (tuple->t_infomask & HEAP_IS_LOCKED)
268                         return true;
269                 return false;
270         }
271
272         if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
273                 return true;
274
275         if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
276         {
277                 /* it must have aborted or crashed */
278                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
279                                         InvalidTransactionId);
280                 return true;
281         }
282
283         /* xmax transaction committed */
284
285         if (tuple->t_infomask & HEAP_IS_LOCKED)
286         {
287                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
288                                         InvalidTransactionId);
289                 return true;
290         }
291
292         SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
293                                 HeapTupleHeaderGetXmax(tuple));
294         return false;
295 }
296
297 /*
298  * HeapTupleSatisfiesNow
299  *              True iff heap tuple is valid "now".
300  *
301  *      Here, we consider the effects of:
302  *              all committed transactions (as of the current instant)
303  *              previous commands of this transaction
304  *
305  * Note we do _not_ include changes made by the current command.  This
306  * solves the "Halloween problem" wherein an UPDATE might try to re-update
307  * its own output tuples.
308  *
309  * Note:
310  *              Assumes heap tuple is valid.
311  *
312  * The satisfaction of "now" requires the following:
313  *
314  * ((Xmin == my-transaction &&                          inserted by the current transaction
315  *       Cmin < my-command &&                                   before this command, and
316  *       (Xmax is null ||                                               the row has not been deleted, or
317  *        (Xmax == my-transaction &&                    it was deleted by the current transaction
318  *         Cmax >= my-command)))                                but not before this command,
319  * ||                                                                           or
320  *      (Xmin is committed &&                                   the row was inserted by a committed transaction, and
321  *              (Xmax is null ||                                        the row has not been deleted, or
322  *               (Xmax == my-transaction &&                     the row is being deleted by this transaction
323  *                Cmax >= my-command) ||                        but it's not deleted "yet", or
324  *               (Xmax != my-transaction &&                     the row was deleted by another transaction
325  *                Xmax is not committed))))                     that has not been committed
326  *
327  *              mao says 17 march 1993:  the tests in this routine are correct;
328  *              if you think they're not, you're wrong, and you should think
329  *              about it again.  i know, it happened to me.  we don't need to
330  *              check commit time against the start time of this transaction
331  *              because 2ph locking protects us from doing the wrong thing.
332  *              if you mess around here, you'll break serializability.  the only
333  *              problem with this code is that it does the wrong thing for system
334  *              catalog updates, because the catalogs aren't subject to 2ph, so
335  *              the serializability guarantees we provide don't extend to xacts
336  *              that do catalog accesses.  this is unfortunate, but not critical.
337  */
338 bool
339 HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
340 {
341         if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
342         {
343                 if (tuple->t_infomask & HEAP_XMIN_INVALID)
344                         return false;
345
346                 if (tuple->t_infomask & HEAP_MOVED_OFF)
347                 {
348                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
349
350                         if (TransactionIdIsCurrentTransactionId(xvac))
351                                 return false;
352                         if (!TransactionIdIsInProgress(xvac))
353                         {
354                                 if (TransactionIdDidCommit(xvac))
355                                 {
356                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
357                                                                 InvalidTransactionId);
358                                         return false;
359                                 }
360                                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
361                                                         InvalidTransactionId);
362                         }
363                 }
364                 else if (tuple->t_infomask & HEAP_MOVED_IN)
365                 {
366                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
367
368                         if (!TransactionIdIsCurrentTransactionId(xvac))
369                         {
370                                 if (TransactionIdIsInProgress(xvac))
371                                         return false;
372                                 if (TransactionIdDidCommit(xvac))
373                                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
374                                                                 InvalidTransactionId);
375                                 else
376                                 {
377                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
378                                                                 InvalidTransactionId);
379                                         return false;
380                                 }
381                         }
382                 }
383                 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
384                 {
385                         if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId())
386                                 return false;   /* inserted after scan started */
387
388                         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid */
389                                 return true;
390
391                         if (tuple->t_infomask & HEAP_IS_LOCKED)         /* not deleter */
392                                 return true;
393
394                         Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
395
396                         if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
397                         {
398                                 /* deleting subtransaction must have aborted */
399                                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
400                                                         InvalidTransactionId);
401                                 return true;
402                         }
403
404                         if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
405                                 return true;    /* deleted after scan started */
406                         else
407                                 return false;   /* deleted before scan started */
408                 }
409                 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
410                         return false;
411                 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
412                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
413                                                 HeapTupleHeaderGetXmin(tuple));
414                 else
415                 {
416                         /* it must have aborted or crashed */
417                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
418                                                 InvalidTransactionId);
419                         return false;
420                 }
421         }
422
423         /* by here, the inserting transaction has committed */
424
425         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid or aborted */
426                 return true;
427
428         if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
429         {
430                 if (tuple->t_infomask & HEAP_IS_LOCKED)
431                         return true;
432                 return false;
433         }
434
435         if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
436         {
437                 /* MultiXacts are currently only allowed to lock tuples */
438                 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
439                 return true;
440         }
441
442         if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
443         {
444                 if (tuple->t_infomask & HEAP_IS_LOCKED)
445                         return true;
446                 if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())
447                         return true;            /* deleted after scan started */
448                 else
449                         return false;           /* deleted before scan started */
450         }
451
452         if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
453                 return true;
454
455         if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
456         {
457                 /* it must have aborted or crashed */
458                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
459                                         InvalidTransactionId);
460                 return true;
461         }
462
463         /* xmax transaction committed */
464
465         if (tuple->t_infomask & HEAP_IS_LOCKED)
466         {
467                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
468                                         InvalidTransactionId);
469                 return true;
470         }
471
472         SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
473                                 HeapTupleHeaderGetXmax(tuple));
474         return false;
475 }
476
477 /*
478  * HeapTupleSatisfiesAny
479  *              Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
480  */
481 bool
482 HeapTupleSatisfiesAny(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
483 {
484         return true;
485 }
486
487 /*
488  * HeapTupleSatisfiesToast
489  *              True iff heap tuple is valid as a TOAST row.
490  *
491  * This is a simplified version that only checks for VACUUM moving conditions.
492  * It's appropriate for TOAST usage because TOAST really doesn't want to do
493  * its own time qual checks; if you can see the main table row that contains
494  * a TOAST reference, you should be able to see the TOASTed value.      However,
495  * vacuuming a TOAST table is independent of the main table, and in case such
496  * a vacuum fails partway through, we'd better do this much checking.
497  *
498  * Among other things, this means you can't do UPDATEs of rows in a TOAST
499  * table.
500  */
501 bool
502 HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot,
503                                                 Buffer buffer)
504 {
505         if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
506         {
507                 if (tuple->t_infomask & HEAP_XMIN_INVALID)
508                         return false;
509
510                 if (tuple->t_infomask & HEAP_MOVED_OFF)
511                 {
512                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
513
514                         if (TransactionIdIsCurrentTransactionId(xvac))
515                                 return false;
516                         if (!TransactionIdIsInProgress(xvac))
517                         {
518                                 if (TransactionIdDidCommit(xvac))
519                                 {
520                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
521                                                                 InvalidTransactionId);
522                                         return false;
523                                 }
524                                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
525                                                         InvalidTransactionId);
526                         }
527                 }
528                 else if (tuple->t_infomask & HEAP_MOVED_IN)
529                 {
530                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
531
532                         if (!TransactionIdIsCurrentTransactionId(xvac))
533                         {
534                                 if (TransactionIdIsInProgress(xvac))
535                                         return false;
536                                 if (TransactionIdDidCommit(xvac))
537                                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
538                                                                 InvalidTransactionId);
539                                 else
540                                 {
541                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
542                                                                 InvalidTransactionId);
543                                         return false;
544                                 }
545                         }
546                 }
547         }
548
549         /* otherwise assume the tuple is valid for TOAST. */
550         return true;
551 }
552
553 /*
554  * HeapTupleSatisfiesUpdate
555  *
556  *      Same logic as HeapTupleSatisfiesNow, but returns a more detailed result
557  *      code, since UPDATE needs to know more than "is it visible?".  Also,
558  *      tuples of my own xact are tested against the passed CommandId not
559  *      CurrentCommandId.
560  *
561  *      The possible return codes are:
562  *
563  *      HeapTupleInvisible: the tuple didn't exist at all when the scan started,
564  *      e.g. it was created by a later CommandId.
565  *
566  *      HeapTupleMayBeUpdated: The tuple is valid and visible, so it may be
567  *      updated.
568  *
569  *      HeapTupleSelfUpdated: The tuple was updated by the current transaction,
570  *      after the current scan started.
571  *
572  *      HeapTupleUpdated: The tuple was updated by a committed transaction.
573  *
574  *      HeapTupleBeingUpdated: The tuple is being updated by an in-progress
575  *      transaction other than the current transaction.  (Note: this includes
576  *      the case where the tuple is share-locked by a MultiXact, even if the
577  *      MultiXact includes the current transaction.  Callers that want to
578  *      distinguish that case must test for it themselves.)
579  */
580 HTSU_Result
581 HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
582                                                  Buffer buffer)
583 {
584         if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
585         {
586                 if (tuple->t_infomask & HEAP_XMIN_INVALID)
587                         return HeapTupleInvisible;
588
589                 if (tuple->t_infomask & HEAP_MOVED_OFF)
590                 {
591                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
592
593                         if (TransactionIdIsCurrentTransactionId(xvac))
594                                 return HeapTupleInvisible;
595                         if (!TransactionIdIsInProgress(xvac))
596                         {
597                                 if (TransactionIdDidCommit(xvac))
598                                 {
599                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
600                                                                 InvalidTransactionId);
601                                         return HeapTupleInvisible;
602                                 }
603                                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
604                                                         InvalidTransactionId);
605                         }
606                 }
607                 else if (tuple->t_infomask & HEAP_MOVED_IN)
608                 {
609                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
610
611                         if (!TransactionIdIsCurrentTransactionId(xvac))
612                         {
613                                 if (TransactionIdIsInProgress(xvac))
614                                         return HeapTupleInvisible;
615                                 if (TransactionIdDidCommit(xvac))
616                                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
617                                                                 InvalidTransactionId);
618                                 else
619                                 {
620                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
621                                                                 InvalidTransactionId);
622                                         return HeapTupleInvisible;
623                                 }
624                         }
625                 }
626                 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
627                 {
628                         if (HeapTupleHeaderGetCmin(tuple) >= curcid)
629                                 return HeapTupleInvisible;              /* inserted after scan started */
630
631                         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid */
632                                 return HeapTupleMayBeUpdated;
633
634                         if (tuple->t_infomask & HEAP_IS_LOCKED)         /* not deleter */
635                                 return HeapTupleMayBeUpdated;
636
637                         Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
638
639                         if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
640                         {
641                                 /* deleting subtransaction must have aborted */
642                                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
643                                                         InvalidTransactionId);
644                                 return HeapTupleMayBeUpdated;
645                         }
646
647                         if (HeapTupleHeaderGetCmax(tuple) >= curcid)
648                                 return HeapTupleSelfUpdated;    /* updated after scan started */
649                         else
650                                 return HeapTupleInvisible;              /* updated before scan started */
651                 }
652                 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
653                         return HeapTupleInvisible;
654                 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
655                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
656                                                 HeapTupleHeaderGetXmin(tuple));
657                 else
658                 {
659                         /* it must have aborted or crashed */
660                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
661                                                 InvalidTransactionId);
662                         return HeapTupleInvisible;
663                 }
664         }
665
666         /* by here, the inserting transaction has committed */
667
668         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid or aborted */
669                 return HeapTupleMayBeUpdated;
670
671         if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
672         {
673                 if (tuple->t_infomask & HEAP_IS_LOCKED)
674                         return HeapTupleMayBeUpdated;
675                 return HeapTupleUpdated;        /* updated by other */
676         }
677
678         if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
679         {
680                 /* MultiXacts are currently only allowed to lock tuples */
681                 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
682
683                 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
684                         return HeapTupleBeingUpdated;
685                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
686                                         InvalidTransactionId);
687                 return HeapTupleMayBeUpdated;
688         }
689
690         if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
691         {
692                 if (tuple->t_infomask & HEAP_IS_LOCKED)
693                         return HeapTupleMayBeUpdated;
694                 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
695                         return HeapTupleSelfUpdated;            /* updated after scan started */
696                 else
697                         return HeapTupleInvisible;      /* updated before scan started */
698         }
699
700         if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
701                 return HeapTupleBeingUpdated;
702
703         if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
704         {
705                 /* it must have aborted or crashed */
706                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
707                                         InvalidTransactionId);
708                 return HeapTupleMayBeUpdated;
709         }
710
711         /* xmax transaction committed */
712
713         if (tuple->t_infomask & HEAP_IS_LOCKED)
714         {
715                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
716                                         InvalidTransactionId);
717                 return HeapTupleMayBeUpdated;
718         }
719
720         SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
721                                 HeapTupleHeaderGetXmax(tuple));
722         return HeapTupleUpdated;        /* updated by other */
723 }
724
725 /*
726  * HeapTupleSatisfiesDirty
727  *              True iff heap tuple is valid including effects of open transactions.
728  *
729  *      Here, we consider the effects of:
730  *              all committed and in-progress transactions (as of the current instant)
731  *              previous commands of this transaction
732  *              changes made by the current command
733  *
734  * This is essentially like HeapTupleSatisfiesSelf as far as effects of
735  * the current transaction and committed/aborted xacts are concerned.
736  * However, we also include the effects of other xacts still in progress.
737  *
738  * A special hack is that the passed-in snapshot struct is used as an
739  * output argument to return the xids of concurrent xacts that affected the
740  * tuple.  snapshot->xmin is set to the tuple's xmin if that is another
741  * transaction that's still in progress; or to InvalidTransactionId if the
742  * tuple's xmin is committed good, committed dead, or my own xact.  Similarly
743  * for snapshot->xmax and the tuple's xmax.
744  */
745 bool
746 HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
747                                                 Buffer buffer)
748 {
749         snapshot->xmin = snapshot->xmax = InvalidTransactionId;
750
751         if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
752         {
753                 if (tuple->t_infomask & HEAP_XMIN_INVALID)
754                         return false;
755
756                 if (tuple->t_infomask & HEAP_MOVED_OFF)
757                 {
758                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
759
760                         if (TransactionIdIsCurrentTransactionId(xvac))
761                                 return false;
762                         if (!TransactionIdIsInProgress(xvac))
763                         {
764                                 if (TransactionIdDidCommit(xvac))
765                                 {
766                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
767                                                                 InvalidTransactionId);
768                                         return false;
769                                 }
770                                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
771                                                         InvalidTransactionId);
772                         }
773                 }
774                 else if (tuple->t_infomask & HEAP_MOVED_IN)
775                 {
776                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
777
778                         if (!TransactionIdIsCurrentTransactionId(xvac))
779                         {
780                                 if (TransactionIdIsInProgress(xvac))
781                                         return false;
782                                 if (TransactionIdDidCommit(xvac))
783                                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
784                                                                 InvalidTransactionId);
785                                 else
786                                 {
787                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
788                                                                 InvalidTransactionId);
789                                         return false;
790                                 }
791                         }
792                 }
793                 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
794                 {
795                         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid */
796                                 return true;
797
798                         if (tuple->t_infomask & HEAP_IS_LOCKED)         /* not deleter */
799                                 return true;
800
801                         Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
802
803                         if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
804                         {
805                                 /* deleting subtransaction must have aborted */
806                                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
807                                                         InvalidTransactionId);
808                                 return true;
809                         }
810
811                         return false;
812                 }
813                 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
814                 {
815                         snapshot->xmin = HeapTupleHeaderGetXmin(tuple);
816                         /* XXX shouldn't we fall through to look at xmax? */
817                         return true;            /* in insertion by other */
818                 }
819                 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
820                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
821                                                 HeapTupleHeaderGetXmin(tuple));
822                 else
823                 {
824                         /* it must have aborted or crashed */
825                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
826                                                 InvalidTransactionId);
827                         return false;
828                 }
829         }
830
831         /* by here, the inserting transaction has committed */
832
833         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid or aborted */
834                 return true;
835
836         if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
837         {
838                 if (tuple->t_infomask & HEAP_IS_LOCKED)
839                         return true;
840                 return false;                   /* updated by other */
841         }
842
843         if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
844         {
845                 /* MultiXacts are currently only allowed to lock tuples */
846                 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
847                 return true;
848         }
849
850         if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
851         {
852                 if (tuple->t_infomask & HEAP_IS_LOCKED)
853                         return true;
854                 return false;
855         }
856
857         if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
858         {
859                 snapshot->xmax = HeapTupleHeaderGetXmax(tuple);
860                 return true;
861         }
862
863         if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
864         {
865                 /* it must have aborted or crashed */
866                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
867                                         InvalidTransactionId);
868                 return true;
869         }
870
871         /* xmax transaction committed */
872
873         if (tuple->t_infomask & HEAP_IS_LOCKED)
874         {
875                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
876                                         InvalidTransactionId);
877                 return true;
878         }
879
880         SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
881                                 HeapTupleHeaderGetXmax(tuple));
882         return false;                           /* updated by other */
883 }
884
885 /*
886  * HeapTupleSatisfiesMVCC
887  *              True iff heap tuple is valid for the given MVCC snapshot.
888  *
889  *      Here, we consider the effects of:
890  *              all transactions committed as of the time of the given snapshot
891  *              previous commands of this transaction
892  *
893  *      Does _not_ include:
894  *              transactions shown as in-progress by the snapshot
895  *              transactions started after the snapshot was taken
896  *              changes made by the current command
897  *
898  * This is the same as HeapTupleSatisfiesNow, except that transactions that
899  * were in progress or as yet unstarted when the snapshot was taken will
900  * be treated as uncommitted, even if they have committed by now.
901  *
902  * (Notice, however, that the tuple status hint bits will be updated on the
903  * basis of the true state of the transaction, even if we then pretend we
904  * can't see it.)
905  */
906 bool
907 HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
908                                            Buffer buffer)
909 {
910         if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
911         {
912                 if (tuple->t_infomask & HEAP_XMIN_INVALID)
913                         return false;
914
915                 if (tuple->t_infomask & HEAP_MOVED_OFF)
916                 {
917                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
918
919                         if (TransactionIdIsCurrentTransactionId(xvac))
920                                 return false;
921                         if (!TransactionIdIsInProgress(xvac))
922                         {
923                                 if (TransactionIdDidCommit(xvac))
924                                 {
925                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
926                                                                 InvalidTransactionId);
927                                         return false;
928                                 }
929                                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
930                                                         InvalidTransactionId);
931                         }
932                 }
933                 else if (tuple->t_infomask & HEAP_MOVED_IN)
934                 {
935                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
936
937                         if (!TransactionIdIsCurrentTransactionId(xvac))
938                         {
939                                 if (TransactionIdIsInProgress(xvac))
940                                         return false;
941                                 if (TransactionIdDidCommit(xvac))
942                                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
943                                                                 InvalidTransactionId);
944                                 else
945                                 {
946                                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
947                                                                 InvalidTransactionId);
948                                         return false;
949                                 }
950                         }
951                 }
952                 else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
953                 {
954                         if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
955                                 return false;   /* inserted after scan started */
956
957                         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid */
958                                 return true;
959
960                         if (tuple->t_infomask & HEAP_IS_LOCKED)         /* not deleter */
961                                 return true;
962
963                         Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
964
965                         if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
966                         {
967                                 /* deleting subtransaction must have aborted */
968                                 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
969                                                         InvalidTransactionId);
970                                 return true;
971                         }
972
973                         if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
974                                 return true;    /* deleted after scan started */
975                         else
976                                 return false;   /* deleted before scan started */
977                 }
978                 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
979                         return false;
980                 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
981                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
982                                                 HeapTupleHeaderGetXmin(tuple));
983                 else
984                 {
985                         /* it must have aborted or crashed */
986                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
987                                                 InvalidTransactionId);
988                         return false;
989                 }
990         }
991
992         /*
993          * By here, the inserting transaction has committed - have to check
994          * when...
995          */
996         if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot))
997                 return false;                   /* treat as still in progress */
998
999         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid or aborted */
1000                 return true;
1001
1002         if (tuple->t_infomask & HEAP_IS_LOCKED)
1003                 return true;
1004
1005         if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1006         {
1007                 /* MultiXacts are currently only allowed to lock tuples */
1008                 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
1009                 return true;
1010         }
1011
1012         if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1013         {
1014                 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
1015                 {
1016                         if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1017                                 return true;    /* deleted after scan started */
1018                         else
1019                                 return false;   /* deleted before scan started */
1020                 }
1021
1022                 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1023                         return true;
1024
1025                 if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
1026                 {
1027                         /* it must have aborted or crashed */
1028                         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1029                                                 InvalidTransactionId);
1030                         return true;
1031                 }
1032
1033                 /* xmax transaction committed */
1034                 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1035                                         HeapTupleHeaderGetXmax(tuple));
1036         }
1037
1038         /*
1039          * OK, the deleting transaction committed too ... but when?
1040          */
1041         if (XidInMVCCSnapshot(HeapTupleHeaderGetXmax(tuple), snapshot))
1042                 return true;                    /* treat as still in progress */
1043
1044         return false;
1045 }
1046
1047
1048 /*
1049  * HeapTupleSatisfiesVacuum
1050  *
1051  *      Determine the status of tuples for VACUUM purposes.  Here, what
1052  *      we mainly want to know is if a tuple is potentially visible to *any*
1053  *      running transaction.  If so, it can't be removed yet by VACUUM.
1054  *
1055  * OldestXmin is a cutoff XID (obtained from GetOldestXmin()).  Tuples
1056  * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
1057  * still be visible to some open transaction, so we can't remove them,
1058  * even if we see that the deleting transaction has committed.
1059  */
1060 HTSV_Result
1061 HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
1062                                                  Buffer buffer)
1063 {
1064         /*
1065          * Has inserting transaction committed?
1066          *
1067          * If the inserting transaction aborted, then the tuple was never visible
1068          * to any other transaction, so we can delete it immediately.
1069          */
1070         if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
1071         {
1072                 if (tuple->t_infomask & HEAP_XMIN_INVALID)
1073                         return HEAPTUPLE_DEAD;
1074                 else if (tuple->t_infomask & HEAP_MOVED_OFF)
1075                 {
1076                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1077
1078                         if (TransactionIdIsCurrentTransactionId(xvac))
1079                                 return HEAPTUPLE_DELETE_IN_PROGRESS;
1080                         if (TransactionIdIsInProgress(xvac))
1081                                 return HEAPTUPLE_DELETE_IN_PROGRESS;
1082                         if (TransactionIdDidCommit(xvac))
1083                         {
1084                                 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1085                                                         InvalidTransactionId);
1086                                 return HEAPTUPLE_DEAD;
1087                         }
1088                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1089                                                 InvalidTransactionId);
1090                 }
1091                 else if (tuple->t_infomask & HEAP_MOVED_IN)
1092                 {
1093                         TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1094
1095                         if (TransactionIdIsCurrentTransactionId(xvac))
1096                                 return HEAPTUPLE_INSERT_IN_PROGRESS;
1097                         if (TransactionIdIsInProgress(xvac))
1098                                 return HEAPTUPLE_INSERT_IN_PROGRESS;
1099                         if (TransactionIdDidCommit(xvac))
1100                                 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1101                                                         InvalidTransactionId);
1102                         else
1103                         {
1104                                 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1105                                                         InvalidTransactionId);
1106                                 return HEAPTUPLE_DEAD;
1107                         }
1108                 }
1109                 else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
1110                 {
1111                         if (tuple->t_infomask & HEAP_XMAX_INVALID)      /* xid invalid */
1112                                 return HEAPTUPLE_INSERT_IN_PROGRESS;
1113                         if (tuple->t_infomask & HEAP_IS_LOCKED)
1114                                 return HEAPTUPLE_INSERT_IN_PROGRESS;
1115                         /* inserted and then deleted by same xact */
1116                         return HEAPTUPLE_DELETE_IN_PROGRESS;
1117                 }
1118                 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
1119                         SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1120                                                 HeapTupleHeaderGetXmin(tuple));
1121                 else
1122                 {
1123                         /*
1124                          * Not in Progress, Not Committed, so either Aborted or crashed
1125                          */
1126                         SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1127                                                 InvalidTransactionId);
1128                         return HEAPTUPLE_DEAD;
1129                 }
1130                 /*
1131                  * At this point the xmin is known committed, but we might not have
1132                  * been able to set the hint bit yet; so we can no longer Assert
1133                  * that it's set.
1134                  */
1135         }
1136
1137         /*
1138          * Okay, the inserter committed, so it was good at some point.  Now what
1139          * about the deleting transaction?
1140          */
1141         if (tuple->t_infomask & HEAP_XMAX_INVALID)
1142                 return HEAPTUPLE_LIVE;
1143
1144         if (tuple->t_infomask & HEAP_IS_LOCKED)
1145         {
1146                 /*
1147                  * "Deleting" xact really only locked it, so the tuple is live in any
1148                  * case.  However, we should make sure that either XMAX_COMMITTED or
1149                  * XMAX_INVALID gets set once the xact is gone, to reduce the costs
1150                  * of examining the tuple for future xacts.  Also, marking dead
1151                  * MultiXacts as invalid here provides defense against MultiXactId
1152                  * wraparound (see also comments in heap_freeze_tuple()).
1153                  */
1154                 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1155                 {
1156                         if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1157                         {
1158                                 if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))
1159                                         return HEAPTUPLE_LIVE;
1160                         }
1161                         else
1162                         {
1163                                 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1164                                         return HEAPTUPLE_LIVE;
1165                         }
1166
1167                         /*
1168                          * We don't really care whether xmax did commit, abort or crash.
1169                          * We know that xmax did lock the tuple, but it did not and will
1170                          * never actually update it.
1171                          */
1172                         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1173                                                 InvalidTransactionId);
1174                 }
1175                 return HEAPTUPLE_LIVE;
1176         }
1177
1178         if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1179         {
1180                 /* MultiXacts are currently only allowed to lock tuples */
1181                 Assert(tuple->t_infomask & HEAP_IS_LOCKED);
1182                 return HEAPTUPLE_LIVE;
1183         }
1184
1185         if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1186         {
1187                 if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
1188                         return HEAPTUPLE_DELETE_IN_PROGRESS;
1189                 else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
1190                         SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1191                                                 HeapTupleHeaderGetXmax(tuple));
1192                 else
1193                 {
1194                         /*
1195                          * Not in Progress, Not Committed, so either Aborted or crashed
1196                          */
1197                         SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1198                                                 InvalidTransactionId);
1199                         return HEAPTUPLE_LIVE;
1200                 }
1201                 /*
1202                  * At this point the xmax is known committed, but we might not have
1203                  * been able to set the hint bit yet; so we can no longer Assert
1204                  * that it's set.
1205                  */
1206         }
1207
1208         /*
1209          * Deleter committed, but check special cases.
1210          */
1211
1212         if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),
1213                                                         HeapTupleHeaderGetXmax(tuple)))
1214         {
1215                 /*
1216                  * Inserter also deleted it, so it was never visible to anyone else.
1217                  * However, we can only remove it early if it's not an updated tuple;
1218                  * else its parent tuple is linking to it via t_ctid, and this tuple
1219                  * mustn't go away before the parent does.
1220                  */
1221                 if (!(tuple->t_infomask & HEAP_UPDATED))
1222                         return HEAPTUPLE_DEAD;
1223         }
1224
1225         if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin))
1226         {
1227                 /* deleting xact is too recent, tuple could still be visible */
1228                 return HEAPTUPLE_RECENTLY_DEAD;
1229         }
1230
1231         /* Otherwise, it's dead and removable */
1232         return HEAPTUPLE_DEAD;
1233 }
1234
1235
1236 /*
1237  * GetTransactionSnapshot
1238  *              Get the appropriate snapshot for a new query in a transaction.
1239  *
1240  * The SerializableSnapshot is the first one taken in a transaction.
1241  * In serializable mode we just use that one throughout the transaction.
1242  * In read-committed mode, we take a new snapshot each time we are called.
1243  *
1244  * Note that the return value points at static storage that will be modified
1245  * by future calls and by CommandCounterIncrement().  Callers should copy
1246  * the result with CopySnapshot() if it is to be used very long.
1247  */
1248 Snapshot
1249 GetTransactionSnapshot(void)
1250 {
1251         /* First call in transaction? */
1252         if (SerializableSnapshot == NULL)
1253         {
1254                 SerializableSnapshot = GetSnapshotData(&SerializableSnapshotData, true);
1255                 return SerializableSnapshot;
1256         }
1257
1258         if (IsXactIsoLevelSerializable)
1259                 return SerializableSnapshot;
1260
1261         LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false);
1262
1263         return LatestSnapshot;
1264 }
1265
1266 /*
1267  * GetLatestSnapshot
1268  *              Get a snapshot that is up-to-date as of the current instant,
1269  *              even if we are executing in SERIALIZABLE mode.
1270  */
1271 Snapshot
1272 GetLatestSnapshot(void)
1273 {
1274         /* Should not be first call in transaction */
1275         if (SerializableSnapshot == NULL)
1276                 elog(ERROR, "no snapshot has been set");
1277
1278         LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false);
1279
1280         return LatestSnapshot;
1281 }
1282
1283 /*
1284  * CopySnapshot
1285  *              Copy the given snapshot.
1286  *
1287  * The copy is palloc'd in the current memory context.
1288  */
1289 Snapshot
1290 CopySnapshot(Snapshot snapshot)
1291 {
1292         Snapshot        newsnap;
1293         Size            subxipoff;
1294         Size            size;
1295
1296         /* We allocate any XID arrays needed in the same palloc block. */
1297         size = subxipoff = sizeof(SnapshotData) +
1298                 snapshot->xcnt * sizeof(TransactionId);
1299         if (snapshot->subxcnt > 0)
1300                 size += snapshot->subxcnt * sizeof(TransactionId);
1301
1302         newsnap = (Snapshot) palloc(size);
1303         memcpy(newsnap, snapshot, sizeof(SnapshotData));
1304
1305         /* setup XID array */
1306         if (snapshot->xcnt > 0)
1307         {
1308                 newsnap->xip = (TransactionId *) (newsnap + 1);
1309                 memcpy(newsnap->xip, snapshot->xip,
1310                            snapshot->xcnt * sizeof(TransactionId));
1311         }
1312         else
1313                 newsnap->xip = NULL;
1314
1315         /* setup subXID array */
1316         if (snapshot->subxcnt > 0)
1317         {
1318                 newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff);
1319                 memcpy(newsnap->subxip, snapshot->subxip,
1320                            snapshot->subxcnt * sizeof(TransactionId));
1321         }
1322         else
1323                 newsnap->subxip = NULL;
1324
1325         return newsnap;
1326 }
1327
1328 /*
1329  * FreeSnapshot
1330  *              Free a snapshot previously copied with CopySnapshot.
1331  *
1332  * This is currently identical to pfree, but is provided for cleanliness.
1333  *
1334  * Do *not* apply this to the results of GetTransactionSnapshot or
1335  * GetLatestSnapshot, since those are just static structs.
1336  */
1337 void
1338 FreeSnapshot(Snapshot snapshot)
1339 {
1340         pfree(snapshot);
1341 }
1342
1343 /*
1344  * FreeXactSnapshot
1345  *              Free snapshot(s) at end of transaction.
1346  */
1347 void
1348 FreeXactSnapshot(void)
1349 {
1350         /*
1351          * We do not free the xip arrays for the static snapshot structs; they
1352          * will be reused soon. So this is now just a state change to prevent
1353          * outside callers from accessing the snapshots.
1354          */
1355         SerializableSnapshot = NULL;
1356         LatestSnapshot = NULL;
1357         ActiveSnapshot = NULL;          /* just for cleanliness */
1358 }
1359
1360 /*
1361  * XidInMVCCSnapshot
1362  *              Is the given XID still-in-progress according to the snapshot?
1363  *
1364  * Note: GetSnapshotData never stores either top xid or subxids of our own
1365  * backend into a snapshot, so these xids will not be reported as "running"
1366  * by this function.  This is OK for current uses, because we actually only
1367  * apply this for known-committed XIDs.
1368  */
1369 static bool
1370 XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
1371 {
1372         uint32          i;
1373
1374         /*
1375          * Make a quick range check to eliminate most XIDs without looking at the
1376          * xip arrays.  Note that this is OK even if we convert a subxact XID to
1377          * its parent below, because a subxact with XID < xmin has surely also got
1378          * a parent with XID < xmin, while one with XID >= xmax must belong to a
1379          * parent that was not yet committed at the time of this snapshot.
1380          */
1381
1382         /* Any xid < xmin is not in-progress */
1383         if (TransactionIdPrecedes(xid, snapshot->xmin))
1384                 return false;
1385         /* Any xid >= xmax is in-progress */
1386         if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
1387                 return true;
1388
1389         /*
1390          * If the snapshot contains full subxact data, the fastest way to check
1391          * things is just to compare the given XID against both subxact XIDs and
1392          * top-level XIDs.      If the snapshot overflowed, we have to use pg_subtrans
1393          * to convert a subxact XID to its parent XID, but then we need only look
1394          * at top-level XIDs not subxacts.
1395          */
1396         if (snapshot->subxcnt >= 0)
1397         {
1398                 /* full data, so search subxip */
1399                 int32           j;
1400
1401                 for (j = 0; j < snapshot->subxcnt; j++)
1402                 {
1403                         if (TransactionIdEquals(xid, snapshot->subxip[j]))
1404                                 return true;
1405                 }
1406
1407                 /* not there, fall through to search xip[] */
1408         }
1409         else
1410         {
1411                 /* overflowed, so convert xid to top-level */
1412                 xid = SubTransGetTopmostTransaction(xid);
1413
1414                 /*
1415                  * If xid was indeed a subxact, we might now have an xid < xmin, so
1416                  * recheck to avoid an array scan.      No point in rechecking xmax.
1417                  */
1418                 if (TransactionIdPrecedes(xid, snapshot->xmin))
1419                         return false;
1420         }
1421
1422         for (i = 0; i < snapshot->xcnt; i++)
1423         {
1424                 if (TransactionIdEquals(xid, snapshot->xip[i]))
1425                         return true;
1426         }
1427
1428         return false;
1429 }