From 9c30fc161f2c2b1af10dd41442688077d0afcb21 Mon Sep 17 00:00:00 2001 From: Marek Majkowski Date: Sun, 27 Apr 2008 23:25:55 +0200 Subject: [PATCH] [MEDIUM] add support for URI hash depth and length limits 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 | 19 +++++++++++++++++-- include/proto/backend.h | 12 +++++++++++- include/types/proxy.h | 2 ++ src/backend.c | 30 +++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 3564ad8eb..399bebb6d 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -745,6 +745,20 @@ balance url_param [check_post []] 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 [check_post []] server's weight on the fly will have no effect. 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 ] [depth ] balance url_param [check_post []] The definition of the load balancing algorithm is mandatory for a backend diff --git a/include/proto/backend.h b/include/proto/backend.h index 03fa518ca..aa27654f3 100644 --- a/include/proto/backend.h +++ b/include/proto/backend.h @@ -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; } diff --git a/include/types/proxy.h b/include/types/proxy.h index 091be57e2..fe69b0896 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -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 */ diff --git a/src/backend.c b/src/backend.c index 649756787..9ced724a4 100644 --- a/src/backend.c +++ b/src/backend.c @@ -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;