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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors