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