With the new snapshot maintenance code, it looks like we can advance the xmin more aggressively.
For instance: S1: INSERT INTO foo VALUES(1); S2: BEGIN; DECLARE c1 CURSOR FOR SELECT i FROM foo; S1: DELETE FROM foo; S2: DECLARE c2 CURSOR FOR SELECT i FROM foo; CLOSE c1; S1: VACUUM VERBOSE foo; The VACUUM should be able to clean up the deleted tuple, because it's no longer visible to anyone. Attached a small patch to accomplish this. I don't expect it to be put in 8.4, but it's small enough that I thought I should at least send it in just in case. Regards, Jeff Davis
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c index 7b6e15b..06bf425 100644 --- a/src/backend/utils/resowner/resowner.c +++ b/src/backend/utils/resowner/resowner.c @@ -21,6 +21,7 @@ #include "postgres.h" #include "access/hash.h" +#include "access/transam.h" #include "storage/bufmgr.h" #include "storage/proc.h" #include "utils/memutils.h" @@ -1026,6 +1027,47 @@ ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot) } /* + * Find the smallest xmin among all ResourceOwners under owner. + */ +TransactionId +ResourceOwnerSnapshotsMinXmin(ResourceOwner owner) +{ + ResourceOwner child; + Snapshot *snapshots = owner->snapshots; + int ns1 = owner->nsnapshots - 1; + int i; + TransactionId min_xmin = InvalidTransactionId; + + for (i = ns1; i >= 0; i--) + { + TransactionId xmin = snapshots[i]->xmin; + + if (!TransactionIdIsValid(xmin)) + continue; + + if (!TransactionIdIsValid(min_xmin) || + TransactionIdPrecedes(xmin, min_xmin)) + min_xmin = xmin; + } + + /* Recurse to handle descendants */ + for (child = owner->firstchild; child != NULL; child = child->nextchild) + { + TransactionId xmin = ResourceOwnerSnapshotsMinXmin(child); + + if (!TransactionIdIsValid(xmin)) + continue; + + if (!TransactionIdIsValid(min_xmin) || + TransactionIdPrecedes(xmin, min_xmin)) + min_xmin = xmin; + } + + return min_xmin; +} + + +/* * Debugging subroutine */ static void diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c index 9992895..b7b0506 100644 --- a/src/backend/utils/time/snapmgr.c +++ b/src/backend/utils/time/snapmgr.c @@ -107,6 +107,7 @@ static bool registered_serializable = false; static Snapshot CopySnapshot(Snapshot snapshot); static void FreeSnapshot(Snapshot snapshot); static void SnapshotResetXmin(void); +static TransactionId GetTrueLocalXmin(void); /* @@ -432,8 +433,53 @@ UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner) static void SnapshotResetXmin(void) { + TransactionId local_xmin; + if (RegisteredSnapshots == 0 && ActiveSnapshot == NULL) + { MyProc->xmin = InvalidTransactionId; + return; + } + + /* + * The transaction may have a snapshot but no xmin during abort + * when the transaction has a registered snapshot that is not + * active. + */ + if (!TransactionIdIsValid(MyProc->xmin)) + return; + + local_xmin = GetTrueLocalXmin(); + if (!TransactionIdIsValid(local_xmin) || + TransactionIdPrecedes(MyProc->xmin, local_xmin)) + MyProc->xmin = local_xmin; +} + +/* + * Returns the smallest xmin value in use by any of the active + * snapshots in the current process. + */ +static TransactionId +GetTrueLocalXmin(void) +{ + TransactionId min_xmin = InvalidTransactionId; + ActiveSnapshotElt *active_elt; + + min_xmin = ResourceOwnerSnapshotsMinXmin(TopTransactionResourceOwner); + + for (active_elt = ActiveSnapshot; active_elt != NULL; active_elt = active_elt->as_next) + { + TransactionId xmin = active_elt->as_snap->xmin; + + if (!TransactionIdIsValid(xmin)) + continue; + + if (!TransactionIdIsValid(min_xmin) || + TransactionIdPrecedes(xmin, min_xmin)) + min_xmin = xmin; + } + + return min_xmin; } /* @@ -458,7 +504,7 @@ AtSubCommit_Snapshot(int level) /* * AtSubAbort_Snapshot - * Clean up snapshots after a subtransaction abort + * Clean up snapshots after a subtransaction abort */ void AtSubAbort_Snapshot(int level) diff --git a/src/include/utils/resowner.h b/src/include/utils/resowner.h index 3f05bf4..f4e051e 100644 --- a/src/include/utils/resowner.h +++ b/src/include/utils/resowner.h @@ -128,5 +128,6 @@ extern void ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot); extern void ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot); +extern TransactionId ResourceOwnerSnapshotsMinXmin(ResourceOwner owner); #endif /* RESOWNER_H */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers