On ons, 2012-01-18 at 14:55 -0500, Tom Lane wrote:
> BTW, it strikes me that maybe the coding should work about like this:
>
> if (!TransactionIdIsValid(age_reference_xid))
> {
> age_reference_xid = GetTopTransactionIdIfAny();
> if (!TransactionIdIsValid(age_reference_xid))
> age_reference_xid = ReadNewTransactionId();
> }
> ... use age_reference_xid to compute result ...
>
> and of course code somewhere to reset age_reference_xid at end of xact.
How about this patch?
diff --git i/src/backend/access/transam/xact.c w/src/backend/access/transam/xact.c
index 7f412b1..25fbd05 100644
--- i/src/backend/access/transam/xact.c
+++ w/src/backend/access/transam/xact.c
@@ -43,6 +43,7 @@
#include "storage/procarray.h"
#include "storage/sinvaladt.h"
#include "storage/smgr.h"
+#include "utils/builtins.h"
#include "utils/combocid.h"
#include "utils/guc.h"
#include "utils/inval.h"
@@ -1938,6 +1939,7 @@ CommitTransaction(void)
AtCommit_Notify();
AtEOXact_GUC(true, 1);
+ AtEOXact_xid();
AtEOXact_SPI(true);
AtEOXact_on_commit_actions(true);
AtEOXact_Namespace(true);
@@ -2191,6 +2193,7 @@ PrepareTransaction(void)
/* PREPARE acts the same as COMMIT as far as GUC is concerned */
AtEOXact_GUC(true, 1);
+ AtEOXact_xid();
AtEOXact_SPI(true);
AtEOXact_on_commit_actions(true);
AtEOXact_Namespace(true);
@@ -2337,6 +2340,7 @@ AbortTransaction(void)
AtEOXact_CatCache(false);
AtEOXact_GUC(false, 1);
+ AtEOXact_xid();
AtEOXact_SPI(false);
AtEOXact_on_commit_actions(false);
AtEOXact_Namespace(false);
diff --git i/src/backend/utils/adt/xid.c w/src/backend/utils/adt/xid.c
index 1829b82..9cf6256 100644
--- i/src/backend/utils/adt/xid.c
+++ w/src/backend/utils/adt/xid.c
@@ -86,22 +86,45 @@ xideq(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2));
}
+
/*
* xid_age - compute age of an XID (relative to current xact)
+ *
+ * We don't want to allocate a new transaction ID just for calling age(),
+ * because it should be avoided in an otherwise read-only transaction, and to
+ * make this work under hot standby. But calling ReadNewTransactionId() would
+ * make this function volatile (instead of stable), so we cache the reference
+ * point for the duration of the transaction.
*/
+
+static TransactionId age_reference_xid = InvalidTransactionId;
+
Datum
xid_age(PG_FUNCTION_ARGS)
{
TransactionId xid = PG_GETARG_TRANSACTIONID(0);
- TransactionId now = GetTopTransactionId();
+
+ if (!TransactionIdIsValid(age_reference_xid))
+ {
+ age_reference_xid = GetTopTransactionIdIfAny();
+ if (!TransactionIdIsValid(age_reference_xid))
+ age_reference_xid = ReadNewTransactionId();
+ }
/* Permanent XIDs are always infinitely old */
if (!TransactionIdIsNormal(xid))
PG_RETURN_INT32(INT_MAX);
- PG_RETURN_INT32((int32) (now - xid));
+ PG_RETURN_INT32((int32) (age_reference_xid - xid));
}
+void
+AtEOXact_xid(void)
+{
+ age_reference_xid = InvalidTransactionId;
+}
+
+
/*
* xidComparator
* qsort comparison function for XIDs
diff --git i/src/include/utils/builtins.h w/src/include/utils/builtins.h
index f246f11..b7906b8 100644
--- i/src/include/utils/builtins.h
+++ w/src/include/utils/builtins.h
@@ -795,6 +795,7 @@ extern Datum xidrecv(PG_FUNCTION_ARGS);
extern Datum xidsend(PG_FUNCTION_ARGS);
extern Datum xideq(PG_FUNCTION_ARGS);
extern Datum xid_age(PG_FUNCTION_ARGS);
+extern void AtEOXact_xid(void);
extern int xidComparator(const void *arg1, const void *arg2);
extern Datum cidin(PG_FUNCTION_ARGS);
extern Datum cidout(PG_FUNCTION_ARGS);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers