From d86d51a95810caebcea587498068ff32fe28293e Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Tue, 5 Jan 2010 21:54:00 +0000 Subject: [PATCH] Support ALTER TABLESPACE name SET/RESET ( tablespace_options ). This patch only supports seq_page_cost and random_page_cost as parameters, but it provides the infrastructure to scalably support many more. In particular, we may want to add support for effective_io_concurrency, but I'm leaving that as future work for now. Thanks to Tom Lane for design help and Alvaro Herrera for the review. --- doc/src/sgml/config.sgml | 11 +- doc/src/sgml/ref/alter_tablespace.sgml | 22 ++- src/backend/access/common/reloptions.c | 50 +++++- src/backend/catalog/aclchk.c | 61 ++------ src/backend/commands/tablespace.c | 73 ++++++++- src/backend/nodes/copyfuncs.c | 17 +- src/backend/nodes/equalfuncs.c | 16 +- src/backend/nodes/outfuncs.c | 3 +- src/backend/optimizer/path/costsize.c | 63 ++++++-- src/backend/optimizer/util/plancat.c | 5 +- src/backend/parser/gram.y | 20 ++- src/backend/tcop/utility.c | 15 +- src/backend/utils/adt/selfuncs.c | 26 +-- src/backend/utils/cache/Makefile | 4 +- src/backend/utils/cache/spccache.c | 183 ++++++++++++++++++++++ src/backend/utils/cache/syscache.c | 15 +- src/bin/pg_dump/pg_dumpall.c | 22 ++- src/include/access/reloptions.h | 9 +- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_tablespace.h | 10 +- src/include/commands/tablespace.h | 8 +- src/include/nodes/nodes.h | 3 +- src/include/nodes/parsenodes.h | 10 +- src/include/nodes/relation.h | 4 +- src/include/utils/spccache.h | 19 +++ src/include/utils/syscache.h | 3 +- src/test/regress/input/tablespace.source | 6 + src/test/regress/output/tablespace.source | 7 + 28 files changed, 588 insertions(+), 101 deletions(-) create mode 100644 src/backend/utils/cache/spccache.c create mode 100644 src/include/utils/spccache.h diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index df8f858c54..34f472555e 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1,4 +1,4 @@ - + Server Configuration @@ -2000,6 +2000,9 @@ archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"' # Windows Sets the planner's estimate of the cost of a disk page fetch that is part of a series of sequential fetches. The default is 1.0. + This value can be overriden for a particular tablespace by setting + the tablespace parameter of the same name + (see ). @@ -2013,6 +2016,12 @@ archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"' # Windows Sets the planner's estimate of the cost of a non-sequentially-fetched disk page. The default is 4.0. + This value can be overriden for a particular tablespace by setting + the tablespace parameter of the same name + (see ). + + + Reducing this value relative to seq_page_cost will cause the system to prefer index scans; raising it will make index scans look relatively more expensive. You can raise diff --git a/doc/src/sgml/ref/alter_tablespace.sgml b/doc/src/sgml/ref/alter_tablespace.sgml index 8c5341dd08..758ee13aa6 100644 --- a/doc/src/sgml/ref/alter_tablespace.sgml +++ b/doc/src/sgml/ref/alter_tablespace.sgml @@ -1,5 +1,5 @@ @@ -23,6 +23,8 @@ PostgreSQL documentation ALTER TABLESPACE name RENAME TO new_name ALTER TABLESPACE name OWNER TO new_owner +ALTER TABLESPACE name SET ( tablespace_option = value [, ... ] ) +ALTER TABLESPACE name RESET ( tablespace_option [, ... ] ) @@ -74,6 +76,24 @@ ALTER TABLESPACE name OWNER TO new_owner + + + tablespace_parameter + + + A tablespace parameter to be set or reset. Currently, the only + available parameters are seq_page_cost and + random_page_cost. Setting either value for a particular + tablespace will override the planner's usual estimate of the cost of + reading pages from tables in that tablespace, as established by + the configuration parameters of the same name (see + , + ). This may be useful if one + tablespace is located on a disk which is faster or slower than the + remainder of the I/O subsystem. + + + diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 2e3fa5bcae..28eacb4e47 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.30 2010/01/02 16:57:33 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.31 2010/01/05 21:53:58 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "access/reloptions.h" #include "catalog/pg_type.h" #include "commands/defrem.h" +#include "commands/tablespace.h" #include "nodes/makefuncs.h" #include "utils/array.h" #include "utils/builtins.h" @@ -179,6 +180,22 @@ static relopt_real realRelOpts[] = }, -1, 0.0, 100.0 }, + { + { + "seq_page_cost", + "Sets the planner's estimate of the cost of a sequentially fetched disk page.", + RELOPT_KIND_TABLESPACE + }, + -1, 0.0, DBL_MAX + }, + { + { + "random_page_cost", + "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.", + RELOPT_KIND_TABLESPACE + }, + -1, 0.0, DBL_MAX + }, /* list terminator */ {{NULL}} }; @@ -1168,3 +1185,34 @@ index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate) return DatumGetByteaP(result); } + +/* + * Option parser for tablespace reloptions + */ +bytea * +tablespace_reloptions(Datum reloptions, bool validate) +{ + relopt_value *options; + TableSpaceOpts *tsopts; + int numoptions; + 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)} + }; + + options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE, + &numoptions); + + /* if none set, we're done */ + if (numoptions == 0) + return NULL; + + tsopts = allocateReloptStruct(sizeof(TableSpaceOpts), options, numoptions); + + fillRelOptions((void *) tsopts, sizeof(TableSpaceOpts), options, numoptions, + validate, tab, lengthof(tab)); + + pfree(options); + + return (bytea *) tsopts; +} diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index d98ebdda4f..6c16fd6a6e 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.159 2010/01/02 16:57:36 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.160 2010/01/05 21:53:58 rhaas Exp $ * * NOTES * See acl.h. @@ -2783,18 +2783,11 @@ ExecGrant_Tablespace(InternalGrant *istmt) int nnewmembers; Oid *oldmembers; Oid *newmembers; - ScanKeyData entry[1]; - SysScanDesc scan; HeapTuple tuple; - /* There's no syscache for pg_tablespace, so must look the hard way */ - ScanKeyInit(&entry[0], - ObjectIdAttributeNumber, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(tblId)); - scan = systable_beginscan(relation, TablespaceOidIndexId, true, - SnapshotNow, 1, entry); - tuple = systable_getnext(scan); + /* Search syscache for pg_tablespace */ + tuple = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(tblId), + 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for tablespace %u", tblId); @@ -2865,8 +2858,7 @@ ExecGrant_Tablespace(InternalGrant *istmt) noldmembers, oldmembers, nnewmembers, newmembers); - systable_endscan(scan); - + ReleaseSysCache(tuple); pfree(new_acl); /* prevent error when processing duplicate objects */ @@ -3696,9 +3688,6 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid, AclMode mask, AclMaskHow how) { AclMode result; - Relation pg_tablespace; - ScanKeyData entry[1]; - SysScanDesc scan; HeapTuple tuple; Datum aclDatum; bool isNull; @@ -3711,17 +3700,9 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid, /* * Get the tablespace's ACL from pg_tablespace - * - * There's no syscache for pg_tablespace, so must look the hard way */ - pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock); - ScanKeyInit(&entry[0], - ObjectIdAttributeNumber, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(spc_oid)); - scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true, - SnapshotNow, 1, entry); - tuple = systable_getnext(scan); + tuple = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(spc_oid), + 0, 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -3729,8 +3710,9 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid, ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner; - aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl, - RelationGetDescr(pg_tablespace), &isNull); + aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple, + Anum_pg_tablespace_spcacl, + &isNull); if (isNull) { @@ -3750,8 +3732,7 @@ pg_tablespace_aclmask(Oid spc_oid, Oid roleid, if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) pfree(acl); - systable_endscan(scan); - heap_close(pg_tablespace, AccessShareLock); + ReleaseSysCache(tuple); return result; } @@ -4338,9 +4319,6 @@ pg_namespace_ownercheck(Oid nsp_oid, Oid roleid) bool pg_tablespace_ownercheck(Oid spc_oid, Oid roleid) { - Relation pg_tablespace; - ScanKeyData entry[1]; - SysScanDesc scan; HeapTuple spctuple; Oid spcowner; @@ -4348,17 +4326,9 @@ pg_tablespace_ownercheck(Oid spc_oid, Oid roleid) if (superuser_arg(roleid)) return true; - /* There's no syscache for pg_tablespace, so must look the hard way */ - pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock); - ScanKeyInit(&entry[0], - ObjectIdAttributeNumber, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(spc_oid)); - scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true, - SnapshotNow, 1, entry); - - spctuple = systable_getnext(scan); - + /* Search syscache for pg_tablespace */ + spctuple = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(spc_oid), + 0, 0, 0); if (!HeapTupleIsValid(spctuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -4366,8 +4336,7 @@ pg_tablespace_ownercheck(Oid spc_oid, Oid roleid) spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner; - systable_endscan(scan); - heap_close(pg_tablespace, AccessShareLock); + ReleaseSysCache(spctuple); return has_privs_of_role(roleid, spcowner); } diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 927711eed2..0da15569f3 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.65 2010/01/02 16:57:37 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.66 2010/01/05 21:53:58 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -49,6 +49,7 @@ #include #include "access/heapam.h" +#include "access/reloptions.h" #include "access/sysattr.h" #include "access/transam.h" #include "access/xact.h" @@ -57,6 +58,7 @@ #include "catalog/indexing.h" #include "catalog/pg_tablespace.h" #include "commands/comment.h" +#include "commands/defrem.h" #include "commands/tablespace.h" #include "miscadmin.h" #include "postmaster/bgwriter.h" @@ -70,6 +72,7 @@ #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/rel.h" +#include "utils/syscache.h" #include "utils/tqual.h" @@ -290,6 +293,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) values[Anum_pg_tablespace_spclocation - 1] = CStringGetTextDatum(location); nulls[Anum_pg_tablespace_spcacl - 1] = true; + nulls[Anum_pg_tablespace_spcoptions - 1] = true; tuple = heap_form_tuple(rel->rd_att, values, nulls); @@ -912,6 +916,73 @@ AlterTableSpaceOwner(const char *name, Oid newOwnerId) } +/* + * Alter table space options + */ +void +AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) +{ + Relation rel; + ScanKeyData entry[1]; + HeapScanDesc scandesc; + HeapTuple tup; + Datum datum; + Datum newOptions; + Datum repl_val[Natts_pg_tablespace]; + bool isnull; + bool repl_null[Natts_pg_tablespace]; + bool repl_repl[Natts_pg_tablespace]; + HeapTuple newtuple; + + /* Search pg_tablespace */ + rel = heap_open(TableSpaceRelationId, RowExclusiveLock); + + ScanKeyInit(&entry[0], + Anum_pg_tablespace_spcname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(stmt->tablespacename)); + scandesc = heap_beginscan(rel, SnapshotNow, 1, entry); + tup = heap_getnext(scandesc, ForwardScanDirection); + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace \"%s\" does not exist", + stmt->tablespacename))); + + /* Must be owner of the existing object */ + if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, + stmt->tablespacename); + + /* Generate new proposed spcoptions (text array) */ + datum = heap_getattr(tup, Anum_pg_tablespace_spcoptions, + RelationGetDescr(rel), &isnull); + newOptions = transformRelOptions(isnull ? (Datum) 0 : datum, + stmt->options, NULL, NULL, false, + stmt->isReset); + (void) tablespace_reloptions(newOptions, true); + + /* Build new tuple. */ + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + if (newOptions != (Datum) 0) + repl_val[Anum_pg_tablespace_spcoptions - 1] = newOptions; + else + repl_null[Anum_pg_tablespace_spcoptions - 1] = true; + repl_repl[Anum_pg_tablespace_spcoptions - 1] = true; + newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, + repl_null, repl_repl); + + /* Update system catalog. */ + simple_heap_update(rel, &newtuple->t_self, newtuple); + CatalogUpdateIndexes(rel, newtuple); + heap_freetuple(newtuple); + + /* Conclude heap scan. */ + heap_endscan(scandesc); + heap_close(rel, NoLock); +} + /* * Routines for handling the GUC variable 'default_tablespace'. */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 7cbbb1f913..8d1f1641d7 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.458 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.459 2010/01/05 21:53:58 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -3064,6 +3064,18 @@ _copyDropTableSpaceStmt(DropTableSpaceStmt *from) return newnode; } +static AlterTableSpaceOptionsStmt * +_copyAlterTableSpaceOptionsStmt(AlterTableSpaceOptionsStmt *from) +{ + AlterTableSpaceOptionsStmt *newnode = makeNode(AlterTableSpaceOptionsStmt); + + COPY_STRING_FIELD(tablespacename); + COPY_NODE_FIELD(options); + COPY_SCALAR_FIELD(isReset); + + return newnode; +} + static CreateFdwStmt * _copyCreateFdwStmt(CreateFdwStmt *from) { @@ -4028,6 +4040,9 @@ copyObject(void *from) case T_DropTableSpaceStmt: retval = _copyDropTableSpaceStmt(from); break; + case T_AlterTableSpaceOptionsStmt: + retval = _copyAlterTableSpaceOptionsStmt(from); + break; case T_CreateFdwStmt: retval = _copyCreateFdwStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 20abee3898..24e5377307 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -22,7 +22,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.379 2010/01/02 16:57:46 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.380 2010/01/05 21:53:58 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -1568,6 +1568,17 @@ _equalDropTableSpaceStmt(DropTableSpaceStmt *a, DropTableSpaceStmt *b) return true; } +static bool +_equalAlterTableSpaceOptionsStmt(AlterTableSpaceOptionsStmt *a, + AlterTableSpaceOptionsStmt *b) +{ + COMPARE_STRING_FIELD(tablespacename); + COMPARE_NODE_FIELD(options); + COMPARE_SCALAR_FIELD(isReset); + + return true; +} + static bool _equalCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b) { @@ -2720,6 +2731,9 @@ equal(void *a, void *b) case T_DropTableSpaceStmt: retval = _equalDropTableSpaceStmt(a, b); break; + case T_AlterTableSpaceOptionsStmt: + retval = _equalAlterTableSpaceOptionsStmt(a, b); + break; case T_CreateFdwStmt: retval = _equalCreateFdwStmt(a, b); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 0342e66b51..5bd092eae2 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.379 2010/01/02 16:57:46 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.380 2010/01/05 21:53:58 rhaas Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -1590,6 +1590,7 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node) WRITE_NODE_FIELD(cheapest_total_path); WRITE_NODE_FIELD(cheapest_unique_path); WRITE_UINT_FIELD(relid); + WRITE_UINT_FIELD(reltablespace); WRITE_ENUM_FIELD(rtekind, RTEKind); WRITE_INT_FIELD(min_attr); WRITE_INT_FIELD(max_attr); diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index bc028ee147..f92c944925 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -27,6 +27,11 @@ * detail. Note that all of these parameters are user-settable, in case * the default values are drastically off for a particular platform. * + * seq_page_cost and random_page_cost can also be overridden for an individual + * tablespace, in case some data is on a fast disk and other data is on a slow + * disk. Per-tablespace overrides never apply to temporary work files such as + * an external sort or a materialize node that overflows work_mem. + * * We compute two separate costs for each path: * total_cost: total estimated cost to fetch all tuples * startup_cost: cost that is expended before first tuple is fetched @@ -54,7 +59,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.213 2010/01/02 16:57:46 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.214 2010/01/05 21:53:58 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -76,6 +81,7 @@ #include "parser/parsetree.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" +#include "utils/spccache.h" #include "utils/tuplesort.h" @@ -164,6 +170,7 @@ void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel) { + double spc_seq_page_cost; Cost startup_cost = 0; Cost run_cost = 0; Cost cpu_per_tuple; @@ -175,10 +182,15 @@ cost_seqscan(Path *path, PlannerInfo *root, if (!enable_seqscan) startup_cost += disable_cost; + /* fetch estimated page cost for tablespace containing table */ + get_tablespace_page_costs(baserel->reltablespace, + NULL, + &spc_seq_page_cost); + /* * disk costs */ - run_cost += seq_page_cost * baserel->pages; + run_cost += spc_seq_page_cost * baserel->pages; /* CPU costs */ startup_cost += baserel->baserestrictcost.startup; @@ -226,6 +238,8 @@ cost_index(IndexPath *path, PlannerInfo *root, Selectivity indexSelectivity; double indexCorrelation, csquared; + double spc_seq_page_cost, + spc_random_page_cost; Cost min_IO_cost, max_IO_cost; Cost cpu_per_tuple; @@ -272,13 +286,18 @@ cost_index(IndexPath *path, PlannerInfo *root, /* estimate number of main-table tuples fetched */ tuples_fetched = clamp_row_est(indexSelectivity * baserel->tuples); + /* fetch estimated page costs for tablespace containing table */ + get_tablespace_page_costs(baserel->reltablespace, + &spc_random_page_cost, + &spc_seq_page_cost); + /*---------- * Estimate number of main-table pages fetched, and compute I/O cost. * * When the index ordering is uncorrelated with the table ordering, * we use an approximation proposed by Mackert and Lohman (see * index_pages_fetched() for details) to compute the number of pages - * fetched, and then charge random_page_cost per page fetched. + * fetched, and then charge spc_random_page_cost per page fetched. * * When the index ordering is exactly correlated with the table ordering * (just after a CLUSTER, for example), the number of pages fetched should @@ -286,7 +305,7 @@ cost_index(IndexPath *path, PlannerInfo *root, * will be sequential fetches, not the random fetches that occur in the * uncorrelated case. So if the number of pages is more than 1, we * ought to charge - * random_page_cost + (pages_fetched - 1) * seq_page_cost + * spc_random_page_cost + (pages_fetched - 1) * spc_seq_page_cost * For partially-correlated indexes, we ought to charge somewhere between * these two estimates. We currently interpolate linearly between the * estimates based on the correlation squared (XXX is that appropriate?). @@ -309,7 +328,7 @@ cost_index(IndexPath *path, PlannerInfo *root, (double) index->pages, root); - max_IO_cost = (pages_fetched * random_page_cost) / num_scans; + max_IO_cost = (pages_fetched * spc_random_page_cost) / num_scans; /* * In the perfectly correlated case, the number of pages touched by @@ -328,7 +347,7 @@ cost_index(IndexPath *path, PlannerInfo *root, (double) index->pages, root); - min_IO_cost = (pages_fetched * random_page_cost) / num_scans; + min_IO_cost = (pages_fetched * spc_random_page_cost) / num_scans; } else { @@ -342,13 +361,13 @@ cost_index(IndexPath *path, PlannerInfo *root, root); /* max_IO_cost is for the perfectly uncorrelated case (csquared=0) */ - max_IO_cost = pages_fetched * random_page_cost; + max_IO_cost = pages_fetched * spc_random_page_cost; /* min_IO_cost is for the perfectly correlated case (csquared=1) */ pages_fetched = ceil(indexSelectivity * (double) baserel->pages); - min_IO_cost = random_page_cost; + min_IO_cost = spc_random_page_cost; if (pages_fetched > 1) - min_IO_cost += (pages_fetched - 1) * seq_page_cost; + min_IO_cost += (pages_fetched - 1) * spc_seq_page_cost; } /* @@ -553,6 +572,8 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, Cost cost_per_page; double tuples_fetched; double pages_fetched; + double spc_seq_page_cost, + spc_random_page_cost; double T; /* Should only be applied to base relations */ @@ -571,6 +592,11 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, startup_cost += indexTotalCost; + /* Fetch estimated page costs for tablespace containing table. */ + get_tablespace_page_costs(baserel->reltablespace, + &spc_random_page_cost, + &spc_seq_page_cost); + /* * Estimate number of main-table pages fetched. */ @@ -609,17 +635,18 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, pages_fetched = ceil(pages_fetched); /* - * For small numbers of pages we should charge random_page_cost apiece, + * For small numbers of pages we should charge spc_random_page_cost apiece, * while if nearly all the table's pages are being read, it's more - * appropriate to charge seq_page_cost apiece. The effect is nonlinear, + * appropriate to charge spc_seq_page_cost apiece. The effect is nonlinear, * too. For lack of a better idea, interpolate like this to determine the * cost per page. */ if (pages_fetched >= 2.0) - cost_per_page = random_page_cost - - (random_page_cost - seq_page_cost) * sqrt(pages_fetched / T); + cost_per_page = spc_random_page_cost - + (spc_random_page_cost - spc_seq_page_cost) + * sqrt(pages_fetched / T); else - cost_per_page = random_page_cost; + cost_per_page = spc_random_page_cost; run_cost += pages_fetched * cost_per_page; @@ -783,6 +810,7 @@ cost_tidscan(Path *path, PlannerInfo *root, QualCost tid_qual_cost; int ntuples; ListCell *l; + double spc_random_page_cost; /* Should only be applied to base relations */ Assert(baserel->relid > 0); @@ -835,8 +863,13 @@ cost_tidscan(Path *path, PlannerInfo *root, */ cost_qual_eval(&tid_qual_cost, tidquals, root); + /* fetch estimated page cost for tablespace containing table */ + get_tablespace_page_costs(baserel->reltablespace, + &spc_random_page_cost, + NULL); + /* disk costs --- assume each tuple on a different page */ - run_cost += random_page_cost * ntuples; + run_cost += spc_random_page_cost * ntuples; /* CPU costs */ startup_cost += baserel->baserestrictcost.startup + diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 1683181107..fdce5bb5a3 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.161 2010/01/02 16:57:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.162 2010/01/05 21:53:58 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -91,6 +91,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, rel->min_attr = FirstLowInvalidHeapAttributeNumber + 1; rel->max_attr = RelationGetNumberOfAttributes(relation); + rel->reltablespace = RelationGetForm(relation)->reltablespace; Assert(rel->max_attr >= rel->min_attr); rel->attr_needed = (Relids *) @@ -183,6 +184,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, info = makeNode(IndexOptInfo); info->indexoid = index->indexrelid; + info->reltablespace = + RelationGetForm(indexRelation)->reltablespace; info->rel = rel; info->ncolumns = ncolumns = index->indnatts; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index ed906c1fed..2ea08893f3 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.701 2010/01/02 16:57:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.702 2010/01/05 21:53:58 rhaas Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -5687,6 +5687,24 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name n->newname = $6; $$ = (Node *)n; } + | ALTER TABLESPACE name SET reloptions + { + AlterTableSpaceOptionsStmt *n = + makeNode(AlterTableSpaceOptionsStmt); + n->tablespacename = $3; + n->options = $5; + n->isReset = FALSE; + $$ = (Node *)n; + } + | ALTER TABLESPACE name RESET reloptions + { + AlterTableSpaceOptionsStmt *n = + makeNode(AlterTableSpaceOptionsStmt); + n->tablespacename = $3; + n->options = $5; + n->isReset = TRUE; + $$ = (Node *)n; + } | ALTER TEXT_P SEARCH PARSER any_name RENAME TO name { RenameStmt *n = makeNode(RenameStmt); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 3bdc6e7819..3da89ba08a 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.326 2010/01/02 16:57:53 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.327 2010/01/05 21:53:58 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -218,6 +218,7 @@ check_xact_readonly(Node *parsetree) case T_CreateUserMappingStmt: case T_AlterUserMappingStmt: case T_DropUserMappingStmt: + case T_AlterTableSpaceOptionsStmt: ereport(ERROR, (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), errmsg("transaction is read-only"))); @@ -528,6 +529,10 @@ standard_ProcessUtility(Node *parsetree, DropTableSpace((DropTableSpaceStmt *) parsetree); break; + case T_AlterTableSpaceOptionsStmt: + AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree); + break; + case T_CreateFdwStmt: CreateForeignDataWrapper((CreateFdwStmt *) parsetree); break; @@ -1456,6 +1461,10 @@ CreateCommandTag(Node *parsetree) tag = "DROP TABLESPACE"; break; + case T_AlterTableSpaceOptionsStmt: + tag = "ALTER TABLESPACE"; + break; + case T_CreateFdwStmt: tag = "CREATE FOREIGN DATA WRAPPER"; break; @@ -2238,6 +2247,10 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_DDL; break; + case T_AlterTableSpaceOptionsStmt: + lev = LOGSTMT_DDL; + break; + case T_CreateFdwStmt: case T_AlterFdwStmt: case T_DropFdwStmt: diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 2506eaaf82..4bd302eab5 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.267 2010/01/04 02:44:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.268 2010/01/05 21:53:59 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -119,6 +119,7 @@ #include "utils/nabstime.h" #include "utils/pg_locale.h" #include "utils/selfuncs.h" +#include "utils/spccache.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -5648,6 +5649,7 @@ genericcostestimate(PlannerInfo *root, QualCost index_qual_cost; double qual_op_cost; double qual_arg_cost; + double spc_random_page_cost; List *selectivityQuals; ListCell *l; @@ -5756,6 +5758,11 @@ genericcostestimate(PlannerInfo *root, else numIndexPages = 1.0; + /* fetch estimated page cost for schema containing index */ + get_tablespace_page_costs(index->reltablespace, + &spc_random_page_cost, + NULL); + /* * Now compute the disk access costs. * @@ -5802,15 +5809,16 @@ genericcostestimate(PlannerInfo *root, * share for each outer scan. (Don't pro-rate for ScalarArrayOpExpr, * since that's internal to the indexscan.) */ - *indexTotalCost = (pages_fetched * random_page_cost) / num_outer_scans; + *indexTotalCost = (pages_fetched * spc_random_page_cost) + / num_outer_scans; } else { /* - * For a single index scan, we just charge random_page_cost per page - * touched. + * For a single index scan, we just charge spc_random_page_cost per + * page touched. */ - *indexTotalCost = numIndexPages * random_page_cost; + *indexTotalCost = numIndexPages * spc_random_page_cost; } /* @@ -5825,11 +5833,11 @@ genericcostestimate(PlannerInfo *root, * * We can deal with this by adding a very small "fudge factor" that * depends on the index size. The fudge factor used here is one - * random_page_cost per 100000 index pages, which should be small enough - * to not alter index-vs-seqscan decisions, but will prevent indexes of - * different sizes from looking exactly equally attractive. + * spc_random_page_cost per 100000 index pages, which should be small + * enough to not alter index-vs-seqscan decisions, but will prevent + * indexes of different sizes from looking exactly equally attractive. */ - *indexTotalCost += index->pages * random_page_cost / 100000.0; + *indexTotalCost += index->pages * spc_random_page_cost / 100000.0; /* * CPU cost: any complex expressions in the indexquals will need to be diff --git a/src/backend/utils/cache/Makefile b/src/backend/utils/cache/Makefile index 1766c0315f..1a3d2cc482 100644 --- a/src/backend/utils/cache/Makefile +++ b/src/backend/utils/cache/Makefile @@ -4,7 +4,7 @@ # Makefile for utils/cache # # IDENTIFICATION -# $PostgreSQL: pgsql/src/backend/utils/cache/Makefile,v 1.23 2008/02/19 10:30:08 petere Exp $ +# $PostgreSQL: pgsql/src/backend/utils/cache/Makefile,v 1.24 2010/01/05 21:53:59 rhaas Exp $ # #------------------------------------------------------------------------- @@ -13,6 +13,6 @@ top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global OBJS = catcache.o inval.o plancache.o relcache.o \ - syscache.o lsyscache.o typcache.o ts_cache.o + spccache.o syscache.o lsyscache.o typcache.o ts_cache.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c new file mode 100644 index 0000000000..00629c09f0 --- /dev/null +++ b/src/backend/utils/cache/spccache.c @@ -0,0 +1,183 @@ +/*------------------------------------------------------------------------- + * + * spccache.c + * Tablespace cache management. + * + * We cache the parsed version of spcoptions for each tablespace to avoid + * needing to reparse on every lookup. Right now, there doesn't appear to + * be a measurable performance gain from doing this, but that might change + * in the future as we add more options. + * + * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/utils/cache/spccache.c,v 1.1 2010/01/05 21:53:59 rhaas Exp $ + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "access/reloptions.h" +#include "catalog/pg_tablespace.h" +#include "commands/tablespace.h" +#include "miscadmin.h" +#include "optimizer/cost.h" +#include "utils/catcache.h" +#include "utils/hsearch.h" +#include "utils/inval.h" +#include "utils/spccache.h" +#include "utils/syscache.h" + +static HTAB *TableSpaceCacheHash = NULL; + +typedef struct { + Oid oid; + TableSpaceOpts *opts; +} TableSpace; + +/* + * InvalidateTableSpaceCacheCallback + * Flush all cache entries when pg_tablespace is updated. + * + * When pg_tablespace is updated, we must flush the cache entry at least + * for that tablespace. Currently, we just flush them all. This is quick + * and easy and doesn't cost much, since there shouldn't be terribly many + * tablespaces, nor do we expect them to be frequently modified. + */ +static void +InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr) +{ + HASH_SEQ_STATUS status; + TableSpace *spc; + + hash_seq_init(&status, TableSpaceCacheHash); + while ((spc = (TableSpace *) hash_seq_search(&status)) != NULL) + { + if (hash_search(TableSpaceCacheHash, (void *) &spc->oid, HASH_REMOVE, + NULL) == NULL) + elog(ERROR, "hash table corrupted"); + if (spc->opts) + pfree(spc->opts); + } +} + +/* + * InitializeTableSpaceCache + * Initiate the tablespace cache. + */ +static void +InitializeTableSpaceCache(void) +{ + HASHCTL ctl; + + /* Initialize the hash table. */ + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(Oid); + ctl.entrysize = sizeof(TableSpace); + ctl.hash = tag_hash; + TableSpaceCacheHash = + hash_create("TableSpace cache", 16, &ctl, + HASH_ELEM | HASH_FUNCTION); + + /* Make sure we've initialized CacheMemoryContext. */ + if (!CacheMemoryContext) + CreateCacheMemoryContext(); + + /* Watch for invalidation events. */ + CacheRegisterSyscacheCallback(TABLESPACEOID, + InvalidateTableSpaceCacheCallback, + (Datum) 0); +} + +/* + * get_tablespace + * Fetch TableSpace structure for a specified table OID. + * + * Pointers returned by this function should not be stored, since a cache + * flush will invalidate them. + */ +static TableSpace * +get_tablespace(Oid spcid) +{ + HeapTuple tp; + TableSpace *spc; + bool found; + + /* + * Since spcid is always from a pg_class tuple, InvalidOid implies the + * default. + */ + if (spcid == InvalidOid) + spcid = MyDatabaseTableSpace; + + /* Find existing cache entry, or create a new one. */ + if (!TableSpaceCacheHash) + InitializeTableSpaceCache(); + spc = (TableSpace *) hash_search(TableSpaceCacheHash, (void *) &spcid, + HASH_ENTER, &found); + if (found) + return spc; + + /* + * Not found in TableSpace cache. Check catcache. If we don't find a + * valid HeapTuple, it must mean someone has managed to request tablespace + * details for a non-existent tablespace. We'll just treat that case as if + * no options were specified. + */ + tp = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(spcid), 0, 0, 0); + if (!HeapTupleIsValid(tp)) + spc->opts = NULL; + else + { + Datum datum; + bool isNull; + MemoryContext octx; + + datum = SysCacheGetAttr(TABLESPACEOID, + tp, + Anum_pg_tablespace_spcoptions, + &isNull); + if (isNull) + spc->opts = NULL; + else + { + octx = MemoryContextSwitchTo(CacheMemoryContext); + spc->opts = (TableSpaceOpts *) tablespace_reloptions(datum, false); + MemoryContextSwitchTo(octx); + } + ReleaseSysCache(tp); + } + + /* Update new TableSpace cache entry with results of option parsing. */ + return spc; +} + +/* + * get_tablespace_page_costs + * Return random and sequential page costs for a given tablespace. + */ +void +get_tablespace_page_costs(Oid spcid, double *spc_random_page_cost, + double *spc_seq_page_cost) +{ + TableSpace *spc = get_tablespace(spcid); + + Assert(spc != NULL); + + if (spc_random_page_cost) + { + if (!spc->opts || spc->opts->random_page_cost < 0) + *spc_random_page_cost = random_page_cost; + else + *spc_random_page_cost = spc->opts->random_page_cost; + } + + if (spc_seq_page_cost) + { + if (!spc->opts || spc->opts->seq_page_cost < 0) + *spc_seq_page_cost = seq_page_cost; + else + *spc_seq_page_cost = spc->opts->seq_page_cost; + } +} diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index bd747abc80..f35712732b 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.123 2010/01/02 16:57:56 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.124 2010/01/05 21:53:59 rhaas Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -43,6 +43,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_statistic.h" +#include "catalog/pg_tablespace.h" #include "catalog/pg_ts_config.h" #include "catalog/pg_ts_config_map.h" #include "catalog/pg_ts_dict.h" @@ -609,6 +610,18 @@ static const struct cachedesc cacheinfo[] = { }, 1024 }, + {TableSpaceRelationId, /* TABLESPACEOID */ + TablespaceOidIndexId, + 0, + 1, + { + ObjectIdAttributeNumber, + 0, + 0, + 0, + }, + 16 + }, {TSConfigMapRelationId, /* TSCONFIGMAP */ TSConfigMapIndexId, 0, diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 8ddc038478..f46a29586c 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.129 2010/01/02 16:57:59 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.130 2010/01/05 21:53:59 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -956,19 +956,28 @@ dumpTablespaces(PGconn *conn) * Get all tablespaces except built-in ones (which we assume are named * pg_xxx) */ - if (server_version >= 80200) + if (server_version >= 80500) res = executeQuery(conn, "SELECT spcname, " "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "spclocation, spcacl, " + "array_to_string(spcoptions, ', ')," "pg_catalog.shobj_description(oid, 'pg_tablespace') " "FROM pg_catalog.pg_tablespace " "WHERE spcname !~ '^pg_' " "ORDER BY 1"); + else if (server_version >= 80200) + res = executeQuery(conn, "SELECT spcname, " + "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " + "spclocation, spcacl, null, " + "pg_catalog.shobj_description(oid, 'pg_tablespace'), " + "FROM pg_catalog.pg_tablespace " + "WHERE spcname !~ '^pg_' " + "ORDER BY 1"); else res = executeQuery(conn, "SELECT spcname, " "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "spclocation, spcacl, " - "null " + "null, null " "FROM pg_catalog.pg_tablespace " "WHERE spcname !~ '^pg_' " "ORDER BY 1"); @@ -983,7 +992,8 @@ dumpTablespaces(PGconn *conn) char *spcowner = PQgetvalue(res, i, 1); char *spclocation = PQgetvalue(res, i, 2); char *spcacl = PQgetvalue(res, i, 3); - char *spccomment = PQgetvalue(res, i, 4); + char *spcoptions = PQgetvalue(res, i, 4); + char *spccomment = PQgetvalue(res, i, 5); char *fspcname; /* needed for buildACLCommands() */ @@ -996,6 +1006,10 @@ dumpTablespaces(PGconn *conn) appendStringLiteralConn(buf, spclocation, conn); appendPQExpBuffer(buf, ";\n"); + if (spcoptions && spcoptions[0] != '\0') + appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n", + fspcname, spcoptions); + if (!skip_acls && !buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner, "", server_version, buf)) diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a845c1d83c..f7f5587f7c 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -1,7 +1,8 @@ /*------------------------------------------------------------------------- * * reloptions.h - * Core support for relation options (pg_class.reloptions) + * Core support for relation and tablespace options (pg_class.reloptions + * and pg_tablespace.spcoptions) * * Note: the functions dealing with text-array reloptions values declare * them as Datum, not ArrayType *, to avoid needing to include array.h @@ -11,7 +12,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.17 2010/01/02 16:58:00 momjian Exp $ + * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.18 2010/01/05 21:53:59 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -39,8 +40,9 @@ typedef enum relopt_kind RELOPT_KIND_HASH = (1 << 3), RELOPT_KIND_GIN = (1 << 4), RELOPT_KIND_GIST = (1 << 5), + RELOPT_KIND_TABLESPACE = (1 << 6), /* if you add a new kind, make sure you update "last_default" too */ - RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_GIST, + RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_TABLESPACE, /* some compilers treat enums as signed ints, so we can't use 1 << 31 */ RELOPT_KIND_MAX = (1 << 30) } relopt_kind; @@ -264,5 +266,6 @@ extern bytea *default_reloptions(Datum reloptions, bool validate, extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate); extern bytea *index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate); +extern bytea *tablespace_reloptions(Datum reloptions, bool validate); #endif /* RELOPTIONS_H */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 49bb919818..6e7a8c33fc 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.566 2010/01/04 12:50:49 heikki Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.567 2010/01/05 21:53:59 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201001041 +#define CATALOG_VERSION_NO 201001051 #endif diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h index 1d15cdfa78..1c189f5651 100644 --- a/src/include/catalog/pg_tablespace.h +++ b/src/include/catalog/pg_tablespace.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_tablespace.h,v 1.14 2010/01/05 01:06:57 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_tablespace.h,v 1.15 2010/01/05 21:53:59 rhaas Exp $ * * NOTES * the genbki.pl script reads this file and generates .bki @@ -34,6 +34,7 @@ CATALOG(pg_tablespace,1213) BKI_SHARED_RELATION Oid spcowner; /* owner of tablespace */ text spclocation; /* physical location (VAR LENGTH) */ aclitem spcacl[1]; /* access permissions (VAR LENGTH) */ + text spcoptions[1]; /* per-tablespace options */ } FormData_pg_tablespace; /* ---------------- @@ -48,14 +49,15 @@ typedef FormData_pg_tablespace *Form_pg_tablespace; * ---------------- */ -#define Natts_pg_tablespace 4 +#define Natts_pg_tablespace 5 #define Anum_pg_tablespace_spcname 1 #define Anum_pg_tablespace_spcowner 2 #define Anum_pg_tablespace_spclocation 3 #define Anum_pg_tablespace_spcacl 4 +#define Anum_pg_tablespace_spcoptions 5 -DATA(insert OID = 1663 ( pg_default PGUID "" _null_ )); -DATA(insert OID = 1664 ( pg_global PGUID "" _null_ )); +DATA(insert OID = 1663 ( pg_default PGUID "" _null_ _null_ )); +DATA(insert OID = 1664 ( pg_global PGUID "" _null_ _null_ )); #define DEFAULTTABLESPACE_OID 1663 #define GLOBALTABLESPACE_OID 1664 diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index 332bf46f0a..9330a1f81f 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.21 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.22 2010/01/05 21:53:59 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -32,11 +32,17 @@ typedef struct xl_tblspc_drop_rec Oid ts_id; } xl_tblspc_drop_rec; +typedef struct TableSpaceOpts +{ + float8 random_page_cost; + float8 seq_page_cost; +} TableSpaceOpts; extern void CreateTableSpace(CreateTableSpaceStmt *stmt); extern void DropTableSpace(DropTableSpaceStmt *stmt); extern void RenameTableSpace(const char *oldname, const char *newname); extern void AlterTableSpaceOwner(const char *name, Oid newOwnerId); +extern void AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt); extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index a84de41096..e1da495439 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.232 2010/01/02 16:58:04 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.233 2010/01/05 21:53:59 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -346,6 +346,7 @@ typedef enum NodeTag T_CreateUserMappingStmt, T_AlterUserMappingStmt, T_DropUserMappingStmt, + T_AlterTableSpaceOptionsStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index d94c6f9908..18673ec30d 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.421 2010/01/02 16:58:04 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.422 2010/01/05 21:53:59 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -1477,6 +1477,14 @@ typedef struct DropTableSpaceStmt bool missing_ok; /* skip error if missing? */ } DropTableSpaceStmt; +typedef struct AlterTableSpaceOptionsStmt +{ + NodeTag type; + char *tablespacename; + List *options; + bool isReset; +} AlterTableSpaceOptionsStmt; + /* ---------------------- * Create/Drop FOREIGN DATA WRAPPER Statements * ---------------------- diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index df8f4afc8d..fd93dfcce3 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.182 2010/01/02 16:58:07 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.183 2010/01/05 21:54:00 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -371,6 +371,7 @@ typedef struct RelOptInfo /* information about a base rel (not set for join rels!) */ Index relid; + Oid reltablespace; /* containing tablespace */ RTEKind rtekind; /* RELATION, SUBQUERY, or FUNCTION */ AttrNumber min_attr; /* smallest attrno of rel (often <0) */ AttrNumber max_attr; /* largest attrno of rel */ @@ -435,6 +436,7 @@ typedef struct IndexOptInfo NodeTag type; Oid indexoid; /* OID of the index relation */ + Oid reltablespace; /* tablespace of index (not table) */ RelOptInfo *rel; /* back-link to index's table */ /* statistics from pg_class */ diff --git a/src/include/utils/spccache.h b/src/include/utils/spccache.h new file mode 100644 index 0000000000..73b9f7370d --- /dev/null +++ b/src/include/utils/spccache.h @@ -0,0 +1,19 @@ +/*------------------------------------------------------------------------- + * + * spccache.h + * Tablespace cache. + * + * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $PostgreSQL: pgsql/src/include/utils/spccache.h,v 1.1 2010/01/05 21:54:00 rhaas Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef SPCCACHE_H +#define SPCCACHE_H + +void get_tablespace_page_costs(Oid spcid, float8 *spc_random_page_cost, + float8 *spc_seq_page_cost); + +#endif /* SPCCACHE_H */ diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 6b12c84da2..8cdd7e79ee 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.77 2010/01/02 16:58:10 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.78 2010/01/05 21:54:00 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -71,6 +71,7 @@ enum SysCacheIdentifier RELOID, RULERELNAME, STATRELATTINH, + TABLESPACEOID, TSCONFIGMAP, TSCONFIGNAMENSP, TSCONFIGOID, diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source index df5479d589..dba96f4547 100644 --- a/src/test/regress/input/tablespace.source +++ b/src/test/regress/input/tablespace.source @@ -1,6 +1,12 @@ -- create a tablespace we can use CREATE TABLESPACE testspace LOCATION '@testtablespace@'; +-- try setting and resetting some properties for the new tablespace +ALTER TABLESPACE testspace SET (random_page_cost = 1.0); +ALTER TABLESPACE testspace SET (some_nonexistent_parameter = true); -- fail +ALTER TABLESPACE testspace RESET (random_page_cost = 2.0); -- fail +ALTER TABLESPACE testspace RESET (random_page_cost, seq_page_cost); -- 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 e57ad2b217..79b12a8698 100644 --- a/src/test/regress/output/tablespace.source +++ b/src/test/regress/output/tablespace.source @@ -1,5 +1,12 @@ -- create a tablespace we can use CREATE TABLESPACE testspace LOCATION '@testtablespace@'; +-- try setting and resetting some properties for the new tablespace +ALTER TABLESPACE testspace SET (random_page_cost = 1.0); +ALTER TABLESPACE testspace SET (some_nonexistent_parameter = true); -- fail +ERROR: unrecognized parameter "some_nonexistent_parameter" +ALTER TABLESPACE testspace RESET (random_page_cost = 2.0); -- fail +ERROR: RESET must not include values for parameters +ALTER TABLESPACE testspace RESET (random_page_cost, seq_page_cost); -- ok -- create a schema we can use CREATE SCHEMA testschema; -- try a table