Skip to content

Commit 9753324

Browse files
committed
Reduce overhead of cache-clobber testing in LookupOpclassInfo().
Commit 03ffc4d 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 03ffc4d.) Also, in >= v13, stop allocating one array entry too many. That's evidently left over from sloppy reversion in 851b14b. 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
1 parent c04c767 commit 9753324

File tree

1 file changed

+24
-20
lines changed

1 file changed

+24
-20
lines changed

src/backend/utils/cache/relcache.c

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,14 +1594,14 @@ LookupOpclassInfo(Oid operatorClassOid,
15941594
/* First time through: initialize the opclass cache */
15951595
HASHCTL ctl;
15961596

1597+
/* Also make sure CacheMemoryContext exists */
1598+
if (!CacheMemoryContext)
1599+
CreateCacheMemoryContext();
1600+
15971601
ctl.keysize = sizeof(Oid);
15981602
ctl.entrysize = sizeof(OpClassCacheEnt);
15991603
OpClassCache = hash_create("Operator class cache", 64,
16001604
&ctl, HASH_ELEM | HASH_BLOBS);
1601-
1602-
/* Also make sure CacheMemoryContext exists */
1603-
if (!CacheMemoryContext)
1604-
CreateCacheMemoryContext();
16051605
}
16061606

16071607
opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
@@ -1610,40 +1610,44 @@ LookupOpclassInfo(Oid operatorClassOid,
16101610

16111611
if (!found)
16121612
{
1613-
/* Need to allocate memory for new entry */
1613+
/* Initialize new entry */
16141614
opcentry->valid = false; /* until known OK */
16151615
opcentry->numSupport = numSupport;
1616-
1617-
if (numSupport > 0)
1618-
opcentry->supportProcs = (RegProcedure *)
1619-
MemoryContextAllocZero(CacheMemoryContext,
1620-
(numSupport + 1) * sizeof(RegProcedure));
1621-
else
1622-
opcentry->supportProcs = NULL;
1616+
opcentry->supportProcs = NULL; /* filled below */
16231617
}
16241618
else
16251619
{
16261620
Assert(numSupport == opcentry->numSupport);
16271621
}
16281622

16291623
/*
1630-
* When testing for cache-flush hazards, we intentionally disable the
1631-
* operator class cache and force reloading of the info on each call. This
1632-
* is helpful because we want to test the case where a cache flush occurs
1633-
* while we are loading the info, and it's very hard to provoke that if
1634-
* this happens only once per opclass per backend.
1624+
* When aggressively testing cache-flush hazards, we disable the operator
1625+
* class cache and force reloading of the info on each call. This models
1626+
* no real-world behavior, since the cache entries are never invalidated
1627+
* otherwise. However it can be helpful for detecting bugs in the cache
1628+
* loading logic itself, such as reliance on a non-nailed index. Given
1629+
* the limited use-case and the fact that this adds a great deal of
1630+
* expense, we enable it only for high values of
1631+
* debug_invalidate_system_caches_always.
16351632
*/
16361633
#ifdef CLOBBER_CACHE_ENABLED
1637-
if (debug_invalidate_system_caches_always > 0)
1634+
if (debug_invalidate_system_caches_always > 2)
16381635
opcentry->valid = false;
16391636
#endif
16401637

16411638
if (opcentry->valid)
16421639
return opcentry;
16431640

16441641
/*
1645-
* Need to fill in new entry.
1646-
*
1642+
* Need to fill in new entry. First allocate space, unless we already did
1643+
* so in some previous attempt.
1644+
*/
1645+
if (opcentry->supportProcs == NULL && numSupport > 0)
1646+
opcentry->supportProcs = (RegProcedure *)
1647+
MemoryContextAllocZero(CacheMemoryContext,
1648+
numSupport * sizeof(RegProcedure));
1649+
1650+
/*
16471651
* To avoid infinite recursion during startup, force heap scans if we're
16481652
* looking up info for the opclasses used by the indexes we would like to
16491653
* reference here.

0 commit comments

Comments
 (0)