store_client.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
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.
7  */
8 
9 /* DEBUG: section 90 Storage Manager Client-Side Interface */
10 
11 #include "squid.h"
12 #include "acl/FilledChecklist.h"
13 #include "base/CodeContext.h"
14 #include "event.h"
15 #include "globals.h"
16 #include "HttpReply.h"
17 #include "HttpRequest.h"
18 #include "MemBuf.h"
19 #include "MemObject.h"
20 #include "mime_header.h"
21 #include "profiler/Profiler.h"
22 #include "SquidConfig.h"
23 #include "StatCounters.h"
24 #include "Store.h"
25 #include "store_swapin.h"
26 #include "StoreClient.h"
27 #include "StoreMeta.h"
28 #include "StoreMetaUnpacker.h"
29 #if USE_DELAY_POOLS
30 #include "DelayPools.h"
31 #endif
32 
33 /*
34  * NOTE: 'Header' refers to the swapfile metadata header.
35  * 'OBJHeader' refers to the object header, with canonical
36  * processed object headers (which may derive from FTP/HTTP etc
37  * upstream protocols
38  * 'Body' refers to the swapfile body, which is the full
39  * HTTP reply (including HTTP headers and body).
40  */
43 static void storeClientCopy2(StoreEntry * e, store_client * sc);
45 static bool CheckQuickAbortIsReasonable(StoreEntry * entry);
46 
48 
49 /* StoreClient */
50 
51 bool
53 {
55  return false;
56 
58  return true;
59 
61  fillChecklist(checklist);
62  return checklist.fastCheck().allowed();
63 }
64 
65 bool
66 StoreClient::startCollapsingOn(const StoreEntry &e, const bool doingRevalidation) const
67 {
69  return false; // collapsing is impossible due to the entry state
70 
71  if (!onCollapsingPath())
72  return false; // collapsing is impossible due to Squid configuration
73 
74  /* collapsing is possible; the caller must collapse */
75 
76  if (const auto tags = loggingTags()) {
77  if (doingRevalidation)
78  tags->collapsingHistory.revalidationCollapses++;
79  else
80  tags->collapsingHistory.otherCollapses++;
81  }
82 
83  debugs(85, 5, e << " doingRevalidation=" << doingRevalidation);
84  return true;
85 }
86 
87 /* store_client */
88 
89 bool
91 {
92  return getType() == STORE_MEM_CLIENT && copyInto.offset < anOffset;
93 }
94 
95 int
97 {
98  return type;
99 }
100 
101 #if STORE_CLIENT_LIST_DEBUG
102 static store_client *
103 storeClientListSearch(const MemObject * mem, void *data)
104 {
105  dlink_node *node;
106  store_client *sc = NULL;
107 
108  for (node = mem->clients.head; node; node = node->next) {
109  sc = node->data;
110 
111  if (sc->owner == data)
112  return sc;
113  }
114 
115  return NULL;
116 }
117 
118 int
119 storeClientIsThisAClient(store_client * sc, void *someClient)
120 {
121  return sc->owner == someClient;
122 }
123 
124 #endif
125 #include "HttpRequest.h"
126 
127 /* add client with fd to client list */
128 store_client *
130 {
131  MemObject *mem = e->mem_obj;
132  store_client *sc;
133  assert(mem);
134 #if STORE_CLIENT_LIST_DEBUG
135 
136  if (storeClientListSearch(mem, data) != NULL)
137  /* XXX die! */
138  assert(1 == 0);
139 
140 #endif
141 
142  sc = new store_client (e);
143 
144  mem->addClient(sc);
145 
146  return sc;
147 }
148 
149 void
151 {
152  size_t bSz = 0;
153 
154  if (sz >= 0 && !error)
155  bSz = sz;
156 
157  StoreIOBuffer result(bSz, 0,copyInto.data);
158 
159  if (sz < 0 || error)
160  result.flags.error = 1;
161 
162  result.offset = cmp_offset;
164  cmp_offset = copyInto.offset + bSz;
165  STCB *temphandler = _callback.callback_handler;
168  copyInto.data = NULL;
169 
171  temphandler(cbdata, result);
172 
174 }
175 
176 static void
178 {
180  debugs(90, 3, "storeClientCopyEvent: Running");
181  assert (sc->flags.copy_event_pending);
182  sc->flags.copy_event_pending = false;
183 
184  if (!sc->_callback.pending())
185  return;
186 
187  storeClientCopy2(sc->entry, sc);
188 }
189 
191  cmp_offset(0),
192 #if STORE_CLIENT_LIST_DEBUG
193  owner(cbdataReference(data)),
194 #endif
195  entry(e),
196  type(e->storeClientType()),
197  object_ok(true)
198 {
199  flags.disk_io_pending = false;
200  flags.store_copying = false;
201  flags.copy_event_pending = false;
202  ++ entry->refcount;
203 
204  if (getType() == STORE_DISK_CLIENT) {
205  /* assert we'll be able to get the data we want */
206  /* maybe we should open swapin_sio here */
208  }
209 }
210 
212 {}
213 
214 /* copy bytes requested by the client */
215 void
217  StoreEntry * e,
218  StoreIOBuffer copyInto,
219  STCB * callback,
220  void *data)
221 {
222  assert (sc != NULL);
223  sc->copy(e, copyInto,callback,data);
224 }
225 
226 void
228  StoreIOBuffer copyRequest,
229  STCB * callback_fn,
230  void *data)
231 {
232  assert (anEntry == entry);
233  assert (callback_fn);
234  assert (data);
236  debugs(90, 3, "store_client::copy: " << entry->getMD5Text() << ", from " <<
237  copyRequest.offset << ", for length " <<
238  (int) copyRequest.length << ", cb " << callback_fn << ", cbdata " <<
239  data);
240 
241 #if STORE_CLIENT_LIST_DEBUG
242 
243  assert(this == storeClientListSearch(entry->mem_obj, data));
244 #endif
245 
247 #if ONLYCONTIGUOUSREQUESTS
248 
249  assert(cmp_offset == copyRequest.offset);
250 #endif
251  /* range requests will skip into the body */
252  cmp_offset = copyRequest.offset;
253  _callback = Callback (callback_fn, cbdataReference(data));
254  copyInto.data = copyRequest.data;
255  copyInto.length = copyRequest.length;
256  copyInto.offset = copyRequest.offset;
257 
258  static bool copying (false);
259  assert (!copying);
260  copying = true;
261  PROF_start(storeClient_kickReads);
262  /* we might be blocking comm reads due to readahead limits
263  * now we have a new offset, trigger those reads...
264  */
265  entry->mem_obj->kickReads();
266  PROF_stop(storeClient_kickReads);
267  copying = false;
268 
269  anEntry->lock("store_client::copy"); // see deletion note below
270 
271  storeClientCopy2(entry, this);
272 
273  // Bug 3480: This store_client object may be deleted now if, for example,
274  // the client rejects the hit response copied above. Use on-stack pointers!
275 
276 #if USE_ADAPTATION
277  anEntry->kickProducer();
278 #endif
279  anEntry->unlock("store_client::copy");
280 
281  // Add no code here. This object may no longer exist.
282 }
283 
285 bool
287 {
289  return true; // there may be more coming
290 
291  /* STORE_OK, including aborted entries: no more data is coming */
292 
293  const int64_t len = entry->objectLen();
294 
295  // If we do not know the entry length, then we have to open the swap file.
296  const bool canSwapIn = entry->hasDisk();
297  if (len < 0)
298  return canSwapIn;
299 
300  if (copyInto.offset >= len)
301  return false; // sent everything there is
302 
303  if (canSwapIn)
304  return true; // if we lack prefix, we can swap it in
305 
306  // If we cannot swap in, make sure we have what we want in RAM. Otherwise,
307  // scheduleRead calls scheduleDiskRead which asserts without a swap file.
308  const MemObject *mem = entry->mem_obj;
309  return mem &&
310  mem->inmem_lo <= copyInto.offset && copyInto.offset < mem->endOffset();
311 }
312 
313 static void
315 {
316  /* reentrancy not allowed - note this could lead to
317  * dropped events
318  */
319 
320  if (sc->flags.copy_event_pending) {
321  return;
322  }
323 
324  if (sc->flags.store_copying) {
325  sc->flags.copy_event_pending = true;
326  debugs(90, 3, "storeClientCopy2: Queueing storeClientCopyEvent()");
327  eventAdd("storeClientCopyEvent", storeClientCopyEvent, sc, 0.0, 0);
328  return;
329  }
330 
331  debugs(90, 3, "storeClientCopy2: " << e->getMD5Text());
332  assert(sc->_callback.pending());
333  /*
334  * We used to check for ENTRY_ABORTED here. But there were some
335  * problems. For example, we might have a slow client (or two) and
336  * the peer server is reading far ahead and swapping to disk. Even
337  * if the peer aborts, we want to give the client(s)
338  * everything we got before the abort condition occurred.
339  */
340  /* Warning: doCopy may indirectly free itself in callbacks,
341  * hence the lock to keep it active for the duration of
342  * this function
343  * XXX: Locking does not prevent calling sc destructor (it only prevents
344  * freeing sc memory) so sc may become invalid from C++ p.o.v.
345  */
346  CbcPointer<store_client> tmpLock = sc;
347  assert (!sc->flags.store_copying);
348  sc->doCopy(e);
349  assert(!sc->flags.store_copying);
350 }
351 
352 void
354 {
355  assert (anEntry == entry);
356  flags.store_copying = true;
357  MemObject *mem = entry->mem_obj;
358 
359  debugs(33, 5, "store_client::doCopy: co: " <<
360  copyInto.offset << ", hi: " <<
361  mem->endOffset());
362 
363  if (!moreToSend()) {
364  /* There is no more to send! */
365  debugs(33, 3, HERE << "There is no more to send!");
366  callback(0);
367  flags.store_copying = false;
368  return;
369  }
370 
371  /* Check that we actually have data */
372  if (anEntry->store_status == STORE_PENDING && copyInto.offset >= mem->endOffset()) {
373  debugs(90, 3, "store_client::doCopy: Waiting for more");
374  flags.store_copying = false;
375  return;
376  }
377 
378  /*
379  * Slight weirdness here. We open a swapin file for any
380  * STORE_DISK_CLIENT, even if we can copy the requested chunk
381  * from memory in the next block. We must try to open the
382  * swapin file before sending any data to the client side. If
383  * we postpone the open, and then can not open the file later
384  * on, the client loses big time. Its transfer just gets cut
385  * off. Better to open it early (while the client side handler
386  * is clientCacheHit) so that we can fall back to a cache miss
387  * if needed.
388  */
389 
390  if (STORE_DISK_CLIENT == getType() && swapin_sio == NULL) {
391  if (!startSwapin())
392  return; // failure
393  }
394  scheduleRead();
395 }
396 
398 bool
400 {
401  debugs(90, 3, "store_client::doCopy: Need to open swap in file");
402  /* gotta open the swapin file */
403 
405  /* yuck -- this causes a TCP_SWAPFAIL_MISS on the client side */
406  fail();
407  flags.store_copying = false;
408  return false;
409  } else if (!flags.disk_io_pending) {
410  /* Don't set store_io_pending here */
411  storeSwapInStart(this);
412 
413  if (swapin_sio == NULL) {
414  fail();
415  flags.store_copying = false;
416  return false;
417  }
418 
419  return true;
420  } else {
421  debugs(90, DBG_IMPORTANT, "WARNING: Averted multiple fd operation (1)");
422  flags.store_copying = false;
423  return false;
424  }
425 }
426 
427 void
429 {
430  MemObject *mem = entry->mem_obj;
431 
432  if (copyInto.offset >= mem->inmem_lo && copyInto.offset < mem->endOffset())
433  scheduleMemRead();
434  else
436 }
437 
438 void
440 {
441  /* What the client wants is not in memory. Schedule a disk read */
442  if (getType() == STORE_DISK_CLIENT) {
443  // we should have called startSwapin() already
444  assert(swapin_sio != NULL);
445  } else if (!swapin_sio && !startSwapin()) {
446  debugs(90, 3, "bailing after swapin start failure for " << *entry);
447  assert(!flags.store_copying);
448  return;
449  }
450 
451  assert(!flags.disk_io_pending);
452 
453  debugs(90, 3, "reading " << *entry << " from disk");
454 
455  fileRead();
456 
457  flags.store_copying = false;
458 }
459 
460 void
462 {
463  /* What the client wants is in memory */
464  /* Old style */
465  debugs(90, 3, "store_client::doCopy: Copying normal from memory");
466  size_t sz = entry->mem_obj->data_hdr.copy(copyInto);
467  callback(sz);
468  flags.store_copying = false;
469 }
470 
471 void
473 {
474  MemObject *mem = entry->mem_obj;
475 
477  assert(!flags.disk_io_pending);
478  flags.disk_io_pending = true;
479 
480  if (mem->swap_hdr_sz != 0)
481  if (entry->swappingOut())
482  assert(mem->swapout.sio->offset() > copyInto.offset + (int64_t)mem->swap_hdr_sz);
483 
485  copyInto.data,
487  copyInto.offset + mem->swap_hdr_sz,
490  this);
491 }
492 
493 void
494 store_client::readBody(const char *, ssize_t len)
495 {
496  int parsed_header = 0;
497 
498  // Don't assert disk_io_pending here.. may be called by read_header
499  flags.disk_io_pending = false;
501  debugs(90, 3, "storeClientReadBody: len " << len << "");
502 
503  if (len < 0)
504  return fail();
505 
506  const auto rep = entry->mem_obj ? &entry->mem().baseReply() : nullptr;
507  if (copyInto.offset == 0 && len > 0 && rep && rep->sline.status() == Http::scNone) {
508  /* Our structure ! */
510  debugs(90, DBG_CRITICAL, "Could not parse headers from on disk object");
511  } else {
512  parsed_header = 1;
513  }
514  }
515 
516  if (len > 0 && rep && entry->mem_obj->inmem_lo == 0 && entry->objectLen() <= (int64_t)Config.Store.maxInMemObjSize && Config.onoff.memory_cache_disk) {
518  // The above may start to free our object so we need to check again
519  if (entry->mem_obj->inmem_lo == 0) {
520  /* Copy read data back into memory.
521  * copyInto.offset includes headers, which is what mem cache needs
522  */
523  int64_t mem_offset = entry->mem_obj->endOffset();
524  if ((copyInto.offset == mem_offset) || (parsed_header && mem_offset == rep->hdr_sz)) {
526  }
527  }
528  }
529 
530  callback(len);
531 }
532 
533 void
535 {
536  object_ok = false;
537  /* synchronous open failures callback from the store,
538  * before startSwapin detects the failure.
539  * TODO: fix this inconsistent behaviour - probably by
540  * having storeSwapInStart become a callback functions,
541  * not synchronous
542  */
543 
544  if (_callback.pending())
545  callback(0, true);
546 }
547 
548 static void
550 {
552  sc->readHeader(buf, len);
553 }
554 
555 static void
556 storeClientReadBody(void *data, const char *buf, ssize_t len, StoreIOState::Pointer)
557 {
559  sc->readBody(buf, len);
560 }
561 
562 bool
563 store_client::unpackHeader(char const *buf, ssize_t len)
564 {
565  debugs(90, 3, "store_client::unpackHeader: len " << len << "");
566  assert(len >= 0);
567 
568  int swap_hdr_sz = 0;
569  tlv *tlv_list = nullptr;
570  try {
571  StoreMetaUnpacker aBuilder(buf, len, &swap_hdr_sz);
572  tlv_list = aBuilder.createStoreMeta();
573  } catch (const std::exception &e) {
574  debugs(90, DBG_IMPORTANT, "WARNING: failed to unpack metadata because " << e.what());
575  return false;
576  }
577  assert(tlv_list);
578 
579  /*
580  * Check the meta data and make sure we got the right object.
581  */
582  for (tlv *t = tlv_list; t; t = t->next) {
583  if (!t->checkConsistency(entry)) {
584  storeSwapTLVFree(tlv_list);
585  return false;
586  }
587  }
588 
589  storeSwapTLVFree(tlv_list);
590 
591  assert(swap_hdr_sz >= 0);
592  entry->mem_obj->swap_hdr_sz = swap_hdr_sz;
593  if (entry->swap_file_sz > 0) { // collapsed hits may not know swap_file_sz
594  assert(entry->swap_file_sz >= static_cast<uint64_t>(swap_hdr_sz));
595  entry->mem_obj->object_sz = entry->swap_file_sz - swap_hdr_sz;
596  }
597  debugs(90, 5, "store_client::unpackHeader: swap_file_sz=" <<
598  entry->swap_file_sz << "( " << swap_hdr_sz << " + " <<
599  entry->mem_obj->object_sz << ")");
600  return true;
601 }
602 
603 void
604 store_client::readHeader(char const *buf, ssize_t len)
605 {
606  MemObject *const mem = entry->mem_obj;
607 
608  assert(flags.disk_io_pending);
609  flags.disk_io_pending = false;
611 
612  // abort if we fail()'d earlier
613  if (!object_ok)
614  return;
615 
616  if (len < 0)
617  return fail();
618 
619  if (!unpackHeader(buf, len)) {
620  fail();
621  return;
622  }
623 
624  /*
625  * If our last read got some data the client wants, then give
626  * it to them, otherwise schedule another read.
627  */
628  size_t body_sz = len - mem->swap_hdr_sz;
629 
630  if (copyInto.offset < static_cast<int64_t>(body_sz)) {
631  /*
632  * we have (part of) what they want
633  */
634  size_t copy_sz = min(copyInto.length, body_sz);
635  debugs(90, 3, "storeClientReadHeader: copying " << copy_sz << " bytes of body");
636  memmove(copyInto.data, copyInto.data + mem->swap_hdr_sz, copy_sz);
637 
638  readBody(copyInto.data, copy_sz);
639 
640  return;
641  }
642 
643  /*
644  * we don't have what the client wants, but at least we now
645  * know the swap header size.
646  */
647  fileRead();
648 }
649 
650 int
652 {
653 #if STORE_CLIENT_LIST_DEBUG
654  assert(sc == storeClientListSearch(e->mem_obj, data));
655 #endif
656 
657  assert(sc);
658  assert(sc->entry == e);
659 
660  if (!sc->_callback.pending())
661  return 0;
662 
663  return 1;
664 }
665 
666 /*
667  * This routine hasn't been optimised to take advantage of the
668  * passed sc. Yet.
669  */
670 int
672 {
673  MemObject *mem = e->mem_obj;
674 #if STORE_CLIENT_LIST_DEBUG
675 
676  assert(sc == storeClientListSearch(e->mem_obj, data));
677 #endif
678 
679  if (mem == NULL)
680  return 0;
681 
682  debugs(90, 3, "storeUnregister: called for '" << e->getMD5Text() << "'");
683 
684  if (sc == NULL) {
685  debugs(90, 3, "storeUnregister: No matching client for '" << e->getMD5Text() << "'");
686  return 0;
687  }
688 
689  if (mem->clientCount() == 0) {
690  debugs(90, 3, "storeUnregister: Consistency failure - store client being unregistered is not in the mem object's list for '" << e->getMD5Text() << "'");
691  return 0;
692  }
693 
694  dlinkDelete(&sc->node, &mem->clients);
695  -- mem->nclients;
696 
697  const auto swapoutFinished = e->swappedOut() || e->swapoutFailed();
698  if (e->store_status == STORE_OK && !swapoutFinished)
699  e->swapOut();
700 
701  if (sc->swapin_sio != NULL) {
702  storeClose(sc->swapin_sio, StoreIOState::readerDone);
703  sc->swapin_sio = NULL;
704  ++statCounter.swap.ins;
705  }
706 
707  if (sc->_callback.pending()) {
708  /* callback with ssize = -1 to indicate unexpected termination */
709  debugs(90, 3, "store_client for " << *e << " has a callback");
710  sc->fail();
711  }
712 
713 #if STORE_CLIENT_LIST_DEBUG
714  cbdataReferenceDone(sc->owner);
715 
716 #endif
717 
718  delete sc;
719 
720  assert(e->locked());
721  // An entry locked by others may be unlocked (and destructed) by others, so
722  // we must lock again to safely dereference e after CheckQuickAbortIsReasonable().
723  e->lock("storeUnregister");
724 
726  e->abort();
727  else
728  mem->kickReads();
729 
730 #if USE_ADAPTATION
731  e->kickProducer();
732 #endif
733 
734  e->unlock("storeUnregister");
735  return 1;
736 }
737 
738 /* Call handlers waiting for data to be appended to E. */
739 void
741 {
742  if (EBIT_TEST(flags, DELAY_SENDING)) {
743  debugs(90, 3, "DELAY_SENDING is on, exiting " << *this);
744  return;
745  }
747  debugs(90, 3, "ENTRY_FWD_HDR_WAIT is on, exiting " << *this);
748  return;
749  }
750 
751  /* Commit what we can to disk, if appropriate */
752  swapOut();
753  int i = 0;
754  store_client *sc;
755  dlink_node *nx = NULL;
756  dlink_node *node;
757 
758  PROF_start(InvokeHandlers);
759 
760  debugs(90, 3, mem_obj->nclients << " clients; " << *this << ' ' << getMD5Text());
761  /* walk the entire list looking for valid callbacks */
762 
763  const auto savedContext = CodeContext::Current();
764  for (node = mem_obj->clients.head; node; node = nx) {
765  sc = (store_client *)node->data;
766  nx = node->next;
767  ++i;
768 
769  if (!sc->_callback.pending())
770  continue;
771 
772  if (sc->flags.disk_io_pending)
773  continue;
774 
775  CodeContext::Reset(sc->_callback.codeContext);
776  debugs(90, 3, "checking client #" << i);
777  storeClientCopy2(this, sc);
778  }
779  CodeContext::Reset(savedContext);
780  PROF_stop(InvokeHandlers);
781 }
782 
783 // Does not account for remote readers/clients.
784 int
786 {
787  MemObject *mem = e->mem_obj;
788  int npend = NULL == mem ? 0 : mem->nclients;
789  debugs(90, 3, "storePendingNClients: returning " << npend);
790  return npend;
791 }
792 
793 /* return true if the request should be aborted */
794 static bool
796 {
797  assert(entry);
798  debugs(90, 3, "entry=" << *entry);
799 
800  if (storePendingNClients(entry) > 0) {
801  debugs(90, 3, "quick-abort? NO storePendingNClients() > 0");
802  return false;
803  }
804 
805  if (!shutting_down && Store::Root().transientReaders(*entry)) {
806  debugs(90, 3, "quick-abort? NO still have one or more transient readers");
807  return false;
808  }
809 
810  if (entry->store_status != STORE_PENDING) {
811  debugs(90, 3, "quick-abort? NO store_status != STORE_PENDING");
812  return false;
813  }
814 
815  if (EBIT_TEST(entry->flags, ENTRY_SPECIAL)) {
816  debugs(90, 3, "quick-abort? NO ENTRY_SPECIAL");
817  return false;
818  }
819 
820  MemObject * const mem = entry->mem_obj;
821  assert(mem);
822  debugs(90, 3, "mem=" << mem);
823 
824  if (mem->request && !mem->request->flags.cachable) {
825  debugs(90, 3, "quick-abort? YES !mem->request->flags.cachable");
826  return true;
827  }
828 
829  if (EBIT_TEST(entry->flags, KEY_PRIVATE)) {
830  debugs(90, 3, "quick-abort? YES KEY_PRIVATE");
831  return true;
832  }
833 
834  const auto &reply = mem->baseReply();
835 
836  if (reply.hdr_sz <= 0) {
837  // TODO: Check whether this condition works for HTTP/0 responses.
838  debugs(90, 3, "quick-abort? YES no object data received yet");
839  return true;
840  }
841 
842  if (Config.quickAbort.min < 0) {
843  debugs(90, 3, "quick-abort? NO disabled");
844  return false;
845  }
846 
847  if (mem->request && mem->request->range && mem->request->getRangeOffsetLimit() < 0) {
848  // the admin has configured "range_offset_limit none"
849  debugs(90, 3, "quick-abort? NO admin configured range replies to full-download");
850  return false;
851  }
852 
853  if (reply.content_length < 0) {
854  // XXX: cf.data.pre does not document what should happen in this case
855  // We know that quick_abort is enabled, but no limit can be applied.
856  debugs(90, 3, "quick-abort? YES unknown content length");
857  return true;
858  }
859  const auto expectlen = reply.hdr_sz + reply.content_length;
860 
861  int64_t curlen = mem->endOffset();
862 
863  if (curlen > expectlen) {
864  debugs(90, 3, "quick-abort? YES bad content length (" << curlen << " of " << expectlen << " bytes received)");
865  return true;
866  }
867 
868  if ((expectlen - curlen) < (Config.quickAbort.min << 10)) {
869  debugs(90, 3, "quick-abort? NO only a little more object left to receive");
870  return false;
871  }
872 
873  if ((expectlen - curlen) > (Config.quickAbort.max << 10)) {
874  debugs(90, 3, "quick-abort? YES too much left to go");
875  return true;
876  }
877 
878  // XXX: This is absurd! TODO: For positives, "a/(b/c) > d" is "a*c > b*d".
879  if (expectlen < 100) {
880  debugs(90, 3, "quick-abort? NO avoid FPE");
881  return false;
882  }
883 
884  if ((curlen / (expectlen / 100)) > (Config.quickAbort.pct)) {
885  debugs(90, 3, "quick-abort? NO past point of no return");
886  return false;
887  }
888 
889  debugs(90, 3, "quick-abort? YES default");
890  return true;
891 }
892 
893 void
894 store_client::dumpStats(MemBuf * output, int clientNumber) const
895 {
896  if (_callback.pending())
897  return;
898 
899  output->appendf("\tClient #%d, %p\n", clientNumber, _callback.callback_data);
900  output->appendf("\t\tcopy_offset: %" PRId64 "\n", copyInto.offset);
901  output->appendf("\t\tcopy_size: %" PRIuSIZE "\n", copyInto.length);
902  output->append("\t\tflags:", 8);
903 
904  if (flags.disk_io_pending)
905  output->append(" disk_io_pending", 16);
906 
907  if (flags.store_copying)
908  output->append(" store_copying", 14);
909 
910  if (flags.copy_event_pending)
911  output->append(" copy_event_pending", 19);
912 
913  output->append("\n",1);
914 }
915 
916 bool
918 {
920 }
921 
923  callback_handler(function),
924  callback_data(data),
925  codeContext(CodeContext::Current())
926 {
927 }
928 
929 #if USE_DELAY_POOLS
930 void
932 {
933  delayId = delay_id;
934 }
935 #endif
936 
Definition: parse.c:104
struct store_client::Callback _callback
HttpReply & adjustableBaseReply()
Definition: MemObject.cc:127
int storeClientIsThisAClient(store_client *sc, void *someClient)
StoreEntry * entry
Definition: StoreClient.h:78
void readHeader(const char *buf, ssize_t len)
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
void STRCB(void *their_data, const char *buf, ssize_t len, StoreIOState::Pointer self)
Definition: StoreIOState.h:29
@ scNone
Definition: StatusCode.h:21
static StoreIOState::STRCB storeClientReadHeader
Definition: store_client.cc:42
acl_access * collapsedForwardingAccess
Definition: SquidConfig.h:411
MemObject * mem_obj
Definition: Store.h:213
RequestFlags flags
Definition: HttpRequest.h:141
mem_hdr data_hdr
Definition: MemObject.h:138
@ DELAY_SENDING
Definition: enums.h:97
struct node * next
Definition: parse.c:105
int64_t getRangeOffsetLimit()
Definition: HttpRequest.cc:602
MemObject & mem()
Definition: Store.h:52
void lock(const char *context)
Definition: store.cc:459
struct StatCounters::@139 swap
void error(char *format,...)
int64_t offset
Definition: StoreIOBuffer.h:55
@ KEY_PRIVATE
Definition: enums.h:102
StoreIOState::Pointer sio
Definition: MemObject.h:152
int64_t max
Definition: SquidConfig.h:93
Definition: cbdata.cc:60
int type
Definition: errorpage.cc:153
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
uint16_t flags
Definition: Store.h:224
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:394
Acl::Answer const & fastCheck()
Definition: Checklist.cc:336
void storeGetMemSpace(int size)
Definition: store.cc:1126
bool moreToSend() const
Whether there is (or will be) more entry data for us.
int64_t endOffset() const
Definition: MemObject.cc:222
int64_t objectLen() const
Definition: Store.h:249
#define DBG_CRITICAL
Definition: Debug.h:45
void scheduleMemRead()
#define cbdataReference(var)
Definition: cbdata.h:341
#define PROF_stop(probename)
Definition: Profiler.h:63
static void storeClientCopy2(StoreEntry *e, store_client *sc)
#define DBG_IMPORTANT
Definition: Debug.h:46
int64_t inmem_lo
Definition: MemObject.h:139
bool parseCharBuf(const char *buf, ssize_t end)
Definition: Message.cc:141
@ readerDone
success or failure: either way, stop swapping in
Definition: StoreIOState.h:72
void invokeHandlers()
static void Reset()
forgets the current context, setting it to nil/unknown
Definition: CodeContext.cc:75
@ ENTRY_SPECIAL
Definition: enums.h:84
@ ENTRY_FWD_HDR_WAIT
Definition: enums.h:111
@ STORE_MEM_CLIENT
Definition: enums.h:73
void scheduleDiskRead()
struct SquidConfig::@113 onoff
void storeRead(StoreIOState::Pointer sio, char *buf, size_t size, off_t offset, StoreIOState::STRCB *callback, void *callback_data)
Definition: store_io.cc:79
int memory_cache_disk
Definition: SquidConfig.h:343
struct SquidConfig::@111 Store
#define NULL
Definition: types.h:166
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:128
const HttpReply & baseReply() const
Definition: MemObject.h:59
void abort()
Definition: store.cc:1082
store_client(StoreEntry *)
struct store_client::@148 flags
uint16_t refcount
Definition: Store.h:223
bool hasDisk(const sdirno dirn=-1, const sfileno filen=-1) const
Definition: store.cc:1927
#define true
Definition: GnuRegex.c:234
@ STORE_DISK_CLIENT
Definition: enums.h:74
bool memReaderHasLowerOffset(int64_t) const
Definition: store_client.cc:90
Definition: MemBuf.h:24
unsigned error
Definition: StoreIOBuffer.h:52
#define EBIT_TEST(flag, bit)
Definition: defines.h:107
int collapsed_forwarding
Definition: SquidConfig.h:330
bool onCollapsingPath() const
whether Squid configuration allows collapsing for this transaction
Definition: store_client.cc:52
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:157
void write(const StoreIOBuffer &buf)
Definition: MemObject.cc:142
StoreMeta * createStoreMeta()
void const char HLPCB void * data
Definition: stub_helper.cc:16
void readBody(const char *buf, ssize_t len)
int unlock(const char *context)
Definition: store.cc:483
virtual LogTags * loggingTags() const =0
off_t offset() const
Definition: StoreIOState.h:60
store_status_t store_status
Definition: Store.h:236
#define assert(EX)
Definition: assert.h:19
bool swapoutFailed() const
whether we failed to write this entry to disk
Definition: Store.h:128
#define cbdataReferenceDone(var)
Definition: cbdata.h:350
HttpHdrRange * range
Definition: HttpRequest.h:143
static int sc[16]
Definition: smbdes.c:121
virtual void fillChecklist(ACLFilledChecklist &) const =0
configure the given checklist (to reflect the current transaction state)
void const char int sz
Definition: stub_cbdata.cc:16
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
@ STORE_OK
Definition: enums.h:50
struct StoreIOBuffer::@149 flags
size_t maxInMemObjSize
Definition: SquidConfig.h:272
void swapOut()
static bool CheckQuickAbortIsReasonable(StoreEntry *entry)
void EVH(void *)
Definition: event.h:19
bool startCollapsingOn(const StoreEntry &, const bool doingRevalidation) const
Definition: store_client.cc:66
DelayId delayId
Definition: StoreClient.h:88
StoreIOBuffer copyInto
Definition: StoreClient.h:94
StoreIOState::Pointer swapin_sio
Definition: StoreClient.h:79
int getType() const
Definition: store_client.cc:96
ssize_t copy(StoreIOBuffer const &) const
Definition: stmem.cc:226
int64_t cmp_offset
Definition: StoreClient.h:72
@ ENTRY_ABORTED
Definition: enums.h:115
bool allowed() const
Definition: Acl.h:143
void kickProducer()
calls back producer registered with deferProducer
Definition: store.cc:388
struct SquidConfig::@114 accessList
static const Pointer & Current()
Definition: CodeContext.cc:33
void storeSwapTLVFree(tlv *n)
void callback(ssize_t len, bool error=false)
int storeTooManyDiskFilesOpen(void)
Definition: store.cc:908
void storeClose(StoreIOState::Pointer sio, int how)
Definition: store_io.cc:65
void dumpStats(MemBuf *output, int clientNumber) const
int64_t object_sz
Definition: MemObject.h:198
class StoreMeta tlv
Definition: StoreMeta.h:15
size_t clientCount() const
Definition: MemObject.h:142
uint64_t swap_file_sz
Definition: Store.h:222
void addClient(store_client *)
Definition: MemObject.cc:311
int storeClientCopyPending(store_client *sc, StoreEntry *e, void *data)
void const char HLPCB * callback
Definition: stub_helper.cc:16
static StoreIOState::STRCB storeClientReadBody
Definition: store_client.cc:41
int64_t min
Definition: SquidConfig.h:91
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
void copy(StoreEntry *, StoreIOBuffer, STCB *, void *)
#define PRId64
Definition: types.h:110
int shutting_down
void kickReads()
Definition: MemObject.cc:458
bool startSwapin()
opens the swapin "file" if possible; otherwise, fail()s and returns false
bool unpackHeader(char const *buf, ssize_t len)
void storeSwapInStart(store_client *sc)
Definition: store_swapin.cc:22
bool hittingRequiresCollapsing() const
whether this entry can feed collapsed requests and only them
Definition: Store.h:208
int locked() const
Definition: Store.h:136
bool swappingOut() const
whether we are in the process of writing this entry to disk
Definition: Store.h:124
void setDelayId(DelayId delay_id)
bool swappedOut() const
whether the entire entry is now on disk (possibly marked for deletion)
Definition: Store.h:126
void doCopy(StoreEntry *e)
int storeUnregister(store_client *sc, StoreEntry *e, void *data)
A const & min(A const &lhs, A const &rhs)
size_t headersEnd(const char *mime, size_t l, bool &containsObsFold)
Definition: mime_header.cc:16
void storeClientCopy(store_client *sc, StoreEntry *e, StoreIOBuffer copyInto, STCB *callback, void *data)
void scheduleRead()
HttpRequestPointer request
Definition: MemObject.h:188
size_t swap_hdr_sz
Definition: MemObject.h:199
int nclients
Definition: MemObject.h:146
const char * getMD5Text() const
Definition: store.cc:205
void const char * buf
Definition: stub_helper.cc:16
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:109
static EVH storeClientCopyEvent
Definition: store_client.cc:44
void STCB(void *, StoreIOBuffer)
Definition: StoreClient.h:18
#define PROF_start(probename)
Definition: Profiler.h:62
class SquidConfig Config
Definition: SquidConfig.cc:12
store_client * storeClientListAdd(StoreEntry *e, void *data)
int storePendingNClients(const StoreEntry *e)
dlink_list clients
Definition: MemObject.h:140
struct SquidConfig::@98 quickAbort
StatCounters statCounter
Definition: StatCounters.cc:12
@ STORE_PENDING
Definition: enums.h:51
SwapOut swapout
Definition: MemObject.h:159
Controller & Root()
safely access controller singleton
Definition: Controller.cc:938

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors