v9-0003-Be-more-paranoid-about-OOM-when-changing-search_p.patch
text/x-patch
Filename: v9-0003-Be-more-paranoid-about-OOM-when-changing-search_p.patch
Type: text/x-patch
Part: 2
Message:
Re: Faster "SET search_path"
Patch
Format: format-patch
Series: patch v9-0003
Subject: Be more paranoid about OOM when changing search_path.
| File | + | − |
|---|---|---|
| src/backend/catalog/namespace.c | 35 | 83 |
From 8d870755b638a193a402292f265cb7e2f78ae432 Mon Sep 17 00:00:00 2001
From: Jeff Davis <jeff@j-davis.com>
Date: Thu, 16 Nov 2023 12:12:49 -0800
Subject: [PATCH v9 3/5] Be more paranoid about OOM when changing search_path.
Commit f26c2368dc introduced a search_path cache, and left some room
for potential problems with out-of-memory conditions.
This change re-introduces one list_copy(), but simplifies things
substantially in addition to better handling OOM.
---
src/backend/catalog/namespace.c | 118 ++++++++++----------------------
1 file changed, 35 insertions(+), 83 deletions(-)
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 69dbe4500f..1a75b50807 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -279,42 +279,23 @@ spcachekey_equal(SearchPathCacheKey a, SearchPathCacheKey b)
static nsphash_hash * SearchPathCache = NULL;
/*
- * Create search path cache.
+ * Create or reset search_path cache as necessary.
*/
static void
spcache_init(void)
{
Assert(SearchPathCacheContext);
- if (SearchPathCache)
- return;
+ if (SearchPathCache && searchPathCacheValid &&
+ SearchPathCache->members < SPCACHE_RESET_THRESHOLD)
+ return;
+ MemoryContextReset(SearchPathCacheContext);
/* arbitrary initial starting size of 16 elements */
SearchPathCache = nsphash_create(SearchPathCacheContext, 16, NULL);
searchPathCacheValid = true;
}
-/*
- * Reset and reinitialize search path cache.
- */
-static void
-spcache_reset(void)
-{
- Assert(SearchPathCacheContext);
- Assert(SearchPathCache);
-
- MemoryContextReset(SearchPathCacheContext);
- SearchPathCache = NULL;
-
- spcache_init();
-}
-
-static uint32
-spcache_members(void)
-{
- return SearchPathCache->members;
-}
-
/*
* Look up or insert entry in search path cache.
*
@@ -325,27 +306,25 @@ static SearchPathCacheEntry *
spcache_insert(const char *searchPath, Oid roleid)
{
SearchPathCacheEntry *entry;
- bool found;
SearchPathCacheKey cachekey = {
.searchPath = searchPath,
.roleid = roleid
};
/*
- * If a new entry is created, we must ensure that it's properly
- * initialized. Set the cache invalid temporarily, so that if the
- * MemoryContextStrdup() below raises an OOM, the cache will be reset on
- * the next use, clearing the uninitialized entry.
+ * searchPath is not saved in SearchPathCacheContext. First perform a
+ * lookup, and copy searchPath only if we need to create a new entry.
*/
- searchPathCacheValid = false;
+ entry = nsphash_lookup(SearchPathCache, cachekey);
- entry = nsphash_insert(SearchPathCache, cachekey, &found);
-
- /* ensure that key is initialized and the rest is zeroed */
- if (!found)
+ if (!entry)
{
- entry->key.searchPath = MemoryContextStrdup(SearchPathCacheContext, searchPath);
- entry->key.roleid = roleid;
+ bool found;
+
+ cachekey.searchPath = MemoryContextStrdup(SearchPathCacheContext, searchPath);
+ entry = nsphash_insert(SearchPathCache, cachekey, &found);
+ Assert(!found);
+
entry->oidlist = NIL;
entry->finalPath = NIL;
entry->firstNS = InvalidOid;
@@ -354,7 +333,6 @@ spcache_insert(const char *searchPath, Oid roleid)
/* do not touch entry->status, used by simplehash */
}
- searchPathCacheValid = true;
return entry;
}
@@ -4183,31 +4161,15 @@ finalNamespacePath(List *oidlist, Oid *firstNS)
/*
* Retrieve search path information from the cache; or if not there, fill
* it. The returned entry is valid only until the next call to this function.
- *
- * We also determine if the newly-computed finalPath is the same as the
- * prevPath passed by the caller (i.e. a no-op or a real change?). It's more
- * efficient to check for a change in this function than the caller, because
- * we can avoid unnecessary temporary copies of the previous path.
*/
static const SearchPathCacheEntry *
-cachedNamespacePath(const char *searchPath, Oid roleid, List *prevPath,
- bool *same)
+cachedNamespacePath(const char *searchPath, Oid roleid)
{
MemoryContext oldcxt;
SearchPathCacheEntry *entry;
- List *prevPathCopy = NIL;
spcache_init();
- /* invalidate cache if necessary */
- if (!searchPathCacheValid || spcache_members() >= SPCACHE_RESET_THRESHOLD)
- {
- /* prevPath will be destroyed; make temp copy for later comparison */
- prevPathCopy = list_copy(prevPath);
- prevPath = prevPathCopy;
- spcache_reset();
- }
-
entry = spcache_insert(searchPath, roleid);
/*
@@ -4232,23 +4194,14 @@ cachedNamespacePath(const char *searchPath, Oid roleid, List *prevPath,
if (entry->finalPath == NIL || object_access_hook ||
entry->forceRecompute)
{
- /*
- * Do not free the stale value of entry->finalPath until we've
- * performed the comparison, in case it's aliased by prevPath (which
- * can only happen when recomputing due to an object_access_hook).
- */
- List *finalPath;
+ list_free(entry->finalPath);
+ entry->finalPath = NIL;
oldcxt = MemoryContextSwitchTo(SearchPathCacheContext);
- finalPath = finalNamespacePath(entry->oidlist,
- &entry->firstNS);
+ entry->finalPath = finalNamespacePath(entry->oidlist,
+ &entry->firstNS);
MemoryContextSwitchTo(oldcxt);
- *same = equal(prevPath, finalPath);
-
- list_free(entry->finalPath);
- entry->finalPath = finalPath;
-
/*
* If an object_access_hook set when finalPath is calculated, the
* result may be affected by the hook. Force recomputation of
@@ -4257,13 +4210,6 @@ cachedNamespacePath(const char *searchPath, Oid roleid, List *prevPath,
*/
entry->forceRecompute = object_access_hook ? true : false;
}
- else
- {
- /* use cached version of finalPath */
- *same = equal(prevPath, entry->finalPath);
- }
-
- list_free(prevPathCopy);
return entry;
}
@@ -4275,7 +4221,6 @@ static void
recomputeNamespacePath(void)
{
Oid roleid = GetUserId();
- bool newPathEqual;
bool pathChanged;
const SearchPathCacheEntry *entry;
@@ -4283,24 +4228,31 @@ recomputeNamespacePath(void)
if (baseSearchPathValid && namespaceUser == roleid)
return;
- entry = cachedNamespacePath(namespace_search_path, roleid, baseSearchPath,
- &newPathEqual);
+ entry = cachedNamespacePath(namespace_search_path, roleid);
if (baseCreationNamespace == entry->firstNS &&
baseTempCreationPending == entry->temp_missing &&
- newPathEqual)
+ equal(entry->finalPath, baseSearchPath))
{
pathChanged = false;
}
else
{
+ MemoryContext oldcxt;
+ List *newpath;
+
pathChanged = true;
- }
- /* Now safe to assign to state variables. */
- baseSearchPath = entry->finalPath;
- baseCreationNamespace = entry->firstNS;
- baseTempCreationPending = entry->temp_missing;
+ oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+ newpath = list_copy(entry->finalPath);
+ MemoryContextSwitchTo(oldcxt);
+
+ /* Now safe to assign to state variables. */
+ list_free(baseSearchPath);
+ baseSearchPath = newpath;
+ baseCreationNamespace = entry->firstNS;
+ baseTempCreationPending = entry->temp_missing;
+ }
/* Mark the path valid. */
baseSearchPathValid = true;
--
2.34.1