]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_client.cc
brought over from modio - storeExpiredReferenceAge() isn't applicable
[thirdparty/squid.git] / src / store_client.cc
CommitLineData
9cef6668 1
2/*
cd748f27 3 * $Id: store_client.cc,v 1.87 2000/05/03 17:15:43 adrian Exp $
9cef6668 4 *
5 * DEBUG: section 20 Storage Manager Client-Side Interface
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 the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
efd900cb 15 * the Regents of the University of California. Please see the
16 * COPYRIGHT file for full details. Squid incorporates software
17 * developed and/or copyrighted by other sources. Please see the
18 * CREDITS file for full details.
9cef6668 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
f09f5b26 36#include "squid.h"
37
e3ef2b09 38/*
39 * NOTE: 'Header' refers to the swapfile metadata header.
40 * 'Body' refers to the swapfile body, which is the full
41 * HTTP reply (including HTTP headers and body).
42 */
2391a162 43static STRCB storeClientReadBody;
44static STRCB storeClientReadHeader;
f09f5b26 45static void storeClientCopy2(StoreEntry * e, store_client * sc);
cfac48c2 46static void storeClientCopy3(StoreEntry * e, store_client * sc);
e3ef2b09 47static void storeClientFileRead(store_client * sc);
d6f51e3c 48static EVH storeClientCopyEvent;
7405a782 49static store_client_t storeClientType(StoreEntry *);
77b32a34 50static int CheckQuickAbort2(StoreEntry * entry);
51static void CheckQuickAbort(StoreEntry * entry);
f09f5b26 52
53/* check if there is any client waiting for this object at all */
54/* return 1 if there is at least one client */
55int
56storeClientWaiting(const StoreEntry * e)
57{
58 MemObject *mem = e->mem_obj;
59 store_client *sc;
60 for (sc = mem->clients; sc; sc = sc->next) {
61 if (sc->callback_data != NULL)
62 return 1;
63 }
64 return 0;
65}
66
67store_client *
68storeClientListSearch(const MemObject * mem, void *data)
69{
70 store_client *sc;
71 for (sc = mem->clients; sc; sc = sc->next) {
72 if (sc->callback_data == data)
73 break;
74 }
75 return sc;
76}
77
7405a782 78static store_client_t
135171fe 79storeClientType(StoreEntry * e)
7405a782 80{
81 MemObject *mem = e->mem_obj;
7405a782 82 if (mem->inmem_lo)
83 return STORE_DISK_CLIENT;
b7fe0ab0 84 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
6a888d16 85 /* I don't think we should be adding clients to aborted entries */
b7fe0ab0 86 debug(20, 1) ("storeClientType: adding to ENTRY_ABORTED entry\n");
7405a782 87 return STORE_MEM_CLIENT;
6a888d16 88 }
89 if (e->store_status == STORE_OK) {
90 if (mem->inmem_lo == 0 && mem->inmem_hi > 0)
91 return STORE_MEM_CLIENT;
92 else
93 return STORE_DISK_CLIENT;
94 }
95 /* here and past, entry is STORE_PENDING */
7405a782 96 /*
97 * If this is the first client, let it be the mem client
98 */
6a888d16 99 else if (mem->nclients == 1)
100 return STORE_MEM_CLIENT;
ce872c10 101 /*
102 * If there is no disk file to open yet, we must make this a
103 * mem client. If we can't open the swapin file before writing
104 * to the client, there is no guarantee that we will be able
7e3ce7b9 105 * to open it later when we really need it.
ce872c10 106 */
107 else if (e->swap_status == SWAPOUT_NONE)
108 return STORE_MEM_CLIENT;
7405a782 109 /*
110 * otherwise, make subsequent clients read from disk so they
111 * can not delay the first, and vice-versa.
112 */
113 else
6a888d16 114 return STORE_DISK_CLIENT;
7405a782 115}
116
f09f5b26 117/* add client with fd to client list */
118void
119storeClientListAdd(StoreEntry * e, void *data)
120{
121 MemObject *mem = e->mem_obj;
122 store_client **T;
123 store_client *sc;
124 assert(mem);
125 if (storeClientListSearch(mem, data) != NULL)
126 return;
7e3ce7b9 127 e->refcount++;
f09f5b26 128 mem->nclients++;
7021844c 129 sc = memAllocate(MEM_STORE_CLIENT);
db1cd23c 130 cbdataAdd(sc, memFree, MEM_STORE_CLIENT); /* sc is callback_data for file_read */
7e3ce7b9 131 cbdataLock(data); /* locked while we point to it */
f09f5b26 132 sc->callback_data = data;
133 sc->seen_offset = 0;
134 sc->copy_offset = 0;
f115fadd 135 sc->flags.disk_io_pending = 0;
07304bf9 136 sc->entry = e;
7405a782 137 sc->type = storeClientType(e);
138 if (sc->type == STORE_DISK_CLIENT)
698a99c2 139 /* assert we'll be able to get the data we want */
140 /* maybe we should open swapin_fd here */
cd748f27 141 assert(e->swap_filen > -1 || storeSwapOutAble(e));
f09f5b26 142 for (T = &mem->clients; *T; T = &(*T)->next);
143 *T = sc;
6b8e7481 144#if DELAY_POOLS
145 sc->delay_id = 0;
6b8e7481 146#endif
f09f5b26 147}
148
b04e66e0 149static void
150storeClientCallback(store_client * sc, ssize_t sz)
151{
152 STCB *callback = sc->callback;
153 char *buf = sc->copy_buf;
154 assert(sc->callback);
b04e66e0 155 sc->callback = NULL;
156 sc->copy_buf = NULL;
157 if (cbdataValid(sc->callback_data))
158 callback(sc->callback_data, buf, sz);
159}
160
f115fadd 161static void
162storeClientCopyEvent(void *data)
163{
164 store_client *sc = data;
fe4a33ac 165 debug(20, 3) ("storeClientCopyEvent: Running\n");
67fd69de 166 sc->flags.copy_event_pending = 0;
a2899918 167 if (!sc->callback)
168 return;
f115fadd 169 storeClientCopy2(sc->entry, sc);
f115fadd 170}
171
f09f5b26 172/* copy bytes requested by the client */
173void
174storeClientCopy(StoreEntry * e,
175 off_t seen_offset,
176 off_t copy_offset,
177 size_t size,
178 char *buf,
179 STCB * callback,
180 void *data)
181{
182 store_client *sc;
b7fe0ab0 183 assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));
f09f5b26 184 debug(20, 3) ("storeClientCopy: %s, seen %d, want %d, size %d, cb %p, cbdata %p\n",
185 storeKeyText(e->key),
186 (int) seen_offset,
187 (int) copy_offset,
188 (int) size,
189 callback,
190 data);
191 sc = storeClientListSearch(e->mem_obj, data);
192 assert(sc != NULL);
193 assert(sc->callback == NULL);
194 sc->copy_offset = copy_offset;
195 sc->seen_offset = seen_offset;
196 sc->callback = callback;
197 sc->copy_buf = buf;
198 sc->copy_size = size;
199 sc->copy_offset = copy_offset;
67fd69de 200 storeClientCopy2(e, sc);
f09f5b26 201}
202
07304bf9 203/*
204 * This function is used below to decide if we have any more data to
0bb129ee 205 * send to the client. If the store_status is STORE_PENDING, then we
b7fe0ab0 206 * do have more data to send. If its STORE_OK, then
0bb129ee 207 * we continue checking. If the object length is negative, then we
208 * don't know the real length and must open the swap file to find out.
209 * If the length is >= 0, then we compare it to the requested copy
210 * offset.
07304bf9 211 */
212static int
213storeClientNoMoreToSend(StoreEntry * e, store_client * sc)
214{
215 ssize_t len;
0bb129ee 216 if (e->store_status == STORE_PENDING)
07304bf9 217 return 0;
218 if ((len = objectLen(e)) < 0)
219 return 0;
220 if (sc->copy_offset < len)
221 return 0;
222 return 1;
223}
224
f09f5b26 225static void
226storeClientCopy2(StoreEntry * e, store_client * sc)
227{
67fd69de 228 if (sc->flags.copy_event_pending)
229 return;
db1cd23c 230 if (EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
231 debug(20, 5) ("storeClientCopy2: returning because ENTRY_FWD_HDR_WAIT set\n");
7e3e1d01 232 return;
db1cd23c 233 }
67fd69de 234 if (sc->flags.store_copying) {
235 sc->flags.copy_event_pending = 1;
3d36b8ab 236 debug(20, 3) ("storeClientCopy2: Queueing storeClientCopyEvent()\n");
c43f5247 237 eventAdd("storeClientCopyEvent", storeClientCopyEvent, sc, 0.0, 0);
67fd69de 238 return;
239 }
a455c097 240 cbdataLock(sc); /* ick, prevent sc from getting freed */
67fd69de 241 sc->flags.store_copying = 1;
f09f5b26 242 debug(20, 3) ("storeClientCopy2: %s\n", storeKeyText(e->key));
b04e66e0 243 assert(sc->callback != NULL);
0bb129ee 244 /*
b7fe0ab0 245 * We used to check for ENTRY_ABORTED here. But there were some
0bb129ee 246 * problems. For example, we might have a slow client (or two) and
247 * the server-side is reading far ahead and swapping to disk. Even
248 * if the server-side aborts, we want to give the client(s)
249 * everything we got before the abort condition occurred.
250 */
cfac48c2 251 storeClientCopy3(e, sc);
252 sc->flags.store_copying = 0;
253 cbdataUnlock(sc); /* ick, allow sc to be freed */
254}
255
256static void
257storeClientCopy3(StoreEntry * e, store_client * sc)
258{
cfac48c2 259 MemObject *mem = e->mem_obj;
260 size_t sz;
cd748f27 261
0bb129ee 262 if (storeClientNoMoreToSend(e, sc)) {
f09f5b26 263 /* There is no more to send! */
b04e66e0 264 storeClientCallback(sc, 0);
cfac48c2 265 return;
266 }
267 if (e->store_status == STORE_PENDING && sc->seen_offset >= mem->inmem_hi) {
f09f5b26 268 /* client has already seen this, wait for more */
cfac48c2 269 debug(20, 3) ("storeClientCopy3: Waiting for more\n");
270 return;
271 }
272 /*
273 * Slight weirdness here. We open a swapin file for any
274 * STORE_DISK_CLIENT, even if we can copy the requested chunk
275 * from memory in the next block. We must try to open the
276 * swapin file before sending any data to the client side. If
277 * we postpone the open, and then can not open the file later
278 * on, the client loses big time. Its transfer just gets cut
279 * off. Better to open it early (while the client side handler
280 * is clientCacheHit) so that we can fall back to a cache miss
281 * if needed.
282 */
283 if (STORE_DISK_CLIENT == sc->type && NULL == sc->swapin_sio) {
284 debug(20, 3) ("storeClientCopy3: Need to open swap in file\n");
f09f5b26 285 /* gotta open the swapin file */
e11322b2 286 if (storeTooManyDiskFilesOpen()) {
43f3238f 287 /* yuck -- this causes a TCP_SWAPFAIL_MISS on the client side */
b04e66e0 288 storeClientCallback(sc, -1);
289 return;
290 }
291 if (!sc->flags.disk_io_pending) {
7e3ce7b9 292 storeSwapInStart(sc);
293 if (NULL == sc->swapin_sio) {
b04e66e0 294 storeClientCallback(sc, -1);
295 return;
7e3ce7b9 296 }
b04e66e0 297 /*
298 * If the open succeeds we either copy from memory, or
299 * schedule a disk read in the next block.
300 */
7e3ce7b9 301 } else {
f3435962 302 debug(20, 1) ("WARNING: Averted multiple fd operation (1)\n");
cfac48c2 303 return;
f09f5b26 304 }
305 }
cfac48c2 306 if (sc->copy_offset >= mem->inmem_lo && sc->copy_offset < mem->inmem_hi) {
307 /* What the client wants is in memory */
308 debug(20, 3) ("storeClientCopy3: Copying from memory\n");
309 sz = stmemCopy(&mem->data_hdr,
cd748f27 310 sc->copy_offset, sc->copy_buf, sc->copy_size);
311 storeClientCallback(sc, sz);
312 return;
cfac48c2 313 }
cd748f27 314 /* What the client wants is not in memory. Schedule a disk read */
cfac48c2 315 assert(STORE_DISK_CLIENT == sc->type);
a928befc 316 assert(!sc->flags.disk_io_pending);
cfac48c2 317 debug(20, 3) ("storeClientCopy3: reading from STORE\n");
cfac48c2 318 storeClientFileRead(sc);
f09f5b26 319}
320
f09f5b26 321static void
e3ef2b09 322storeClientFileRead(store_client * sc)
f09f5b26 323{
07304bf9 324 MemObject *mem = sc->entry->mem_obj;
f09f5b26 325 assert(sc->callback != NULL);
b04e66e0 326 assert(!sc->flags.disk_io_pending);
327 sc->flags.disk_io_pending = 1;
dee51794 328 if (mem->swap_hdr_sz == 0) {
2391a162 329 storeRead(sc->swapin_sio,
d8b9a541 330 sc->copy_buf,
331 sc->copy_size,
e3ef2b09 332 0,
333 storeClientReadHeader,
334 sc);
9d66d521 335 } else {
3157c72f 336 if (sc->entry->swap_status == SWAPOUT_WRITING)
2391a162 337 assert(storeOffset(mem->swapout.sio) > sc->copy_offset + mem->swap_hdr_sz);
338 storeRead(sc->swapin_sio,
e3ef2b09 339 sc->copy_buf,
340 sc->copy_size,
341 sc->copy_offset + mem->swap_hdr_sz,
342 storeClientReadBody,
343 sc);
3157c72f 344 }
f09f5b26 345}
346
347static void
5bd1abac 348storeClientReadBody(void *data, const char *buf, ssize_t len)
f09f5b26 349{
350 store_client *sc = data;
07304bf9 351 MemObject *mem = sc->entry->mem_obj;
27002b34 352 assert(sc->flags.disk_io_pending);
f115fadd 353 sc->flags.disk_io_pending = 0;
f09f5b26 354 assert(sc->callback != NULL);
2391a162 355 debug(20, 3) ("storeClientReadBody: len %d\n", len);
cb69b4c7 356 if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
9bc73deb 357 httpReplyParse(mem->reply, sc->copy_buf, headersEnd(sc->copy_buf, len));
b04e66e0 358 storeClientCallback(sc, len);
f09f5b26 359}
360
e3ef2b09 361static void
5bd1abac 362storeClientReadHeader(void *data, const char *buf, ssize_t len)
e3ef2b09 363{
e3ef2b09 364 store_client *sc = data;
07304bf9 365 StoreEntry *e = sc->entry;
366 MemObject *mem = e->mem_obj;
e3ef2b09 367 int swap_hdr_sz = 0;
368 size_t body_sz;
369 size_t copy_sz;
370 tlv *tlv_list;
7e3ce7b9 371 tlv *t;
372 int swap_object_ok = 1;
27002b34 373 assert(sc->flags.disk_io_pending);
f115fadd 374 sc->flags.disk_io_pending = 0;
e3ef2b09 375 assert(sc->callback != NULL);
2391a162 376 debug(20, 3) ("storeClientReadHeader: len %d\n", len);
e3ef2b09 377 if (len < 0) {
2391a162 378 debug(20, 3) ("storeClientReadHeader: %s\n", xstrerror());
b04e66e0 379 storeClientCallback(sc, len);
e3ef2b09 380 return;
381 }
382 tlv_list = storeSwapMetaUnpack(buf, &swap_hdr_sz);
9bc73deb 383 if (swap_hdr_sz > len) {
384 /* oops, bad disk file? */
efd900cb 385 debug(20, 1) ("WARNING: swapfile header too small\n");
b04e66e0 386 storeClientCallback(sc, -1);
9bc73deb 387 return;
388 }
e3ef2b09 389 if (tlv_list == NULL) {
cd748f27 390 debug(20, 1) ("WARNING: failed to unpack meta data\n");
b04e66e0 391 storeClientCallback(sc, -1);
e3ef2b09 392 return;
393 }
394 /*
7e3ce7b9 395 * Check the meta data and make sure we got the right object.
e3ef2b09 396 */
7e3ce7b9 397 for (t = tlv_list; t; t = t->next) {
398 switch (t->type) {
399 case STORE_META_KEY:
400 assert(t->length == MD5_DIGEST_CHARS);
b04e66e0 401 if (memcmp(t->value, e->key, MD5_DIGEST_CHARS)) {
7e3ce7b9 402 debug(20, 1) ("WARNING: swapin MD5 mismatch\n");
b04e66e0 403 debug(20, 1) ("\t%s\n", storeKeyText(t->value));
404 debug(20, 1) ("\t%s\n", storeKeyText(e->key));
405 }
7e3ce7b9 406 break;
407 case STORE_META_URL:
408 if (NULL == mem->url)
409 (void) 0; /* can't check */
410 else if (0 == strcasecmp(mem->url, t->value))
411 (void) 0; /* a match! */
412 else {
413 debug(20, 1) ("storeClientReadHeader: URL mismatch\n");
414 debug(20, 1) ("\t{%s} != {%s}\n", t->value, mem->url);
415 swap_object_ok = 0;
416 break;
417 }
418 break;
419 case STORE_META_STD:
420 break;
421 default:
422 debug(20, 1) ("WARNING: got unused STORE_META type %d\n", t->type);
423 break;
424 }
425 }
07304bf9 426 storeSwapTLVFree(tlv_list);
7e3ce7b9 427 if (!swap_object_ok) {
b04e66e0 428 storeClientCallback(sc, -1);
7e3ce7b9 429 return;
430 }
e3ef2b09 431 mem->swap_hdr_sz = swap_hdr_sz;
07304bf9 432 mem->object_sz = e->swap_file_sz - swap_hdr_sz;
e3ef2b09 433 /*
434 * If our last read got some data the client wants, then give
435 * it to them, otherwise schedule another read.
436 */
437 body_sz = len - swap_hdr_sz;
438 if (sc->copy_offset < body_sz) {
439 /*
25535cbe 440 * we have (part of) what they want
e3ef2b09 441 */
442 copy_sz = XMIN(sc->copy_size, body_sz);
25535cbe 443 debug(20, 3) ("storeClientReadHeader: copying %d bytes of body\n",
444 copy_sz);
d8b9a541 445 xmemmove(sc->copy_buf, sc->copy_buf + swap_hdr_sz, copy_sz);
cb69b4c7 446 if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
9bc73deb 447 httpReplyParse(mem->reply, sc->copy_buf,
448 headersEnd(sc->copy_buf, copy_sz));
b04e66e0 449 storeClientCallback(sc, copy_sz);
e3ef2b09 450 return;
451 }
452 /*
453 * we don't have what the client wants, but at least we now
454 * know the swap header size.
455 */
e3ef2b09 456 storeClientFileRead(sc);
457}
458
f09f5b26 459int
460storeClientCopyPending(StoreEntry * e, void *data)
461{
462 /* return 1 if there is a callback registered for this client */
463 store_client *sc = storeClientListSearch(e->mem_obj, data);
464 if (sc == NULL)
465 return 0;
466 if (sc->callback == NULL)
467 return 0;
468 return 1;
469}
470
471int
472storeUnregister(StoreEntry * e, void *data)
473{
474 MemObject *mem = e->mem_obj;
475 store_client *sc;
476 store_client **S;
f09f5b26 477 if (mem == NULL)
478 return 0;
479 debug(20, 3) ("storeUnregister: called for '%s'\n", storeKeyText(e->key));
480 for (S = &mem->clients; (sc = *S) != NULL; S = &(*S)->next) {
481 if (sc->callback_data == data)
482 break;
483 }
484 if (sc == NULL)
485 return 0;
4c454c5c 486 if (sc == mem->clients) {
487 /*
488 * If we are unregistering the _first_ client for this
489 * entry, then we have to reset the client FD to -1.
490 */
491 mem->fd = -1;
492 }
f09f5b26 493 *S = sc->next;
494 mem->nclients--;
f09f5b26 495 if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE)
2391a162 496 storeSwapOut(e);
eb824054 497 if (sc->swapin_sio) {
2391a162 498 storeClose(sc->swapin_sio);
cfac48c2 499 cbdataUnlock(sc->swapin_sio);
eb824054 500 sc->swapin_sio = NULL;
501 }
b04e66e0 502 if (NULL != sc->callback) {
f09f5b26 503 /* callback with ssize = -1 to indicate unexpected termination */
504 debug(20, 3) ("storeUnregister: store_client for %s has a callback\n",
505 mem->url);
b04e66e0 506 storeClientCallback(sc, -1);
f09f5b26 507 }
b6a2f15e 508#if DELAY_POOLS
509 delayUnregisterDelayIdPtr(&sc->delay_id);
510#endif
7e3ce7b9 511 cbdataUnlock(sc->callback_data); /* we're done with it now */
a928befc 512 /*assert(!sc->flags.disk_io_pending); */
f09f5b26 513 cbdataFree(sc);
77b32a34 514 assert(e->lock_count > 0);
515 if (mem->nclients == 0)
516 CheckQuickAbort(e);
f09f5b26 517 return 1;
518}
519
520off_t
521storeLowestMemReaderOffset(const StoreEntry * entry)
522{
523 const MemObject *mem = entry->mem_obj;
50a49a6f 524 off_t lowest = mem->inmem_hi + 1;
f09f5b26 525 store_client *sc;
526 store_client *nx = NULL;
527 for (sc = mem->clients; sc; sc = nx) {
528 nx = sc->next;
529 if (sc->callback_data == NULL) /* open slot */
530 continue;
cd748f27 531 if (sc->type != STORE_MEM_CLIENT)
532 continue;
cfac48c2 533 if (sc->type == STORE_DISK_CLIENT)
534 if (NULL != sc->swapin_sio)
535 continue;
f09f5b26 536 if (sc->copy_offset < lowest)
537 lowest = sc->copy_offset;
538 }
539 return lowest;
540}
541
542/* Call handlers waiting for data to be appended to E. */
543void
544InvokeHandlers(StoreEntry * e)
545{
546 int i = 0;
547 MemObject *mem = e->mem_obj;
548 store_client *sc;
549 store_client *nx = NULL;
550 assert(mem->clients != NULL || mem->nclients == 0);
551 debug(20, 3) ("InvokeHandlers: %s\n", storeKeyText(e->key));
552 /* walk the entire list looking for valid callbacks */
553 for (sc = mem->clients; sc; sc = nx) {
554 nx = sc->next;
555 debug(20, 3) ("InvokeHandlers: checking client #%d\n", i++);
556 if (sc->callback_data == NULL)
557 continue;
558 if (sc->callback == NULL)
559 continue;
a928befc 560 if (sc->flags.disk_io_pending)
561 continue;
f09f5b26 562 storeClientCopy2(e, sc);
563 }
564}
565
566int
567storePendingNClients(const StoreEntry * e)
568{
f09f5b26 569 MemObject *mem = e->mem_obj;
36547bcf 570 int npend = NULL == mem ? 0 : mem->nclients;
1afe05c5 571 debug(20, 3) ("storePendingNClients: returning %d\n", npend);
f09f5b26 572 return npend;
573}
77b32a34 574
575/* return 1 if the request should be aborted */
576static int
577CheckQuickAbort2(StoreEntry * entry)
578{
579 int curlen;
580 int minlen;
581 int expectlen;
582 MemObject *mem = entry->mem_obj;
583 assert(mem);
584 debug(20, 3) ("CheckQuickAbort2: entry=%p, mem=%p\n", entry, mem);
0e5bd28f 585 if (mem->request && !mem->request->flags.cachable) {
6946d7e1 586 debug(20, 3) ("CheckQuickAbort2: YES !mem->request->flags.cachable\n");
77b32a34 587 return 1;
588 }
589 if (EBIT_TEST(entry->flags, KEY_PRIVATE)) {
6946d7e1 590 debug(20, 3) ("CheckQuickAbort2: YES KEY_PRIVATE\n");
77b32a34 591 return 1;
592 }
b6a2f15e 593 expectlen = mem->reply->content_length + mem->reply->hdr_sz;
77b32a34 594 curlen = (int) mem->inmem_hi;
595 minlen = (int) Config.quickAbort.min << 10;
596 if (minlen < 0) {
597 debug(20, 3) ("CheckQuickAbort2: NO disabled\n");
598 return 0;
599 }
600 if (curlen > expectlen) {
6946d7e1 601 debug(20, 3) ("CheckQuickAbort2: YES bad content length\n");
77b32a34 602 return 1;
603 }
604 if ((expectlen - curlen) < minlen) {
605 debug(20, 3) ("CheckQuickAbort2: NO only little more left\n");
606 return 0;
607 }
608 if ((expectlen - curlen) > (Config.quickAbort.max << 10)) {
6946d7e1 609 debug(20, 3) ("CheckQuickAbort2: YES too much left to go\n");
77b32a34 610 return 1;
611 }
612 if (expectlen < 100) {
613 debug(20, 3) ("CheckQuickAbort2: NO avoid FPE\n");
614 return 0;
615 }
616 if ((curlen / (expectlen / 100)) > Config.quickAbort.pct) {
617 debug(20, 3) ("CheckQuickAbort2: NO past point of no return\n");
618 return 0;
619 }
6946d7e1 620 debug(20, 3) ("CheckQuickAbort2: YES default, returning 1\n");
77b32a34 621 return 1;
622}
623
624static void
625CheckQuickAbort(StoreEntry * entry)
626{
627 if (entry == NULL)
628 return;
629 if (storePendingNClients(entry) > 0)
630 return;
631 if (entry->store_status != STORE_PENDING)
632 return;
986ebffc 633 if (EBIT_TEST(entry->flags, ENTRY_SPECIAL))
634 return;
77b32a34 635 if (CheckQuickAbort2(entry) == 0)
636 return;
637 Counter.aborted_requests++;
7197b20d 638 storeAbort(entry);
77b32a34 639}