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, cbFile, cbIo, data);
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, cbFile, 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
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, cbFile, cbIo, data);
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 assert(slot->sameKey(static_cast<const cache_key*>(e.key)));
795 // For collapsed disk hits: e.swap_file_sz and slot->basics.swap_file_sz
796 // may still be zero and basics.swap_file_sz may grow.
798
799 return sio;
800}
801
802void
804{
805 if (!theFile)
806 fatalf("Rock cache_dir failed to initialize db file: %s", filePath);
807
808 if (theFile->error()) {
809 int xerrno = errno; // XXX: where does errno come from
810 fatalf("Rock cache_dir at %s failed to open db file: %s", filePath,
811 xstrerr(xerrno));
812 }
813
814 debugs(47, 2, "Rock cache_dir[" << index << "] limits: " <<
815 std::setw(12) << maxSize() << " disk bytes, " <<
816 std::setw(7) << map->entryLimit() << " entries, and " <<
817 std::setw(7) << map->sliceLimit() << " slots");
818
819 if (!Rebuild::Start(*this))
820 storeRebuildComplete(nullptr);
821}
822
823void
825{
826 theFile = nullptr;
827}
828
829void
830Rock::SwapDir::readCompleted(const char *, int rlen, int errflag, RefCount< ::ReadRequest> r)
831{
832 ReadRequest *request = dynamic_cast<Rock::ReadRequest*>(r.getRaw());
833 assert(request);
834 IoState::Pointer sio = request->sio;
835 sio->handleReadCompletion(*request, rlen, errflag);
836}
837
838void
840{
841 // TODO: Move details into IoState::handleWriteCompletion() after figuring
842 // out how to deal with map access. See readCompleted().
843
844 Rock::WriteRequest *request = dynamic_cast<Rock::WriteRequest*>(r.getRaw());
845 assert(request);
846 assert(request->sio != nullptr);
847 IoState &sio = *request->sio;
848
849 // quit if somebody called IoState::close() while we were waiting
850 if (!sio.stillWaiting()) {
851 debugs(79, 3, "ignoring closed entry " << sio.swap_filen);
852 noteFreeMapSlice(request->sidCurrent);
853 return;
854 }
855
856 debugs(79, 7, "errflag=" << errflag << " rlen=" << request->len << " eof=" << request->eof);
857
858 if (errflag != DISK_OK)
859 handleWriteCompletionProblem(errflag, *request);
860 else if (!sio.expectedReply(request->id))
861 handleWriteCompletionProblem(DISK_ERROR, *request);
862 else
863 handleWriteCompletionSuccess(*request);
864
865 if (sio.touchingStoreEntry())
867}
868
870void
872{
873 auto &sio = *(request.sio);
874 sio.splicingPoint = request.sidCurrent;
875 // do not increment sio.offset_ because we do it in sio->write()
876
877 assert(sio.writeableAnchor_);
878 if (sio.writeableAnchor_->start < 0) { // wrote the first slot
879 Must(request.sidPrevious < 0);
880 sio.writeableAnchor_->start = request.sidCurrent;
881 } else {
882 Must(request.sidPrevious >= 0);
883 map->writeableSlice(sio.swap_filen, request.sidPrevious).next = request.sidCurrent;
884 }
885
886 // finalize the shared slice info after writing slice contents to disk;
887 // the chain gets possession of the slice we were writing
888 Ipc::StoreMap::Slice &slice =
889 map->writeableSlice(sio.swap_filen, request.sidCurrent);
890 slice.size = request.len - sizeof(DbCellHeader);
891 Must(slice.next < 0);
892
893 if (request.eof) {
894 assert(sio.e);
895 if (sio.touchingStoreEntry()) {
896 sio.e->swap_file_sz = sio.writeableAnchor_->basics.swap_file_sz =
897 sio.offset_;
898
899 map->switchWritingToReading(sio.swap_filen);
900 // sio.e keeps the (now read) lock on the anchor
901 // storeSwapOutFileClosed() sets swap_status and calls storeWriterDone()
902 }
903 sio.writeableAnchor_ = nullptr;
904 sio.finishedWriting(DISK_OK);
905 }
906}
907
909void
911{
912 auto &sio = *request.sio;
913
914 noteFreeMapSlice(request.sidCurrent);
915
916 writeError(sio);
917 sio.finishedWriting(errflag);
918 // and hope that Core will call disconnect() to close the map entry
919}
920
921void
923{
924 // Do not abortWriting here. The entry should keep the write lock
925 // instead of losing association with the store and confusing core.
926 map->freeEntry(sio.swap_filen); // will mark as unusable, just in case
927
928 if (sio.touchingStoreEntry())
930 // else noop: a fresh entry update error does not affect stale entry readers
931
932 // All callers must also call IoState callback, to propagate the error.
933}
934
935void
937{
938 if (!map)
939 return;
940
941 Ipc::StoreMapUpdate update(updatedE);
942 if (!map->openForUpdating(update, updatedE->swap_filen))
943 return;
944
945 try {
946 AsyncJob::Start(new HeaderUpdater(this, update));
947 } catch (const std::exception &ex) {
948 debugs(20, 2, "error starting to update entry " << *updatedE << ": " << ex.what());
949 map->abortUpdating(update);
950 }
951}
952
953bool
955{
956 return freeSlots != nullptr && !freeSlots->size();
957}
958
959// storeSwapOutFileClosed calls this nethod on DISK_NO_SPACE_LEFT,
960// but it should not happen for us
961void
963{
964 debugs(20, DBG_IMPORTANT, "ERROR: Squid BUG: No space left with rock cache_dir: " <<
965 filePath);
966}
967
969void
971{
972 // The Store calls this to free some db space, but there is nothing wrong
973 // with a full() db, except when db has to shrink after reconfigure, and
974 // we do not support shrinking yet (it would have to purge specific slots).
975 // TODO: Disable maintain() requests when they are pointless.
976}
977
978void
980{
981 debugs(47, 5, &e << ' ' << e.swap_dirn << ' ' << e.swap_filen);
982 if (repl && repl->Referenced)
983 repl->Referenced(repl, &e, &e.repl);
984}
985
986bool
988{
989 debugs(47, 5, &e << ' ' << e.swap_dirn << ' ' << e.swap_filen);
990 if (repl && repl->Dereferenced)
991 repl->Dereferenced(repl, &e, &e.repl);
992
993 // no need to keep e in the global store_table for us; we have our own map
994 return false;
995}
996
997bool
999{
1000 // no entry-specific files to unlink
1001 return false;
1002}
1003
1004void
1006{
1007 if (map)
1008 map->freeEntryByKey(key); // may not be there
1009}
1010
1011void
1013{
1014 debugs(47, 5, e);
1015 if (e.hasDisk(index)) {
1016 if (map->freeEntry(e.swap_filen))
1018 if (!e.locked())
1019 disconnect(e);
1020 } else if (const auto key = e.publicKey()) {
1021 evictIfFound(key);
1022 }
1023}
1024
1025void
1027{
1028 debugs(47, 5, e);
1029 if (repl)
1030 repl->Add(repl, &e, &e.repl);
1031}
1032
1033void
1035{
1036 debugs(47, 5, e);
1037 if (repl)
1038 repl->Remove(repl, &e, &e.repl);
1039}
1040
1041void
1043{
1044 storeAppendPrintf(&e, "\n");
1045 storeAppendPrintf(&e, "Maximum Size: %" PRIu64 " KB\n", maxSize() >> 10);
1046 storeAppendPrintf(&e, "Current Size: %.2f KB %.2f%%\n",
1047 currentSize() / 1024.0,
1048 Math::doublePercent(currentSize(), maxSize()));
1049
1050 const int entryLimit = entryLimitActual();
1051 const int slotLimit = slotLimitActual();
1052 storeAppendPrintf(&e, "Maximum entries: %9d\n", entryLimit);
1053 if (map && entryLimit > 0) {
1054 const int entryCount = map->entryCount();
1055 storeAppendPrintf(&e, "Current entries: %9d %.2f%%\n",
1056 entryCount, (100.0 * entryCount / entryLimit));
1057 }
1058
1059 storeAppendPrintf(&e, "Maximum slots: %9d\n", slotLimit);
1060 if (map && slotLimit > 0) {
1061 const unsigned int slotsFree = !freeSlots ? 0 : freeSlots->size();
1062 if (slotsFree <= static_cast<unsigned int>(slotLimit)) {
1063 const int usedSlots = slotLimit - static_cast<int>(slotsFree);
1064 storeAppendPrintf(&e, "Used slots: %9d %.2f%%\n",
1065 usedSlots, (100.0 * usedSlots / slotLimit));
1066 }
1067 if (slotLimit < 100) { // XXX: otherwise too expensive to count
1069 map->updateStats(stats);
1070 stats.dump(e);
1071 }
1072 }
1073
1074 storeAppendPrintf(&e, "Pending operations: %d out of %d\n",
1076
1077 storeAppendPrintf(&e, "Flags:");
1078
1079 if (flags.selected)
1080 storeAppendPrintf(&e, " SELECTED");
1081
1082 if (flags.read_only)
1083 storeAppendPrintf(&e, " READ-ONLY");
1084
1085 storeAppendPrintf(&e, "\n");
1086
1087}
1088
1089SBuf
1091{
1092 return Ipc::Mem::Segment::Name(SBuf(path), "map");
1093}
1094
1095const char *
1097{
1098 static String spacesPath;
1099 spacesPath = path;
1100 spacesPath.append("_spaces");
1101 return spacesPath.termedBuf();
1102}
1103
1104bool
1106{
1107 return map->hasReadableEntry(reinterpret_cast<const cache_key*>(e.key));
1108}
1109
1110namespace Rock
1111{
1113}
1114
1116{
1117 Must(mapOwners.empty() && freeSlotsOwners.empty());
1118 for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
1119 if (const Rock::SwapDir *const sd = dynamic_cast<Rock::SwapDir *>(INDEXSD(i))) {
1120 rebuildStatsOwners.push_back(Rebuild::Stats::Init(*sd));
1121
1122 const int64_t capacity = sd->slotLimitActual();
1123
1124 SwapDir::DirMap::Owner *const mapOwner =
1125 SwapDir::DirMap::Init(sd->inodeMapPath(), capacity);
1126 mapOwners.push_back(mapOwner);
1127
1128 // TODO: somehow remove pool id and counters from PageStack?
1131 config.pageSize = 0; // this is an index of slots on _disk_
1132 config.capacity = capacity;
1133 config.createFull = false; // Rebuild finds and pushes free slots
1134 Ipc::Mem::Owner<Ipc::Mem::PageStack> *const freeSlotsOwner =
1135 shm_new(Ipc::Mem::PageStack)(sd->freeSlotsPath(), config);
1136 freeSlotsOwners.push_back(freeSlotsOwner);
1137 }
1138 }
1139}
1140
1142{
1143 for (size_t i = 0; i < mapOwners.size(); ++i) {
1144 delete rebuildStatsOwners[i];
1145 delete mapOwners[i];
1146 delete freeSlotsOwners[i];
1147 }
1148}
1149
#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
class SquidConfig Config
Definition: SquidConfig.cc:12
#define INDEXSD(i)
Definition: SquidConfig.h:72
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
Definition: TextException.h:59
#define Must(condition)
Definition: TextException.h:71
#define assert(EX)
Definition: assert.h:17
static char vector[AUTH_VECTOR_LEN]
void self_destruct(void)
Definition: cache_cf.cc:276
static void Start(const Pointer &job)
Definition: AsyncJob.cc:24
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:66
bool sameKey(const cache_key *const aKey) const
Definition: StoreMap.cc:952
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:959
void exportInto(StoreEntry &) const
load StoreEntry basics that were previously stored with set()
Definition: StoreMap.cc:979
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:152
SwapOut swapout
Definition: MemObject.h:159
C * getRaw() const
Definition: RefCount.h:80
bool expectedReply(const IoXactionId receivedId)
Definition: RockIoState.cc:335
Ipc::StoreMapAnchor * writeableAnchor_
starting point for writing
Definition: RockIoState.h:57
void file(const RefCount< DiskFile > &aFile)
Definition: RockIoState.cc:70
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:152
IoState::Pointer sio
static Ipc::Mem::Owner< Stats > * Init(const SwapDir &)
Definition: RockRebuild.cc:257
static bool Start(SwapDir &dir)
Definition: RockRebuild.cc:279
initializes shared memory segments used by Rock::SwapDir
Definition: RockSwapDir.h:156
~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:830
void handleWriteCompletionProblem(const int errflag, const WriteRequest &request)
code shared by writeCompleted() error handling cases
Definition: RockSwapDir.cc:910
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:936
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:871
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
Definition: RockSwapDir.cc:998
const char * freeSlotsPath() const
bool full() const
no more entries can be stored without purging
Definition: RockSwapDir.cc:954
void evictCached(StoreEntry &) override
void finalizeSwapoutSuccess(const StoreEntry &) override
finalize the successful swapout that has been already noticed by Store
Definition: RockSwapDir.cc:170
StoreIOState::Pointer createStoreIO(StoreEntry &, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *) override
Definition: RockSwapDir.cc:612
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:987
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:979
void diskFull() override
Definition: RockSwapDir.cc:962
void writeCompleted(int errflag, size_t len, RefCount< ::WriteRequest >) override
Definition: RockSwapDir.cc:839
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
StoreIOState::Pointer openStoreIO(StoreEntry &, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *) override
Definition: RockSwapDir.cc:755
int64_t diskOffsetLimit() const
Definition: RockSwapDir.cc:693
void trackReferences(StoreEntry &e)
add to replacement policy scope
void closeCompleted() override
Definition: RockSwapDir.cc:824
void maintain() override
purge while full(); it should be sufficient to purge just one
Definition: RockSwapDir.cc:970
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:803
StoreIOState::Pointer createUpdateIO(const Ipc::StoreMapUpdate &update, StoreIOState::STFNCB *, 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:922
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:421
int max_open_disk_fds
Definition: SquidConfig.h:454
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:1922
bool hasDisk(const sdirno dirn=-1, const sfileno filen=-1) const
Definition: store.cc:1897
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:1776
void attachToDisk(const sdirno, const sfileno, const swap_status_t)
Definition: store.cc:1908
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:1543
uint64_t swap_file_sz
Definition: Store.h:230
void STFNCB(void *their_data, int errflag, StoreIOState::Pointer self)
Definition: StoreIOState.h:41
sfileno swap_filen
Definition: StoreIOState.h:84
StoreEntry * e
Definition: StoreIOState.h:85
bool touchingStoreEntry() const
Definition: StoreIOState.cc:56
sdirno swap_dirn
Definition: StoreIOState.h:83
void STIOCB(void *their_data, int errflag, StoreIOState::Pointer self)
Definition: StoreIOState.h:51
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:149
A const & max(A const &lhs, A const &rhs)
A const & min(A const &lhs, A const &rhs)
#define MYNAME
Definition: Stream.h:235
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:193
#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:114
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
RunnerRegistrationEntry(SwapDirRr)
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:829
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