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")) {
round-robin
weighted-round-robin
carp
+ userhash
+ sourcehash
multicast-responder
closest-only
no-digest
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
peerSelectInit();
carpInit();
+ peerUserHashInit();
+ peerSourceHashInit();
}
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.
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");
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))) {
#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)
}
void
-carpInit(void)
+peerSourceHashInit(void)
{
int W = 0;
int K;
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);
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
*
* 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 */
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;
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)) {
}
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;
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);
}
}
#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)
}
void
-carpInit(void)
+peerUserHashInit(void)
{
int W = 0;
int K;
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);
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
*
* 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 */
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;
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)
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)) {
}
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;
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);
}
}
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);
#endif
unsigned int allow_miss:1;
unsigned int carp:1;
+ unsigned int userhash:1;
+ unsigned int sourcehash:1;
unsigned int originserver:1;
} options;
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;