Fix for regression caused by heap tuple header changes - Mailing list pgsql-patches

From Manfred Koizar
Subject Fix for regression caused by heap tuple header changes
Date
Msg-id fn88juoppeach5avalao7ial0v41hns5h4@4ax.com
Whole thread Raw
Responses Re: Fix for regression caused by heap tuple header changes
Re: Fix for regression caused by heap tuple header changes
List pgsql-patches
This patch fixes a regression caused by my recent changes to heap
tuple header.  The fix is based on the thought that HEAP_MOVED_IN is
not needed any more as soon as HEAP_XMIN_COMMITTED has been set.  So
in tqual.c and vacuum.c the HEAP_MOVED bits are cleared when
HEAP_XMIN_COMMITTED is set.

Vacuum robustness is enhanced by rearranging ifs, so that we have a
chance to elog(ERROR, ...) before an assertion fails.

A new regression test is included.

Servus
 Manfred
diff -ruN ../base/src/backend/commands/vacuum.c src/backend/commands/vacuum.c
--- ../base/src/backend/commands/vacuum.c    2002-07-15 20:39:19.000000000 +0200
+++ src/backend/commands/vacuum.c    2002-07-16 13:41:59.000000000 +0200
@@ -1534,8 +1534,6 @@

             if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
             {
-                if (HeapTupleHeaderGetXvac(tuple.t_data) != myXID)
-                    elog(ERROR, "Invalid XVAC in tuple header");
                 if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
                     elog(ERROR, "HEAP_MOVED_IN was not expected");

@@ -1546,6 +1544,8 @@
                  */
                 if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
                 {
+                    if (HeapTupleHeaderGetXvac(tuple.t_data) != myXID)
+                        elog(ERROR, "Invalid XVAC in tuple header");
                     if (keep_tuples == 0)
                         continue;
                     if (chain_tuple_moved)        /* some chains was moved
@@ -2009,7 +2009,7 @@

             /*
              * Mark new tuple as moved_in by vacuum and store vacuum XID
-             * in t_cmin !!!
+             * in t_cid !!!
              */
             newtup.t_data->t_infomask &=
                 ~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_OFF);
@@ -2035,7 +2035,7 @@

             /*
              * Mark old tuple as moved_off by vacuum and store vacuum XID
-             * in t_cmin !!!
+             * in t_cid !!!
              */
             tuple.t_data->t_infomask &=
                 ~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN);
@@ -2088,12 +2088,12 @@
                 tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
                 if (tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED)
                     continue;
-                if (HeapTupleHeaderGetXvac(tuple.t_data) != myXID)
-                    elog(ERROR, "Invalid XVAC in tuple header (4)");
                 if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
                     elog(ERROR, "HEAP_MOVED_IN was not expected (2)");
                 if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
                 {
+                    if (HeapTupleHeaderGetXvac(tuple.t_data) != myXID)
+                        elog(ERROR, "Invalid XVAC in tuple header (4)");
                     /* some chains was moved while */
                     if (chain_tuple_moved)
                     {            /* cleaning this page */
@@ -2117,6 +2117,8 @@
                         keep_tuples--;
                     }
                 }
+                else
+                    elog(ERROR, "HEAP_MOVED_OFF was expected (2)");
             }
         }

@@ -2226,17 +2228,18 @@
             tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
             if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
             {
+                if (!(tuple.t_data->t_infomask & HEAP_MOVED))
+                    elog(ERROR, "HEAP_MOVED_OFF/HEAP_MOVED_IN was expected");
                 if (HeapTupleHeaderGetXvac(tuple.t_data) != myXID)
                     elog(ERROR, "Invalid XVAC in tuple header (2)");
                 if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
                 {
                     tuple.t_data->t_infomask |= HEAP_XMIN_COMMITTED;
+                    tuple.t_data->t_infomask &= ~HEAP_MOVED;
                     num_tuples++;
                 }
-                else if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
-                    tuple.t_data->t_infomask |= HEAP_XMIN_INVALID;
                 else
-                    elog(ERROR, "HEAP_MOVED_OFF/HEAP_MOVED_IN was expected");
+                    tuple.t_data->t_infomask |= HEAP_XMIN_INVALID;
             }
         }
         LockBuffer(buf, BUFFER_LOCK_UNLOCK);
