Optimize SearchPathCache by saving the last entry.
authorJeff Davis <[email protected]>
Tue, 5 Dec 2023 01:19:16 +0000 (17:19 -0800)
committerJeff Davis <[email protected]>
Tue, 5 Dec 2023 01:19:16 +0000 (17:19 -0800)
Repeated lookups are common, so it's worth it to check the last entry
before doing another hash lookup.

Discussion: https://postgr.es/m/04c8592dbd694e4114a3ed87139a7a04e4363030.camel%40j-davis.com

src/backend/catalog/namespace.c

index 5027efc91d6e4371749571a7eaab625ce12dbe69..37a69e9023fb6c3f1200ca1da7473a2190854a0f 100644 (file)
@@ -241,7 +241,8 @@ static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
  *
  * 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.
+ * to initialize a key, optimizes repeated lookups of the same key, and also
+ * offers a more convenient API.
  */
 
 static inline uint32
@@ -281,6 +282,7 @@ spcachekey_equal(SearchPathCacheKey a, SearchPathCacheKey b)
 #define SPCACHE_RESET_THRESHOLD        256
 
 static nsphash_hash * SearchPathCache = NULL;
+static SearchPathCacheEntry * LastSearchPathCacheEntry = NULL;
 
 /*
  * Create or reset search_path cache as necessary.
@@ -295,6 +297,7 @@ spcache_init(void)
        return;
 
    MemoryContextReset(SearchPathCacheContext);
+   LastSearchPathCacheEntry = NULL;
    /* arbitrary initial starting size of 16 elements */
    SearchPathCache = nsphash_create(SearchPathCacheContext, 16, NULL);
    searchPathCacheValid = true;
@@ -307,12 +310,25 @@ spcache_init(void)
 static SearchPathCacheEntry *
 spcache_lookup(const char *searchPath, Oid roleid)
 {
-   SearchPathCacheKey cachekey = {
-       .searchPath = searchPath,
-       .roleid = roleid
-   };
+   if (LastSearchPathCacheEntry &&
+       LastSearchPathCacheEntry->key.roleid == roleid &&
+       strcmp(LastSearchPathCacheEntry->key.searchPath, searchPath) == 0)
+   {
+       return LastSearchPathCacheEntry;
+   }
+   else
+   {
+       SearchPathCacheEntry *entry;
+       SearchPathCacheKey cachekey = {
+           .searchPath = searchPath,
+           .roleid = roleid
+       };
+
+       entry = nsphash_lookup(SearchPathCache, cachekey);
 
-   return nsphash_lookup(SearchPathCache, cachekey);
+       LastSearchPathCacheEntry = entry;
+       return entry;
+   }
 }
 
 /*
@@ -324,35 +340,45 @@ spcache_lookup(const char *searchPath, Oid roleid)
 static SearchPathCacheEntry *
 spcache_insert(const char *searchPath, Oid roleid)
 {
-   SearchPathCacheEntry *entry;
-   SearchPathCacheKey cachekey = {
-       .searchPath = searchPath,
-       .roleid = roleid
-   };
-
-   /*
-    * searchPath is not saved in SearchPathCacheContext. First perform a
-    * lookup, and copy searchPath only if we need to create a new entry.
-    */
-   entry = nsphash_lookup(SearchPathCache, cachekey);
-
-   if (!entry)
+   if (LastSearchPathCacheEntry &&
+       LastSearchPathCacheEntry->key.roleid == roleid &&
+       strcmp(LastSearchPathCacheEntry->key.searchPath, searchPath) == 0)
    {
-       bool        found;
+       return LastSearchPathCacheEntry;
+   }
+   else
+   {
+       SearchPathCacheEntry *entry;
+       SearchPathCacheKey cachekey = {
+           .searchPath = searchPath,
+           .roleid = roleid
+       };
 
-       cachekey.searchPath = MemoryContextStrdup(SearchPathCacheContext, searchPath);
-       entry = nsphash_insert(SearchPathCache, cachekey, &found);
-       Assert(!found);
+       /*
+        * searchPath is not saved in SearchPathCacheContext. First perform a
+        * lookup, and copy searchPath only if we need to create a new entry.
+        */
+       entry = nsphash_lookup(SearchPathCache, cachekey);
 
-       entry->oidlist = NIL;
-       entry->finalPath = NIL;
-       entry->firstNS = InvalidOid;
-       entry->temp_missing = false;
-       entry->forceRecompute = false;
-       /* do not touch entry->status, used by simplehash */
-   }
+       if (!entry)
+       {
+           bool        found;
+
+           cachekey.searchPath = MemoryContextStrdup(SearchPathCacheContext, searchPath);
+           entry = nsphash_insert(SearchPathCache, cachekey, &found);
+           Assert(!found);
+
+           entry->oidlist = NIL;
+           entry->finalPath = NIL;
+           entry->firstNS = InvalidOid;
+           entry->temp_missing = false;
+           entry->forceRecompute = false;
+           /* do not touch entry->status, used by simplehash */
+       }
 
-   return entry;
+       LastSearchPathCacheEntry = entry;
+       return entry;
+   }
 }
 
 /*