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