📄 tqual.c
字号:
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ return true; if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */ return true; Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI)); /* deleting subtransaction aborted? */ /* FIXME -- is this correct w.r.t. the cmax of the tuple? */ if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) { tuple->t_infomask |= HEAP_XMAX_INVALID; SetBufferCommitInfoNeedsSave(buffer); return true; } Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple))); if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) return false; else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) { tuple->t_infomask |= HEAP_XMIN_COMMITTED; SetBufferCommitInfoNeedsSave(buffer); } else { /* it must have aborted or crashed */ tuple->t_infomask |= HEAP_XMIN_INVALID; SetBufferCommitInfoNeedsSave(buffer); return false; } } /* * By here, the inserting transaction has committed - have to check * when... * * Note that the provided snapshot contains only top-level XIDs, so we * have to convert a subxact XID to its parent for comparison. However, we * can make first-pass range checks with the given XID, because a subxact * with XID < xmin has surely also got a parent with XID < xmin, while one * with XID >= xmax must belong to a parent that was not yet committed at * the time of this snapshot. */ if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmin(tuple), snapshot->xmin)) { TransactionId parentXid; if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmin(tuple), snapshot->xmax)) return false; parentXid = SubTransGetTopmostTransaction(HeapTupleHeaderGetXmin(tuple)); if (TransactionIdFollowsOrEquals(parentXid, snapshot->xmin)) { uint32 i; /* no point in checking parentXid against xmax here */ for (i = 0; i < snapshot->xcnt; i++) { if (TransactionIdEquals(parentXid, snapshot->xip[i])) return false; } } } if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return true; if (tuple->t_infomask & HEAP_IS_LOCKED) return true; if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { /* MultiXacts are currently only allowed to lock tuples */ Assert(tuple->t_infomask & HEAP_IS_LOCKED); 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 (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) return true; if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) { /* it must have aborted or crashed */ tuple->t_infomask |= HEAP_XMAX_INVALID; SetBufferCommitInfoNeedsSave(buffer); return true; } /* xmax transaction committed */ tuple->t_infomask |= HEAP_XMAX_COMMITTED; SetBufferCommitInfoNeedsSave(buffer); } /* * OK, the deleting transaction committed too ... but when? * * See notes for the similar tests on tuple xmin, above. */ if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmax(tuple), snapshot->xmin)) { TransactionId parentXid; if (TransactionIdFollowsOrEquals(HeapTupleHeaderGetXmax(tuple), snapshot->xmax)) return true; parentXid = SubTransGetTopmostTransaction(HeapTupleHeaderGetXmax(tuple)); if (TransactionIdFollowsOrEquals(parentXid, snapshot->xmin)) { uint32 i; /* no point in checking parentXid against xmax here */ for (i = 0; i < snapshot->xcnt; i++) { if (TransactionIdEquals(parentXid, snapshot->xip[i])) return true; } } }/* This is to be used only for disaster recovery and requires serious analysis. */#ifndef MAKE_EXPIRED_TUPLES_VISIBLE return false;#else return true;#endif}/* * 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, Buffer buffer){ /* * 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. */ 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; SetBufferCommitInfoNeedsSave(buffer); return HEAPTUPLE_DEAD; } tuple->t_infomask |= HEAP_XMIN_COMMITTED; SetBufferCommitInfoNeedsSave(buffer); } 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; SetBufferCommitInfoNeedsSave(buffer); } else { tuple->t_infomask |= HEAP_XMIN_INVALID; SetBufferCommitInfoNeedsSave(buffer); return HEAPTUPLE_DEAD; } } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) { if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ return HEAPTUPLE_INSERT_IN_PROGRESS; if (tuple->t_infomask & HEAP_IS_LOCKED) 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; SetBufferCommitInfoNeedsSave(buffer); } else { /* * Not in Progress, Not Committed, so either Aborted or crashed */ tuple->t_infomask |= HEAP_XMIN_INVALID; SetBufferCommitInfoNeedsSave(buffer); 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_IS_LOCKED) { /* * "Deleting" xact really only locked it, 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 (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple))) return HEAPTUPLE_LIVE; } else { if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) return HEAPTUPLE_LIVE; } /* * We don't really care whether xmax did commit, abort or crash. * We know that xmax did lock the tuple, but it did not and will * never actually update it. */ tuple->t_infomask |= HEAP_XMAX_INVALID; SetBufferCommitInfoNeedsSave(buffer); } return HEAPTUPLE_LIVE; } if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { /* MultiXacts are currently only allowed to lock tuples */ Assert(tuple->t_infomask & HEAP_IS_LOCKED); 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; SetBufferCommitInfoNeedsSave(buffer); } else { /* * Not in Progress, Not Committed, so either Aborted or crashed */ tuple->t_infomask |= HEAP_XMAX_INVALID; SetBufferCommitInfoNeedsSave(buffer); 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. * However, we can only remove it early if it's not an updated tuple; * else its parent tuple is linking to it via t_ctid, and this tuple * mustn't go away before the parent does. */ if (!(tuple->t_infomask & HEAP_UPDATED)) 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;}/* * GetTransactionSnapshot * Get the appropriate snapshot for a new query in a transaction. * * 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 each time we are called. * * Note that the return value points at static storage that will be modified * by future calls and by CommandCounterIncrement(). Callers should copy * the result with CopySnapshot() if it is to be used very long. */SnapshotGetTransactionSnapshot(void){ /* First call in transaction? */ if (SerializableSnapshot == NULL) { SerializableSnapshot = GetSnapshotData(&SerializableSnapshotData, true); return SerializableSnapshot; } if (IsXactIsoLevelSerializable) return SerializableSnapshot; LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false); return LatestSnapshot;}/* * GetLatestSnapshot * Get a snapshot that is up-to-date as of the current instant, * even if we are executing in SERIALIZABLE mode. */SnapshotGetLatestSnapshot(void){ /* Should not be first call in transaction */ if (SerializableSnapshot == NULL) elog(ERROR, "no snapshot has been set"); LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false); return LatestSnapshot;}/* * CopySnapshot * Copy the given snapshot. * * The copy is palloc'd in the current memory context. * * Note that this will not work on "special" snapshots. */SnapshotCopySnapshot(Snapshot snapshot){ Snapshot newsnap; /* We allocate any XID array needed in the same palloc block. */ newsnap = (Snapshot) palloc(sizeof(SnapshotData) + snapshot->xcnt * sizeof(TransactionId)); memcpy(newsnap, snapshot, sizeof(SnapshotData)); if (snapshot->xcnt > 0) { newsnap->xip = (TransactionId *) (newsnap + 1); memcpy(newsnap->xip, snapshot->xip, snapshot->xcnt * sizeof(TransactionId)); } else newsnap->xip = NULL; return newsnap;}/* * FreeSnapshot * Free a snapshot previously copied with CopySnapshot. * * This is currently identical to pfree, but is provided for cleanliness. * * Do *not* apply this to the results of GetTransactionSnapshot or * GetLatestSnapshot. */voidFreeSnapshot(Snapshot snapshot){ pfree(snapshot);}/* * FreeXactSnapshot * Free snapshot(s) at end of transaction. */voidFreeXactSnapshot(void){ /* * We do not free the xip arrays for the static snapshot structs; they * will be reused soon. So this is now just a state change to prevent * outside callers from accessing the snapshots. */ SerializableSnapshot = NULL; LatestSnapshot = NULL; ActiveSnapshot = NULL; /* just for cleanliness */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -