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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers