]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_dir.cc
make netdbExchangeStart standard
[thirdparty/squid.git] / src / store_dir.cc
CommitLineData
f1dc9b30 1
2/*
0ce5d801 3 * $Id: store_dir.cc,v 1.64 1998/04/16 17:47:15 wessels Exp $
f1dc9b30 4 *
5 * DEBUG: section 47 Store Directory Routines
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * --------------------------------------------------------
10 *
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
14 * the National Science Foundation.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 */
31
596dddc1 32#include "squid.h"
596dddc1 33
34#define SWAP_DIR_SHIFT 24
35#define SWAP_FILE_MASK 0x00FFFFFF
36#define DefaultLevelOneDirs 16
37#define DefaultLevelTwoDirs 256
38
85407535 39static char *storeSwapSubDir(int dirn, int subdirn);
40static int storeMostFreeSwapDir(void);
41static int storeVerifyDirectory(const char *path);
42static void storeCreateDirectory(const char *path, int lvl);
43static void storeCreateSwapSubDirs(int j);
44
596dddc1 45/* return full name to swapfile */
46char *
47storeSwapFullPath(int fn, char *fullpath)
48{
49 LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
f1dc9b30 50 int dirn = (fn >> SWAP_DIR_SHIFT) % Config.cacheSwap.n_configured;
596dddc1 51 int filn = fn & SWAP_FILE_MASK;
27a4d8b1 52 int L1 = Config.cacheSwap.swapDirs[dirn].l1;
53 int L2 = Config.cacheSwap.swapDirs[dirn].l2;
596dddc1 54 if (!fullpath)
55 fullpath = fullfilename;
56 fullpath[0] = '\0';
6cf028ab 57 snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X/%08X",
58 Config.cacheSwap.swapDirs[dirn].path,
27a4d8b1 59 ((filn / L2) / L2) % L1,
60 (filn / L2) % L2,
6cf028ab 61 filn);
596dddc1 62 return fullpath;
63}
64
85407535 65static char *
66storeSwapSubDir(int dirn, int subdirn)
67{
68 LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
69 SwapDir *SD;
70 assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
71 SD = &Config.cacheSwap.swapDirs[dirn];
72 assert(0 <= subdirn && subdirn < SD->l1);
73 snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%02X",
74 Config.cacheSwap.swapDirs[dirn].path,
75 subdirn);
76 return fullfilename;
77}
78
0c04c389 79char *
80storeSwapSubSubDir(int fn, char *fullpath)
81{
82 LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
f1dc9b30 83 int dirn = (fn >> SWAP_DIR_SHIFT) % Config.cacheSwap.n_configured;
0c04c389 84 int filn = fn & SWAP_FILE_MASK;
27a4d8b1 85 int L1 = Config.cacheSwap.swapDirs[dirn].l1;
86 int L2 = Config.cacheSwap.swapDirs[dirn].l2;
0c04c389 87 if (!fullpath)
88 fullpath = fullfilename;
89 fullpath[0] = '\0';
56878878 90 snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X",
6cf028ab 91 Config.cacheSwap.swapDirs[dirn].path,
27a4d8b1 92 ((filn / L2) / L2) % L1,
93 (filn / L2) % L2);
0c04c389 94 return fullpath;
95}
96
68c2e6f7 97/*
98 * Does swapfile number 'fn' belong in cachedir #F0,
99 * level1 dir #F1, level2 dir #F2?
100 *
101 * This is called by storeDirClean(), but placed here because
102 * the algorithm needs to match storeSwapSubSubDir().
b109de6b 103 *
104 * Don't check that (fn >> SWAP_DIR_SHIFT) == F0 because
105 * 'fn' may not have the directory bits set.
68c2e6f7 106 */
107int
108storeFilenoBelongsHere(int fn, int F0, int F1, int F2)
109{
b109de6b 110 int D1, D2;
68c2e6f7 111 int L1, L2;
112 int filn = fn & SWAP_FILE_MASK;
b109de6b 113 assert(F0 < Config.cacheSwap.n_configured);
114 L1 = Config.cacheSwap.swapDirs[F0].l1;
115 L2 = Config.cacheSwap.swapDirs[F0].l2;
68c2e6f7 116 D1 = ((filn / L2) / L2) % L1;
117 if (F1 != D1)
118 return 0;
119 D2 = (filn / L2) % L2;
120 if (F2 != D2)
121 return 0;
122 return 1;
123}
124
c7863c6f 125static void
85407535 126storeCreateDirectory(const char *path, int lvl)
127{
128 struct stat st;
129 if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
130 debug(20, lvl) ("%s exists\n", path);
131 } else if (mkdir(path, 0755) == 0) {
132 debug(20, lvl) ("%s created\n", path);
133 } else if (errno == EEXIST) {
134 debug(20, lvl) ("%s exists\n", path);
135 } else {
136 snprintf(tmp_error_buf, ERROR_BUF_SZ,
137 "Failed to make swap directory %s: %s",
138 path, xstrerror());
139 fatal(tmp_error_buf);
140 }
141}
142
596dddc1 143static int
85407535 144storeVerifyDirectory(const char *path)
596dddc1 145{
146 struct stat sb;
85407535 147 if (stat(path, &sb) < 0) {
148 debug(20, 0) ("%s: %s\n", path, xstrerror());
149 return -1;
047146c3 150 }
85407535 151 if (S_ISDIR(sb.st_mode) == 0) {
152 debug(20, 0) ("%s is not a directory\n", path);
153 return -1;
596dddc1 154 }
85407535 155 return 0;
596dddc1 156}
157
85407535 158/*
159 * This function is called by storeInit(). If this returns < 0,
160 * then Squid exits, complains about swap directories not
161 * existing, and instructs the admin to run 'squid -z'
162 */
596dddc1 163int
85407535 164storeVerifyCacheDirs(void)
165{
166 int i;
167 int j;
168 const char *path;
169 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
170 path = Config.cacheSwap.swapDirs[i].path;
171 if (storeVerifyDirectory(path) < 0)
172 return -1;
173 for (j = 0; j < Config.cacheSwap.swapDirs[i].l1; j++) {
174 path = storeSwapSubDir(i, j);
175 if (storeVerifyDirectory(path) < 0)
176 return -1;
177 }
178 }
179 return 0;
180}
181
182void
183storeCreateSwapDirectories(void)
596dddc1 184{
185 int i;
186 const char *path = NULL;
f1dc9b30 187 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
188 path = Config.cacheSwap.swapDirs[i].path;
85407535 189 debug(47, 3) ("Creating swap space in %s\n", path);
190 storeCreateDirectory(path, 0);
047146c3 191 storeCreateSwapSubDirs(i);
596dddc1 192 }
596dddc1 193}
194
85407535 195static void
596dddc1 196storeCreateSwapSubDirs(int j)
197{
198 int i, k;
f1dc9b30 199 SwapDir *SD = &Config.cacheSwap.swapDirs[j];
596dddc1 200 LOCAL_ARRAY(char, name, MAXPATHLEN);
201 for (i = 0; i < SD->l1; i++) {
56878878 202 snprintf(name, MAXPATHLEN, "%s/%02X", SD->path, i);
85407535 203 storeCreateDirectory(name, 0);
f1dc9b30 204 debug(47, 1) ("Making directories in %s\n", name);
596dddc1 205 for (k = 0; k < SD->l2; k++) {
042461c3 206 snprintf(name, MAXPATHLEN, "%s/%02X/%02X", SD->path, i, k);
85407535 207 storeCreateDirectory(name, 2);
596dddc1 208 }
209 }
210}
211
85407535 212static int
596dddc1 213storeMostFreeSwapDir(void)
214{
c932b107 215 double least_used = 1.0;
216 double this_used;
596dddc1 217 int dirn = 0;
218 int i;
c932b107 219 SwapDir *SD;
f1dc9b30 220 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
221 SD = &Config.cacheSwap.swapDirs[i];
c932b107 222 this_used = (double) SD->cur_size / SD->max_size;
223 if (this_used > least_used)
596dddc1 224 continue;
c932b107 225 if (SD->read_only)
596dddc1 226 continue;
c932b107 227 least_used = this_used;
596dddc1 228 dirn = i;
229 }
230 return dirn;
231}
232
e3ef2b09 233int
234storeDirValidFileno(int fn)
235{
236 int dirn = fn >> SWAP_DIR_SHIFT;
237 int filn = fn & SWAP_FILE_MASK;
e3ef2b09 238 if (dirn > Config.cacheSwap.n_configured)
239 return 0;
8c128028 240 if (dirn < 0)
241 return 0;
242 if (filn < 0)
243 return 0;
244 if (filn > Config.cacheSwap.swapDirs[dirn].map->max_n_files)
e3ef2b09 245 return 0;
246 return 1;
247}
248
0c04c389 249int
250storeDirMapBitTest(int fn)
251{
252 int dirn = fn >> SWAP_DIR_SHIFT;
253 int filn = fn & SWAP_FILE_MASK;
f1dc9b30 254 return file_map_bit_test(Config.cacheSwap.swapDirs[dirn].map, filn);
0c04c389 255}
256
596dddc1 257void
258storeDirMapBitSet(int fn)
259{
260 int dirn = fn >> SWAP_DIR_SHIFT;
261 int filn = fn & SWAP_FILE_MASK;
f1dc9b30 262 file_map_bit_set(Config.cacheSwap.swapDirs[dirn].map, filn);
596dddc1 263}
264
265void
266storeDirMapBitReset(int fn)
267{
268 int dirn = fn >> SWAP_DIR_SHIFT;
269 int filn = fn & SWAP_FILE_MASK;
f1dc9b30 270 file_map_bit_reset(Config.cacheSwap.swapDirs[dirn].map, filn);
596dddc1 271}
272
273int
274storeDirMapAllocate(void)
275{
276 int dirn = storeMostFreeSwapDir();
f1dc9b30 277 SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
596dddc1 278 int filn = file_map_allocate(SD->map, SD->suggest);
6cf028ab 279 SD->suggest = filn + 1;
a7e9d816 280 return (dirn << SWAP_DIR_SHIFT) | (filn & SWAP_FILE_MASK);
596dddc1 281}
282
283char *
284storeSwapDir(int dirn)
285{
6d80d9a6 286 assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
f1dc9b30 287 return Config.cacheSwap.swapDirs[dirn].path;
596dddc1 288}
4683e377 289
5608850b 290int
291storeDirNumber(int swap_file_number)
292{
293 return swap_file_number >> SWAP_DIR_SHIFT;
294}
295
c932b107 296int
297storeDirProperFileno(int dirn, int fn)
298{
299 return (dirn << SWAP_DIR_SHIFT) | (fn & SWAP_FILE_MASK);
300}
301
b109de6b 302/*
303 * An entry written to the swap log MUST have the following
304 * properties.
305 * 1. It MUST be a public key. It does no good to log
306 * a public ADD, change the key, then log a private
307 * DEL. So we need to log a DEL before we change a
308 * key from public to private.
309 * 2. It MUST have a valid (> -1) swap_file_number.
310 */
4683e377 311void
5830cdb3 312storeDirSwapLog(const StoreEntry * e, int op)
4683e377 313{
6a76db70 314 storeSwapLogData *s;
4683e377 315 int dirn;
4683e377 316 dirn = e->swap_file_number >> SWAP_DIR_SHIFT;
f1dc9b30 317 assert(dirn < Config.cacheSwap.n_configured);
b109de6b 318 assert(!EBIT_TEST(e->flag, KEY_PRIVATE));
319 assert(e->swap_file_number >= 0);
6c57e268 320 /*
321 * icons and such; don't write them to the swap log
322 */
323 if (EBIT_TEST(e->flag, ENTRY_SPECIAL))
324 return;
b109de6b 325 assert(op > SWAP_LOG_NOP && op < SWAP_LOG_MAX);
07304bf9 326 debug(20, 3) ("storeDirSwapLog: %s %s %08X\n",
b109de6b 327 swap_log_op_str[op],
07304bf9 328 storeKeyText(e->key),
329 e->swap_file_number);
6a76db70 330 s = xcalloc(1, sizeof(storeSwapLogData));
5830cdb3 331 s->op = (char) op;
332 s->swap_file_number = e->swap_file_number;
333 s->timestamp = e->timestamp;
334 s->lastref = e->lastref;
335 s->expires = e->expires;
336 s->lastmod = e->lastmod;
07304bf9 337 s->swap_file_sz = e->swap_file_sz;
5830cdb3 338 s->refcount = e->refcount;
339 s->flags = e->flag;
340 xmemcpy(s->key, e->key, MD5_DIGEST_CHARS);
f1dc9b30 341 file_write(Config.cacheSwap.swapDirs[dirn].swaplog_fd,
d377699f 342 -1,
5830cdb3 343 s,
07304bf9 344 sizeof(storeSwapLogData),
5608850b 345 NULL,
346 NULL,
347 xfree);
4683e377 348}
349
5608850b 350char *
351storeDirSwapLogFile(int dirn, const char *ext)
4683e377 352{
353 LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN);
354 LOCAL_ARRAY(char, digit, 32);
355 if (Config.Log.swap) {
356 xstrncpy(path, Config.Log.swap, SQUID_MAXPATHLEN - 64);
357 strcat(path, ".");
042461c3 358 snprintf(digit, 32, "%02d", dirn);
5608850b 359 strncat(path, digit, 3);
4683e377 360 } else {
361 xstrncpy(path, storeSwapDir(dirn), SQUID_MAXPATHLEN - 64);
d0d3ec94 362 strcat(path, "/swap.state");
4683e377 363 }
5608850b 364 if (ext)
365 strncat(path, ext, 16);
4683e377 366 return path;
367}
368
369void
370storeDirOpenSwapLogs(void)
371{
372 int i;
4683e377 373 char *path;
5608850b 374 int fd;
4683e377 375 SwapDir *SD;
f1dc9b30 376 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
377 SD = &Config.cacheSwap.swapDirs[i];
5608850b 378 path = storeDirSwapLogFile(i, NULL);
6cf028ab 379 fd = file_open(path, O_WRONLY | O_CREAT, NULL, NULL, NULL);
4683e377 380 if (fd < 0) {
a3d5953d 381 debug(50, 1) ("%s: %s\n", path, xstrerror());
4683e377 382 fatal("storeDirOpenSwapLogs: Failed to open swap log.");
383 }
f1dc9b30 384 debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", i, fd);
4683e377 385 SD->swaplog_fd = fd;
386 }
387}
5608850b 388
389void
390storeDirCloseSwapLogs(void)
391{
392 int i;
393 SwapDir *SD;
f1dc9b30 394 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
395 SD = &Config.cacheSwap.swapDirs[i];
edd2eb63 396 if (SD->swaplog_fd < 0) /* not open */
397 continue;
5608850b 398 file_close(SD->swaplog_fd);
f1dc9b30 399 debug(47, 3) ("Cache Dir #%d log closed on FD %d\n", i, SD->swaplog_fd);
e7a22b88 400 SD->swaplog_fd = -1;
5608850b 401 }
402}
403
404FILE *
25535cbe 405storeDirOpenTmpSwapLog(int dirn, int *clean_flag, int *zero_flag)
5608850b 406{
407 char *swaplog_path = xstrdup(storeDirSwapLogFile(dirn, NULL));
408 char *clean_path = xstrdup(storeDirSwapLogFile(dirn, ".last-clean"));
409 char *new_path = xstrdup(storeDirSwapLogFile(dirn, ".new"));
410 struct stat log_sb;
411 struct stat clean_sb;
f1dc9b30 412 SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
5608850b 413 FILE *fp;
414 int fd;
415 if (stat(swaplog_path, &log_sb) < 0) {
f1dc9b30 416 debug(47, 1) ("Cache Dir #%d: No log file\n", dirn);
5608850b 417 safe_free(swaplog_path);
418 safe_free(clean_path);
419 safe_free(new_path);
420 return NULL;
421 }
25535cbe 422 *zero_flag = log_sb.st_size == 0 ? 1 : 0;
5608850b 423 /* close the existing write-only FD */
95d15928 424 if (SD->swaplog_fd >= 0)
4f92c80c 425 file_close(SD->swaplog_fd);
5608850b 426 /* open a write-only FD for the new log */
6cf028ab 427 fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC, NULL, NULL, NULL);
5608850b 428 if (fd < 0) {
a3d5953d 429 debug(50, 1) ("%s: %s\n", new_path, xstrerror());
5608850b 430 fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
431 }
432 SD->swaplog_fd = fd;
433 /* open a read-only stream of the old log */
434 fp = fopen(swaplog_path, "r");
435 if (fp == NULL) {
a3d5953d 436 debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror());
5608850b 437 fatal("Failed to open swap log for reading");
438 }
f88211e8 439 memset(&clean_sb, '\0', sizeof(struct stat));
5608850b 440 if (stat(clean_path, &clean_sb) < 0)
441 *clean_flag = 0;
442 else if (clean_sb.st_mtime < log_sb.st_mtime)
443 *clean_flag = 0;
444 else
445 *clean_flag = 1;
446 safeunlink(clean_path, 1);
447 safe_free(swaplog_path);
448 safe_free(clean_path);
449 safe_free(new_path);
450 return fp;
451}
452
453void
454storeDirCloseTmpSwapLog(int dirn)
455{
456 char *swaplog_path = xstrdup(storeDirSwapLogFile(dirn, NULL));
457 char *new_path = xstrdup(storeDirSwapLogFile(dirn, ".new"));
f1dc9b30 458 SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
5608850b 459 int fd;
df087e68 460 file_close(SD->swaplog_fd);
5608850b 461 if (rename(new_path, swaplog_path) < 0) {
a3d5953d 462 debug(50, 0) ("%s,%s: %s\n", new_path, swaplog_path, xstrerror());
5608850b 463 fatal("storeDirCloseTmpSwapLog: rename failed");
464 }
6cf028ab 465 fd = file_open(swaplog_path, O_WRONLY | O_CREAT, NULL, NULL, NULL);
5608850b 466 if (fd < 0) {
a3d5953d 467 debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror());
5608850b 468 fatal("storeDirCloseTmpSwapLog: Failed to open swap log.");
469 }
e7a22b88 470 safe_free(swaplog_path);
471 safe_free(new_path);
5608850b 472 SD->swaplog_fd = fd;
f1dc9b30 473 debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", dirn, fd);
5608850b 474}
76fefb77 475
476void
c932b107 477storeDirUpdateSwapSize(int fn, size_t size, int sign)
76fefb77 478{
f1dc9b30 479 int dirn = (fn >> SWAP_DIR_SHIFT) % Config.cacheSwap.n_configured;
c932b107 480 int k = ((size + 1023) >> 10) * sign;
f1dc9b30 481 Config.cacheSwap.swapDirs[dirn].cur_size += k;
76fefb77 482 store_swap_size += k;
483}
c932b107 484
485void
3e347513 486storeDirStats(StoreEntry * sentry)
c932b107 487{
488 int i;
489 SwapDir *SD;
490 storeAppendPrintf(sentry, "Store Directory Statistics:\n");
3f6c0fb2 491 storeAppendPrintf(sentry, "Store Entries : %d\n",
492 memInUse(MEM_STOREENTRY));
493 storeAppendPrintf(sentry, "Maximum Swap Size : %8d KB\n",
494 Config.Swap.maxSize);
495 storeAppendPrintf(sentry, "Current Store Swap Size: %8d KB\n",
496 store_swap_size);
dd8037ab 497 storeAppendPrintf(sentry, "Current Capacity : %d%% used, %d%% free\n",
498 percent((int) store_swap_size, (int) Config.Swap.maxSize),
38d04788 499 percent((int) (Config.Swap.maxSize - store_swap_size), (int) Config.Swap.maxSize));
f1dc9b30 500 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
501 SD = &Config.cacheSwap.swapDirs[i];
c932b107 502 storeAppendPrintf(sentry, "\n");
503 storeAppendPrintf(sentry, "Store Directory #%d: %s\n", i, SD->path);
504 storeAppendPrintf(sentry, "First level subdirectories: %d\n", SD->l1);
505 storeAppendPrintf(sentry, "Second level subdirectories: %d\n", SD->l2);
506 storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size);
507 storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size);
508 storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n",
3e347513 509 100.0 * SD->cur_size / SD->max_size);
0ce5d801 510 storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n",
511 SD->map->n_files_in_map, SD->map->max_n_files,
512 percent(SD->map->n_files_in_map, SD->map->max_n_files));
c932b107 513 }
514}
e3ef2b09 515
5d406e78 516int
517storeDirMapBitsInUse(void)
518{
519 int i;
520 int n = 0;
521 for (i = 0; i < Config.cacheSwap.n_configured; i++)
522 n += Config.cacheSwap.swapDirs[i].map->n_files_in_map;
523 return n;
524}
525
e3ef2b09 526/*
527 * storeDirWriteCleanLogs
528 *
529 * Writes a "clean" swap log file from in-memory metadata.
530 */
531#define CLEAN_BUF_SZ 16384
532int
533storeDirWriteCleanLogs(int reopen)
534{
535 StoreEntry *e = NULL;
536 int *fd;
e3ef2b09 537 int n = 0;
538 time_t start, stop, r;
539 struct stat sb;
540 char **cur;
541 char **new;
542 char **cln;
543 int dirn;
ea524965 544 int N = Config.cacheSwap.n_configured;
e3ef2b09 545 dlink_node *m;
7be811df 546 char **outbuf;
547 off_t *outbufoffset;
9748816a 548 storeSwapLogData s;
549 size_t ss = sizeof(storeSwapLogData);
e3ef2b09 550 if (store_rebuilding) {
551 debug(20, 1) ("Not currently OK to rewrite swap log.\n");
552 debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.\n");
61316c1b 553#if DONT
554 /*
555 * why did we want to close the current swap logs here?
556 * DW/1.2.beta19
557 */
e3ef2b09 558 storeDirCloseSwapLogs();
61316c1b 559#endif
e3ef2b09 560 return 0;
561 }
562 debug(20, 1) ("storeDirWriteCleanLogs: Starting...\n");
563 start = squid_curtime;
ea524965 564 fd = xcalloc(N, sizeof(int));
565 cur = xcalloc(N, sizeof(char *));
566 new = xcalloc(N, sizeof(char *));
567 cln = xcalloc(N, sizeof(char *));
568 for (dirn = 0; dirn < N; dirn++) {
e3ef2b09 569 fd[dirn] = -1;
570 cur[dirn] = xstrdup(storeDirSwapLogFile(dirn, NULL));
571 new[dirn] = xstrdup(storeDirSwapLogFile(dirn, ".clean"));
572 cln[dirn] = xstrdup(storeDirSwapLogFile(dirn, ".last-clean"));
573 unlink(new[dirn]);
574 unlink(cln[dirn]);
575 fd[dirn] = file_open(new[dirn],
576 O_WRONLY | O_CREAT | O_TRUNC,
577 NULL,
578 NULL,
579 NULL);
580 if (fd[dirn] < 0) {
581 debug(50, 0) ("storeDirWriteCleanLogs: %s: %s\n", new[dirn], xstrerror());
582 continue;
583 }
27a4d8b1 584 debug(20, 3) ("storeDirWriteCleanLogs: opened %s, FD %d\n",
585 new[dirn], fd[dirn]);
e3ef2b09 586#if HAVE_FCHMOD
587 if (stat(cur[dirn], &sb) == 0)
588 fchmod(fd[dirn], sb.st_mode);
589#endif
590 }
ea524965 591 outbuf = xcalloc(N, sizeof(char *));
592 outbufoffset = xcalloc(N, sizeof(*outbufoffset));
593 for (dirn = 0; dirn < N; dirn++) {
594 outbuf[dirn] = xcalloc(CLEAN_BUF_SZ, 1);
7be811df 595 outbufoffset[dirn] = 0;
e3ef2b09 596 }
597 for (m = store_list.tail; m; m = m->prev) {
598 e = m->data;
599 if (e->swap_file_number < 0)
600 continue;
601 if (e->swap_status != SWAPOUT_DONE)
602 continue;
07304bf9 603 if (e->swap_file_sz <= 0)
e3ef2b09 604 continue;
605 if (EBIT_TEST(e->flag, RELEASE_REQUEST))
606 continue;
607 if (EBIT_TEST(e->flag, KEY_PRIVATE))
608 continue;
6c57e268 609 if (EBIT_TEST(e->flag, ENTRY_SPECIAL))
610 continue;
e3ef2b09 611 dirn = storeDirNumber(e->swap_file_number);
ea524965 612 assert(dirn < N);
e3ef2b09 613 if (fd[dirn] < 0)
614 continue;
9748816a 615 memset(&s, '\0', ss);
616 s.op = (char) SWAP_LOG_ADD;
617 s.swap_file_number = e->swap_file_number;
618 s.timestamp = e->timestamp;
619 s.lastref = e->lastref;
620 s.expires = e->expires;
621 s.lastmod = e->lastmod;
622 s.swap_file_sz = e->swap_file_sz;
623 s.refcount = e->refcount;
624 s.flags = e->flag;
625 xmemcpy(&s.key, e->key, MD5_DIGEST_CHARS);
626 xmemcpy(outbuf[dirn] + outbufoffset[dirn], &s, ss);
627 outbufoffset[dirn] += ss;
e3ef2b09 628 /* buffered write */
9748816a 629 if (outbufoffset[dirn] + ss > CLEAN_BUF_SZ) {
7be811df 630 if (write(fd[dirn], outbuf[dirn], outbufoffset[dirn]) < 0) {
25354045 631 debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
25535cbe 632 new[dirn], xstrerror());
e3ef2b09 633 debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n");
634 file_close(fd[dirn]);
635 fd[dirn] = -1;
25354045 636 unlink(new[dirn]);
e3ef2b09 637 continue;
638 }
7be811df 639 outbufoffset[dirn] = 0;
e3ef2b09 640 }
bcf3a738 641 if ((++n & 0xFFFF) == 0) {
e3ef2b09 642 getCurrentTime();
7be811df 643 debug(20, 1) (" %7d entries written so far.\n", n);
e3ef2b09 644 }
645 }
e3ef2b09 646 /* flush */
ea524965 647 for (dirn = 0; dirn < N; dirn++) {
7be811df 648 if (outbufoffset[dirn] == 0)
649 continue;
25354045 650 if (fd[dirn] < 0)
651 continue;
7be811df 652 if (write(fd[dirn], outbuf[dirn], outbufoffset[dirn]) < 0) {
25354045 653 debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
654 new[dirn], xstrerror());
7be811df 655 debug(20, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n");
656 file_close(fd[dirn]);
657 fd[dirn] = -1;
25354045 658 unlink(new[dirn]);
7be811df 659 continue;
e3ef2b09 660 }
7be811df 661 safe_free(outbuf[dirn]);
e3ef2b09 662 }
7be811df 663 safe_free(outbuf);
664 safe_free(outbufoffset);
25354045 665 /* rename */
ea524965 666 for (dirn = 0; dirn < N; dirn++) {
25354045 667 if (fd[dirn] < 0)
668 continue;
e3ef2b09 669 if (rename(new[dirn], cur[dirn]) < 0) {
670 debug(50, 0) ("storeDirWriteCleanLogs: rename failed: %s, %s -> %s\n",
671 xstrerror(), new[dirn], cur[dirn]);
672 }
673 }
674 storeDirCloseSwapLogs();
675 if (reopen)
676 storeDirOpenSwapLogs();
677 stop = squid_curtime;
678 r = stop - start;
7be811df 679 debug(20, 1) (" Finished. Wrote %d entries.\n", n);
5f6ac48b 680 debug(20, 1) (" Took %d seconds (%6.1f entries/sec).\n",
681 r > 0 ? (int) r : 0,
682 (double) n / (r > 0 ? r : 1));
e3ef2b09 683 /* touch a timestamp file if we're not still validating */
25354045 684 if (!store_rebuilding) {
ea524965 685 for (dirn = 0; dirn < N; dirn++) {
25354045 686 if (fd[dirn] < 0)
27a4d8b1 687 continue;
e3ef2b09 688 file_close(file_open(cln[dirn],
27a4d8b1 689 O_WRONLY | O_CREAT | O_TRUNC, NULL, NULL, NULL));
690 }
25354045 691 }
692 /* close */
ea524965 693 for (dirn = 0; dirn < N; dirn++) {
e3ef2b09 694 safe_free(cur[dirn]);
695 safe_free(new[dirn]);
696 safe_free(cln[dirn]);
25354045 697 if (fd[dirn] < 0)
698 continue;
699 file_close(fd[dirn]);
700 fd[dirn] = -1;
e3ef2b09 701 }
702 safe_free(cur);
703 safe_free(new);
704 safe_free(cln);
705 safe_free(fd);
706 return n;
707}
708#undef CLEAN_BUF_SZ