Thread: More heap tuple header fixes

More heap tuple header fixes

From
Manfred Koizar
Date:
This patch fixes one serious bug (runaway INSERT) and a few rare (and
hard to reproduce) error conditions.

Servus
 Manfred
diff -ruN ../base/src/backend/access/heap/heapam.c src/backend/access/heap/heapam.c
--- ../base/src/backend/access/heap/heapam.c    2002-07-20 17:27:18.000000000 +0200
+++ src/backend/access/heap/heapam.c    2002-07-20 19:43:19.000000000 +0200
@@ -1123,11 +1123,14 @@
             CheckMaxObjectId(HeapTupleGetOid(tup));
     }

+    tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
     HeapTupleHeaderSetXmin(tup->t_data, GetCurrentTransactionId());
     HeapTupleHeaderSetCmin(tup->t_data, cid);
     HeapTupleHeaderSetXmaxInvalid(tup->t_data);
-    HeapTupleHeaderSetCmax(tup->t_data, FirstCommandId);
-    tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
+    /*
+     * Do *not* set Cmax!  This would overwrite Cmin.
+     */
+    /* HeapTupleHeaderSetCmax(tup->t_data, FirstCommandId); */
     tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
     tup->t_tableOid = relation->rd_id;

@@ -2147,7 +2150,11 @@

     if (redo)
     {
-        htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
+        /*
+         * On redo from WAL we cannot rely on a tqual-routine
+         * to have reset HEAP_MOVED.
+         */
+        htup->t_infomask &= ~(HEAP_MOVED | HEAP_XMAX_COMMITTED |
                               HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
         HeapTupleHeaderSetXmax(htup, record->xl_xid);
         HeapTupleHeaderSetCmax(htup, FirstCommandId);
@@ -2320,7 +2327,11 @@
         }
         else
         {
-            htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
+            /*
+             * On redo from WAL we cannot rely on a tqual-routine
+             * to have reset HEAP_MOVED.
+             */
+            htup->t_infomask &= ~(HEAP_MOVED | HEAP_XMAX_COMMITTED |
                              HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
             HeapTupleHeaderSetXmax(htup, record->xl_xid);
             HeapTupleHeaderSetCmax(htup, FirstCommandId);
diff -ruN ../base/src/backend/utils/time/tqual.c src/backend/utils/time/tqual.c
--- ../base/src/backend/utils/time/tqual.c    2002-07-20 17:27:19.000000000 +0200
+++ src/backend/utils/time/tqual.c    2002-07-20 19:27:03.000000000 +0200
@@ -83,6 +83,7 @@
                     return false;
                 }
                 tuple->t_infomask |= HEAP_XMIN_COMMITTED;
+                tuple->t_infomask &= ~HEAP_MOVED;
             }
         }
         else if (tuple->t_infomask & HEAP_MOVED_IN)

Re: More heap tuple header fixes

From
Tom Lane
Date:
Manfred Koizar <mkoi-pg@aon.at> writes:

> +    tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
>      HeapTupleHeaderSetXmin(tup->t_data, GetCurrentTransactionId());
>      HeapTupleHeaderSetCmin(tup->t_data, cid);
>      HeapTupleHeaderSetXmaxInvalid(tup->t_data);
> -    HeapTupleHeaderSetCmax(tup->t_data, FirstCommandId);
> -    tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
> +    /*
> +     * Do *not* set Cmax!  This would overwrite Cmin.
> +     */
> +    /* HeapTupleHeaderSetCmax(tup->t_data, FirstCommandId); */
>      tup->t_data->t_infomask |= HEAP_XMAX_INVALID;

This sort of thing crystallizes the vague unease I had about those
HeapTupleHeader macros.

I'd recommend redesigning the HeapTupleHeaderSet macros so that they
do not do any setting of t_infomask bits, or even take any conditional
action based on them, but solely Assert() that the bits are already
in the appropriate state to allow storing of the value to be stored.
Then, all uses have to be checked to ensure that t_infomask is coerced
into the right state *before* doing HeapTupleHeaderSetFoo.  Anything
else is subject to order-of-operations mistakes that were not errors
before, and cannot be detected by the macros as now defined.  The
cmax-set-is-not-okay bug illustrated above is a perfect example of
what I'm talking about.

            regards, tom lane

Re: More heap tuple header fixes

From
Manfred Koizar
Date:
On Sat, 20 Jul 2002 16:27:14 -0400, Tom Lane <tgl@sss.pgh.pa.us>
wrote:
>I'd recommend redesigning the HeapTupleHeaderSet macros so that they
>do not do any setting of t_infomask bits, or even take any conditional
>action based on them,

The HEAP_XMIN_IS_XMAX bit is exclusively managed by these macros.
Pulling the handling of this bit out of the macros and spreading it to
the places, where the macros are used, cannot make the whole thing
more robust.  This would mean, the caller had to decide whether to
store Cmax into t_cid or t_xmax...

