Re: problems with table corruption continued
От | Tom Lane |
---|---|
Тема | Re: problems with table corruption continued |
Дата | |
Msg-id | 1499.1008782595@sss.pgh.pa.us обсуждение исходный текст |
Ответ на | Re: problems with table corruption continued (Tom Lane <tgl@sss.pgh.pa.us>) |
Список | 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_ thecurrent 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 currentcommand. * * 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; } } elseif (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 invalidor 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; } } elseif (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 afterscan * 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 afterscan * 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; /* insertedafter 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 afterscan * 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)) returnfalse; ! 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; } } elseif (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 ----
В списке pgsql-hackers по дате отправления: