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

Reply via email to