diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index cfbabb5265..a576fdec5c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -111,7 +111,7 @@ static relopt_bool boolRelOpts[] = { "autovacuum_enabled", "Enables autovacuum in this relation", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, true @@ -221,7 +221,7 @@ static relopt_int intRelOpts[] = { "autovacuum_vacuum_threshold", "Minimum number of tuple updates or deletes prior to vacuum", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 0, INT_MAX @@ -230,7 +230,7 @@ static relopt_int intRelOpts[] = { "autovacuum_analyze_threshold", "Minimum number of tuple inserts, updates or deletes prior to analyze", - RELOPT_KIND_HEAP, + RELOPT_KIND_HEAP | RELOPT_KIND_TABLESPACE | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 0, INT_MAX @@ -239,7 +239,7 @@ static relopt_int intRelOpts[] = { "autovacuum_vacuum_cost_limit", "Vacuum cost amount available before napping, for autovacuum", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 1, 10000 @@ -248,7 +248,7 @@ static relopt_int intRelOpts[] = { "autovacuum_freeze_min_age", "Minimum age at which VACUUM should freeze a table row, for autovacuum", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 0, 1000000000 @@ -257,7 +257,7 @@ static relopt_int intRelOpts[] = { "autovacuum_multixact_freeze_min_age", "Minimum multixact age at which VACUUM should freeze a row multixact's, for autovacuum", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 0, 1000000000 @@ -266,7 +266,7 @@ static relopt_int intRelOpts[] = { "autovacuum_freeze_max_age", "Age at which to autovacuum a table to prevent transaction ID wraparound", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 100000, 2000000000 @@ -275,7 +275,7 @@ static relopt_int intRelOpts[] = { "autovacuum_multixact_freeze_max_age", "Multixact age at which to autovacuum a table to prevent multixact wraparound", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 10000, 2000000000 @@ -284,7 +284,7 @@ static relopt_int intRelOpts[] = { "autovacuum_freeze_table_age", "Age at which VACUUM should perform a full table sweep to freeze row versions", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 0, 2000000000 }, @@ -292,7 +292,7 @@ static relopt_int intRelOpts[] = { "autovacuum_multixact_freeze_table_age", "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 0, 2000000000 }, @@ -300,7 +300,7 @@ static relopt_int intRelOpts[] = { "log_autovacuum_min_duration", "Sets the minimum execution time above which autovacuum actions will be logged", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, -1, INT_MAX @@ -364,7 +364,7 @@ static relopt_real realRelOpts[] = { "autovacuum_vacuum_cost_delay", "Vacuum cost delay in milliseconds, for autovacuum", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 0.0, 100.0 @@ -373,7 +373,7 @@ static relopt_real realRelOpts[] = { "autovacuum_vacuum_scale_factor", "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 0.0, 100.0 @@ -382,7 +382,7 @@ static relopt_real realRelOpts[] = { "autovacuum_analyze_scale_factor", "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples", - RELOPT_KIND_HEAP, + RELOPT_KIND_HEAP | RELOPT_KIND_TABLESPACE, ShareUpdateExclusiveLock }, -1, 0.0, 100.0 @@ -766,9 +766,9 @@ add_string_reloption(bits32 kinds, const char *name, const char *desc, const cha * that are in the passed namespace. The output values do not include the * namespace. * - * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and - * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing - * reloptions value (possibly NULL), and we replace or remove entries + * This is used for four cases: CREATE TABLE/INDEX, CREATE TABLEPSACE, ALTER + * TABLE SET, and ALTER TABLE RESET. In the ALTER cases, oldOptions is the + * existing reloptions value (possibly NULL), and we replace or remove entries * as needed. * * If acceptOidsOff is true, then we allow oids = false, but throw error when @@ -1562,7 +1562,35 @@ tablespace_reloptions(Datum reloptions, bool validate) static const relopt_parse_elt tab[] = { {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)}, {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)}, - {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)} + {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)}, + {"autovacuum_enabled", RELOPT_TYPE_BOOL, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, enabled)}, + {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)}, + {"autovacuum_analyze_threshold", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)}, + {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)}, + {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)}, + {"autovacuum_freeze_min_age", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)}, + {"autovacuum_freeze_max_age", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)}, + {"autovacuum_freeze_table_age", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)}, + {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)}, + {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)}, + {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)}, + {"log_autovacuum_min_duration", RELOPT_TYPE_INT, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, log_min_duration)}, + {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)}, + {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL, + offsetof(TableSpaceOpts, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)}, }; options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE, diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 53c91d9277..a5909375fc 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -102,6 +102,7 @@ #include "utils/ps_status.h" #include "utils/rel.h" #include "utils/snapmgr.h" +#include "utils/spccache.h" #include "utils/syscache.h" #include "utils/timeout.h" #include "utils/timestamp.h" @@ -2718,21 +2719,29 @@ static AutoVacOpts * extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc) { bytea *relopts; - AutoVacOpts *av; + AutoVacOpts *av, *retav; Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE); relopts = extractRelOptions(tup, pg_class_desc, NULL); - if (relopts == NULL) + av = (relopts != NULL) ? &(((StdRdOptions *)relopts)->autovacuum): NULL; + /* Fetch per-tablespace autovacuum options if any */ + if (av == NULL) + { + Oid spcid = ((Form_pg_class) GETSTRUCT(tup))->reltablespace; + av = get_tablespace_autovacuum_options(spcid); + } + if (av == NULL) return NULL; - av = palloc(sizeof(AutoVacOpts)); - memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts)); - pfree(relopts); + retav = palloc(sizeof(AutoVacOpts)); + memcpy(retav, av, sizeof(AutoVacOpts)); + if (relopts != NULL) + pfree(relopts); - return av; + return retav; } /* diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c index 6309a017c1..133c5560c4 100644 --- a/src/backend/utils/cache/spccache.c +++ b/src/backend/utils/cache/spccache.c @@ -221,3 +221,13 @@ get_tablespace_io_concurrency(Oid spcid) else return spc->opts->effective_io_concurrency; } + +AutoVacOpts * +get_tablespace_autovacuum_options(Oid spcid) +{ + TableSpaceCacheEntry *spc = get_tablespace(spcid); + + if (!spc->opts) + return NULL; + return &(spc->opts->autovacuum); +} diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index 003c874c22..67a1beef8e 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -18,6 +18,7 @@ #include "catalog/objectaddress.h" #include "lib/stringinfo.h" #include "nodes/parsenodes.h" +#include "utils/rel.h" /* XLOG stuff */ #define XLOG_TBLSPC_CREATE 0x00 @@ -40,6 +41,7 @@ typedef struct TableSpaceOpts float8 random_page_cost; float8 seq_page_cost; int effective_io_concurrency; + AutoVacOpts autovacuum; /* autovacuum-related options */ } TableSpaceOpts; extern Oid CreateTableSpace(CreateTableSpaceStmt *stmt); diff --git a/src/include/utils/spccache.h b/src/include/utils/spccache.h index 9120abcd9b..517e347301 100644 --- a/src/include/utils/spccache.h +++ b/src/include/utils/spccache.h @@ -13,8 +13,11 @@ #ifndef SPCCACHE_H #define SPCCACHE_H +#include "utils/rel.h" + void get_tablespace_page_costs(Oid spcid, float8 *spc_random_page_cost, float8 *spc_seq_page_cost); int get_tablespace_io_concurrency(Oid spcid); +AutoVacOpts *get_tablespace_autovacuum_options(Oid spcid); #endif /* SPCCACHE_H */ diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source index 14ce0e7e04..805424e082 100644 --- a/src/test/regress/input/tablespace.source +++ b/src/test/regress/input/tablespace.source @@ -16,6 +16,34 @@ ALTER TABLESPACE regress_tblspace SET (random_page_cost = 1.0, seq_page_cost = 1 ALTER TABLESPACE regress_tblspace SET (some_nonexistent_parameter = true); -- fail ALTER TABLESPACE regress_tblspace RESET (random_page_cost = 2.0); -- fail ALTER TABLESPACE regress_tblspace RESET (random_page_cost, effective_io_concurrency); -- ok +ALTER TABLESPACE regress_tblspace SET (autovacuum_enabled = true, + autovacuum_vacuum_threshold = 100, + autovacuum_analyze_threshold = 100, + autovacuum_vacuum_cost_limit = 1000, + autovacuum_freeze_min_age = 100000000, + autovacuum_freeze_max_age = 400000000, + autovacuum_freeze_table_age = 300000000, + autovacuum_multixact_freeze_min_age = 10000000, + autovacuum_multixact_freeze_table_age = 150000000, + autovacuum_multixact_freeze_max_age = 800000000, + log_autovacuum_min_duration = 250, + autovacuum_vacuum_cost_delay = 0, + autovacuum_vacuum_scale_factor = 0.4, + autovacuum_analyze_scale_factor = 0.4); -- ok +ALTER TABLESPACE regress_tblspace RESET (autovacuum_enabled, + autovacuum_vacuum_threshold, + autovacuum_analyze_threshold, + autovacuum_vacuum_cost_limit, + autovacuum_freeze_min_age, + autovacuum_freeze_table_age, + autovacuum_freeze_max_age, + autovacuum_multixact_freeze_min_age, + autovacuum_multixact_freeze_table_age, + autovacuum_multixact_freeze_max_age, + log_autovacuum_min_duration, + autovacuum_vacuum_cost_delay, + autovacuum_vacuum_scale_factor, + autovacuum_analyze_scale_factor); -- ok -- create a schema we can use CREATE SCHEMA testschema; diff --git a/src/test/regress/output/tablespace.source b/src/test/regress/output/tablespace.source index 8ebe08b9b2..9c6f1ab19a 100644 --- a/src/test/regress/output/tablespace.source +++ b/src/test/regress/output/tablespace.source @@ -20,6 +20,34 @@ ERROR: unrecognized parameter "some_nonexistent_parameter" ALTER TABLESPACE regress_tblspace RESET (random_page_cost = 2.0); -- fail ERROR: RESET must not include values for parameters ALTER TABLESPACE regress_tblspace RESET (random_page_cost, effective_io_concurrency); -- ok +ALTER TABLESPACE regress_tblspace SET (autovacuum_enabled = true, + autovacuum_vacuum_threshold = 100, + autovacuum_analyze_threshold = 100, + autovacuum_vacuum_cost_limit = 1000, + autovacuum_freeze_min_age = 100000000, + autovacuum_freeze_max_age = 400000000, + autovacuum_freeze_table_age = 300000000, + autovacuum_multixact_freeze_min_age = 10000000, + autovacuum_multixact_freeze_table_age = 150000000, + autovacuum_multixact_freeze_max_age = 800000000, + log_autovacuum_min_duration = 250, + autovacuum_vacuum_cost_delay = 0, + autovacuum_vacuum_scale_factor = 0.4, + autovacuum_analyze_scale_factor = 0.4); -- ok +ALTER TABLESPACE regress_tblspace RESET (autovacuum_enabled, + autovacuum_vacuum_threshold, + autovacuum_analyze_threshold, + autovacuum_vacuum_cost_limit, + autovacuum_freeze_min_age, + autovacuum_freeze_table_age, + autovacuum_freeze_max_age, + autovacuum_multixact_freeze_min_age, + autovacuum_multixact_freeze_table_age, + autovacuum_multixact_freeze_max_age, + log_autovacuum_min_duration, + autovacuum_vacuum_cost_delay, + autovacuum_vacuum_scale_factor, + autovacuum_analyze_scale_factor); -- ok -- create a schema we can use CREATE SCHEMA testschema; -- try a table