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