Re: problems with table corruption continued

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: "Mikheev, Vadim" <vmikheev(at)SECTORBASE(dot)COM>, Postgres Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: problems with table corruption continued
Date: 2001-12-19 17:23:15
Message-ID: 1499.1008782595@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Okay, I've applied the attached patch to tqual.c. This brings all the
variants of HeapTupleSatisfies up to speed: I have compared them
carefully and they now all make equivalent series of tests on the tuple
status (though they may interpret the results differently).

I decided that Hiroshi had a good point about testing
TransactionIdIsInProgress, so the code now does that before risking
a change to t_infomask, even in the VACUUM cases.

regards, tom lane

*** src/backend/utils/time/tqual.c.orig Mon Oct 29 15:31:08 2001
--- src/backend/utils/time/tqual.c Wed Dec 19 12:09:32 2001
***************
*** 31,37 ****
/*
* HeapTupleSatisfiesItself
* True iff heap tuple is valid for "itself."
! * "{it}self" means valid as of everything that's happened
* in the current transaction, _including_ the current command.
*
* Note:
--- 31,37 ----
/*
* HeapTupleSatisfiesItself
* True iff heap tuple is valid for "itself."
! * "itself" means valid as of everything that's happened
* in the current transaction, _including_ the current command.
*
* Note:
***************
*** 53,59 ****
bool
HeapTupleSatisfiesItself(HeapTupleHeader tuple)
{
-
if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
{
if (tuple->t_infomask & HEAP_XMIN_INVALID)
--- 53,58 ----
***************
*** 61,86 ****

if (tuple->t_infomask & HEAP_MOVED_OFF)
{
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! {
! tuple->t_infomask |= HEAP_XMIN_INVALID;
return false;
}
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
! if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
{
! tuple->t_infomask |= HEAP_XMIN_INVALID;
! return false;
}
}
else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
{
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return true;
if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
return true;
return false;
}
else if (!TransactionIdDidCommit(tuple->t_xmin))
--- 60,102 ----

if (tuple->t_infomask & HEAP_MOVED_OFF)
{
! if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
return false;
+ if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ {
+ if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
+ {
+ tuple->t_infomask |= HEAP_XMIN_INVALID;
+ return false;
+ }
+ tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
! if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
{
! if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! return false;
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! else
! {
! tuple->t_infomask |= HEAP_XMIN_INVALID;
! return false;
! }
}
}
else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
{
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return true;
+
+ Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax));
+
if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
return true;
+
return false;
}
else if (!TransactionIdDidCommit(tuple->t_xmin))
***************
*** 89,97 ****
tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return false;
}
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
! /* the tuple was inserted validly */

if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
return true;
--- 105,115 ----
tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return false;
}
! else
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
!
! /* by here, the inserting transaction has committed */

if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
return true;
***************
*** 117,123 ****
return true;
}

! /* by here, deleting transaction has committed */
tuple->t_infomask |= HEAP_XMAX_COMMITTED;

if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
--- 135,141 ----
return true;
}

! /* xmax transaction committed */
tuple->t_infomask |= HEAP_XMAX_COMMITTED;

if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
***************
*** 177,194 ****

if (tuple->t_infomask & HEAP_MOVED_OFF)
{
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! {
! tuple->t_infomask |= HEAP_XMIN_INVALID;
return false;
}
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
! if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
{
! tuple->t_infomask |= HEAP_XMIN_INVALID;
! return false;
}
}
else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
--- 195,225 ----

if (tuple->t_infomask & HEAP_MOVED_OFF)
{
! if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
return false;
+ if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ {
+ if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
+ {
+ tuple->t_infomask |= HEAP_XMIN_INVALID;
+ return false;
+ }
+ tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
! if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
{
! if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! return false;
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! else
! {
! tuple->t_infomask |= HEAP_XMIN_INVALID;
! return false;
! }
}
}
else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
***************
*** 215,221 ****
tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return false;
}
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}

/* by here, the inserting transaction has committed */
--- 246,253 ----
tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return false;
}
! else
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}

/* by here, the inserting transaction has committed */
***************
*** 257,348 ****
}

