]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_client.cc
Removed a bunch of code marked UNUSED_CODE, OLD, and BROKEN_CODE
[thirdparty/squid.git] / src / store_client.cc
CommitLineData
9cef6668 1
2/*
942799f1 3 * $Id: store_client.cc,v 1.151 2007/04/20 06:54:48 wessels Exp $
9cef6668 4 *
2f44bd34 5 * DEBUG: section 90 Storage Manager Client-Side Interface
9cef6668 6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9cef6668 9 * ----------------------------------------------------------
10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the 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 *
2f44bd34 34 * Portions copyright (c) 2003 Robert Collins <robertc@squid-cache.org>
9cef6668 35 */
36
f09f5b26 37#include "squid.h"
a553a5a3 38#include "event.h"
c8be6d7b 39#include "StoreClient.h"
e6ccf245 40#include "Store.h"
528b2c61 41#include "HttpReply.h"
42#include "MemObject.h"
43#include "StoreMeta.h"
44#include "StoreMetaUnpacker.h"
b67e2c8c 45#if DELAY_POOLS
46#include "DelayPools.h"
47#endif
a2ac85d9 48#include "HttpRequest.h"
0eb49b6d 49#include "MemBuf.h"
c8be6d7b 50
e3ef2b09 51/*
52 * NOTE: 'Header' refers to the swapfile metadata header.
528b2c61 53 * 'OBJHeader' refers to the object header, with cannonical
54 * processed object headers (which may derive from FTP/HTTP etc
55 * upstream protocols
e3ef2b09 56 * 'Body' refers to the swapfile body, which is the full
57 * HTTP reply (including HTTP headers and body).
58 */
4fcc8876 59static StoreIOState::STRCB storeClientReadBody;
60static StoreIOState::STRCB storeClientReadHeader;
f09f5b26 61static void storeClientCopy2(StoreEntry * e, store_client * sc);
d6f51e3c 62static EVH storeClientCopyEvent;
77b32a34 63static int CheckQuickAbort2(StoreEntry * entry);
64static void CheckQuickAbort(StoreEntry * entry);
f09f5b26 65
b001e822 66CBDATA_CLASS_INIT(store_client);
528b2c61 67
68void *
b001e822 69store_client::operator new (size_t)
528b2c61 70{
528b2c61 71 CBDATA_INIT_TYPE(store_client);
b001e822 72 store_client *result = cbdataAlloc(store_client);
73 return result;
528b2c61 74}
75
76void
77store_client::operator delete (void *address)
78{
b001e822 79 store_client *t = static_cast<store_client *>(address);
80 cbdataFree(t);
528b2c61 81}
82
83bool
84store_client::memReaderHasLowerOffset(off_t anOffset) const
85{
86 return getType() == STORE_MEM_CLIENT && copyInto.offset < anOffset;
87}
88
89int
90store_client::getType() const
91{
92 return type;
93}
94
06d2839d 95#if STORE_CLIENT_LIST_DEBUG
fa80a8ef 96static store_client *
f09f5b26 97storeClientListSearch(const MemObject * mem, void *data)
98{
06d2839d 99 dlink_node *node;
100 store_client *sc = NULL;
62e76326 101
06d2839d 102 for (node = mem->clients.head; node; node = node->next) {
62e76326 103 sc = node->data;
104
105 if (sc->owner == data)
106 return sc;
f09f5b26 107 }
62e76326 108
06d2839d 109 return NULL;
f09f5b26 110}
c8be6d7b 111
112int
113storeClientIsThisAClient(store_client * sc, void *someClient)
114{
115 return sc->owner == someClient;
116}
62e76326 117
06d2839d 118#endif
924f73bc 119#include "HttpRequest.h"
f09f5b26 120
121/* add client with fd to client list */
06d2839d 122store_client *
f09f5b26 123storeClientListAdd(StoreEntry * e, void *data)
124{
125 MemObject *mem = e->mem_obj;
f09f5b26 126 store_client *sc;
127 assert(mem);
06d2839d 128#if STORE_CLIENT_LIST_DEBUG
62e76326 129
f09f5b26 130 if (storeClientListSearch(mem, data) != NULL)
62e76326 131 /* XXX die! */
132 assert(1 == 0);
133
6b8e7481 134#endif
62e76326 135
528b2c61 136 sc = new store_client (e);
62e76326 137
528b2c61 138 mem->addClient(sc);
62e76326 139
06d2839d 140 return sc;
f09f5b26 141}
142
528b2c61 143void
144store_client::callback(ssize_t sz, bool error)
b04e66e0 145{
528b2c61 146 StoreIOBuffer result (sz, 0 ,copyInto.data);
62e76326 147
c8be6d7b 148 if (sz < 0) {
62e76326 149 result.flags.error = 1;
150 result.length = 0;
528b2c61 151 } else {
62e76326 152 result.flags.error = error ? 1 : 0;
c8be6d7b 153 }
62e76326 154
528b2c61 155 result.offset = cmp_offset;
90703668 156 assert(_callback.pending());
528b2c61 157 cmp_offset = copyInto.offset + sz;
158 STCB *temphandler = _callback.callback_handler;
159 void *cbdata = _callback.callback_data;
160 _callback = Callback(NULL, NULL);
161 copyInto.data = NULL;
62e76326 162
528b2c61 163 if (cbdataReferenceValid(cbdata))
62e76326 164 temphandler(cbdata, result);
165
528b2c61 166 cbdataReferenceDone(cbdata);
b04e66e0 167}
168
f115fadd 169static void
170storeClientCopyEvent(void *data)
171{
e6ccf245 172 store_client *sc = (store_client *)data;
2f44bd34 173 debug(90, 3)("storeClientCopyEvent: Running\n");
528b2c61 174 assert (sc->flags.copy_event_pending);
67fd69de 175 sc->flags.copy_event_pending = 0;
62e76326 176
90703668 177 if (!sc->_callback.pending())
62e76326 178 return;
179
f115fadd 180 storeClientCopy2(sc->entry, sc);
f115fadd 181}
182
b67e2c8c 183store_client::store_client(StoreEntry *e) : entry (e)
184#if DELAY_POOLS
62e76326 185 , delayId()
b67e2c8c 186#endif
62e76326 187 , type (e->storeClientType())
188 , object_ok(true)
528b2c61 189{
190 cmp_offset = 0;
191 flags.disk_io_pending = 0;
192 entry->refcount++;
62e76326 193
528b2c61 194 if (getType() == STORE_DISK_CLIENT)
62e76326 195 /* assert we'll be able to get the data we want */
196 /* maybe we should open swapin_fd here */
c07cbbf4 197 assert(entry->swap_filen > -1 || entry->swapOutAble());
62e76326 198
528b2c61 199#if STORE_CLIENT_LIST_DEBUG
62e76326 200
528b2c61 201 owner = cbdataReference(data);
62e76326 202
528b2c61 203#endif
204}
205
2f44bd34 206store_client::~store_client()
62e76326 207{}
2f44bd34 208
f09f5b26 209/* copy bytes requested by the client */
210void
a4b8110e 211storeClientCopy(store_client * sc,
62e76326 212 StoreEntry * e,
213 StoreIOBuffer copyInto,
214 STCB * callback,
215 void *data)
f09f5b26 216{
528b2c61 217 assert (sc != NULL);
218 sc->copy(e, copyInto,callback,data);
219}
220
221void
222store_client::copy(StoreEntry * anEntry,
62e76326 223 StoreIOBuffer copyRequest,
224 STCB * callback_fn,
225 void *data)
528b2c61 226{
227 assert (anEntry == entry);
228 assert (callback_fn);
229 assert (data);
230 assert(!EBIT_TEST(entry->flags, ENTRY_ABORTED));
b2cc18b9 231 debug(90, 3)("store_client::copy: %s, from %lu, for length %d, cb %p, cbdata %p\n",
62e76326 232 entry->getMD5Text(),
233 (unsigned long) copyRequest.offset,
234 (int) copyRequest.length,
235 callback_fn,
236 data);
06d2839d 237#if STORE_CLIENT_LIST_DEBUG
62e76326 238
528b2c61 239 assert(this == storeClientListSearch(entry->mem_obj, data));
06d2839d 240#endif
62e76326 241
90703668 242 assert(!_callback.pending());
528b2c61 243#if ONLYCONTIGUOUSREQUESTS
62e76326 244
528b2c61 245 assert(cmp_offset == copyRequest.offset);
246#endif
247 /* range requests will skip into the body */
248 cmp_offset = copyRequest.offset;
249 _callback = Callback (callback_fn, cbdataReference(data));
250 copyInto.data = copyRequest.data;
251 copyInto.length = copyRequest.length;
252 copyInto.offset = copyRequest.offset;
253
1d5161bd 254 static bool copying (false);
255 assert (!copying);
256 copying = true;
257 PROF_start(storeClient_kickReads);
a46d2c0e 258 /* we might be blocking comm reads due to readahead limits
259 * now we have a new offset, trigger those reads...
260 */
261 entry->mem_obj->kickReads();
1d5161bd 262 PROF_stop(storeClient_kickReads);
263 copying = false;
a46d2c0e 264
528b2c61 265 storeClientCopy2(entry, this);
f09f5b26 266}
267
07304bf9 268/*
269 * This function is used below to decide if we have any more data to
0bb129ee 270 * send to the client. If the store_status is STORE_PENDING, then we
b7fe0ab0 271 * do have more data to send. If its STORE_OK, then
0bb129ee 272 * we continue checking. If the object length is negative, then we
273 * don't know the real length and must open the swap file to find out.
274 * If the length is >= 0, then we compare it to the requested copy
275 * offset.
07304bf9 276 */
277static int
278storeClientNoMoreToSend(StoreEntry * e, store_client * sc)
279{
280 ssize_t len;
62e76326 281
0bb129ee 282 if (e->store_status == STORE_PENDING)
62e76326 283 return 0;
284
707fdc47 285 if ((len = e->objectLen()) < 0)
62e76326 286 return 0;
287
c8be6d7b 288 if (sc->copyInto.offset < len)
62e76326 289 return 0;
290
07304bf9 291 return 1;
292}
293
f09f5b26 294static void
295storeClientCopy2(StoreEntry * e, store_client * sc)
296{
528b2c61 297 /* reentrancy not allowed - note this could lead to
298 * dropped events
299 */
62e76326 300
fa80a8ef 301 if (sc->flags.copy_event_pending) {
62e76326 302 return;
fa80a8ef 303 }
62e76326 304
db1cd23c 305 if (EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
62e76326 306 debug(90, 5)("storeClientCopy2: returning because ENTRY_FWD_HDR_WAIT set\n");
307 return;
db1cd23c 308 }
62e76326 309
67fd69de 310 if (sc->flags.store_copying) {
62e76326 311 sc->flags.copy_event_pending = 1;
312 debug(90, 3)("storeClientCopy2: Queueing storeClientCopyEvent()\n");
313 eventAdd("storeClientCopyEvent", storeClientCopyEvent, sc, 0.0, 0);
314 return;
67fd69de 315 }
62e76326 316
2f44bd34 317 debug(90, 3)("storeClientCopy2: %s\n", e->getMD5Text());
90703668 318 assert(sc->_callback.pending());
0bb129ee 319 /*
b7fe0ab0 320 * We used to check for ENTRY_ABORTED here. But there were some
0bb129ee 321 * problems. For example, we might have a slow client (or two) and
322 * the server-side is reading far ahead and swapping to disk. Even
323 * if the server-side aborts, we want to give the client(s)
324 * everything we got before the abort condition occurred.
325 */
528b2c61 326 /* Warning: doCopy may indirectly free itself in callbacks,
7e6b941f 327 * hence the lock to keep it active for the duration of
fa80a8ef 328 * this function
329 */
7e6b941f 330 cbdataInternalLock(sc);
528b2c61 331 assert (sc->flags.store_copying == 0);
332 sc->doCopy(e);
333 assert (sc->flags.store_copying == 0);
7e6b941f 334 cbdataInternalUnlock(sc);
cfac48c2 335}
336
528b2c61 337void
338store_client::doCopy(StoreEntry *anEntry)
cfac48c2 339{
528b2c61 340 assert (anEntry == entry);
341 flags.store_copying = 1;
342 MemObject *mem = entry->mem_obj;
cd748f27 343
528b2c61 344 debug(33, 5)("store_client::doCopy: co: %lu, hi: %ld\n", (unsigned long) copyInto.offset, (long int) mem->endOffset());
add2192d 345
528b2c61 346 if (storeClientNoMoreToSend(entry, this)) {
62e76326 347 /* There is no more to send! */
348 callback(0);
349 flags.store_copying = 0;
350 return;
cfac48c2 351 }
62e76326 352
add2192d 353 /* Check that we actually have data */
528b2c61 354 if (anEntry->store_status == STORE_PENDING && copyInto.offset >= mem->endOffset()) {
62e76326 355 debug(90, 3)("store_client::doCopy: Waiting for more\n");
356 flags.store_copying = 0;
357 return;
cfac48c2 358 }
62e76326 359
cfac48c2 360 /*
361 * Slight weirdness here. We open a swapin file for any
362 * STORE_DISK_CLIENT, even if we can copy the requested chunk
363 * from memory in the next block. We must try to open the
364 * swapin file before sending any data to the client side. If
365 * we postpone the open, and then can not open the file later
366 * on, the client loses big time. Its transfer just gets cut
367 * off. Better to open it early (while the client side handler
368 * is clientCacheHit) so that we can fall back to a cache miss
369 * if needed.
370 */
fa80a8ef 371
4e70dae3 372 if (STORE_DISK_CLIENT == getType() && NULL == swapin_sio.getRaw())
373 startSwapin();
374 else
375 scheduleRead();
376}
377
378void
379store_client::startSwapin()
380{
381 debug(90, 3)("store_client::doCopy: Need to open swap in file\n");
382 /* gotta open the swapin file */
383
384 if (storeTooManyDiskFilesOpen()) {
385 /* yuck -- this causes a TCP_SWAPFAIL_MISS on the client side */
386 fail();
387 flags.store_copying = 0;
388 return;
389 } else if (!flags.disk_io_pending) {
390 /* Don't set store_io_pending here */
391 storeSwapInStart(this);
62e76326 392
4e70dae3 393 if (NULL == swapin_sio.getRaw()) {
62e76326 394 fail();
395 flags.store_copying = 0;
396 return;
62e76326 397 }
62e76326 398
4e70dae3 399 /*
400 * If the open succeeds we either copy from memory, or
401 * schedule a disk read in the next block.
402 */
403 scheduleRead();
404
405 return;
406 } else {
407 debug (90, 1)("WARNING: Averted multiple fd operation (1)\n");
62e76326 408 flags.store_copying = 0;
409 return;
cfac48c2 410 }
4e70dae3 411}
62e76326 412
4e70dae3 413void
414store_client::scheduleRead()
415{
416 MemObject *mem = entry->mem_obj;
417
418 if (copyInto.offset >= mem->inmem_lo && copyInto.offset < mem->endOffset())
419 scheduleMemRead();
420 else
421 scheduleDiskRead();
422}
423
424void
425store_client::scheduleDiskRead()
426{
cd748f27 427 /* What the client wants is not in memory. Schedule a disk read */
528b2c61 428 assert(STORE_DISK_CLIENT == getType());
62e76326 429
528b2c61 430 assert(!flags.disk_io_pending);
62e76326 431
2f44bd34 432 debug(90, 3)("store_client::doCopy: reading from STORE\n");
62e76326 433
528b2c61 434 fileRead();
62e76326 435
528b2c61 436 flags.store_copying = 0;
f09f5b26 437}
438
4e70dae3 439void
440store_client::scheduleMemRead()
441{
442 /* What the client wants is in memory */
443 /* Old style */
444 debug(90, 3)("store_client::doCopy: Copying normal from memory\n");
90703668 445 size_t sz = entry->mem_obj->data_hdr.copy(copyInto);
4e70dae3 446 callback(sz);
447 flags.store_copying = 0;
448}
449
528b2c61 450void
451store_client::fileRead()
f09f5b26 452{
528b2c61 453 MemObject *mem = entry->mem_obj;
454
90703668 455 assert(_callback.pending());
528b2c61 456 assert(!flags.disk_io_pending);
457 flags.disk_io_pending = 1;
62e76326 458
528b2c61 459 if (mem->swap_hdr_sz != 0)
62e76326 460 if (entry->swap_status == SWAPOUT_WRITING)
461 assert(mem->swapout.sio->offset() > copyInto.offset + (off_t)mem->swap_hdr_sz);
462
528b2c61 463 storeRead(swapin_sio,
62e76326 464 copyInto.data,
465 copyInto.length,
466 copyInto.offset + mem->swap_hdr_sz,
467 mem->swap_hdr_sz == 0 ? storeClientReadHeader
468 : storeClientReadBody,
469 this);
f09f5b26 470}
471
472static void
e5de8b13 473storeClientReadBody(void *data, const char *buf, ssize_t len, StoreIOState::Pointer self)
f09f5b26 474{
e6ccf245 475 store_client *sc = (store_client *)data;
27002b34 476 assert(sc->flags.disk_io_pending);
f115fadd 477 sc->flags.disk_io_pending = 0;
90703668 478 assert(sc->_callback.pending());
2f44bd34 479 debug(90, 3)("storeClientReadBody: len %d", (int) len);
62e76326 480
06a5ae20 481 if (sc->copyInto.offset == 0 && len > 0 && sc->entry->getReply()->sline.status == 0) {
62e76326 482 /* Our structure ! */
06a5ae20 483 HttpReply *rep = (HttpReply *) sc->entry->getReply(); // bypass const
484
59eed7dc 485 if (!rep->parseCharBuf(sc->copyInto.data, headersEnd(sc->copyInto.data, len))) {
62e76326 486 debug (90,0)("Could not parse headers from on disk object\n");
487 }
06a5ae20 488 }
62e76326 489
528b2c61 490 sc->callback(len);
491}
492
493void
62e76326 494store_client::fail()
528b2c61 495{
496 object_ok = false;
db2ff94c 497 /* synchronous open failures callback from the store,
498 * before startSwapin detects the failure.
499 * TODO: fix this inconsistent behaviour - probably by
500 * having storeSwapInStart become a callback functions,
501 * not synchronous
502 */
503
90703668 504 if (_callback.pending())
db2ff94c 505 callback(0, true);
f09f5b26 506}
507
e3ef2b09 508static void
e5de8b13 509storeClientReadHeader(void *data, const char *buf, ssize_t len, StoreIOState::Pointer self)
e3ef2b09 510{
e6ccf245 511 store_client *sc = (store_client *)data;
528b2c61 512 sc->readHeader(buf, len);
513}
514
515void
516store_client::unpackHeader(char const *buf, ssize_t len)
517{
2f44bd34 518 debug(90, 3)("store_client::unpackHeader: len %d", (int) len);
62e76326 519
e3ef2b09 520 if (len < 0) {
62e76326 521 debug(90, 3)("store_client::unpackHeader: %s", xstrerror());
522 fail();
523 return;
e3ef2b09 524 }
62e76326 525
528b2c61 526 int swap_hdr_sz = 0;
527 StoreMetaUnpacker aBuilder(buf, len, &swap_hdr_sz);
62e76326 528
528b2c61 529 if (!aBuilder.isBufferSane()) {
62e76326 530 /* oops, bad disk file? */
531 debug(90, 1) ("WARNING: swapfile header inconsistent with available data\n");
532 fail();
533 return;
9bc73deb 534 }
62e76326 535
528b2c61 536 tlv *tlv_list = aBuilder.createStoreMeta ();
62e76326 537
e3ef2b09 538 if (tlv_list == NULL) {
62e76326 539 debug(90, 1) ("WARNING: failed to unpack meta data\n");
540 fail();
541 return;
e3ef2b09 542 }
62e76326 543
e3ef2b09 544 /*
7e3ce7b9 545 * Check the meta data and make sure we got the right object.
e3ef2b09 546 */
528b2c61 547 for (tlv *t = tlv_list; t; t = t->next) {
62e76326 548 if (!t->checkConsistency(entry)) {
549 storeSwapTLVFree(tlv_list);
550 fail();
551 return;
552 }
7e3ce7b9 553 }
62e76326 554
07304bf9 555 storeSwapTLVFree(tlv_list);
528b2c61 556
557 entry->mem_obj->swap_hdr_sz = swap_hdr_sz;
558 entry->mem_obj->object_sz = entry->swap_file_sz - swap_hdr_sz;
559
560}
561
562void
563store_client::readHeader(char const *buf, ssize_t len)
564{
565 MemObject *const mem = entry->mem_obj;
62e76326 566
528b2c61 567 assert(flags.disk_io_pending);
568 flags.disk_io_pending = 0;
90703668 569 assert(_callback.pending());
528b2c61 570
571 unpackHeader (buf, len);
62e76326 572
528b2c61 573 if (!object_ok)
62e76326 574 return;
575
e3ef2b09 576 /*
577 * If our last read got some data the client wants, then give
578 * it to them, otherwise schedule another read.
579 */
528b2c61 580 size_t body_sz = len - mem->swap_hdr_sz;
62e76326 581
528b2c61 582 if (static_cast<size_t>(copyInto.offset) < body_sz) {
62e76326 583 /*
584 * we have (part of) what they want
585 */
586 size_t copy_sz = XMIN(copyInto.length, body_sz)
587 ;
588 debug(90, 3) ("storeClientReadHeader: copying %d bytes of body\n",
589 (int) copy_sz);
590 xmemmove(copyInto.data, copyInto.data + mem->swap_hdr_sz, copy_sz);
591
06a5ae20 592 if (copyInto.offset == 0 && len > 0 && entry->getReply()->sline.status == 0) {
62e76326 593 /* Our structure ! */
06a5ae20 594 HttpReply *rep = (HttpReply *) entry->getReply(); // bypass const
595
59eed7dc 596 if (!rep->parseCharBuf(copyInto.data, headersEnd(copyInto.data, copy_sz))) {
62e76326 597 debug (90,0)("could not parse headers from on disk structure!\n");
598 }
06a5ae20 599 }
528b2c61 600
601 callback(copy_sz);
62e76326 602 return;
e3ef2b09 603 }
62e76326 604
e3ef2b09 605 /*
606 * we don't have what the client wants, but at least we now
607 * know the swap header size.
608 */
528b2c61 609 fileRead();
e3ef2b09 610}
611
f09f5b26 612int
a4b8110e 613storeClientCopyPending(store_client * sc, StoreEntry * e, void *data)
f09f5b26 614{
06d2839d 615#if STORE_CLIENT_LIST_DEBUG
616 assert(sc == storeClientListSearch(e->mem_obj, data));
edce4d98 617#endif
618#ifndef SILLY_CODE
62e76326 619
edce4d98 620 assert(sc);
06d2839d 621#endif
62e76326 622
06d2839d 623 assert(sc->entry == e);
edce4d98 624#if SILLY_CODE
62e76326 625
f09f5b26 626 if (sc == NULL)
62e76326 627 return 0;
628
edce4d98 629#endif
62e76326 630
90703668 631 if (!sc->_callback.pending())
62e76326 632 return 0;
633
f09f5b26 634 return 1;
635}
636
06d2839d 637/*
638 * This routine hasn't been optimised to take advantage of the
639 * passed sc. Yet.
640 */
f09f5b26 641int
a4b8110e 642storeUnregister(store_client * sc, StoreEntry * e, void *data)
f09f5b26 643{
644 MemObject *mem = e->mem_obj;
06d2839d 645#if STORE_CLIENT_LIST_DEBUG
62e76326 646
06d2839d 647 assert(sc == storeClientListSearch(e->mem_obj, data));
648#endif
62e76326 649
f09f5b26 650 if (mem == NULL)
62e76326 651 return 0;
652
2f44bd34 653 debug(90, 3) ("storeUnregister: called for '%s'\n", e->getMD5Text());
62e76326 654
2f44bd34 655 if (sc == NULL) {
62e76326 656 debug(90, 3) ("storeUnregister: No matching client for '%s'\n", e->getMD5Text());
657 return 0;
2f44bd34 658 }
62e76326 659
0e3f3e0d 660 if (mem->clientCount() == 0) {
62e76326 661 debug(90, 3) ("storeUnregister: Consistency failure - store client being unregistered is not in the mem object's list for '%s'\n", e->getMD5Text());
662 return 0;
2f44bd34 663 }
62e76326 664
06d2839d 665 dlinkDelete(&sc->node, &mem->clients);
f09f5b26 666 mem->nclients--;
62e76326 667
f09f5b26 668 if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE)
c07cbbf4 669 e->swapOut();
62e76326 670
d3b3ab85 671 if (sc->swapin_sio.getRaw()) {
62e76326 672 storeClose(sc->swapin_sio);
673 sc->swapin_sio = NULL;
674 statCounter.swap.ins++;
eb824054 675 }
62e76326 676
90703668 677 if (sc->_callback.pending()) {
62e76326 678 /* callback with ssize = -1 to indicate unexpected termination */
679 debug(90, 3) ("storeUnregister: store_client for %s has a callback\n",
680 mem->url);
681 sc->fail();
f09f5b26 682 }
62e76326 683
fa80a8ef 684#if STORE_CLIENT_LIST_DEBUG
685 cbdataReferenceDone(sc->owner);
62e76326 686
fa80a8ef 687#endif
62e76326 688
528b2c61 689 delete sc;
62e76326 690
77b32a34 691 assert(e->lock_count > 0);
62e76326 692
77b32a34 693 if (mem->nclients == 0)
62e76326 694 CheckQuickAbort(e);
a46d2c0e 695 else
696 mem->kickReads();
62e76326 697
f09f5b26 698 return 1;
699}
700
f09f5b26 701/* Call handlers waiting for data to be appended to E. */
702void
703InvokeHandlers(StoreEntry * e)
704{
528b2c61 705 /* Commit what we can to disk, if appropriate */
c07cbbf4 706 e->swapOut();
f09f5b26 707 int i = 0;
708 MemObject *mem = e->mem_obj;
709 store_client *sc;
06d2839d 710 dlink_node *nx = NULL;
711 dlink_node *node;
712
9ea37c79 713 PROF_start(InvokeHandlers);
714
2f44bd34 715 debug(90, 3) ("InvokeHandlers: %s\n", e->getMD5Text());
f09f5b26 716 /* walk the entire list looking for valid callbacks */
62e76326 717
06d2839d 718 for (node = mem->clients.head; node; node = nx) {
62e76326 719 sc = (store_client *)node->data;
720 nx = node->next;
721 debug(90, 3) ("InvokeHandlers: checking client #%d\n", i++);
722
90703668 723 if (!sc->_callback.pending())
62e76326 724 continue;
725
726 if (sc->flags.disk_io_pending)
727 continue;
728
729 storeClientCopy2(e, sc);
f09f5b26 730 }
9ea37c79 731 PROF_stop(InvokeHandlers);
f09f5b26 732}
733
734int
735storePendingNClients(const StoreEntry * e)
736{
f09f5b26 737 MemObject *mem = e->mem_obj;
36547bcf 738 int npend = NULL == mem ? 0 : mem->nclients;
2f44bd34 739 debug(90, 3) ("storePendingNClients: returning %d\n", npend);
f09f5b26 740 return npend;
741}
77b32a34 742
743/* return 1 if the request should be aborted */
744static int
745CheckQuickAbort2(StoreEntry * entry)
746{
528b2c61 747 MemObject * const mem = entry->mem_obj;
77b32a34 748 assert(mem);
2f44bd34 749 debug(90, 3) ("CheckQuickAbort2: entry=%p, mem=%p\n", entry, mem);
62e76326 750
0e5bd28f 751 if (mem->request && !mem->request->flags.cachable) {
62e76326 752 debug(90, 3) ("CheckQuickAbort2: YES !mem->request->flags.cachable\n");
753 return 1;
77b32a34 754 }
62e76326 755
77b32a34 756 if (EBIT_TEST(entry->flags, KEY_PRIVATE)) {
62e76326 757 debug(90, 3) ("CheckQuickAbort2: YES KEY_PRIVATE\n");
758 return 1;
77b32a34 759 }
62e76326 760
90703668 761 size_t expectlen = entry->getReply()->content_length + entry->getReply()->hdr_sz;
0e3f3e0d 762
763 if (expectlen < 0)
764 /* expectlen is < 0 if *no* information about the object has been recieved */
765 return 1;
766
90703668 767 size_t curlen = (size_t) mem->endOffset ();
0e3f3e0d 768
90703668 769 size_t minlen = (size_t) Config.quickAbort.min << 10;
62e76326 770
77b32a34 771 if (minlen < 0) {
62e76326 772 debug(90, 3) ("CheckQuickAbort2: NO disabled\n");
773 return 0;
77b32a34 774 }
62e76326 775
77b32a34 776 if (curlen > expectlen) {
62e76326 777 debug(90, 3) ("CheckQuickAbort2: YES bad content length\n");
778 return 1;
77b32a34 779 }
62e76326 780
77b32a34 781 if ((expectlen - curlen) < minlen) {
62e76326 782 debug(90, 3) ("CheckQuickAbort2: NO only little more left\n");
783 return 0;
77b32a34 784 }
62e76326 785
77b32a34 786 if ((expectlen - curlen) > (Config.quickAbort.max << 10)) {
62e76326 787 debug(90, 3) ("CheckQuickAbort2: YES too much left to go\n");
788 return 1;
77b32a34 789 }
62e76326 790
77b32a34 791 if (expectlen < 100) {
62e76326 792 debug(90, 3) ("CheckQuickAbort2: NO avoid FPE\n");
793 return 0;
77b32a34 794 }
62e76326 795
e6ccf245 796 if ((curlen / (expectlen / 100)) > (size_t)Config.quickAbort.pct) {
62e76326 797 debug(90, 3) ("CheckQuickAbort2: NO past point of no return\n");
798 return 0;
77b32a34 799 }
62e76326 800
2f44bd34 801 debug(90, 3) ("CheckQuickAbort2: YES default, returning 1\n");
77b32a34 802 return 1;
803}
804
805static void
806CheckQuickAbort(StoreEntry * entry)
807{
528b2c61 808 assert (entry);
62e76326 809
77b32a34 810 if (storePendingNClients(entry) > 0)
62e76326 811 return;
812
77b32a34 813 if (entry->store_status != STORE_PENDING)
62e76326 814 return;
815
986ebffc 816 if (EBIT_TEST(entry->flags, ENTRY_SPECIAL))
62e76326 817 return;
818
77b32a34 819 if (CheckQuickAbort2(entry) == 0)
62e76326 820 return;
821
7197b20d 822 storeAbort(entry);
77b32a34 823}
c8be6d7b 824
825void
fcc35180 826store_client::dumpStats(MemBuf * output, int clientNumber) const
c8be6d7b 827{
90703668 828 if (_callback.pending())
62e76326 829 return;
830
2fe7eff9 831 output->Printf("\tClient #%d, %p\n", clientNumber, _callback.callback_data);
62e76326 832
2fe7eff9 833 output->Printf("\t\tcopy_offset: %lu\n",
834 (unsigned long) copyInto.offset);
62e76326 835
2fe7eff9 836 output->Printf("\t\tcopy_size: %d\n",
837 (int) copyInto.length);
62e76326 838
2fe7eff9 839 output->Printf("\t\tflags:");
62e76326 840
528b2c61 841 if (flags.disk_io_pending)
2fe7eff9 842 output->Printf(" disk_io_pending");
62e76326 843
528b2c61 844 if (flags.store_copying)
2fe7eff9 845 output->Printf(" store_copying");
62e76326 846
528b2c61 847 if (flags.copy_event_pending)
2fe7eff9 848 output->Printf(" copy_event_pending");
62e76326 849
2fe7eff9 850 output->Printf("\n");
528b2c61 851}
c8be6d7b 852
528b2c61 853bool
90703668 854store_client::Callback::pending() const
528b2c61 855{
90703668 856 return callback_handler && callback_data;
c8be6d7b 857}
528b2c61 858
859store_client::Callback::Callback(STCB *function, void *data) : callback_handler(function), callback_data (data) {}
b67e2c8c 860
515ec4dc 861#if DELAY_POOLS
b67e2c8c 862void
863store_client::setDelayId(DelayId delay_id)
864{
865 delayId = delay_id;
866}
62e76326 867
515ec4dc 868#endif