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