X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/19897d528de779d4d3804fd7d10c235e8b50a53e..4226691b79845d9b41041e2f64a3a241dcb99f4d:/src/src/search.c diff --git a/src/src/search.c b/src/src/search.c index 86363a210..b1dc884c9 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/search.c,v 1.6 2007/08/29 14:02:22 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2007 */ +/* Copyright (c) University of Cambridge 1995 - 2015 */ /* See the file NOTICE for conditions of use and distribution. */ /* A set of functions to search databases in various formats. An open @@ -64,14 +62,14 @@ Returns: +ve => valid lookup name; value is offset in lookup_list */ int -search_findtype(uschar *name, int len) +search_findtype(const uschar *name, int len) { int bot = 0; int top = lookup_list_count; while (top > bot) { int mid = (top + bot)/2; - int c = Ustrncmp(name, lookup_list[mid].name, len); + int c = Ustrncmp(name, lookup_list[mid]->name, len); /* If c == 0 we have matched the incoming name with the start of the search type name. However, some search types are substrings of others (e.g. nis and @@ -81,9 +79,9 @@ while (top > bot) are testing. By leaving c == 0 when the lengths are different, and doing a > 0 test below, this all falls out correctly. */ - if (c == 0 && Ustrlen(lookup_list[mid].name) == len) + if (c == 0 && Ustrlen(lookup_list[mid]->name) == len) { - if (lookup_list[mid].find != NULL) return mid; + if (lookup_list[mid]->find != NULL) return mid; search_error_message = string_sprintf("lookup type \"%.*s\" is not " "available (not in the binary - check buildtime LOOKUP configuration)", len, name); @@ -123,12 +121,12 @@ Returns: +ve => valid lookup name; value is offset in lookup_list */ int -search_findtype_partial(uschar *name, int *ptypeptr, uschar **ptypeaff, +search_findtype_partial(const uschar *name, int *ptypeptr, const uschar **ptypeaff, int *afflen, int *starflags) { int len, stype; int pv = -1; -uschar *ss = name; +const uschar *ss = name; *starflags = 0; *ptypeaff = NULL; @@ -237,8 +235,8 @@ if (t->left != NULL) tidyup_subtree(t->left); if (t->right != NULL) tidyup_subtree(t->right); if (c != NULL && c->handle != NULL && - lookup_list[c->search_type].close != NULL) - lookup_list[c->search_type].close(c->handle); + lookup_list[c->search_type]->close != NULL) + lookup_list[c->search_type]->close(c->handle); } @@ -270,7 +268,7 @@ open_filecount = 0; /* Call the general tidyup entry for any drivers that have one. */ for (i = 0; i < lookup_list_count; i++) - if (lookup_list[i].tidy != NULL) (lookup_list[i].tidy)(); + if (lookup_list[i]->tidy != NULL) (lookup_list[i]->tidy)(); if (search_reset_point != NULL) store_reset(search_reset_point); search_reset_point = NULL; @@ -335,7 +333,7 @@ search_open(uschar *filename, int search_type, int modemask, uid_t *owners, void *handle; tree_node *t; search_cache *c; -lookup_info *lk = lookup_list + search_type; +lookup_info *lk = lookup_list[search_type]; uschar keybuffer[256]; int old_pool = store_pool; @@ -388,7 +386,7 @@ if (lk->type == lookup_absfile && open_filecount >= lookup_open_max) ((search_cache *)(open_bot->data.ptr))->down = NULL; else open_top = NULL; - ((lookup_list + c->search_type)->close)(c->handle); + ((lookup_list[c->search_type])->close)(c->handle); c->handle = NULL; open_filecount--; } @@ -468,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; @@ -480,7 +479,7 @@ search_find_defer = FALSE; DEBUG(D_lookup) debug_printf("internal_search_find: file=\"%s\"\n " "type=%s key=\"%s\"\n", filename, - lookup_list[search_type].name, keystring); + lookup_list[search_type]->name, keystring); /* Insurance. If the keystring is empty, just fail. */ @@ -493,29 +492,36 @@ 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 like FAIL, except that search_find_defer is set so the caller can distinguish if necessary. */ - if (lookup_list[search_type].find(c->handle, filename, keystring, keylength, + 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 @@ -526,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 + { + e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len); + e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache; + e->ptr = data; + t = (tree_node *)(e+1); + 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 @@ -542,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; } @@ -603,7 +606,7 @@ Returns: a pointer to a dynamic string containing the answer, uschar * search_find(void *handle, uschar *filename, uschar *keystring, int partial, - uschar *affix, int affixlen, int starflags, int *expand_setup) + const uschar *affix, int affixlen, int starflags, int *expand_setup) { tree_node *t = (tree_node *)handle; BOOL set_null_wild = FALSE; @@ -622,7 +625,7 @@ DEBUG(D_lookup) that opens real files. */ if (open_top != (tree_node *)handle && - lookup_list[t->name[0]-'0'].type == lookup_absfile) + lookup_list[t->name[0]-'0']->type == lookup_absfile) { search_cache *c = (search_cache *)(t->data.ptr); tree_node *up = c->up; @@ -754,7 +757,7 @@ else if (partial >= 0) } /* If nothing has been matched, but the option to look for "*@" is set, try -replacing everthing to the left of @ by *. After a match, the wild part +replacing everything to the left of @ by *. After a match, the wild part is set to the string to the left of the @. */ if (yield == NULL && (starflags & SEARCH_STARAT) != 0)