]>
Commit | Line | Data |
---|---|---|
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 | 39 | static char *storeSwapSubDir(int dirn, int subdirn); |
40 | static int storeMostFreeSwapDir(void); | |
41 | static int storeVerifyDirectory(const char *path); | |
42 | static void storeCreateDirectory(const char *path, int lvl); | |
43 | static void storeCreateSwapSubDirs(int j); | |
44 | ||
596dddc1 | 45 | /* return full name to swapfile */ |
46 | char * | |
47 | storeSwapFullPath(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 | 65 | static char * |
66 | storeSwapSubDir(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 | 79 | char * |
80 | storeSwapSubSubDir(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 | */ |
107 | int | |
108 | storeFilenoBelongsHere(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 | 125 | static void |
85407535 | 126 | storeCreateDirectory(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 | 143 | static int |
85407535 | 144 | storeVerifyDirectory(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 | 163 | int |
85407535 | 164 | storeVerifyCacheDirs(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 | ||
182 | void | |
183 | storeCreateSwapDirectories(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 | 195 | static void |
596dddc1 | 196 | storeCreateSwapSubDirs(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 | 212 | static int |
596dddc1 | 213 | storeMostFreeSwapDir(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 | 233 | int |
234 | storeDirValidFileno(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 | 249 | int |
250 | storeDirMapBitTest(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 | 257 | void |
258 | storeDirMapBitSet(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 | ||
265 | void | |
266 | storeDirMapBitReset(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 | ||
273 | int | |
274 | storeDirMapAllocate(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 | ||
283 | char * | |
284 | storeSwapDir(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 | 290 | int |
291 | storeDirNumber(int swap_file_number) | |
292 | { | |
293 | return swap_file_number >> SWAP_DIR_SHIFT; | |
294 | } | |
295 | ||
c932b107 | 296 | int |
297 | storeDirProperFileno(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 | 311 | void |
5830cdb3 | 312 | storeDirSwapLog(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 | 350 | char * |
351 | storeDirSwapLogFile(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 | ||
369 | void | |
370 | storeDirOpenSwapLogs(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 | |
389 | void | |
390 | storeDirCloseSwapLogs(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 | ||
404 | FILE * | |
25535cbe | 405 | storeDirOpenTmpSwapLog(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 | ||
453 | void | |
454 | storeDirCloseTmpSwapLog(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 | |
476 | void | |
c932b107 | 477 | storeDirUpdateSwapSize(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 | |
485 | void | |
3e347513 | 486 | storeDirStats(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 | 516 | int |
517 | storeDirMapBitsInUse(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 | |
532 | int | |
533 | storeDirWriteCleanLogs(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 |