@@ -2305,15 +2308,15 @@

                 if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
                 {
-                    if (HeapTupleHeaderGetXvac(tuple.t_data) != myXID)
-                        elog(ERROR, "Invalid XVAC in tuple header (3)");
                     if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
                     {
+                        if (HeapTupleHeaderGetXvac(tuple.t_data) != myXID)
+                            elog(ERROR, "Invalid XVAC in tuple header (3)");
                         itemid->lp_flags &= ~LP_USED;
                         num_tuples++;
                     }
                     else
-                        elog(ERROR, "HEAP_MOVED_OFF was expected (2)");
+                        elog(ERROR, "HEAP_MOVED_OFF was expected (3)");
                 }

             }
diff -ruN ../base/src/backend/utils/time/tqual.c src/backend/utils/time/tqual.c
--- ../base/src/backend/utils/time/tqual.c    2002-06-21 02:12:23.000000000 +0200
+++ src/backend/utils/time/tqual.c    2002-07-16 13:19:59.000000000 +0200
@@ -92,7 +92,10 @@
                 if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
                     return false;
                 if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
+                {
                     tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                    tuple->t_infomask &= ~HEAP_MOVED;
+                }
                 else
                 {
                     tuple->t_infomask |= HEAP_XMIN_INVALID;
@@ -219,6 +222,7 @@
                     return false;
                 }
                 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                tuple->t_infomask &= ~HEAP_MOVED;
             }
         }
         else if (tuple->t_infomask & HEAP_MOVED_IN)
@@ -228,7 +232,10 @@
                 if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
                     return false;
                 if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
+                {
                     tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                    tuple->t_infomask &= ~HEAP_MOVED;
+                }
                 else
                 {
                     tuple->t_infomask |= HEAP_XMIN_INVALID;
@@ -336,6 +343,7 @@
                     return false;
                 }
                 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                tuple->t_infomask &= ~HEAP_MOVED;
             }
         }
         else if (tuple->t_infomask & HEAP_MOVED_IN)
@@ -345,7 +353,10 @@
                 if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
                     return false;
                 if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
+                {
                     tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                    tuple->t_infomask &= ~HEAP_MOVED;
+                }
                 else
                 {
                     tuple->t_infomask |= HEAP_XMIN_INVALID;
@@ -389,6 +400,7 @@
                     return HeapTupleInvisible;
                 }
                 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                tuple->t_infomask &= ~HEAP_MOVED;
             }
         }
         else if (tuple->t_infomask & HEAP_MOVED_IN)
@@ -398,7 +410,10 @@
                 if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
                     return HeapTupleInvisible;
                 if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
+                {
                     tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                    tuple->t_infomask &= ~HEAP_MOVED;
+                }
                 else
                 {
                     tuple->t_infomask |= HEAP_XMIN_INVALID;
@@ -520,6 +535,7 @@
                     return false;
                 }
                 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                tuple->t_infomask &= ~HEAP_MOVED;
             }
         }
         else if (tuple->t_infomask & HEAP_MOVED_IN)
@@ -529,7 +545,10 @@
                 if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
                     return false;
                 if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
+                {
                     tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                    tuple->t_infomask &= ~HEAP_MOVED;
+                }
                 else
                 {
                     tuple->t_infomask |= HEAP_XMIN_INVALID;
@@ -651,6 +670,7 @@
                     return false;
                 }
                 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                tuple->t_infomask &= ~HEAP_MOVED;
             }
         }
         else if (tuple->t_infomask & HEAP_MOVED_IN)
@@ -660,7 +680,10 @@
                 if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
                     return false;
                 if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
