UFSSwapDir.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#define CLEAN_BUF_SZ 16384
12
13#include "squid.h"
14#include "base/Random.h"
15#include "cache_cf.h"
16#include "ConfigOption.h"
17#include "DiskIO/DiskIOModule.h"
19#include "fde.h"
20#include "FileMap.h"
21#include "fs_io.h"
22#include "globals.h"
23#include "Parsing.h"
24#include "RebuildState.h"
25#include "SquidConfig.h"
26#include "SquidMath.h"
27#include "StatCounters.h"
28#include "store_key_md5.h"
29#include "StoreSwapLogData.h"
30#include "tools.h"
31#include "UFSSwapDir.h"
32
33#include <cerrno>
34#include <cmath>
35#if HAVE_SYS_STAT_H
36#include <sys/stat.h>
37#endif
38
41
43{
44
45public:
46 UFSCleanLog(SwapDir *aSwapDir) : sd(aSwapDir) {}
47
49 const StoreEntry *nextEntry() override;
50
52 void write(StoreEntry const &) override;
53
57 char *outbuf = nullptr;
58 off_t outbuf_offset = 0;
59 int fd = -1;
61 SwapDir *sd = nullptr;
62};
63
64const StoreEntry *
66{
67 const StoreEntry *entry = nullptr;
68
69 if (walker)
70 entry = walker->Next(walker);
71
72 return entry;
73}
74
75void
77{
79 static size_t ss = sizeof(StoreSwapLogData);
80 s.op = (char) SWAP_LOG_ADD;
82 s.timestamp = e.timestamp;
83 s.lastref = e.lastref;
84 s.expires = e.expires;
85 s.lastmod = e.lastModified();
87 s.refcount = e.refcount;
88 s.flags = e.flags;
89 memcpy(&s.key, e.key, SQUID_MD5_DIGEST_LENGTH);
90 s.finalize();
91 memcpy(outbuf + outbuf_offset, &s, ss);
92 outbuf_offset += ss;
93 /* buffered write */
94
95 if (outbuf_offset + ss >= CLEAN_BUF_SZ) {
97 int xerrno = errno;
98 /* XXX This error handling should probably move up to the caller */
99 debugs(50, DBG_CRITICAL, MYNAME << newLog << ": write: " << xstrerr(xerrno));
100 debugs(50, DBG_CRITICAL, MYNAME << "Current swap logfile not replaced.");
101 file_close(fd);
102 fd = -1;
103 unlink(newLog.c_str());
104 sd->cleanLog = nullptr;
105 delete this;
106 return;
107 }
108
109 outbuf_offset = 0;
110 }
111}
112
113bool
114Fs::Ufs::UFSSwapDir::canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const
115{
116 if (!SwapDir::canStore(e, diskSpaceNeeded, load))
117 return false;
118
119 if (IO->shedLoad())
120 return false;
121
122 load = IO->load();
123 return true;
124}
125
126static void
127FreeObject(void *address)
128{
129 StoreSwapLogData *anObject = static_cast <StoreSwapLogData *>(address);
130 delete anObject;
131}
132
133static int
134rev_int_sort(const void *A, const void *B)
135{
136 const int *i1 = (const int *)A;
137 const int *i2 = (const int *)B;
138 return *i2 - *i1;
139}
140
141void
143{
144 int i = GetInteger();
145 if (i <= 0)
146 fatal("UFSSwapDir::parseSizeL1L2: invalid size value");
147
148 const uint64_t size = static_cast<uint64_t>(i) << 20; // MBytes to Bytes
149
150 /* just reconfigure it */
151 if (reconfiguring) {
152 if (size == maxSize())
153 debugs(3, 2, "Cache dir '" << path << "' size remains unchanged at " << i << " MB");
154 else
155 debugs(3, DBG_IMPORTANT, "Cache dir '" << path << "' size changed to " << i << " MB");
156 }
157
158 max_size = size;
159
160 l1 = GetInteger();
161
162 if (l1 <= 0)
163 fatal("UFSSwapDir::parseSizeL1L2: invalid level 1 directories value");
164
165 l2 = GetInteger();
166
167 if (l2 <= 0)
168 fatal("UFSSwapDir::parseSizeL1L2: invalid level 2 directories value");
169}
170
171void
173{
174 parseSizeL1L2();
175 parseOptions(1);
176}
177
178void
179Fs::Ufs::UFSSwapDir::parse (int anIndex, char *aPath)
180{
181 index = anIndex;
182 path = xstrdup(aPath);
183
184 parseSizeL1L2();
185
186 /* Initialise replacement policy stuff */
188
189 parseOptions(0);
190}
191
192void
194{
195 DiskIOStrategy *anIO = module->createStrategy();
196 safe_free(ioType);
197 ioType = xstrdup(module->type());
198
199 delete IO->io;
200 IO->io = anIO;
201 /* Change the IO Options */
202
203 if (currentIOOptions && currentIOOptions->options.size() > 2) {
204 delete currentIOOptions->options.back();
205 currentIOOptions->options.pop_back();
206 }
207
208 /* TODO: factor out these 4 lines */
209 ConfigOption *ioOptions = IO->io->getOptionTree();
210
211 if (currentIOOptions && ioOptions)
212 currentIOOptions->options.push_back(ioOptions);
213}
214
215bool
216Fs::Ufs::UFSSwapDir::optionIOParse(char const *option, const char *value, int isaReconfig)
217{
218 if (strcmp(option, "IOEngine") != 0)
219 return false;
220
221 if (isaReconfig)
222 /* silently ignore this */
223 return true;
224
225 if (!value) {
227 return false;
228 }
229
230 DiskIOModule *module = DiskIOModule::Find(value);
231
232 if (!module) {
234 return false;
235 }
236
237 changeIO(module);
238
239 return true;
240}
241
242void
244{
245 storeAppendPrintf(e, " IOEngine=%s", ioType);
246}
247
250{
251 ConfigOption *parentResult = SwapDir::getOptionTree();
252
253 if (currentIOOptions == nullptr)
254 currentIOOptions = new ConfigOptionVector();
255
256 currentIOOptions->options.push_back(parentResult);
257
258 currentIOOptions->options.push_back(new ConfigOptionAdapter<UFSSwapDir>(*const_cast<UFSSwapDir *>(this), &UFSSwapDir::optionIOParse, &UFSSwapDir::optionIODump));
259
260 if (ConfigOption *ioOptions = IO->io->getOptionTree())
261 currentIOOptions->options.push_back(ioOptions);
262
263 ConfigOption* result = currentIOOptions;
264
265 currentIOOptions = nullptr;
266
267 return result;
268}
269
270void
272{
273 debugs(47, 3, "Initialising UFS SwapDir engine.");
274 /* Parsing must be finished by now - force to NULL, don't delete */
275 currentIOOptions = nullptr;
276 static int started_clean_event = 0;
277 static const char *errmsg =
278 "\tFailed to verify one of the swap directories, Check cache.log\n"
279 "\tfor details. Run 'squid -z' to create swap directories\n"
280 "\tif needed, or if running Squid for the first time.";
281 IO->init();
282
283 if (verifyCacheDirs())
284 fatal(errmsg);
285
286 openLog();
287
288 rebuild();
289
290 if (!started_clean_event) {
291 eventAdd("UFS storeDirClean", CleanEvent, nullptr, 15.0, 1);
292 started_clean_event = 1;
293 }
294
295 (void) fsBlockSize(path, &fs.blksize);
296}
297
298void
300{
301 debugs(47, 3, "Creating swap space in " << path);
302 createDirectory(path, 0);
303 createSwapSubDirs();
304}
305
306Fs::Ufs::UFSSwapDir::UFSSwapDir(char const *aType, const char *anIOType) :
307 SwapDir(aType),
308 IO(nullptr),
309 fsdata(nullptr),
310 map(new FileMap()),
311 suggest(0),
312 l1(16),
313 l2(256),
314 swaplog_fd(-1),
315 currentIOOptions(new ConfigOptionVector()),
316 ioType(xstrdup(anIOType)),
317 cur_size(0),
319 rebuilding_(false)
320{
321 /* modulename is only set to disk modules that are built, by configure,
322 * so the Find call should never return NULL here.
323 */
324 IO = new Fs::Ufs::UFSStrategy(DiskIOModule::Find(anIOType)->createStrategy());
325}
326
328{
329 if (swaplog_fd > -1) {
330 file_close(swaplog_fd);
331 swaplog_fd = -1;
332 }
333 xfree(ioType);
334 delete map;
335 delete IO;
336 delete currentIOOptions;
337}
338
339void
341{
342 debugs(47, DBG_CRITICAL, "FILENO "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << e.swap_filen);
343 debugs(47, DBG_CRITICAL, "PATH " << fullPath(e.swap_filen, nullptr) );
344 e.dump(0);
345}
346
347bool
349{
350
351 struct stat sb;
352
353 if (::stat(fullPath(e.swap_filen, nullptr), &sb) < 0) {
354 debugs(47, DBG_CRITICAL, "WARNING: Missing swap file");
355 dumpEntry(e);
356 return true;
357 }
358
359 if ((off_t)e.swap_file_sz != sb.st_size) {
360 debugs(47, DBG_CRITICAL, "WARNING: Size Mismatch. Entry size: "
361 << e.swap_file_sz << ", file size: " << sb.st_size);
362 dumpEntry(e);
363 return true;
364 }
365
366 return false;
367}
368
369void
371{
372 int totl_kb = 0;
373 int free_kb = 0;
374 int totl_in = 0;
375 int free_in = 0;
376 int x;
377 storeAppendPrintf(&sentry, "First level subdirectories: %d\n", l1);
378 storeAppendPrintf(&sentry, "Second level subdirectories: %d\n", l2);
379 storeAppendPrintf(&sentry, "Maximum Size: %" PRIu64 " KB\n", maxSize() >> 10);
380 storeAppendPrintf(&sentry, "Current Size: %.2f KB\n", currentSize() / 1024.0);
381 storeAppendPrintf(&sentry, "Percent Used: %0.2f%%\n",
382 Math::doublePercent(currentSize(), maxSize()));
383 storeAppendPrintf(&sentry, "Filemap bits in use: %d of %d (%d%%)\n",
384 map->numFilesInMap(), map->capacity(),
385 Math::intPercent(map->numFilesInMap(), map->capacity()));
386 x = fsStats(path, &totl_kb, &free_kb, &totl_in, &free_in);
387
388 if (0 == x) {
389 storeAppendPrintf(&sentry, "Filesystem Space in use: %d/%d KB (%d%%)\n",
390 totl_kb - free_kb,
391 totl_kb,
392 Math::intPercent(totl_kb - free_kb, totl_kb));
393 storeAppendPrintf(&sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n",
394 totl_in - free_in,
395 totl_in,
396 Math::intPercent(totl_in - free_in, totl_in));
397 }
398
399 storeAppendPrintf(&sentry, "Flags:");
400
401 if (flags.selected)
402 storeAppendPrintf(&sentry, " SELECTED");
403
404 if (flags.read_only)
405 storeAppendPrintf(&sentry, " READ-ONLY");
406
407 storeAppendPrintf(&sentry, "\n");
408
409 IO->statfs(sentry);
410}
411
412void
414{
415 /* TODO: possible options for improvement;
416 *
417 * Note that too much aggression here is not good. It means that disk
418 * controller is getting a long queue of removals to act on, along
419 * with its regular I/O queue, and that client traffic is 'paused'
420 * and growing the network I/O queue as well while the scan happens.
421 * Possibly bad knock-on effects as Squid catches up on all that.
422 *
423 * Bug 2448 may have been a sign of what can wrong. At the least it
424 * provides a test case for aggression effects in overflow conditions.
425 *
426 * - base removal limit on space saved, instead of count ?
427 *
428 * - base removal rate on a traffic speed counter ?
429 * as the purge took up more time out of the second it would grow to
430 * a graceful full pause
431 *
432 * - pass out a value to cause another event to be scheduled immediately
433 * instead of waiting a whole second more ?
434 * knock on; schedule less if all caches are under low-water
435 *
436 * - admin configurable removal rate or count ?
437 * the current numbers are arbitrary, config helps with experimental
438 * trials and future-proofing the install base.
439 * we also have this indirectly by shifting the relative positions
440 * of low-, high- water and the total capacity limit.
441 */
442
443 // minSize() is swap_low_watermark in bytes
444 const uint64_t lowWaterSz = minSize();
445
446 if (currentSize() < lowWaterSz) {
447 debugs(47, 5, "space still available in " << path);
448 return;
449 }
450
451 /* We can't delete objects while rebuilding swap */
452 /* XXX each store should start maintaining as it comes online. */
454 // suppress the warnings, except once each minute
455 static int64_t lastWarn = 0;
456 int warnLevel = 3;
457 if (lastWarn+60 < squid_curtime) {
458 lastWarn = squid_curtime;
459 warnLevel = DBG_IMPORTANT;
460 }
461 debugs(47, warnLevel, StoreController::store_dirs_rebuilding << " cache_dir still rebuilding. Skip GC for " << path);
462 return;
463 }
464
465 // maxSize() is cache_dir total size in bytes
466 const uint64_t highWaterSz = ((maxSize() * Config.Swap.highWaterMark) / 100);
467
468 // f is percentage of 'gap' filled between low- and high-water.
469 // Used to reduced purge rate when between water markers, and
470 // to multiply it more aggressively the further above high-water
471 // it reaches. But in a graceful linear growth curve.
472 double f = 1.0;
473 if (highWaterSz > lowWaterSz) {
474 // might be equal. n/0 is bad.
475 f = (double) (currentSize() - lowWaterSz) / (highWaterSz - lowWaterSz);
476 }
477
478 // how deep to look for a single object that can be removed
479 int max_scan = (int) (f * 400.0 + 100.0);
480
481 // try to purge only this many objects this cycle.
482 int max_remove = (int) (f * 300.0 + 20.0);
483
484 /*
485 * This is kinda cheap, but so we need this priority hack?
486 */
487 debugs(47, 3, "f=" << f << ", max_scan=" << max_scan << ", max_remove=" << max_remove);
488
489 RemovalPurgeWalker *walker = repl->PurgeInit(repl, max_scan);
490
491 int removed = 0;
492 // only purge while above low-water
493 while (currentSize() >= lowWaterSz) {
494
495 // stop if we reached max removals for this cycle,
496 // Bug 2448 may be from this not clearing enough,
497 // but it predates the current algorithm so not sure
498 if (removed >= max_remove)
499 break;
500
501 StoreEntry *e = walker->Next(walker);
502
503 // stop if all objects are locked / in-use,
504 // or the cache is empty
505 if (!e)
506 break; /* no more objects */
507
508 ++removed;
509
510 e->release(true);
511 }
512
513 walker->Done(walker);
514 debugs(47, (removed ? 2 : 3), path <<
515 " removed " << removed << "/" << max_remove << " f=" <<
516 std::setprecision(4) << f << " max_scan=" << max_scan);
517
518 // what if cache is still over the high watermark ?
519 // Store::Maintain() schedules another purge in 1 second.
520}
521
522void
524{
525 debugs(47, 3, "referencing " << &e << " " <<
526 e.swap_dirn << "/" << e.swap_filen);
527
528 if (repl->Referenced)
529 repl->Referenced(repl, &e, &e.repl);
530}
531
532bool
534{
535 debugs(47, 3, "dereferencing " << &e << " " <<
536 e.swap_dirn << "/" << e.swap_filen);
537
538 if (repl->Dereferenced)
539 repl->Dereferenced(repl, &e, &e.repl);
540
541 return true; // keep e in the global store_table
542}
543
545Fs::Ufs::UFSSwapDir::createStoreIO(StoreEntry &e, StoreIOState::STIOCB * const aCallback, void * const callback_data)
546{
547 return IO->create(this, &e, aCallback, callback_data);
548}
549
551Fs::Ufs::UFSSwapDir::openStoreIO(StoreEntry &e, StoreIOState::STIOCB * const aCallback, void * const callback_data)
552{
553 return IO->open(this, &e, aCallback, callback_data);
554}
555
556int
558{
559 return map->testBit(filn);
560}
561
562void
564{
565 map->setBit(filn);
566}
567
568void
570{
571 /*
572 * We have to test the bit before calling clearBit as
573 * it doesn't do bounds checking and blindly assumes
574 * filn is a valid file number, but it might not be because
575 * the map is dynamic in size. Also clearing an already clear
576 * bit puts the map counter of-of-whack.
577 */
578
579 if (map->testBit(filn))
580 map->clearBit(filn);
581}
582
583int
585{
586 int fn;
587 fn = map->allocate(suggest);
588 map->setBit(fn);
589 suggest = fn + 1;
590 return fn;
591}
592
593char *
595{
596 LOCAL_ARRAY(char, fullfilename, MAXPATHLEN);
597 assert(0 <= subdirn && subdirn < l1);
598 snprintf(fullfilename, MAXPATHLEN, "%s/%02X", path, subdirn);
599 return fullfilename;
600}
601
602int
603Fs::Ufs::UFSSwapDir::createDirectory(const char *aPath, int should_exist)
604{
605 int created = 0;
606
607 struct stat st;
609
610 if (0 == ::stat(aPath, &st)) {
611 if (S_ISDIR(st.st_mode)) {
612 debugs(47, (should_exist ? 3 : DBG_IMPORTANT), aPath << " exists");
613 } else {
614 fatalf("Swap directory %s is not a directory.", aPath);
615 }
616 } else if (0 == mkdir(aPath, 0755)) {
617 debugs(47, (should_exist ? DBG_IMPORTANT : 3), aPath << " created");
618 created = 1;
619 } else {
620 int xerrno = errno;
621 fatalf("Failed to make swap directory %s: %s", aPath, xstrerr(xerrno));
622 }
623
624 return created;
625}
626
627bool
629{
630
631 struct stat sb;
632
633 if (::stat(aPath, &sb) < 0) {
634 int xerrno = errno;
635 debugs(47, DBG_CRITICAL, "ERROR: " << aPath << ": " << xstrerr(xerrno));
636 return false;
637 }
638
639 if (S_ISDIR(sb.st_mode) == 0) {
640 debugs(47, DBG_CRITICAL, "WARNING: " << aPath << " is not a directory");
641 return false;
642 }
643
644 return true;
645}
646
647bool
649{
650 if (!pathIsDirectory(path))
651 return true;
652
653 for (int j = 0; j < l1; ++j) {
654 char const *aPath = swapSubDir(j);
655
656 if (!pathIsDirectory(aPath))
657 return true;
658 }
659
660 return false;
661}
662
663void
665{
666 LOCAL_ARRAY(char, name, MAXPATHLEN);
667
668 for (int i = 0; i < l1; ++i) {
669 snprintf(name, MAXPATHLEN, "%s/%02X", path, i);
670
671 int should_exist;
672
673 if (createDirectory(name, 0))
674 should_exist = 0;
675 else
676 should_exist = 1;
677
678 debugs(47, DBG_IMPORTANT, "Making directories in " << name);
679
680 for (int k = 0; k < l2; ++k) {
681 snprintf(name, MAXPATHLEN, "%s/%02X/%02X", path, i, k);
682 createDirectory(name, should_exist);
683 }
684 }
685}
686
687SBuf
688Fs::Ufs::UFSSwapDir::logFile(char const *ext) const
689{
690 SBuf lpath;
691
692 if (Config.Log.swap) {
693 static char pathtmp[MAXPATHLEN];
694 char *pathtmp2 = xstrncpy(pathtmp, path, MAXPATHLEN - 64);
695
696 // replace all '/' with '.'
697 while ((pathtmp2 = strchr(pathtmp2, '/')))
698 *pathtmp2 = '.';
699
700 // remove any trailing '.' characters
701 int pos = strlen(pathtmp);
702 while (pos && pathtmp[pos-1] == '.')
703 pathtmp[--pos] = '\0';
704
705 // remove any prefix '.' characters
706 for (pathtmp2 = pathtmp; *pathtmp2 == '.'; ++pathtmp2);
707 // replace a '%s' (if any) in the config string
708 // with the resulting pathtmp2 string
709 lpath.appendf(Config.Log.swap, pathtmp2);
710
711 // is pathtmp2 was NOT injected, append numeric file extension
712 if (lpath.cmp(Config.Log.swap) == 0) {
713 lpath.append(".", 1);
714 lpath.appendf("%02d", index);
715 }
716 } else {
717 lpath.append(path);
718 lpath.append("/swap.state", 11);
719 }
720
721 lpath.append(ext); // may be nil, that is okay.
722
723 return lpath;
724}
725
726void
728{
729 if (!IamWorkerProcess())
730 return;
731
732 assert(NumberOfUFSDirs || !UFSDirToGlobalDirMapping);
733 ++NumberOfUFSDirs;
734 assert(NumberOfUFSDirs <= Config.cacheSwap.n_configured);
735
736 if (rebuilding_) { // we did not close the temporary log used for rebuilding
737 assert(swaplog_fd >= 0);
738 return;
739 }
740
741 SBuf logPath(logFile());
742 swaplog_fd = file_open(logPath.c_str(), O_WRONLY | O_CREAT | O_BINARY);
743
744 if (swaplog_fd < 0) {
745 int xerrno = errno;
746 debugs(50, DBG_IMPORTANT, "ERROR: opening swap log " << logPath << ": " << xstrerr(xerrno));
747 fatal("UFSSwapDir::openLog: Failed to open swap log.");
748 }
749
750 debugs(50, 3, "Cache Dir #" << index << " log opened on FD " << swaplog_fd);
751}
752
753void
755{
756 if (swaplog_fd < 0) /* not open */
757 return;
758
759 --NumberOfUFSDirs;
760 assert(NumberOfUFSDirs >= 0);
761 if (!NumberOfUFSDirs)
762 safe_free(UFSDirToGlobalDirMapping);
763
764 if (rebuilding_) // we cannot close the temporary log used for rebuilding
765 return;
766
767 file_close(swaplog_fd);
768
769 debugs(47, 3, "Cache Dir #" << index << " log closed on FD " << swaplog_fd);
770
771 swaplog_fd = -1;
772}
773
774bool
776{
777 return anInt < l1;
778}
779
780bool
782{
783 return anInt < l2;
784}
785
788 sfileno file_number,
789 uint64_t swap_file_sz,
790 time_t expires,
791 time_t timestamp,
792 time_t lastref,
793 time_t lastmod,
794 uint32_t refcount,
795 uint16_t newFlags,
796 int)
797{
798 StoreEntry *e = nullptr;
799 debugs(47, 5, storeKeyText(key) <<
800 ", fileno="<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << file_number);
801 /* if you call this you'd better be sure file_number is not
802 * already in use! */
803 e = new StoreEntry();
806 e->attachToDisk(index, file_number, SWAPOUT_DONE);
807 e->swap_file_sz = swap_file_sz;
808 e->lastref = lastref;
809 e->timestamp = timestamp;
810 e->expires = expires;
811 e->lastModified(lastmod);
812 e->refcount = refcount;
813 e->flags = newFlags;
816 mapBitSet(e->swap_filen);
817 cur_size += fs.blksize * sizeInBlocks(e->swap_file_sz);
819 e->hashInsert(key);
820 replacementAdd (e);
821 return e;
822}
823
824void
826{
827 eventAdd("storeRebuild", Fs::Ufs::RebuildState::RebuildStep, new Fs::Ufs::RebuildState(this), 0.0, 1);
828}
829
830void
832{
833 assert(rebuilding_);
834 rebuilding_ = false;
835
836 SBuf swaplog_path(logFile()); // where the swaplog should be
837 SBuf tmp_path(logFile(".new"));
838
839 file_close(swaplog_fd);
840
841 if (!FileRename(tmp_path, swaplog_path)) {
842 fatalf("Failed to rename log file " SQUIDSBUFPH " to " SQUIDSBUFPH, SQUIDSBUFPRINT(tmp_path), SQUIDSBUFPRINT(swaplog_path));
843 }
844
845 int fd = file_open(swaplog_path.c_str(), O_WRONLY | O_CREAT | O_BINARY);
846
847 if (fd < 0) {
848 int xerrno = errno;
849 debugs(50, DBG_IMPORTANT, "ERROR: " << swaplog_path << ": " << xstrerr(xerrno));
850 fatalf("Failed to open swap log " SQUIDSBUFPH, SQUIDSBUFPRINT(swaplog_path));
851 }
852
853 swaplog_fd = fd;
854 debugs(47, 3, "Cache Dir #" << index << " log opened on FD " << fd);
855}
856
857FILE *
858Fs::Ufs::UFSSwapDir::openTmpSwapLog(int *clean_flag, int *zero_flag)
859{
860 assert(!rebuilding_);
861
862 SBuf swaplog_path(logFile());
863 SBuf clean_path(logFile(".last-clean"));
864 SBuf new_path(logFile(".new"));
865
866 struct stat log_sb;
867
868 struct stat clean_sb;
869
870 if (::stat(swaplog_path.c_str(), &log_sb) < 0) {
871 debugs(47, DBG_IMPORTANT, "Cache Dir #" << index << ": No log file");
872 return nullptr;
873 }
874
875 *zero_flag = log_sb.st_size == 0 ? 1 : 0;
876 /* close the existing write-only FD */
877
878 if (swaplog_fd >= 0)
879 file_close(swaplog_fd);
880
881 /* open a write-only FD for the new log */
882 int fd = file_open(new_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
883 if (fd < 0) {
884 int xerrno = errno;
885 debugs(50, DBG_IMPORTANT, "ERROR: while opening swap log" << new_path << ": " << xstrerr(xerrno));
886 fatalf("Failed to open swap log " SQUIDSBUFPH, SQUIDSBUFPRINT(new_path));
887 }
888
889 swaplog_fd = fd;
890 rebuilding_ = true;
891
892 {
893 const StoreSwapLogHeader header;
894 MemBuf buf;
895 buf.init(header.record_size, header.record_size);
896 buf.append(reinterpret_cast<const char*>(&header), sizeof(header));
897 // Pad to keep in sync with UFSSwapDir::writeCleanStart().
898 memset(buf.space(), 0, header.gapSize());
899 buf.appended(header.gapSize());
900 file_write(swaplog_fd, -1, buf.content(), buf.contentSize(),
901 nullptr, nullptr, buf.freeFunc());
902 }
903
904 /* open a read-only stream of the old log */
905 FILE *fp = fopen(swaplog_path.c_str(), "rb");
906 if (!fp) {
907 int xerrno = errno;
908 debugs(50, DBG_CRITICAL, "ERROR: while opening " << swaplog_path << ": " << xstrerr(xerrno));
909 fatalf("Failed to open swap log for reading " SQUIDSBUFPH, SQUIDSBUFPRINT(swaplog_path));
910 }
911
912 memset(&clean_sb, '\0', sizeof(struct stat));
913
914 if (::stat(clean_path.c_str(), &clean_sb) < 0)
915 *clean_flag = 0;
916 else if (clean_sb.st_mtime < log_sb.st_mtime)
917 *clean_flag = 0;
918 else
919 *clean_flag = 1;
920
921 safeunlink(clean_path.c_str(), 1);
922
923 return fp;
924}
925
926/*
927 * Begin the process to write clean cache state. For AUFS this means
928 * opening some log files and allocating write buffers. Return 0 if
929 * we succeed, and assign the 'func' and 'data' return pointers.
930 */
931int
933{
934 UFSCleanLog *state = new UFSCleanLog(this);
935 StoreSwapLogHeader header;
936#if HAVE_FCHMOD
937
938 struct stat sb;
939#endif
940
941 cleanLog = nullptr;
942 state->cur = logFile();
943 state->newLog = logFile(".clean");
944 state->fd = file_open(state->newLog.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
945
946 if (state->fd < 0) {
947 delete state;
948 return -1;
949 }
950
951 state->cln = state->cur;
952 state->cln.append(".last-clean");
953 state->outbuf = (char *)xcalloc(CLEAN_BUF_SZ, 1);
954 state->outbuf_offset = 0;
955 /*copy the header */
956 memcpy(state->outbuf, &header, sizeof(StoreSwapLogHeader));
957 // Leave a gap to keep in sync with UFSSwapDir::openTmpSwapLog().
958 memset(state->outbuf + sizeof(StoreSwapLogHeader), 0, header.gapSize());
959 state->outbuf_offset += header.record_size;
960
961 state->walker = repl->WalkInit(repl);
962 ::unlink(state->cln.c_str());
963 debugs(47, 3, "opened " << state->newLog << ", FD " << state->fd);
964#if HAVE_FCHMOD
965
966 if (::stat(state->cur.c_str(), &sb) == 0)
967 fchmod(state->fd, sb.st_mode);
968
969#endif
970
971 cleanLog = state;
972 return 0;
973}
974
975void
977{
978 UFSCleanLog *state = (UFSCleanLog *)cleanLog;
979 int fd;
980
981 if (nullptr == state)
982 return;
983
984 if (state->fd < 0)
985 return;
986
987 state->walker->Done(state->walker);
988
989 if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) {
990 int xerrno = errno;
991 debugs(50, DBG_CRITICAL, MYNAME << state->newLog << ": write: " << xstrerr(xerrno));
992 debugs(50, DBG_CRITICAL, MYNAME << "Current swap logfile not replaced.");
993 file_close(state->fd);
994 state->fd = -1;
995 ::unlink(state->newLog.c_str());
996 }
997
998 safe_free(state->outbuf);
999 /*
1000 * You can't rename open files on Microsoft "operating systems"
1001 * so we have to close before renaming.
1002 */
1003 closeLog();
1004 /* save the fd value for a later test */
1005 fd = state->fd;
1006 /* rename */
1007
1008 if (state->fd >= 0) {
1009#if _SQUID_OS2_ || _SQUID_WINDOWS_
1010 file_close(state->fd);
1011 state->fd = -1;
1012#endif
1013
1014 FileRename(state->newLog, state->cur);
1015 // TODO handle rename errors
1016 }
1017
1018 /* touch a timestamp file if we're not still validating */
1020 (void) 0;
1021 else if (fd < 0)
1022 (void) 0;
1023 else
1024 file_close(file_open(state->cln.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY));
1025
1026 /* close */
1027 if (state->fd >= 0)
1028 file_close(state->fd);
1029
1030 state->fd = -1;
1031
1032 delete state;
1033
1034 cleanLog = nullptr;
1035}
1036
1038int
1040{
1041 static int swap_index = 0;
1042 int i;
1043 int j = 0;
1044 int n = 0;
1045
1046 if (!NumberOfUFSDirs)
1047 return 0; // probably in the middle of reconfiguration
1048
1049 if (nullptr == UFSDirToGlobalDirMapping) {
1050 SwapDir *sd;
1051 /*
1052 * Initialize the little array that translates UFS cache_dir
1053 * number into the Config.cacheSwap.swapDirs array index.
1054 */
1055 UFSDirToGlobalDirMapping = (int *)xcalloc(NumberOfUFSDirs, sizeof(*UFSDirToGlobalDirMapping));
1056
1057 for (i = 0, n = 0; i < Config.cacheSwap.n_configured; ++i) {
1058 /* This is bogus, the controller should just clean each instance once */
1059 sd = dynamic_cast <SwapDir *>(INDEXSD(i));
1060
1061 if (!UFSSwapDir::IsUFSDir(sd))
1062 continue;
1063
1064 UFSSwapDir *usd = dynamic_cast<UFSSwapDir *>(sd);
1065
1066 assert (usd);
1067
1068 UFSDirToGlobalDirMapping[n] = i;
1069 ++n;
1070
1071 j += (usd->l1 * usd->l2);
1072 }
1073
1074 assert(n == NumberOfUFSDirs);
1075 /*
1076 * Start the commonUfsDirClean() swap_index with a random
1077 * value. j equals the total number of UFS level 2
1078 * swap directories
1079 */
1080 static std::mt19937 mt(RandomSeed32());
1081 std::uniform_int_distribution<> dist(0, j);
1082 swap_index = dist(mt);
1083 }
1084
1085 /* if the rebuild is finished, start cleaning directories. */
1087 n = DirClean(swap_index);
1088 ++swap_index;
1089 }
1090
1091 return n;
1092}
1093
1094void
1096{
1097 const int n = HandleCleanEvent();
1098 eventAdd("storeDirClean", CleanEvent, nullptr,
1099 15.0 * exp(-0.25 * n), 1);
1100}
1101
1102bool
1104{
1105 UFSSwapDir *mySD = dynamic_cast<UFSSwapDir *>(sd);
1106 return (mySD != nullptr) ;
1107}
1108
1109/*
1110 * XXX: this is broken - it assumes all cache dirs use the same
1111 * l1 and l2 scheme. -RBC 20021215. Partial fix is in place -
1112 * if not UFSSwapDir return 0;
1113 */
1114bool
1116{
1117 int D1, D2;
1118 int L1, L2;
1119 int filn = fn;
1121 assert (UFSSwapDir::IsUFSDir (dynamic_cast<SwapDir *>(INDEXSD(F0))));
1122 UFSSwapDir *sd = dynamic_cast<UFSSwapDir *>(INDEXSD(F0));
1123
1124 if (!sd)
1125 return 0;
1126
1127 L1 = sd->l1;
1128
1129 L2 = sd->l2;
1130
1131 D1 = ((filn / L2) / L2) % L1;
1132
1133 if (F1 != D1)
1134 return 0;
1135
1136 D2 = (filn / L2) % L2;
1137
1138 if (F2 != D2)
1139 return 0;
1140
1141 return 1;
1142}
1143
1144int
1146{
1147 if (filn < 0)
1148 return 0;
1149
1150 /*
1151 * If flag is set it means out-of-range file number should
1152 * be considered invalid.
1153 */
1154 if (flag)
1155 if (filn > map->capacity())
1156 return 0;
1157
1158 return 1;
1159}
1160
1161void
1163{
1164 debugs(79, 3, "unlinking fileno " << std::setfill('0') <<
1165 std::hex << std::uppercase << std::setw(8) << f << " '" <<
1166 fullPath(f,nullptr) << "'");
1167 /* commonUfsDirMapBitReset(this, f); */
1168 IO->unlinkFile(fullPath(f,nullptr));
1169}
1170
1171bool
1173{
1174 // unlinkd may be useful only in workers
1175 return IamWorkerProcess() && IO->io->unlinkdUseful();
1176}
1177
1178void
1180{
1181 debugs(79, 3, e);
1182 if (e.locked()) // somebody else may still be using this file
1183 return; // nothing to do: our get() always returns nil
1184
1185 if (!e.hasDisk())
1186 return; // see evictIfFound()
1187
1188 // Since these fields grow only after swap out ends successfully,
1189 // do not decrement them for e.swappingOut() and e.swapoutFailed().
1190 if (e.swappedOut()) {
1191 cur_size -= fs.blksize * sizeInBlocks(e.swap_file_sz);
1193 }
1194 replacementRemove(&e);
1195 mapBitReset(e.swap_filen);
1197 e.detachFromDisk();
1198}
1199
1200void
1202{
1203 // UFS disk entries always have (attached) StoreEntries so if we got here,
1204 // the entry is not cached on disk and there is nothing for us to do.
1205}
1206
1207void
1209{
1210 debugs(47, 4, "added node " << e << " to dir " << index);
1211 repl->Add(repl, e, &e->repl);
1212}
1213
1214void
1216{
1217 assert(e->hasDisk());
1218
1220
1221 assert (dynamic_cast<UFSSwapDir *>(SD.getRaw()) == this);
1222
1223 debugs(47, 4, "remove node " << e << " from dir " << index);
1224
1225 repl->Remove(repl, e, &e->repl);
1226}
1227
1228void
1230{
1231 storeAppendPrintf(&entry, " %" PRIu64 " %d %d", maxSize() >> 20, l1, l2);
1232 dumpOptions(&entry);
1233}
1234
1235char *
1236Fs::Ufs::UFSSwapDir::fullPath(sfileno filn, char *fullpath) const
1237{
1238 LOCAL_ARRAY(char, fullfilename, MAXPATHLEN);
1239 int L1 = l1;
1240 int L2 = l2;
1241
1242 if (!fullpath)
1243 fullpath = fullfilename;
1244
1245 fullpath[0] = '\0';
1246
1247 snprintf(fullpath, MAXPATHLEN, "%s/%02X/%02X/%08X",
1248 path,
1249 ((filn / L2) / L2) % L1,
1250 (filn / L2) % L2,
1251 filn);
1252
1253 return fullpath;
1254}
1255
1256int
1258{
1259 return IO->callback();
1260}
1261
1262void
1264{
1265 IO->sync();
1266}
1267
1268void
1270{
1271 cur_size += fs.blksize * sizeInBlocks(e.swap_file_sz);
1273}
1274
1275void
1277{
1278 debugs(47, 5, entry);
1279 // rely on the expected eventual StoreEntry::release(), evictCached(), or
1280 // a similar call to call unlink(), detachFromDisk(), etc. for the entry.
1281}
1282
1283void
1285{
1286 if (swaplog_fd < 0) {
1287 debugs(36, 5, "cannot log " << e << " in the middle of reconfiguration");
1288 return;
1289 }
1290
1292 s->op = (char) op;
1293 s->swap_filen = e.swap_filen;
1294 s->timestamp = e.timestamp;
1295 s->lastref = e.lastref;
1296 s->expires = e.expires;
1297 s->lastmod = e.lastModified();
1299 s->refcount = e.refcount;
1300 s->flags = e.flags;
1301 memcpy(s->key, e.key, SQUID_MD5_DIGEST_LENGTH);
1302 s->finalize();
1303 file_write(swaplog_fd,
1304 -1,
1305 s,
1306 sizeof(StoreSwapLogData),
1307 nullptr,
1308 nullptr,
1309 FreeObject);
1310}
1311
1312int
1314{
1315 DIR *dir_pointer = nullptr;
1316 int files[20];
1317 int swapfileno;
1318 int fn; /* same as swapfileno, but with dirn bits set */
1319 int n = 0;
1320 int k = 0;
1321 int N0, N1, N2;
1322 int D0, D1, D2;
1323 UFSSwapDir *SD;
1324 N0 = NumberOfUFSDirs;
1325 D0 = UFSDirToGlobalDirMapping[swap_index % N0];
1326 SD = dynamic_cast<UFSSwapDir *>(INDEXSD(D0));
1327 assert (SD);
1328 N1 = SD->l1;
1329 D1 = (swap_index / N0) % N1;
1330 N2 = SD->l2;
1331 D2 = ((swap_index / N0) / N1) % N2;
1332
1333 SBuf p1;
1334 p1.appendf("%s/%02X/%02X", SD->path, D1, D2);
1335 debugs(36, 3, "Cleaning directory " << p1);
1336 dir_pointer = opendir(p1.c_str());
1337
1338 if (!dir_pointer) {
1339 int xerrno = errno;
1340 if (xerrno == ENOENT) {
1341 debugs(36, DBG_CRITICAL, MYNAME << "WARNING: Creating " << p1);
1342 if (mkdir(p1.c_str(), 0777) == 0)
1343 return 0;
1344 }
1345
1346 debugs(50, DBG_CRITICAL, MYNAME << p1 << ": " << xstrerr(xerrno));
1347 safeunlink(p1.c_str(), 1);
1348 return 0;
1349 }
1350
1351 dirent_t *de;
1352 while ((de = readdir(dir_pointer)) != nullptr && k < 20) {
1353 if (sscanf(de->d_name, "%X", &swapfileno) != 1)
1354 continue;
1355
1356 fn = swapfileno; /* XXX should remove this cruft ! */
1357
1358 if (SD->validFileno(fn, 1))
1359 if (SD->mapBitTest(fn))
1360 if (UFSSwapDir::FilenoBelongsHere(fn, D0, D1, D2))
1361 continue;
1362
1363 files[k] = swapfileno;
1364 ++k;
1365 }
1366
1367 closedir(dir_pointer);
1368
1369 if (k == 0)
1370 return 0;
1371
1372 qsort(files, k, sizeof(int), rev_int_sort);
1373
1374 if (k > 10)
1375 k = 10;
1376
1377 for (n = 0; n < k; ++n) {
1378 debugs(36, 3, "Cleaning file "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << files[n]);
1379 SBuf p2(p1);
1380 p2.appendf("/%08X", files[n]);
1381 safeunlink(p2.c_str(), 0);
1383 }
1384
1385 debugs(36, 3, "Cleaned " << k << " unused files from " << p1);
1386 return k;
1387}
1388
int size
Definition: ModDevPoll.cc:75
int GetInteger(void)
Definition: Parsing.cc:148
time_t squid_curtime
Definition: stub_libtime.cc:20
RemovalPolicy * createRemovalPolicy(RemovalPolicySettings *settings)
Definition: store.cc:1657
#define SQUIDSBUFPH
Definition: SBuf.h:31
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
class SquidConfig Config
Definition: SquidConfig.cc:12
#define INDEXSD(i)
Definition: SquidConfig.h:74
StatCounters statCounter
Definition: StatCounters.cc:12
static int rev_int_sort(const void *A, const void *B)
Definition: UFSSwapDir.cc:134
#define CLEAN_BUF_SZ
Definition: UFSSwapDir.cc:11
static void FreeObject(void *address)
Definition: UFSSwapDir.cc:127
#define assert(EX)
Definition: assert.h:17
std::mt19937::result_type RandomSeed32()
Definition: Random.cc:13
void self_destruct(void)
Definition: cache_cf.cc:277
static DiskIOModule * Find(char const *type)
virtual char const * type() const =0
virtual DiskIOStrategy * createStrategy()=0
static EVH RebuildStep
Definition: RebuildState.h:29
virtual int load()
Definition: UFSStrategy.cc:25
virtual bool shedLoad()
Definition: UFSStrategy.cc:19
void openLog() override
Definition: UFSSwapDir.cc:727
bool pathIsDirectory(const char *path) const
Definition: UFSSwapDir.cc:628
void sync() override
prepare for shutdown
Definition: UFSSwapDir.cc:1263
static EVH CleanEvent
Definition: UFSSwapDir.h:130
void finalizeSwapoutFailure(StoreEntry &) override
abort the failed swapout that has been already noticed by Store
Definition: UFSSwapDir.cc:1276
bool unlinkdUseful() const override
whether SwapDir may benefit from unlinkd
Definition: UFSSwapDir.cc:1172
int callback() override
called once every main loop iteration; TODO: Move to UFS code.
Definition: UFSSwapDir.cc:1257
void replacementAdd(StoreEntry *e)
Definition: UFSSwapDir.cc:1208
void evictIfFound(const cache_key *) override
Definition: UFSSwapDir.cc:1201
UFSSwapDir(char const *aType, const char *aModuleType)
Definition: UFSSwapDir.cc:306
StoreEntry * addDiskRestore(const cache_key *key, sfileno file_number, uint64_t swap_file_sz, time_t expires, time_t timestamp, time_t lastref, time_t lastmod, uint32_t refcount, uint16_t flags, int clean)
Definition: UFSSwapDir.cc:787
void mapBitReset(sfileno filn)
Definition: UFSSwapDir.cc:569
void optionIODump(StoreEntry *e) const
Definition: UFSSwapDir.cc:243
int createDirectory(const char *path, int)
Definition: UFSSwapDir.cc:603
void changeIO(DiskIOModule *)
Definition: UFSSwapDir.cc:193
~UFSSwapDir() override
Definition: UFSSwapDir.cc:327
void reconfigure() override
Definition: UFSSwapDir.cc:172
void finalizeSwapoutSuccess(const StoreEntry &) override
finalize the successful swapout that has been already noticed by Store
Definition: UFSSwapDir.cc:1269
void parse(int index, char *path) override
Definition: UFSSwapDir.cc:179
void statfs(StoreEntry &) const override
Definition: UFSSwapDir.cc:370
static int DirClean(int swap_index)
Definition: UFSSwapDir.cc:1313
SBuf logFile(char const *ext=nullptr) const
Definition: UFSSwapDir.cc:688
FILE * openTmpSwapLog(int *clean_flag, int *zero_flag)
Definition: UFSSwapDir.cc:858
void create() override
create system resources needed for this store to operate in the future
Definition: UFSSwapDir.cc:299
void mapBitSet(sfileno filn)
Definition: UFSSwapDir.cc:563
void evictCached(StoreEntry &) override
Definition: UFSSwapDir.cc:1179
void reference(StoreEntry &) override
somebody needs this entry (many cache replacement policies need to know)
Definition: UFSSwapDir.cc:523
char * swapSubDir(int subdirn) const
Definition: UFSSwapDir.cc:594
static int * UFSDirToGlobalDirMapping
Definition: UFSSwapDir.h:127
void init() override
Definition: UFSSwapDir.cc:271
int validFileno(sfileno filn, int flag) const
Definition: UFSSwapDir.cc:1145
void replacementRemove(StoreEntry *e)
Definition: UFSSwapDir.cc:1215
int mapBitTest(sfileno filn)
Definition: UFSSwapDir.cc:557
Fs::Ufs::UFSStrategy * IO
Definition: UFSSwapDir.h:83
void dumpEntry(StoreEntry &) const
Definition: UFSSwapDir.cc:340
bool dereference(StoreEntry &) override
Definition: UFSSwapDir.cc:533
bool doubleCheck(StoreEntry &) override
Definition: UFSSwapDir.cc:348
void maintain() override
perform regular periodic maintenance; TODO: move to UFSSwapDir::Maintain
Definition: UFSSwapDir.cc:413
static bool IsUFSDir(SwapDir *sd)
Definition: UFSSwapDir.cc:1103
ConfigOption * getOptionTree() const override
Definition: UFSSwapDir.cc:249
static int NumberOfUFSDirs
Definition: UFSSwapDir.h:126
StoreIOState::Pointer createStoreIO(StoreEntry &, StoreIOState::STIOCB *, void *) override
Definition: UFSSwapDir.cc:545
StoreIOState::Pointer openStoreIO(StoreEntry &, StoreIOState::STIOCB *, void *) override
Definition: UFSSwapDir.cc:551
void logEntry(const StoreEntry &e, int op) const override
Definition: UFSSwapDir.cc:1284
void dump(StoreEntry &) const override
Definition: UFSSwapDir.cc:1229
static bool FilenoBelongsHere(int fn, int cachedir, int level1dir, int level2dir)
Definition: UFSSwapDir.cc:1115
char * fullPath(sfileno, char *) const
Definition: UFSSwapDir.cc:1236
int writeCleanStart() override
Definition: UFSSwapDir.cc:932
void closeLog() override
Definition: UFSSwapDir.cc:754
static int HandleCleanEvent()
safely cleans a few unused files if possible
Definition: UFSSwapDir.cc:1039
void unlinkFile(sfileno f)
Definition: UFSSwapDir.cc:1162
bool validL1(int) const
Definition: UFSSwapDir.cc:775
bool optionIOParse(char const *option, const char *value, int reconfiguring)
Definition: UFSSwapDir.cc:216
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: UFSSwapDir.cc:114
bool validL2(int) const
Definition: UFSSwapDir.cc:781
void writeCleanDone() override
Definition: UFSSwapDir.cc:976
Definition: MemBuf.h:24
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
char * space()
returns buffer after data; does not check space existence
Definition: MemBuf.h:57
FREE * freeFunc()
Definition: MemBuf.cc:303
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
char * content()
start of the added data
Definition: MemBuf.h:41
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
void appended(mb_size_t sz)
updates content size after external append
Definition: MemBuf.cc:226
C * getRaw() const
Definition: RefCount.h:89
const StoreEntry *(* Next)(RemovalPolicyWalker *walker)
Definition: RemovalPolicy.h:62
void(* Done)(RemovalPolicyWalker *walker)
Definition: RemovalPolicy.h:63
void(* Done)(RemovalPurgeWalker *walker)
Definition: RemovalPolicy.h:75
StoreEntry *(* Next)(RemovalPurgeWalker *walker)
Definition: RemovalPolicy.h:74
Definition: SBuf.h:94
const char * c_str()
Definition: SBuf.cc:516
SBuf & appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:229
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:275
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
char * swap
Definition: SquidConfig.h:185
RemovalPolicySettings * replPolicy
Definition: SquidConfig.h:99
Store::DiskConfig cacheSwap
Definition: SquidConfig.h:423
struct SquidConfig::@98 Log
int highWaterMark
Definition: SquidConfig.h:85
struct SquidConfig::@91 Swap
struct StatCounters::@131 swap
void hashInsert(const cache_key *)
Definition: store.cc:410
bool swappedOut() const
whether the entire entry is now on disk (possibly marked for deletion)
Definition: Store.h:136
uint16_t flags
Definition: Store.h:232
sdirno swap_dirn
Definition: Store.h:238
int locked() const
Definition: Store.h:146
void dump(int debug_lvl) const
Definition: store.cc:1485
time_t expires
Definition: Store.h:226
void lastModified(const time_t when)
Definition: Store.h:176
void release(const bool shareable=false)
Definition: store.cc:1132
void detachFromDisk()
Definition: store.cc:1940
bool hasDisk(const sdirno dirn=-1, const sfileno filen=-1) const
Definition: store.cc:1915
time_t timestamp
Definition: Store.h:224
sfileno swap_filen
unique ID inside a cache_dir for swapped out entries; -1 for others
Definition: Store.h:236
void attachToDisk(const sdirno, const sfileno, const swap_status_t)
Definition: store.cc:1926
RemovalPolicyNode repl
Definition: Store.h:222
ping_status_t ping_status
Definition: Store.h:242
store_status_t store_status
Definition: Store.h:244
time_t lastref
Definition: Store.h:225
uint64_t swap_file_sz
Definition: Store.h:230
uint16_t refcount
Definition: Store.h:231
void setMemStatus(mem_status_t)
Definition: store.cc:1510
void STIOCB(void *their_data, int errflag, StoreIOState::Pointer self)
Definition: StoreIOState.h:39
unsigned char key[SQUID_MD5_DIGEST_LENGTH]
SwappedTime timestamp
void finalize()
call this before storing the log entry
size_t gapSize() const
number of bytes after the log header before the first log entry
static int store_dirs_rebuilding
the number of cache_dirs being rebuilt; TODO: move to Disks::Rebuilding
Definition: Controller.h:134
manages a single cache_dir
Definition: Disk.h:22
char * path
Definition: Disk.h:102
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
CleanLog * cleanLog
Definition: Disk.h:140
virtual ConfigOption * getOptionTree() const
Definition: Disk.cc:258
char * outbuf
Definition: UFSSwapDir.cc:57
off_t outbuf_offset
Definition: UFSSwapDir.cc:58
SwapDir * sd
Definition: UFSSwapDir.cc:61
UFSCleanLog(SwapDir *aSwapDir)
Definition: UFSSwapDir.cc:46
void write(StoreEntry const &) override
"write" an entry to the clean log file.
Definition: UFSSwapDir.cc:76
const StoreEntry * nextEntry() override
Get the next entry that is a candidate for clean log writing.
Definition: UFSSwapDir.cc:65
RemovalPolicyWalker * walker
Definition: UFSSwapDir.cc:60
#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 EBIT_CLR(flag, bit)
Definition: defines.h:68
#define O_BINARY
Definition: defines.h:136
@ NOT_IN_MEMORY
Definition: enums.h:35
@ PING_NONE
Has not considered whether to send ICP queries to peers yet.
Definition: enums.h:41
@ SWAPOUT_DONE
Definition: enums.h:64
@ ENTRY_VALIDATED
Definition: enums.h:113
@ STORE_OK
Definition: enums.h:50
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:107
void fatal(const char *message)
Definition: fatal.cc:28
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
int FD_WRITE_METHOD(int fd, const char *buf, int len)
Definition: fde.h:200
int file_open(const char *path, int mode)
Definition: fs_io.cc:45
bool FileRename(const SBuf &from, const SBuf &to)
Definition: fs_io.cc:480
void safeunlink(const char *s, int quiet)
Definition: fs_io.cc:469
int fsBlockSize(const char *path, int *blksize)
Definition: fs_io.cc:503
void file_close(int fd)
Definition: fs_io.cc:73
int fsStats(const char *path, int *totl_kb, int *free_kb, int *totl_in, int *free_in)
Definition: fs_io.cc:527
void file_write(int fd, off_t file_offset, void const *ptr_to_buf, int len, DWCB *handle, void *handle_data, FREE *free_func)
Definition: fs_io.cc:326
int n_disk_objects
int reconfiguring
static uint32 A
Definition: md4.c:43
static uint32 B
Definition: md4.c:43
#define F1(x, y, z)
Definition: md5.c:166
#define F2(x, y, z)
Definition: md5.c:167
#define SQUID_MD5_DIGEST_LENGTH
Definition: md5.h:66
int intPercent(const int a, const int b)
Definition: SquidMath.cc:13
double doublePercent(const double, const double)
Definition: SquidMath.cc:25
#define xfree
#define xstrdup
#define LOCAL_ARRAY(type, name, size)
Definition: squid.h:68
static struct stat sb
Definition: squidclient.cc:71
#define MAXPATHLEN
Definition: stdio.h:62
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
const char * storeKeyText(const cache_key *key)
void EVH void double
Definition: stub_event.cc:16
int unsigned int
Definition: stub_fd.cc:19
time_t getCurrentTime() STUB_RETVAL(0) int tvSubUsec(struct timeval
bool IamWorkerProcess()
whether the current process handles HTTP transactions and such
Definition: stub_tools.cc:47
@ SWAP_LOG_ADD
Definition: swap_log_op.h:14
#define PRIu64
Definition: types.h:114
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
#define safe_free(x)
Definition: xalloc.h:73
const char * xstrerr(int error)
Definition: xstrerror.cc:83
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors