From: Jeff Davis Date: Mon, 20 Nov 2023 23:53:42 +0000 (-0800) Subject: Optimize check_search_path() by using SearchPathCache. X-Git-Tag: REL_17_BETA1~1435 X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=ad57c2a7c58665c14236a999435d37ba59eb7fc4;p=postgresql.git Optimize check_search_path() by using SearchPathCache. A hash lookup is faster than re-validating the string, particularly because we use SplitIdentifierString() for validation. Important when search_path changes frequently. Discussion: https://postgr.es/m/04c8592dbd694e4114a3ed87139a7a04e4363030.camel%40j-davis.com --- diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index d74f6181a9c..5027efc91d6 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -235,6 +235,10 @@ static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames, * when a function has search_path set in proconfig. Add a search path cache * that can be used by recomputeNamespacePath(). * + * The cache is also used to remember already-validated strings in + * check_search_path() to avoid the need to call SplitIdentifierString() + * repeatedly. + * * The search path cache is based on a wrapper around a simplehash hash table * (nsphash, defined below). The spcache wrapper deals with OOM while trying * to initialize a key, and also offers a more convenient API. @@ -296,6 +300,21 @@ spcache_init(void) searchPathCacheValid = true; } +/* + * Look up entry in search path cache without inserting. Returns NULL if not + * present. + */ +static SearchPathCacheEntry * +spcache_lookup(const char *searchPath, Oid roleid) +{ + SearchPathCacheKey cachekey = { + .searchPath = searchPath, + .roleid = roleid + }; + + return nsphash_lookup(SearchPathCache, cachekey); +} + /* * Look up or insert entry in search path cache. * @@ -4578,11 +4597,40 @@ ResetTempTableNamespace(void) bool check_search_path(char **newval, void **extra, GucSource source) { + Oid roleid = InvalidOid; + const char *searchPath = *newval; char *rawname; List *namelist; + bool use_cache = (SearchPathCacheContext != NULL); - /* Need a modifiable copy of string */ - rawname = pstrdup(*newval); + /* + * We used to try to check that the named schemas exist, but there are + * many valid use-cases for having search_path settings that include + * schemas that don't exist; and often, we are not inside a transaction + * here and so can't consult the system catalogs anyway. So now, the only + * requirement is syntactic validity of the identifier list. + */ + + /* + * Checking only the syntactic validity also allows us to use the search + * path cache (if available) to avoid calling SplitIdentifierString() on + * the same string repeatedly. + */ + if (use_cache) + { + spcache_init(); + + roleid = GetUserId(); + + if (spcache_lookup(searchPath, roleid) != NULL) + return true; + } + + /* + * Ensure validity check succeeds before creating cache entry. + */ + + rawname = pstrdup(searchPath); /* need a modifiable copy */ /* Parse string into list of identifiers */ if (!SplitIdentifierString(rawname, ',', &namelist)) @@ -4605,6 +4653,10 @@ check_search_path(char **newval, void **extra, GucSource source) pfree(rawname); list_free(namelist); + /* create empty cache entry */ + if (use_cache) + (void) spcache_insert(searchPath, roleid); + return true; }