[MEDIUM] add support for URI hash depth and length limits
authorMarek Majkowski <majek04@gmail.com>
Sun, 27 Apr 2008 21:25:55 +0000 (23:25 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 27 Apr 2008 22:43:55 +0000 (00:43 +0200)
This patch adds two optional arguments "len" and "depth" to
"balance uri". They are used to limit the length in characters
of the analysis, as well as the number of directory components
it applies to.

doc/configuration.txt
include/proto/backend.h
include/types/proxy.h
src/backend.c

index 3564ad8..399bebb 100644 (file)
@@ -745,6 +745,20 @@ balance url_param <param> [check_post [<max_wait>]]
                   that changing a server's weight on the fly will have no
                   effect.
 
+                  This algorithm support two optional parameters "len" and
+                  "depth", both followed by a positive integer number. These
+                  options may be helpful when it is needed to balance servers
+                  based on the beginning of the URI only. The "len" parameter
+                  indicates that the algorithm should only consider that many
+                  characters at the beginning of the URI to compute the hash.
+                  Note that having "len" set to 1 rarely makes sense since most
+                  URIs start with a leading "/".
+
+                  The "depth" parameter indicates the maximum directory depth
+                  to be used to compute the hash. One level is counted for each
+                  slash in the request. If both parameters are specified, the
+                  evaluation stops when either is reached.
+
       url_param   The URL parameter specified in argument will be looked up in
                   the query string of each HTTP GET request.
 
@@ -783,9 +797,10 @@ balance url_param <param> [check_post [<max_wait>]]
                   server's weight on the fly will have no effect.
 
     <arguments> is an optional list of arguments which may be needed by some
-                algorithms. Right now, only the "url_param" algorithm supports
-                an optional argument.
+                algorithms. Right now, only "url_param" and "uri" support an
+                optional argument.
 
+                balance uri [len <len>] [depth <depth>]
                 balance url_param <param> [check_post [<max_wait>]]
 
   The definition of the load balancing algorithm is mandatory for a backend
index 03fa518..aa27654 100644 (file)
@@ -159,6 +159,7 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_
 {
        unsigned long hash = 0;
        int c;
+       int slashes = 0;
 
        if (px->lbprm.tot_weight == 0)
                return NULL;
@@ -166,10 +167,19 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_
        if (px->lbprm.map.state & PR_MAP_RECALC)
                recalc_server_map(px);
 
+       if (px->uri_len_limit)
+               uri_len = MIN(uri_len, px->uri_len_limit);
+
        while (uri_len--) {
                c = *uri++;
-               if (c == '?')
+               if (c == '/') {
+                       slashes++;
+                       if (slashes == px->uri_dirs_depth1) /* depth+1 */
+                               break;
+               }
+               else if (c == '?')
                        break;
+
                hash = c + (hash << 6) + (hash << 16) - hash;
        }
 
index 091be57..fe69b08 100644 (file)
@@ -166,6 +166,8 @@ struct proxy {
        char *url_param_name;                   /* name of the URL parameter used for hashing */
        int  url_param_len;                     /* strlen(url_param_name), computed only once */
        unsigned url_param_post_limit;          /* if checking POST body for URI parameter, max body to wait for */
+       int  uri_len_limit;                     /* character limit for uri balancing algorithm */
+       int  uri_dirs_depth1;                   /* directories+1 (slashes) limit for uri balancing algorithm */
        char *appsession_name;                  /* name of the cookie to look for */
        int  appsession_name_len;               /* strlen(appsession_name), computed only once */
        int  appsession_len;                    /* length of the appsession cookie value to be used */
index 6497567..9ced724 100644 (file)
@@ -1973,8 +1973,36 @@ int backend_parse_balance(const char **args, char *err, int errlen, struct proxy
                curproxy->lbprm.algo |= BE_LB_ALGO_SH;
        }
        else if (!strcmp(args[0], "uri")) {
+               int arg = 1;
+
                curproxy->lbprm.algo &= ~BE_LB_ALGO;
                curproxy->lbprm.algo |= BE_LB_ALGO_UH;
+
+               while (*args[arg]) {
+                       if (!strcmp(args[arg], "len")) {
+                               if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) {
+                                       snprintf(err, errlen, "'balance uri len' expects a positive integer (got '%s').", args[arg+1]);
+                                       return -1;
+                               }
+                               curproxy->uri_len_limit = atoi(args[arg+1]);
+                               arg += 2;
+                       }
+                       else if (!strcmp(args[arg], "depth")) {
+                               if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) {
+                                       snprintf(err, errlen, "'balance uri depth' expects a positive integer (got '%s').", args[arg+1]);
+                                       return -1;
+                               }
+                               /* hint: we store the position of the ending '/' (depth+1) so
+                                * that we avoid a comparison while computing the hash.
+                                */
+                               curproxy->uri_dirs_depth1 = atoi(args[arg+1]) + 1;
+                               arg += 2;
+                       }
+                       else {
+                               snprintf(err, errlen, "'balance uri' only accepts parameters 'len' and 'depth' (got '%s').", args[arg]);
+                               return -1;
+                       }
+               }
        }
        else if (!strcmp(args[0], "url_param")) {
                if (!*args[1]) {
@@ -1987,7 +2015,7 @@ int backend_parse_balance(const char **args, char *err, int errlen, struct proxy
                        free(curproxy->url_param_name);
                curproxy->url_param_name = strdup(args[1]);
                curproxy->url_param_len = strlen(args[1]);
-               if ( *args[2] ) {
+               if (*args[2]) {
                        if (strcmp(args[2], "check_post")) {
                                snprintf(err, errlen, "'balance url_param' only accepts check_post modifier.");
                                return -1;