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