]> git.ipfire.org Git - thirdparty/squid.git/blame - src/carp.cc
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / src / carp.cc
CommitLineData
f740a279 1
afd88fbe 2/*
262a0e14 3 * $Id$
afd88fbe 4 *
67f46679 5 * DEBUG: section 39 Cache Array Routing Protocol
b3995439 6 * AUTHOR: Henrik Nordstrom
7 * BASED ON: carp.c by Eric Stern and draft-vinod-carp-v1-03.txt
afd88fbe 8 *
2b6662ba 9 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 10 * ----------------------------------------------------------
11 *
2b6662ba 12 * Squid is the result of efforts by numerous individuals from
13 * the Internet community; see the CONTRIBUTORS file for full
14 * details. Many organizations have provided support for Squid's
15 * development; see the SPONSORS file for full details. Squid is
16 * Copyrighted (C) 2001 by the Regents of the University of
17 * California; see the COPYRIGHT file for full details. Squid
18 * incorporates software developed and/or copyrighted by other
19 * sources; see the CREDITS file for full details.
e25c139f 20 *
afd88fbe 21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26ac0430 25 *
afd88fbe 26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
26ac0430 30 *
afd88fbe 31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
cbdec147 33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 34 *
0cdcddb9 35 */
afd88fbe 36
37#include "squid.h"
62ee09ca 38#include "CacheManager.h"
e6ccf245 39#include "Store.h"
afd88fbe 40
b3995439 41#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
42
43static int n_carp_peers = 0;
44static peer **carp_peers = NULL;
8ee9b49f 45static OBJH carpCachemgr;
46
b3995439 47static int
48peerSortWeight(const void *a, const void *b)
49{
ff83713b 50 const peer *const *p1 = (const peer *const *)a;
51 const peer *const *p2 = (const peer *const *)b;
b3995439 52 return (*p1)->weight - (*p2)->weight;
53}
54
5f5e883f
FC
55static void
56carpRegisterWithCacheManager(void)
57{
58 CacheManager::GetInstance()->
26ac0430 59 registerAction("carp", "CARP information", carpCachemgr, 0, 1);
5f5e883f
FC
60}
61
afd88fbe 62void
63carpInit(void)
64{
b3995439 65 int W = 0;
66 int K;
afd88fbe 67 int k;
b3995439 68 double P_last, X_last, Xn;
afd88fbe 69 peer *p;
b3995439 70 peer **P;
71 char *t;
72 /* Clean up */
62e76326 73
b3995439 74 for (k = 0; k < n_carp_peers; k++) {
62e76326 75 cbdataReferenceDone(carp_peers[k]);
b3995439 76 }
62e76326 77
b3995439 78 safe_free(carp_peers);
79 n_carp_peers = 0;
8cb183ec
FC
80
81 /* initialize cache manager before we have a chance to leave the execution path */
82 carpRegisterWithCacheManager();
83
b3995439 84 /* find out which peers we have */
62e76326 85
afd88fbe 86 for (p = Config.peers; p; p = p->next) {
62e76326 87 if (!p->options.carp)
88 continue;
89
90 assert(p->type == PEER_PARENT);
91
92 if (p->weight == 0)
93 continue;
94
95 n_carp_peers++;
96
97 W += p->weight;
afd88fbe 98 }
62e76326 99
b3995439 100 if (n_carp_peers == 0)
62e76326 101 return;
102
ff83713b 103 carp_peers = (peer **)xcalloc(n_carp_peers, sizeof(*carp_peers));
62e76326 104
b3995439 105 /* Build a list of the found peers and calculate hashes and load factors */
106 for (P = carp_peers, p = Config.peers; p; p = p->next) {
62e76326 107 if (!p->options.carp)
108 continue;
109
110 if (p->weight == 0)
111 continue;
112
113 /* calculate this peers hash */
114 p->carp.hash = 0;
115
d4140027 116 for (t = p->name; *t != 0; t++)
62e76326 117 p->carp.hash += ROTATE_LEFT(p->carp.hash, 19) + (unsigned int) *t;
118
119 p->carp.hash += p->carp.hash * 0x62531965;
120
121 p->carp.hash = ROTATE_LEFT(p->carp.hash, 21);
122
123 /* and load factor */
124 p->carp.load_factor = ((double) p->weight) / (double) W;
125
126 if (floor(p->carp.load_factor * 1000.0) == 0.0)
127 p->carp.load_factor = 0.0;
128
129 /* add it to our list of peers */
130 *P++ = cbdataReference(p);
67766c17 131 }
62e76326 132
b3995439 133 /* Sort our list on weight */
134 qsort(carp_peers, n_carp_peers, sizeof(*carp_peers), peerSortWeight);
62e76326 135
b3995439 136 /* Calculate the load factor multipliers X_k
137 *
138 * X_1 = pow ((K*p_1), (1/K))
139 * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1})
140 * X_k += pow ((X_{k-1}, {K-k+1})
141 * X_k = pow (X_k, {1/(K-k+1)})
142 * simplified to have X_1 part of the loop
afd88fbe 143 */
b3995439 144 K = n_carp_peers;
62e76326 145
b3995439 146 P_last = 0.0; /* Empty P_0 */
62e76326 147
b3995439 148 Xn = 1.0; /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */
62e76326 149
b3995439 150 X_last = 0.0; /* Empty X_0, nullifies the first pow statement */
62e76326 151
b3995439 152 for (k = 1; k <= K; k++) {
62e76326 153 double Kk1 = (double) (K - k + 1);
154 p = carp_peers[k - 1];
155 p->carp.load_multiplier = (Kk1 * (p->carp.load_factor - P_last)) / Xn;
156 p->carp.load_multiplier += pow(X_last, Kk1);
157 p->carp.load_multiplier = pow(p->carp.load_multiplier, 1.0 / Kk1);
158 Xn *= p->carp.load_multiplier;
159 X_last = p->carp.load_multiplier;
160 P_last = p->carp.load_factor;
afd88fbe 161 }
62ee09ca 162}
62e76326 163
afd88fbe 164peer *
190154cf 165carpSelectParent(HttpRequest * request)
afd88fbe 166{
b3995439 167 int k;
afd88fbe 168 const char *c;
169 peer *p = NULL;
170 peer *tp;
b3995439 171 unsigned int user_hash = 0;
172 unsigned int combined_hash;
173 double score;
174 double high_score = 0;
ecefb559 175 const char *key = NULL;
b3995439 176
177 if (n_carp_peers == 0)
62e76326 178 return NULL;
b3995439 179
358a75e0 180 key = urlCanonical(request);
b3995439 181
182 /* calculate hash key */
bf8fe701 183 debugs(39, 2, "carpSelectParent: Calculating hash for " << key);
62e76326 184
b3995439 185 for (c = key; *c != 0; c++)
62e76326 186 user_hash += ROTATE_LEFT(user_hash, 19) + *c;
187
afd88fbe 188 /* select peer */
b3995439 189 for (k = 0; k < n_carp_peers; k++) {
62e76326 190 tp = carp_peers[k];
191 combined_hash = (user_hash ^ tp->carp.hash);
192 combined_hash += combined_hash * 0x62531965;
193 combined_hash = ROTATE_LEFT(combined_hash, 21);
194 score = combined_hash * tp->carp.load_multiplier;
26ac0430 195 debugs(39, 3, "carpSelectParent: " << tp->name << " combined_hash " << combined_hash <<
bf8fe701 196 " score " << std::setprecision(0) << score);
62e76326 197
198 if ((score > high_score) && peerHTTPOkay(tp, request)) {
199 p = tp;
200 high_score = score;
201 }
afd88fbe 202 }
62e76326 203
afd88fbe 204 if (p)
d4140027 205 debugs(39, 2, "carpSelectParent: selected " << p->name);
62e76326 206
afd88fbe 207 return p;
208}
8ee9b49f 209
210static void
211carpCachemgr(StoreEntry * sentry)
212{
213 peer *p;
214 int sumfetches = 0;
215 storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
62e76326 216 "Hostname",
217 "Hash",
218 "Multiplier",
219 "Factor",
220 "Actual");
221
8ee9b49f 222 for (p = Config.peers; p; p = p->next)
62e76326 223 sumfetches += p->stats.fetches;
224
8ee9b49f 225 for (p = Config.peers; p; p = p->next) {
62e76326 226 storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
d4140027 227 p->name, p->carp.hash,
62e76326 228 p->carp.load_multiplier,
229 p->carp.load_factor,
230 sumfetches ? (double) p->stats.fetches / sumfetches : -1.0);
8ee9b49f 231 }
8ee9b49f 232}