Skip to content

Commit ff9f854

Browse files
author
Commitfest Bot
committed
[PATCH]: ./002_cleanup_spl_funccache_v2.patch
1 parent 8a27d41 commit ff9f854

File tree

2 files changed

+118
-2
lines changed

2 files changed

+118
-2
lines changed

src/backend/utils/cache/funccache.c

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,36 @@
3030
#include "funcapi.h"
3131
#include "utils/funccache.h"
3232
#include "utils/hsearch.h"
33+
#include "utils/inval.h"
3334
#include "utils/syscache.h"
3435

3536

3637
/*
3738
* Hash table for cached functions
3839
*/
3940
static HTAB *cfunc_hashtable = NULL;
41+
static HTAB *cfunc_key_hashtable = NULL;
42+
43+
static bool funccache_inval_registed = false;
4044

4145
typedef struct CachedFunctionHashEntry
4246
{
4347
CachedFunctionHashKey key; /* hash key, must be first */
4448
CachedFunction *function; /* points to data of language-specific size */
4549
} CachedFunctionHashEntry;
4650

51+
typedef struct CachedFunctionKeyEntry
52+
{
53+
uint32 keyhash;
54+
CachedFunctionHashKey *key;
55+
} CachedFunctionKeyEntry;
56+
4757
#define FUNCS_PER_USER 128 /* initial table size */
4858

4959
static uint32 cfunc_hash(const void *key, Size keysize);
5060
static int cfunc_match(const void *key1, const void *key2, Size keysize);
51-
61+
static uint32 cfuncoid_hash(Oid funcoid);
62+
static void InvalidateFuncPlanCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
5263

5364
/*
5465
* Initialize the hash table on first use.
@@ -67,10 +78,27 @@ cfunc_hashtable_init(void)
6778
ctl.entrysize = sizeof(CachedFunctionHashEntry);
6879
ctl.hash = cfunc_hash;
6980
ctl.match = cfunc_match;
81+
ctl.hcxt = CacheMemoryContext;
7082
cfunc_hashtable = hash_create("Cached function hash",
7183
FUNCS_PER_USER,
7284
&ctl,
73-
HASH_ELEM | HASH_FUNCTION | HASH_COMPARE);
85+
HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);
86+
}
87+
88+
static void
89+
cfunc_key_hashtable_init(void)
90+
{
91+
HASHCTL ctl2;
92+
93+
Assert(cfunc_key_hashtable == NULL);
94+
95+
ctl2.keysize = sizeof(uint32);
96+
ctl2.entrysize = sizeof(CachedFunctionKeyEntry);
97+
ctl2.hcxt = CacheMemoryContext;
98+
cfunc_key_hashtable = hash_create("Cached function hash",
99+
FUNCS_PER_USER,
100+
&ctl2,
101+
HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
74102
}
75103

76104
/*
@@ -168,7 +196,9 @@ cfunc_hashtable_insert(CachedFunction *function,
168196
CachedFunctionHashKey *func_key)
169197
{
170198
CachedFunctionHashEntry *hentry;
199+
CachedFunctionKeyEntry *kentry;
171200
bool found;
201+
uint32 keyhash;
172202

173203
if (cfunc_hashtable == NULL)
174204
cfunc_hashtable_init();
@@ -198,6 +228,16 @@ cfunc_hashtable_insert(CachedFunction *function,
198228

199229
/* Set back-link from function to hashtable key */
200230
function->fn_hashkey = &hentry->key;
231+
232+
/* Insert function key entry */
233+
if (cfunc_key_hashtable == NULL)
234+
cfunc_key_hashtable_init();
235+
236+
keyhash = cfuncoid_hash(function->fn_hashkey->funcOid);
237+
kentry = (CachedFunctionKeyEntry *) hash_search(cfunc_key_hashtable,
238+
&keyhash,
239+
HASH_ENTER, NULL);
240+
kentry->key = function->fn_hashkey;
201241
}
202242