int
! HeapTupleSatisfiesUpdate(HeapTuple tuple)
{
! HeapTupleHeader th = tuple->t_data;

if (AMI_OVERRIDE)
return HeapTupleMayBeUpdated;

! if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
{
! if (th->t_infomask & HEAP_XMIN_INVALID) /* xid invalid or aborted */
return HeapTupleInvisible;

! if (th->t_infomask & HEAP_MOVED_OFF)
{
! if (TransactionIdDidCommit((TransactionId) th->t_cmin))
! {
! th->t_infomask |= HEAP_XMIN_INVALID;
return HeapTupleInvisible;
}
}
! else if (th->t_infomask & HEAP_MOVED_IN)
{
! if (!TransactionIdDidCommit((TransactionId) th->t_cmin))
{
! th->t_infomask |= HEAP_XMIN_INVALID;
! return HeapTupleInvisible;
}
}
! else if (TransactionIdIsCurrentTransactionId(th->t_xmin))
{
! if (CommandIdGEScanCommandId(th->t_cmin))
return HeapTupleInvisible; /* inserted after scan
* started */

! if (th->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return HeapTupleMayBeUpdated;

! Assert(TransactionIdIsCurrentTransactionId(th->t_xmax));

! if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
return HeapTupleMayBeUpdated;

! if (CommandIdGEScanCommandId(th->t_cmax))
return HeapTupleSelfUpdated; /* updated after scan
* started */
else
return HeapTupleInvisible; /* updated before scan
* started */
}
! else if (!TransactionIdDidCommit(th->t_xmin))
{
! if (TransactionIdDidAbort(th->t_xmin))
! th->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return HeapTupleInvisible;
}
! th->t_infomask |= HEAP_XMIN_COMMITTED;
}

/* by here, the inserting transaction has committed */

! if (th->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
return HeapTupleMayBeUpdated;

! if (th->t_infomask & HEAP_XMAX_COMMITTED)
{
! if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
return HeapTupleMayBeUpdated;
return HeapTupleUpdated; /* updated by other */
}

! if (TransactionIdIsCurrentTransactionId(th->t_xmax))
{
! if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
return HeapTupleMayBeUpdated;
! if (CommandIdGEScanCommandId(th->t_cmax))
return HeapTupleSelfUpdated; /* updated after scan
* started */
else
return HeapTupleInvisible; /* updated before scan started */
}

! if (!TransactionIdDidCommit(th->t_xmax))
{
! if (TransactionIdDidAbort(th->t_xmax))
{
! th->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
return HeapTupleMayBeUpdated;
}
/* running xact */
--- 289,394 ----
}

int
! HeapTupleSatisfiesUpdate(HeapTuple htuple)
{
! HeapTupleHeader tuple = htuple->t_data;

if (AMI_OVERRIDE)
return HeapTupleMayBeUpdated;

! if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
{
! if (tuple->t_infomask & HEAP_XMIN_INVALID)
return HeapTupleInvisible;

! if (tuple->t_infomask & HEAP_MOVED_OFF)
{
! if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
return HeapTupleInvisible;
+ if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ {
+ if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
+ {
+ tuple->t_infomask |= HEAP_XMIN_INVALID;
+ return HeapTupleInvisible;
+ }
+ tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
}
! else if (tuple->t_infomask & HEAP_MOVED_IN)
{
! if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
{
! if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! return HeapTupleInvisible;
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! else
! {
! tuple->t_infomask |= HEAP_XMIN_INVALID;
! return HeapTupleInvisible;
! }
}
}
! else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
{
! if (CommandIdGEScanCommandId(tuple->t_cmin))
return HeapTupleInvisible; /* inserted after scan
* started */

! if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return HeapTupleMayBeUpdated;

! Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax));

! if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
return HeapTupleMayBeUpdated;

! if (CommandIdGEScanCommandId(tuple->t_cmax))
return HeapTupleSelfUpdated; /* updated after scan
* started */
else
return HeapTupleInvisible; /* updated before scan
* started */
}
! else if (!TransactionIdDidCommit(tuple->t_xmin))
{
! if (TransactionIdDidAbort(tuple->t_xmin))
! tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return HeapTupleInvisible;
}
! else
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}

/* by here, the inserting transaction has committed */

! if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
return HeapTupleMayBeUpdated;

! if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{
! if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
return HeapTupleMayBeUpdated;
return HeapTupleUpdated; /* updated by other */
}

! if (TransactionIdIsCurrentTransactionId(tuple->t_xmax))
{
! if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
return HeapTupleMayBeUpdated;
! if (CommandIdGEScanCommandId(tuple->t_cmax))
return HeapTupleSelfUpdated; /* updated after scan
* started */
else
return HeapTupleInvisible; /* updated before scan started */
}

! if (!TransactionIdDidCommit(tuple->t_xmax))
{
! if (TransactionIdDidAbort(tuple->t_xmax))
{
! tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */
return HeapTupleMayBeUpdated;
}
/* running xact */
***************
*** 350,358 ****
}

/* xmax transaction committed */
! th->t_infomask |= HEAP_XMAX_COMMITTED;

! if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
return HeapTupleMayBeUpdated;

return HeapTupleUpdated; /* updated by other */
--- 396,404 ----
}

/* xmax transaction committed */
! tuple->t_infomask |= HEAP_XMAX_COMMITTED;

! if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
return HeapTupleMayBeUpdated;

return HeapTupleUpdated; /* updated by other */
***************
*** 374,396 ****

if (tuple->t_infomask & HEAP_MOVED_OFF)
{
- /*
- * HeapTupleSatisfiesDirty is used by unique btree-s and so
- * may be used while vacuuming.
- */
if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
return false;
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
{
! tuple->t_infomask |= HEAP_XMIN_INVALID;
! return false;
}
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
{
if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
tuple->t_infomask |= HEAP_XMIN_COMMITTED;
else
--- 420,443 ----

if (tuple->t_infomask & HEAP_MOVED_OFF)
{
if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
return false;
! if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
{
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! {
! tuple->t_infomask |= HEAP_XMIN_INVALID;
! return false;
! }
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
{
+ if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ return false;
if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
tuple->t_infomask |= HEAP_XMIN_COMMITTED;
else
***************
*** 416,425 ****
{
if (TransactionIdDidAbort(tuple->t_xmin))
{
! tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return false;
}
SnapshotDirty->xmin = tuple->t_xmin;
return true; /* in insertion by other */
}
else
--- 463,473 ----
{
if (TransactionIdDidAbort(tuple->t_xmin))
{
! tuple->t_infomask |= HEAP_XMIN_INVALID;
return false;
}
SnapshotDirty->xmin = tuple->t_xmin;
+ /* XXX shouldn't we fall through to look at xmax? */
return true; /* in insertion by other */
}
else
***************
*** 474,479 ****
--- 522,528 ----
if (AMI_OVERRIDE)
return true;

+ /* XXX this is horribly ugly: */
if (ReferentialIntegritySnapshotOverride)
return HeapTupleSatisfiesNow(tuple);

***************
*** 484,501 ****

if (tuple->t_infomask & HEAP_MOVED_OFF)
{
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! {
! tuple->t_infomask |= HEAP_XMIN_INVALID;
return false;
}
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
! if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
{
! tuple->t_infomask |= HEAP_XMIN_INVALID;
! return false;
}
}
else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
--- 533,563 ----

if (tuple->t_infomask & HEAP_MOVED_OFF)
{
! if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
return false;
+ if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ {
+ if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
+ {
+ tuple->t_infomask |= HEAP_XMIN_INVALID;
+ return false;
+ }
+ tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
! if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
{
! if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! return false;
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! else
! {
! tuple->t_infomask |= HEAP_XMIN_INVALID;
! return false;
! }
}
}
else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
***************
*** 519,528 ****
else if (!TransactionIdDidCommit(tuple->t_xmin))
{
if (TransactionIdDidAbort(tuple->t_xmin))
! tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
return false;
}
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}

/*
--- 581,591 ----
else if (!TransactionIdDidCommit(tuple->t_xmin))
{
if (TransactionIdDidAbort(tuple->t_xmin))
! tuple->t_infomask |= HEAP_XMIN_INVALID;
return false;
}
! else
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}

/*
***************
*** 623,646 ****
return HEAPTUPLE_DEAD;
else if (tuple->t_infomask & HEAP_MOVED_OFF)
{
if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
{
tuple->t_infomask |= HEAP_XMIN_INVALID;
return HEAPTUPLE_DEAD;
}
- /* Assume we can only get here if previous VACUUM aborted, */
- /* ie, it couldn't still be in progress */
tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
! if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
{
- /* Assume we can only get here if previous VACUUM aborted */
tuple->t_infomask |= HEAP_XMIN_INVALID;
return HEAPTUPLE_DEAD;
}
- tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
else if (TransactionIdIsInProgress(tuple->t_xmin))
return HEAPTUPLE_INSERT_IN_PROGRESS;
--- 686,715 ----
return HEAPTUPLE_DEAD;
else if (tuple->t_infomask & HEAP_MOVED_OFF)
{
+ if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
+ return HEAPTUPLE_DELETE_IN_PROGRESS;
+ if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
+ return HEAPTUPLE_DELETE_IN_PROGRESS;
if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
{
tuple->t_infomask |= HEAP_XMIN_INVALID;
return HEAPTUPLE_DEAD;
}
tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
! if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
! return HEAPTUPLE_INSERT_IN_PROGRESS;
! if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
! return HEAPTUPLE_INSERT_IN_PROGRESS;
! if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
! tuple->t_infomask |= HEAP_XMIN_COMMITTED;
! else
{
tuple->t_infomask |= HEAP_XMIN_INVALID;
return HEAPTUPLE_DEAD;
}
}
else if (TransactionIdIsInProgress(tuple->t_xmin))
return HEAPTUPLE_INSERT_IN_PROGRESS;
***************
*** 671,676 ****
--- 740,751 ----
if (tuple->t_infomask & HEAP_XMAX_INVALID)
return HEAPTUPLE_LIVE;

+ if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
+ {
+ /* "deleting" xact really only marked it for update */
+ return HEAPTUPLE_LIVE;
+ }
+
if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
{
if (TransactionIdIsInProgress(tuple->t_xmax))
***************
*** 698,709 ****
/*
* Deleter committed, but check special cases.
*/
-
- if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
- {
- /* "deleting" xact really only marked it for update */
- return HEAPTUPLE_LIVE;
- }

if (TransactionIdEquals(tuple->t_xmin, tuple->t_xmax))
{
--- 773,778 ----

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Luis Amigo 2001-12-19 17:25:22 7.2b4 on irix6.5.13
Previous Message Thomas Lockhart 2001-12-19 15:48:43 Re: FreeBSD/alpha