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