203243
/*
@@ -208,11 +248,16 @@ cfunc_hashtable_delete(CachedFunction *function)
208248
{
209249
CachedFunctionHashEntry *hentry;
210250
TupleDesc tupdesc;
251+
uint32 keyhash;
211252

212253
/* do nothing if not in table */
213254
if (function->fn_hashkey == NULL)
214255
return;
215256

257+
/* Release key hash table entry */
258+
keyhash = cfuncoid_hash(function->fn_hashkey->funcOid);
259+
hash_search(cfunc_key_hashtable, &keyhash, HASH_REMOVE, NULL);
260+
216261
/*
217262
* We need to free the callResultType if present, which is slightly tricky
218263
* because it has to be valid during the hashtable search. Fortunately,
@@ -332,6 +377,18 @@ compute_function_hashkey(FunctionCallInfo fcinfo,
332377
}
333378
}
334379

380+
static uint32
381+
cfuncoid_hash(Oid funcoid)
382+
{
383+
uint32 hashValue = 0;
384+
uint32 oneHash;
385+
386+
oneHash = murmurhash32((uint32) funcoid);
387+
hashValue ^= oneHash;
388+
389+
return hashValue;
390+
}
391+
335392
/*
336393
* This is the same as the standard resolve_polymorphic_argtypes() function,
337394
* except that:
@@ -493,6 +550,16 @@ cached_function_compile(FunctionCallInfo fcinfo,
493550
bool hashkey_valid = false;
494551
bool new_function = false;
495552

553+
/*
554+
* Register catalog invalidate callback
555+
*/
556+
if (!funccache_inval_registed)
557+
{
558+
funccache_inval_registed = true;
559+
560+
CacheRegisterSyscacheCallback(PROCOID, InvalidateFuncPlanCacheCallback, (Datum) 0);
561+
}
562+
496563
/*
497564
* Lookup the pg_proc tuple by Oid; we'll need it in any case
498565
*/
@@ -632,3 +699,48 @@ cached_function_compile(FunctionCallInfo fcinfo,
632699
*/
633700
return function;
634701
}
702+
703+
704+
/*
705+
* Try to delete and release the plan cache from the hash table.
706+
*/
707+
static void
708+
InvalidateFuncPlanCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
709+
{
710+
Assert(cacheid == PROCOID);
711+
712+
if (cfunc_hashtable == NULL || cfunc_key_hashtable == NULL)
713+
return;
714+
715+
if (hashvalue == 0)
716+
{
717+
HASH_SEQ_STATUS scan;
718+
CachedFunctionHashEntry *hentry;
719+
720+
hash_seq_init(&scan, cfunc_hashtable);
721+
while ((hentry = (CachedFunctionHashEntry *) hash_seq_search(&scan)))
722+
{
723+
if (hentry->function == NULL)
724+
continue;
725+
726+
/* ... and free */
727+
delete_function(hentry->function);
728+
}
729+
}
730+
else
731+
{
732+
CachedFunctionKeyEntry *kentry;
733+
CachedFunction *function;
734+
bool found;
735+
736+
kentry = (CachedFunctionKeyEntry *) hash_search(cfunc_key_hashtable,
737+
&hashvalue, HASH_FIND, &found);
738+
if (found)
739+
{
740+
function = cfunc_hashtable_lookup(kentry->key);
741+
742+
if (function)
743+
delete_function(function);
744+
}
745+
}
746+
}

src/test/regress/expected/plpgsql.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4596,6 +4596,10 @@ LINE 4: return 'foo\\bar\041baz';
45964596
^
45974597
HINT: Use the escape string syntax for backslashes, e.g., E'\\'.
45984598
select strtest();
4599+
WARNING: nonstandard use of \\ in a string literal
4600+
HINT: Use the escape string syntax for backslashes, e.g., E'\\'.
4601+
WARNING: nonstandard use of \\ in a string literal
4602+
HINT: Use the escape string syntax for backslashes, e.g., E'\\'.
45994603
NOTICE: foo\bar!baz
46004604
WARNING: nonstandard use of \\ in a string literal
46014605
LINE 1: 'foo\\bar\041baz'

0 commit comments

Comments
 (0)