DNS: time-limit cached returns, using TTL. Bug 1395
[exim.git] / src / src / search.c
index a055291961aa5418ae001a0ed76aa1c35962f244..cd522dae82344e36e44c96aa0e3d0b138dd567e2 100644 (file)
@@ -466,6 +466,7 @@ internal_search_find(void *handle, uschar *filename, uschar *keystring)
 {
 tree_node *t = (tree_node *)handle;
 search_cache *c = (search_cache *)(t->data.ptr);
+expiring_data *e;
 uschar *data = NULL;
 int search_type = t->name[0] - '0';
 int old_pool = store_pool;
@@ -491,18 +492,27 @@ store_pool = POOL_SEARCH;
 /* Look up the data for the key, unless it is already in the cache for this
 file. No need to check c->item_cache for NULL, tree_search will do so. */
 
-if ((t = tree_search(c->item_cache, keystring)) == NULL)
+if (  (t = tree_search(c->item_cache, keystring))
+   && (!(e = t->data.ptr)->expiry || e->expiry > time(NULL))
+   )
+  { /* Data was in the cache already; set the pointer from the tree node */
+  data = e->ptr;
+  DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
+    keystring,
+    filename ? US"\n  in " : US"", filename ? filename : US"");
+  }
+else
   {
-  BOOL do_cache = TRUE;
+  uint do_cache = UINT_MAX;
   int keylength = Ustrlen(keystring);
 
   DEBUG(D_lookup)
     {
-    if (filename != NULL)
-      debug_printf("file lookup required for %s\n  in %s\n",
-        keystring, filename);
-    else
-      debug_printf("database lookup required for %s\n", keystring);
+    if (t) debug_printf("cached data found but past valid time; ");
+    debug_printf("%s lookup required for %s%s%s\n",
+      filename ? US"file" : US"database",
+      keystring,
+      filename ? US"\n  in " : US"", filename ? filename : US"");
     }
 
   /* Call the code for the different kinds of search. DEFER is handled
@@ -511,9 +521,7 @@ if ((t = tree_search(c->item_cache, keystring)) == NULL)
 
   if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
       &data, &search_error_message, &do_cache) == DEFER)
-    {
     search_find_defer = TRUE;
-    }
 
   /* A record that has been found is now in data, which is either NULL
   or points to a bit of dynamic store. Cache the result of the lookup if
@@ -524,10 +532,22 @@ if ((t = tree_search(c->item_cache, keystring)) == NULL)
   else if (do_cache)
     {
     int len = keylength + 1;
-    t = store_get(sizeof(tree_node) + len);
-    memcpy(t->name, keystring, len);
-    t->data.ptr = data;
-    tree_insertnode(&c->item_cache, t);
+
+    if (t)     /* Previous, out-of-date cache entry.  Update with the */
+      {        /* new result and forget the old one */
+      e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
+      e->ptr = data;
+      }
+    else
+      {
+      t = store_get(sizeof(tree_node) + len + sizeof(expiring_data));
+      e = (expiring_data *)((char *)t + sizeof(tree_node) + len);
+      e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
+      e->ptr = data;
+      memcpy(t->name, keystring, len);
+      t->data.ptr = e;
+      tree_insertnode(&c->item_cache, t);
+      }
     }
 
   /* If caching was disabled, empty the cache tree. We just set the cache
@@ -540,34 +560,19 @@ if ((t = tree_search(c->item_cache, keystring)) == NULL)
     }
   }
 
-/* Data was in the cache already; set the pointer from the tree node */
-
-else
-  {
-  data = US t->data.ptr;
-  DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
-    keystring,
-    (filename == NULL)? US"" : US"\n  in ",
-    (filename == NULL)? US"" : filename);
-  }
-
-/* Debug: output the answer */
-
 DEBUG(D_lookup)
   {
-  if (data == NULL)
-    {
-    if (search_find_defer) debug_printf("lookup deferred: %s\n",
-      search_error_message);
-    else debug_printf("lookup failed\n");
-    }
-  else debug_printf("lookup yielded: %s\n", data);
+  if (data)
+    debug_printf("lookup yielded: %s\n", data);
+  else if (search_find_defer)
+    debug_printf("lookup deferred: %s\n", search_error_message);
+  else debug_printf("lookup failed\n");
   }
 
 /* Return it in new dynamic store in the regular pool */
 
 store_pool = old_pool;
-return (data == NULL)? NULL : string_copy(data);
+return data ? string_copy(data) : NULL;
 }