]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: 51d: add LRU-based cache on User-Agent string detection
authorDragan Dosen <ddosen@haproxy.com>
Mon, 29 Jun 2015 14:43:26 +0000 (16:43 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 30 Jun 2015 08:43:03 +0000 (10:43 +0200)
This cache is used by 51d converter. The input User-Agent string, the
converter args and a random seed are used as a hashing key. The cached
entries contains a pointer to the resulting string for specific
User-Agent string detection.

The cache size can be tuned using 51degrees-cache-size parameter.

include/types/global.h
src/51d.c
src/haproxy.c

index 72024f8cfc14dd61480b5440ef76cf437ede6d69..db1618e27685fc6a9e12650b12de3f4a3e5696d0 100644 (file)
@@ -193,6 +193,7 @@ struct global {
 #ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
                fiftyoneDegreesDataSet data_set; /* data set used with the pattern detection method. */
 #endif
+               int cache_size;
        } _51degrees;
 #endif
 };
index 03cf742c852cdb6d50301f4bcd023b37b033404b..abb5cce9eb07262c962b0f8094602dbb5dcf9287 100644 (file)
--- a/src/51d.c
+++ b/src/51d.c
@@ -6,6 +6,7 @@
 #include <proto/log.h>
 #include <proto/sample.h>
 #include <import/xxhash.h>
+#include <import/lru.h>
 
 #include <import/51d.h>
 
@@ -14,6 +15,9 @@ struct _51d_property_names {
        char *name;
 };
 
+static struct lru64_head *_51d_lru_tree = NULL;
+static unsigned long long _51d_lru_seed;
+
 static int _51d_data_file(char **args, int section_type, struct proxy *curpx,
                           struct proxy *defpx, const char *file, int line,
                           char **err)
@@ -78,6 +82,28 @@ static int _51d_property_separator(char **args, int section_type, struct proxy *
        return 0;
 }
 
+static int _51d_cache_size(char **args, int section_type, struct proxy *curpx,
+                           struct proxy *defpx, const char *file, int line,
+                           char **err)
+{
+       if (*(args[1]) == 0) {
+               memprintf(err,
+                         "'%s' expects a positive numeric value.",
+                         args[0]);
+               return -1;
+       }
+
+       global._51degrees.cache_size = atoi(args[1]);
+       if (global._51degrees.cache_size < 0) {
+               memprintf(err,
+                         "'%s' expects a positive numeric value, got '%s'.",
+                         args[0], args[1]);
+               return -1;
+       }
+
+       return 0;
+}
+
 static int _51d_conv(const struct arg *args, struct sample *smp, void *private)
 {
        int i;
@@ -92,6 +118,20 @@ static int _51d_conv(const struct arg *args, struct sample *smp, void *private)
        int device_offset;
        int property_index;
 #endif
+       struct lru64 *lru = NULL;
+
+       /* Look in the list. */
+       if (_51d_lru_tree) {
+               unsigned long long seed = _51d_lru_seed ^ (long)args;
+
+               lru = lru64_get(XXH64(smp->data.str.str, smp->data.str.len, seed),
+                               _51d_lru_tree, global._51degrees.data_file_path, 0);
+               if (lru && lru->domain) {
+                       smp->data.str.str = lru->data;
+                       smp->data.str.len = strlen(smp->data.str.str);
+                       return 1;
+               }
+       }
 
 #ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
        /* Create workset. This will later contain detection results. */
@@ -158,6 +198,9 @@ static int _51d_conv(const struct arg *args, struct sample *smp, void *private)
        fiftyoneDegreesFreeWorkset(ws);
 #endif
 
+       if (lru)
+               lru64_commit(lru, strdup(smp->data.str.str), global._51degrees.data_file_path, 0, free);
+
        return 1;
 }
 
@@ -228,6 +271,10 @@ int init_51degrees(void)
        }
        free(_51d_property_list);
 
+       _51d_lru_seed = random();
+       if (global._51degrees.cache_size)
+               _51d_lru_tree = lru64_new(global._51degrees.cache_size);
+
        return 0;
 }
 
@@ -247,12 +294,15 @@ void deinit_51degrees(void)
                LIST_DEL(&_51d_prop_name->list);
                free(_51d_prop_name);
        }
+
+       while (lru64_destroy(_51d_lru_tree));
 }
 
 static struct cfg_kw_list _51dcfg_kws = {{ }, {
        { CFG_GLOBAL, "51degrees-data-file", _51d_data_file },
        { CFG_GLOBAL, "51degrees-property-name-list", _51d_property_name_list },
        { CFG_GLOBAL, "51degrees-property-separator", _51d_property_separator },
+       { CFG_GLOBAL, "51degrees-cache-size", _51d_cache_size },
        { 0, NULL, NULL },
 }};
 
index f93502a4bf2845253862b5e5a2bdc6a21f03f1b5..b0b25468f109e4aa8f6d5551c245f3da1b668241 100644 (file)
@@ -195,6 +195,7 @@ struct global global = {
                .data_file_path = NULL,
 #ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
                .data_set = { },
+               .cache_size = 0,
 #endif
        },
 #endif