mirror of
https://github.com/postgres/postgres.git
synced 2025-05-13 01:13:08 -04:00
walsender.h should depend on xlog.h, not vice versa. (Actually, the inclusion was circular until a couple hours ago, which was even sillier; but Bruce broke it in the expedient rather than logically correct direction.) Because of that poor decision, plus blind application of pgrminclude, we had a situation where half the system was depending on xlog.h to include such unrelated stuff as array.h and guc.h. Clean up the header inclusion, and manually revert a lot of what pgrminclude had done so things build again. This episode reinforces my feeling that pgrminclude should not be run without adult supervision. Inclusion changes in header files in particular need to be reviewed with great care. More generally, it'd be good if we had a clearer notion of module layering to dictate which headers can sanely include which others ... but that's a big task for another day.
201 lines
5.1 KiB
C
201 lines
5.1 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* 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-2011, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* IDENTIFICATION
|
|
* src/backend/utils/cache/spccache.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#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/hsearch.h"
|
|
#include "utils/inval.h"
|
|
#include "utils/spccache.h"
|
|
#include "utils/syscache.h"
|
|
|
|
|
|
/* Hash table for information about each tablespace */
|
|
static HTAB *TableSpaceCacheHash = NULL;
|
|
|
|
typedef struct
|
|
{
|
|
Oid oid; /* lookup key - must be first */
|
|
TableSpaceOpts *opts; /* options, or NULL if none */
|
|
} TableSpaceCacheEntry;
|
|
|
|
|
|
/*
|
|
* 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, uint32 hashvalue)
|
|
{
|
|
HASH_SEQ_STATUS status;
|
|
TableSpaceCacheEntry *spc;
|
|
|
|
hash_seq_init(&status, TableSpaceCacheHash);
|
|
while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
|
|
{
|
|
if (spc->opts)
|
|
pfree(spc->opts);
|
|
if (hash_search(TableSpaceCacheHash,
|
|
(void *) &spc->oid,
|
|
HASH_REMOVE,
|
|
NULL) == NULL)
|
|
elog(ERROR, "hash table corrupted");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* InitializeTableSpaceCache
|
|
* Initialize 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(TableSpaceCacheEntry);
|
|
ctl.hash = oid_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 TableSpaceCacheEntry structure for a specified table OID.
|
|
*
|
|
* Pointers returned by this function should not be stored, since a cache
|
|
* flush will invalidate them.
|
|
*/
|
|
static TableSpaceCacheEntry *
|
|
get_tablespace(Oid spcid)
|
|
{
|
|
TableSpaceCacheEntry *spc;
|
|
HeapTuple tp;
|
|
TableSpaceOpts *opts;
|
|
|
|
/*
|
|
* Since spcid is always from a pg_class tuple, InvalidOid implies the
|
|
* default.
|
|
*/
|
|
if (spcid == InvalidOid)
|
|
spcid = MyDatabaseTableSpace;
|
|
|
|
/* Find existing cache entry, if any. */
|
|
if (!TableSpaceCacheHash)
|
|
InitializeTableSpaceCache();
|
|
spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
|
|
(void *) &spcid,
|
|
HASH_FIND,
|
|
NULL);
|
|
if (spc)
|
|
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 = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcid));
|
|
if (!HeapTupleIsValid(tp))
|
|
opts = NULL;
|
|
else
|
|
{
|
|
Datum datum;
|
|
bool isNull;
|
|
|
|
datum = SysCacheGetAttr(TABLESPACEOID,
|
|
tp,
|
|
Anum_pg_tablespace_spcoptions,
|
|
&isNull);
|
|
if (isNull)
|
|
opts = NULL;
|
|
else
|
|
{
|
|
bytea *bytea_opts = tablespace_reloptions(datum, false);
|
|
|
|
opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
|
|
memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
|
|
}
|
|
ReleaseSysCache(tp);
|
|
}
|
|
|
|
/*
|
|
* Now create the cache entry. It's important to do this only after
|
|
* reading the pg_tablespace entry, since doing so could cause a cache
|
|
* flush.
|
|
*/
|
|
spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
|
|
(void *) &spcid,
|
|
HASH_ENTER,
|
|
NULL);
|
|
spc->opts = opts;
|
|
return spc;
|
|
}
|
|
|
|
/*
|
|
* get_tablespace_page_costs
|
|
* Return random and/or sequential page costs for a given tablespace.
|
|
*/
|
|
void
|
|
get_tablespace_page_costs(Oid spcid,
|
|
double *spc_random_page_cost,
|
|
double *spc_seq_page_cost)
|
|
{
|
|
TableSpaceCacheEntry *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;
|
|
}
|
|
}
|