> but solely Assert() that the bits are already
>in the appropriate state to allow storing of the value to be stored.
>Then, all uses have to be checked to ensure that t_infomask is coerced
>into the right state *before* doing HeapTupleHeaderSetFoo.

Apart from HEAP_XMIN_IS_XMAX this was my intention;  we already do
this with HEAP_MOVED.  I could add an assertion to SetCmax:
    Assert(!((tup)->t_infomask & HEAP_XMAX_INVALID));

OTOH I thought about putting *more* logic into the macros to make
their use less fragile.  For example SetXmaxInvalid could set the
HEAP_XMAX_INVALID bit, likewise SetCminInvalid with XMIN_INVALID.

Anyway, with this patch applied the heap tuple header changes should
be able to survive the next two weeks.  I don't want to hack together
a quick change now, before I go on vacation.  Let's find the perfect
solution, when I'm back ...

Servus
 Manfred

Re: More heap tuple header fixes

From
Tom Lane
Date:
Manfred Koizar <mkoi-pg@aon.at> writes:
> On Sat, 20 Jul 2002 16:27:14 -0400, Tom Lane <tgl@sss.pgh.pa.us>
> wrote:
>> I'd recommend redesigning the HeapTupleHeaderSet macros so that they
>> do not do any setting of t_infomask bits, or even take any conditional
>> action based on them,

> The HEAP_XMIN_IS_XMAX bit is exclusively managed by these macros.
> Pulling the handling of this bit out of the macros and spreading it to
> the places, where the macros are used, cannot make the whole thing
> more robust.  This would mean, the caller had to decide whether to
> store Cmax into t_cid or t_xmax...

But the present scheme is very obviously not robust.

> Anyway, with this patch applied the heap tuple header changes should
> be able to survive the next two weeks.  I don't want to hack together
> a quick change now, before I go on vacation.  Let's find the perfect
> solution, when I'm back ...

I'm on the road too.  But I want to see a different solution before
we release.  I do not trust the current code at all.

            regards, tom lane

Re: More heap tuple header fixes

From
Bruce Momjian
Date:
Your patch has been added to the PostgreSQL unapplied patches list at:

    http://candle.pha.pa.us/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------


Manfred Koizar wrote:
> On Sat, 20 Jul 2002 16:27:14 -0400, Tom Lane <tgl@sss.pgh.pa.us>
> wrote:
> >I'd recommend redesigning the HeapTupleHeaderSet macros so that they
> >do not do any setting of t_infomask bits, or even take any conditional
> >action based on them,
>
> The HEAP_XMIN_IS_XMAX bit is exclusively managed by these macros.
> Pulling the handling of this bit out of the macros and spreading it to
> the places, where the macros are used, cannot make the whole thing
> more robust.  This would mean, the caller had to decide whether to
> store Cmax into t_cid or t_xmax...
>
> > but solely Assert() that the bits are already
> >in the appropriate state to allow storing of the value to be stored.
> >Then, all uses have to be checked to ensure that t_infomask is coerced
> >into the right state *before* doing HeapTupleHeaderSetFoo.
>
> Apart from HEAP_XMIN_IS_XMAX this was my intention;  we already do
> this with HEAP_MOVED.  I could add an assertion to SetCmax:
>     Assert(!((tup)->t_infomask & HEAP_XMAX_INVALID));
>
> OTOH I thought about putting *more* logic into the macros to make
> their use less fragile.  For example SetXmaxInvalid could set the
> HEAP_XMAX_INVALID bit, likewise SetCminInvalid with XMIN_INVALID.
>
> Anyway, with this patch applied the heap tuple header changes should
> be able to survive the next two weeks.  I don't want to hack together
> a quick change now, before I go on vacation.  Let's find the perfect
> solution, when I'm back ...
>
> Servus
>  Manfred
>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
> subscribe-nomail command to majordomo@postgresql.org so that your
> message can get through to the mailing list cleanly
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: More heap tuple header fixes

From
Bruce Momjian
Date:
Your patch has been added to the PostgreSQL unapplied patches list at:

    http://candle.pha.pa.us/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------


Manfred Koizar wrote:
> This patch fixes one serious bug (runaway INSERT) and a few rare (and
> hard to reproduce) error conditions.
>
> Servus
>  Manfred

