]> git.ipfire.org Git - thirdparty/squid.git/blame - src/peer_select.cc
update
[thirdparty/squid.git] / src / peer_select.cc
CommitLineData
641941c0 1
062e2281 2/*
51fdcbd5 3 * $Id: peer_select.cc,v 1.25 1997/08/24 00:37:05 wessels Exp $
062e2281 4 *
5 * DEBUG: section 44 Peer Selection Algorithm
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * --------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by
14 * the National Science Foundation.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 */
31
32#include "squid.h"
33
429fdbec 34const char *hier_strings[] =
35{
36 "NONE",
37 "DIRECT",
38 "SIBLING_HIT",
39 "PARENT_HIT",
40 "DEFAULT_PARENT",
41 "SINGLE_PARENT",
42 "FIRST_UP_PARENT",
43 "NO_PARENT_DIRECT",
44 "FIRST_PARENT_MISS",
45 "CLOSEST_PARENT_MISS",
46 "CLOSEST_DIRECT",
47 "NO_DIRECT_FAIL",
48 "SOURCE_FASTEST",
49 "SIBLING_UDP_HIT_OBJ",
50 "PARENT_UDP_HIT_OBJ",
51 "PASSTHROUGH_PARENT",
52 "SSL_PARENT_MISS",
53 "ROUNDROBIN_PARENT",
54 "INVALID CODE"
55};
56
85034133 57static struct {
75e88d56 58 int timeouts;
85034133 59} PeerStats;
062e2281 60
f9e5a344 61static char *DirectStr[] =
62{
63 "DIRECT_NO",
64 "DIRECT_MAYBE",
65 "DIRECT_YES"
7b665aeb 66};
75e88d56 67
b6c0e933 68static void peerSelectFoo _PARAMS((ps_state *));
93775f90 69static void peerPingTimeout _PARAMS((void *data));
b6c0e933 70static void peerSelectCallbackFail _PARAMS((ps_state * psstate));
71static void peerHandleIcpReply _PARAMS((peer * p, peer_t type, icp_opcode op, void *data));
348b2031 72static void peerSelectStateFree _PARAMS((ps_state * psstate));
73
74static void
75peerSelectStateFree(ps_state * psstate)
76{
77 if (psstate->acl_checklist) {
51fdcbd5 78 debug(44, 1) ("calling aclChecklistFree() from peerSelectStateFree\n");
348b2031 79 aclChecklistFree(psstate->acl_checklist);
80 }
81 requestUnlink(psstate->request);
8407afee 82 psstate->request = NULL;
83 cbdataFree(psstate);
348b2031 84}
062e2281 85
86int
87peerSelectIcpPing(request_t * request, int direct, StoreEntry * entry)
88{
7b665aeb 89 int n;
93775f90 90 if (entry == NULL)
91 return 0;
f9e5a344 92 debug(44, 3) ("peerSelectIcpPing: %s\n", entry->url);
062e2281 93 if (entry->ping_status != PING_NONE)
94 return 0;
95 if (direct == DIRECT_YES)
96 fatal_dump("direct == DIRECT_YES");
97 if (!BIT_TEST(entry->flag, HIERARCHICAL) && direct != DIRECT_NO)
98 return 0;
17a0a4ee 99 if (Config.onoff.single_parent_bypass && !Config.onoff.source_ping)
062e2281 100 if (getSingleParent(request))
101 return 0;
102 if (BIT_TEST(entry->flag, KEY_PRIVATE) && !neighbors_do_private_keys)
103 if (direct != DIRECT_NO)
104 return 0;
7b665aeb 105 n = neighborsCount(request);
f9e5a344 106 debug(44, 3) ("peerSelectIcpPing: counted %d neighbors\n", n);
7b665aeb 107 return n;
062e2281 108}
109
110
111peer *
112peerGetSomeParent(request_t * request, hier_code * code)
113{
114 peer *p;
062e2281 115 if ((p = getDefaultParent(request))) {
429fdbec 116 *code = DEFAULT_PARENT;
062e2281 117 return p;
118 }
119 if ((p = getSingleParent(request))) {
429fdbec 120 *code = SINGLE_PARENT;
062e2281 121 return p;
122 }
123 if ((p = getRoundRobinParent(request))) {
429fdbec 124 *code = ROUNDROBIN_PARENT;
062e2281 125 return p;
126 }
127 if ((p = getFirstUpParent(request))) {
429fdbec 128 *code = FIRSTUP_PARENT;
062e2281 129 return p;
130 }
131 return NULL;
132}
133
134void
93775f90 135peerSelect(request_t * request,
b6c0e933 136 StoreEntry * entry,
582b6456 137 PSC * callback,
138 PSC * fail_callback,
b6c0e933 139 void *callback_data)
75e88d56 140{
b6c0e933 141 ps_state *psstate = xcalloc(1, sizeof(ps_state));
86b389fc 142 if (entry)
f9e5a344 143 debug(44, 3) ("peerSelect: %s\n", entry->url);
86b389fc 144 else
f9e5a344 145 debug(44, 3) ("peerSelect: %s\n", RequestMethodStr[request->method]);
8407afee 146 cbdataAdd(psstate);
b6c0e933 147 psstate->request = requestLink(request);
148 psstate->entry = entry;
149 psstate->callback = callback;
150 psstate->fail_callback = fail_callback;
151 psstate->callback_data = callback_data;
8407afee 152 cbdataLock(callback_data);
b6c0e933 153 psstate->icp.start = current_time;
154 peerSelectFoo(psstate);
75e88d56 155}
156
157static void
158peerCheckNeverDirectDone(int answer, void *data)
159{
b6c0e933 160 ps_state *psstate = data;
348b2031 161 psstate->acl_checklist = NULL;
a3d5953d 162 debug(44, 3) ("peerCheckNeverDirectDone: %d\n", answer);
b6c0e933 163 psstate->never_direct = answer ? 1 : -1;
164 peerSelectFoo(psstate);
75e88d56 165}
166
167static void
168peerCheckAlwaysDirectDone(int answer, void *data)
169{
b6c0e933 170 ps_state *psstate = data;
348b2031 171 psstate->acl_checklist = NULL;
a3d5953d 172 debug(44, 3) ("peerCheckAlwaysDirectDone: %d\n", answer);
7b665aeb 173 psstate->always_direct = answer ? 1 : -1;
b6c0e933 174 peerSelectFoo(psstate);
75e88d56 175}
176
93775f90 177static void
b6c0e933 178peerSelectCallback(ps_state * psstate, peer * p)
93775f90 179{
b6c0e933 180 StoreEntry *entry = psstate->entry;
8407afee 181 void *data = psstate->callback_data;
b6c0e933 182 if (entry) {
f9e5a344 183 debug(44, 3) ("peerSelectCallback: %s\n", entry->url);
b6c0e933 184 if (entry->ping_status == PING_WAITING)
185 eventDelete(peerPingTimeout, psstate);
186 entry->ping_status = PING_DONE;
187 }
8407afee 188 if (cbdataValid(data))
365e5b34 189 psstate->callback(p, data);
8407afee 190 cbdataUnlock(data);
348b2031 191 peerSelectStateFree(psstate);
93775f90 192}
193
194static void
b6c0e933 195peerSelectCallbackFail(ps_state * psstate)
93775f90 196{
b6c0e933 197 request_t *request = psstate->request;
8407afee 198 void *data = psstate->callback_data;
b6c0e933 199 char *url = psstate->entry ? psstate->entry->url : urlCanonical(request, NULL);
a3d5953d 200 debug(44, 1) ("Failed to select source for '%s'\n", url);
201 debug(44, 1) (" always_direct = %d\n", psstate->always_direct);
202 debug(44, 1) (" never_direct = %d\n", psstate->never_direct);
203 debug(44, 1) (" timeout = %d\n", psstate->icp.timeout);
8407afee 204 if (cbdataValid(data))
365e5b34 205 psstate->fail_callback(NULL, data);
8407afee 206 cbdataUnlock(data);
348b2031 207 peerSelectStateFree(psstate);
063347b4 208 /* XXX When this happens, the client request just hangs */
93775f90 209}
210
211static void
b6c0e933 212peerSelectFoo(ps_state * psstate)
062e2281 213{
214 peer *p;
215 hier_code code;
b6c0e933 216 StoreEntry *entry = psstate->entry;
217 request_t *request = psstate->request;
75e88d56 218 int direct;
7b665aeb 219 debug(44, 3) ("peerSelectFoo: '%s %s'\n",
b6c0e933 220 RequestMethodStr[request->method],
221 request->host);
eeeb6107 222 if (psstate->never_direct == 0 && Config.accessList.NeverDirect) {
348b2031 223 psstate->acl_checklist = aclChecklistCreate(
224 Config.accessList.NeverDirect,
75e88d56 225 request,
226 request->client_addr,
227 NULL, /* user agent */
348b2031 228 NULL); /* ident */
229 aclNBCheck(psstate->acl_checklist,
75e88d56 230 peerCheckNeverDirectDone,
b6c0e933 231 psstate);
75e88d56 232 return;
b6c0e933 233 } else if (psstate->never_direct > 0) {
75e88d56 234 direct = DIRECT_NO;
eeeb6107 235 } else if (psstate->always_direct == 0 && Config.accessList.AlwaysDirect) {
348b2031 236 psstate->acl_checklist = aclChecklistCreate(
237 Config.accessList.AlwaysDirect,
75e88d56 238 request,
239 request->client_addr,
240 NULL, /* user agent */
348b2031 241 NULL); /* ident */
242 aclNBCheck(psstate->acl_checklist,
75e88d56 243 peerCheckAlwaysDirectDone,
b6c0e933 244 psstate);
75e88d56 245 return;
b6c0e933 246 } else if (psstate->always_direct > 0) {
75e88d56 247 direct = DIRECT_YES;
248 } else {
249 direct = DIRECT_MAYBE;
250 }
7b665aeb 251 debug(44, 3) ("peerSelectFoo: direct = %s\n", DirectStr[direct]);
062e2281 252 if (direct == DIRECT_YES) {
7b665aeb 253 debug(44, 3) ("peerSelectFoo: DIRECT\n");
a4394ebd 254 hierarchyNote(&request->hier, DIRECT, &psstate->icp, request->host);
b6c0e933 255 peerSelectCallback(psstate, NULL);
062e2281 256 return;
257 }
258 if (peerSelectIcpPing(request, direct, entry)) {
93775f90 259 if (entry->ping_status != PING_NONE)
b6c0e933 260 fatal_dump("peerSelectFoo: bad ping_status");
a3d5953d 261 debug(44, 3) ("peerSelect: Doing ICP pings\n");
b6c0e933 262 psstate->icp.n_sent = neighborsUdpPing(request,
263 entry,
264 peerHandleIcpReply,
265 psstate,
266 &psstate->icp.n_replies_expected);
267 if (psstate->icp.n_sent > 0) {
062e2281 268 entry->ping_status = PING_WAITING;
93775f90 269 eventAdd("peerPingTimeout",
85034133 270 peerPingTimeout,
b6c0e933 271 psstate,
062e2281 272 Config.neighborTimeout);
273 return;
274 }
275 debug_trap("peerSelect: neighborsUdpPing returned 0");
276 }
429fdbec 277 if ((p = psstate->first_parent_miss)) {
278 code = FIRST_PARENT_MISS;
a3d5953d 279 debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], p->host);
a4394ebd 280 hierarchyNote(&request->hier, code, &psstate->icp, p->host);
b6c0e933 281 peerSelectCallback(psstate, p);
93775f90 282 } else if (direct != DIRECT_NO) {
429fdbec 283 code = DIRECT;
a3d5953d 284 debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], request->host);
a4394ebd 285 hierarchyNote(&request->hier, code, &psstate->icp, request->host);
b6c0e933 286 peerSelectCallback(psstate, NULL);
93775f90 287 } else if ((p = peerGetSomeParent(request, &code))) {
a3d5953d 288 debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], p->host);
a4394ebd 289 hierarchyNote(&request->hier, code, &psstate->icp, p->host);
b6c0e933 290 peerSelectCallback(psstate, p);
93775f90 291 } else {
429fdbec 292 code = NO_DIRECT_FAIL;
a4394ebd 293 hierarchyNote(&request->hier, code, &psstate->icp, NULL);
b6c0e933 294 peerSelectCallbackFail(psstate);
062e2281 295 }
296}
297
85034133 298void
93775f90 299peerPingTimeout(void *data)
062e2281 300{
b6c0e933 301 ps_state *psstate = data;
302 StoreEntry *entry = psstate->entry;
86b389fc 303 if (entry)
f9e5a344 304 debug(44, 3) ("peerPingTimeout: '%s'\n", entry->url);
93775f90 305 entry->ping_status = PING_TIMEOUT;
75e88d56 306 PeerStats.timeouts++;
b6c0e933 307 psstate->icp.timeout = 1;
308 peerSelectFoo(psstate);
85034133 309}
310
311void
312peerSelectInit(void)
313{
75e88d56 314 memset(&PeerStats, '\0', sizeof(PeerStats));
062e2281 315}
93775f90 316
317
b6c0e933 318static void
319peerHandleIcpReply(peer * p, peer_t type, icp_opcode op, void *data)
93775f90 320{
b6c0e933 321 ps_state *psstate = data;
93775f90 322 int w_rtt;
b6c0e933 323 request_t *request = psstate->request;
f9e5a344 324 debug(44, 3) ("peerHandleIcpReply: %s %s\n",
7b665aeb 325 IcpOpcodeStr[op],
326 psstate->entry->url);
b6c0e933 327 psstate->icp.n_recv++;
93775f90 328 if (op == ICP_OP_MISS || op == ICP_OP_DECHO) {
329 if (type == PEER_PARENT) {
b6c0e933 330 w_rtt = tvSubMsec(psstate->icp.start, current_time) / p->weight;
331 if (psstate->icp.w_rtt == 0 || w_rtt < psstate->icp.w_rtt) {
429fdbec 332 psstate->first_parent_miss = p;
b6c0e933 333 psstate->icp.w_rtt = w_rtt;
93775f90 334 }
335 }
336 } else if (op == ICP_OP_HIT || op == ICP_OP_HIT_OBJ) {
a4394ebd 337 hierarchyNote(&request->hier,
429fdbec 338 type == PEER_PARENT ? PARENT_HIT : SIBLING_HIT,
b6c0e933 339 &psstate->icp,
93775f90 340 p->host);
b6c0e933 341 peerSelectCallback(psstate, p);
93775f90 342 return;
343 } else if (op == ICP_OP_SECHO) {
a4394ebd 344 hierarchyNote(&request->hier,
429fdbec 345 SOURCE_FASTEST,
b6c0e933 346 &psstate->icp,
347 request->host);
4f92c80c 348 peerSelectCallback(psstate, NULL);
93775f90 349 return;
350 }
b6c0e933 351 if (psstate->icp.n_recv < psstate->icp.n_replies_expected)
93775f90 352 return;
b6c0e933 353 peerSelectFoo(psstate);
93775f90 354}