tqual.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,080 行 · 第 1/3 页
C
1,080 行
return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) tuple->t_infomask |= HEAP_XMIN_INVALID; return false; } else tuple->t_infomask |= HEAP_XMIN_COMMITTED; } /* * By here, the inserting transaction has committed - have to check * when... */ if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmin(tuple), snapshot->xmin)) { uint32 i; if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmin(tuple), snapshot->xmax)) return false; for (i = 0; i < snapshot->xcnt; i++) { if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple), snapshot->xip[i])) return false; } } if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return true; if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) return true; if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) { if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple))) { if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */ return true; } /* xmax transaction committed */ tuple->t_infomask |= HEAP_XMAX_COMMITTED; } /* * OK, the deleting transaction committed too ... but when? */ if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmax(tuple), snapshot->xmin)) { uint32 i; if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmax(tuple), snapshot->xmax)) return true; for (i = 0; i < snapshot->xcnt; i++) { if (TransactionIdEquals(HeapTupleHeaderGetXmax(tuple), snapshot->xip[i])) return true; } } return false;}/* * HeapTupleSatisfiesVacuum * * Determine the status of tuples for VACUUM purposes. Here, what * we mainly want to know is if a tuple is potentially visible to *any* * running transaction. If so, it can't be removed yet by VACUUM. * * OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might * still be visible to some open transaction, so we can't remove them, * even if we see that the deleting transaction has committed. */HTSV_ResultHeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin){ /* * Has inserting transaction committed? * * If the inserting transaction aborted, then the tuple was never visible * to any other transaction, so we can delete it immediately. * * NOTE: must check TransactionIdIsInProgress (which looks in PROC array) * before TransactionIdDidCommit/TransactionIdDidAbort (which look in * pg_clog). Otherwise we have a race condition where we might decide * that a just-committed transaction crashed, because none of the * tests succeed. xact.c is careful to record commit/abort in pg_clog * before it unsets MyProc->xid in PROC array. */ if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) return HEAPTUPLE_DEAD; else if (tuple->t_infomask & HEAP_MOVED_OFF) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (TransactionIdIsCurrentTransactionId(xvac)) return HEAPTUPLE_DELETE_IN_PROGRESS; if (TransactionIdIsInProgress(xvac)) return HEAPTUPLE_DELETE_IN_PROGRESS; if (TransactionIdDidCommit(xvac)) { tuple->t_infomask |= HEAP_XMIN_INVALID; return HEAPTUPLE_DEAD; } tuple->t_infomask |= HEAP_XMIN_COMMITTED; } else if (tuple->t_infomask & HEAP_MOVED_IN) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (TransactionIdIsCurrentTransactionId(xvac)) return HEAPTUPLE_INSERT_IN_PROGRESS; if (TransactionIdIsInProgress(xvac)) return HEAPTUPLE_INSERT_IN_PROGRESS; if (TransactionIdDidCommit(xvac)) tuple->t_infomask |= HEAP_XMIN_COMMITTED; else { tuple->t_infomask |= HEAP_XMIN_INVALID; return HEAPTUPLE_DEAD; } } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) { if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ return HEAPTUPLE_INSERT_IN_PROGRESS; Assert(HeapTupleHeaderGetXmin(tuple) == HeapTupleHeaderGetXmax(tuple)); if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) return HEAPTUPLE_INSERT_IN_PROGRESS; /* inserted and then deleted by same xact */ return HEAPTUPLE_DELETE_IN_PROGRESS; } else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) tuple->t_infomask |= HEAP_XMIN_COMMITTED; else { /* * Not in Progress, Not Committed, so either Aborted or * crashed */ tuple->t_infomask |= HEAP_XMIN_INVALID; return HEAPTUPLE_DEAD; } /* Should only get here if we set XMIN_COMMITTED */ Assert(tuple->t_infomask & HEAP_XMIN_COMMITTED); } /* * Okay, the inserter committed, so it was good at some point. Now * what about the deleting transaction? */ 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, so the tuple * is live in any case. However, we must make sure that either * XMAX_COMMITTED or XMAX_INVALID gets set once the xact is gone; * otherwise it is unsafe to recycle CLOG status after vacuuming. */ if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) { if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) return HEAPTUPLE_LIVE; /* * We don't really care whether xmax did commit, abort or * crash. We know that xmax did mark the tuple for update, but * it did not and will never actually update it. */ tuple->t_infomask |= HEAP_XMAX_INVALID; } return HEAPTUPLE_LIVE; } if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) { if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) return HEAPTUPLE_DELETE_IN_PROGRESS; else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) tuple->t_infomask |= HEAP_XMAX_COMMITTED; else { /* * Not in Progress, Not Committed, so either Aborted or * crashed */ tuple->t_infomask |= HEAP_XMAX_INVALID; return HEAPTUPLE_LIVE; } /* Should only get here if we set XMAX_COMMITTED */ Assert(tuple->t_infomask & HEAP_XMAX_COMMITTED); } /* * Deleter committed, but check special cases. */ if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple), HeapTupleHeaderGetXmax(tuple))) { /* * inserter also deleted it, so it was never visible to anyone * else */ return HEAPTUPLE_DEAD; } if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin)) { /* deleting xact is too recent, tuple could still be visible */ return HEAPTUPLE_RECENTLY_DEAD; } /* Otherwise, it's dead and removable */ return HEAPTUPLE_DEAD;}/* * SetQuerySnapshot * Initialize query snapshot for a new query * * The SerializableSnapshot is the first one taken in a transaction. * In serializable mode we just use that one throughout the transaction. * In read-committed mode, we take a new snapshot at the start of each query. */voidSetQuerySnapshot(void){ /* 1st call in xaction? */ if (SerializableSnapshot == NULL) { SerializableSnapshot = GetSnapshotData(&SerializableSnapshotData, true); QuerySnapshot = SerializableSnapshot; Assert(QuerySnapshot != NULL); return; } if (XactIsoLevel == XACT_SERIALIZABLE) QuerySnapshot = SerializableSnapshot; else QuerySnapshot = GetSnapshotData(&QuerySnapshotData, false); Assert(QuerySnapshot != NULL);}/* * CopyQuerySnapshot * Copy the current query snapshot. * * Copying the snapshot is done so that a query is guaranteed to use a * consistent snapshot for its entire execution life, even if the command * counter is incremented or SetQuerySnapshot() is called while it runs * (as could easily happen, due to triggers etc. executing queries). * * The copy is palloc'd in the current memory context. */SnapshotCopyQuerySnapshot(void){ Snapshot snapshot; if (QuerySnapshot == NULL) /* should be set beforehand */ elog(ERROR, "no snapshot has been set"); snapshot = (Snapshot) palloc(sizeof(SnapshotData)); memcpy(snapshot, QuerySnapshot, sizeof(SnapshotData)); if (snapshot->xcnt > 0) { snapshot->xip = (TransactionId *) palloc(snapshot->xcnt * sizeof(TransactionId)); memcpy(snapshot->xip, QuerySnapshot->xip, snapshot->xcnt * sizeof(TransactionId)); } else snapshot->xip = NULL; return snapshot;}/* * CopyCurrentSnapshot * Make a snapshot that is up-to-date as of the current instant, * and return a copy. * * The copy is palloc'd in the current memory context. */SnapshotCopyCurrentSnapshot(void){ Snapshot currentSnapshot; Snapshot snapshot; if (QuerySnapshot == NULL) /* should not be first call in xact */ elog(ERROR, "no snapshot has been set"); /* Update the static struct */ currentSnapshot = GetSnapshotData(&CurrentSnapshotData, false); currentSnapshot->curcid = GetCurrentCommandId(); /* Make a copy */ snapshot = (Snapshot) palloc(sizeof(SnapshotData)); memcpy(snapshot, currentSnapshot, sizeof(SnapshotData)); if (snapshot->xcnt > 0) { snapshot->xip = (TransactionId *) palloc(snapshot->xcnt * sizeof(TransactionId)); memcpy(snapshot->xip, currentSnapshot->xip, snapshot->xcnt * sizeof(TransactionId)); } else snapshot->xip = NULL; return snapshot;}/* * FreeXactSnapshot * Free snapshot(s) at end of transaction. */voidFreeXactSnapshot(void){ /* * We do not free the xip arrays for the snapshot structs; * they will be reused soon. So this is now just a state * change to prevent outside callers from accessing the snapshots. */ QuerySnapshot = NULL; SerializableSnapshot = NULL;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?