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