diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-09-02 03:16:46 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-09-02 03:16:46 +0000 |
commit | 9513918c6c4d4f370ceb7c7d1b1a5a152aea091c (patch) | |
tree | a5d3c2dd055ac17de2b273668fb6873965693add /src/backend/utils/cache/typcache.c | |
parent | f3c903f86757a0e25f2781c438dab1738b773d0e (diff) | |
download | postgresql-9513918c6c4d4f370ceb7c7d1b1a5a152aea091c.tar.gz postgresql-9513918c6c4d4f370ceb7c7d1b1a5a152aea091c.zip |
Fix up flushing of composite-type typcache entries to be driven directly by
SI invalidation events, rather than indirectly through the relcache.
In the previous coding, we had to flush a composite-type typcache entry
whenever we discarded the corresponding relcache entry. This caused problems
at least when testing with RELCACHE_FORCE_RELEASE, as shown in recent report
from Jeff Davis, and might result in real-world problems given the kind of
unexpected relcache flush that that test mechanism is intended to model.
The new coding decouples relcache and typcache management, which is a good
thing anyway from a structural perspective. The cost is that we have to
search the typcache linearly to find entries that need to be flushed. There
are a couple of ways we could avoid that, but at the moment it's not clear
it's worth any extra trouble, because the typcache contains very few entries
in typical operation.
Back-patch to 8.2, the same as some other recent fixes in this general area.
The patch could be carried back to 8.0 with some additional work, but given
that it's only hypothetical whether we're fixing any problem observable in
the field, it doesn't seem worth the work now.
Diffstat (limited to 'src/backend/utils/cache/typcache.c')
-rw-r--r-- | src/backend/utils/cache/typcache.c | 81 |
1 files changed, 51 insertions, 30 deletions
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index 35b63516362..8d0d753a3e0 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -4,14 +4,14 @@ * POSTGRES type cache code * * The type cache exists to speed lookup of certain information about data - * types that is not directly available from a type's pg_type row. In - * particular, we use a type's default btree opclass, or the default hash + * types that is not directly available from a type's pg_type row. For + * example, we use a type's default btree opclass, or the default hash * opclass if no btree opclass exists, to determine which operators should * be used for grouping and sorting the type (GROUP BY, ORDER BY ASC/DESC). * * Several seemingly-odd choices have been made to support use of the type * cache by the generic array comparison routines array_eq() and array_cmp(). - * Because these routines are used as index support operations, they cannot + * Because those routines are used as index support operations, they cannot * leak memory. To allow them to execute efficiently, all information that * either of them would like to re-use across calls is made available in the * type cache. @@ -36,7 +36,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.32 2010/02/14 18:42:17 rhaas Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.33 2010/09/02 03:16:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -48,6 +48,7 @@ #include "catalog/pg_type.h" #include "commands/defrem.h" #include "utils/builtins.h" +#include "utils/inval.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -86,6 +87,8 @@ static TupleDesc *RecordCacheArray = NULL; static int32 RecordCacheArrayLen = 0; /* allocated length of array */ static int32 NextRecordTypmod = 0; /* number of entries used */ +static void TypeCacheRelCallback(Datum arg, Oid relid); + /* * lookup_type_cache @@ -116,6 +119,9 @@ lookup_type_cache(Oid type_id, int flags) TypeCacheHash = hash_create("Type information cache", 64, &ctl, HASH_ELEM | HASH_FUNCTION); + /* Also set up a callback for relcache SI invalidations */ + CacheRegisterRelcacheCallback(TypeCacheRelCallback, (Datum) 0); + /* Also make sure CacheMemoryContext exists */ if (!CacheMemoryContext) CreateCacheMemoryContext(); @@ -497,36 +503,51 @@ assign_record_type_typmod(TupleDesc tupDesc) } /* - * flush_rowtype_cache + * TypeCacheRelCallback + * Relcache inval callback function + * + * Delete the cached tuple descriptor (if any) for the given rel's composite + * type, or for all composite types if relid == InvalidOid. * - * If a typcache entry exists for a rowtype, delete the entry's cached - * tuple descriptor link. This is called from relcache.c when a cached - * relation tupdesc is about to be dropped. + * This is called when a relcache invalidation event occurs for the given + * relid. We must scan the whole typcache hash since we don't know the + * type OID corresponding to the relid. We could do a direct search if this + * were a syscache-flush callback on pg_type, but then we would need all + * ALTER-TABLE-like commands that could modify a rowtype to issue syscache + * invals against the rel's pg_type OID. The extra SI signaling could very + * well cost more than we'd save, since in most usages there are not very + * many entries in a backend's typcache. The risk of bugs-of-omission seems + * high, too. + * + * Another possibility, with only localized impact, is to maintain a second + * hashtable that indexes composite-type typcache entries by their typrelid. + * But it's still not clear it's worth the trouble. */ -void -flush_rowtype_cache(Oid type_id) +static void +TypeCacheRelCallback(Datum arg, Oid relid) { + HASH_SEQ_STATUS status; TypeCacheEntry *typentry; - if (TypeCacheHash == NULL) - return; /* no table, so certainly no entry */ - - typentry = (TypeCacheEntry *) hash_search(TypeCacheHash, - (void *) &type_id, - HASH_FIND, NULL); - if (typentry == NULL) - return; /* no matching entry */ - if (typentry->tupDesc == NULL) - return; /* tupdesc hasn't been requested */ - - /* - * Release our refcount and free the tupdesc if none remain. (Can't use - * DecrTupleDescRefCount because this reference is not logged in current - * resource owner.) - */ - Assert(typentry->tupDesc->tdrefcount > 0); - if (--typentry->tupDesc->tdrefcount == 0) - FreeTupleDesc(typentry->tupDesc); + /* TypeCacheHash must exist, else this callback wouldn't be registered */ + hash_seq_init(&status, TypeCacheHash); + while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL) + { + if (typentry->tupDesc == NULL) + continue; /* not composite, or tupdesc hasn't been requested */ - typentry->tupDesc = NULL; + /* Delete if match, or if we're zapping all composite types */ + if (relid == typentry->typrelid || relid == InvalidOid) + { + /* + * Release our refcount, and free the tupdesc if none remain. + * (Can't use DecrTupleDescRefCount because this reference is not + * logged in current resource owner.) + */ + Assert(typentry->tupDesc->tdrefcount > 0); + if (--typentry->tupDesc->tdrefcount == 0) + FreeTupleDesc(typentry->tupDesc); + typentry->tupDesc = NULL; + } + } } |