From 00150fbc45581006c5a37599eaf6a3e1ef900e56 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Tue, 8 Dec 2020 17:54:04 +1300
Subject: [PATCH 4/5] Remove code duplication in nodeResultCache.c

---
 src/backend/executor/nodeResultCache.c | 123 ++++++++++---------------
 1 file changed, 51 insertions(+), 72 deletions(-)

diff --git a/src/backend/executor/nodeResultCache.c b/src/backend/executor/nodeResultCache.c
index 5b58c2f059..b1b4f22a03 100644
--- a/src/backend/executor/nodeResultCache.c
+++ b/src/backend/executor/nodeResultCache.c
@@ -431,6 +431,54 @@ cache_reduce_memory(ResultCacheState *rcstate, ResultCacheKey *specialkey)
 	return specialkey_intact;
 }
 
+/*
+ * cache_check_mem
+ *		Check if we've allocate more than our memory budget and, if so, reduce
+ *		the memory used by the cache.  Returns the cache entry belonging to
+ *		'entry', which may have changed address by shuffling the deleted
+ *		entries back to their optimal position.  Returns NULL if the attempt
+ *		to free enough memory resulted in 'entry' itself being evicted from
+ *		the cache.
+ */
+static ResultCacheEntry *
+cache_check_mem(ResultCacheState *rcstate, ResultCacheEntry *entry)
+{
+	/*
+	 * If we've gone over our memory budget, then we'll free up some space in
+	 * the cache.
+	 */
+	if (rcstate->mem_used > rcstate->mem_limit)
+	{
+		ResultCacheKey *key = entry->key;
+
+		if (!cache_reduce_memory(rcstate, key))
+			return NULL;
+
+		/*
+		 * The process of removing entries from the cache may have caused the
+		 * code in simplehash.h to shuffle elements to earlier buckets in the
+		 * hash table.  If it has, we'll need to find the entry again by
+		 * performing a lookup.  Fortunately, we can detect if this has
+		 * happened by seeing if the entry is still in use and that the key
+		 * pointer matches our expected key.
+		 */
+		if (entry->status != resultcache_SH_IN_USE || entry->key != key)
+		{
+			/*
+			 * We need to repopulate the probeslot as lookups performed during
+			 * the cache evictions above will have stored some other key.
+			 */
+			prepare_probe_slot(rcstate, key);
+
+			/* Re-find the newly added entry */
+			entry = resultcache_lookup(rcstate->hashtable, NULL);
+			Assert(entry != NULL);
+		}
+	}
+
+	return entry;
+}
+
 /*
  * cache_lookup
  *		Perform a lookup to see if we've already cached results based on the
@@ -493,44 +541,7 @@ cache_lookup(ResultCacheState *rcstate, bool *found)
 
 	MemoryContextSwitchTo(oldcontext);
 
-	/*
-	 * If we've gone over our memory budget, then we'll free up some space in
-	 * the cache.
-	 */
-	if (rcstate->mem_used > rcstate->mem_limit)
-	{
-		/*
-		 * Try to free up some memory.  It's highly unlikely that we'll fail
-		 * to do so here since the entry we've just added is yet to contain
-		 * any tuples and we're able to remove any other entry to reduce the
-		 * memory consumption.
-		 */
-		if (unlikely(!cache_reduce_memory(rcstate, key)))
-			return NULL;
-
-		/*
-		 * The process of removing entries from the cache may have caused the
-		 * code in simplehash.h to shuffle elements to earlier buckets in the
-		 * hash table.  If it has, we'll need to find the entry again by
-		 * performing a lookup.  Fortunately, we can detect if this has
-		 * happened by seeing if the entry is still in use and that the key
-		 * pointer matches our expected key.
-		 */
-		if (entry->status != resultcache_SH_IN_USE || entry->key != key)
-		{
-			/*
-			 * We need to repopulate the probeslot as lookups performed during
-			 * the cache evictions above will have stored some other key.
-			 */
-			prepare_probe_slot(rcstate, key);
-
-			/* Re-find the newly added entry */
-			entry = resultcache_lookup(rcstate->hashtable, NULL);
-			Assert(entry != NULL);
-		}
-	}
-
-	return entry;
+	return cache_check_mem(rcstate, entry);
 }
 
 /*
@@ -576,41 +587,9 @@ cache_store_tuple(ResultCacheState *rcstate, TupleTableSlot *slot)
 	rcstate->last_tuple = tuple;
 	MemoryContextSwitchTo(oldcontext);
 
-	/*
-	 * If we've gone over our memory budget then free up some space in the
-	 * cache.
-	 */
-	if (rcstate->mem_used > rcstate->mem_limit)
-	{
-		ResultCacheKey *key = entry->key;
-
-		if (!cache_reduce_memory(rcstate, key))
-			return false;
-
-		/*
-		 * The process of removing entries from the cache may have caused the
-		 * code in simplehash.h to shuffle elements to earlier buckets in the
-		 * hash table.  If it has, we'll need to find the entry again by
-		 * performing a lookup.  Fortunately, we can detect if this has
-		 * happened by seeing if the entry is still in use and that the key
-		 * pointer matches our expected key.
-		 */
-		if (entry->status != resultcache_SH_IN_USE || entry->key != key)
-		{
-			/*
-			 * We need to repopulate the probeslot as lookups performed during
-			 * the cache evictions above will have stored some other key.
-			 */
-			prepare_probe_slot(rcstate, key);
-
-			/* Re-find the entry */
-			rcstate->entry = entry = resultcache_lookup(rcstate->hashtable,
-														NULL);
-			Assert(entry != NULL);
-		}
-	}
+	rcstate->entry = entry = cache_check_mem(rcstate, entry);
 
-	return true;
+	return (entry != NULL);
 }
 
 static TupleTableSlot *
-- 
2.17.0

