Optimize SearchPathCache by saving the last entry.
authorJeff Davis <jdavis@postgresql.org>
Tue, 5 Dec 2023 01:19:16 +0000 (17:19 -0800)
committerJeff Davis <jdavis@postgresql.org>
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;
+       }
 }
 
 /*