From a9af93fcb9ccf6e120c70e08165f54d5fce44db4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Wed, 26 Sep 2012 18:43:06 +0200
Subject: [PATCH] Core: Added a dynamic cache size threshold for
 compile_memsearcher().

The internal cache for compile_memsearcher() could grow very large before
the gc would clear some of its entries (each entry has a size of ~16KB).
It now has a dynamic threshold for when it clears the cache on its own.
---
 src/pike_search.c        |  6 +++++
 src/pike_search_engine.c | 50 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/src/pike_search.c b/src/pike_search.c
index ad666796e0..154d83329a 100644
--- a/src/pike_search.c
+++ b/src/pike_search.c
@@ -23,6 +23,12 @@ ptrdiff_t pike_search_struct_offset;
 #define OB2MSEARCH(O) ((struct pike_mem_searcher *)((O)->storage+pike_search_struct_offset))
 #define THIS_MSEARCH ((struct pike_mem_searcher *)(Pike_fp->current_storage))
 
+/* NB: We use the least significant bit of memsearch_cache_threshold
+ *     to indicate whether we are at MIN_MEMSEARCH_THRESHOLD or not.
+ */
+#define MIN_MEMSEARCH_THRESHOLD	128
+static int memsearch_cache_threshold;
+
 static struct mapping *memsearch_cache;
 static struct program *pike_search_program;
 
diff --git a/src/pike_search_engine.c b/src/pike_search_engine.c
index 0cf5668f1b..305f039ef1 100644
--- a/src/pike_search_engine.c
+++ b/src/pike_search_engine.c
@@ -313,6 +313,56 @@ SearchMojt NameN(compile_memsearcher)(NCHAR *needle,
 	  return s->mojt;
 	}
       }
+      /* Paranoia: Junk entry in the mapping. Remove it. */
+      SET_SVAL(stmp, T_STRING, 0, string, hashkey);
+      map_delete(memsearch_cache, &stmp);
+    }
+
+    if (memsearch_cache->data->size >= memsearch_cache_threshold) {
+      /* Perform a gc of all Search objects that only are
+       * referenced from the cache.
+       * Allow the cache to grow to double the size before
+       * the next synchronous gc.
+       */
+      struct keypair *k = NULL;
+      struct mapping_data *md = memsearch_cache->data;
+      int e;
+      int count = 0;
+      /* NB: We inline some stuff from mapping.c here to avoid copying the md.
+       */
+      for (e=0; e < md->hashsize; e++) {
+	struct keypair **prev;
+	for(prev = md->hash + e; (k = *prev);) {
+	  count++;
+	  if ((TYPEOF(k->val) <= MAX_REF_TYPE) &&
+	      (*k->val.u.refs == 1)) {
+	    /* map_delete(memsearch_cache, &k->ind); */
+	    *prev = k->next;
+	    free_svalue(&k->ind);
+	    free_svalue(&k->val);
+	    mapping_free_keypair(md, k);
+	    md->size--;
+	    continue;
+	  } else if (count < 10) {
+	    // locate_references(k->val.u.refs);
+	  }
+	  prev = &k->next;
+	}
+      }
+      memsearch_cache_threshold = (memsearch_cache->data->size<<1) | 1;
+      if (memsearch_cache_threshold < MIN_MEMSEARCH_THRESHOLD) {
+	memsearch_cache_threshold = MIN_MEMSEARCH_THRESHOLD;
+      }
+    } else if ((memsearch_cache_threshold & 1) &&
+	       (memsearch_cache->data->size<<2 < memsearch_cache_threshold)) {
+      /* The real gc() has run and zapped some of our entries.
+       * Assume that all entries left in the cache have more than
+       * one reference.
+       */
+      memsearch_cache_threshold = (memsearch_cache->data->size<<1) | 1;
+      if (memsearch_cache_threshold < MIN_MEMSEARCH_THRESHOLD) {
+	memsearch_cache_threshold = MIN_MEMSEARCH_THRESHOLD;
+      }
     }
 
     o=low_clone(pike_search_program);
-- 
GitLab