]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_client.cc
SourceFormat: enforcement
[thirdparty/squid.git] / src / store_client.cc
CommitLineData
9cef6668 1
2/*
262a0e14 3 * $Id$
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.
26ac0430 24 *
9cef6668 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.
26ac0430 29 *
9cef6668 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
47f6e231 84store_client::memReaderHasLowerOffset(int64_t anOffset) const
528b2c61 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{
967a359a 146 StoreIOBuffer result(sz, 0 ,copyInto.data);
62e76326 147
964ae882 148 if (sz < 0) {
62e76326 149 result.flags.error = 1;
964ae882
AJ
150 result.length = 0;
151 } else {
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;
bf8fe701 173 debugs(90, 3, "storeClientCopyEvent: Running");
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 */
02a2d80b 196 /* maybe we should open swapin_sio 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));
bf8fe701 231 debugs(90, 3, "store_client::copy: " << entry->getMD5Text() << ", from " <<
47f6e231 232 copyRequest.offset << ", for length " <<
bf8fe701 233 (int) copyRequest.length << ", cb " << callback_fn << ", cbdata " <<
234 data);
235
06d2839d 236#if STORE_CLIENT_LIST_DEBUG
62e76326 237
528b2c61 238 assert(this == storeClientListSearch(entry->mem_obj, data));
06d2839d 239#endif
62e76326 240
90703668 241 assert(!_callback.pending());
528b2c61 242#if ONLYCONTIGUOUSREQUESTS
62e76326 243
528b2c61 244 assert(cmp_offset == copyRequest.offset);
245#endif
246 /* range requests will skip into the body */
247 cmp_offset = copyRequest.offset;
248 _callback = Callback (callback_fn, cbdataReference(data));
249 copyInto.data = copyRequest.data;
250 copyInto.length = copyRequest.length;
251 copyInto.offset = copyRequest.offset;
252
1d5161bd 253 static bool copying (false);
254 assert (!copying);
255 copying = true;
256 PROF_start(storeClient_kickReads);
a46d2c0e 257 /* we might be blocking comm reads due to readahead limits
258 * now we have a new offset, trigger those reads...
259 */
260 entry->mem_obj->kickReads();
1d5161bd 261 PROF_stop(storeClient_kickReads);
262 copying = false;
a46d2c0e 263
528b2c61 264 storeClientCopy2(entry, this);
f09f5b26 265}
266
07304bf9 267/*
268 * This function is used below to decide if we have any more data to
0bb129ee 269 * send to the client. If the store_status is STORE_PENDING, then we
b7fe0ab0 270 * do have more data to send. If its STORE_OK, then
0bb129ee 271 * we continue checking. If the object length is negative, then we
272 * don't know the real length and must open the swap file to find out.
273 * If the length is >= 0, then we compare it to the requested copy
274 * offset.
07304bf9 275 */
276static int
277storeClientNoMoreToSend(StoreEntry * e, store_client * sc)
278{
47f6e231 279 int64_t len;
62e76326 280
0bb129ee 281 if (e->store_status == STORE_PENDING)
62e76326 282 return 0;
283
707fdc47 284 if ((len = e->objectLen()) < 0)
62e76326 285 return 0;
286
c8be6d7b 287 if (sc->copyInto.offset < len)
62e76326 288 return 0;
289
07304bf9 290 return 1;
291}
292
f09f5b26 293static void
294storeClientCopy2(StoreEntry * e, store_client * sc)
295{
528b2c61 296 /* reentrancy not allowed - note this could lead to
297 * dropped events
298 */
62e76326 299
fa80a8ef 300 if (sc->flags.copy_event_pending) {
62e76326 301 return;
fa80a8ef 302 }
62e76326 303
db1cd23c 304 if (EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
bf8fe701 305 debugs(90, 5, "storeClientCopy2: returning because ENTRY_FWD_HDR_WAIT set");
62e76326 306 return;
db1cd23c 307 }
62e76326 308
67fd69de 309 if (sc->flags.store_copying) {
62e76326 310 sc->flags.copy_event_pending = 1;
bf8fe701 311 debugs(90, 3, "storeClientCopy2: Queueing storeClientCopyEvent()");
62e76326 312 eventAdd("storeClientCopyEvent", storeClientCopyEvent, sc, 0.0, 0);
313 return;
67fd69de 314 }
62e76326 315
bf8fe701 316 debugs(90, 3, "storeClientCopy2: " << e->getMD5Text());
90703668 317 assert(sc->_callback.pending());
0bb129ee 318 /*
b7fe0ab0 319 * We used to check for ENTRY_ABORTED here. But there were some
0bb129ee 320 * problems. For example, we might have a slow client (or two) and
321 * the server-side is reading far ahead and swapping to disk. Even
322 * if the server-side aborts, we want to give the client(s)
323 * everything we got before the abort condition occurred.
324 */
528b2c61 325 /* Warning: doCopy may indirectly free itself in callbacks,
7e6b941f 326 * hence the lock to keep it active for the duration of
fa80a8ef 327 * this function
328 */
7e6b941f 329 cbdataInternalLock(sc);
528b2c61 330 assert (sc->flags.store_copying == 0);
331 sc->doCopy(e);
332 assert (sc->flags.store_copying == 0);
7e6b941f 333 cbdataInternalUnlock(sc);
cfac48c2 334}
335
528b2c61 336void
337store_client::doCopy(StoreEntry *anEntry)
cfac48c2 338{
528b2c61 339 assert (anEntry == entry);
340 flags.store_copying = 1;
341 MemObject *mem = entry->mem_obj;
cd748f27 342
bf8fe701 343 debugs(33, 5, "store_client::doCopy: co: " <<
47f6e231 344 copyInto.offset << ", hi: " <<
345 mem->endOffset());
add2192d 346
528b2c61 347 if (storeClientNoMoreToSend(entry, this)) {
62e76326 348 /* There is no more to send! */
26ac0430 349 debugs(33, 3, HERE << "There is no more to send!");
62e76326 350 callback(0);
351 flags.store_copying = 0;
352 return;
cfac48c2 353 }
62e76326 354
add2192d 355 /* Check that we actually have data */
528b2c61 356 if (anEntry->store_status == STORE_PENDING && copyInto.offset >= mem->endOffset()) {
bf8fe701 357 debugs(90, 3, "store_client::doCopy: Waiting for more");
62e76326 358 flags.store_copying = 0;
359 return;
cfac48c2 360 }
62e76326 361
cfac48c2 362 /*
363 * Slight weirdness here. We open a swapin file for any
364 * STORE_DISK_CLIENT, even if we can copy the requested chunk
365 * from memory in the next block. We must try to open the
366 * swapin file before sending any data to the client side. If
367 * we postpone the open, and then can not open the file later
368 * on, the client loses big time. Its transfer just gets cut
369 * off. Better to open it early (while the client side handler
370 * is clientCacheHit) so that we can fall back to a cache miss
371 * if needed.
372 */
fa80a8ef 373
85a4b153 374 if (STORE_DISK_CLIENT == getType() && swapin_sio == NULL)
4e70dae3 375 startSwapin();
376 else
377 scheduleRead();
378}
379
380void
381store_client::startSwapin()
382{
bf8fe701 383 debugs(90, 3, "store_client::doCopy: Need to open swap in file");
4e70dae3 384 /* gotta open the swapin file */
385
386 if (storeTooManyDiskFilesOpen()) {
387 /* yuck -- this causes a TCP_SWAPFAIL_MISS on the client side */
388 fail();
389 flags.store_copying = 0;
390 return;
391 } else if (!flags.disk_io_pending) {
392 /* Don't set store_io_pending here */
393 storeSwapInStart(this);
62e76326 394
85a4b153 395 if (swapin_sio == NULL) {
62e76326 396 fail();
397 flags.store_copying = 0;
398 return;
62e76326 399 }
62e76326 400
4e70dae3 401 /*
402 * If the open succeeds we either copy from memory, or
403 * schedule a disk read in the next block.
404 */
405 scheduleRead();
406
407 return;
408 } else {
bf8fe701 409 debugs(90, 1, "WARNING: Averted multiple fd operation (1)");
62e76326 410 flags.store_copying = 0;
411 return;
cfac48c2 412 }
4e70dae3 413}
62e76326 414
4e70dae3 415void
416store_client::scheduleRead()
417{
418 MemObject *mem = entry->mem_obj;
419
420 if (copyInto.offset >= mem->inmem_lo && copyInto.offset < mem->endOffset())
421 scheduleMemRead();
422 else
423 scheduleDiskRead();
424}
425
426void
427store_client::scheduleDiskRead()
428{
cd748f27 429 /* What the client wants is not in memory. Schedule a disk read */
528b2c61 430 assert(STORE_DISK_CLIENT == getType());
62e76326 431
528b2c61 432 assert(!flags.disk_io_pending);
62e76326 433
bf8fe701 434 debugs(90, 3, "store_client::doCopy: reading from STORE");
62e76326 435
528b2c61 436 fileRead();
62e76326 437
528b2c61 438 flags.store_copying = 0;
f09f5b26 439}
440
4e70dae3 441void
442store_client::scheduleMemRead()
443{
444 /* What the client wants is in memory */
445 /* Old style */
bf8fe701 446 debugs(90, 3, "store_client::doCopy: Copying normal from memory");
90703668 447 size_t sz = entry->mem_obj->data_hdr.copy(copyInto);
4e70dae3 448 callback(sz);
449 flags.store_copying = 0;
450}
451
528b2c61 452void
453store_client::fileRead()
f09f5b26 454{
528b2c61 455 MemObject *mem = entry->mem_obj;
456
90703668 457 assert(_callback.pending());
528b2c61 458 assert(!flags.disk_io_pending);
459 flags.disk_io_pending = 1;
62e76326 460
528b2c61 461 if (mem->swap_hdr_sz != 0)
62e76326 462 if (entry->swap_status == SWAPOUT_WRITING)
47f6e231 463 assert(mem->swapout.sio->offset() > copyInto.offset + (int64_t)mem->swap_hdr_sz);
62e76326 464
528b2c61 465 storeRead(swapin_sio,
62e76326 466 copyInto.data,
467 copyInto.length,
468 copyInto.offset + mem->swap_hdr_sz,
469 mem->swap_hdr_sz == 0 ? storeClientReadHeader
470 : storeClientReadBody,
471 this);
f09f5b26 472}
473
474static void
beae59b0 475storeClientMemWriteComplete(void *data, StoreIOBuffer wroteBuffer)
f09f5b26 476{
e1381638 477 // Nothin to do here but callback is needed
beae59b0
HN
478}
479
480void
481store_client::readBody(const char *buf, ssize_t len)
482{
483 int parsed_header = 0;
484
485 // Don't assert disk_io_pending here.. may be called by read_header
486 flags.disk_io_pending = 0;
487 assert(_callback.pending());
4a7a3d56 488 debugs(90, 3, "storeClientReadBody: len " << len << "");
62e76326 489
beae59b0 490 if (copyInto.offset == 0 && len > 0 && entry->getReply()->sline.status == 0) {
62e76326 491 /* Our structure ! */
beae59b0 492 HttpReply *rep = (HttpReply *) entry->getReply(); // bypass const
06a5ae20 493
beae59b0 494 if (!rep->parseCharBuf(copyInto.data, headersEnd(copyInto.data, len))) {
bf8fe701 495 debugs(90, 0, "Could not parse headers from on disk object");
beae59b0 496 } else {
3196f526
HN
497 parsed_header = 1;
498 }
06a5ae20 499 }
62e76326 500
beae59b0 501 const HttpReply *rep = entry->getReply();
ff4b33f4 502 if (len > 0 && rep && entry->mem_obj->inmem_lo == 0 && entry->objectLen() <= (int64_t)Config.Store.maxInMemObjSize && Config.onoff.memory_cache_disk) {
6d3c2758
HN
503 storeGetMemSpace(len);
504 // The above may start to free our object so we need to check again
505 if (entry->mem_obj->inmem_lo == 0) {
506 /* Copy read data back into memory.
507 * but first we need to adjust offset.. some parts of the code
508 * counts offset including headers, some parts count offset as
509 * withing the body.. copyInto is including headers, but the mem
510 * cache expects offset without headers (using negative for headers)
511 * eventually not storing packed headers in memory at all.
512 */
619da1e9 513 int64_t mem_offset = entry->mem_obj->endOffset();
6d3c2758
HN
514 if ((copyInto.offset == mem_offset) || (parsed_header && mem_offset == rep->hdr_sz)) {
515 entry->mem_obj->write(StoreIOBuffer(len, copyInto.offset - rep->hdr_sz, copyInto.data), storeClientMemWriteComplete, this);
516 }
3196f526 517 }
beae59b0
HN
518 }
519
520 callback(len);
528b2c61 521}
522
523void
62e76326 524store_client::fail()
528b2c61 525{
526 object_ok = false;
db2ff94c 527 /* synchronous open failures callback from the store,
528 * before startSwapin detects the failure.
529 * TODO: fix this inconsistent behaviour - probably by
26ac0430 530 * having storeSwapInStart become a callback functions,
db2ff94c 531 * not synchronous
532 */
533
90703668 534 if (_callback.pending())
db2ff94c 535 callback(0, true);
f09f5b26 536}
537
e3ef2b09 538static void
e5de8b13 539storeClientReadHeader(void *data, const char *buf, ssize_t len, StoreIOState::Pointer self)
e3ef2b09 540{
e6ccf245 541 store_client *sc = (store_client *)data;
528b2c61 542 sc->readHeader(buf, len);
543}
544
beae59b0
HN
545static void
546storeClientReadBody(void *data, const char *buf, ssize_t len, StoreIOState::Pointer self)
547{
548 store_client *sc = (store_client *)data;
549 sc->readBody(buf, len);
550}
551
528b2c61 552void
553store_client::unpackHeader(char const *buf, ssize_t len)
554{
4a7a3d56 555 debugs(90, 3, "store_client::unpackHeader: len " << len << "");
62e76326 556
e3ef2b09 557 if (len < 0) {
bf8fe701 558 debugs(90, 3, "store_client::unpackHeader: " << xstrerror() << "");
62e76326 559 fail();
560 return;
e3ef2b09 561 }
62e76326 562
528b2c61 563 int swap_hdr_sz = 0;
564 StoreMetaUnpacker aBuilder(buf, len, &swap_hdr_sz);
62e76326 565
528b2c61 566 if (!aBuilder.isBufferSane()) {
62e76326 567 /* oops, bad disk file? */
bf8fe701 568 debugs(90, 1, "WARNING: swapfile header inconsistent with available data");
62e76326 569 fail();
570 return;
9bc73deb 571 }
62e76326 572
528b2c61 573 tlv *tlv_list = aBuilder.createStoreMeta ();
62e76326 574
e3ef2b09 575 if (tlv_list == NULL) {
bf8fe701 576 debugs(90, 1, "WARNING: failed to unpack meta data");
62e76326 577 fail();
578 return;
e3ef2b09 579 }
62e76326 580
e3ef2b09 581 /*
7e3ce7b9 582 * Check the meta data and make sure we got the right object.
e3ef2b09 583 */
528b2c61 584 for (tlv *t = tlv_list; t; t = t->next) {
62e76326 585 if (!t->checkConsistency(entry)) {
586 storeSwapTLVFree(tlv_list);
587 fail();
588 return;
589 }
7e3ce7b9 590 }
62e76326 591
07304bf9 592 storeSwapTLVFree(tlv_list);
528b2c61 593
594 entry->mem_obj->swap_hdr_sz = swap_hdr_sz;
595 entry->mem_obj->object_sz = entry->swap_file_sz - swap_hdr_sz;
596
597}
598
599void
600store_client::readHeader(char const *buf, ssize_t len)
601{
602 MemObject *const mem = entry->mem_obj;
62e76326 603
528b2c61 604 assert(flags.disk_io_pending);
605 flags.disk_io_pending = 0;
90703668 606 assert(_callback.pending());
528b2c61 607
608 unpackHeader (buf, len);
62e76326 609
528b2c61 610 if (!object_ok)
62e76326 611 return;
612
e3ef2b09 613 /*
614 * If our last read got some data the client wants, then give
615 * it to them, otherwise schedule another read.
616 */
528b2c61 617 size_t body_sz = len - mem->swap_hdr_sz;
62e76326 618
47f6e231 619 if (copyInto.offset < static_cast<int64_t>(body_sz)) {
62e76326 620 /*
621 * we have (part of) what they want
622 */
d85c3078 623 size_t copy_sz = min(copyInto.length, body_sz);
4a7a3d56 624 debugs(90, 3, "storeClientReadHeader: copying " << copy_sz << " bytes of body");
62e76326 625 xmemmove(copyInto.data, copyInto.data + mem->swap_hdr_sz, copy_sz);
626
3196f526 627 readBody(copyInto.data, copy_sz);
528b2c61 628
62e76326 629 return;
e3ef2b09 630 }
62e76326 631
e3ef2b09 632 /*
633 * we don't have what the client wants, but at least we now
634 * know the swap header size.
635 */
528b2c61 636 fileRead();
e3ef2b09 637}
638
f09f5b26 639int
a4b8110e 640storeClientCopyPending(store_client * sc, StoreEntry * e, void *data)
f09f5b26 641{
06d2839d 642#if STORE_CLIENT_LIST_DEBUG
643 assert(sc == storeClientListSearch(e->mem_obj, data));
edce4d98 644#endif
645#ifndef SILLY_CODE
62e76326 646
edce4d98 647 assert(sc);
06d2839d 648#endif
62e76326 649
06d2839d 650 assert(sc->entry == e);
edce4d98 651#if SILLY_CODE
62e76326 652
f09f5b26 653 if (sc == NULL)
62e76326 654 return 0;
655
edce4d98 656#endif
62e76326 657
90703668 658 if (!sc->_callback.pending())
62e76326 659 return 0;
660
f09f5b26 661 return 1;
662}
663
06d2839d 664/*
665 * This routine hasn't been optimised to take advantage of the
666 * passed sc. Yet.
667 */
f09f5b26 668int
a4b8110e 669storeUnregister(store_client * sc, StoreEntry * e, void *data)
f09f5b26 670{
671 MemObject *mem = e->mem_obj;
06d2839d 672#if STORE_CLIENT_LIST_DEBUG
62e76326 673
06d2839d 674 assert(sc == storeClientListSearch(e->mem_obj, data));
675#endif
62e76326 676
f09f5b26 677 if (mem == NULL)
62e76326 678 return 0;
679
26ac0430 680 debugs(90, 3, "storeUnregister: called for '" << e->getMD5Text() << "'");
62e76326 681
2f44bd34 682 if (sc == NULL) {
bf8fe701 683 debugs(90, 3, "storeUnregister: No matching client for '" << e->getMD5Text() << "'");
62e76326 684 return 0;
2f44bd34 685 }
62e76326 686
0e3f3e0d 687 if (mem->clientCount() == 0) {
bf8fe701 688 debugs(90, 3, "storeUnregister: Consistency failure - store client being unregistered is not in the mem object's list for '" << e->getMD5Text() << "'");
62e76326 689 return 0;
2f44bd34 690 }
62e76326 691
06d2839d 692 dlinkDelete(&sc->node, &mem->clients);
f09f5b26 693 mem->nclients--;
62e76326 694
f09f5b26 695 if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE)
c07cbbf4 696 e->swapOut();
62e76326 697
85a4b153 698 if (sc->swapin_sio != NULL) {
62e76326 699 storeClose(sc->swapin_sio);
700 sc->swapin_sio = NULL;
701 statCounter.swap.ins++;
eb824054 702 }
62e76326 703
90703668 704 if (sc->_callback.pending()) {
62e76326 705 /* callback with ssize = -1 to indicate unexpected termination */
bf8fe701 706 debugs(90, 3, "storeUnregister: store_client for " << mem->url << " has a callback");
62e76326 707 sc->fail();
f09f5b26 708 }
62e76326 709
fa80a8ef 710#if STORE_CLIENT_LIST_DEBUG
711 cbdataReferenceDone(sc->owner);
62e76326 712
fa80a8ef 713#endif
62e76326 714
528b2c61 715 delete sc;
62e76326 716
77b32a34 717 assert(e->lock_count > 0);
62e76326 718
77b32a34 719 if (mem->nclients == 0)
62e76326 720 CheckQuickAbort(e);
a46d2c0e 721 else
722 mem->kickReads();
62e76326 723
f09f5b26 724 return 1;
725}
726
f09f5b26 727/* Call handlers waiting for data to be appended to E. */
728void
d88e3c49 729StoreEntry::invokeHandlers()
f09f5b26 730{
528b2c61 731 /* Commit what we can to disk, if appropriate */
d88e3c49 732 swapOut();
f09f5b26 733 int i = 0;
f09f5b26 734 store_client *sc;
06d2839d 735 dlink_node *nx = NULL;
736 dlink_node *node;
737
0bc8db64 738 PROF_start(InvokeHandlers);
9ea37c79 739
bf8fe701 740 debugs(90, 3, "InvokeHandlers: " << getMD5Text() );
f09f5b26 741 /* walk the entire list looking for valid callbacks */
62e76326 742
d88e3c49 743 for (node = mem_obj->clients.head; node; node = nx) {
62e76326 744 sc = (store_client *)node->data;
745 nx = node->next;
bf8fe701 746 debugs(90, 3, "StoreEntry::InvokeHandlers: checking client #" << i++ );
62e76326 747
90703668 748 if (!sc->_callback.pending())
62e76326 749 continue;
750
751 if (sc->flags.disk_io_pending)
752 continue;
753
d88e3c49 754 storeClientCopy2(this, sc);
f09f5b26 755 }
0bc8db64 756 PROF_stop(InvokeHandlers);
f09f5b26 757}
758
759int
760storePendingNClients(const StoreEntry * e)
761{
f09f5b26 762 MemObject *mem = e->mem_obj;
36547bcf 763 int npend = NULL == mem ? 0 : mem->nclients;
bf8fe701 764 debugs(90, 3, "storePendingNClients: returning " << npend);
f09f5b26 765 return npend;
766}
77b32a34 767
768/* return 1 if the request should be aborted */
769static int
770CheckQuickAbort2(StoreEntry * entry)
771{
528b2c61 772 MemObject * const mem = entry->mem_obj;
77b32a34 773 assert(mem);
bf8fe701 774 debugs(90, 3, "CheckQuickAbort2: entry=" << entry << ", mem=" << mem);
62e76326 775
0e5bd28f 776 if (mem->request && !mem->request->flags.cachable) {
bf8fe701 777 debugs(90, 3, "CheckQuickAbort2: YES !mem->request->flags.cachable");
62e76326 778 return 1;
77b32a34 779 }
62e76326 780
77b32a34 781 if (EBIT_TEST(entry->flags, KEY_PRIVATE)) {
bf8fe701 782 debugs(90, 3, "CheckQuickAbort2: YES KEY_PRIVATE");
62e76326 783 return 1;
77b32a34 784 }
62e76326 785
47f6e231 786 int64_t expectlen = entry->getReply()->content_length + entry->getReply()->hdr_sz;
0e3f3e0d 787
788 if (expectlen < 0)
2324cda2 789 /* expectlen is < 0 if *no* information about the object has been received */
0e3f3e0d 790 return 1;
791
47f6e231 792 int64_t curlen = mem->endOffset ();
62e76326 793
47f6e231 794 if (Config.quickAbort.min < 0) {
bf8fe701 795 debugs(90, 3, "CheckQuickAbort2: NO disabled");
62e76326 796 return 0;
77b32a34 797 }
62e76326 798
ab275c7b
AJ
799 if ( Config.rangeOffsetLimit < 0 && mem->request && mem->request->range ) {
800 /* Don't abort if the admin has configured range_ofset -1 to download fully for caching. */
801 debugs(90, 3, "CheckQuickAbort2: NO admin configured range replies to full-download");
802 return 0;
803 }
804
77b32a34 805 if (curlen > expectlen) {
bf8fe701 806 debugs(90, 3, "CheckQuickAbort2: YES bad content length");
62e76326 807 return 1;
77b32a34 808 }
62e76326 809
47f6e231 810 if ((expectlen - curlen) < (Config.quickAbort.min << 10)) {
bf8fe701 811 debugs(90, 3, "CheckQuickAbort2: NO only little more left");
62e76326 812 return 0;
77b32a34 813 }
62e76326 814
77b32a34 815 if ((expectlen - curlen) > (Config.quickAbort.max << 10)) {
bf8fe701 816 debugs(90, 3, "CheckQuickAbort2: YES too much left to go");
62e76326 817 return 1;
77b32a34 818 }
62e76326 819
77b32a34 820 if (expectlen < 100) {
bf8fe701 821 debugs(90, 3, "CheckQuickAbort2: NO avoid FPE");
62e76326 822 return 0;
77b32a34 823 }
62e76326 824
47f6e231 825 if ((curlen / (expectlen / 100)) > (Config.quickAbort.pct)) {
bf8fe701 826 debugs(90, 3, "CheckQuickAbort2: NO past point of no return");
62e76326 827 return 0;
77b32a34 828 }
62e76326 829
bf8fe701 830 debugs(90, 3, "CheckQuickAbort2: YES default, returning 1");
77b32a34 831 return 1;
832}
833
834static void
835CheckQuickAbort(StoreEntry * entry)
836{
528b2c61 837 assert (entry);
62e76326 838
77b32a34 839 if (storePendingNClients(entry) > 0)
62e76326 840 return;
841
77b32a34 842 if (entry->store_status != STORE_PENDING)
62e76326 843 return;
844
986ebffc 845 if (EBIT_TEST(entry->flags, ENTRY_SPECIAL))
62e76326 846 return;
847
77b32a34 848 if (CheckQuickAbort2(entry) == 0)
62e76326 849 return;
850
bfb55b6f 851 entry->abort();
77b32a34 852}
c8be6d7b 853
854void
fcc35180 855store_client::dumpStats(MemBuf * output, int clientNumber) const
c8be6d7b 856{
90703668 857 if (_callback.pending())
62e76326 858 return;
859
2fe7eff9 860 output->Printf("\tClient #%d, %p\n", clientNumber, _callback.callback_data);
62e76326 861
47f6e231 862 output->Printf("\t\tcopy_offset: %"PRId64"\n",
863 copyInto.offset);
62e76326 864
2fe7eff9 865 output->Printf("\t\tcopy_size: %d\n",
866 (int) copyInto.length);
62e76326 867
2fe7eff9 868 output->Printf("\t\tflags:");
62e76326 869
528b2c61 870 if (flags.disk_io_pending)
2fe7eff9 871 output->Printf(" disk_io_pending");
62e76326 872
528b2c61 873 if (flags.store_copying)
2fe7eff9 874 output->Printf(" store_copying");
62e76326 875
528b2c61 876 if (flags.copy_event_pending)
2fe7eff9 877 output->Printf(" copy_event_pending");
62e76326 878
2fe7eff9 879 output->Printf("\n");
528b2c61 880}
c8be6d7b 881
528b2c61 882bool
90703668 883store_client::Callback::pending() const
528b2c61 884{
90703668 885 return callback_handler && callback_data;
c8be6d7b 886}
528b2c61 887
888store_client::Callback::Callback(STCB *function, void *data) : callback_handler(function), callback_data (data) {}
b67e2c8c 889
515ec4dc 890#if DELAY_POOLS
b67e2c8c 891void
892store_client::setDelayId(DelayId delay_id)
893{
894 delayId = delay_id;
895}
62e76326 896
515ec4dc 897#endif