11
11
* containing the tuple. (VACUUM FULL assumes it's sufficient to have
12
12
* exclusive lock on the containing relation, instead.)
13
13
*
14
+ * NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array)
15
+ * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
16
+ * pg_clog). Otherwise we have a race condition: we might decide that a
17
+ * just-committed transaction crashed, because none of the tests succeed.
18
+ * xact.c is careful to record commit/abort in pg_clog before it unsets
19
+ * MyProc->xid in PGPROC array. That fixes that problem, but it also
20
+ * means there is a window where TransactionIdIsInProgress and
21
+ * TransactionIdDidCommit will both return true. If we check only
22
+ * TransactionIdDidCommit, we could consider a tuple committed when a
23
+ * later GetSnapshotData call will still think the originating transaction
24
+ * is in progress, which leads to application-level inconsistency. The
25
+ * upshot is that we gotta check TransactionIdIsInProgress first in all
26
+ * code paths.
27
+ *
14
28
*
15
29
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
16
30
* Portions Copyright (c) 1994, Regents of the University of California
17
31
*
18
32
* IDENTIFICATION
19
- * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.49 2002/01/16 23:51:56 tgl Exp $
33
+ * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.49.2.1 2005/05/07 21: 23:49 tgl Exp $
20
34
*
21
35
*-------------------------------------------------------------------------
22
36
*/
@@ -109,14 +123,16 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple)
109
123
110
124
return false;
111
125
}
112
- else if (!TransactionIdDidCommit (tuple -> t_xmin ))
126
+ else if (TransactionIdIsInProgress (tuple -> t_xmin ))
127
+ return false;
128
+ else if (TransactionIdDidCommit (tuple -> t_xmin ))
129
+ tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
130
+ else
113
131
{
114
- if ( TransactionIdDidAbort ( tuple -> t_xmin ))
115
- tuple -> t_infomask |=HEAP_XMIN_INVALID ;/* aborted */
132
+ /* it must have aborted or crashed */
133
+ tuple -> t_infomask |=HEAP_XMIN_INVALID ;
116
134
return false;
117
135
}
118
- else
119
- tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
120
136
}
121
137
122
138
/* by here, the inserting transaction has committed */
@@ -138,10 +154,13 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple)
138
154
return false;
139
155
}
140
156
157
+ if (TransactionIdIsInProgress (tuple -> t_xmax ))
158
+ return true;
159
+
141
160
if (!TransactionIdDidCommit (tuple -> t_xmax ))
142
161
{
143
- if ( TransactionIdDidAbort ( tuple -> t_xmax ))
144
- tuple -> t_infomask |=HEAP_XMAX_INVALID ;/* aborted */
162
+ /* it must have aborted or crashed */
163
+ tuple -> t_infomask |=HEAP_XMAX_INVALID ;
145
164
return true;
146
165
}
147
166
@@ -254,14 +273,16 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple)
254
273
else
255
274
return false;/* deleted before scan started */
256
275
}
257
- else if (!TransactionIdDidCommit (tuple -> t_xmin ))
276
+ else if (TransactionIdIsInProgress (tuple -> t_xmin ))
277
+ return false;
278
+ else if (TransactionIdDidCommit (tuple -> t_xmin ))
279
+ tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
280
+ else
258
281
{
259
- if ( TransactionIdDidAbort ( tuple -> t_xmin ))
260
- tuple -> t_infomask |=HEAP_XMIN_INVALID ;/* aborted */
282
+ /* it must have aborted or crashed */
283
+ tuple -> t_infomask |=HEAP_XMIN_INVALID ;
261
284
return false;
262
285
}
263
- else
264
- tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
265
286
}
266
287
267
288
/* by here, the inserting transaction has committed */
@@ -286,10 +307,13 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple)
286
307
return false;/* deleted before scan started */
287
308
}
288
309
310
+ if (TransactionIdIsInProgress (tuple -> t_xmax ))
311
+ return true;
312
+
289
313
if (!TransactionIdDidCommit (tuple -> t_xmax ))
290
314
{
291
- if ( TransactionIdDidAbort ( tuple -> t_xmax ))
292
- tuple -> t_infomask |=HEAP_XMAX_INVALID ;/* aborted */
315
+ /* it must have aborted or crashed */
316
+ tuple -> t_infomask |=HEAP_XMAX_INVALID ;
293
317
return true;
294
318
}
295
319
@@ -428,14 +452,16 @@ HeapTupleSatisfiesUpdate(HeapTuple htuple)
428
452
return HeapTupleInvisible ;/* updated before scan
429
453
* started */
430
454
}
431
- else if (!TransactionIdDidCommit (tuple -> t_xmin ))
455
+ else if (TransactionIdIsInProgress (tuple -> t_xmin ))
456
+ return HeapTupleInvisible ;
457
+ else if (TransactionIdDidCommit (tuple -> t_xmin ))
458
+ tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
459
+ else
432
460
{
433
- if ( TransactionIdDidAbort ( tuple -> t_xmin ))
434
- tuple -> t_infomask |=HEAP_XMIN_INVALID ;/* aborted */
461
+ /* it must have aborted or crashed */
462
+ tuple -> t_infomask |=HEAP_XMIN_INVALID ;
435
463
return HeapTupleInvisible ;
436
464
}
437
- else
438
- tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
439
465
}
440
466
441
467
/* by here, the inserting transaction has committed */
@@ -461,15 +487,14 @@ HeapTupleSatisfiesUpdate(HeapTuple htuple)
461
487
return HeapTupleInvisible ;/* updated before scan started */
462
488
}
463
489
490
+ if (TransactionIdIsInProgress (tuple -> t_xmax ))
491
+ return HeapTupleBeingUpdated ;
492
+
464
493
if (!TransactionIdDidCommit (tuple -> t_xmax ))
465
494
{
466
- if (TransactionIdDidAbort (tuple -> t_xmax ))
467
- {
468
- tuple -> t_infomask |=HEAP_XMAX_INVALID ;/* aborted */
469
- return HeapTupleMayBeUpdated ;
470
- }
471
- /* running xact */
472
- return HeapTupleBeingUpdated ;/* in updation by other */
495
+ /* it must have aborted or crashed */
496
+ tuple -> t_infomask |=HEAP_XMAX_INVALID ;
497
+ return HeapTupleMayBeUpdated ;
473
498
}
474
499
475
500
/* xmax transaction committed */
@@ -553,19 +578,20 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple)
553
578
554
579
return false;
555
580
}
556
- else if (! TransactionIdDidCommit (tuple -> t_xmin ))
581
+ else if (TransactionIdIsInProgress (tuple -> t_xmin ))
557
582
{
558
- if (TransactionIdDidAbort (tuple -> t_xmin ))
559
- {
560
- tuple -> t_infomask |=HEAP_XMIN_INVALID ;
561
- return false;
562
- }
563
583
SnapshotDirty -> xmin = tuple -> t_xmin ;
564
584
/* XXX shouldn't we fall through to look at xmax? */
565
585
return true;/* in insertion by other */
566
586
}
567
- else
587
+ else if ( TransactionIdDidCommit ( tuple -> t_xmin ))
568
588
tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
589
+ else
590
+ {
591
+ /* it must have aborted or crashed */
592
+ tuple -> t_infomask |=HEAP_XMIN_INVALID ;
593
+ return false;
594
+ }
569
595
}
570
596
571
597
/* by here, the inserting transaction has committed */
@@ -588,16 +614,17 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple)
588
614
return false;
589
615
}
590
616
591
- if (! TransactionIdDidCommit (tuple -> t_xmax ))
617
+ if (TransactionIdIsInProgress (tuple -> t_xmax ))
592
618
{
593
- if (TransactionIdDidAbort (tuple -> t_xmax ))
594
- {
595
- tuple -> t_infomask |=HEAP_XMAX_INVALID ;/* aborted */
596
- return true;
597
- }
598
- /* running xact */
599
619
SnapshotDirty -> xmax = tuple -> t_xmax ;
600
- return true;/* in updation by other */
620
+ return true;
621
+ }
622
+
623
+ if (!TransactionIdDidCommit (tuple -> t_xmax ))
624
+ {
625
+ /* it must have aborted or crashed */
626
+ tuple -> t_infomask |=HEAP_XMAX_INVALID ;
627
+ return true;
601
628
}
602
629
603
630
/* xmax transaction committed */
@@ -693,14 +720,16 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot)
693
720
else
694
721
return false;/* deleted before scan started */
695
722
}
696
- else if (!TransactionIdDidCommit (tuple -> t_xmin ))
723
+ else if (TransactionIdIsInProgress (tuple -> t_xmin ))
724
+ return false;
725
+ else if (TransactionIdDidCommit (tuple -> t_xmin ))
726
+ tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
727
+ else
697
728
{
698
- if ( TransactionIdDidAbort ( tuple -> t_xmin ))
699
- tuple -> t_infomask |=HEAP_XMIN_INVALID ;
729
+ /* it must have aborted or crashed */
730
+ tuple -> t_infomask |=HEAP_XMIN_INVALID ;
700
731
return false;
701
732
}
702
- else
703
- tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
704
733
}
705
734
706
735
/*
@@ -737,10 +766,13 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot)
737
766
return false;/* deleted before scan started */
738
767
}
739
768
769
+ if (TransactionIdIsInProgress (tuple -> t_xmax ))
770
+ return true;
771
+
740
772
if (!TransactionIdDidCommit (tuple -> t_xmax ))
741
773
{
742
- if ( TransactionIdDidAbort ( tuple -> t_xmax ))
743
- tuple -> t_infomask |=HEAP_XMAX_INVALID ;/* aborted */
774
+ /* it must have aborted or crashed */
775
+ tuple -> t_infomask |=HEAP_XMAX_INVALID ;
744
776
return true;
745
777
}
746
778
@@ -785,13 +817,6 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin)
785
817
*
786
818
* If the inserting transaction aborted, then the tuple was never visible
787
819
* to any other transaction, so we can delete it immediately.
788
- *
789
- * NOTE: must check TransactionIdIsInProgress (which looks in PROC array)
790
- * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
791
- * pg_clog). Otherwise we have a race condition where we might decide
792
- * that a just-committed transaction crashed, because none of the
793
- * tests succeed. xact.c is careful to record commit/abort in pg_clog
794
- * before it unsets MyProc->xid in PROC array.
795
820
*/
796
821
if (!(tuple -> t_infomask & HEAP_XMIN_COMMITTED ))
797
822
{
@@ -828,17 +853,9 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin)
828
853
return HEAPTUPLE_INSERT_IN_PROGRESS ;
829
854
else if (TransactionIdDidCommit (tuple -> t_xmin ))
830
855
tuple -> t_infomask |=HEAP_XMIN_COMMITTED ;
831
- else if (TransactionIdDidAbort (tuple -> t_xmin ))
832
- {
833
- tuple -> t_infomask |=HEAP_XMIN_INVALID ;
834
- return HEAPTUPLE_DEAD ;
835
- }
836
856
else
837
857
{
838
- /*
839
- * Not in Progress, Not Committed, Not Aborted - so it's from
840
- * crashed process. - vadim 11/26/96
841
- */
858
+ /* it must be aborted or crashed */
842
859
tuple -> t_infomask |=HEAP_XMIN_INVALID ;
843
860
return HEAPTUPLE_DEAD ;
844
861
}
@@ -879,22 +896,12 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin)
879
896
return HEAPTUPLE_DELETE_IN_PROGRESS ;
880
897
else if (TransactionIdDidCommit (tuple -> t_xmax ))
881
898
tuple -> t_infomask |=HEAP_XMAX_COMMITTED ;
882
- else if (TransactionIdDidAbort (tuple -> t_xmax ))
883
- {
884
- tuple -> t_infomask |=HEAP_XMAX_INVALID ;
885
- return HEAPTUPLE_LIVE ;
886
- }
887
899
else
888
900
{
889
- /*
890
- * Not in Progress, Not Committed, Not Aborted - so it's from
891
- * crashed process. - vadim 06/02/97
892
- */
901
+ /* it must be aborted or crashed */
893
902
tuple -> t_infomask |=HEAP_XMAX_INVALID ;
894
903
return HEAPTUPLE_LIVE ;
895
904
}
896
- /* Should only get here if we set XMAX_COMMITTED */
897
- Assert (tuple -> t_infomask & HEAP_XMAX_COMMITTED );
898
905
}
899
906
900
907
/*