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