mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-30 01:17:19 +02:00
Reduce overhead of cache-clobber testing in LookupOpclassInfo().
Commit03ffc4d6d
added logic to bypass all caching behavior in LookupOpclassInfo when CLOBBER_CACHE_ALWAYS is enabled. It doesn't look like I stopped to think much about what that would cost, but recent investigation shows that the cost is enormous: it roughly doubles the time needed for cache-clobber test runs. There does seem to be value in this behavior when trying to test the opclass-cache loading logic itself, but for other purposes the cost is excessive. Hence, let's back off to doing this only when debug_invalidate_system_caches_always is at least 3; or in older branches, when CLOBBER_CACHE_RECURSIVELY is defined. While here, clean up some other minor issues in LookupOpclassInfo. Re-order the code so we aren't left with broken cache entries (leading to later core dumps) in the unlikely case that we suffer OOM while trying to allocate space for a new entry. (That seems to be my oversight in 03ffc4d6d.) Also, in >= v13, stop allocating one array entry too many. That's evidently left over from sloppy reversion in851b14b0c
. Back-patch to all supported branches, mainly to reduce the runtime of cache-clobbering buildfarm animals. Discussion: https://postgr.es/m/1370856.1625428625@sss.pgh.pa.us
This commit is contained in:
parent
73ede4da6b
commit
3edc2dbc00
43
src/backend/utils/cache/relcache.c
vendored
43
src/backend/utils/cache/relcache.c
vendored
@ -1612,15 +1612,15 @@ LookupOpclassInfo(Oid operatorClassOid,
|
|||||||
/* First time through: initialize the opclass cache */
|
/* First time through: initialize the opclass cache */
|
||||||
HASHCTL ctl;
|
HASHCTL ctl;
|
||||||
|
|
||||||
|
/* Also make sure CacheMemoryContext exists */
|
||||||
|
if (!CacheMemoryContext)
|
||||||
|
CreateCacheMemoryContext();
|
||||||
|
|
||||||
MemSet(&ctl, 0, sizeof(ctl));
|
MemSet(&ctl, 0, sizeof(ctl));
|
||||||
ctl.keysize = sizeof(Oid);
|
ctl.keysize = sizeof(Oid);
|
||||||
ctl.entrysize = sizeof(OpClassCacheEnt);
|
ctl.entrysize = sizeof(OpClassCacheEnt);
|
||||||
OpClassCache = hash_create("Operator class cache", 64,
|
OpClassCache = hash_create("Operator class cache", 64,
|
||||||
&ctl, HASH_ELEM | HASH_BLOBS);
|
&ctl, HASH_ELEM | HASH_BLOBS);
|
||||||
|
|
||||||
/* Also make sure CacheMemoryContext exists */
|
|
||||||
if (!CacheMemoryContext)
|
|
||||||
CreateCacheMemoryContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
|
opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
|
||||||
@ -1629,16 +1629,10 @@ LookupOpclassInfo(Oid operatorClassOid,
|
|||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
/* Need to allocate memory for new entry */
|
/* Initialize new entry */
|
||||||
opcentry->valid = false; /* until known OK */
|
opcentry->valid = false; /* until known OK */
|
||||||
opcentry->numSupport = numSupport;
|
opcentry->numSupport = numSupport;
|
||||||
|
opcentry->supportProcs = NULL; /* filled below */
|
||||||
if (numSupport > 0)
|
|
||||||
opcentry->supportProcs = (RegProcedure *)
|
|
||||||
MemoryContextAllocZero(CacheMemoryContext,
|
|
||||||
numSupport * sizeof(RegProcedure));
|
|
||||||
else
|
|
||||||
opcentry->supportProcs = NULL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1646,13 +1640,15 @@ LookupOpclassInfo(Oid operatorClassOid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When testing for cache-flush hazards, we intentionally disable the
|
* When aggressively testing cache-flush hazards, we disable the operator
|
||||||
* operator class cache and force reloading of the info on each call. This
|
* class cache and force reloading of the info on each call. This models
|
||||||
* is helpful because we want to test the case where a cache flush occurs
|
* no real-world behavior, since the cache entries are never invalidated
|
||||||
* while we are loading the info, and it's very hard to provoke that if
|
* otherwise. However it can be helpful for detecting bugs in the cache
|
||||||
* this happens only once per opclass per backend.
|
* 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 in CLOBBER_CACHE_RECURSIVELY mode.
|
||||||
*/
|
*/
|
||||||
#if defined(CLOBBER_CACHE_ALWAYS)
|
#if defined(CLOBBER_CACHE_RECURSIVELY)
|
||||||
opcentry->valid = false;
|
opcentry->valid = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1660,8 +1656,15 @@ LookupOpclassInfo(Oid operatorClassOid,
|
|||||||
return opcentry;
|
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
|
* 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
|
* looking up info for the opclasses used by the indexes we would like to
|
||||||
* reference here.
|
* reference here.
|
||||||
|
Loading…
Reference in New Issue
Block a user