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