diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index bb32690788..9d21ee6b07 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -175,7 +175,12 @@ static int maxSharedInvalidMessagesArray; /* * Dynamically-registered callback functions. Current implementation - * assumes there won't be very many of these at once; could improve if needed. + * assumes there won't be enough of these to justify a dynamically resizable + * array; it'd be easy to improve that if needed. + * + * To avoid searching in CallSyscacheCallbacks, all callbacks for a given + * syscache are linked into a list pointed to by syscache_callback_links[id]. + * The link values are syscache_callback_list[] index plus 1, or 0 for none. */ #define MAX_SYSCACHE_CALLBACKS 64 @@ -184,10 +189,13 @@ static int maxSharedInvalidMessagesArray; static struct SYSCACHECALLBACK { int16 id; /* cache number */ + int16 link; /* next callback index+1 for same cache */ SyscacheCallbackFunction function; Datum arg; } syscache_callback_list[MAX_SYSCACHE_CALLBACKS]; +static int16 syscache_callback_links[SysCacheSize]; + static int syscache_callback_count = 0; static struct RELCACHECALLBACK @@ -1355,10 +1363,28 @@ CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg) { + if (cacheid < 0 || cacheid >= SysCacheSize) + elog(FATAL, "invalid cache ID: %d", cacheid); if (syscache_callback_count >= MAX_SYSCACHE_CALLBACKS) elog(FATAL, "out of syscache_callback_list slots"); + if (syscache_callback_links[cacheid] == 0) + { + /* first callback for this cache */ + syscache_callback_links[cacheid] = syscache_callback_count + 1; + } + else + { + /* add to end of chain, so that older callbacks are called first */ + int i = syscache_callback_links[cacheid] - 1; + + while (syscache_callback_list[i].link > 0) + i = syscache_callback_list[i].link - 1; + syscache_callback_list[i].link = syscache_callback_count + 1; + } + syscache_callback_list[syscache_callback_count].id = cacheid; + syscache_callback_list[syscache_callback_count].link = 0; syscache_callback_list[syscache_callback_count].function = func; syscache_callback_list[syscache_callback_count].arg = arg; @@ -1398,11 +1424,16 @@ CallSyscacheCallbacks(int cacheid, uint32 hashvalue) { int i; - for (i = 0; i < syscache_callback_count; i++) + if (cacheid < 0 || cacheid >= SysCacheSize) + elog(ERROR, "invalid cache ID: %d", cacheid); + + i = syscache_callback_links[cacheid] - 1; + while (i >= 0) { struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i; - if (ccitem->id == cacheid) - (*ccitem->function) (ccitem->arg, cacheid, hashvalue); + Assert(ccitem->id == cacheid); + (*ccitem->function) (ccitem->arg, cacheid, hashvalue); + i = ccitem->link - 1; } } diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index ef7541e2bb..9fc1870442 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -845,8 +845,6 @@ static const struct cachedesc cacheinfo[] = { } }; -#define SysCacheSize ((int) lengthof(cacheinfo)) - static CatCache *SysCache[SysCacheSize]; static bool CacheInitialized = false; @@ -877,6 +875,9 @@ InitCatalogCache(void) int i, j; + StaticAssertStmt(SysCacheSize == (int) lengthof(cacheinfo), + "SysCacheSize does not match syscache.c's array"); + Assert(!CacheInitialized); SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0; diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index ec83e4a096..d4ac93d958 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -97,6 +97,8 @@ enum SysCacheIdentifier TYPEOID, USERMAPPINGOID, USERMAPPINGUSERSERVER + +#define SysCacheSize (USERMAPPINGUSERSERVER + 1) }; extern void InitCatalogCache(void);