1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-23 14:01:44 +03:00

Improve the plan cache invalidation mechanism to make it invalidate plans

when user-defined functions used in a plan are modified.  Also invalidate
plans when schemas, operators, or operator classes are modified; but for these
cases we just invalidate everything rather than tracking exact dependencies,
since these types of objects seldom change in a production database.

Tom Lane; loosely based on a patch by Martin Pihlak.
This commit is contained in:
Tom Lane
2008-09-09 18:58:09 +00:00
parent c06629c72e
commit ee33b95d9c
18 changed files with 522 additions and 275 deletions

View File

@ -80,7 +80,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.86 2008/06/19 21:32:56 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.87 2008/09/09 18:58:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -160,16 +160,25 @@ static TransInvalidationInfo *transInvalInfo = NULL;
* assumes there won't be very many of these at once; could improve if needed.
*/
#define MAX_CACHE_CALLBACKS 20
#define MAX_SYSCACHE_CALLBACKS 20
#define MAX_RELCACHE_CALLBACKS 5
static struct CACHECALLBACK
static struct SYSCACHECALLBACK
{
int16 id; /* cache number or message type id */
CacheCallbackFunction function;
int16 id; /* cache number */
SyscacheCallbackFunction function;
Datum arg;
} cache_callback_list[MAX_CACHE_CALLBACKS];
} syscache_callback_list[MAX_SYSCACHE_CALLBACKS];
static int cache_callback_count = 0;
static int syscache_callback_count = 0;
static struct RELCACHECALLBACK
{
RelcacheCallbackFunction function;
Datum arg;
} relcache_callback_list[MAX_RELCACHE_CALLBACKS];
static int relcache_callback_count = 0;
/* info values for 2PC callback */
#define TWOPHASE_INFO_MSG 0 /* SharedInvalidationMessage */
@ -484,12 +493,13 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
msg->cc.hashValue,
&msg->cc.tuplePtr);
for (i = 0; i < cache_callback_count; i++)
for (i = 0; i < syscache_callback_count; i++)
{
struct CACHECALLBACK *ccitem = cache_callback_list + i;
struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i;
if (ccitem->id == msg->cc.id)
(*ccitem->function) (ccitem->arg, InvalidOid);
(*ccitem->function) (ccitem->arg,
msg->cc.id, &msg->cc.tuplePtr);
}
}
}
@ -499,12 +509,11 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
{
RelationCacheInvalidateEntry(msg->rc.relId);
for (i = 0; i < cache_callback_count; i++)
for (i = 0; i < relcache_callback_count; i++)
{
struct CACHECALLBACK *ccitem = cache_callback_list + i;
struct RELCACHECALLBACK *ccitem = relcache_callback_list + i;
if (ccitem->id == SHAREDINVALRELCACHE_ID)
(*ccitem->function) (ccitem->arg, msg->rc.relId);
(*ccitem->function) (ccitem->arg, msg->rc.relId);
}
}
}
@ -539,9 +548,16 @@ InvalidateSystemCaches(void)
ResetCatalogCaches();
RelationCacheInvalidate(); /* gets smgr cache too */
for (i = 0; i < cache_callback_count; i++)
for (i = 0; i < syscache_callback_count; i++)
{
struct CACHECALLBACK *ccitem = cache_callback_list + i;
struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i;
(*ccitem->function) (ccitem->arg, ccitem->id, NULL);
}
for (i = 0; i < relcache_callback_count; i++)
{
struct RELCACHECALLBACK *ccitem = relcache_callback_list + i;
(*ccitem->function) (ccitem->arg, InvalidOid);
}
@ -1177,26 +1193,25 @@ CacheInvalidateRelcacheByRelid(Oid relid)
/*
* CacheRegisterSyscacheCallback
* Register the specified function to be called for all future
* invalidation events in the specified cache.
* invalidation events in the specified cache. The cache ID and the
* TID of the tuple being invalidated will be passed to the function.
*
* NOTE: currently, the OID argument to the callback routine is not
* provided for syscache callbacks; the routine doesn't really get any
* useful info as to exactly what changed. It should treat every call
* as a "cache flush" request.
* NOTE: NULL will be passed for the TID if a cache reset request is received.
* In this case the called routines should flush all cached state.
*/
void
CacheRegisterSyscacheCallback(int cacheid,
CacheCallbackFunction func,
SyscacheCallbackFunction func,
Datum arg)
{
if (cache_callback_count >= MAX_CACHE_CALLBACKS)
elog(FATAL, "out of cache_callback_list slots");
if (syscache_callback_count >= MAX_SYSCACHE_CALLBACKS)
elog(FATAL, "out of syscache_callback_list slots");
cache_callback_list[cache_callback_count].id = cacheid;
cache_callback_list[cache_callback_count].function = func;
cache_callback_list[cache_callback_count].arg = arg;
syscache_callback_list[syscache_callback_count].id = cacheid;
syscache_callback_list[syscache_callback_count].function = func;
syscache_callback_list[syscache_callback_count].arg = arg;
++cache_callback_count;
++syscache_callback_count;
}
/*
@ -1209,15 +1224,14 @@ CacheRegisterSyscacheCallback(int cacheid,
* In this case the called routines should flush all cached state.
*/
void
CacheRegisterRelcacheCallback(CacheCallbackFunction func,
CacheRegisterRelcacheCallback(RelcacheCallbackFunction func,
Datum arg)
{
if (cache_callback_count >= MAX_CACHE_CALLBACKS)
elog(FATAL, "out of cache_callback_list slots");
if (relcache_callback_count >= MAX_RELCACHE_CALLBACKS)
elog(FATAL, "out of relcache_callback_list slots");
cache_callback_list[cache_callback_count].id = SHAREDINVALRELCACHE_ID;
cache_callback_list[cache_callback_count].function = func;
cache_callback_list[cache_callback_count].arg = arg;
relcache_callback_list[relcache_callback_count].function = func;
relcache_callback_list[relcache_callback_count].arg = arg;
++cache_callback_count;
++relcache_callback_count;
}