RockSwapDir.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 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 47 Store Directory Routines */
10 
11 #include "squid.h"
12 #include "cache_cf.h"
13 #include "CollapsedForwarding.h"
14 #include "ConfigOption.h"
15 #include "DiskIO/DiskIOModule.h"
16 #include "DiskIO/DiskIOStrategy.h"
17 #include "DiskIO/ReadRequest.h"
18 #include "DiskIO/WriteRequest.h"
20 #include "fs/rock/RockIoRequests.h"
21 #include "fs/rock/RockIoState.h"
22 #include "fs/rock/RockRebuild.h"
23 #include "fs/rock/RockSwapDir.h"
24 #include "globals.h"
25 #include "ipc/mem/Pages.h"
26 #include "MemObject.h"
27 #include "Parsing.h"
28 #include "SquidConfig.h"
29 #include "SquidMath.h"
30 #include "tools.h"
31 
32 #include <cstdlib>
33 #include <iomanip>
34 #include <limits>
35 
36 #if HAVE_SYS_STAT_H
37 #include <sys/stat.h>
38 #endif
39 
40 const int64_t Rock::SwapDir::HeaderSize = 16*1024;
41 
43  slotSize(HeaderSize), filePath(NULL), map(NULL), io(NULL),
44  waitingForPage(NULL)
45 {
46 }
47 
49 {
50  delete io;
51  delete map;
52  safe_free(filePath);
53 }
54 
55 // called when Squid core needs a StoreEntry with a given key
56 StoreEntry *
58 {
59  if (!map || !theFile || !theFile->canRead())
60  return NULL;
61 
62  sfileno filen;
63  const Ipc::StoreMapAnchor *const slot = map->openForReading(key, filen);
64  if (!slot)
65  return NULL;
66 
67  // create a brand new store entry and initialize it with stored basics
68  StoreEntry *e = new StoreEntry();
69  e->createMemObject();
70  anchorEntry(*e, filen, *slot);
71  trackReferences(*e);
72  return e;
73 }
74 
75 bool
77 {
78  if (!map || !theFile || !theFile->canRead())
79  return false;
80 
81  sfileno filen;
82  const Ipc::StoreMapAnchor *const slot = map->openForReading(
83  reinterpret_cast<cache_key*>(entry.key), filen);
84  if (!slot)
85  return false;
86 
87  anchorEntry(entry, filen, *slot);
88  inSync = updateAnchoredWith(entry, *slot);
89  return true; // even if inSync is false
90 }
91 
92 bool
94 {
95  if (!map || !theFile || !theFile->canRead())
96  return false;
97 
98  assert(entry.hasDisk(index));
99 
100  const Ipc::StoreMapAnchor &s = map->readableEntry(entry.swap_filen);
101  return updateAnchoredWith(entry, s);
102 }
103 
104 bool
106 {
107  entry.swap_file_sz = anchor.basics.swap_file_sz;
108  return true;
109 }
110 
111 void
113 {
114  anchor.exportInto(e);
115 
116  const bool complete = anchor.complete();
117  e.store_status = complete ? STORE_OK : STORE_PENDING;
118  // SWAPOUT_WRITING: even though another worker writes?
119  e.attachToDisk(index, filen, complete ? SWAPOUT_DONE : SWAPOUT_WRITING);
120 
122 
124 }
125 
127 {
128  assert(e.hasDisk(index));
129 
130  ignoreReferences(e);
131 
132  // do not rely on e.swap_status here because there is an async delay
133  // before it switches from SWAPOUT_WRITING to SWAPOUT_DONE.
134 
135  // since e has swap_filen, its slot is locked for reading and/or writing
136  // but it is difficult to know whether THIS worker is reading or writing e,
137  // especially since we may switch from writing to reading. This code relies
138  // on Rock::IoState::writeableAnchor_ being set when we locked for writing.
139  if (e.mem_obj && e.mem_obj->swapout.sio != NULL &&
140  dynamic_cast<IoState&>(*e.mem_obj->swapout.sio).writeableAnchor_) {
141  map->abortWriting(e.swap_filen);
142  e.detachFromDisk();
143  dynamic_cast<IoState&>(*e.mem_obj->swapout.sio).writeableAnchor_ = NULL;
144  Store::Root().stopSharing(e); // broadcasts after the change
145  } else {
146  map->closeForReading(e.swap_filen);
147  e.detachFromDisk();
148  }
149 }
150 
151 uint64_t
153 {
154  const uint64_t spaceSize = !freeSlots ?
155  maxSize() : (slotSize * freeSlots->size());
156  // everything that is not free is in use
157  return maxSize() - spaceSize;
158 }
159 
160 uint64_t
162 {
163  return map ? map->entryCount() : 0;
164 }
165 
168 bool
170 {
171  return ::SwapDir::doReportStat() && (!UsingSmp() || IamDiskProcess());
172 }
173 
174 void
176 {
177  // nothing to do
178 }
179 
180 void
182 {
183  debugs(47, 5, entry);
184  disconnect(entry); // calls abortWriting() to free the disk entry
185 }
186 
187 int64_t
189 {
190  // the max value is an invalid one; all values must be below the limit
194 }
195 
196 int64_t
198 {
199  const int64_t sWanted = (maxSize() - HeaderSize)/slotSize;
200  const int64_t sLimitLo = map ? map->sliceLimit() : 0; // dynamic shrinking unsupported
201  const int64_t sLimitHi = slotLimitAbsolute();
202  return min(max(sLimitLo, sWanted), sLimitHi);
203 }
204 
205 int64_t
207 {
208  return min(slotLimitActual(), entryLimitAbsolute());
209 }
210 
211 // TODO: encapsulate as a tool
212 void
214 {
215  assert(path);
216  assert(filePath);
217 
218  if (UsingSmp() && !IamDiskProcess()) {
219  debugs (47,3, HERE << "disker will create in " << path);
220  return;
221  }
222 
223  debugs (47,3, HERE << "creating in " << path);
224 
225  struct stat dir_sb;
226  if (::stat(path, &dir_sb) == 0) {
227  struct stat file_sb;
228  if (::stat(filePath, &file_sb) == 0) {
229  debugs (47, DBG_IMPORTANT, "Skipping existing Rock db: " << filePath);
230  return;
231  }
232  // else the db file is not there or is not accessible, and we will try
233  // to create it later below, generating a detailed error on failures.
234  } else { // path does not exist or is inaccessible
235  // If path exists but is not accessible, mkdir() below will fail, and
236  // the admin should see the error and act accordingly, so there is
237  // no need to distinguish ENOENT from other possible stat() errors.
238  debugs (47, DBG_IMPORTANT, "Creating Rock db directory: " << path);
239  const int res = mkdir(path, 0700);
240  if (res != 0)
241  createError("mkdir");
242  }
243 
244  debugs (47, DBG_IMPORTANT, "Creating Rock db: " << filePath);
245  const int swap = open(filePath, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600);
246  if (swap < 0)
247  createError("create");
248 
249 #if SLOWLY_FILL_WITH_ZEROS
250  char block[1024];
251  Must(maxSize() % sizeof(block) == 0);
252  memset(block, '\0', sizeof(block));
253 
254  for (off_t offset = 0; offset < maxSize(); offset += sizeof(block)) {
255  if (write(swap, block, sizeof(block)) != sizeof(block))
256  createError("write");
257  }
258 #else
259  if (ftruncate(swap, maxSize()) != 0)
260  createError("truncate");
261 
262  char header[HeaderSize];
263  memset(header, '\0', sizeof(header));
264  if (write(swap, header, sizeof(header)) != sizeof(header))
265  createError("write");
266 #endif
267 
268  close(swap);
269 }
270 
271 // report Rock DB creation error and exit
272 void
273 Rock::SwapDir::createError(const char *const msg)
274 {
275  int xerrno = errno; // XXX: where does errno come from?
276  debugs(47, DBG_CRITICAL, "ERROR: Failed to initialize Rock Store db in " <<
277  filePath << "; " << msg << " error: " << xstrerr(xerrno));
278  fatal("Rock Store db creation error");
279 }
280 
281 void
283 {
284  debugs(47,2, HERE);
285 
286  // XXX: SwapDirs aren't refcounted. We make IORequestor calls, which
287  // are refcounted. We up our count once to avoid implicit delete's.
288  lock();
289 
290  freeSlots = shm_old(Ipc::Mem::PageStack)(freeSlotsPath());
291 
292  Must(!map);
293  map = new DirMap(inodeMapPath());
294  map->cleaner = this;
295 
296  const char *ioModule = needsDiskStrand() ? "IpcIo" : "Blocking";
297  if (DiskIOModule *m = DiskIOModule::Find(ioModule)) {
298  debugs(47,2, HERE << "Using DiskIO module: " << ioModule);
299  io = m->createStrategy();
300  io->init();
301  } else {
302  debugs(47, DBG_CRITICAL, "FATAL: Rock store is missing DiskIO module: " <<
303  ioModule);
304  fatal("Rock Store missing a required DiskIO module");
305  }
306 
307  theFile = io->newFile(filePath);
308  theFile->configure(fileConfig);
309  theFile->open(O_RDWR, 0644, this);
310 
311  // Increment early. Otherwise, if one SwapDir finishes rebuild before
312  // others start, storeRebuildComplete() will think the rebuild is over!
313  // TODO: move store_dirs_rebuilding hack to store modules that need it.
315 }
316 
317 bool
319 {
320  const bool wontEvenWorkWithoutDisker = Config.workers > 1;
321  const bool wouldWorkBetterWithDisker = DiskIOModule::Find("IpcIo");
322  return InDaemonMode() && (wontEvenWorkWithoutDisker ||
323  wouldWorkBetterWithDisker);
324 }
325 
326 void
327 Rock::SwapDir::parse(int anIndex, char *aPath)
328 {
329  index = anIndex;
330 
331  path = xstrdup(aPath);
332 
333  // cache store is located at path/db
334  String fname(path);
335  fname.append("/rock");
336  filePath = xstrdup(fname.termedBuf());
337 
338  parseSize(false);
339  parseOptions(0);
340 
341  // Current openForWriting() code overwrites the old slot if needed
342  // and possible, so proactively removing old slots is probably useless.
343  assert(!repl); // repl = createRemovalPolicy(Config.replPolicy);
344 
345  validateOptions();
346 }
347 
348 void
350 {
351  parseSize(true);
352  parseOptions(1);
353  // TODO: can we reconfigure the replacement policy (repl)?
354  validateOptions();
355 }
356 
358 void
359 Rock::SwapDir::parseSize(const bool reconfig)
360 {
361  const int i = GetInteger();
362  if (i < 0)
363  fatal("negative Rock cache_dir size value");
364  const uint64_t new_max_size =
365  static_cast<uint64_t>(i) << 20; // MBytes to Bytes
366  if (!reconfig)
367  max_size = new_max_size;
368  else if (new_max_size != max_size) {
369  debugs(3, DBG_IMPORTANT, "WARNING: cache_dir '" << path << "' size "
370  "cannot be changed dynamically, value left unchanged (" <<
371  (max_size >> 20) << " MB)");
372  }
373 }
374 
375 ConfigOption *
377 {
379  ConfigOptionVector *vector = dynamic_cast<ConfigOptionVector*>(copt);
380  if (vector) {
381  // if copt is actually a ConfigOptionVector
382  vector->options.push_back(new ConfigOptionAdapter<SwapDir>(*const_cast<SwapDir *>(this), &SwapDir::parseSizeOption, &SwapDir::dumpSizeOption));
383  vector->options.push_back(new ConfigOptionAdapter<SwapDir>(*const_cast<SwapDir *>(this), &SwapDir::parseTimeOption, &SwapDir::dumpTimeOption));
384  vector->options.push_back(new ConfigOptionAdapter<SwapDir>(*const_cast<SwapDir *>(this), &SwapDir::parseRateOption, &SwapDir::dumpRateOption));
385  } else {
386  // we don't know how to handle copt, as it's not a ConfigOptionVector.
387  // free it (and return nullptr)
388  delete copt;
389  copt = nullptr;
390  }
391  return copt;
392 }
393 
394 bool
395 Rock::SwapDir::allowOptionReconfigure(const char *const option) const
396 {
397  return strcmp(option, "slot-size") != 0 &&
399 }
400 
402 bool
403 Rock::SwapDir::parseTimeOption(char const *option, const char *value, int reconfig)
404 {
405  // TODO: ::SwapDir or, better, Config should provide time-parsing routines,
406  // including time unit handling. Same for size and rate.
407 
408  time_msec_t *storedTime;
409  if (strcmp(option, "swap-timeout") == 0)
410  storedTime = &fileConfig.ioTimeout;
411  else
412  return false;
413 
414  if (!value) {
415  self_destruct();
416  return false;
417  }
418 
419  // TODO: handle time units and detect parsing errors better
420  const int64_t parsedValue = strtoll(value, NULL, 10);
421  if (parsedValue < 0) {
422  debugs(3, DBG_CRITICAL, "FATAL: cache_dir " << path << ' ' << option << " must not be negative but is: " << parsedValue);
423  self_destruct();
424  return false;
425  }
426 
427  const time_msec_t newTime = static_cast<time_msec_t>(parsedValue);
428 
429  if (!reconfig)
430  *storedTime = newTime;
431  else if (*storedTime != newTime) {
432  debugs(3, DBG_IMPORTANT, "WARNING: cache_dir " << path << ' ' << option
433  << " cannot be changed dynamically, value left unchanged: " <<
434  *storedTime);
435  }
436 
437  return true;
438 }
439 
441 void
443 {
444  if (fileConfig.ioTimeout)
445  storeAppendPrintf(e, " swap-timeout=%" PRId64,
446  static_cast<int64_t>(fileConfig.ioTimeout));
447 }
448 
450 bool
451 Rock::SwapDir::parseRateOption(char const *option, const char *value, int isaReconfig)
452 {
453  int *storedRate;
454  if (strcmp(option, "max-swap-rate") == 0)
455  storedRate = &fileConfig.ioRate;
456  else
457  return false;
458 
459  if (!value) {
460  self_destruct();
461  return false;
462  }
463 
464  // TODO: handle time units and detect parsing errors better
465  const int64_t parsedValue = strtoll(value, NULL, 10);
466  if (parsedValue < 0) {
467  debugs(3, DBG_CRITICAL, "FATAL: cache_dir " << path << ' ' << option << " must not be negative but is: " << parsedValue);
468  self_destruct();
469  return false;
470  }
471 
472  const int newRate = static_cast<int>(parsedValue);
473 
474  if (newRate < 0) {
475  debugs(3, DBG_CRITICAL, "FATAL: cache_dir " << path << ' ' << option << " must not be negative but is: " << newRate);
476  self_destruct();
477  return false;
478  }
479 
480  if (!isaReconfig)
481  *storedRate = newRate;
482  else if (*storedRate != newRate) {
483  debugs(3, DBG_IMPORTANT, "WARNING: cache_dir " << path << ' ' << option
484  << " cannot be changed dynamically, value left unchanged: " <<
485  *storedRate);
486  }
487 
488  return true;
489 }
490 
492 void
494 {
495  if (fileConfig.ioRate >= 0)
496  storeAppendPrintf(e, " max-swap-rate=%d", fileConfig.ioRate);
497 }
498 
500 bool
501 Rock::SwapDir::parseSizeOption(char const *option, const char *value, int reconfig)
502 {
503  uint64_t *storedSize;
504  if (strcmp(option, "slot-size") == 0)
505  storedSize = &slotSize;
506  else
507  return false;
508 
509  if (!value) {
510  self_destruct();
511  return false;
512  }
513 
514  // TODO: handle size units and detect parsing errors better
515  const uint64_t newSize = strtoll(value, NULL, 10);
516  if (newSize <= 0) {
517  debugs(3, DBG_CRITICAL, "FATAL: cache_dir " << path << ' ' << option << " must be positive; got: " << newSize);
518  self_destruct();
519  return false;
520  }
521 
522  if (newSize <= sizeof(DbCellHeader)) {
523  debugs(3, DBG_CRITICAL, "FATAL: cache_dir " << path << ' ' << option << " must exceed " << sizeof(DbCellHeader) << "; got: " << newSize);
524  self_destruct();
525  return false;
526  }
527 
528  if (!reconfig)
529  *storedSize = newSize;
530  else if (*storedSize != newSize) {
531  debugs(3, DBG_IMPORTANT, "WARNING: cache_dir " << path << ' ' << option
532  << " cannot be changed dynamically, value left unchanged: " <<
533  *storedSize);
534  }
535 
536  return true;
537 }
538 
540 void
542 {
543  storeAppendPrintf(e, " slot-size=%" PRId64, slotSize);
544 }
545 
547 void
549 {
550  if (slotSize <= 0)
551  fatal("Rock store requires a positive slot-size");
552 
553  const int64_t maxSizeRoundingWaste = 1024 * 1024; // size is configured in MB
554  const int64_t slotSizeRoundingWaste = slotSize;
555  const int64_t maxRoundingWaste =
556  max(maxSizeRoundingWaste, slotSizeRoundingWaste);
557 
558  // an entry consumes at least one slot; round up to reduce false warnings
559  const int64_t blockSize = static_cast<int64_t>(slotSize);
560  const int64_t maxObjSize = max(blockSize,
561  ((maxObjectSize()+blockSize-1)/blockSize)*blockSize);
562 
563  // Does the "sfileno*max-size" limit match configured db capacity?
564  const double entriesMayOccupy = entryLimitAbsolute()*static_cast<double>(maxObjSize);
565  if (entriesMayOccupy + maxRoundingWaste < maxSize()) {
566  const int64_t diskWasteSize = maxSize() - static_cast<int64_t>(entriesMayOccupy);
567  debugs(47, DBG_CRITICAL, "WARNING: Rock cache_dir " << path << " wastes disk space due to entry limits:" <<
568  "\n\tconfigured db capacity: " << maxSize() << " bytes" <<
569  "\n\tconfigured db slot size: " << slotSize << " bytes" <<
570  "\n\tconfigured maximum entry size: " << maxObjectSize() << " bytes" <<
571  "\n\tmaximum number of cache_dir entries supported by Squid: " << entryLimitAbsolute() <<
572  "\n\tdisk space all entries may use: " << entriesMayOccupy << " bytes" <<
573  "\n\tdisk space wasted: " << diskWasteSize << " bytes");
574  }
575 
576  // Does the "absolute slot count" limit match configured db capacity?
577  const double slotsMayOccupy = slotLimitAbsolute()*static_cast<double>(slotSize);
578  if (slotsMayOccupy + maxRoundingWaste < maxSize()) {
579  const int64_t diskWasteSize = maxSize() - static_cast<int64_t>(entriesMayOccupy);
580  debugs(47, DBG_CRITICAL, "WARNING: Rock cache_dir " << path << " wastes disk space due to slot limits:" <<
581  "\n\tconfigured db capacity: " << maxSize() << " bytes" <<
582  "\n\tconfigured db slot size: " << slotSize << " bytes" <<
583  "\n\tmaximum number of rock cache_dir slots supported by Squid: " << slotLimitAbsolute() <<
584  "\n\tdisk space all slots may use: " << slotsMayOccupy << " bytes" <<
585  "\n\tdisk space wasted: " << diskWasteSize << " bytes");
586  }
587 }
588 
589 void
591 {
592  //++StoreController::store_dirs_rebuilding; // see Rock::SwapDir::init()
593  AsyncJob::Start(new Rebuild(this));
594 }
595 
596 bool
597 Rock::SwapDir::canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const
598 {
599  if (diskSpaceNeeded >= 0)
600  diskSpaceNeeded += sizeof(DbCellHeader);
601  if (!::SwapDir::canStore(e, diskSpaceNeeded, load))
602  return false;
603 
604  if (!theFile || !theFile->canWrite())
605  return false;
606 
607  if (!map)
608  return false;
609 
610  // Do not start I/O transaction if there are less than 10% free pages left.
611  // TODO: reserve page instead
612  if (needsDiskStrand() &&
614  debugs(47, 5, HERE << "too few shared pages for IPC I/O left");
615  return false;
616  }
617 
618  if (io->shedLoad())
619  return false;
620 
621  load = io->load();
622  return true;
623 }
624 
627 {
628  if (!theFile || theFile->error()) {
629  debugs(47,4, HERE << theFile);
630  return NULL;
631  }
632 
633  sfileno filen;
634  Ipc::StoreMapAnchor *const slot =
635  map->openForWriting(reinterpret_cast<const cache_key *>(e.key), filen);
636  if (!slot) {
637  debugs(47, 5, HERE << "map->add failed");
638  return NULL;
639  }
640 
641  assert(filen >= 0);
642  slot->set(e);
643 
644  // XXX: We rely on our caller, storeSwapOutStart(), to set e.fileno.
645  // If that does not happen, the entry will not decrement the read level!
646 
647  Rock::SwapDir::Pointer self(this);
648  IoState *sio = new IoState(self, &e, cbFile, cbIo, data);
649 
650  sio->swap_dirn = index;
651  sio->swap_filen = filen;
652  sio->writeableAnchor_ = slot;
653 
654  debugs(47,5, HERE << "dir " << index << " created new filen " <<
655  std::setfill('0') << std::hex << std::uppercase << std::setw(8) <<
656  sio->swap_filen << std::dec << " starting at " <<
657  diskOffset(sio->swap_filen));
658 
659  sio->file(theFile);
660 
661  trackReferences(e);
662  return sio;
663 }
664 
667 {
668  if (!theFile || theFile->error()) {
669  debugs(47,4, theFile);
670  return nullptr;
671  }
672 
673  Must(update.fresh);
674  Must(update.fresh.fileNo >= 0);
675 
676  Rock::SwapDir::Pointer self(this);
677  IoState *sio = new IoState(self, update.entry, cbFile, cbIo, data);
678 
679  sio->swap_dirn = index;
680  sio->swap_filen = update.fresh.fileNo;
681  sio->writeableAnchor_ = update.fresh.anchor;
682 
683  debugs(47,5, "dir " << index << " updating filen " <<
684  std::setfill('0') << std::hex << std::uppercase << std::setw(8) <<
685  sio->swap_filen << std::dec << " starting at " <<
686  diskOffset(sio->swap_filen));
687 
688  sio->file(theFile);
689  return sio;
690 }
691 
692 int64_t
693 Rock::SwapDir::diskOffset(const SlotId sid) const
694 {
695  assert(sid >= 0);
696  return HeaderSize + slotSize*sid;
697 }
698 
699 int64_t
701 {
702  assert(pageId);
703  return diskOffset(pageId.number - 1);
704 }
705 
706 int64_t
708 {
709  assert(map);
710  return diskOffset(map->sliceLimit());
711 }
712 
713 bool
715 {
716  if (freeSlots->pop(pageId)) {
717  debugs(47, 5, "got a previously free slot: " << pageId);
718  return true;
719  }
720 
721  // catch free slots delivered to noteFreeMapSlice()
722  assert(!waitingForPage);
723  waitingForPage = &pageId;
724  if (map->purgeOne()) {
725  assert(!waitingForPage); // noteFreeMapSlice() should have cleared it
726  assert(pageId.set());
727  debugs(47, 5, "got a previously busy slot: " << pageId);
728  return true;
729  }
730  assert(waitingForPage == &pageId);
731  waitingForPage = NULL;
732 
733  debugs(47, 3, "cannot get a slot; entries: " << map->entryCount());
734  return false;
735 }
736 
737 bool
739 {
740  return 0 <= slotId && slotId < slotLimitActual();
741 }
742 
743 void
745 {
746  Ipc::Mem::PageId pageId;
747  pageId.pool = index+1;
748  pageId.number = sliceId+1;
749  if (waitingForPage) {
750  *waitingForPage = pageId;
751  waitingForPage = NULL;
752  } else {
753  freeSlots->push(pageId);
754  }
755 }
756 
757 // tries to open an old entry with swap_filen for reading
760 {
761  if (!theFile || theFile->error()) {
762  debugs(47,4, HERE << theFile);
763  return NULL;
764  }
765 
766  if (!e.hasDisk()) {
767  debugs(47,4, HERE << e);
768  return NULL;
769  }
770 
771  // Do not start I/O transaction if there are less than 10% free pages left.
772  // TODO: reserve page instead
773  if (needsDiskStrand() &&
775  debugs(47, 5, HERE << "too few shared pages for IPC I/O left");
776  return NULL;
777  }
778 
779  // The are two ways an entry can get swap_filen: our get() locked it for
780  // reading or our storeSwapOutStart() locked it for writing. Peeking at our
781  // locked entry is safe, but no support for reading the entry we swap out.
782  const Ipc::StoreMapAnchor *slot = map->peekAtReader(e.swap_filen);
783  if (!slot)
784  return NULL; // we were writing afterall
785 
786  Rock::SwapDir::Pointer self(this);
787  IoState *sio = new IoState(self, &e, cbFile, cbIo, data);
788 
789  sio->swap_dirn = index;
790  sio->swap_filen = e.swap_filen;
791  sio->readableAnchor_ = slot;
792  sio->file(theFile);
793 
794  debugs(47,5, HERE << "dir " << index << " has old filen: " <<
795  std::setfill('0') << std::hex << std::uppercase << std::setw(8) <<
796  sio->swap_filen);
797 
798  assert(slot->sameKey(static_cast<const cache_key*>(e.key)));
799  // For collapsed disk hits: e.swap_file_sz and slot->basics.swap_file_sz
800  // may still be zero and basics.swap_file_sz may grow.
802 
803  return sio;
804 }
805 
806 void
808 {
809  if (!theFile)
810  fatalf("Rock cache_dir failed to initialize db file: %s", filePath);
811 
812  if (theFile->error()) {
813  int xerrno = errno; // XXX: where does errno come from
814  fatalf("Rock cache_dir at %s failed to open db file: %s", filePath,
815  xstrerr(xerrno));
816  }
817 
818  debugs(47, 2, "Rock cache_dir[" << index << "] limits: " <<
819  std::setw(12) << maxSize() << " disk bytes, " <<
820  std::setw(7) << map->entryLimit() << " entries, and " <<
821  std::setw(7) << map->sliceLimit() << " slots");
822 
823  rebuild();
824 }
825 
826 void
828 {
829  theFile = NULL;
830 }
831 
832 void
833 Rock::SwapDir::readCompleted(const char *, int rlen, int errflag, RefCount< ::ReadRequest> r)
834 {
835  ReadRequest *request = dynamic_cast<Rock::ReadRequest*>(r.getRaw());
836  assert(request);
837  IoState::Pointer sio = request->sio;
838 
839  if (errflag == DISK_OK && rlen > 0)
840  sio->offset_ += rlen;
841 
842  sio->callReaderBack(r->buf, rlen);
843 }
844 
845 void
847 {
848  Rock::WriteRequest *request = dynamic_cast<Rock::WriteRequest*>(r.getRaw());
849  assert(request);
850  assert(request->sio != NULL);
851  IoState &sio = *request->sio;
852 
853  // quit if somebody called IoState::close() while we were waiting
854  if (!sio.stillWaiting()) {
855  debugs(79, 3, "ignoring closed entry " << sio.swap_filen);
856  noteFreeMapSlice(request->sidNext);
857  return;
858  }
859 
860  debugs(79, 7, "errflag=" << errflag << " rlen=" << request->len << " eof=" << request->eof);
861 
862  // TODO: Fail if disk dropped one of the previous write requests.
863 
864  if (errflag == DISK_OK) {
865  // do not increment sio.offset_ because we do it in sio->write()
866 
867  // finalize the shared slice info after writing slice contents to disk
868  Ipc::StoreMap::Slice &slice =
869  map->writeableSlice(sio.swap_filen, request->sidCurrent);
870  slice.size = request->len - sizeof(DbCellHeader);
871  slice.next = request->sidNext;
872 
873  if (request->eof) {
874  assert(sio.e);
876  if (sio.touchingStoreEntry()) {
878  sio.offset_;
879  map->switchWritingToReading(sio.swap_filen);
880  // sio.e keeps the (now read) lock on the anchor
881  }
882  sio.writeableAnchor_ = NULL;
883  sio.splicingPoint = request->sidCurrent;
884  sio.finishedWriting(errflag);
885  }
886  } else {
887  noteFreeMapSlice(request->sidNext);
888 
889  writeError(sio);
890  sio.finishedWriting(errflag);
891  // and wait for the finalizeSwapoutFailure() call to close the map entry
892  }
893 
894  if (sio.touchingStoreEntry())
896 }
897 
898 void
900 {
901  // Do not abortWriting here. The entry should keep the write lock
902  // instead of losing association with the store and confusing core.
903  map->freeEntry(sio.swap_filen); // will mark as unusable, just in case
904 
905  if (sio.touchingStoreEntry())
906  Store::Root().stopSharing(*sio.e);
907  // else noop: a fresh entry update error does not affect stale entry readers
908 
909  // All callers must also call IoState callback, to propagate the error.
910 }
911 
912 void
914 {
915  if (!map)
916  return;
917 
918  Ipc::StoreMapUpdate update(updatedE);
919  if (!map->openForUpdating(update, updatedE->swap_filen))
920  return;
921 
922  try {
923  AsyncJob::Start(new HeaderUpdater(this, update));
924  } catch (const std::exception &ex) {
925  debugs(20, 2, "error starting to update entry " << *updatedE << ": " << ex.what());
926  map->abortUpdating(update);
927  }
928 }
929 
930 bool
932 {
933  return freeSlots != NULL && !freeSlots->size();
934 }
935 
936 // storeSwapOutFileClosed calls this nethod on DISK_NO_SPACE_LEFT,
937 // but it should not happen for us
938 void
940 {
941  debugs(20, DBG_IMPORTANT, "BUG: No space left with rock cache_dir: " <<
942  filePath);
943 }
944 
946 void
948 {
949  // The Store calls this to free some db space, but there is nothing wrong
950  // with a full() db, except when db has to shrink after reconfigure, and
951  // we do not support shrinking yet (it would have to purge specific slots).
952  // TODO: Disable maintain() requests when they are pointless.
953 }
954 
955 void
957 {
958  debugs(47, 5, HERE << &e << ' ' << e.swap_dirn << ' ' << e.swap_filen);
959  if (repl && repl->Referenced)
960  repl->Referenced(repl, &e, &e.repl);
961 }
962 
963 bool
965 {
966  debugs(47, 5, HERE << &e << ' ' << e.swap_dirn << ' ' << e.swap_filen);
967  if (repl && repl->Dereferenced)
968  repl->Dereferenced(repl, &e, &e.repl);
969 
970  // no need to keep e in the global store_table for us; we have our own map
971  return false;
972 }
973 
974 bool
976 {
977  // no entry-specific files to unlink
978  return false;
979 }
980 
981 void
983 {
984  if (map)
985  map->freeEntryByKey(key); // may not be there
986 }
987 
988 void
990 {
991  debugs(47, 5, e);
992  if (e.hasDisk(index)) {
993  if (map->freeEntry(e.swap_filen))
995  if (!e.locked())
996  disconnect(e);
997  } else if (const auto key = e.publicKey()) {
998  evictIfFound(key);
999  }
1000 }
1001 
1002 void
1004 {
1005  debugs(47, 5, HERE << e);
1006  if (repl)
1007  repl->Add(repl, &e, &e.repl);
1008 }
1009 
1010 void
1012 {
1013  debugs(47, 5, HERE << e);
1014  if (repl)
1015  repl->Remove(repl, &e, &e.repl);
1016 }
1017 
1018 void
1020 {
1021  storeAppendPrintf(&e, "\n");
1022  storeAppendPrintf(&e, "Maximum Size: %" PRIu64 " KB\n", maxSize() >> 10);
1023  storeAppendPrintf(&e, "Current Size: %.2f KB %.2f%%\n",
1024  currentSize() / 1024.0,
1025  Math::doublePercent(currentSize(), maxSize()));
1026 
1027  const int entryLimit = entryLimitActual();
1028  const int slotLimit = slotLimitActual();
1029  storeAppendPrintf(&e, "Maximum entries: %9d\n", entryLimit);
1030  if (map && entryLimit > 0) {
1031  const int entryCount = map->entryCount();
1032  storeAppendPrintf(&e, "Current entries: %9d %.2f%%\n",
1033  entryCount, (100.0 * entryCount / entryLimit));
1034  }
1035 
1036  storeAppendPrintf(&e, "Maximum slots: %9d\n", slotLimit);
1037  if (map && slotLimit > 0) {
1038  const unsigned int slotsFree = !freeSlots ? 0 : freeSlots->size();
1039  if (slotsFree <= static_cast<const unsigned int>(slotLimit)) {
1040  const int usedSlots = slotLimit - static_cast<const int>(slotsFree);
1041  storeAppendPrintf(&e, "Used slots: %9d %.2f%%\n",
1042  usedSlots, (100.0 * usedSlots / slotLimit));
1043  }
1044  if (slotLimit < 100) { // XXX: otherwise too expensive to count
1046  map->updateStats(stats);
1047  stats.dump(e);
1048  }
1049  }
1050 
1051  storeAppendPrintf(&e, "Pending operations: %d out of %d\n",
1053 
1054  storeAppendPrintf(&e, "Flags:");
1055 
1056  if (flags.selected)
1057  storeAppendPrintf(&e, " SELECTED");
1058 
1059  if (flags.read_only)
1060  storeAppendPrintf(&e, " READ-ONLY");
1061 
1062  storeAppendPrintf(&e, "\n");
1063 
1064 }
1065 
1066 SBuf
1068 {
1069  return Ipc::Mem::Segment::Name(SBuf(path), "map");
1070 }
1071 
1072 const char *
1074 {
1075  static String spacesPath;
1076  spacesPath = path;
1077  spacesPath.append("_spaces");
1078  return spacesPath.termedBuf();
1079 }
1080 
1081 bool
1083 {
1084  return map->hasReadableEntry(reinterpret_cast<const cache_key*>(e.key));
1085 }
1086 
1087 namespace Rock
1088 {
1090 }
1091 
1093 {
1094  Must(mapOwners.empty() && freeSlotsOwners.empty());
1095  for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
1096  if (const Rock::SwapDir *const sd = dynamic_cast<Rock::SwapDir *>(INDEXSD(i))) {
1097  const int64_t capacity = sd->slotLimitActual();
1098 
1099  SwapDir::DirMap::Owner *const mapOwner =
1100  SwapDir::DirMap::Init(sd->inodeMapPath(), capacity);
1101  mapOwners.push_back(mapOwner);
1102 
1103  // TODO: somehow remove pool id and counters from PageStack?
1104  Ipc::Mem::Owner<Ipc::Mem::PageStack> *const freeSlotsOwner =
1105  shm_new(Ipc::Mem::PageStack)(sd->freeSlotsPath(),
1106  i+1, capacity, 0);
1107  freeSlotsOwners.push_back(freeSlotsOwner);
1108 
1109  // TODO: add method to initialize PageStack with no free pages
1110  while (true) {
1111  Ipc::Mem::PageId pageId;
1112  if (!freeSlotsOwner->object()->pop(pageId))
1113  break;
1114  }
1115  }
1116  }
1117 }
1118 
1120 {
1121  for (size_t i = 0; i < mapOwners.size(); ++i) {
1122  delete mapOwners[i];
1123  delete freeSlotsOwners[i];
1124  }
1125 }
1126 
virtual bool doReportStat() const
Definition: RockSwapDir.cc:169
int max_open_disk_fds
Definition: SquidConfig.h:455
virtual bool needsDiskStrand() const
needs a dedicated kid process
Definition: RockSwapDir.cc:318
sdirno swap_dirn
Definition: Store.h:214
void detachFromDisk()
Definition: store.cc:2022
virtual ~SwapDirRr()
int GetInteger(void)
Definition: Parsing.cc:142
virtual void evictIfFound(const cache_key *)
Definition: RockSwapDir.cc:982
static int store_dirs_rebuilding
the number of cache_dirs being rebuilt; TODO: move to Disks::Rebuilding
Definition: Controller.h:139
virtual bool anchorToCache(StoreEntry &entry, bool &inSync)
Definition: RockSwapDir.cc:76
sfileno fileNo
StoreMap::fileNos[name], for convenience/speed.
Definition: StoreMap.h:172
virtual StoreIOState::Pointer createStoreIO(StoreEntry &, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *)
Definition: RockSwapDir.cc:626
std::atomic< uint64_t > swap_file_sz
Definition: StoreMap.h:102
bool complete() const
Definition: StoreMap.h:74
#define assert(EX)
Definition: assert.h:17
IoState::Pointer sio
struct Ipc::StoreMapAnchor::Basics basics
std::atomic< StoreMapSliceId > next
ID of the next entry slice.
Definition: StoreMap.h:46
static char vector[AUTH_VECTOR_LEN]
Aggregates information required for updating entry metadata and headers.
Definition: StoreMap.h:159
virtual StoreIOState::Pointer openStoreIO(StoreEntry &, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *)
Definition: RockSwapDir.cc:759
bool eof
whether this is the last request for the entry
Definition: SBuf.h:86
RunnerRegistrationEntry(SwapDirRr)
std::atomic< Size > size
slice contents size
Definition: StoreMap.h:45
unsigned char cache_key
Store key.
Definition: forward.h:29
#define shm_old(Class)
Definition: Pointer.h:180
void self_destruct(void)
Definition: cache_cf.cc:257
static SBuf Name(const SBuf &prefix, const char *suffix)
concatenates parts of a name to form a complete name (or its prefix)
Definition: Segment.cc:52
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
int i
Definition: membanger.c:49
bool touchingStoreEntry() const
Definition: StoreIOState.cc:56
#define xstrdup
#define PRId64
Definition: types.h:110
void attachToDisk(const sdirno, const sfileno, const swap_status_t)
Definition: store.cc:2008
void stopSharing(StoreEntry &)
stop any current (and prevent any future) SMP sharing of the given entry
Definition: Controller.cc:592
void dumpRateOption(StoreEntry *e) const
reports rate-specific options; mimics SwapDir::optionObjectSizeDump()
Definition: RockSwapDir.cc:493
#define safe_free(x)
Definition: xalloc.h:73
virtual void evictCached(StoreEntry &)
Definition: RockSwapDir.cc:989
virtual void disconnect(StoreEntry &e)
called when the entry is about to forget its association with cache_dir
Definition: RockSwapDir.cc:126
bool hasDisk(const sdirno dirn=-1, const sfileno filen=-1) const
Definition: store.cc:1997
class Ping::pingStats_ stats
virtual void ioCompletedNotification()
Definition: RockSwapDir.cc:807
sfileno SlotId
db cell number, starting with cell 0 (always occupied by the db header)
Definition: forward.h:30
virtual bool unlinkdUseful() const
whether SwapDir may benefit from unlinkd
Definition: RockSwapDir.cc:975
bool validSlotId(const SlotId slotId) const
whether the given slot ID may point to a slot in this db
Definition: RockSwapDir.cc:738
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
char * buf
Definition: ReadRequest.h:24
approximate stats of a set of ReadWriteLocks
Definition: ReadWriteLock.h:56
static void Broadcast(const StoreEntry &e, const bool includingThisWorker=false)
notify other workers about changes in entry state (e.g., new data)
virtual void init()
Definition: RockSwapDir.cc:282
sfileno swap_filen
unique ID inside a cache_dir for swapped out entries; -1 for others
Definition: Store.h:212
#define DBG_CRITICAL
Definition: Debug.h:45
virtual void diskFull()
Definition: RockSwapDir.cc:939
Controller & Root()
safely access controller singleton
Definition: Controller.cc:877
uint32_t pool
page pool ID within Squid
Definition: Page.h:33
int64_t slotLimitAbsolute() const
Rock store implementation limit.
Definition: RockSwapDir.cc:188
virtual void reference(StoreEntry &e)
somebody needs this entry (many cache replacement policies need to know)
Definition: RockSwapDir.cc:956
A const & max(A const &lhs, A const &rhs)
void append(char const *buf, int len)
Definition: String.cc:161
SlotId splicingPoint
the last db slot successfully read or written
Definition: RockIoState.h:55
void rebuild()
starts loading and validating stored entry metadata
Definition: RockSwapDir.cc:590
virtual void readCompleted(const char *buf, int len, int errflag, RefCount< ::ReadRequest >)
Definition: RockSwapDir.cc:833
StoreIOState::Pointer sio
Definition: MemObject.h:117
virtual bool hasReadableEntry(const StoreEntry &) const
whether this cache dir has an entry with e.key
std::vector< ConfigOption * > options
Definition: ConfigOption.h:35
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
virtual void closeCompleted()
Definition: RockSwapDir.cc:827
void dumpSizeOption(StoreEntry *e) const
reports size-specific options; mimics SwapDir::optionObjectSizeDump()
Definition: RockSwapDir.cc:541
double doublePercent(const double, const double)
Definition: SquidMath.cc:25
static Pointer Start(AsyncJob *job)
starts a freshly created job (i.e., makes the job asynchronous)
Definition: AsyncJob.cc:23
virtual void updateHeaders(StoreEntry *e)
make stored metadata and HTTP headers the same as in the given entry
Definition: RockSwapDir.cc:913
virtual ~SwapDir()
Definition: RockSwapDir.cc:48
bool sameKey(const cache_key *const aKey) const
Definition: StoreMap.cc:770
int locked() const
Definition: store.cc:1249
uint64_t swap_file_sz
Definition: Store.h:206
static DiskIOModule * Find(char const *type)
uint32_t number
page number within the segment
Definition: Page.h:35
const char * xstrerr(int error)
Definition: xstrerror.cc:83
uint64_t time_msec_t
Definition: SquidTime.h:20
ping_status_t ping_status
Definition: Store.h:218
void const char HLPCB void * data
Definition: stub_helper.cc:16
virtual void reconfigure()
Definition: RockSwapDir.cc:349
virtual void finalizeSwapoutSuccess(const StoreEntry &)
finalize the successful swapout that has been already noticed by Store
Definition: RockSwapDir.cc:175
virtual bool canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const
check whether we can store the entry; if we can, report current load
Definition: RockSwapDir.cc:597
virtual void noteFreeMapSlice(const Ipc::StoreMapSliceId fileno)
adjust slice-linked state before a locked Readable slice is erased
Definition: RockSwapDir.cc:744
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
Ipc::StoreMapAnchor * writeableAnchor_
starting point for writing
Definition: RockIoState.h:52
bool stillWaiting() const
whether we are still waiting for the I/O results (i.e., not closed)
Definition: RockIoState.h:42
#define DBG_IMPORTANT
Definition: Debug.h:46
bool pop(PageId &page)
sets value and returns true unless no free page numbers are found
Definition: PageStack.cc:40
void parseSize(const bool reconfiguring)
parses anonymous cache_dir size option
Definition: RockSwapDir.cc:359
void writeError(StoreIOState &sio)
Definition: RockSwapDir.cc:899
void STFNCB(void *their_data, int errflag, StoreIOState::Pointer self)
Definition: StoreIOState.h:41
static const int64_t HeaderSize
on-disk db header size
Definition: RockSwapDir.h:148
char const * termedBuf() const
Definition: SquidString.h:91
StoreIOState::Pointer createUpdateIO(const Ipc::StoreMapUpdate &update, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *)
Definition: RockSwapDir.cc:666
void Init(void)
prepares to parse ACLs configuration
Definition: AclRegs.cc:114
int32_t StoreMapSliceId
Definition: StoreMap.h:24
int64_t diskOffsetLimit() const
Definition: RockSwapDir.cc:707
void dumpTimeOption(StoreEntry *e) const
reports time-specific options; mimics SwapDir::optionObjectSizeDump()
Definition: RockSwapDir.cc:442
void fatal(const char *message)
Definition: fatal.cc:28
virtual ConfigOption * getOptionTree() const
Definition: RockSwapDir.cc:376
bool updateAnchoredWith(StoreEntry &, const Ipc::StoreMapAnchor &)
Definition: RockSwapDir.cc:105
uint16_t flags
Definition: Store.h:208
RemovalPolicyNode repl
Definition: Store.h:198
virtual bool updateAnchored(StoreEntry &)
Definition: RockSwapDir.cc:93
int64_t diskOffset(Ipc::Mem::PageId &pageId) const
Definition: RockSwapDir.cc:700
StoreMapAnchor * anchor
StoreMap::anchors[fileNo], for convenience/speed.
Definition: StoreMap.h:171
signed_int32_t sfileno
Definition: forward.h:22
MemObject * mem_obj
Definition: Store.h:197
bool useFreeSlot(Ipc::Mem::PageId &pageId)
removes a slot from a list of free slots or returns false
Definition: RockSwapDir.cc:714
void ignoreReferences(StoreEntry &e)
delete from repl policy scope
#define INDEXSD(i)
Definition: SquidConfig.h:68
virtual bool allowOptionReconfigure(const char *const option) const
Definition: RockSwapDir.cc:395
void validateOptions()
warns of configuration problems; may quit
Definition: RockSwapDir.cc:548
bool UsingSmp()
Whether there should be more than one worker process running.
Definition: tools.cc:658
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
virtual void create()
create system resources needed for this store to operate in the future
Definition: RockSwapDir.cc:213
#define shm_new(Class)
Definition: Pointer.h:179
bool set() const
true if and only if both critical components have been initialized
Definition: Page.h:27
SwapOut swapout
Definition: MemObject.h:124
SlotId sidCurrent
slot being written using this write request
Definition: enums.h:46
virtual uint64_t currentSize() const
current size
Definition: RockSwapDir.cc:152
IoState::Pointer sio
void STIOCB(void *their_data, int errflag, StoreIOState::Pointer self)
Definition: StoreIOState.h:51
bool InDaemonMode()
Whether we are running in daemon mode.
Definition: tools.cc:652
void anchorEntry(StoreEntry &e, const sfileno filen, const Ipc::StoreMapAnchor &anchor)
Definition: RockSwapDir.cc:112
#define PRIu64
Definition: types.h:120
virtual bool allowOptionReconfigure(const char *const) const
Definition: Disk.h:85
void trackReferences(StoreEntry &e)
add to replacement policy scope
#define EBIT_SET(flag, bit)
Definition: defines.h:105
store_status_t store_status
Definition: Store.h:220
const char * freeSlotsPath() const
void finishedWriting(const int errFlag)
called by SwapDir::writeCompleted() after the last write and on error
Definition: RockIoState.cc:325
int64_t entryLimitActual() const
max number of possible entries in db
Definition: RockSwapDir.cc:206
Store::DiskConfig cacheSwap
Definition: SquidConfig.h:422
virtual uint64_t currentCount() const
the total number of objects stored right now
Definition: RockSwapDir.cc:161
Edition fresh
new anchor and updated chain prefix
Definition: StoreMap.h:187
int store_open_disk_fd
void callReaderBack(const char *buf, int rlen)
forwards read data to the reader that initiated this I/O
Definition: RockIoState.cc:134
StoreEntry * e
Definition: StoreIOState.h:85
virtual bool dereference(StoreEntry &e)
Definition: RockSwapDir.cc:964
int64_t slotLimitActual() const
total number of slots in this db
Definition: RockSwapDir.cc:197
void exportInto(StoreEntry &) const
load StoreEntry basics that were previously stored with set()
Definition: StoreMap.cc:797
const cache_key * publicKey() const
Definition: Store.h:98
Shared memory page identifier, address, or handler.
Definition: Page.h:21
size_t PageLevel()
approximate total number of shared memory pages used now
Definition: Pages.cc:80
void createError(const char *const msg)
Definition: RockSwapDir.cc:273
SBuf inodeMapPath() const
virtual ConfigOption * getOptionTree() const
Definition: Disk.cc:258
virtual void writeCompleted(int errflag, size_t len, RefCount< ::WriteRequest >)
Definition: RockSwapDir.cc:846
void set(const StoreEntry &anEntry, const cache_key *aKey=nullptr)
store StoreEntry key and basics for an inode slot
Definition: StoreMap.cc:777
SlotId sidNext
allocated next slot (negative if we are writing the last slot)
bool parseRateOption(char const *option, const char *value, int reconfiguring)
parses rate-specific options; mimics SwapDir::optionObjectSizeParse()
Definition: RockSwapDir.cc:451
bool IamDiskProcess() STUB_RETVAL_NOP(false) bool InDaemonMode() STUB_RETVAL_NOP(false) bool UsingSmp() STUB_RETVAL_NOP(false) bool IamCoordinatorProcess() STUB_RETVAL(false) bool IamPrimaryProcess() STUB_RETVAL(false) int NumberOfKids() STUB_RETVAL(0) void setMaxFD(void) STUB void setSystemLimits(void) STUB void squid_signal(int
whether the current process is dedicated to managing a cache_dir
#define DISK_OK
Definition: defines.h:39
int64_t strtoll(const char *nptr, char **endptr, int base)
Definition: strtoll.c:81
#define O_BINARY
Definition: defines.h:204
off_t offset_
number of bytes written or read for this entry so far
Definition: StoreIOState.h:87
virtual void statfs(StoreEntry &e) const
Class * object()
Raw access; handy to finalize initiatization, but avoid if possible.
Definition: Pointer.h:41
virtual void create()
called when the runner should create a new memory segment
virtual void maintain()
purge while full(); it should be sufficient to purge just one
Definition: RockSwapDir.cc:947
virtual void finalizeSwapoutFailure(StoreEntry &)
abort the failed swapout that has been already noticed by Store
Definition: RockSwapDir.cc:181
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:875
bool full() const
no more entries can be stored without purging
Definition: RockSwapDir.cc:931
virtual StoreEntry * get(const cache_key *key)
Definition: RockSwapDir.cc:57
C * getRaw() const
Definition: RefCount.h:74
size_t PageLimit()
the total number of shared memory pages that can be in use at any time
Definition: Pages.cc:55
class SquidConfig Config
Definition: SquidConfig.cc:12
#define NULL
Definition: types.h:166
bool parseSizeOption(char const *option, const char *value, int reconfiguring)
parses size-specific options; mimics SwapDir::optionObjectSizeParse()
Definition: RockSwapDir.cc:501
initializes shared memory segments used by Rock::SwapDir
Definition: RockSwapDir.h:152
A const & min(A const &lhs, A const &rhs)
sfileno swap_filen
Definition: StoreIOState.h:84
void dump(StoreEntry &e) const
virtual void parse(int index, char *path)
Definition: RockSwapDir.cc:327
StoreEntry * entry
the store entry being updated
Definition: StoreMap.h:185
void createMemObject()
Definition: store.cc:1609
bool parseTimeOption(char const *option, const char *value, int reconfiguring)
parses time-specific options; mimics SwapDir::optionObjectSizeParse()
Definition: RockSwapDir.cc:403

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors