dnsproxy: Deal nicer with a cache-full situation
authorArjan van de Ven <arjan@linux.intel.com>
Tue, 10 Jan 2012 00:08:49 +0000 (16:08 -0800)
committerDaniel Wagner <daniel.wagner@bmw-carit.de>
Tue, 10 Jan 2012 12:43:57 +0000 (13:43 +0100)
Now that we have hit counts for the cache, we can make the cache-full
handling slightly smarter; if we can't make space freeing expired entries,
we can now make space freeing entries that have a very low use count.

src/dnsproxy.c

index d2fa07c..730b033 100644 (file)
@@ -938,6 +938,7 @@ out:
 struct cache_timeout {
        time_t current_time;
        int max_timeout;
+       int try_harder;
 };
 
 static gboolean cache_check_entry(gpointer key, gpointer value,
@@ -947,6 +948,10 @@ static gboolean cache_check_entry(gpointer key, gpointer value,
        struct cache_entry *entry = value;
        int max_timeout;
 
+       /* Scale the number of hits by half as part of cache aging */
+
+       entry->hits /= 2;
+
        /*
         * If either IPv4 or IPv6 cached entry has expired, we
         * remove both from the cache.
@@ -970,6 +975,13 @@ static gboolean cache_check_entry(gpointer key, gpointer value,
                        return TRUE;
        }
 
+       /*
+        * if we're asked to try harder, also remove entries that have
+        * few hits
+        */
+       if (data->try_harder && entry->hits < 4)
+               return TRUE;
+
        return FALSE;
 }
 
@@ -977,20 +989,32 @@ static void cache_cleanup(void)
 {
        static int max_timeout;
        struct cache_timeout data;
-       int count;
+       int count = 0;
 
        data.current_time = time(0);
        data.max_timeout = 0;
+       data.try_harder = 0;
 
-       if (max_timeout > data.current_time) {
-               DBG("waiting %ld secs before cleaning cache",
-                       max_timeout - data.current_time);
-               return;
+       /*
+        * In the first pass, we only remove entries that have timed out.
+        * We use a cache of the first time to expire to do this only
+        * when it makes sense.
+        */
+       if (max_timeout <= data.current_time) {
+               count = g_hash_table_foreach_remove(cache, cache_check_entry,
+                                               &data);
        }
+       DBG("removed %d in the first pass", count);
 
-       count = g_hash_table_foreach_remove(cache, cache_check_entry,
+       /*
+        * In the second pass, if the first pass turned up blank,
+        * we also expire entries with a low hit count,
+        * while aging the hit count at the same time.
+        */
+       data.try_harder = 1;
+       if (count == 0)
+               count = g_hash_table_foreach_remove(cache, cache_check_entry,
                                                &data);
-       DBG("removed %d", count);
 
        if (count == 0)
                /*