|
11 | 11 | * "hint" status bits if we see that the inserting or deleting transaction
|
12 | 12 | * has now committed or aborted.
|
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, except for a few cases where we are looking at |
| 27 | + * subtransactions of our own main transaction and so there can't be any |
| 28 | + * race condition. |
| 29 | + * |
14 | 30 | *
|
15 | 31 | * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
16 | 32 | * Portions Copyright (c) 1994, Regents of the University of California
|
17 | 33 | *
|
18 | 34 | * IDENTIFICATION
|
19 |
| - * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.87 2005/04/28 21:47:16 tgl Exp $ |
| 35 | + * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.88 2005/05/07 21:22:01 tgl Exp $ |
20 | 36 | *
|
21 | 37 | *-------------------------------------------------------------------------
|
22 | 38 | */
|
@@ -147,19 +163,19 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple, Buffer buffer)
|
147 | 163 |
|
148 | 164 | return false;
|
149 | 165 | }
|
150 |
| - else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
151 |
| - { |
152 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) |
153 |
| - { |
154 |
| - tuple->t_infomask |= HEAP_XMIN_INVALID; |
155 |
| - SetBufferCommitInfoNeedsSave(buffer); |
156 |
| - } |
| 166 | + else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) |
157 | 167 | return false;
|
| 168 | + else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
| 169 | + { |
| 170 | + tuple->t_infomask |= HEAP_XMIN_COMMITTED; |
| 171 | + SetBufferCommitInfoNeedsSave(buffer); |
158 | 172 | }
|
159 | 173 | else
|
160 | 174 | {
|
161 |
| - tuple->t_infomask |= HEAP_XMIN_COMMITTED; |
| 175 | + /* it must have aborted or crashed */ |
| 176 | + tuple->t_infomask |= HEAP_XMIN_INVALID; |
162 | 177 | SetBufferCommitInfoNeedsSave(buffer);
|
| 178 | + return false; |
163 | 179 | }
|
164 | 180 | }
|
165 | 181 |
|
@@ -189,13 +205,14 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple, Buffer buffer)
|
189 | 205 | return false;
|
190 | 206 | }
|
191 | 207 |
|
| 208 | + if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) |
| 209 | + return true; |
| 210 | + |
192 | 211 | if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
|
193 | 212 | {
|
194 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) |
195 |
| - { |
196 |
| - tuple->t_infomask |= HEAP_XMAX_INVALID; |
197 |
| - SetBufferCommitInfoNeedsSave(buffer); |
198 |
| - } |
| 213 | + /* it must have aborted or crashed */ |
| 214 | + tuple->t_infomask |= HEAP_XMAX_INVALID; |
| 215 | + SetBufferCommitInfoNeedsSave(buffer); |
199 | 216 | return true;
|
200 | 217 | }
|
201 | 218 |
|
@@ -330,19 +347,19 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer)
|
330 | 347 | else
|
331 | 348 | return false; /* deleted before scan started */
|
332 | 349 | }
|
333 |
| - else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
334 |
| - { |
335 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) |
336 |
| - { |
337 |
| - tuple->t_infomask |= HEAP_XMIN_INVALID; |
338 |
| - SetBufferCommitInfoNeedsSave(buffer); |
339 |
| - } |
| 350 | + else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) |
340 | 351 | return false;
|
| 352 | + else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
| 353 | + { |
| 354 | + tuple->t_infomask |= HEAP_XMIN_COMMITTED; |
| 355 | + SetBufferCommitInfoNeedsSave(buffer); |
341 | 356 | }
|
342 | 357 | else
|
343 | 358 | {
|
344 |
| - tuple->t_infomask |= HEAP_XMIN_COMMITTED; |
| 359 | + /* it must have aborted or crashed */ |
| 360 | + tuple->t_infomask |= HEAP_XMIN_INVALID; |
345 | 361 | SetBufferCommitInfoNeedsSave(buffer);
|
| 362 | + return false; |
346 | 363 | }
|
347 | 364 | }
|
348 | 365 |
|
@@ -375,13 +392,14 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer)
|
375 | 392 | return false; /* deleted before scan started */
|
376 | 393 | }
|
377 | 394 |
|
| 395 | + if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) |
| 396 | + return true; |
| 397 | + |
378 | 398 | if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
|
379 | 399 | {
|
380 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) |
381 |
| - { |
382 |
| - tuple->t_infomask |= HEAP_XMAX_INVALID; |
383 |
| - SetBufferCommitInfoNeedsSave(buffer); |
384 |
| - } |
| 400 | + /* it must have aborted or crashed */ |
| 401 | + tuple->t_infomask |= HEAP_XMAX_INVALID; |
| 402 | + SetBufferCommitInfoNeedsSave(buffer); |
385 | 403 | return true;
|
386 | 404 | }
|
387 | 405 |
|
@@ -569,19 +587,19 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
|
569 | 587 | return HeapTupleInvisible; /* updated before scan
|
570 | 588 | * started */
|
571 | 589 | }
|
572 |
| - else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
573 |
| - { |
574 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) |
575 |
| - { |
576 |
| - tuple->t_infomask |= HEAP_XMIN_INVALID; |
577 |
| - SetBufferCommitInfoNeedsSave(buffer); |
578 |
| - } |
| 590 | + else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) |
579 | 591 | return HeapTupleInvisible;
|
| 592 | + else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
| 593 | + { |
| 594 | + tuple->t_infomask |= HEAP_XMIN_COMMITTED; |
| 595 | + SetBufferCommitInfoNeedsSave(buffer); |
580 | 596 | }
|
581 | 597 | else
|
582 | 598 | {
|
583 |
| - tuple->t_infomask |= HEAP_XMIN_COMMITTED; |
| 599 | + /* it must have aborted or crashed */ |
| 600 | + tuple->t_infomask |= HEAP_XMIN_INVALID; |
584 | 601 | SetBufferCommitInfoNeedsSave(buffer);
|
| 602 | + return HeapTupleInvisible; |
585 | 603 | }
|
586 | 604 | }
|
587 | 605 |
|
@@ -620,16 +638,15 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
|
620 | 638 | return HeapTupleInvisible; /* updated before scan started */
|
621 | 639 | }
|
622 | 640 |
|
| 641 | + if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) |
| 642 | + return HeapTupleBeingUpdated; |
| 643 | + |
623 | 644 | if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
|
624 | 645 | {
|
625 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) |
626 |
| - { |
627 |
| - tuple->t_infomask |= HEAP_XMAX_INVALID; |
628 |
| - SetBufferCommitInfoNeedsSave(buffer); |
629 |
| - return HeapTupleMayBeUpdated; |
630 |
| - } |
631 |
| - /* running xact */ |
632 |
| - return HeapTupleBeingUpdated; /* in updation by other */ |
| 646 | + /* it must have aborted or crashed */ |
| 647 | + tuple->t_infomask |= HEAP_XMAX_INVALID; |
| 648 | + SetBufferCommitInfoNeedsSave(buffer); |
| 649 | + return HeapTupleMayBeUpdated; |
633 | 650 | }
|
634 | 651 |
|
635 | 652 | /* xmax transaction committed */
|
@@ -735,23 +752,24 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer)
|
735 | 752 |
|
736 | 753 | return false;
|
737 | 754 | }
|
738 |
| - else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
| 755 | + else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) |
739 | 756 | {
|
740 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) |
741 |
| - { |
742 |
| - tuple->t_infomask |= HEAP_XMIN_INVALID; |
743 |
| - SetBufferCommitInfoNeedsSave(buffer); |
744 |
| - return false; |
745 |
| - } |
746 | 757 | SnapshotDirty->xmin = HeapTupleHeaderGetXmin(tuple);
|
747 | 758 | /* XXX shouldn't we fall through to look at xmax? */
|
748 | 759 | return true; /* in insertion by other */
|
749 | 760 | }
|
750 |
| - else |
| 761 | + else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
751 | 762 | {
|
752 | 763 | tuple->t_infomask |= HEAP_XMIN_COMMITTED;
|
753 | 764 | SetBufferCommitInfoNeedsSave(buffer);
|
754 | 765 | }
|
| 766 | + else |
| 767 | + { |
| 768 | + /* it must have aborted or crashed */ |
| 769 | + tuple->t_infomask |= HEAP_XMIN_INVALID; |
| 770 | + SetBufferCommitInfoNeedsSave(buffer); |
| 771 | + return false; |
| 772 | + } |
755 | 773 | }
|
756 | 774 |
|
757 | 775 | /* by here, the inserting transaction has committed */
|
@@ -781,17 +799,18 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer)
|
781 | 799 | return false;
|
782 | 800 | }
|
783 | 801 |
|
784 |
| - if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) |
| 802 | + if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) |
785 | 803 | {
|
786 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) |
787 |
| - { |
788 |
| - tuple->t_infomask |= HEAP_XMAX_INVALID; |
789 |
| - SetBufferCommitInfoNeedsSave(buffer); |
790 |
| - return true; |
791 |
| - } |
792 |
| - /* running xact */ |
793 | 804 | SnapshotDirty->xmax = HeapTupleHeaderGetXmax(tuple);
|
794 |
| - return true; /* in updation by other */ |
| 805 | + return true; |
| 806 | + } |
| 807 | + |
| 808 | + if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) |
| 809 | + { |
| 810 | + /* it must have aborted or crashed */ |
| 811 | + tuple->t_infomask |= HEAP_XMAX_INVALID; |
| 812 | + SetBufferCommitInfoNeedsSave(buffer); |
| 813 | + return true; |
795 | 814 | }
|
796 | 815 |
|
797 | 816 | /* xmax transaction committed */
|
@@ -907,19 +926,19 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot,
|
907 | 926 | else
|
908 | 927 | return false; /* deleted before scan started */
|
909 | 928 | }
|
910 |
| - else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
911 |
| - { |
912 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) |
913 |
| - { |
914 |
| - tuple->t_infomask |= HEAP_XMIN_INVALID; |
915 |
| - SetBufferCommitInfoNeedsSave(buffer); |
916 |
| - } |
| 929 | + else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) |
917 | 930 | return false;
|
| 931 | + else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) |
| 932 | + { |
| 933 | + tuple->t_infomask |= HEAP_XMIN_COMMITTED; |
| 934 | + SetBufferCommitInfoNeedsSave(buffer); |
918 | 935 | }
|
919 | 936 | else
|
920 | 937 | {
|
921 |
| - tuple->t_infomask |= HEAP_XMIN_COMMITTED; |
| 938 | + /* it must have aborted or crashed */ |
| 939 | + tuple->t_infomask |= HEAP_XMIN_INVALID; |
922 | 940 | SetBufferCommitInfoNeedsSave(buffer);
|
| 941 | + return false; |
923 | 942 | }
|
924 | 943 | }
|
925 | 944 |
|
@@ -982,13 +1001,14 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot,
|
982 | 1001 | return false; /* deleted before scan started */
|
983 | 1002 | }
|
984 | 1003 |
|
| 1004 | + if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) |
| 1005 | + return true; |
| 1006 | + |
985 | 1007 | if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
|
986 | 1008 | {
|
987 |
| - if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) |
988 |
| - { |
989 |
| - tuple->t_infomask |= HEAP_XMAX_INVALID; |
990 |
| - SetBufferCommitInfoNeedsSave(buffer); |
991 |
| - } |
| 1009 | + /* it must have aborted or crashed */ |
| 1010 | + tuple->t_infomask |= HEAP_XMAX_INVALID; |
| 1011 | + SetBufferCommitInfoNeedsSave(buffer); |
992 | 1012 | return true;
|
993 | 1013 | }
|
994 | 1014 |
|
@@ -1057,13 +1077,6 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
|
1057 | 1077 | *
|
1058 | 1078 | * If the inserting transaction aborted, then the tuple was never visible
|
1059 | 1079 | * to any other transaction, so we can delete it immediately.
|
1060 |
| - * |
1061 |
| - * NOTE: must check TransactionIdIsInProgress (which looks in PROC array) |
1062 |
| - * before TransactionIdDidCommit/TransactionIdDidAbort (which look in |
1063 |
| - * pg_clog). Otherwise we have a race condition where we might decide |
1064 |
| - * that a just-committed transaction crashed, because none of the |
1065 |
| - * tests succeed. xact.c is careful to record commit/abort in pg_clog |
1066 |
| - * before it unsets MyProc->xid in PROC array. |
1067 | 1080 | */
|
1068 | 1081 | if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
|
1069 | 1082 | {
|
|
0 commit comments