diff options
Diffstat (limited to 'src/backend/utils/cache/inval.c')
-rw-r--r-- | src/backend/utils/cache/inval.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 72c8e9e0c48..a1e6ea2a356 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -177,7 +177,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 @@ -186,10 +191,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 @@ -1383,10 +1391,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; @@ -1426,11 +1452,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; } } |