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 "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 canonical
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) const
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 /* store_client */
87 
88 bool
90 {
91  return getType() == STORE_MEM_CLIENT && copyInto.offset < anOffset;
92 }
93 
94 int
96 {
97  return type;
98 }
99 
100 #if STORE_CLIENT_LIST_DEBUG
101 static store_client *
102 storeClientListSearch(const MemObject * mem, void *data)
103 {
104  dlink_node *node;
105  store_client *sc = NULL;
106 
107  for (node = mem->clients.head; node; node = node->next) {
108  sc = node->data;
109 
110  if (sc->owner == data)
111  return sc;
112  }
113 
114  return NULL;
115 }
116 
117 int
118 storeClientIsThisAClient(store_client * sc, void *someClient)
119 {
120  return sc->owner == someClient;
121 }
122 
123 #endif
124 #include "HttpRequest.h"
125 
126 /* add client with fd to client list */
127 store_client *
129 {
130  MemObject *mem = e->mem_obj;
131  store_client *sc;
132  assert(mem);
133 #if STORE_CLIENT_LIST_DEBUG
134 
135  if (storeClientListSearch(mem, data) != NULL)
136  /* XXX die! */
137  assert(1 == 0);
138 #else
139  (void)data;
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 {
179  store_client *sc = (store_client *)data;
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  /* we might be blocking comm reads due to readahead limits
262  * now we have a new offset, trigger those reads...
263  */
264  entry->mem_obj->kickReads();
265  copying = false;
266 
267  anEntry->lock("store_client::copy"); // see deletion note below
268 
269  storeClientCopy2(entry, this);
270 
271  // Bug 3480: This store_client object may be deleted now if, for example,
272  // the client rejects the hit response copied above. Use on-stack pointers!
273 
274 #if USE_ADAPTATION
275  anEntry->kickProducer();
276 #endif
277  anEntry->unlock("store_client::copy");
278 
279  // Add no code here. This object may no longer exist.
280 }
281 
283 bool
285 {
287  return true; // there may be more coming
288 
289  /* STORE_OK, including aborted entries: no more data is coming */
290 
291  const int64_t len = entry->objectLen();
292 
293  // If we do not know the entry length, then we have to open the swap file.
294  const bool canSwapIn = entry->hasDisk();
295  if (len < 0)
296  return canSwapIn;
297 
298  if (copyInto.offset >= len)
299  return false; // sent everything there is
300 
301  if (canSwapIn)
302  return true; // if we lack prefix, we can swap it in
303 
304  // If we cannot swap in, make sure we have what we want in RAM. Otherwise,
305  // scheduleRead calls scheduleDiskRead which asserts without a swap file.
306  const MemObject *mem = entry->mem_obj;
307  return mem &&
308  mem->inmem_lo <= copyInto.offset && copyInto.offset < mem->endOffset();
309 }
310 
311 static void
313 {
314  /* reentrancy not allowed - note this could lead to
315  * dropped events
316  */
317 
318  if (sc->flags.copy_event_pending) {
319  return;
320  }
321 
322  if (sc->flags.store_copying) {
323  sc->flags.copy_event_pending = true;
324  debugs(90, 3, "storeClientCopy2: Queueing storeClientCopyEvent()");
325  eventAdd("storeClientCopyEvent", storeClientCopyEvent, sc, 0.0, 0);
326  return;
327  }
328 
329  debugs(90, 3, "storeClientCopy2: " << e->getMD5Text());
330  assert(sc->_callback.pending());
331  /*
332  * We used to check for ENTRY_ABORTED here. But there were some
333  * problems. For example, we might have a slow client (or two) and
334  * the peer server is reading far ahead and swapping to disk. Even
335  * if the peer aborts, we want to give the client(s)
336  * everything we got before the abort condition occurred.
337  */
338  /* Warning: doCopy may indirectly free itself in callbacks,
339  * hence the lock to keep it active for the duration of
340  * this function
341  * XXX: Locking does not prevent calling sc destructor (it only prevents
342  * freeing sc memory) so sc may become invalid from C++ p.o.v.
343  */
344  CbcPointer<store_client> tmpLock = sc;
345  assert (!sc->flags.store_copying);
346  sc->doCopy(e);
347  assert(!sc->flags.store_copying);
348 }
349 
350 void
352 {
353  assert (anEntry == entry);
354  flags.store_copying = true;
355  MemObject *mem = entry->mem_obj;
356 
357  debugs(33, 5, "store_client::doCopy: co: " <<
358  copyInto.offset << ", hi: " <<
359  mem->endOffset());
360 
361  if (!moreToSend()) {
362  /* There is no more to send! */
363  debugs(33, 3, HERE << "There is no more to send!");
364  callback(0);
365  flags.store_copying = false;
366  return;
367  }
368 
369  /* Check that we actually have data */
370  if (anEntry->store_status == STORE_PENDING && copyInto.offset >= mem->endOffset()) {
371  debugs(90, 3, "store_client::doCopy: Waiting for more");
372  flags.store_copying = false;
373  return;
374  }
375 
376  /*
377  * Slight weirdness here. We open a swapin file for any
378  * STORE_DISK_CLIENT, even if we can copy the requested chunk
379  * from memory in the next block. We must try to open the
380  * swapin file before sending any data to the client side. If
381  * we postpone the open, and then can not open the file later
382  * on, the client loses big time. Its transfer just gets cut
383  * off. Better to open it early (while the client side handler
384  * is clientCacheHit) so that we can fall back to a cache miss
385  * if needed.
386  */
387 
388  if (STORE_DISK_CLIENT == getType() && swapin_sio == NULL) {
389  if (!startSwapin())
390  return; // failure
391  }
392  scheduleRead();
393 }
394 
396 bool
398 {
399  debugs(90, 3, "store_client::doCopy: Need to open swap in file");
400  /* gotta open the swapin file */
401 
403  /* yuck -- this causes a TCP_SWAPFAIL_MISS on the client side */
404  fail();
405  flags.store_copying = false;
406  return false;
407  } else if (!flags.disk_io_pending) {
408  /* Don't set store_io_pending here */
409  storeSwapInStart(this);
410 
411  if (swapin_sio == NULL) {
412  fail();
413  flags.store_copying = false;
414  return false;
415  }
416 
417  return true;
418  } else {
419  debugs(90, DBG_IMPORTANT, "WARNING: Averted multiple fd operation (1)");
420  flags.store_copying = false;
421  return false;
422  }
423 }
424 
425 void
427 {
428  MemObject *mem = entry->mem_obj;
429 
430  if (copyInto.offset >= mem->inmem_lo && copyInto.offset < mem->endOffset())
431  scheduleMemRead();
432  else
434 }
435 
436 void
438 {
439  /* What the client wants is not in memory. Schedule a disk read */
440  if (getType() == STORE_DISK_CLIENT) {
441  // we should have called startSwapin() already
442  assert(swapin_sio != NULL);
443  } else if (!swapin_sio && !startSwapin()) {
444  debugs(90, 3, "bailing after swapin start failure for " << *entry);
445  assert(!flags.store_copying);
446  return;
447  }
448 
449  assert(!flags.disk_io_pending);
450 
451  debugs(90, 3, "reading " << *entry << " from disk");
452 
453  fileRead();
454 
455  flags.store_copying = false;
456 }
457 
458 void
460 {
461  /* What the client wants is in memory */
462  /* Old style */
463  debugs(90, 3, "store_client::doCopy: Copying normal from memory");
464  size_t sz = entry->mem_obj->data_hdr.copy(copyInto);
465  callback(sz);
466  flags.store_copying = false;
467 }
468 
469 void
471 {
472  MemObject *mem = entry->mem_obj;
473 
475  assert(!flags.disk_io_pending);
476  flags.disk_io_pending = true;
477 
478  if (mem->swap_hdr_sz != 0)
479  if (entry->swappingOut())
480  assert(mem->swapout.sio->offset() > copyInto.offset + (int64_t)mem->swap_hdr_sz);
481 
483  copyInto.data,
485  copyInto.offset + mem->swap_hdr_sz,
488  this);
489 }
490 
491 void
492 store_client::readBody(const char *, ssize_t len)
493 {
494  int parsed_header = 0;
495 
496  // Don't assert disk_io_pending here.. may be called by read_header
497  flags.disk_io_pending = false;
499  debugs(90, 3, "storeClientReadBody: len " << len << "");
500 
501  if (len < 0)
502  return fail();
503 
504  const auto rep = entry->mem_obj ? &entry->mem().baseReply() : nullptr;
505  if (copyInto.offset == 0 && len > 0 && rep && rep->sline.status() == Http::scNone) {
506  /* Our structure ! */
508  debugs(90, DBG_CRITICAL, "Could not parse headers from on disk object");
509  } else {
510  parsed_header = 1;
511  }
512  }
513 
514  if (len > 0 && rep && entry->mem_obj->inmem_lo == 0 && entry->objectLen() <= (int64_t)Config.Store.maxInMemObjSize && Config.onoff.memory_cache_disk) {
515  storeGetMemSpace(len);
516  // The above may start to free our object so we need to check again
517  if (entry->mem_obj->inmem_lo == 0) {
518  /* Copy read data back into memory.
519  * copyInto.offset includes headers, which is what mem cache needs
520  */
521  int64_t mem_offset = entry->mem_obj->endOffset();
522  if ((copyInto.offset == mem_offset) || (parsed_header && mem_offset == rep->hdr_sz)) {
524  }
525  }
526  }
527 
528  callback(len);
529 }
530 
531 void
533 {
534  object_ok = false;
535  /* synchronous open failures callback from the store,
536  * before startSwapin detects the failure.
537  * TODO: fix this inconsistent behaviour - probably by
538  * having storeSwapInStart become a callback functions,
539  * not synchronous
540  */
541 
542  if (_callback.pending())
543  callback(0, true);
544 }
545 
546 static void
547 storeClientReadHeader(void *data, const char *buf, ssize_t len, StoreIOState::Pointer)
548 {
549  store_client *sc = (store_client *)data;
550  sc->readHeader(buf, len);
551 }
552 
553 static void
554 storeClientReadBody(void *data, const char *buf, ssize_t len, StoreIOState::Pointer)
555 {
556  store_client *sc = (store_client *)data;
557  sc->readBody(buf, len);
558 }
559 
560 bool
561 store_client::unpackHeader(char const *buf, ssize_t len)
562 {
563  debugs(90, 3, "store_client::unpackHeader: len " << len << "");
564  assert(len >= 0);
565 
566  int swap_hdr_sz = 0;
567  tlv *tlv_list = nullptr;
568  try {
569  StoreMetaUnpacker aBuilder(buf, len, &swap_hdr_sz);
570  tlv_list = aBuilder.createStoreMeta();
571  } catch (const std::exception &e) {
572  debugs(90, DBG_IMPORTANT, "WARNING: failed to unpack metadata because " << e.what());
573  return false;
574  }
575  assert(tlv_list);
576 
577  /*
578  * Check the meta data and make sure we got the right object.
579  */
580  for (tlv *t = tlv_list; t; t = t->next) {
581  if (!t->checkConsistency(entry)) {
582  storeSwapTLVFree(tlv_list);
583  return false;
584  }
585  }
586 
587  storeSwapTLVFree(tlv_list);
588 
589  assert(swap_hdr_sz >= 0);
590  entry->mem_obj->swap_hdr_sz = swap_hdr_sz;
591  if (entry->swap_file_sz > 0) { // collapsed hits may not know swap_file_sz
592  assert(entry->swap_file_sz >= static_cast<uint64_t>(swap_hdr_sz));
593  entry->mem_obj->object_sz = entry->swap_file_sz - swap_hdr_sz;
594  }
595  debugs(90, 5, "store_client::unpackHeader: swap_file_sz=" <<
596  entry->swap_file_sz << "( " << swap_hdr_sz << " + " <<
597  entry->mem_obj->object_sz << ")");
598  return true;
599 }
600 
601 void
602 store_client::readHeader(char const *buf, ssize_t len)
603 {
604  MemObject *const mem = entry->mem_obj;
605 
606  assert(flags.disk_io_pending);
607  flags.disk_io_pending = false;
609 
610  // abort if we fail()'d earlier
611  if (!object_ok)
612  return;
613 
614  if (len < 0)
615  return fail();
616 
617  if (!unpackHeader(buf, len)) {
618  fail();
619  return;
620  }
621 
622  /*
623  * If our last read got some data the client wants, then give
624  * it to them, otherwise schedule another read.
625  */
626  size_t body_sz = len - mem->swap_hdr_sz;
627 
628  if (copyInto.offset < static_cast<int64_t>(body_sz)) {
629  /*
630  * we have (part of) what they want
631  */
632  size_t copy_sz = min(copyInto.length, body_sz);
633  debugs(90, 3, "storeClientReadHeader: copying " << copy_sz << " bytes of body");
634  memmove(copyInto.data, copyInto.data + mem->swap_hdr_sz, copy_sz);
635 
636  readBody(copyInto.data, copy_sz);
637 
638  return;
639  }
640 
641  /*
642  * we don't have what the client wants, but at least we now
643  * know the swap header size.
644  */
645  fileRead();
646 }
647 
648 int
650 {
651 #if STORE_CLIENT_LIST_DEBUG
652  assert(sc == storeClientListSearch(e->mem_obj, data));
653 #else
654  (void)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  assert(sc == storeClientListSearch(e->mem_obj, data));
676 #else
677  (void)data;
678 #endif
679 
680  if (mem == NULL)
681  return 0;
682 
683  debugs(90, 3, "storeUnregister: called for '" << e->getMD5Text() << "'");
684 
685  if (sc == NULL) {
686  debugs(90, 3, "storeUnregister: No matching client for '" << e->getMD5Text() << "'");
687  return 0;
688  }
689 
690  if (mem->clientCount() == 0) {
691  debugs(90, 3, "storeUnregister: Consistency failure - store client being unregistered is not in the mem object's list for '" << e->getMD5Text() << "'");
692  return 0;
693  }
694 
695  dlinkDelete(&sc->node, &mem->clients);
696  -- mem->nclients;
697 
698  const auto swapoutFinished = e->swappedOut() || e->swapoutFailed();
699  if (e->store_status == STORE_OK && !swapoutFinished)
700  e->swapOut();
701 
702  if (sc->swapin_sio != NULL) {
703  storeClose(sc->swapin_sio, StoreIOState::readerDone);
704  sc->swapin_sio = NULL;
705  ++statCounter.swap.ins;
706  }
707 
708  if (sc->_callback.pending()) {
709  /* callback with ssize = -1 to indicate unexpected termination */
710  debugs(90, 3, "store_client for " << *e << " has a callback");
711  sc->fail();
712  }
713 
714 #if STORE_CLIENT_LIST_DEBUG
715  cbdataReferenceDone(sc->owner);
716 
717 #endif
718 
719  delete sc;
720 
721  assert(e->locked());
722  // An entry locked by others may be unlocked (and destructed) by others, so
723  // we must lock again to safely dereference e after CheckQuickAbortIsReasonable().
724  e->lock("storeUnregister");
725 
727  e->abort();
728  else
729  mem->kickReads();
730 
731 #if USE_ADAPTATION
732  e->kickProducer();
733 #endif
734 
735  e->unlock("storeUnregister");
736  return 1;
737 }
738 
739 /* Call handlers waiting for data to be appended to E. */
740 void
742 {
743  if (EBIT_TEST(flags, DELAY_SENDING)) {
744  debugs(90, 3, "DELAY_SENDING is on, exiting " << *this);
745  return;
746  }
748  debugs(90, 3, "ENTRY_FWD_HDR_WAIT is on, exiting " << *this);
749  return;
750  }
751 
752  /* Commit what we can to disk, if appropriate */
753  swapOut();
754  int i = 0;
755  store_client *sc;
756  dlink_node *nx = NULL;
757  dlink_node *node;
758 
759  debugs(90, 3, mem_obj->nclients << " clients; " << *this << ' ' << getMD5Text());
760  /* walk the entire list looking for valid callbacks */
761 
762  const auto savedContext = CodeContext::Current();
763  for (node = mem_obj->clients.head; node; node = nx) {
764  sc = (store_client *)node->data;
765  nx = node->next;
766  ++i;
767 
768  if (!sc->_callback.pending())
769  continue;
770 
771  if (sc->flags.disk_io_pending)
772  continue;
773 
774  CodeContext::Reset(sc->_callback.codeContext);
775  debugs(90, 3, "checking client #" << i);
776  storeClientCopy2(this, sc);
777  }
778  CodeContext::Reset(savedContext);
779 }
780 
781 // Does not account for remote readers/clients.
782 int
784 {
785  MemObject *mem = e->mem_obj;
786  int npend = NULL == mem ? 0 : mem->nclients;
787  debugs(90, 3, "storePendingNClients: returning " << npend);
788  return npend;
789 }
790 
791 /* return true if the request should be aborted */
792 static bool
794 {
795  assert(entry);
796  debugs(90, 3, "entry=" << *entry);
797 
798  if (storePendingNClients(entry) > 0) {
799  debugs(90, 3, "quick-abort? NO storePendingNClients() > 0");
800  return false;
801  }
802 
803  if (!shutting_down && Store::Root().transientReaders(*entry)) {
804  debugs(90, 3, "quick-abort? NO still have one or more transient readers");
805  return false;
806  }
807 
808  if (entry->store_status != STORE_PENDING) {
809  debugs(90, 3, "quick-abort? NO store_status != STORE_PENDING");
810  return false;
811  }
812 
813  if (EBIT_TEST(entry->flags, ENTRY_SPECIAL)) {
814  debugs(90, 3, "quick-abort? NO ENTRY_SPECIAL");
815  return false;
816  }
817 
818  MemObject * const mem = entry->mem_obj;
819  assert(mem);
820  debugs(90, 3, "mem=" << mem);
821 
822  if (mem->request && !mem->request->flags.cachable) {
823  debugs(90, 3, "quick-abort? YES !mem->request->flags.cachable");
824  return true;
825  }
826 
827  if (EBIT_TEST(entry->flags, KEY_PRIVATE)) {
828  debugs(90, 3, "quick-abort? YES KEY_PRIVATE");
829  return true;
830  }
831 
832  const auto &reply = mem->baseReply();
833 
834  if (reply.hdr_sz <= 0) {
835  // TODO: Check whether this condition works for HTTP/0 responses.
836  debugs(90, 3, "quick-abort? YES no object data received yet");
837  return true;
838  }
839 
840  if (Config.quickAbort.min < 0) {
841  debugs(90, 3, "quick-abort? NO disabled");
842  return false;
843  }
844 
845  if (mem->request && mem->request->range && mem->request->getRangeOffsetLimit() < 0) {
846  // the admin has configured "range_offset_limit none"
847  debugs(90, 3, "quick-abort? NO admin configured range replies to full-download");
848  return false;
849  }
850 
851  if (reply.content_length < 0) {
852  // XXX: cf.data.pre does not document what should happen in this case
853  // We know that quick_abort is enabled, but no limit can be applied.
854  debugs(90, 3, "quick-abort? YES unknown content length");
855  return true;
856  }
857  const auto expectlen = reply.hdr_sz + reply.content_length;
858 
859  int64_t curlen = mem->endOffset();
860 
861  if (curlen > expectlen) {
862  debugs(90, 3, "quick-abort? YES bad content length (" << curlen << " of " << expectlen << " bytes received)");
863  return true;
864  }
865 
866  if ((expectlen - curlen) < (Config.quickAbort.min << 10)) {
867  debugs(90, 3, "quick-abort? NO only a little more object left to receive");
868  return false;
869  }
870 
871  if ((expectlen - curlen) > (Config.quickAbort.max << 10)) {
872  debugs(90, 3, "quick-abort? YES too much left to go");
873  return true;
874  }
875 
876  // XXX: This is absurd! TODO: For positives, "a/(b/c) > d" is "a*c > b*d".
877  if (expectlen < 100) {
878  debugs(90, 3, "quick-abort? NO avoid FPE");
879  return false;
880  }
881 
882  if ((curlen / (expectlen / 100)) > (Config.quickAbort.pct)) {
883  debugs(90, 3, "quick-abort? NO past point of no return");
884  return false;
885  }
886 
887  debugs(90, 3, "quick-abort? YES default");
888  return true;
889 }
890 
891 void
892 store_client::dumpStats(MemBuf * output, int clientNumber) const
893 {
894  if (_callback.pending())
895  return;
896 
897  output->appendf("\tClient #%d, %p\n", clientNumber, _callback.callback_data);
898  output->appendf("\t\tcopy_offset: %" PRId64 "\n", copyInto.offset);
899  output->appendf("\t\tcopy_size: %" PRIuSIZE "\n", copyInto.length);
900  output->append("\t\tflags:", 8);
901 
902  if (flags.disk_io_pending)
903  output->append(" disk_io_pending", 16);
904 
905  if (flags.store_copying)
906  output->append(" store_copying", 14);
907 
908  if (flags.copy_event_pending)
909  output->append(" copy_event_pending", 19);
910 
911  output->append("\n",1);
912 }
913 
914 bool
916 {
918 }
919 
920 store_client::Callback::Callback(STCB *function, void *data):
921  callback_handler(function),
922  callback_data(data),
923  codeContext(CodeContext::Current())
924 {
925 }
926 
927 #if USE_DELAY_POOLS
928 void
930 {
931  delayId = delay_id;
932 }
933 #endif
934 
Definition: parse.c:104
struct store_client::Callback _callback
HttpReply & adjustableBaseReply()
Definition: MemObject.cc:123
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:41
acl_access * collapsedForwardingAccess
Definition: SquidConfig.h:413
MemObject * mem_obj
Definition: Store.h:222
RequestFlags flags
Definition: HttpRequest.h:141
mem_hdr data_hdr
Definition: MemObject.h:138
struct node * next
Definition: parse.c:105
@ KEY_PRIVATE
Definition: enums.h:102
@ ENTRY_FWD_HDR_WAIT
Definition: enums.h:111
int64_t getRangeOffsetLimit()
Definition: HttpRequest.cc:602
MemObject & mem()
Definition: Store.h:52
void lock(const char *context)
Definition: store.cc:459
void error(char *format,...)
int64_t offset
Definition: StoreIOBuffer.h:55
StoreIOState::Pointer sio
Definition: MemObject.h:152
int64_t max
Definition: SquidConfig.h:94
Definition: cbdata.cc:60
int type
Definition: errorpage.cc:153
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:211
uint16_t flags
Definition: Store.h:233
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:398
Acl::Answer const & fastCheck()
Definition: Checklist.cc:332
void storeGetMemSpace(int size)
Definition: store.cc:1135
bool moreToSend() const
Whether there is (or will be) more entry data for us.
struct StoreIOBuffer::@147 flags
int64_t endOffset() const
Definition: MemObject.cc:216
int64_t objectLen() const
Definition: Store.h:258
#define DBG_CRITICAL
Definition: Debug.h:40
void scheduleMemRead()
#define cbdataReference(var)
Definition: cbdata.h:341
static void storeClientCopy2(StoreEntry *e, store_client *sc)
#define DBG_IMPORTANT
Definition: Debug.h:41
int64_t inmem_lo
Definition: MemObject.h:139
bool parseCharBuf(const char *buf, ssize_t end)
Definition: Message.cc:140
@ 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_ABORTED
Definition: enums.h:115
@ STORE_MEM_CLIENT
Definition: enums.h:73
void scheduleDiskRead()
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
#define NULL
Definition: types.h:166
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
const HttpReply & baseReply() const
Definition: MemObject.h:59
struct StatCounters::@137 swap
void abort()
Definition: store.cc:1091
store_client(StoreEntry *)
uint16_t refcount
Definition: Store.h:232
bool hasDisk(const sdirno dirn=-1, const sfileno filen=-1) const
Definition: store.cc:1930
#define true
Definition: GnuRegex.c:234
@ STORE_DISK_CLIENT
Definition: enums.h:74
bool memReaderHasLowerOffset(int64_t) const
Definition: store_client.cc:89
Definition: MemBuf.h:24
unsigned error
Definition: StoreIOBuffer.h:52
#define EBIT_TEST(flag, bit)
Definition: defines.h:69
int collapsed_forwarding
Definition: SquidConfig.h:330
bool onCollapsingPath() const
whether Squid configuration allows collapsing for this transaction
Definition: store_client.cc:51
struct SquidConfig::@96 quickAbort
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:152
void write(const StoreIOBuffer &buf)
Definition: MemObject.cc:138
StoreMeta * createStoreMeta()
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:245
struct SquidConfig::@112 accessList
#define assert(EX)
Definition: assert.h:19
@ DELAY_SENDING
Definition: enums.h:97
struct store_client::@146 flags
bool swapoutFailed() const
whether we failed to write this entry to disk
Definition: Store.h:137
#define cbdataReferenceDone(var)
Definition: cbdata.h:350
@ ENTRY_SPECIAL
Definition: enums.h:84
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
size_t maxInMemObjSize
Definition: SquidConfig.h:273
void swapOut()
static bool CheckQuickAbortIsReasonable(StoreEntry *entry)
void EVH(void *)
Definition: event.h:18
bool startCollapsingOn(const StoreEntry &, const bool doingRevalidation) const
Definition: store_client.cc:65
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:95
ssize_t copy(StoreIOBuffer const &) const
Definition: stmem.cc:225
int64_t cmp_offset
Definition: StoreClient.h:72
bool allowed() const
Definition: Acl.h:143
void kickProducer()
calls back producer registered with deferProducer
Definition: store.cc:388
struct SquidConfig::@111 onoff
static const Pointer & Current()
Definition: CodeContext.cc:33
void storeSwapTLVFree(tlv *n)
void callback(ssize_t len, bool error=false)
struct SquidConfig::@109 Store
int storeTooManyDiskFilesOpen(void)
Definition: store.cc:903
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:231
void addClient(store_client *)
Definition: MemObject.cc:305
int storeClientCopyPending(store_client *sc, StoreEntry *e, void *data)
static StoreIOState::STRCB storeClientReadBody
Definition: store_client.cc:40
int64_t min
Definition: SquidConfig.h:92
void copy(StoreEntry *, StoreIOBuffer, STCB *, void *)
#define PRId64
Definition: types.h:110
int shutting_down
void kickReads()
Definition: MemObject.cc:455
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:217
int locked() const
Definition: Store.h:145
bool swappingOut() const
whether we are in the process of writing this entry to disk
Definition: Store.h:133
void setDelayId(DelayId delay_id)
bool swappedOut() const
whether the entire entry is now on disk (possibly marked for deletion)
Definition: Store.h:135
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:17
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 eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:108
static EVH storeClientCopyEvent
Definition: store_client.cc:43
void STCB(void *, StoreIOBuffer)
Definition: StoreClient.h:18
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
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:934

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors