diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 94fbf1aa19..5dac9f0696 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1594,14 +1594,14 @@ LookupOpclassInfo(Oid operatorClassOid, /* First time through: initialize the opclass cache */ HASHCTL ctl; + /* Also make sure CacheMemoryContext exists */ + if (!CacheMemoryContext) + CreateCacheMemoryContext(); + ctl.keysize = sizeof(Oid); ctl.entrysize = sizeof(OpClassCacheEnt); OpClassCache = hash_create("Operator class cache", 64, &ctl, HASH_ELEM | HASH_BLOBS); - - /* Also make sure CacheMemoryContext exists */ - if (!CacheMemoryContext) - CreateCacheMemoryContext(); } opcentry = (OpClassCacheEnt *) hash_search(OpClassCache, @@ -1610,16 +1610,10 @@ LookupOpclassInfo(Oid operatorClassOid, if (!found) { - /* Need to allocate memory for new entry */ + /* Initialize new entry */ opcentry->valid = false; /* until known OK */ opcentry->numSupport = numSupport; - - if (numSupport > 0) - opcentry->supportProcs = (RegProcedure *) - MemoryContextAllocZero(CacheMemoryContext, - (numSupport + 1) * sizeof(RegProcedure)); - else - opcentry->supportProcs = NULL; + opcentry->supportProcs = NULL; /* filled below */ } else { @@ -1627,14 +1621,17 @@ LookupOpclassInfo(Oid operatorClassOid, } /* - * When testing for cache-flush hazards, we intentionally disable the - * operator class cache and force reloading of the info on each call. This - * is helpful because we want to test the case where a cache flush occurs - * while we are loading the info, and it's very hard to provoke that if - * this happens only once per opclass per backend. + * When aggressively testing cache-flush hazards, we disable the operator + * class cache and force reloading of the info on each call. This models + * no real-world behavior, since the cache entries are never invalidated + * otherwise. However it can be helpful for detecting bugs in the cache + * loading logic itself, such as reliance on a non-nailed index. Given + * the limited use-case and the fact that this adds a great deal of + * expense, we enable it only for high values of + * debug_invalidate_system_caches_always. */ #ifdef CLOBBER_CACHE_ENABLED - if (debug_invalidate_system_caches_always > 0) + if (debug_invalidate_system_caches_always > 2) opcentry->valid = false; #endif @@ -1642,8 +1639,15 @@ LookupOpclassInfo(Oid operatorClassOid, return opcentry; /* - * Need to fill in new entry. - * + * Need to fill in new entry. First allocate space, unless we already did + * so in some previous attempt. + */ + if (opcentry->supportProcs == NULL && numSupport > 0) + opcentry->supportProcs = (RegProcedure *) + MemoryContextAllocZero(CacheMemoryContext, + numSupport * sizeof(RegProcedure)); + + /* * To avoid infinite recursion during startup, force heap scans if we're * looking up info for the opclasses used by the indexes we would like to * reference here.