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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors