diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 2f03e7425fc..923d8f3b65d 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -1740,6 +1740,18 @@ parse_peer(peer ** head) p->options.carp = 1; + } else if (!strcasecmp(token, "userhash")) { + if (p->type != PEER_PARENT) + fatalf("parse_peer: non-parent userhash peer %s/%d\n", p->host, p->http_port); + + p->options.userhash = 1; + + } else if (!strcasecmp(token, "sourcehash")) { + if (p->type != PEER_PARENT) + fatalf("parse_peer: non-parent sourcehash peer %s/%d\n", p->host, p->http_port); + + p->options.sourcehash = 1; + #if DELAY_POOLS } else if (!strcasecmp(token, "no-delay")) { diff --git a/src/cf.data.pre b/src/cf.data.pre index 2eced0f28fe..7f91577ed0c 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -1571,6 +1571,8 @@ DOC_START round-robin weighted-round-robin carp + userhash + sourcehash multicast-responder closest-only no-digest @@ -1645,6 +1647,12 @@ DOC_START distributed among the parents based on the CARP load balancing hash function based on their weight. + use 'userhash' to load-balance amongst a set of parents + based on the client proxy_auth or ident username. + + use 'sourcehash' to load-balance amongst a set of parents + based on the client source ip. + 'multicast-responder' indicates the named peer is a member of a multicast group. ICP queries will not be sent directly to the peer, but ICP replies diff --git a/src/main.cc b/src/main.cc index b673775c842..3303d1b1529 100644 --- a/src/main.cc +++ b/src/main.cc @@ -628,6 +628,8 @@ serverConnectionsOpen(void) peerSelectInit(); carpInit(); + peerUserHashInit(); + peerSourceHashInit(); } void @@ -969,6 +971,8 @@ mainInitialize(void) asnRegisterWithCacheManager(manager); authenticateRegisterWithCacheManager(&Config.authConfiguration, manager); carpRegisterWithCacheManager(manager); + peerUserHashRegisterWithCacheManager(manager); + peerSourceHashRegisterWithCacheManager(manager); cbdataRegisterWithCacheManager(manager); /* These use separate calls so that the comm loops can eventually * coexist. diff --git a/src/neighbors.cc b/src/neighbors.cc index ed318d93d4f..93f3b9d9de3 100644 --- a/src/neighbors.cc +++ b/src/neighbors.cc @@ -1538,6 +1538,15 @@ dump_peer_options(StoreEntry * sentry, peer * p) if (p->options.roundrobin) storeAppendPrintf(sentry, " round-robin"); + if (p->options.carp) + storeAppendPrintf(sentry, " carp"); + + if (p->options.userhash) + storeAppendPrintf(sentry, " userhash"); + + if (p->options.userhash) + storeAppendPrintf(sentry, " sourcehash"); + if (p->options.weighted_roundrobin) storeAppendPrintf(sentry, " weighted-round-robin"); diff --git a/src/peer_select.cc b/src/peer_select.cc index f48a7c082a3..1da61149d4f 100644 --- a/src/peer_select.cc +++ b/src/peer_select.cc @@ -503,6 +503,10 @@ peerGetSomeParent(ps_state * ps) if ((p = getDefaultParent(request))) { code = DEFAULT_PARENT; + } else if ((p = peerUserHashSelectParent(request))) { + code = USERHASH_PARENT; + } else if ((p = peerSourceHashSelectParent(request))) { + code = SOURCEHASH_PARENT; } else if ((p = carpSelectParent(request))) { code = CARP; } else if ((p = getRoundRobinParent(request))) { diff --git a/src/peer_sourcehash.cc b/src/peer_sourcehash.cc index d291e47dc04..a2205543394 100644 --- a/src/peer_sourcehash.cc +++ b/src/peer_sourcehash.cc @@ -40,9 +40,9 @@ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) -static int n_carp_peers = 0; -static peer **carp_peers = NULL; -static OBJH carpCachemgr; +static int n_sourcehash_peers = 0; +static peer **sourcehash_peers = NULL; +static OBJH peerSourceHashCachemgr; static int peerSortWeight(const void *a, const void *b) @@ -53,7 +53,7 @@ peerSortWeight(const void *a, const void *b) } void -carpInit(void) +peerSourceHashInit(void) { int W = 0; int K; @@ -64,16 +64,16 @@ carpInit(void) char *t; /* Clean up */ - for (k = 0; k < n_carp_peers; k++) { - cbdataReferenceDone(carp_peers[k]); + for (k = 0; k < n_sourcehash_peers; k++) { + cbdataReferenceDone(sourcehash_peers[k]); } - safe_free(carp_peers); - n_carp_peers = 0; + safe_free(sourcehash_peers); + n_sourcehash_peers = 0; /* find out which peers we have */ for (p = Config.peers; p; p = p->next) { - if (!p->options.carp) + if (!p->options.sourcehash) continue; assert(p->type == PEER_PARENT); @@ -81,46 +81,46 @@ carpInit(void) if (p->weight == 0) continue; - n_carp_peers++; + n_sourcehash_peers++; W += p->weight; } - if (n_carp_peers == 0) + if (n_sourcehash_peers == 0) return; - carp_peers = (peer **)xcalloc(n_carp_peers, sizeof(*carp_peers)); + sourcehash_peers = (peer **)xcalloc(n_sourcehash_peers, sizeof(*sourcehash_peers)); /* Build a list of the found peers and calculate hashes and load factors */ - for (P = carp_peers, p = Config.peers; p; p = p->next) { - if (!p->options.carp) + for (P = sourcehash_peers, p = Config.peers; p; p = p->next) { + if (!p->options.sourcehash) continue; if (p->weight == 0) continue; /* calculate this peers hash */ - p->carp.hash = 0; + p->sourcehash.hash = 0; for (t = p->name; *t != 0; t++) - p->carp.hash += ROTATE_LEFT(p->carp.hash, 19) + (unsigned int) *t; + p->sourcehash.hash += ROTATE_LEFT(p->sourcehash.hash, 19) + (unsigned int) *t; - p->carp.hash += p->carp.hash * 0x62531965; + p->sourcehash.hash += p->sourcehash.hash * 0x62531965; - p->carp.hash = ROTATE_LEFT(p->carp.hash, 21); + p->sourcehash.hash = ROTATE_LEFT(p->sourcehash.hash, 21); /* and load factor */ - p->carp.load_factor = ((double) p->weight) / (double) W; + p->sourcehash.load_factor = ((double) p->weight) / (double) W; - if (floor(p->carp.load_factor * 1000.0) == 0.0) - p->carp.load_factor = 0.0; + if (floor(p->sourcehash.load_factor * 1000.0) == 0.0) + p->sourcehash.load_factor = 0.0; /* add it to our list of peers */ *P++ = cbdataReference(p); } /* Sort our list on weight */ - qsort(carp_peers, n_carp_peers, sizeof(*carp_peers), peerSortWeight); + qsort(sourcehash_peers, n_sourcehash_peers, sizeof(*sourcehash_peers), peerSortWeight); /* Calculate the load factor multipliers X_k * @@ -130,7 +130,7 @@ carpInit(void) * X_k = pow (X_k, {1/(K-k+1)}) * simplified to have X_1 part of the loop */ - K = n_carp_peers; + K = n_sourcehash_peers; P_last = 0.0; /* Empty P_0 */ @@ -140,24 +140,24 @@ carpInit(void) for (k = 1; k <= K; k++) { double Kk1 = (double) (K - k + 1); - p = carp_peers[k - 1]; - p->carp.load_multiplier = (Kk1 * (p->carp.load_factor - P_last)) / Xn; - p->carp.load_multiplier += pow(X_last, Kk1); - p->carp.load_multiplier = pow(p->carp.load_multiplier, 1.0 / Kk1); - Xn *= p->carp.load_multiplier; - X_last = p->carp.load_multiplier; - P_last = p->carp.load_factor; + p = sourcehash_peers[k - 1]; + p->sourcehash.load_multiplier = (Kk1 * (p->sourcehash.load_factor - P_last)) / Xn; + p->sourcehash.load_multiplier += pow(X_last, Kk1); + p->sourcehash.load_multiplier = pow(p->sourcehash.load_multiplier, 1.0 / Kk1); + Xn *= p->sourcehash.load_multiplier; + X_last = p->sourcehash.load_multiplier; + P_last = p->sourcehash.load_factor; } } void -carpRegisterWithCacheManager(CacheManager & manager) +peerSourceHashRegisterWithCacheManager(CacheManager & manager) { - manager.registerAction("carp", "CARP information", carpCachemgr, 0, 1); + manager.registerAction("sourcehash", "CARP information", peerSourceHashCachemgr, 0, 1); } peer * -carpSelectParent(HttpRequest * request) +peerSourceHashSelectParent(HttpRequest * request) { int k; const char *c; @@ -170,25 +170,25 @@ carpSelectParent(HttpRequest * request) const char *key = NULL; char ntoabuf[MAX_IPSTRLEN]; - if (n_carp_peers == 0) + if (n_sourcehash_peers == 0) return NULL; key = request->client_addr.NtoA(ntoabuf, sizeof(ntoabuf)); /* calculate hash key */ - debugs(39, 2, "carpSelectParent: Calculating hash for " << key); + debugs(39, 2, "peerSourceHashSelectParent: Calculating hash for " << key); for (c = key; *c != 0; c++) user_hash += ROTATE_LEFT(user_hash, 19) + *c; /* select peer */ - for (k = 0; k < n_carp_peers; k++) { - tp = carp_peers[k]; - combined_hash = (user_hash ^ tp->carp.hash); + for (k = 0; k < n_sourcehash_peers; k++) { + tp = sourcehash_peers[k]; + combined_hash = (user_hash ^ tp->sourcehash.hash); combined_hash += combined_hash * 0x62531965; combined_hash = ROTATE_LEFT(combined_hash, 21); - score = combined_hash * tp->carp.load_multiplier; - debugs(39, 3, "carpSelectParent: " << tp->name << " combined_hash " << combined_hash << + score = combined_hash * tp->sourcehash.load_multiplier; + debugs(39, 3, "peerSourceHashSelectParent: " << tp->name << " combined_hash " << combined_hash << " score " << std::setprecision(0) << score); if ((score > high_score) && peerHTTPOkay(tp, request)) { @@ -198,13 +198,13 @@ carpSelectParent(HttpRequest * request) } if (p) - debugs(39, 2, "carpSelectParent: selected " << p->name); + debugs(39, 2, "peerSourceHashSelectParent: selected " << p->name); return p; } static void -carpCachemgr(StoreEntry * sentry) +peerSourceHashCachemgr(StoreEntry * sentry) { peer *p; int sumfetches = 0; @@ -220,9 +220,9 @@ carpCachemgr(StoreEntry * sentry) for (p = Config.peers; p; p = p->next) { storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n", - p->name, p->carp.hash, - p->carp.load_multiplier, - p->carp.load_factor, + p->name, p->sourcehash.hash, + p->sourcehash.load_multiplier, + p->sourcehash.load_factor, sumfetches ? (double) p->stats.fetches / sumfetches : -1.0); } } diff --git a/src/peer_userhash.cc b/src/peer_userhash.cc index eb679fe5ba9..a5853c7a9ad 100644 --- a/src/peer_userhash.cc +++ b/src/peer_userhash.cc @@ -40,9 +40,9 @@ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) -static int n_carp_peers = 0; -static peer **carp_peers = NULL; -static OBJH carpCachemgr; +static int n_userhash_peers = 0; +static peer **userhash_peers = NULL; +static OBJH peerUserHashCachemgr; static int peerSortWeight(const void *a, const void *b) @@ -53,7 +53,7 @@ peerSortWeight(const void *a, const void *b) } void -carpInit(void) +peerUserHashInit(void) { int W = 0; int K; @@ -64,16 +64,16 @@ carpInit(void) char *t; /* Clean up */ - for (k = 0; k < n_carp_peers; k++) { - cbdataReferenceDone(carp_peers[k]); + for (k = 0; k < n_userhash_peers; k++) { + cbdataReferenceDone(userhash_peers[k]); } - safe_free(carp_peers); - n_carp_peers = 0; + safe_free(userhash_peers); + n_userhash_peers = 0; /* find out which peers we have */ for (p = Config.peers; p; p = p->next) { - if (!p->options.carp) + if (!p->options.userhash) continue; assert(p->type == PEER_PARENT); @@ -81,46 +81,46 @@ carpInit(void) if (p->weight == 0) continue; - n_carp_peers++; + n_userhash_peers++; W += p->weight; } - if (n_carp_peers == 0) + if (n_userhash_peers == 0) return; - carp_peers = (peer **)xcalloc(n_carp_peers, sizeof(*carp_peers)); + userhash_peers = (peer **)xcalloc(n_userhash_peers, sizeof(*userhash_peers)); /* Build a list of the found peers and calculate hashes and load factors */ - for (P = carp_peers, p = Config.peers; p; p = p->next) { - if (!p->options.carp) + for (P = userhash_peers, p = Config.peers; p; p = p->next) { + if (!p->options.userhash) continue; if (p->weight == 0) continue; /* calculate this peers hash */ - p->carp.hash = 0; + p->userhash.hash = 0; for (t = p->name; *t != 0; t++) - p->carp.hash += ROTATE_LEFT(p->carp.hash, 19) + (unsigned int) *t; + p->userhash.hash += ROTATE_LEFT(p->userhash.hash, 19) + (unsigned int) *t; - p->carp.hash += p->carp.hash * 0x62531965; + p->userhash.hash += p->userhash.hash * 0x62531965; - p->carp.hash = ROTATE_LEFT(p->carp.hash, 21); + p->userhash.hash = ROTATE_LEFT(p->userhash.hash, 21); /* and load factor */ - p->carp.load_factor = ((double) p->weight) / (double) W; + p->userhash.load_factor = ((double) p->weight) / (double) W; - if (floor(p->carp.load_factor * 1000.0) == 0.0) - p->carp.load_factor = 0.0; + if (floor(p->userhash.load_factor * 1000.0) == 0.0) + p->userhash.load_factor = 0.0; /* add it to our list of peers */ *P++ = cbdataReference(p); } /* Sort our list on weight */ - qsort(carp_peers, n_carp_peers, sizeof(*carp_peers), peerSortWeight); + qsort(userhash_peers, n_userhash_peers, sizeof(*userhash_peers), peerSortWeight); /* Calculate the load factor multipliers X_k * @@ -130,7 +130,7 @@ carpInit(void) * X_k = pow (X_k, {1/(K-k+1)}) * simplified to have X_1 part of the loop */ - K = n_carp_peers; + K = n_userhash_peers; P_last = 0.0; /* Empty P_0 */ @@ -140,24 +140,24 @@ carpInit(void) for (k = 1; k <= K; k++) { double Kk1 = (double) (K - k + 1); - p = carp_peers[k - 1]; - p->carp.load_multiplier = (Kk1 * (p->carp.load_factor - P_last)) / Xn; - p->carp.load_multiplier += pow(X_last, Kk1); - p->carp.load_multiplier = pow(p->carp.load_multiplier, 1.0 / Kk1); - Xn *= p->carp.load_multiplier; - X_last = p->carp.load_multiplier; - P_last = p->carp.load_factor; + p = userhash_peers[k - 1]; + p->userhash.load_multiplier = (Kk1 * (p->userhash.load_factor - P_last)) / Xn; + p->userhash.load_multiplier += pow(X_last, Kk1); + p->userhash.load_multiplier = pow(p->userhash.load_multiplier, 1.0 / Kk1); + Xn *= p->userhash.load_multiplier; + X_last = p->userhash.load_multiplier; + P_last = p->userhash.load_factor; } } void -carpRegisterWithCacheManager(CacheManager & manager) +peerUserHashRegisterWithCacheManager(CacheManager & manager) { - manager.registerAction("carp", "CARP information", carpCachemgr, 0, 1); + manager.registerAction("userhash", "CARP information", peerUserHashCachemgr, 0, 1); } peer * -carpSelectParent(HttpRequest * request) +peerUserHashSelectParent(HttpRequest * request) { int k; const char *c; @@ -169,7 +169,7 @@ carpSelectParent(HttpRequest * request) double high_score = 0; const char *key = NULL; - if (n_carp_peers == 0) + if (n_userhash_peers == 0) return NULL; if (request->auth_user_request) @@ -179,19 +179,19 @@ carpSelectParent(HttpRequest * request) return NULL; /* calculate hash key */ - debugs(39, 2, "carpSelectParent: Calculating hash for " << key); + debugs(39, 2, "peerUserHashSelectParent: Calculating hash for " << key); for (c = key; *c != 0; c++) user_hash += ROTATE_LEFT(user_hash, 19) + *c; /* select peer */ - for (k = 0; k < n_carp_peers; k++) { - tp = carp_peers[k]; - combined_hash = (user_hash ^ tp->carp.hash); + for (k = 0; k < n_userhash_peers; k++) { + tp = userhash_peers[k]; + combined_hash = (user_hash ^ tp->userhash.hash); combined_hash += combined_hash * 0x62531965; combined_hash = ROTATE_LEFT(combined_hash, 21); - score = combined_hash * tp->carp.load_multiplier; - debugs(39, 3, "carpSelectParent: " << tp->name << " combined_hash " << combined_hash << + score = combined_hash * tp->userhash.load_multiplier; + debugs(39, 3, "peerUserHashSelectParent: " << tp->name << " combined_hash " << combined_hash << " score " << std::setprecision(0) << score); if ((score > high_score) && peerHTTPOkay(tp, request)) { @@ -201,13 +201,13 @@ carpSelectParent(HttpRequest * request) } if (p) - debugs(39, 2, "carpSelectParent: selected " << p->name); + debugs(39, 2, "peerUserHashSelectParent: selected " << p->name); return p; } static void -carpCachemgr(StoreEntry * sentry) +peerUserHashCachemgr(StoreEntry * sentry) { peer *p; int sumfetches = 0; @@ -223,9 +223,9 @@ carpCachemgr(StoreEntry * sentry) for (p = Config.peers; p; p = p->next) { storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n", - p->name, p->carp.hash, - p->carp.load_multiplier, - p->carp.load_factor, + p->name, p->userhash.hash, + p->userhash.load_multiplier, + p->userhash.load_factor, sumfetches ? (double) p->stats.fetches / sumfetches : -1.0); } } diff --git a/src/protos.h b/src/protos.h index 741556041f5..8a6aa8fb427 100644 --- a/src/protos.h +++ b/src/protos.h @@ -729,9 +729,16 @@ SQUIDCEXTERN const char *internalHostname(void); SQUIDCEXTERN int internalHostnameIs(const char *); SQUIDCEXTERN void carpInit(void); -extern void carpRegisterWithCacheManager(CacheManager & manager); +SQUIDCEXTERN extern void carpRegisterWithCacheManager(CacheManager & manager); SQUIDCEXTERN peer *carpSelectParent(HttpRequest *); +SQUIDCEXTERN void peerUserHashInit(void); +SQUIDCEXTERN void peerUserHashRegisterWithCacheManager(CacheManager & manager); +SQUIDCEXTERN peer * peerUserHashSelectParent(HttpRequest * request); + +SQUIDCEXTERN void peerSourceHashInit(void); +SQUIDCEXTERN void peerSourceHashRegisterWithCacheManager(CacheManager & manager); +SQUIDCEXTERN peer * peerSourceHashSelectParent(HttpRequest * request); #if USE_LEAKFINDER SQUIDCEXTERN void leakInit(void); diff --git a/src/structs.h b/src/structs.h index 3a4b22321c0..95b2b33de61 100755 --- a/src/structs.h +++ b/src/structs.h @@ -930,6 +930,8 @@ struct peer #endif unsigned int allow_miss:1; unsigned int carp:1; + unsigned int userhash:1; + unsigned int sourcehash:1; unsigned int originserver:1; } options; @@ -972,6 +974,20 @@ struct peer double load_factor; /* normalized weight value */ } carp; + struct + { + unsigned int hash; + double load_multiplier; + double load_factor; /* normalized weight value */ + } userhash; + + struct + { + unsigned int hash; + double load_multiplier; + double load_factor; /* normalized weight value */ + } sourcehash; + char *login; /* Proxy authorization */ time_t connect_timeout; int max_conn;