]> git.ipfire.org Git - thirdparty/squid.git/blob - src/peer_sourcehash.cc
Merged from trunk
[thirdparty/squid.git] / src / peer_sourcehash.cc
1
2 /*
3 * DEBUG: section 39 Peer source hash based selection
4 * AUTHOR: Henrik Nordstrom
5 * BASED ON: carp.cc
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
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.
18 *
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.
23 *
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.
28 *
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
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35 #include "squid.h"
36 #include "CachePeer.h"
37 #include "HttpRequest.h"
38 #include "mgr/Registration.h"
39 #include "neighbors.h"
40 #include "SquidConfig.h"
41 #include "Store.h"
42
43 #if HAVE_MATH_H
44 #include <math.h>
45 #endif
46
47 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
48
49 static int n_sourcehash_peers = 0;
50 static CachePeer **sourcehash_peers = NULL;
51 static OBJH peerSourceHashCachemgr;
52 static void peerSourceHashRegisterWithCacheManager(void);
53
54 static int
55 peerSortWeight(const void *a, const void *b)
56 {
57 const CachePeer *const *p1 = (const CachePeer *const *)a;
58 const CachePeer *const *p2 = (const CachePeer *const *)b;
59 return (*p1)->weight - (*p2)->weight;
60 }
61
62 void
63 peerSourceHashInit(void)
64 {
65 int W = 0;
66 int K;
67 int k;
68 double P_last, X_last, Xn;
69 CachePeer *p;
70 CachePeer **P;
71 char *t;
72 /* Clean up */
73
74 for (k = 0; k < n_sourcehash_peers; ++k) {
75 cbdataReferenceDone(sourcehash_peers[k]);
76 }
77
78 safe_free(sourcehash_peers);
79 n_sourcehash_peers = 0;
80 /* find out which peers we have */
81
82 for (p = Config.peers; p; p = p->next) {
83 if (!p->options.sourcehash)
84 continue;
85
86 assert(p->type == PEER_PARENT);
87
88 if (p->weight == 0)
89 continue;
90
91 ++n_sourcehash_peers;
92
93 W += p->weight;
94 }
95
96 peerSourceHashRegisterWithCacheManager();
97
98 if (n_sourcehash_peers == 0)
99 return;
100
101 sourcehash_peers = (CachePeer **)xcalloc(n_sourcehash_peers, sizeof(*sourcehash_peers));
102
103 /* Build a list of the found peers and calculate hashes and load factors */
104 for (P = sourcehash_peers, p = Config.peers; p; p = p->next) {
105 if (!p->options.sourcehash)
106 continue;
107
108 if (p->weight == 0)
109 continue;
110
111 /* calculate this peers hash */
112 p->sourcehash.hash = 0;
113
114 for (t = p->name; *t != 0; ++t)
115 p->sourcehash.hash += ROTATE_LEFT(p->sourcehash.hash, 19) + (unsigned int) *t;
116
117 p->sourcehash.hash += p->sourcehash.hash * 0x62531965;
118
119 p->sourcehash.hash = ROTATE_LEFT(p->sourcehash.hash, 21);
120
121 /* and load factor */
122 p->sourcehash.load_factor = ((double) p->weight) / (double) W;
123
124 if (floor(p->sourcehash.load_factor * 1000.0) == 0.0)
125 p->sourcehash.load_factor = 0.0;
126
127 /* add it to our list of peers */
128 *P++ = cbdataReference(p);
129 }
130
131 /* Sort our list on weight */
132 qsort(sourcehash_peers, n_sourcehash_peers, sizeof(*sourcehash_peers), peerSortWeight);
133
134 /* Calculate the load factor multipliers X_k
135 *
136 * X_1 = pow ((K*p_1), (1/K))
137 * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1})
138 * X_k += pow ((X_{k-1}, {K-k+1})
139 * X_k = pow (X_k, {1/(K-k+1)})
140 * simplified to have X_1 part of the loop
141 */
142 K = n_sourcehash_peers;
143
144 P_last = 0.0; /* Empty P_0 */
145
146 Xn = 1.0; /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */
147
148 X_last = 0.0; /* Empty X_0, nullifies the first pow statement */
149
150 for (k = 1; k <= K; ++k) {
151 double Kk1 = (double) (K - k + 1);
152 p = sourcehash_peers[k - 1];
153 p->sourcehash.load_multiplier = (Kk1 * (p->sourcehash.load_factor - P_last)) / Xn;
154 p->sourcehash.load_multiplier += pow(X_last, Kk1);
155 p->sourcehash.load_multiplier = pow(p->sourcehash.load_multiplier, 1.0 / Kk1);
156 Xn *= p->sourcehash.load_multiplier;
157 X_last = p->sourcehash.load_multiplier;
158 P_last = p->sourcehash.load_factor;
159 }
160 }
161
162 static void
163 peerSourceHashRegisterWithCacheManager(void)
164 {
165 Mgr::RegisterAction("sourcehash", "peer sourcehash information",
166 peerSourceHashCachemgr, 0, 1);
167 }
168
169 CachePeer *
170 peerSourceHashSelectParent(HttpRequest * request)
171 {
172 int k;
173 const char *c;
174 CachePeer *p = NULL;
175 CachePeer *tp;
176 unsigned int user_hash = 0;
177 unsigned int combined_hash;
178 double score;
179 double high_score = 0;
180 const char *key = NULL;
181 char ntoabuf[MAX_IPSTRLEN];
182
183 if (n_sourcehash_peers == 0)
184 return NULL;
185
186 key = request->client_addr.NtoA(ntoabuf, sizeof(ntoabuf));
187
188 /* calculate hash key */
189 debugs(39, 2, "peerSourceHashSelectParent: Calculating hash for " << key);
190
191 for (c = key; *c != 0; ++c)
192 user_hash += ROTATE_LEFT(user_hash, 19) + *c;
193
194 /* select CachePeer */
195 for (k = 0; k < n_sourcehash_peers; ++k) {
196 tp = sourcehash_peers[k];
197 combined_hash = (user_hash ^ tp->sourcehash.hash);
198 combined_hash += combined_hash * 0x62531965;
199 combined_hash = ROTATE_LEFT(combined_hash, 21);
200 score = combined_hash * tp->sourcehash.load_multiplier;
201 debugs(39, 3, "peerSourceHashSelectParent: " << tp->name << " combined_hash " << combined_hash <<
202 " score " << std::setprecision(0) << score);
203
204 if ((score > high_score) && peerHTTPOkay(tp, request)) {
205 p = tp;
206 high_score = score;
207 }
208 }
209
210 if (p)
211 debugs(39, 2, "peerSourceHashSelectParent: selected " << p->name);
212
213 return p;
214 }
215
216 static void
217 peerSourceHashCachemgr(StoreEntry * sentry)
218 {
219 CachePeer *p;
220 int sumfetches = 0;
221 storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
222 "Hostname",
223 "Hash",
224 "Multiplier",
225 "Factor",
226 "Actual");
227
228 for (p = Config.peers; p; p = p->next)
229 sumfetches += p->stats.fetches;
230
231 for (p = Config.peers; p; p = p->next) {
232 storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
233 p->name, p->sourcehash.hash,
234 p->sourcehash.load_multiplier,
235 p->sourcehash.load_factor,
236 sumfetches ? (double) p->stats.fetches / sumfetches : -1.0);
237 }
238 }