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