diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml index cf174f0715..d692308cf4 100644 --- a/doc/src/sgml/maintenance.sgml +++ b/doc/src/sgml/maintenance.sgml @@ -640,7 +640,12 @@ HINT: Stop the postmaster and vacuum that database in single-user mode. possible multixact ID still appearing in any tuple of that table. If this value is older than , a whole-table - scan is forced. Whole-table VACUUM scans, regardless of + scan is forced. mxid_age() can be used on + pg_class.relminmxid to find its age. + + + + Whole-table VACUUM scans, regardless of what causes them, enable advancing the value for that table. Eventually, as all tables in all databases are scanned and their oldest multixact values are advanced, on-disk storage for older diff --git a/src/backend/utils/adt/xid.c b/src/backend/utils/adt/xid.c index 602a9e5d6f..ecb3cf55dd 100644 --- a/src/backend/utils/adt/xid.c +++ b/src/backend/utils/adt/xid.c @@ -16,6 +16,7 @@ #include +#include "access/multixact.h" #include "access/transam.h" #include "access/xact.h" #include "libpq/pqformat.h" @@ -102,6 +103,21 @@ xid_age(PG_FUNCTION_ARGS) PG_RETURN_INT32((int32) (now - xid)); } +/* + * mxid_age - compute age of a multi XID (relative to latest stable mxid) + */ +Datum +mxid_age(PG_FUNCTION_ARGS) +{ + TransactionId xid = PG_GETARG_TRANSACTIONID(0); + MultiXactId now = ReadNextMultiXactId(); + + if (!MultiXactIdIsValid(xid)) + PG_RETURN_INT32(INT_MAX); + + PG_RETURN_INT32((int32) (now - xid)); +} + /* * xidComparator * qsort comparison function for XIDs diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 5dc0455477..74582e9bbb 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201409091 +#define CATALOG_VERSION_NO 201409101 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index bd1b41723c..a56a6359ca 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -1279,6 +1279,8 @@ DATA(insert OID = 1180 ( abstime PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 7 DESCR("convert timestamp with time zone to abstime"); DATA(insert OID = 1181 ( age PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 23 "28" _null_ _null_ _null_ _null_ xid_age _null_ _null_ _null_ )); DESCR("age of a transaction ID, in transactions before current transaction"); +DATA(insert OID = 3939 ( mxid_age PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 23 "28" _null_ _null_ _null_ _null_ mxid_age _null_ _null_ _null_ )); +DESCR("age of a multi-transaction ID, in multi-transactions before current multi-transaction"); DATA(insert OID = 1188 ( timestamptz_mi PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1186 "1184 1184" _null_ _null_ _null_ _null_ timestamp_mi _null_ _null_ _null_ )); DATA(insert OID = 1189 ( timestamptz_pl_interval PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 1184 "1184 1186" _null_ _null_ _null_ _null_ timestamptz_pl_interval _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 78cc0a0bea..d88e7a3b26 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -845,6 +845,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 Datum mxid_age(PG_FUNCTION_ARGS); extern int xidComparator(const void *arg1, const void *arg2); extern Datum cidin(PG_FUNCTION_ARGS); extern Datum cidout(PG_FUNCTION_ARGS);