mirror of https://github.com/postgres/postgres
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.REL9_0_ALPHA4_BRANCH
parent
72559b49c0
commit
d86d51a958
@ -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; |
||||
} |
||||
} |
@ -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 */ |
Loading…
Reference in new issue