+                {
                     tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                    tuple->t_infomask &= ~HEAP_MOVED;
+                }
                 else
                 {
                     tuple->t_infomask |= HEAP_XMIN_INVALID;
@@ -809,6 +832,7 @@
                 return HEAPTUPLE_DEAD;
             }
             tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+            tuple->t_infomask &= ~HEAP_MOVED;
         }
         else if (tuple->t_infomask & HEAP_MOVED_IN)
         {
@@ -817,7 +841,10 @@
             if (TransactionIdIsInProgress(HeapTupleHeaderGetXvac(tuple)))
                 return HEAPTUPLE_INSERT_IN_PROGRESS;
             if (TransactionIdDidCommit(HeapTupleHeaderGetXvac(tuple)))
+            {
                 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                tuple->t_infomask &= ~HEAP_MOVED;
+            }
             else
             {
                 tuple->t_infomask |= HEAP_XMIN_INVALID;
diff -ruN ../base/src/test/regress/expected/vacuum.out src/test/regress/expected/vacuum.out
--- ../base/src/test/regress/expected/vacuum.out    2002-07-16 14:12:56.000000000 +0200
+++ src/test/regress/expected/vacuum.out    2002-07-16 14:26:05.000000000 +0200
@@ -0,0 +1,59 @@
+--
+-- VACUUM
+--
+CREATE TABLE vactst (i INT);
+INSERT INTO vactst VALUES (1);
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst VALUES (0);
+SELECT count(*) FROM vactst;
+ count
+-------
+  2049
+(1 row)
+
+DELETE FROM vactst WHERE i != 0;
+SELECT * FROM vactst;
+ i
+---
+ 0
+(1 row)
+
+VACUUM FULL vactst;
+UPDATE vactst SET i = i + 1;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst VALUES (0);
+SELECT count(*) FROM vactst;
+ count
+-------
+  2049
+(1 row)
+
+DELETE FROM vactst WHERE i != 0;
+VACUUM FULL vactst;
+DELETE FROM vactst;
+SELECT * FROM vactst;
+ i
+---
+(0 rows)
+
+DROP TABLE vactst;
diff -ruN ../base/src/test/regress/parallel_schedule src/test/regress/parallel_schedule
--- ../base/src/test/regress/parallel_schedule    2002-07-10 23:29:32.000000000 +0200
+++ src/test/regress/parallel_schedule    2002-07-16 14:01:23.000000000 +0200
@@ -38,7 +38,7 @@
 # ----------
 # The third group of parallel test
 # ----------
-test: constraints triggers create_misc create_aggregate create_operator create_index inherit
+test: constraints triggers create_misc create_aggregate create_operator create_index inherit vacuum

 # Depends on the above
 test: create_view
diff -ruN ../base/src/test/regress/serial_schedule src/test/regress/serial_schedule
--- ../base/src/test/regress/serial_schedule    2002-07-10 23:31:16.000000000 +0200
+++ src/test/regress/serial_schedule    2002-07-16 14:01:45.000000000 +0200
@@ -50,6 +50,7 @@
 test: create_operator
 test: create_index
 test: inherit
+test: vacuum
 test: create_view
 test: sanity_check
 test: errors
diff -ruN ../base/src/test/regress/sql/vacuum.sql src/test/regress/sql/vacuum.sql
--- ../base/src/test/regress/sql/vacuum.sql    2002-07-16 14:36:30.000000000 +0200
+++ src/test/regress/sql/vacuum.sql    2002-07-16 14:22:43.000000000 +0200
@@ -0,0 +1,42 @@
+--
+-- VACUUM
+--
+
+CREATE TABLE vactst (i INT);
+INSERT INTO vactst VALUES (1);
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst VALUES (0);
+SELECT count(*) FROM vactst;
+DELETE FROM vactst WHERE i != 0;
+SELECT * FROM vactst;
+VACUUM FULL vactst;
+UPDATE vactst SET i = i + 1;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst SELECT * FROM vactst;
+INSERT INTO vactst VALUES (0);
+SELECT count(*) FROM vactst;
+DELETE FROM vactst WHERE i != 0;
+VACUUM FULL vactst;
+DELETE FROM vactst;
+SELECT * FROM vactst;
+
+DROP TABLE vactst;

pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: several minor cleanups
Next
From: Bruce Momjian
Date:
Subject: Re: several minor cleanups