> diff -ruN ../base/src/backend/access/heap/heapam.c src/backend/access/heap/heapam.c
> --- ../base/src/backend/access/heap/heapam.c    2002-07-20 17:27:18.000000000 +0200
> +++ src/backend/access/heap/heapam.c    2002-07-20 19:43:19.000000000 +0200
> @@ -1123,11 +1123,14 @@
>              CheckMaxObjectId(HeapTupleGetOid(tup));
>      }
>
> +    tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
>      HeapTupleHeaderSetXmin(tup->t_data, GetCurrentTransactionId());
>      HeapTupleHeaderSetCmin(tup->t_data, cid);
>      HeapTupleHeaderSetXmaxInvalid(tup->t_data);
> -    HeapTupleHeaderSetCmax(tup->t_data, FirstCommandId);
> -    tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
> +    /*
> +     * Do *not* set Cmax!  This would overwrite Cmin.
> +     */
> +    /* HeapTupleHeaderSetCmax(tup->t_data, FirstCommandId); */
>      tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
>      tup->t_tableOid = relation->rd_id;
>
> @@ -2147,7 +2150,11 @@
>
>      if (redo)
>      {
> -        htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
> +        /*
> +         * On redo from WAL we cannot rely on a tqual-routine
> +         * to have reset HEAP_MOVED.
> +         */
> +        htup->t_infomask &= ~(HEAP_MOVED | HEAP_XMAX_COMMITTED |
>                                HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
>          HeapTupleHeaderSetXmax(htup, record->xl_xid);
>          HeapTupleHeaderSetCmax(htup, FirstCommandId);
> @@ -2320,7 +2327,11 @@
>          }
>          else
>          {
> -            htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
> +            /*
> +             * On redo from WAL we cannot rely on a tqual-routine
> +             * to have reset HEAP_MOVED.
> +             */
> +            htup->t_infomask &= ~(HEAP_MOVED | HEAP_XMAX_COMMITTED |
>                               HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
>              HeapTupleHeaderSetXmax(htup, record->xl_xid);
>              HeapTupleHeaderSetCmax(htup, FirstCommandId);
> diff -ruN ../base/src/backend/utils/time/tqual.c src/backend/utils/time/tqual.c
> --- ../base/src/backend/utils/time/tqual.c    2002-07-20 17:27:19.000000000 +0200
> +++ src/backend/utils/time/tqual.c    2002-07-20 19:27:03.000000000 +0200
> @@ -83,6 +83,7 @@
>                      return false;
>                  }
>                  tuple->t_infomask |= HEAP_XMIN_COMMITTED;
> +                tuple->t_infomask &= ~HEAP_MOVED;
>              }
>          }
>          else if (tuple->t_infomask & HEAP_MOVED_IN)

>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/users-lounge/docs/faq.html

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: More heap tuple header fixes

From
Bruce Momjian
Date:
Patch applied.  Thanks.

---------------------------------------------------------------------------


Manfred Koizar wrote:
> This patch fixes one serious bug (runaway INSERT) and a few rare (and
> hard to reproduce) error conditions.
>
> Servus
>  Manfred

> diff -ruN ../base/src/backend/access/heap/heapam.c src/backend/access/heap/heapam.c
> --- ../base/src/backend/access/heap/heapam.c    2002-07-20 17:27:18.000000000 +0200
> +++ src/backend/access/heap/heapam.c    2002-07-20 19:43:19.000000000 +0200
> @@ -1123,11 +1123,14 @@
>              CheckMaxObjectId(HeapTupleGetOid(tup));
>      }
>
> +    tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
>      HeapTupleHeaderSetXmin(tup->t_data, GetCurrentTransactionId());
>      HeapTupleHeaderSetCmin(tup->t_data, cid);
>      HeapTupleHeaderSetXmaxInvalid(tup->t_data);
> -    HeapTupleHeaderSetCmax(tup->t_data, FirstCommandId);
> -    tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
> +    /*
> +     * Do *not* set Cmax!  This would overwrite Cmin.
> +     */
> +    /* HeapTupleHeaderSetCmax(tup->t_data, FirstCommandId); */
>      tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
>      tup->t_tableOid = relation->rd_id;
>
> @@ -2147,7 +2150,11 @@
>
>      if (redo)
>      {
> -        htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
> +        /*
> +         * On redo from WAL we cannot rely on a tqual-routine
> +         * to have reset HEAP_MOVED.
> +         */
> +        htup->t_infomask &= ~(HEAP_MOVED | HEAP_XMAX_COMMITTED |
>                                HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
>          HeapTupleHeaderSetXmax(htup, record->xl_xid);
>          HeapTupleHeaderSetCmax(htup, FirstCommandId);
> @@ -2320,7 +2327,11 @@
>          }
>          else
>          {
> -            htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
> +            /*
> +             * On redo from WAL we cannot rely on a tqual-routine
> +             * to have reset HEAP_MOVED.
> +             */
> +            htup->t_infomask &= ~(HEAP_MOVED | HEAP_XMAX_COMMITTED |
>                               HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
>              HeapTupleHeaderSetXmax(htup, record->xl_xid);
>              HeapTupleHeaderSetCmax(htup, FirstCommandId);
> diff -ruN ../base/src/backend/utils/time/tqual.c src/backend/utils/time/tqual.c
> --- ../base/src/backend/utils/time/tqual.c    2002-07-20 17:27:19.000000000 +0200
> +++ src/backend/utils/time/tqual.c    2002-07-20 19:27:03.000000000 +0200
> @@ -83,6 +83,7 @@
>                      return false;
>                  }
>                  tuple->t_infomask |= HEAP_XMIN_COMMITTED;
> +                tuple->t_infomask &= ~HEAP_MOVED;
>              }
>          }
>          else if (tuple->t_infomask & HEAP_MOVED_IN)

>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/users-lounge/docs/faq.html

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026