From d779199175b3db630f2eab1e6316da2386ca0d2a Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 22 Jan 2010 16:42:31 +0000 Subject: [PATCH] Fix several oversights in previous commit - attribute options patch. I failed to 'cvs add' the new files and also neglected to bump catversion. --- src/backend/utils/cache/attoptcache.c | 181 ++++++++++++++++++++++++++++++++++ src/include/catalog/catversion.h | 4 +- src/include/utils/attoptcache.h | 28 ++++++ 3 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 src/backend/utils/cache/attoptcache.c create mode 100644 src/include/utils/attoptcache.h diff --git a/src/backend/utils/cache/attoptcache.c b/src/backend/utils/cache/attoptcache.c new file mode 100644 index 0000000000..f553655803 --- /dev/null +++ b/src/backend/utils/cache/attoptcache.c @@ -0,0 +1,181 @@ +/*------------------------------------------------------------------------- + * + * attoptcache.c + * Attribute options cache management. + * + * Attribute options are cached separately from the fixed-size portion of + * pg_attribute entries, which are handled by the relcache. + * + * 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/attoptcache.c,v 1.1 2010/01/22 16:42:31 rhaas Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/reloptions.h" +#include "catalog/pg_attribute.h" +#include "utils/attoptcache.h" +#include "utils/catcache.h" +#include "utils/hsearch.h" +#include "utils/inval.h" +#include "utils/rel.h" +#include "utils/syscache.h" + + +/* Hash table for informations about each attribute's options */ +static HTAB *AttoptCacheHash = NULL; + +/* attrelid and attnum form the lookup key, and must appear first */ +typedef struct +{ + Oid attrelid; + int attnum; +} AttoptCacheKey; + +typedef struct +{ + AttoptCacheKey key; /* lookup key - must be first */ + AttributeOpts *opts; /* options, or NULL if none */ +} AttoptCacheEntry; + + +/* + * InvalidateAttoptCacheCallback + * Flush all cache entries when pg_attribute is updated. + * + * When pg_attribute is updated, we must flush the cache entry at least + * for that attribute. Currently, we just flush them all. Since attribute + * options are not currently used in performance-critical paths (such as + * query execution), this seems OK. + */ +static void +InvalidateAttoptCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr) +{ + HASH_SEQ_STATUS status; + AttoptCacheEntry *attopt; + + hash_seq_init(&status, AttoptCacheHash); + while ((attopt = (AttoptCacheEntry *) hash_seq_search(&status)) != NULL) + { + if (attopt->opts) + pfree(attopt->opts); + if (hash_search(AttoptCacheHash, + (void *) &attopt->key, + HASH_REMOVE, + NULL) == NULL) + elog(ERROR, "hash table corrupted"); + } +} + +/* + * InitializeAttoptCache + * Initialize the tablespace cache. + */ +static void +InitializeAttoptCache(void) +{ + HASHCTL ctl; + + /* Initialize the hash table. */ + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(AttoptCacheKey); + ctl.entrysize = sizeof(AttoptCacheEntry); + ctl.hash = tag_hash; + AttoptCacheHash = + hash_create("Attopt cache", 256, &ctl, + HASH_ELEM | HASH_FUNCTION); + + /* Make sure we've initialized CacheMemoryContext. */ + if (!CacheMemoryContext) + CreateCacheMemoryContext(); + + /* Watch for invalidation events. */ + CacheRegisterSyscacheCallback(ATTNUM, + InvalidateAttoptCacheCallback, + (Datum) 0); +} + +/* + * get_attribute_options + * Fetch attribute options for a specified table OID. + */ +AttributeOpts * +get_attribute_options(Oid attrelid, int attnum) +{ + AttoptCacheKey key; + AttoptCacheEntry *attopt; + AttributeOpts *result; + HeapTuple tp; + + /* Find existing cache entry, if any. */ + if (!AttoptCacheHash) + InitializeAttoptCache(); + memset(&key, 0, sizeof(key)); /* make sure any padding bits are unset */ + key.attrelid = attrelid; + key.attnum = attnum; + attopt = + (AttoptCacheEntry *) hash_search(AttoptCacheHash, + (void *) &key, + HASH_FIND, + NULL); + + /* Not found in Attopt cache. Construct new cache entry. */ + if (!attopt) + { + AttributeOpts *opts; + + tp = SearchSysCache(ATTNUM, + ObjectIdGetDatum(attrelid), + Int16GetDatum(attnum), + 0, 0); + + /* + * If we don't find a valid HeapTuple, it must mean someone has + * managed to request attribute details for a non-existent attribute. + * We treat that case as if no options were specified. + */ + if (!HeapTupleIsValid(tp)) + opts = NULL; + else + { + Datum datum; + bool isNull; + + datum = SysCacheGetAttr(ATTNUM, + tp, + Anum_pg_attribute_attoptions, + &isNull); + if (isNull) + opts = NULL; + else + { + bytea *bytea_opts = attribute_reloptions(datum, false); + opts = MemoryContextAlloc(CacheMemoryContext, + VARSIZE(bytea_opts)); + memcpy(opts, bytea_opts, VARSIZE(bytea_opts)); + } + ReleaseSysCache(tp); + } + + /* + * It's important to create the actual cache entry only after + * reading pg_attribute, since the read could cause a cache flush. + */ + attopt = (AttoptCacheEntry *) hash_search(AttoptCacheHash, + (void *) &key, + HASH_ENTER, + NULL); + attopt->opts = opts; + } + + /* Return results in caller's memory context. */ + if (attopt->opts == NULL) + return NULL; + result = palloc(VARSIZE(attopt->opts)); + memcpy(result, attopt->opts, VARSIZE(attopt->opts)); + return result; +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 29e04bea01..33ce640906 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.577 2010/01/22 15:45:15 petere Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.578 2010/01/22 16:42:31 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201001221 +#define CATALOG_VERSION_NO 201001222 #endif diff --git a/src/include/utils/attoptcache.h b/src/include/utils/attoptcache.h new file mode 100644 index 0000000000..017bcbd91e --- /dev/null +++ b/src/include/utils/attoptcache.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * attoptcache.h + * Attribute options 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/attoptcache.h,v 1.1 2010/01/22 16:42:31 rhaas Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef SPCCACHE_H +#define SPCCACHE_H + +/* + * Attribute options. + */ +typedef struct AttributeOpts +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + float8 n_distinct; + float8 n_distinct_inherited; +} AttributeOpts; + +AttributeOpts *get_attribute_options(Oid spcid, int attnum); + +#endif /* SPCCACHE_H */ -- 2.11.0