]> git.ipfire.org Git - thirdparty/squid.git/blame - src/carp.cc
Supply AccessLogEntry (ALE) for more fast ACL checks. (#182)
[thirdparty/squid.git] / src / carp.cc
CommitLineData
afd88fbe 1/*
5b74111a 2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
0cdcddb9 7 */
afd88fbe 8
bbc27441
AJ
9/* DEBUG: section 39 Cache Array Routing Protocol */
10
582c2af2 11#include "squid.h"
a011edee 12#include "CachePeer.h"
de03b596 13#include "HttpRequest.h"
8822ebee 14#include "mgr/Registration.h"
f0ba2534 15#include "neighbors.h"
cb365059 16#include "PeerSelectState.h"
4d5904f7 17#include "SquidConfig.h"
e6ccf245 18#include "Store.h"
b1bd952a 19#include "URL.h"
afd88fbe 20
074d6a40 21#include <cmath>
582c2af2 22
b3995439 23#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
24
25static int n_carp_peers = 0;
a3c6762c 26static CachePeer **carp_peers = NULL;
8ee9b49f 27static OBJH carpCachemgr;
28
b3995439 29static int
30peerSortWeight(const void *a, const void *b)
31{
a3c6762c
FC
32 const CachePeer *const *p1 = (const CachePeer *const *)a;
33 const CachePeer *const *p2 = (const CachePeer *const *)b;
b3995439 34 return (*p1)->weight - (*p2)->weight;
35}
36
5f5e883f
FC
37static void
38carpRegisterWithCacheManager(void)
39{
8822ebee 40 Mgr::RegisterAction("carp", "CARP information", carpCachemgr, 0, 1);
5f5e883f
FC
41}
42
afd88fbe 43void
44carpInit(void)
45{
b3995439 46 int W = 0;
47 int K;
afd88fbe 48 int k;
b3995439 49 double P_last, X_last, Xn;
a3c6762c
FC
50 CachePeer *p;
51 CachePeer **P;
b3995439 52 char *t;
53 /* Clean up */
62e76326 54
d7ae3534 55 for (k = 0; k < n_carp_peers; ++k) {
62e76326 56 cbdataReferenceDone(carp_peers[k]);
b3995439 57 }
62e76326 58
b3995439 59 safe_free(carp_peers);
60 n_carp_peers = 0;
8cb183ec
FC
61
62 /* initialize cache manager before we have a chance to leave the execution path */
63 carpRegisterWithCacheManager();
64
b3995439 65 /* find out which peers we have */
62e76326 66
afd88fbe 67 for (p = Config.peers; p; p = p->next) {
62e76326 68 if (!p->options.carp)
69 continue;
70
71 assert(p->type == PEER_PARENT);
72
73 if (p->weight == 0)
74 continue;
75
d7ae3534 76 ++n_carp_peers;
62e76326 77
78 W += p->weight;
afd88fbe 79 }
62e76326 80
b3995439 81 if (n_carp_peers == 0)
62e76326 82 return;
83
a3c6762c 84 carp_peers = (CachePeer **)xcalloc(n_carp_peers, sizeof(*carp_peers));
62e76326 85
b3995439 86 /* Build a list of the found peers and calculate hashes and load factors */
87 for (P = carp_peers, p = Config.peers; p; p = p->next) {
62e76326 88 if (!p->options.carp)
89 continue;
90
91 if (p->weight == 0)
92 continue;
93
94 /* calculate this peers hash */
95 p->carp.hash = 0;
96
d7ae3534 97 for (t = p->name; *t != 0; ++t)
62e76326 98 p->carp.hash += ROTATE_LEFT(p->carp.hash, 19) + (unsigned int) *t;
99
100 p->carp.hash += p->carp.hash * 0x62531965;
101
102 p->carp.hash = ROTATE_LEFT(p->carp.hash, 21);
103
104 /* and load factor */
105 p->carp.load_factor = ((double) p->weight) / (double) W;
106
107 if (floor(p->carp.load_factor * 1000.0) == 0.0)
108 p->carp.load_factor = 0.0;
109
110 /* add it to our list of peers */
a38ec4b1
FC
111 *P = cbdataReference(p);
112 ++P;
67766c17 113 }
62e76326 114
b3995439 115 /* Sort our list on weight */
116 qsort(carp_peers, n_carp_peers, sizeof(*carp_peers), peerSortWeight);
62e76326 117
b3995439 118 /* Calculate the load factor multipliers X_k
119 *
120 * X_1 = pow ((K*p_1), (1/K))
121 * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1})
122 * X_k += pow ((X_{k-1}, {K-k+1})
123 * X_k = pow (X_k, {1/(K-k+1)})
124 * simplified to have X_1 part of the loop
afd88fbe 125 */
b3995439 126 K = n_carp_peers;
62e76326 127
f53969cc 128 P_last = 0.0; /* Empty P_0 */
62e76326 129
f53969cc 130 Xn = 1.0; /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */
62e76326 131
f53969cc 132 X_last = 0.0; /* Empty X_0, nullifies the first pow statement */
62e76326 133
d7ae3534 134 for (k = 1; k <= K; ++k) {
62e76326 135 double Kk1 = (double) (K - k + 1);
136 p = carp_peers[k - 1];
137 p->carp.load_multiplier = (Kk1 * (p->carp.load_factor - P_last)) / Xn;
138 p->carp.load_multiplier += pow(X_last, Kk1);
139 p->carp.load_multiplier = pow(p->carp.load_multiplier, 1.0 / Kk1);
140 Xn *= p->carp.load_multiplier;
141 X_last = p->carp.load_multiplier;
142 P_last = p->carp.load_factor;
afd88fbe 143 }
62ee09ca 144}
62e76326 145
a3c6762c 146CachePeer *
cb365059 147carpSelectParent(PeerSelector *ps)
afd88fbe 148{
cb365059
EB
149 assert(ps);
150 HttpRequest *request = ps->request;
151
b3995439 152 int k;
a3c6762c
FC
153 CachePeer *p = NULL;
154 CachePeer *tp;
b3995439 155 unsigned int user_hash = 0;
156 unsigned int combined_hash;
157 double score;
158 double high_score = 0;
b3995439 159
160 if (n_carp_peers == 0)
62e76326 161 return NULL;
b3995439 162
b3995439 163 /* calculate hash key */
851feda6 164 debugs(39, 2, "carpSelectParent: Calculating hash for " << request->effectiveRequestUri());
62e76326 165
a3c6762c 166 /* select CachePeer */
d7ae3534 167 for (k = 0; k < n_carp_peers; ++k) {
2128aa19 168 SBuf key;
62e76326 169 tp = carp_peers[k];
de03b596 170 if (tp->options.carp_key.set) {
851feda6
AJ
171 // this code follows URI syntax pattern.
172 // corner cases should use the full effective request URI
de03b596 173 if (tp->options.carp_key.scheme) {
d31d59d8 174 key.append(request->url.getScheme().image());
2128aa19 175 if (key.length()) //if the scheme is not empty
de03b596
FC
176 key.append("://");
177 }
178 if (tp->options.carp_key.host) {
5c51bffb 179 key.append(request->url.host());
de03b596
FC
180 }
181 if (tp->options.carp_key.port) {
5c51bffb 182 key.appendf(":%u", request->url.port());
de03b596
FC
183 }
184 if (tp->options.carp_key.path) {
51b5dcf5
AJ
185 // XXX: fix when path and query are separate
186 key.append(request->url.path().substr(0,request->url.path().find('?'))); // 0..N
de03b596
FC
187 }
188 if (tp->options.carp_key.params) {
51b5dcf5
AJ
189 // XXX: fix when path and query are separate
190 SBuf::size_type pos;
191 if ((pos=request->url.path().find('?')) != SBuf::npos)
192 key.append(request->url.path().substr(pos)); // N..npos
de03b596 193 }
96f6f33b 194 }
de03b596
FC
195 // if the url-based key is empty, e.g. because the user is
196 // asking to balance on the path but the request doesn't supply any,
851feda6 197 // then fall back to the effective request URI
de03b596 198
2128aa19 199 if (key.isEmpty())
851feda6 200 key=request->effectiveRequestUri();
de03b596 201
2128aa19 202 for (const char *c = key.rawContent(), *e=key.rawContent()+key.length(); c < e; ++c)
de03b596 203 user_hash += ROTATE_LEFT(user_hash, 19) + *c;
62e76326 204 combined_hash = (user_hash ^ tp->carp.hash);
205 combined_hash += combined_hash * 0x62531965;
206 combined_hash = ROTATE_LEFT(combined_hash, 21);
207 score = combined_hash * tp->carp.load_multiplier;
de03b596
FC
208 debugs(39, 3, "carpSelectParent: key=" << key << " name=" << tp->name << " combined_hash=" << combined_hash <<
209 " score=" << std::setprecision(0) << score);
62e76326 210
cb365059 211 if ((score > high_score) && peerHTTPOkay(tp, ps)) {
62e76326 212 p = tp;
213 high_score = score;
214 }
afd88fbe 215 }
62e76326 216
afd88fbe 217 if (p)
d4140027 218 debugs(39, 2, "carpSelectParent: selected " << p->name);
62e76326 219
afd88fbe 220 return p;
221}
8ee9b49f 222
223static void
224carpCachemgr(StoreEntry * sentry)
225{
a3c6762c 226 CachePeer *p;
8ee9b49f 227 int sumfetches = 0;
228 storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
62e76326 229 "Hostname",
230 "Hash",
231 "Multiplier",
232 "Factor",
233 "Actual");
234
8ee9b49f 235 for (p = Config.peers; p; p = p->next)
62e76326 236 sumfetches += p->stats.fetches;
237
8ee9b49f 238 for (p = Config.peers; p; p = p->next) {
62e76326 239 storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
d4140027 240 p->name, p->carp.hash,
62e76326 241 p->carp.load_multiplier,
242 p->carp.load_factor,
243 sumfetches ? (double) p->stats.fetches / sumfetches : -1.0);
8ee9b49f 244 }
8ee9b49f 245}
f53969cc 246