]> git.ipfire.org Git - thirdparty/squid.git/blame - src/fs/ufs/store_dir_ufs.cc
Fix for --enable-cpu-profiling mode. Do not change PROF_start() arg.
[thirdparty/squid.git] / src / fs / ufs / store_dir_ufs.cc
CommitLineData
cd748f27 1
2/*
b3fb9070 3 * $Id: store_dir_ufs.cc,v 1.79 2007/04/12 23:51:58 wessels Exp $
cd748f27 4 *
5 * DEBUG: section 47 Store Directory Routines
6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
cd748f27 9 * ----------------------------------------------------------
10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
cd748f27 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36#include "squid.h"
e6ccf245 37#include "Store.h"
528b2c61 38#include "fde.h"
4d6d905e 39#include "ufscommon.h"
51ee7c82 40#include "StoreSwapLogData.h"
b9ae18aa 41#include "ConfigOption.h"
42#include "DiskIO/DiskIOStrategy.h"
43#include "DiskIO/DiskIOModule.h"
c8f4eac4 44#include "Parsing.h"
985c86bc 45#include "SquidTime.h"
cd748f27 46
d3b3ab85 47#include "SwapDir.h"
d3b3ab85 48int UFSSwapDir::NumberOfUFSDirs = 0;
49int *UFSSwapDir::UFSDirToGlobalDirMapping = NULL;
cd748f27 50
cd748f27 51/*
52 * storeUfsDirCheckObj
53 *
54 * This routine is called by storeDirSelectSwapDir to see if the given
55 * object is able to be stored on this filesystem. UFS filesystems will
56 * happily store anything as long as the LRU time isn't too small.
57 */
58int
59b2d47f 59UFSSwapDir::canStore(StoreEntry const &e)const
cd748f27 60{
59b2d47f 61 if (IO->shedLoad())
62 return -1;
62e76326 63
59b2d47f 64 return IO->load();
cd748f27 65}
66
8e8d4f30 67
59b2d47f 68/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */
d3b3ab85 69
70void
59b2d47f 71UFSSwapDir::parseSizeL1L2()
cd748f27 72{
cd748f27 73 int i;
74 int size;
cd748f27 75
76 i = GetInteger();
77 size = i << 10; /* Mbytes to kbytes */
62e76326 78
cd748f27 79 if (size <= 0)
59b2d47f 80 fatal("UFSSwapDir::parseSizeL1L2: invalid size value");
cd748f27 81
82 /* just reconfigure it */
0931cb03 83 if (reconfiguring) {
84 if (size == max_size)
85 debug(3, 2) ("Cache dir '%s' size remains unchanged at %d KB\n",
86 path, size);
87 else
88 debug(3, 1) ("Cache dir '%s' size changed to %d KB\n",
89 path, size);
90 }
62e76326 91
d3b3ab85 92 max_size = size;
59b2d47f 93
94 l1 = GetInteger();
95
96 if (l1 <= 0)
97 fatal("UFSSwapDir::parseSizeL1L2: invalid level 1 directories value");
98
99 l2 = GetInteger();
100
101 if (l2 <= 0)
102 fatal("UFSSwapDir::parseSizeL1L2: invalid level 2 directories value");
cd748f27 103}
104
59b2d47f 105/*
106 * storeUfsDirReconfigure
107 *
108 * This routine is called when the given swapdir needs reconfiguring
109 */
110
cd748f27 111void
59b2d47f 112UFSSwapDir::reconfigure(int index, char *path)
cd748f27 113{
59b2d47f 114 parseSizeL1L2();
115 parseOptions(1);
cd748f27 116}
117
cd748f27 118/*
119 * storeUfsDirParse
120 *
121 * Called when a *new* fs is being setup.
122 */
d3b3ab85 123void
59b2d47f 124UFSSwapDir::parse (int anIndex, char *aPath)
cd748f27 125{
59b2d47f 126 index = anIndex;
59b2d47f 127 path = xstrdup(aPath);
62e76326 128
1cd79a58 129 parseSizeL1L2();
130
59b2d47f 131 /* Initialise replacement policy stuff */
132 repl = createRemovalPolicy(Config.replPolicy);
62e76326 133
59b2d47f 134 parseOptions(0);
135}
62e76326 136
b9ae18aa 137void
138UFSSwapDir::changeIO(DiskIOModule *module)
139{
140 DiskIOStrategy *anIO = module->createStrategy();
141 safe_free(ioType);
142 ioType = xstrdup(module->type());
143
144 delete IO->io;
145 IO->io = anIO;
146 /* Change the IO Options */
147
148 if (currentIOOptions->options.size() > 2)
149 delete currentIOOptions->options.pop_back();
150
151 /* TODO: factor out these 4 lines */
152 ConfigOption *ioOptions = IO->io->getOptionTree();
153
154 if (ioOptions)
155 currentIOOptions->options.push_back(ioOptions);
156}
157
158bool
159UFSSwapDir::optionIOParse(char const *option, const char *value, int reconfiguring)
59b2d47f 160{
b9ae18aa 161 if (strcmp(option, "IOEngine") != 0)
162 return false;
62e76326 163
b9ae18aa 164 if (reconfiguring)
165 /* silently ignore this */
166 return true;
62e76326 167
b9ae18aa 168 if (!value)
169 self_destruct();
d3b3ab85 170
b9ae18aa 171 DiskIOModule *module = DiskIOModule::Find(value);
62e76326 172
b9ae18aa 173 if (!module)
174 self_destruct();
8e8d4f30 175
b9ae18aa 176 changeIO(module);
177
178 return true;
179}
180
181void
182UFSSwapDir::optionIODump(StoreEntry * e) const
183{
184 storeAppendPrintf(e, " IOEngine=%s", ioType);
185}
186
187ConfigOption *
188UFSSwapDir::getOptionTree() const
189{
190 ConfigOption *parentResult = SwapDir::getOptionTree();
191
e2a8733e 192 if (currentIOOptions == NULL)
193 currentIOOptions = new ConfigOptionVector();
194
b9ae18aa 195 currentIOOptions->options.push_back(parentResult);
e2a8733e 196
b9ae18aa 197 currentIOOptions->options.push_back(new ConfigOptionAdapter<UFSSwapDir>(*const_cast<UFSSwapDir *>(this), &UFSSwapDir::optionIOParse, &UFSSwapDir::optionIODump));
198
5f2d056f 199 if (ConfigOption *ioOptions = IO->io->getOptionTree())
b9ae18aa 200 currentIOOptions->options.push_back(ioOptions);
201
e2a8733e 202 ConfigOption* result = currentIOOptions;
203
204 currentIOOptions = NULL;
205
206 return result;
cd748f27 207}
208
209/*
210 * Initial setup / end destruction
211 */
d3b3ab85 212void
213UFSSwapDir::init()
214{
d295d770 215 debugs(47, 3, "Initialising UFS SwapDir engine.");
216 /* Parsing must be finished by now - force to NULL, don't delete */
b9ae18aa 217 currentIOOptions = NULL;
d3b3ab85 218 static int started_clean_event = 0;
219 static const char *errmsg =
62e76326 220 "\tFailed to verify one of the swap directories, Check cache.log\n"
221 "\tfor details. Run 'squid -z' to create swap directories\n"
222 "\tif needed, or if running Squid for the first time.";
59b2d47f 223 IO->init();
62e76326 224
d3b3ab85 225 if (verifyCacheDirs())
62e76326 226 fatal(errmsg);
227
d3b3ab85 228 openLog();
62e76326 229
d3b3ab85 230 rebuild();
62e76326 231
d3b3ab85 232 if (!started_clean_event) {
62e76326 233 eventAdd("UFS storeDirClean", CleanEvent, NULL, 15.0, 1);
234 started_clean_event = 1;
d3b3ab85 235 }
62e76326 236
d3b3ab85 237 (void) storeDirGetBlkSize(path, &fs.blksize);
238}
239
240void
c8f4eac4 241UFSSwapDir::create()
d3b3ab85 242{
d295d770 243 debugs(47, 3, "Creating swap space in " << path);
d3b3ab85 244 createDirectory(path, 0);
245 createSwapSubDirs();
246}
247
b7717b61 248UFSSwapDir::UFSSwapDir(char const *aType, const char *anIOType) : SwapDir(aType), IO(NULL), map(file_map_create()), suggest(0), swaplog_fd (-1), currentIOOptions(new ConfigOptionVector()), ioType(xstrdup(anIOType))
249{
250 /* modulename is only set to disk modules that are built, by configure,
251 * so the Find call should never return NULL here.
252 */
253 IO = new UFSStrategy(DiskIOModule::Find(anIOType)->createStrategy());
254}
d3b3ab85 255
256UFSSwapDir::~UFSSwapDir()
257{
258 if (swaplog_fd > -1) {
62e76326 259 file_close(swaplog_fd);
260 swaplog_fd = -1;
d3b3ab85 261 }
62e76326 262
d3b3ab85 263 filemapFreeMemory(map);
62e76326 264
d3b3ab85 265 if (IO)
00d77d6b 266 delete IO;
62e76326 267
d3b3ab85 268 IO = NULL;
b9ae18aa 269
270 safe_free(ioType);
d3b3ab85 271}
272
d3b3ab85 273void
274UFSSwapDir::dumpEntry(StoreEntry &e) const
275{
276 debug(47, 0) ("UFSSwapDir::dumpEntry: FILENO %08X\n", e.swap_filen);
277 debug(47, 0) ("UFSSwapDir::dumpEntry: PATH %s\n",
62e76326 278 fullPath(e.swap_filen, NULL));
d3b3ab85 279 storeEntryDump(&e, 0);
280}
281
282/*
283 * UFSSwapDir::doubleCheck
284 *
285 * This is called by storeCleanup() if -S was given on the command line.
286 */
287bool
288UFSSwapDir::doubleCheck(StoreEntry & e)
289{
62e76326 290
d3b3ab85 291 struct stat sb;
62e76326 292
c8f4eac4 293 if (::stat(fullPath(e.swap_filen, NULL), &sb) < 0) {
62e76326 294 debug(47, 0) ("UFSSwapDir::doubleCheck: MISSING SWAP FILE\n");
295 dumpEntry(e);
296 return true;
d3b3ab85 297 }
62e76326 298
d3b3ab85 299 if ((off_t)e.swap_file_sz != sb.st_size) {
62e76326 300 debug(47, 0) ("UFSSwapDir::doubleCheck: SIZE MISMATCH\n");
301 debug(47, 0) ("UFSSwapDir::doubleCheck: ENTRY SIZE: %ld, FILE SIZE: %ld\n",
302 (long int) e.swap_file_sz, (long int) sb.st_size);
303 dumpEntry(e);
304 return true;
d3b3ab85 305 }
62e76326 306
d3b3ab85 307 return false;
308}
309
310void
311UFSSwapDir::statfs(StoreEntry & sentry) const
312{
313 int totl_kb = 0;
314 int free_kb = 0;
315 int totl_in = 0;
316 int free_in = 0;
317 int x;
318 storeAppendPrintf(&sentry, "First level subdirectories: %d\n", l1);
319 storeAppendPrintf(&sentry, "Second level subdirectories: %d\n", l2);
320 storeAppendPrintf(&sentry, "Maximum Size: %d KB\n", max_size);
321 storeAppendPrintf(&sentry, "Current Size: %d KB\n", cur_size);
322 storeAppendPrintf(&sentry, "Percent Used: %0.2f%%\n",
62e76326 323 100.0 * cur_size / max_size);
d3b3ab85 324 storeAppendPrintf(&sentry, "Filemap bits in use: %d of %d (%d%%)\n",
62e76326 325 map->n_files_in_map, map->max_n_files,
326 percent(map->n_files_in_map, map->max_n_files));
d3b3ab85 327 x = storeDirGetUFSStats(path, &totl_kb, &free_kb, &totl_in, &free_in);
62e76326 328
d3b3ab85 329 if (0 == x) {
62e76326 330 storeAppendPrintf(&sentry, "Filesystem Space in use: %d/%d KB (%d%%)\n",
331 totl_kb - free_kb,
332 totl_kb,
333 percent(totl_kb - free_kb, totl_kb));
334 storeAppendPrintf(&sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n",
335 totl_in - free_in,
336 totl_in,
337 percent(totl_in - free_in, totl_in));
d3b3ab85 338 }
62e76326 339
d3b3ab85 340 storeAppendPrintf(&sentry, "Flags:");
62e76326 341
d3b3ab85 342 if (flags.selected)
62e76326 343 storeAppendPrintf(&sentry, " SELECTED");
344
d3b3ab85 345 if (flags.read_only)
62e76326 346 storeAppendPrintf(&sentry, " READ-ONLY");
347
d3b3ab85 348 storeAppendPrintf(&sentry, "\n");
59b2d47f 349
350 IO->statfs(sentry);
d3b3ab85 351}
352
353void
c8f4eac4 354UFSSwapDir::maintain()
d3b3ab85 355{
650c4b88 356 /* We can't delete objects while rebuilding swap */
357
bef81ea5 358 /* XXX FIXME each store should start maintaining as it comes online. */
359
360 if (StoreController::store_dirs_rebuilding)
650c4b88 361 return;
362
d3b3ab85 363 StoreEntry *e = NULL;
650c4b88 364
d3b3ab85 365 int removed = 0;
650c4b88 366
d3b3ab85 367 RemovalPurgeWalker *walker;
62e76326 368
c8f4eac4 369 double f = (double) (cur_size - minSize()) / (max_size - minSize());
650c4b88 370
371 f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f;
372
373 int max_scan = (int) (f * 400.0 + 100.0);
374
375 int max_remove = (int) (f * 70.0 + 10.0);
376
377 /*
378 * This is kinda cheap, but so we need this priority hack?
379 */
62e76326 380
d3b3ab85 381 debug(47, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n",
62e76326 382 f, max_scan, max_remove);
650c4b88 383
d3b3ab85 384 walker = repl->PurgeInit(repl, max_scan);
62e76326 385
d3b3ab85 386 while (1) {
c8f4eac4 387 if (cur_size < (int) minSize()) /* cur_size should be unsigned */
62e76326 388 break;
389
390 if (removed >= max_remove)
391 break;
392
393 e = walker->Next(walker);
394
395 if (!e)
396 break; /* no more objects */
397
398 removed++;
399
5f33b71d 400 e->release();
d3b3ab85 401 }
62e76326 402
d3b3ab85 403 walker->Done(walker);
c8f4eac4 404 debug(47, (removed ? 2 : 3)) ("UFSSwapDir::maintain: %s removed %d/%d f=%.03f max_scan=%d\n",
62e76326 405 path, removed, max_remove, f, max_scan);
d3b3ab85 406}
407
408/*
409 * UFSSwapDir::reference
410 *
411 * This routine is called whenever an object is referenced, so we can
412 * maintain replacement information within the storage fs.
413 */
414void
415UFSSwapDir::reference(StoreEntry &e)
416{
417 debug(47, 3) ("UFSSwapDir::reference: referencing %p %d/%d\n", &e, e.swap_dirn,
62e76326 418 e.swap_filen);
419
d3b3ab85 420 if (repl->Referenced)
62e76326 421 repl->Referenced(repl, &e, &e.repl);
422}
d3b3ab85 423
424/*
425 * UFSSwapDir::dereference
426 * This routine is called whenever the last reference to an object is
427 * removed, to maintain replacement information within the storage fs.
428 */
429void
430UFSSwapDir::dereference(StoreEntry & e)
431{
432 debug(47, 3) ("UFSSwapDir::dereference: referencing %p %d/%d\n", &e, e.swap_dirn,
62e76326 433 e.swap_filen);
434
d3b3ab85 435 if (repl->Dereferenced)
62e76326 436 repl->Dereferenced(repl, &e, &e.repl);
d3b3ab85 437}
438
439StoreIOState::Pointer
4fcc8876 440UFSSwapDir::createStoreIO(StoreEntry &e, StoreIOState::STFNCB * file_callback, StoreIOState::STIOCB * callback, void *callback_data)
d3b3ab85 441{
442 return IO->create (this, &e, file_callback, callback, callback_data);
443}
444
445StoreIOState::Pointer
4fcc8876 446UFSSwapDir::openStoreIO(StoreEntry &e, StoreIOState::STFNCB * file_callback, StoreIOState::STIOCB * callback, void *callback_data)
d3b3ab85 447{
448 return IO->open (this, &e, file_callback, callback, callback_data);
449}
450
451int
452UFSSwapDir::mapBitTest(sfileno filn)
453{
454 return file_map_bit_test(map, filn);
455}
456
457void
458UFSSwapDir::mapBitSet(sfileno filn)
459{
460 file_map_bit_set(map, filn);
461}
462
463void
464UFSSwapDir::mapBitReset(sfileno filn)
465{
466 /*
467 * We have to test the bit before calling file_map_bit_reset.
468 * file_map_bit_reset doesn't do bounds checking. It assumes
469 * filn is a valid file number, but it might not be because
470 * the map is dynamic in size. Also clearing an already clear
471 * bit puts the map counter of-of-whack.
472 */
62e76326 473
d3b3ab85 474 if (file_map_bit_test(map, filn))
62e76326 475 file_map_bit_reset(map, filn);
d3b3ab85 476}
477
478int
479UFSSwapDir::mapBitAllocate()
480{
481 int fn;
482 fn = file_map_allocate(map, suggest);
483 file_map_bit_set(map, fn);
484 suggest = fn + 1;
485 return fn;
486}
487
d3b3ab85 488char *
489UFSSwapDir::swapSubDir(int subdirn)const
490{
491 LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
492 assert(0 <= subdirn && subdirn < l1);
493 snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%02X", path, subdirn);
494 return fullfilename;
495}
496
497int
498UFSSwapDir::createDirectory(const char *path, int should_exist)
499{
500 int created = 0;
62e76326 501
d3b3ab85 502 struct stat st;
503 getCurrentTime();
62e76326 504
c8f4eac4 505 if (0 == ::stat(path, &st)) {
62e76326 506 if (S_ISDIR(st.st_mode)) {
507 debug(47, should_exist ? 3 : 1) ("%s exists\n", path);
508 } else {
509 fatalf("Swap directory %s is not a directory.", path);
510 }
511
d3b3ab85 512#ifdef _SQUID_MSWIN_
62e76326 513
d3b3ab85 514 } else if (0 == mkdir(path)) {
515#else
62e76326 516
d3b3ab85 517 } else if (0 == mkdir(path, 0755)) {
518#endif
62e76326 519 debug(47, should_exist ? 1 : 3) ("%s created\n", path);
520 created = 1;
d3b3ab85 521 } else {
62e76326 522 fatalf("Failed to make swap directory %s: %s",
523 path, xstrerror());
d3b3ab85 524 }
62e76326 525
d3b3ab85 526 return created;
527}
528
529bool
530UFSSwapDir::pathIsDirectory(const char *path)const
531{
62e76326 532
d3b3ab85 533 struct stat sb;
62e76326 534
c8f4eac4 535 if (::stat(path, &sb) < 0) {
62e76326 536 debug(47, 0) ("%s: %s\n", path, xstrerror());
537 return false;
d3b3ab85 538 }
62e76326 539
d3b3ab85 540 if (S_ISDIR(sb.st_mode) == 0) {
62e76326 541 debug(47, 0) ("%s is not a directory\n", path);
542 return false;
d3b3ab85 543 }
62e76326 544
d3b3ab85 545 return true;
546}
547
548/*
549 * This function is called by commonUfsDirInit(). If this returns < 0,
550 * then Squid exits, complains about swap directories not
551 * existing, and instructs the admin to run 'squid -z'
552 */
553bool
554UFSSwapDir::verifyCacheDirs()
555{
556 if (!pathIsDirectory(path))
62e76326 557 return true;
558
d3b3ab85 559 for (int j = 0; j < l1; j++) {
62e76326 560 char const *aPath = swapSubDir(j);
561
562 if (!pathIsDirectory(aPath))
563 return true;
d3b3ab85 564 }
62e76326 565
d3b3ab85 566 return false;
567}
568
569void
570UFSSwapDir::createSwapSubDirs()
571{
d3b3ab85 572 LOCAL_ARRAY(char, name, MAXPATHLEN);
62e76326 573
59b2d47f 574 for (int i = 0; i < l1; i++) {
62e76326 575 snprintf(name, MAXPATHLEN, "%s/%02X", path, i);
576
59b2d47f 577 int should_exist;
578
62e76326 579 if (createDirectory(name, 0))
580 should_exist = 0;
581 else
582 should_exist = 1;
583
584 debug(47, 1) ("Making directories in %s\n", name);
585
59b2d47f 586 for (int k = 0; k < l2; k++) {
62e76326 587 snprintf(name, MAXPATHLEN, "%s/%02X/%02X", path, i, k);
588 createDirectory(name, should_exist);
589 }
d3b3ab85 590 }
591}
592
593char *
594UFSSwapDir::logFile(char const *ext) const
595{
596 LOCAL_ARRAY(char, lpath, SQUID_MAXPATHLEN);
597 LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN);
598 LOCAL_ARRAY(char, digit, 32);
599 char *pathtmp2;
62e76326 600
d3b3ab85 601 if (Config.Log.swap) {
62e76326 602 xstrncpy(pathtmp, path, SQUID_MAXPATHLEN - 64);
603 pathtmp2 = pathtmp;
604
605 while ((pathtmp2 = strchr(pathtmp2, '/')) != NULL)
606 *pathtmp2 = '.';
607
608 while (strlen(pathtmp) && pathtmp[strlen(pathtmp) - 1] == '.')
609 pathtmp[strlen(pathtmp) - 1] = '\0';
610
611 for (pathtmp2 = pathtmp; *pathtmp2 == '.'; pathtmp2++)
612
613 ;
614 snprintf(lpath, SQUID_MAXPATHLEN - 64, Config.Log.swap, pathtmp2);
615
616 if (strncmp(lpath, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) {
617 strcat(lpath, ".");
618 snprintf(digit, 32, "%02d", index);
619 strncat(lpath, digit, 3);
620 }
d3b3ab85 621 } else {
62e76326 622 xstrncpy(lpath, path, SQUID_MAXPATHLEN - 64);
623 strcat(lpath, "/swap.state");
d3b3ab85 624 }
62e76326 625
d3b3ab85 626 if (ext)
62e76326 627 strncat(lpath, ext, 16);
628
d3b3ab85 629 return lpath;
630}
631
632void
633UFSSwapDir::openLog()
634{
635 char *logPath;
636 logPath = logFile();
637 swaplog_fd = file_open(logPath, O_WRONLY | O_CREAT | O_BINARY);
62e76326 638
d3b3ab85 639 if (swaplog_fd < 0) {
62e76326 640 debug(50, 1) ("%s: %s\n", logPath, xstrerror());
641 fatal("commonUfsDirOpenSwapLog: Failed to open swap log.");
d3b3ab85 642 }
62e76326 643
d3b3ab85 644 debug(50, 3) ("Cache Dir #%d log opened on FD %d\n", index, swaplog_fd);
62e76326 645
d3b3ab85 646 if (0 == NumberOfUFSDirs)
62e76326 647 assert(NULL == UFSDirToGlobalDirMapping);
648
d3b3ab85 649 ++NumberOfUFSDirs;
62e76326 650
d3b3ab85 651 assert(NumberOfUFSDirs <= Config.cacheSwap.n_configured);
652}
653
654void
655UFSSwapDir::closeLog()
656{
657 if (swaplog_fd < 0) /* not open */
62e76326 658 return;
659
d3b3ab85 660 file_close(swaplog_fd);
62e76326 661
d3b3ab85 662 debug(47, 3) ("Cache Dir #%d log closed on FD %d\n",
62e76326 663 index, swaplog_fd);
664
d3b3ab85 665 swaplog_fd = -1;
62e76326 666
59b2d47f 667 --NumberOfUFSDirs;
62e76326 668
d3b3ab85 669 assert(NumberOfUFSDirs >= 0);
62e76326 670
d3b3ab85 671 if (0 == NumberOfUFSDirs)
62e76326 672 safe_free(UFSDirToGlobalDirMapping);
d3b3ab85 673}
674
675bool
676UFSSwapDir::validL1(int anInt) const
677{
678 return anInt < l1;
679}
680
681bool
682UFSSwapDir::validL2(int anInt) const
683{
684 return anInt < l2;
685}
686
687/* Add a new object to the cache with empty memory copy and pointer to disk
688 * use to rebuild store from disk. */
689StoreEntry *
690UFSSwapDir::addDiskRestore(const cache_key * key,
62e76326 691 sfileno file_number,
692 size_t swap_file_sz,
693 time_t expires,
694 time_t timestamp,
695 time_t lastref,
696 time_t lastmod,
697 u_int32_t refcount,
698 u_int16_t flags,
699 int clean)
d3b3ab85 700{
701 StoreEntry *e = NULL;
702 debug(47, 5) ("commonUfsAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number);
62e76326 703 /* if you call this you'd better be sure file_number is not
d3b3ab85 704 * already in use! */
c8f4eac4 705 e = new StoreEntry();
d3b3ab85 706 e->store_status = STORE_OK;
707 storeSetMemStatus(e, NOT_IN_MEMORY);
708 e->swap_status = SWAPOUT_DONE;
709 e->swap_filen = file_number;
710 e->swap_dirn = index;
711 e->swap_file_sz = swap_file_sz;
712 e->lock_count = 0;
713 e->lastref = lastref;
714 e->timestamp = timestamp;
715 e->expires = expires;
716 e->lastmod = lastmod;
717 e->refcount = refcount;
718 e->flags = flags;
719 EBIT_SET(e->flags, ENTRY_CACHABLE);
720 EBIT_CLR(e->flags, RELEASE_REQUEST);
721 EBIT_CLR(e->flags, KEY_PRIVATE);
722 e->ping_status = PING_NONE;
723 EBIT_CLR(e->flags, ENTRY_VALIDATED);
724 mapBitSet(e->swap_filen);
725 storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */
726 replacementAdd (e);
727 return e;
728}
729
730void
731UFSSwapDir::rebuild()
732{
bef81ea5 733 ++StoreController::store_dirs_rebuilding;
c8f4eac4 734 eventAdd("storeRebuild", RebuildState::RebuildStep, new RebuildState(this), 0.0, 1);
d3b3ab85 735}
736
737void
738UFSSwapDir::closeTmpSwapLog()
739{
740 char *swaplog_path = xstrdup(logFile(NULL));
741 char *new_path = xstrdup(logFile(".new"));
742 int fd;
743 file_close(swaplog_fd);
62e76326 744
d3b3ab85 745 if (xrename(new_path, swaplog_path) < 0) {
62e76326 746 fatal("commonUfsDirCloseTmpSwapLog: rename failed");
d3b3ab85 747 }
62e76326 748
d3b3ab85 749 fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY);
62e76326 750
d3b3ab85 751 if (fd < 0) {
62e76326 752 debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror());
753 fatal("commonUfsDirCloseTmpSwapLog: Failed to open swap log.");
d3b3ab85 754 }
62e76326 755
d3b3ab85 756 safe_free(swaplog_path);
757 safe_free(new_path);
758 swaplog_fd = fd;
759 debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", index, fd);
760}
761
762FILE *
763UFSSwapDir::openTmpSwapLog(int *clean_flag, int *zero_flag)
764{
765 char *swaplog_path = xstrdup(logFile(NULL));
766 char *clean_path = xstrdup(logFile(".last-clean"));
767 char *new_path = xstrdup(logFile(".new"));
62e76326 768
d3b3ab85 769 struct stat log_sb;
62e76326 770
d3b3ab85 771 struct stat clean_sb;
772 FILE *fp;
773 int fd;
62e76326 774
c8f4eac4 775 if (::stat(swaplog_path, &log_sb) < 0) {
62e76326 776 debug(47, 1) ("Cache Dir #%d: No log file\n", index);
777 safe_free(swaplog_path);
778 safe_free(clean_path);
779 safe_free(new_path);
780 return NULL;
d3b3ab85 781 }
62e76326 782
d3b3ab85 783 *zero_flag = log_sb.st_size == 0 ? 1 : 0;
784 /* close the existing write-only FD */
62e76326 785
d3b3ab85 786 if (swaplog_fd >= 0)
62e76326 787 file_close(swaplog_fd);
788
d3b3ab85 789 /* open a write-only FD for the new log */
790 fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
62e76326 791
d3b3ab85 792 if (fd < 0) {
62e76326 793 debug(50, 1) ("%s: %s\n", new_path, xstrerror());
794 fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
d3b3ab85 795 }
62e76326 796
d3b3ab85 797 swaplog_fd = fd;
798 /* open a read-only stream of the old log */
799 fp = fopen(swaplog_path, "rb");
62e76326 800
d3b3ab85 801 if (fp == NULL) {
62e76326 802 debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror());
803 fatal("Failed to open swap log for reading");
d3b3ab85 804 }
62e76326 805
d3b3ab85 806 memset(&clean_sb, '\0', sizeof(struct stat));
62e76326 807
c8f4eac4 808 if (::stat(clean_path, &clean_sb) < 0)
62e76326 809 *clean_flag = 0;
d3b3ab85 810 else if (clean_sb.st_mtime < log_sb.st_mtime)
62e76326 811 *clean_flag = 0;
d3b3ab85 812 else
62e76326 813 *clean_flag = 1;
814
d3b3ab85 815 safeunlink(clean_path, 1);
62e76326 816
d3b3ab85 817 safe_free(swaplog_path);
62e76326 818
d3b3ab85 819 safe_free(clean_path);
62e76326 820
d3b3ab85 821 safe_free(new_path);
62e76326 822
d3b3ab85 823 return fp;
824}
825
62e76326 826class UFSCleanLog : public SwapDir::CleanLog
827{
828
829public:
d3b3ab85 830 UFSCleanLog(SwapDir *);
831 virtual const StoreEntry *nextEntry();
832 virtual void write(StoreEntry const &);
833 char *cur;
834 char *newLog;
835 char *cln;
836 char *outbuf;
837 off_t outbuf_offset;
838 int fd;
839 RemovalPolicyWalker *walker;
840 SwapDir *sd;
841};
842
843#define CLEAN_BUF_SZ 16384
844
d3b3ab85 845
846UFSCleanLog::UFSCleanLog(SwapDir *aSwapDir) : cur(NULL),newLog(NULL),cln(NULL),outbuf(NULL),
62e76326 847 outbuf_offset(0), fd(-1),walker(NULL), sd(aSwapDir)
848{}
d3b3ab85 849
59b2d47f 850/*
851 * Begin the process to write clean cache state. For AUFS this means
852 * opening some log files and allocating write buffers. Return 0 if
853 * we succeed, and assign the 'func' and 'data' return pointers.
854 */
d3b3ab85 855int
856UFSSwapDir::writeCleanStart()
857{
858 UFSCleanLog *state = new UFSCleanLog(this);
859#if HAVE_FCHMOD
62e76326 860
d3b3ab85 861 struct stat sb;
862#endif
62e76326 863
d3b3ab85 864 cleanLog = NULL;
865 state->newLog = xstrdup(logFile(".clean"));
866 state->fd = file_open(state->newLog, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
62e76326 867
d3b3ab85 868 if (state->fd < 0) {
62e76326 869 xfree(state->newLog);
870 delete state;
871 return -1;
d3b3ab85 872 }
62e76326 873
d3b3ab85 874 state->cur = xstrdup(logFile(NULL));
875 state->cln = xstrdup(logFile(".last-clean"));
876 state->outbuf = (char *)xcalloc(CLEAN_BUF_SZ, 1);
877 state->outbuf_offset = 0;
878 state->walker = repl->WalkInit(repl);
879 ::unlink(state->cln);
880 debug(47, 3) ("storeDirWriteCleanLogs: opened %s, FD %d\n",
62e76326 881 state->newLog, state->fd);
d3b3ab85 882#if HAVE_FCHMOD
62e76326 883
c8f4eac4 884 if (::stat(state->cur, &sb) == 0)
62e76326 885 fchmod(state->fd, sb.st_mode);
886
d3b3ab85 887#endif
62e76326 888
d3b3ab85 889 cleanLog = state;
62e76326 890
d3b3ab85 891 return 0;
892}
893
894/*
895 * Get the next entry that is a candidate for clean log writing
896 */
897const StoreEntry *
898UFSCleanLog::nextEntry()
899{
900 const StoreEntry *entry = NULL;
62e76326 901
d3b3ab85 902 if (walker)
62e76326 903 entry = walker->Next(walker);
904
d3b3ab85 905 return entry;
906}
907
908/*
909 * "write" an entry to the clean log file.
910 */
911void
912UFSCleanLog::write(StoreEntry const &e)
913{
51ee7c82 914 StoreSwapLogData s;
915 static size_t ss = sizeof(StoreSwapLogData);
d3b3ab85 916 s.op = (char) SWAP_LOG_ADD;
917 s.swap_filen = e.swap_filen;
918 s.timestamp = e.timestamp;
919 s.lastref = e.lastref;
920 s.expires = e.expires;
921 s.lastmod = e.lastmod;
922 s.swap_file_sz = e.swap_file_sz;
923 s.refcount = e.refcount;
924 s.flags = e.flags;
925 xmemcpy(&s.key, e.key, MD5_DIGEST_CHARS);
78fe982f 926 xmemcpy(outbuf + outbuf_offset, &s, ss);
927 outbuf_offset += ss;
d3b3ab85 928 /* buffered write */
62e76326 929
e79ee799 930 if (outbuf_offset + ss >= CLEAN_BUF_SZ) {
78fe982f 931 if (FD_WRITE_METHOD(fd, outbuf, outbuf_offset) < 0) {
932 /* XXX This error handling should probably move up to the caller */
62e76326 933 debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
78fe982f 934 newLog, xstrerror());
62e76326 935 debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n");
78fe982f 936 file_close(fd);
937 fd = -1;
938 unlink(newLog);
62e76326 939 sd->cleanLog = NULL;
78fe982f 940 delete this;
62e76326 941 return;
942 }
943
78fe982f 944 outbuf_offset = 0;
d3b3ab85 945 }
946}
947
948void
949UFSSwapDir::writeCleanDone()
950{
951 UFSCleanLog *state = (UFSCleanLog *)cleanLog;
952 int fd;
62e76326 953
d3b3ab85 954 if (NULL == state)
62e76326 955 return;
956
d3b3ab85 957 if (state->fd < 0)
62e76326 958 return;
959
d3b3ab85 960 state->walker->Done(state->walker);
62e76326 961
d3b3ab85 962 if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) {
62e76326 963 debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
964 state->newLog, xstrerror());
965 debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile "
966 "not replaced.\n");
967 file_close(state->fd);
968 state->fd = -1;
969 ::unlink(state->newLog);
d3b3ab85 970 }
62e76326 971
d3b3ab85 972 safe_free(state->outbuf);
973 /*
974 * You can't rename open files on Microsoft "operating systems"
975 * so we have to close before renaming.
976 */
977 closeLog();
978 /* save the fd value for a later test */
979 fd = state->fd;
980 /* rename */
62e76326 981
d3b3ab85 982 if (state->fd >= 0) {
ec4daaa5 983#if defined(_SQUID_OS2_) || defined (_SQUID_WIN32_)
62e76326 984 file_close(state->fd);
985 state->fd = -1;
986
d3b3ab85 987#endif
62e76326 988
989 xrename(state->newLog, state->cur);
d3b3ab85 990 }
62e76326 991
d3b3ab85 992 /* touch a timestamp file if we're not still validating */
bef81ea5 993 if (StoreController::store_dirs_rebuilding)
62e76326 994 (void) 0;
d3b3ab85 995 else if (fd < 0)
62e76326 996 (void) 0;
d3b3ab85 997 else
62e76326 998 file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY));
999
d3b3ab85 1000 /* close */
1001 safe_free(state->cur);
62e76326 1002
d3b3ab85 1003 safe_free(state->newLog);
62e76326 1004
d3b3ab85 1005 safe_free(state->cln);
62e76326 1006
d3b3ab85 1007 if (state->fd >= 0)
62e76326 1008 file_close(state->fd);
1009
d3b3ab85 1010 state->fd = -1;
62e76326 1011
d3b3ab85 1012 delete state;
62e76326 1013
d3b3ab85 1014 cleanLog = NULL;
1015}
1016
061c7171 1017static void
1018FreeObject(void *address)
1019{
1020 StoreSwapLogData *anObject = static_cast <StoreSwapLogData *>(address);
1021 delete anObject;
1022}
1023
d3b3ab85 1024void
1025UFSSwapDir::logEntry(const StoreEntry & e, int op) const
1026{
51ee7c82 1027 StoreSwapLogData *s = new StoreSwapLogData;
d3b3ab85 1028 s->op = (char) op;
1029 s->swap_filen = e.swap_filen;
1030 s->timestamp = e.timestamp;
1031 s->lastref = e.lastref;
1032 s->expires = e.expires;
1033 s->lastmod = e.lastmod;
1034 s->swap_file_sz = e.swap_file_sz;
1035 s->refcount = e.refcount;
1036 s->flags = e.flags;
1037 xmemcpy(s->key, e.key, MD5_DIGEST_CHARS);
1038 file_write(swaplog_fd,
62e76326 1039 -1,
1040 s,
51ee7c82 1041 sizeof(StoreSwapLogData),
62e76326 1042 NULL,
1043 NULL,
061c7171 1044 FreeObject);
d3b3ab85 1045}
1046
1047static QS rev_int_sort;
1048static int
1049rev_int_sort(const void *A, const void *B)
1050{
1051 const int *i1 = (const int *)A;
1052 const int *i2 = (const int *)B;
1053 return *i2 - *i1;
1054}
1055
1056int
1057UFSSwapDir::DirClean(int swap_index)
1058{
bef81ea5 1059 DIR *dir_pointer = NULL;
62e76326 1060
d3b3ab85 1061 struct dirent *de = NULL;
1062 LOCAL_ARRAY(char, p1, MAXPATHLEN + 1);
1063 LOCAL_ARRAY(char, p2, MAXPATHLEN + 1);
62e76326 1064
d3b3ab85 1065 int files[20];
1066 int swapfileno;
1067 int fn; /* same as swapfileno, but with dirn bits set */
1068 int n = 0;
1069 int k = 0;
1070 int N0, N1, N2;
1071 int D0, D1, D2;
1072 UFSSwapDir *SD;
1073 N0 = NumberOfUFSDirs;
1074 D0 = UFSDirToGlobalDirMapping[swap_index % N0];
1075 SD = dynamic_cast<UFSSwapDir *>(INDEXSD(D0));
1076 assert (SD);
1077 N1 = SD->l1;
1078 D1 = (swap_index / N0) % N1;
1079 N2 = SD->l2;
1080 D2 = ((swap_index / N0) / N1) % N2;
1081 snprintf(p1, SQUID_MAXPATHLEN, "%s/%02X/%02X",
62e76326 1082 SD->path, D1, D2);
d3b3ab85 1083 debug(36, 3) ("storeDirClean: Cleaning directory %s\n", p1);
bef81ea5 1084 dir_pointer = opendir(p1);
62e76326 1085
bef81ea5 1086 if (dir_pointer == NULL) {
62e76326 1087 if (errno == ENOENT) {
1088 debug(36, 0) ("storeDirClean: WARNING: Creating %s\n", p1);
d3b3ab85 1089#ifdef _SQUID_MSWIN_
62e76326 1090
1091 if (mkdir(p1) == 0)
d3b3ab85 1092#else
62e76326 1093
1094 if (mkdir(p1, 0777) == 0)
d3b3ab85 1095#endif
62e76326 1096
1097 return 0;
1098 }
1099
1100 debug(50, 0) ("storeDirClean: %s: %s\n", p1, xstrerror());
1101 safeunlink(p1, 1);
1102 return 0;
d3b3ab85 1103 }
62e76326 1104
bef81ea5 1105 while ((de = readdir(dir_pointer)) != NULL && k < 20) {
62e76326 1106 if (sscanf(de->d_name, "%X", &swapfileno) != 1)
1107 continue;
1108
1109 fn = swapfileno; /* XXX should remove this cruft ! */
1110
1111 if (SD->validFileno(fn, 1))
1112 if (SD->mapBitTest(fn))
1113 if (UFSSwapDir::FilenoBelongsHere(fn, D0, D1, D2))
1114 continue;
1115
62e76326 1116 files[k++] = swapfileno;
d3b3ab85 1117 }
62e76326 1118
bef81ea5 1119 closedir(dir_pointer);
62e76326 1120
d3b3ab85 1121 if (k == 0)
62e76326 1122 return 0;
1123
d3b3ab85 1124 qsort(files, k, sizeof(int), rev_int_sort);
62e76326 1125
d3b3ab85 1126 if (k > 10)
62e76326 1127 k = 10;
1128
d3b3ab85 1129 for (n = 0; n < k; n++) {
62e76326 1130 debug(36, 3) ("storeDirClean: Cleaning file %08X\n", files[n]);
1131 snprintf(p2, MAXPATHLEN + 1, "%s/%08X", p1, files[n]);
62e76326 1132 safeunlink(p2, 0);
62e76326 1133 statCounter.swap.files_cleaned++;
d3b3ab85 1134 }
62e76326 1135
d3b3ab85 1136 debug(36, 3) ("Cleaned %d unused files from %s\n", k, p1);
1137 return k;
1138}
1139
1140void
1141UFSSwapDir::CleanEvent(void *unused)
1142{
1143 static int swap_index = 0;
1144 int i;
1145 int j = 0;
1146 int n = 0;
1147 /*
1148 * Assert that there are UFS cache_dirs configured, otherwise
1149 * we should never be called.
1150 */
1151 assert(NumberOfUFSDirs);
62e76326 1152
d3b3ab85 1153 if (NULL == UFSDirToGlobalDirMapping) {
62e76326 1154 SwapDir *sd;
1155 /*
1156 * Initialize the little array that translates UFS cache_dir
1157 * number into the Config.cacheSwap.swapDirs array index.
1158 */
1159 UFSDirToGlobalDirMapping = (int *)xcalloc(NumberOfUFSDirs, sizeof(*UFSDirToGlobalDirMapping));
1160
1161 for (i = 0, n = 0; i < Config.cacheSwap.n_configured; i++) {
c8f4eac4 1162 /* This is bogus, the controller should just clean each instance once */
1163 sd = dynamic_cast <SwapDir *>(INDEXSD(i));
62e76326 1164
1165 if (!UFSSwapDir::IsUFSDir(sd))
1166 continue;
1167
1168 UFSSwapDir *usd = dynamic_cast<UFSSwapDir *>(sd);
1169
1170 assert (usd);
1171
1172 UFSDirToGlobalDirMapping[n++] = i;
1173
1174 j += (usd->l1 * usd->l2);
1175 }
1176
1177 assert(n == NumberOfUFSDirs);
1178 /*
1179 * Start the commonUfsDirClean() swap_index with a random
1180 * value. j equals the total number of UFS level 2
1181 * swap directories
1182 */
1183 swap_index = (int) (squid_random() % j);
d3b3ab85 1184 }
62e76326 1185
bef81ea5 1186 /* if the rebuild is finished, start cleaning directories. */
1187 if (0 == StoreController::store_dirs_rebuilding) {
62e76326 1188 n = DirClean(swap_index);
1189 swap_index++;
d3b3ab85 1190 }
62e76326 1191
d3b3ab85 1192 eventAdd("storeDirClean", CleanEvent, NULL,
62e76326 1193 15.0 * exp(-0.25 * n), 1);
d3b3ab85 1194}
1195
1196int
1197UFSSwapDir::IsUFSDir(SwapDir * sd)
1198{
1199 UFSSwapDir *mySD = dynamic_cast<UFSSwapDir *>(sd);
1200 return mySD ? 1 : 0 ;
1201}
1202
1203/*
1204 * Does swapfile number 'fn' belong in cachedir #F0,
1205 * level1 dir #F1, level2 dir #F2?
1206 * XXX: this is broken - it assumes all cache dirs use the same
1207 * l1 and l2 scheme. -RBC 20021215. Partial fix is in place -
1208 * if not UFSSwapDir return 0;
1209 */
1210int
1211UFSSwapDir::FilenoBelongsHere(int fn, int F0, int F1, int F2)
1212{
1213 int D1, D2;
1214 int L1, L2;
1215 int filn = fn;
1216 assert(F0 < Config.cacheSwap.n_configured);
c8f4eac4 1217 assert (UFSSwapDir::IsUFSDir (dynamic_cast<SwapDir *>(INDEXSD(F0))));
d3b3ab85 1218 UFSSwapDir *sd = dynamic_cast<UFSSwapDir *>(INDEXSD(F0));
62e76326 1219
d3b3ab85 1220 if (!sd)
62e76326 1221 return 0;
1222
d3b3ab85 1223 L1 = sd->l1;
62e76326 1224
d3b3ab85 1225 L2 = sd->l2;
62e76326 1226
d3b3ab85 1227 D1 = ((filn / L2) / L2) % L1;
62e76326 1228
d3b3ab85 1229 if (F1 != D1)
62e76326 1230 return 0;
1231
d3b3ab85 1232 D2 = (filn / L2) % L2;
62e76326 1233
d3b3ab85 1234 if (F2 != D2)
62e76326 1235 return 0;
1236
d3b3ab85 1237 return 1;
1238}
1239
bef81ea5 1240
d3b3ab85 1241int
1242UFSSwapDir::validFileno(sfileno filn, int flag) const
1243{
1244 if (filn < 0)
62e76326 1245 return 0;
1246
d3b3ab85 1247 /*
1248 * If flag is set it means out-of-range file number should
1249 * be considered invalid.
1250 */
1251 if (flag)
62e76326 1252 if (filn > map->max_n_files)
1253 return 0;
1254
d3b3ab85 1255 return 1;
1256}
1257
59b2d47f 1258
1259
d3b3ab85 1260/*
1261 * UFSSwapDir::unlinkFile
1262 *
1263 * This routine unlinks a file and pulls it out of the bitmap.
1264 * It used to be in commonUfsUnlink(), however an interface change
1265 * forced this bit of code here. Eeek.
1266 */
1267void
1268UFSSwapDir::unlinkFile(sfileno f)
1269{
59b2d47f 1270 debug(79, 3) ("UFSSwapDir::unlinkFile: unlinking fileno %08X '%s'\n", f, fullPath(f,NULL));
d3b3ab85 1271 /* commonUfsDirMapBitReset(this, f); */
59b2d47f 1272 IO->unlinkFile(fullPath(f,NULL));
1273}
1274
1275void
1276UFSSwapDir::unlink(StoreEntry & e)
1277{
1278 debug(79, 3) ("storeUfsUnlink: dirno %d, fileno %08X\n", index, e.swap_filen);
1279 replacementRemove(&e);
1280 mapBitReset(e.swap_filen);
1281 UFSSwapDir::unlinkFile(e.swap_filen);
d3b3ab85 1282}
1283
1284/*
1285 * Add and remove the given StoreEntry from the replacement policy in
1286 * use.
1287 */
1288
1289void
1290UFSSwapDir::replacementAdd(StoreEntry * e)
1291{
1292 debug(47, 4) ("UFSSwapDir::replacementAdd: added node %p to dir %d\n", e,
62e76326 1293 index);
d3b3ab85 1294 repl->Add(repl, e, &e->repl);
1295}
1296
1297
1298void
1299UFSSwapDir::replacementRemove(StoreEntry * e)
1300{
c8f4eac4 1301 StorePointer SD;
62e76326 1302
d3b3ab85 1303 if (e->swap_dirn < 0)
62e76326 1304 return;
1305
d3b3ab85 1306 SD = INDEXSD(e->swap_dirn);
62e76326 1307
c8f4eac4 1308 assert (dynamic_cast<UFSSwapDir *>(SD.getRaw()) == this);
62e76326 1309
d3b3ab85 1310 debug(47, 4) ("UFSSwapDir::replacementRemove: remove node %p from dir %d\n", e,
62e76326 1311 index);
1312
d3b3ab85 1313 repl->Remove(repl, e, &e->repl);
1314}
1315
1316void
1317UFSSwapDir::dump(StoreEntry & entry) const
1318{
1319 storeAppendPrintf(&entry, " %d %d %d",
62e76326 1320 max_size >> 10,
1321 l1,
1322 l2);
59b2d47f 1323 dumpOptions(&entry);
d3b3ab85 1324}
1325
1326char *
1327UFSSwapDir::fullPath(sfileno filn, char *fullpath) const
1328{
1329 LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
1330 int L1 = l1;
1331 int L2 = l2;
62e76326 1332
d3b3ab85 1333 if (!fullpath)
62e76326 1334 fullpath = fullfilename;
1335
d3b3ab85 1336 fullpath[0] = '\0';
62e76326 1337
d3b3ab85 1338 snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X/%08X",
62e76326 1339 path,
1340 ((filn / L2) / L2) % L1,
1341 (filn / L2) % L2,
1342 filn);
1343
d3b3ab85 1344 return fullpath;
1345}
59b2d47f 1346
1347int
1348UFSSwapDir::callback()
1349{
1350 return IO->callback();
1351}
1352
1353void
1354UFSSwapDir::sync()
1355{
1356 IO->sync();
1357}
c8f4eac4 1358
1359StoreSearch *
1360UFSSwapDir::search(String const url, HttpRequest *request)
1361{
1362 if (url.size())
1363 fatal ("Cannot search by url yet\n");
1364
1365 return new StoreSearchUFS (this);
1366}
1367
1368CBDATA_CLASS_INIT(StoreSearchUFS);
1369StoreSearchUFS::StoreSearchUFS(RefCount<UFSSwapDir> aSwapDir) : sd(aSwapDir), walker (sd->repl->WalkInit(sd->repl)), current (NULL), _done (false)
1370{}
1371
1372/* do not link
1373StoreSearchUFS::StoreSearchUFS(StoreSearchUFS const &);
1374*/
1375
1376StoreSearchUFS::~StoreSearchUFS()
1377{
1378 walker->Done(walker);
1379 walker = NULL;
1380}
1381
1382void
1383StoreSearchUFS::next(void (callback)(void *cbdata), void *cbdata)
1384{
1385 next();
1386 callback (cbdata);
1387}
1388
1389bool
1390StoreSearchUFS::next()
1391{
1392 /* the walker API doesn't make sense. the store entries referred to are already readwrite
1393 * from their hash table entries
1394 */
1395
1396 if (walker)
1397 current = const_cast<StoreEntry *>(walker->Next(walker));
1398
1399 if (current == NULL)
1400 _done = true;
1401
1402 return current != NULL;
1403}
1404
1405bool
1406StoreSearchUFS::error() const
1407{
1408 return false;
1409}
1410
1411bool
1412StoreSearchUFS::isDone() const
1413{
1414 return _done;
1415}
1416
1417StoreEntry *
1418StoreSearchUFS::currentItem()
1419{
1420 return current;
1421}