]>
Commit | Line | Data |
---|---|---|
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 | 34 | const 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 | 57 | static struct { |
75e88d56 | 58 | int timeouts; |
85034133 | 59 | } PeerStats; |
062e2281 | 60 | |
f9e5a344 | 61 | static char *DirectStr[] = |
62 | { | |
63 | "DIRECT_NO", | |
64 | "DIRECT_MAYBE", | |
65 | "DIRECT_YES" | |
7b665aeb | 66 | }; |
75e88d56 | 67 | |
b6c0e933 | 68 | static void peerSelectFoo _PARAMS((ps_state *)); |
93775f90 | 69 | static void peerPingTimeout _PARAMS((void *data)); |
b6c0e933 | 70 | static void peerSelectCallbackFail _PARAMS((ps_state * psstate)); |
71 | static void peerHandleIcpReply _PARAMS((peer * p, peer_t type, icp_opcode op, void *data)); | |
348b2031 | 72 | static void peerSelectStateFree _PARAMS((ps_state * psstate)); |
73 | ||
74 | static void | |
75 | peerSelectStateFree(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 | |
86 | int | |
87 | peerSelectIcpPing(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 | ||
111 | peer * | |
112 | peerGetSomeParent(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 | ||
134 | void | |
93775f90 | 135 | peerSelect(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 | ||
157 | static void | |
158 | peerCheckNeverDirectDone(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 | ||
167 | static void | |
168 | peerCheckAlwaysDirectDone(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 | 177 | static void |
b6c0e933 | 178 | peerSelectCallback(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 | ||
194 | static void | |
b6c0e933 | 195 | peerSelectCallbackFail(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 | ||
211 | static void | |
b6c0e933 | 212 | peerSelectFoo(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 | 298 | void |
93775f90 | 299 | peerPingTimeout(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 | ||
311 | void | |
312 | peerSelectInit(void) | |
313 | { | |
75e88d56 | 314 | memset(&PeerStats, '\0', sizeof(PeerStats)); |
062e2281 | 315 | } |
93775f90 | 316 | |
317 | ||
b6c0e933 | 318 | static void |
319 | peerHandleIcpReply(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 | } |