[MINOR] lb_map: reorder code in order to ease integration of new hash functions

We need to remove hash map accesses out of backend.c if we want to
later support new hash methods. This patch separates the hash computation
method from the server lookup. It leaves the lookup function to lb_map.c
and calls it with the result of the hash.
This commit is contained in:
Willy Tarreau 2009-10-01 21:11:15 +02:00
parent f89c1873f8
commit 39c9ba72a7
3 changed files with 105 additions and 92 deletions

View File

@ -1,5 +1,5 @@
/* /*
* include/proto/lb_map.h * include/proto/lb_map.h
* Map-based load-balancing (RR and HASH) * Map-based load-balancing (RR and HASH)
* *
* Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu * Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
@ -31,6 +31,7 @@ void map_set_server_status_up(struct server *srv);
void recalc_server_map(struct proxy *px); void recalc_server_map(struct proxy *px);
void init_server_map(struct proxy *p); void init_server_map(struct proxy *p);
struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid); struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid);
struct server *map_get_server_hash(struct proxy *px, unsigned int hash);
#endif /* _PROTO_LB_MAP_H */ #endif /* _PROTO_LB_MAP_H */

View File

@ -92,6 +92,78 @@ void update_backend_weight(struct proxy *px)
} }
} }
/*
* This function tries to find a running server for the proxy <px> following
* the source hash method. Depending on the number of active/backup servers,
* it will either look for active servers, or for backup servers.
* If any server is found, it will be returned. If no valid server is found,
* NULL is returned.
*/
struct server *get_server_sh(struct proxy *px, const char *addr, int len)
{
unsigned int h, l;
if (px->lbprm.tot_weight == 0)
return NULL;
l = h = 0;
/* note: we won't hash if there's only one server left */
if (px->lbprm.tot_used == 1)
goto hash_done;
while ((l + sizeof (int)) <= len) {
h ^= ntohl(*(unsigned int *)(&addr[l]));
l += sizeof (int);
}
hash_done:
return map_get_server_hash(px, h);
}
/*
* This function tries to find a running server for the proxy <px> following
* the URI hash method. In order to optimize cache hits, the hash computation
* ends at the question mark. Depending on the number of active/backup servers,
* it will either look for active servers, or for backup servers.
* If any server is found, it will be returned. If no valid server is found,
* NULL is returned.
*
* This code was contributed by Guillaume Dallaire, who also selected this hash
* algorithm out of a tens because it gave him the best results.
*
*/
struct server *get_server_uh(struct proxy *px, char *uri, int uri_len)
{
unsigned long hash = 0;
int c;
int slashes = 0;
if (px->lbprm.tot_weight == 0)
return NULL;
/* note: we won't hash if there's only one server left */
if (px->lbprm.tot_used == 1)
goto hash_done;
if (px->uri_len_limit)
uri_len = MIN(uri_len, px->uri_len_limit);
while (uri_len--) {
c = *uri++;
if (c == '/') {
slashes++;
if (slashes == px->uri_dirs_depth1) /* depth+1 */
break;
}
else if (c == '?')
break;
hash = c + (hash << 6) + (hash << 16) - hash;
}
hash_done:
return map_get_server_hash(px, hash);
}
/* /*
* This function tries to find a running server for the proxy <px> following * This function tries to find a running server for the proxy <px> following
* the URL parameter hash method. It looks for a specific parameter in the * the URL parameter hash method. It looks for a specific parameter in the
@ -115,9 +187,6 @@ struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len)
if ((p = memchr(uri, '?', uri_len)) == NULL) if ((p = memchr(uri, '?', uri_len)) == NULL)
return NULL; return NULL;
if (px->lbprm.map.state & PR_MAP_RECALC)
recalc_server_map(px);
p++; p++;
uri_len -= (p - uri); uri_len -= (p - uri);
@ -140,7 +209,7 @@ struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len)
uri_len--; uri_len--;
p++; p++;
} }
return px->lbprm.map.srv[hash % px->lbprm.tot_weight]; return map_get_server_hash(px, hash);
} }
} }
/* skip to next parameter */ /* skip to next parameter */
@ -182,9 +251,6 @@ struct server *get_server_ph_post(struct session *s)
if ( len == 0 ) if ( len == 0 )
return NULL; return NULL;
if (px->lbprm.map.state & PR_MAP_RECALC)
recalc_server_map(px);
ctx.idx = 0; ctx.idx = 0;
/* if the message is chunked, we skip the chunk size, but use the value as len */ /* if the message is chunked, we skip the chunk size, but use the value as len */
@ -242,7 +308,7 @@ struct server *get_server_ph_post(struct session *s)
p++; p++;
/* should we break if vlen exceeds limit? */ /* should we break if vlen exceeds limit? */
} }
return px->lbprm.map.srv[hash % px->lbprm.tot_weight]; return map_get_server_hash(px, hash);
} }
} }
/* skip to next parameter */ /* skip to next parameter */
@ -281,9 +347,6 @@ struct server *get_server_hh(struct session *s)
if (px->lbprm.tot_weight == 0) if (px->lbprm.tot_weight == 0)
return NULL; return NULL;
if (px->lbprm.map.state & PR_MAP_RECALC)
recalc_server_map(px);
ctx.idx = 0; ctx.idx = 0;
/* if the message is chunked, we skip the chunk size, but use the value as len */ /* if the message is chunked, we skip the chunk size, but use the value as len */
@ -293,6 +356,10 @@ struct server *get_server_hh(struct session *s)
if (!ctx.idx || !ctx.vlen) if (!ctx.idx || !ctx.vlen)
return NULL; return NULL;
/* note: we won't hash if there's only one server left */
if (px->lbprm.tot_used == 1)
goto hash_done;
/* Found a the hh_name in the headers. /* Found a the hh_name in the headers.
* we will compute the hash based on this value ctx.val. * we will compute the hash based on this value ctx.val.
*/ */
@ -327,7 +394,8 @@ struct server *get_server_hh(struct session *s)
p--; p--;
} }
} }
return px->lbprm.map.srv[hash % px->lbprm.tot_weight]; hash_done:
return map_get_server_hash(px, hash);
} }
struct server *get_server_rch(struct session *s) struct server *get_server_rch(struct session *s)
@ -344,9 +412,6 @@ struct server *get_server_rch(struct session *s)
if (px->lbprm.tot_weight == 0) if (px->lbprm.tot_weight == 0)
return NULL; return NULL;
if (px->lbprm.map.state & PR_MAP_RECALC)
recalc_server_map(px);
memset(&expr, 0, sizeof(expr)); memset(&expr, 0, sizeof(expr));
memset(&test, 0, sizeof(test)); memset(&test, 0, sizeof(test));
@ -357,6 +422,10 @@ struct server *get_server_rch(struct session *s)
if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0) if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0)
return NULL; return NULL;
/* note: we won't hash if there's only one server left */
if (px->lbprm.tot_used == 1)
goto hash_done;
/* Found a the hh_name in the headers. /* Found a the hh_name in the headers.
* we will compute the hash based on this value ctx.val. * we will compute the hash based on this value ctx.val.
*/ */
@ -367,8 +436,8 @@ struct server *get_server_rch(struct session *s)
len--; len--;
p++; p++;
} }
hash_done:
return px->lbprm.map.srv[hash % px->lbprm.tot_weight]; return map_get_server_hash(px, hash);
} }
/* /*
@ -1152,80 +1221,6 @@ static void __backend_init(void)
acl_register_keywords(&acl_kws); acl_register_keywords(&acl_kws);
} }
/*
* This function tries to find a running server for the proxy <px> following
* the source hash method. Depending on the number of active/backup servers,
* it will either look for active servers, or for backup servers.
* If any server is found, it will be returned. If no valid server is found,
* NULL is returned.
*/
struct server *get_server_sh(struct proxy *px, const char *addr, int len)
{
unsigned int h, l;
if (px->lbprm.tot_weight == 0)
return NULL;
if (px->lbprm.map.state & PR_MAP_RECALC)
recalc_server_map(px);
l = h = 0;
/* note: we won't hash if there's only one server left */
if (px->lbprm.tot_used > 1) {
while ((l + sizeof (int)) <= len) {
h ^= ntohl(*(unsigned int *)(&addr[l]));
l += sizeof (int);
}
h %= px->lbprm.tot_weight;
}
return px->lbprm.map.srv[h];
}
/*
* This function tries to find a running server for the proxy <px> following
* the URI hash method. In order to optimize cache hits, the hash computation
* ends at the question mark. Depending on the number of active/backup servers,
* it will either look for active servers, or for backup servers.
* If any server is found, it will be returned. If no valid server is found,
* NULL is returned.
*
* This code was contributed by Guillaume Dallaire, who also selected this hash
* algorithm out of a tens because it gave him the best results.
*
*/
struct server *get_server_uh(struct proxy *px, char *uri, int uri_len)
{
unsigned long hash = 0;
int c;
int slashes = 0;
if (px->lbprm.tot_weight == 0)
return NULL;
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 == '/') {
slashes++;
if (slashes == px->uri_dirs_depth1) /* depth+1 */
break;
}
else if (c == '?')
break;
hash = c + (hash << 6) + (hash << 16) - hash;
}
return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
}
/* /*
* Local variables: * Local variables:
* c-indent-level: 8 * c-indent-level: 8

View File

@ -253,6 +253,23 @@ struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid)
return avoided; return avoided;
} }
/*
* This function returns the running server from the map at the location
* pointed to by the result of a modulo operation on <hash>. The server map may
* be recomputed if required before being looked up. If any server is found, it
* will be returned. If no valid server is found, NULL is returned.
*/
struct server *map_get_server_hash(struct proxy *px, unsigned int hash)
{
if (px->lbprm.tot_weight == 0)
return NULL;
if (px->lbprm.map.state & PR_MAP_RECALC)
recalc_server_map(px);
return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
}
/* /*
* Local variables: * Local variables: