Skip to content

Commit

Permalink
Optimize check_search_path() by using SearchPathCache.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jeff-davis committed Nov 20, 2023
1 parent 8efa301 commit ad57c2a
Showing 1 changed file with 54 additions and 2 deletions.
56 changes: 54 additions & 2 deletions src/backend/catalog/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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))
Expand All @@ -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;
}

Expand Down

0 comments on commit ad57c2a

Please sign in to comment.