]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/store_dir.cc
3 * $Id: store_dir.cc,v 1.83 1998/09/23 15:37:43 wessels Exp $
5 * DEBUG: section 47 Store Directory Routines
6 * AUTHOR: Duane Wessels
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
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.
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.
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.
38 #if HAVE_SYS_STATVFS_H
39 #include <sys/statvfs.h>
43 #define SWAP_DIR_SHIFT 24
44 #define SWAP_FILE_MASK 0x00FFFFFF
45 #define DefaultLevelOneDirs 16
46 #define DefaultLevelTwoDirs 256
48 static char *storeSwapSubDir(int dirn
, int subdirn
);
49 static int storeDirSelectSwapDir(void);
50 static int storeVerifyDirectory(const char *path
);
51 static int storeCreateDirectory(const char *path
, int);
52 static void storeCreateSwapSubDirs(int j
);
54 /* return full name to swapfile */
56 storeSwapFullPath(int fn
, char *fullpath
)
58 LOCAL_ARRAY(char, fullfilename
, SQUID_MAXPATHLEN
);
59 int dirn
= (fn
>> SWAP_DIR_SHIFT
) % Config
.cacheSwap
.n_configured
;
60 int filn
= fn
& SWAP_FILE_MASK
;
61 int L1
= Config
.cacheSwap
.swapDirs
[dirn
].l1
;
62 int L2
= Config
.cacheSwap
.swapDirs
[dirn
].l2
;
64 fullpath
= fullfilename
;
66 snprintf(fullpath
, SQUID_MAXPATHLEN
, "%s/%02X/%02X/%08X",
67 Config
.cacheSwap
.swapDirs
[dirn
].path
,
68 ((filn
/ L2
) / L2
) % L1
,
75 storeSwapSubDir(int dirn
, int subdirn
)
77 LOCAL_ARRAY(char, fullfilename
, SQUID_MAXPATHLEN
);
79 assert(0 <= dirn
&& dirn
< Config
.cacheSwap
.n_configured
);
80 SD
= &Config
.cacheSwap
.swapDirs
[dirn
];
81 assert(0 <= subdirn
&& subdirn
< SD
->l1
);
82 snprintf(fullfilename
, SQUID_MAXPATHLEN
, "%s/%02X",
83 Config
.cacheSwap
.swapDirs
[dirn
].path
,
89 storeSwapSubSubDir(int fn
, char *fullpath
)
91 LOCAL_ARRAY(char, fullfilename
, SQUID_MAXPATHLEN
);
92 int dirn
= (fn
>> SWAP_DIR_SHIFT
) % Config
.cacheSwap
.n_configured
;
93 int filn
= fn
& SWAP_FILE_MASK
;
94 int L1
= Config
.cacheSwap
.swapDirs
[dirn
].l1
;
95 int L2
= Config
.cacheSwap
.swapDirs
[dirn
].l2
;
97 fullpath
= fullfilename
;
99 snprintf(fullpath
, SQUID_MAXPATHLEN
, "%s/%02X/%02X",
100 Config
.cacheSwap
.swapDirs
[dirn
].path
,
101 ((filn
/ L2
) / L2
) % L1
,
107 * Does swapfile number 'fn' belong in cachedir #F0,
108 * level1 dir #F1, level2 dir #F2?
110 * This is called by storeDirClean(), but placed here because
111 * the algorithm needs to match storeSwapSubSubDir().
113 * Don't check that (fn >> SWAP_DIR_SHIFT) == F0 because
114 * 'fn' may not have the directory bits set.
117 storeFilenoBelongsHere(int fn
, int F0
, int F1
, int F2
)
121 int filn
= fn
& SWAP_FILE_MASK
;
122 assert(F0
< Config
.cacheSwap
.n_configured
);
123 L1
= Config
.cacheSwap
.swapDirs
[F0
].l1
;
124 L2
= Config
.cacheSwap
.swapDirs
[F0
].l2
;
125 D1
= ((filn
/ L2
) / L2
) % L1
;
128 D2
= (filn
/ L2
) % L2
;
135 storeCreateDirectory(const char *path
, int should_exist
)
140 if (0 == stat(path
, &st
)) {
141 if (S_ISDIR(st
.st_mode
)) {
142 debug(20, should_exist
? 3 : 1) ("%s exists\n", path
);
144 fatalf("Swap directory %s is not a directory.", path
);
146 } else if (0 == mkdir(path
, 0755)) {
147 debug(20, should_exist
? 1 : 3) ("%s created\n", path
);
150 fatalf("Failed to make swap directory %s: %s",
157 storeVerifyDirectory(const char *path
)
160 if (stat(path
, &sb
) < 0) {
161 debug(20, 0) ("%s: %s\n", path
, xstrerror());
164 if (S_ISDIR(sb
.st_mode
) == 0) {
165 debug(20, 0) ("%s is not a directory\n", path
);
172 * This function is called by storeInit(). If this returns < 0,
173 * then Squid exits, complains about swap directories not
174 * existing, and instructs the admin to run 'squid -z'
177 storeVerifyCacheDirs(void)
182 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++) {
183 path
= Config
.cacheSwap
.swapDirs
[i
].path
;
184 if (storeVerifyDirectory(path
) < 0)
186 for (j
= 0; j
< Config
.cacheSwap
.swapDirs
[i
].l1
; j
++) {
187 path
= storeSwapSubDir(i
, j
);
188 if (storeVerifyDirectory(path
) < 0)
196 storeCreateSwapDirectories(void)
199 const char *path
= NULL
;
200 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++) {
201 path
= Config
.cacheSwap
.swapDirs
[i
].path
;
202 debug(47, 3) ("Creating swap space in %s\n", path
);
203 storeCreateDirectory(path
, 0);
204 storeCreateSwapSubDirs(i
);
209 storeCreateSwapSubDirs(int j
)
213 SwapDir
*SD
= &Config
.cacheSwap
.swapDirs
[j
];
214 LOCAL_ARRAY(char, name
, MAXPATHLEN
);
215 for (i
= 0; i
< SD
->l1
; i
++) {
216 snprintf(name
, MAXPATHLEN
, "%s/%02X", SD
->path
, i
);
217 if (storeCreateDirectory(name
, 0))
221 debug(47, 1) ("Making directories in %s\n", name
);
222 for (k
= 0; k
< SD
->l2
; k
++) {
223 snprintf(name
, MAXPATHLEN
, "%s/%02X/%02X", SD
->path
, i
, k
);
224 storeCreateDirectory(name
, should_exist
);
230 *Spread load across least 3/4 of the store directories
233 storeDirSelectSwapDir(void)
235 double least_used
= 1.0;
236 double high
= (double) Config
.Swap
.highWaterMark
/ 100.0;
241 static int nleast
= 0;
242 static int nconf
= 0;
243 static int *dirq
= NULL
;
244 static double *diru
= NULL
;
246 * Handle simplest case of a single swap directory immediately
248 if (Config
.cacheSwap
.n_configured
== 1)
251 * Initialise dirq on the first call or on change of number of dirs
253 if (nconf
!= Config
.cacheSwap
.n_configured
) {
254 nconf
= Config
.cacheSwap
.n_configured
;
255 nleast
= (nconf
* 3) / 4;
257 dirq
= (int *) xmalloc(sizeof(int) * nleast
);
259 diru
= (double *) xmalloc(sizeof(double) * nconf
);
260 for (j
= 0; j
< nleast
; j
++)
264 * Scan for a non-negative dirn in the dirq array and return that one
267 for (j
= 0; j
< nleast
; j
++) {
275 * If we found a valid dirn return it
280 * Now for the real guts of the algorithm - building the dirq array
282 for (i
= 0; i
< nconf
; i
++) {
284 SD
= &Config
.cacheSwap
.swapDirs
[i
];
285 SD
->flags
.selected
= 0;
288 u
= (double) SD
->cur_size
/ SD
->max_size
;
293 for (j
= 0; j
< nleast
; j
++) {
297 for (i
= 0; i
< nconf
; i
++) {
298 if (diru
[i
] < least_used
) {
299 least_used
= diru
[i
];
307 /* set selected flag for debugging/cachemgr only */
308 Config
.cacheSwap
.swapDirs
[dirn
].flags
.selected
= 1;
311 * Setup default return of 0 if no least found
321 storeDirValidFileno(int fn
)
323 int dirn
= fn
>> SWAP_DIR_SHIFT
;
324 int filn
= fn
& SWAP_FILE_MASK
;
325 if (dirn
> Config
.cacheSwap
.n_configured
)
331 if (filn
> Config
.cacheSwap
.swapDirs
[dirn
].map
->max_n_files
)
337 storeDirMapBitTest(int fn
)
339 int dirn
= fn
>> SWAP_DIR_SHIFT
;
340 int filn
= fn
& SWAP_FILE_MASK
;
341 return file_map_bit_test(Config
.cacheSwap
.swapDirs
[dirn
].map
, filn
);
345 storeDirMapBitSet(int fn
)
347 int dirn
= fn
>> SWAP_DIR_SHIFT
;
348 int filn
= fn
& SWAP_FILE_MASK
;
349 file_map_bit_set(Config
.cacheSwap
.swapDirs
[dirn
].map
, filn
);
353 storeDirMapBitReset(int fn
)
355 int dirn
= fn
>> SWAP_DIR_SHIFT
;
356 int filn
= fn
& SWAP_FILE_MASK
;
357 file_map_bit_reset(Config
.cacheSwap
.swapDirs
[dirn
].map
, filn
);
361 storeDirMapAllocate(void)
363 int dirn
= storeDirSelectSwapDir();
364 SwapDir
*SD
= &Config
.cacheSwap
.swapDirs
[dirn
];
365 int filn
= file_map_allocate(SD
->map
, SD
->suggest
);
366 SD
->suggest
= filn
+ 1;
367 return (dirn
<< SWAP_DIR_SHIFT
) | (filn
& SWAP_FILE_MASK
);
371 storeSwapDir(int dirn
)
373 assert(0 <= dirn
&& dirn
< Config
.cacheSwap
.n_configured
);
374 return Config
.cacheSwap
.swapDirs
[dirn
].path
;
378 storeDirNumber(int swap_file_number
)
380 return swap_file_number
>> SWAP_DIR_SHIFT
;
384 storeDirProperFileno(int dirn
, int fn
)
386 return (dirn
<< SWAP_DIR_SHIFT
) | (fn
& SWAP_FILE_MASK
);
390 * An entry written to the swap log MUST have the following
392 * 1. It MUST be a public key. It does no good to log
393 * a public ADD, change the key, then log a private
394 * DEL. So we need to log a DEL before we change a
395 * key from public to private.
396 * 2. It MUST have a valid (> -1) swap_file_number.
399 storeDirSwapLog(const StoreEntry
* e
, int op
)
403 dirn
= e
->swap_file_number
>> SWAP_DIR_SHIFT
;
404 assert(dirn
< Config
.cacheSwap
.n_configured
);
405 assert(!EBIT_TEST(e
->flags
, KEY_PRIVATE
));
406 assert(e
->swap_file_number
>= 0);
408 * icons and such; don't write them to the swap log
410 if (EBIT_TEST(e
->flags
, ENTRY_SPECIAL
))
412 assert(op
> SWAP_LOG_NOP
&& op
< SWAP_LOG_MAX
);
413 debug(20, 3) ("storeDirSwapLog: %s %s %08X\n",
415 storeKeyText(e
->key
),
416 e
->swap_file_number
);
417 s
= xcalloc(1, sizeof(storeSwapLogData
));
419 s
->swap_file_number
= e
->swap_file_number
;
420 s
->timestamp
= e
->timestamp
;
421 s
->lastref
= e
->lastref
;
422 s
->expires
= e
->expires
;
423 s
->lastmod
= e
->lastmod
;
424 s
->swap_file_sz
= e
->swap_file_sz
;
425 s
->refcount
= e
->refcount
;
427 xmemcpy(s
->key
, e
->key
, MD5_DIGEST_CHARS
);
428 file_write(Config
.cacheSwap
.swapDirs
[dirn
].swaplog_fd
,
431 sizeof(storeSwapLogData
),
438 storeDirSwapLogFile(int dirn
, const char *ext
)
440 LOCAL_ARRAY(char, path
, SQUID_MAXPATHLEN
);
441 LOCAL_ARRAY(char, digit
, 32);
442 if (Config
.Log
.swap
) {
443 xstrncpy(path
, Config
.Log
.swap
, SQUID_MAXPATHLEN
- 64);
445 snprintf(digit
, 32, "%02d", dirn
);
446 strncat(path
, digit
, 3);
448 xstrncpy(path
, storeSwapDir(dirn
), SQUID_MAXPATHLEN
- 64);
449 strcat(path
, "/swap.state");
452 strncat(path
, ext
, 16);
457 storeDirOpenSwapLogs(void)
463 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++) {
464 SD
= &Config
.cacheSwap
.swapDirs
[i
];
465 path
= storeDirSwapLogFile(i
, NULL
);
466 fd
= file_open(path
, O_WRONLY
| O_CREAT
, NULL
, NULL
, NULL
);
468 debug(50, 1) ("%s: %s\n", path
, xstrerror());
469 fatal("storeDirOpenSwapLogs: Failed to open swap log.");
471 debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", i
, fd
);
477 storeDirCloseSwapLogs(void)
481 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++) {
482 SD
= &Config
.cacheSwap
.swapDirs
[i
];
483 if (SD
->swaplog_fd
< 0) /* not open */
485 file_close(SD
->swaplog_fd
);
486 debug(47, 3) ("Cache Dir #%d log closed on FD %d\n", i
, SD
->swaplog_fd
);
492 storeDirOpenTmpSwapLog(int dirn
, int *clean_flag
, int *zero_flag
)
494 char *swaplog_path
= xstrdup(storeDirSwapLogFile(dirn
, NULL
));
495 char *clean_path
= xstrdup(storeDirSwapLogFile(dirn
, ".last-clean"));
496 char *new_path
= xstrdup(storeDirSwapLogFile(dirn
, ".new"));
498 struct stat clean_sb
;
499 SwapDir
*SD
= &Config
.cacheSwap
.swapDirs
[dirn
];
502 if (stat(swaplog_path
, &log_sb
) < 0) {
503 debug(47, 1) ("Cache Dir #%d: No log file\n", dirn
);
504 safe_free(swaplog_path
);
505 safe_free(clean_path
);
509 *zero_flag
= log_sb
.st_size
== 0 ? 1 : 0;
510 /* close the existing write-only FD */
511 if (SD
->swaplog_fd
>= 0)
512 file_close(SD
->swaplog_fd
);
513 /* open a write-only FD for the new log */
514 fd
= file_open(new_path
, O_WRONLY
| O_CREAT
| O_TRUNC
, NULL
, NULL
, NULL
);
516 debug(50, 1) ("%s: %s\n", new_path
, xstrerror());
517 fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
520 /* open a read-only stream of the old log */
521 fp
= fopen(swaplog_path
, "r");
523 debug(50, 0) ("%s: %s\n", swaplog_path
, xstrerror());
524 fatal("Failed to open swap log for reading");
526 memset(&clean_sb
, '\0', sizeof(struct stat
));
527 if (stat(clean_path
, &clean_sb
) < 0)
529 else if (clean_sb
.st_mtime
< log_sb
.st_mtime
)
533 safeunlink(clean_path
, 1);
534 safe_free(swaplog_path
);
535 safe_free(clean_path
);
541 storeDirCloseTmpSwapLog(int dirn
)
543 char *swaplog_path
= xstrdup(storeDirSwapLogFile(dirn
, NULL
));
544 char *new_path
= xstrdup(storeDirSwapLogFile(dirn
, ".new"));
545 SwapDir
*SD
= &Config
.cacheSwap
.swapDirs
[dirn
];
547 file_close(SD
->swaplog_fd
);
548 if (rename(new_path
, swaplog_path
) < 0) {
549 debug(50, 0) ("%s,%s: %s\n", new_path
, swaplog_path
, xstrerror());
550 fatal("storeDirCloseTmpSwapLog: rename failed");
552 fd
= file_open(swaplog_path
, O_WRONLY
| O_CREAT
, NULL
, NULL
, NULL
);
554 debug(50, 1) ("%s: %s\n", swaplog_path
, xstrerror());
555 fatal("storeDirCloseTmpSwapLog: Failed to open swap log.");
557 safe_free(swaplog_path
);
560 debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", dirn
, fd
);
564 storeDirUpdateSwapSize(int fn
, size_t size
, int sign
)
566 int dirn
= (fn
>> SWAP_DIR_SHIFT
) % Config
.cacheSwap
.n_configured
;
567 int k
= ((size
+ 1023) >> 10) * sign
;
568 Config
.cacheSwap
.swapDirs
[dirn
].cur_size
+= k
;
569 store_swap_size
+= k
;
577 storeDirStats(StoreEntry
* sentry
)
584 storeAppendPrintf(sentry
, "Store Directory Statistics:\n");
585 storeAppendPrintf(sentry
, "Store Entries : %d\n",
586 memInUse(MEM_STOREENTRY
));
587 storeAppendPrintf(sentry
, "Maximum Swap Size : %8d KB\n",
588 Config
.Swap
.maxSize
);
589 storeAppendPrintf(sentry
, "Current Store Swap Size: %8d KB\n",
591 storeAppendPrintf(sentry
, "Current Capacity : %d%% used, %d%% free\n",
592 percent((int) store_swap_size
, (int) Config
.Swap
.maxSize
),
593 percent((int) (Config
.Swap
.maxSize
- store_swap_size
), (int) Config
.Swap
.maxSize
));
594 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++) {
595 SD
= &Config
.cacheSwap
.swapDirs
[i
];
596 storeAppendPrintf(sentry
, "\n");
597 storeAppendPrintf(sentry
, "Store Directory #%d: %s\n", i
, SD
->path
);
598 storeAppendPrintf(sentry
, "First level subdirectories: %d\n", SD
->l1
);
599 storeAppendPrintf(sentry
, "Second level subdirectories: %d\n", SD
->l2
);
600 storeAppendPrintf(sentry
, "Maximum Size: %d KB\n", SD
->max_size
);
601 storeAppendPrintf(sentry
, "Current Size: %d KB\n", SD
->cur_size
);
602 storeAppendPrintf(sentry
, "Percent Used: %0.2f%%\n",
603 100.0 * SD
->cur_size
/ SD
->max_size
);
604 storeAppendPrintf(sentry
, "Filemap bits in use: %d of %d (%d%%)\n",
605 SD
->map
->n_files_in_map
, SD
->map
->max_n_files
,
606 percent(SD
->map
->n_files_in_map
, SD
->map
->max_n_files
));
608 #define fsbtoblk(num, fsbs, bs) \
609 (((fsbs) != 0 && (fsbs) < (bs)) ? \
610 (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs)))
611 if (!statvfs(SD
->path
, &sfs
)) {
612 storeAppendPrintf(sentry
, "Filesystem Space in use: %d/%d KB (%d%%)\n",
613 fsbtoblk((sfs
.f_blocks
- sfs
.f_bfree
), sfs
.f_frsize
, 1024),
614 fsbtoblk(sfs
.f_blocks
, sfs
.f_frsize
, 1024),
615 percent(sfs
.f_blocks
- sfs
.f_bfree
, sfs
.f_blocks
));
616 storeAppendPrintf(sentry
, "Filesystem Inodes in use: %d/%d (%d%%)\n",
617 sfs
.f_files
- sfs
.f_ffree
, sfs
.f_files
,
618 percent(sfs
.f_files
- sfs
.f_ffree
, sfs
.f_files
));
621 storeAppendPrintf(sentry
, "Flags:");
622 if (SD
->flags
.selected
)
623 storeAppendPrintf(sentry
, " SELECTED");
624 storeAppendPrintf(sentry
, "\n");
629 storeDirMapBitsInUse(void)
633 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++)
634 n
+= Config
.cacheSwap
.swapDirs
[i
].map
->n_files_in_map
;
639 * storeDirWriteCleanLogs
641 * Writes a "clean" swap log file from in-memory metadata.
643 #define CLEAN_BUF_SZ 16384
645 storeDirWriteCleanLogs(int reopen
)
647 StoreEntry
*e
= NULL
;
650 time_t start
, stop
, r
;
656 int N
= Config
.cacheSwap
.n_configured
;
661 size_t ss
= sizeof(storeSwapLogData
);
662 if (store_rebuilding
) {
663 debug(20, 1) ("Not currently OK to rewrite swap log.\n");
664 debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.\n");
667 debug(20, 1) ("storeDirWriteCleanLogs: Starting...\n");
668 start
= squid_curtime
;
669 fd
= xcalloc(N
, sizeof(int));
670 cur
= xcalloc(N
, sizeof(char *));
671 new = xcalloc(N
, sizeof(char *));
672 cln
= xcalloc(N
, sizeof(char *));
673 for (dirn
= 0; dirn
< N
; dirn
++) {
675 cur
[dirn
] = xstrdup(storeDirSwapLogFile(dirn
, NULL
));
676 new[dirn
] = xstrdup(storeDirSwapLogFile(dirn
, ".clean"));
677 cln
[dirn
] = xstrdup(storeDirSwapLogFile(dirn
, ".last-clean"));
680 fd
[dirn
] = file_open(new[dirn
],
681 O_WRONLY
| O_CREAT
| O_TRUNC
,
686 debug(50, 0) ("storeDirWriteCleanLogs: %s: %s\n", new[dirn
], xstrerror());
689 debug(20, 3) ("storeDirWriteCleanLogs: opened %s, FD %d\n",
690 new[dirn
], fd
[dirn
]);
692 if (stat(cur
[dirn
], &sb
) == 0)
693 fchmod(fd
[dirn
], sb
.st_mode
);
696 outbuf
= xcalloc(N
, sizeof(char *));
697 outbufoffset
= xcalloc(N
, sizeof(*outbufoffset
));
698 for (dirn
= 0; dirn
< N
; dirn
++) {
699 outbuf
[dirn
] = xcalloc(CLEAN_BUF_SZ
, 1);
700 outbufoffset
[dirn
] = 0;
702 for (m
= store_list
.tail
; m
; m
= m
->prev
) {
704 if (e
->swap_file_number
< 0)
706 if (e
->swap_status
!= SWAPOUT_DONE
)
708 if (e
->swap_file_sz
<= 0)
710 if (EBIT_TEST(e
->flags
, RELEASE_REQUEST
))
712 if (EBIT_TEST(e
->flags
, KEY_PRIVATE
))
714 if (EBIT_TEST(e
->flags
, ENTRY_SPECIAL
))
716 dirn
= storeDirNumber(e
->swap_file_number
);
720 memset(&s
, '\0', ss
);
721 s
.op
= (char) SWAP_LOG_ADD
;
722 s
.swap_file_number
= e
->swap_file_number
;
723 s
.timestamp
= e
->timestamp
;
724 s
.lastref
= e
->lastref
;
725 s
.expires
= e
->expires
;
726 s
.lastmod
= e
->lastmod
;
727 s
.swap_file_sz
= e
->swap_file_sz
;
728 s
.refcount
= e
->refcount
;
730 xmemcpy(&s
.key
, e
->key
, MD5_DIGEST_CHARS
);
731 xmemcpy(outbuf
[dirn
] + outbufoffset
[dirn
], &s
, ss
);
732 outbufoffset
[dirn
] += ss
;
734 if (outbufoffset
[dirn
] + ss
> CLEAN_BUF_SZ
) {
735 if (write(fd
[dirn
], outbuf
[dirn
], outbufoffset
[dirn
]) < 0) {
736 debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
737 new[dirn
], xstrerror());
738 debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n");
739 file_close(fd
[dirn
]);
744 outbufoffset
[dirn
] = 0;
746 if ((++n
& 0xFFFF) == 0) {
748 debug(20, 1) (" %7d entries written so far.\n", n
);
752 for (dirn
= 0; dirn
< N
; dirn
++) {
753 if (outbufoffset
[dirn
] == 0)
757 if (write(fd
[dirn
], outbuf
[dirn
], outbufoffset
[dirn
]) < 0) {
758 debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
759 new[dirn
], xstrerror());
760 debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n");
761 file_close(fd
[dirn
]);
766 safe_free(outbuf
[dirn
]);
769 safe_free(outbufoffset
);
772 * You can't rename open files on Microsoft "operating systems"
773 * so we close before renaming.
775 storeDirCloseSwapLogs();
778 for (dirn
= 0; dirn
< N
; dirn
++) {
781 if (rename(new[dirn
], cur
[dirn
]) < 0) {
782 debug(50, 0) ("storeDirWriteCleanLogs: rename failed: %s, %s -> %s\n",
783 xstrerror(), new[dirn
], cur
[dirn
]);
786 #ifndef _SQUID_MSWIN_
787 storeDirCloseSwapLogs();
790 storeDirOpenSwapLogs();
791 stop
= squid_curtime
;
793 debug(20, 1) (" Finished. Wrote %d entries.\n", n
);
794 debug(20, 1) (" Took %d seconds (%6.1f entries/sec).\n",
796 (double) n
/ (r
> 0 ? r
: 1));
797 /* touch a timestamp file if we're not still validating */
798 if (!store_rebuilding
) {
799 for (dirn
= 0; dirn
< N
; dirn
++) {
802 file_close(file_open(cln
[dirn
],
803 O_WRONLY
| O_CREAT
| O_TRUNC
, NULL
, NULL
, NULL
));
807 for (dirn
= 0; dirn
< N
; dirn
++) {
808 safe_free(cur
[dirn
]);
809 safe_free(new[dirn
]);
810 safe_free(cln
[dirn
]);
813 file_close(fd
[dirn
]);
825 storeDirConfigure(void)
831 Config
.Swap
.maxSize
= 0;
832 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++) {
833 SD
= &Config
.cacheSwap
.swapDirs
[i
];;
834 Config
.Swap
.maxSize
+= SD
->max_size
;
835 n
= 2 * SD
->max_size
/ Config
.Store
.avgObjectSize
;
836 if (NULL
== SD
->map
) {
838 SD
->map
= file_map_create(n
);
839 } else if (n
> SD
->map
->max_n_files
) {
840 /* it grew, need to expand */
841 fm
= file_map_create(n
);
842 filemapCopy(SD
->map
, fm
);
843 filemapFreeMemory(SD
->map
);
846 /* else it shrunk, and we leave the old one in place */
851 storeDirDiskFull(int fn
)
853 int dirn
= fn
>> SWAP_DIR_SHIFT
;
854 SwapDir
*SD
= &Config
.cacheSwap
.swapDirs
[dirn
];
855 assert(0 <= dirn
&& dirn
< Config
.cacheSwap
.n_configured
);
856 SD
->max_size
= SD
->cur_size
;
857 debug(20, 1) ("WARNING: Shrinking cache_dir #%d to %d KB\n",