]>
Commit | Line | Data |
---|---|---|
f1dc9b30 | 1 | |
2 | /* | |
5a5c22d3 | 3 | * $Id: store_dir.cc,v 1.101 2000/01/05 06:25:42 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/ | |
e25c139f | 9 | * ---------------------------------------------------------- |
f1dc9b30 | 10 | * |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
e25c139f | 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. | |
f1dc9b30 | 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 | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
f1dc9b30 | 34 | */ |
35 | ||
596dddc1 | 36 | #include "squid.h" |
85407535 | 37 | |
0e4e0e7d | 38 | const char *SwapDirType[] = |
39 | { | |
40 | "ufs", | |
41 | "!ERROR!" | |
42 | }; | |
43 | ||
9838d6c8 | 44 | void |
45 | storeDirInit(void) | |
596dddc1 | 46 | { |
b2c141d4 | 47 | int i; |
48 | SwapDir *sd; | |
49 | for (i = 0; i < Config.cacheSwap.n_configured; i++) { | |
50 | sd = &Config.cacheSwap.swapDirs[i]; | |
51 | sd->init(sd); | |
52 | } | |
85407535 | 53 | } |
54 | ||
55 | void | |
56 | storeCreateSwapDirectories(void) | |
596dddc1 | 57 | { |
b2c141d4 | 58 | int i; |
59 | SwapDir *sd; | |
60 | pid_t pid; | |
61 | int status; | |
62 | for (i = 0; i < Config.cacheSwap.n_configured; i++) { | |
63 | if (fork()) | |
64 | continue; | |
65 | sd = &Config.cacheSwap.swapDirs[i]; | |
66 | sd->newfs(sd); | |
67 | exit(0); | |
68 | } | |
69 | do { | |
70 | #ifdef _SQUID_NEXT_ | |
71 | pid = wait3(&status, WNOHANG, NULL); | |
72 | #else | |
73 | pid = waitpid(-1, &status, 0); | |
74 | #endif | |
75 | } while (pid > 0 || (pid < 0 && errno == EINTR)); | |
596dddc1 | 76 | } |
77 | ||
5a5c22d3 | 78 | static int |
79 | storeDirSelectSwapDir(void) | |
80 | { | |
81 | SwapDir *SD; | |
82 | int min_away = 10000; | |
83 | int min_size = 1<<30; | |
84 | int dirn = 0; | |
85 | int i; | |
86 | for (i = 0; i < Config.cacheSwap.n_configured; i++) { | |
87 | SD = &Config.cacheSwap.swapDirs[i]; | |
88 | if (SD->cur_size > SD->max_size) | |
89 | continue; | |
90 | if (SD->u.diskd.away > min_away) | |
91 | continue; | |
92 | if (SD->cur_size > min_size) | |
93 | continue; | |
94 | if (SD->flags.read_only) | |
95 | continue; | |
96 | min_away = SD->u.diskd.away; | |
97 | min_size = SD->cur_size; | |
98 | dirn = i; | |
99 | } | |
100 | return dirn; | |
101 | } | |
102 | ||
103 | #if OLD | |
a2899918 | 104 | /* |
105 | *Spread load across least 3/4 of the store directories | |
106 | */ | |
107 | static int | |
108 | storeDirSelectSwapDir(void) | |
109 | { | |
110 | double least_used = 1.0; | |
72615e4a | 111 | double high = (double) Config.Swap.highWaterMark / 100.0; |
112 | double u; | |
a2899918 | 113 | int dirn; |
114 | int i, j; | |
115 | SwapDir *SD; | |
116 | static int nleast = 0; | |
117 | static int nconf = 0; | |
118 | static int *dirq = NULL; | |
119 | static double *diru = NULL; | |
120 | /* | |
121 | * Handle simplest case of a single swap directory immediately | |
122 | */ | |
123 | if (Config.cacheSwap.n_configured == 1) | |
124 | return 0; | |
125 | /* | |
126 | * Initialise dirq on the first call or on change of number of dirs | |
127 | */ | |
128 | if (nconf != Config.cacheSwap.n_configured) { | |
129 | nconf = Config.cacheSwap.n_configured; | |
130 | nleast = (nconf * 3) / 4; | |
60a05f69 | 131 | safe_free(dirq); |
a2899918 | 132 | dirq = (int *) xmalloc(sizeof(int) * nleast); |
60a05f69 | 133 | safe_free(diru); |
a2899918 | 134 | diru = (double *) xmalloc(sizeof(double) * nconf); |
135 | for (j = 0; j < nleast; j++) | |
136 | dirq[j] = -1; | |
137 | } | |
138 | /* | |
139 | * Scan for a non-negative dirn in the dirq array and return that one | |
140 | */ | |
141 | dirn = -1; | |
142 | for (j = 0; j < nleast; j++) { | |
143 | dirn = dirq[j]; | |
144 | if (dirn < 0) | |
145 | continue; | |
146 | dirq[j] = -1; | |
147 | break; | |
148 | } | |
149 | /* | |
150 | * If we found a valid dirn return it | |
151 | */ | |
152 | if (dirn >= 0) | |
153 | return dirn; | |
154 | /* | |
155 | * Now for the real guts of the algorithm - building the dirq array | |
156 | */ | |
157 | for (i = 0; i < nconf; i++) { | |
158 | diru[i] = 1.1; | |
159 | SD = &Config.cacheSwap.swapDirs[i]; | |
72615e4a | 160 | SD->flags.selected = 0; |
b6a2f15e | 161 | if (SD->flags.read_only) |
a2899918 | 162 | continue; |
72615e4a | 163 | u = (double) SD->cur_size / SD->max_size; |
164 | if (u > high) | |
165 | continue; | |
166 | diru[i] = u; | |
a2899918 | 167 | } |
168 | for (j = 0; j < nleast; j++) { | |
169 | dirq[j] = -1; | |
170 | least_used = 1.0; | |
171 | dirn = -1; | |
172 | for (i = 0; i < nconf; i++) { | |
173 | if (diru[i] < least_used) { | |
174 | least_used = diru[i]; | |
175 | dirn = i; | |
176 | } | |
177 | } | |
178 | if (dirn < 0) | |
179 | break; | |
180 | dirq[j] = dirn; | |
181 | diru[dirn] = 1.1; | |
72615e4a | 182 | /* set selected flag for debugging/cachemgr only */ |
183 | Config.cacheSwap.swapDirs[dirn].flags.selected = 1; | |
a2899918 | 184 | } |
185 | /* | |
186 | * Setup default return of 0 if no least found | |
187 | */ | |
188 | if (dirq[0] < 0) | |
189 | dirq[0] = 0; | |
190 | dirn = dirq[0]; | |
191 | dirq[0] = -1; | |
192 | return dirn; | |
193 | } | |
5a5c22d3 | 194 | #endif |
596dddc1 | 195 | |
e3ef2b09 | 196 | int |
8b108705 | 197 | storeDirValidFileno(int fn, int flag) |
e3ef2b09 | 198 | { |
199 | int dirn = fn >> SWAP_DIR_SHIFT; | |
200 | int filn = fn & SWAP_FILE_MASK; | |
e3ef2b09 | 201 | if (dirn > Config.cacheSwap.n_configured) |
202 | return 0; | |
8c128028 | 203 | if (dirn < 0) |
204 | return 0; | |
205 | if (filn < 0) | |
206 | return 0; | |
8b108705 | 207 | /* |
208 | * If flag is set it means out-of-range file number should | |
209 | * be considered invalid. | |
210 | */ | |
211 | if (flag) | |
212 | if (filn > Config.cacheSwap.swapDirs[dirn].map->max_n_files) | |
213 | return 0; | |
e3ef2b09 | 214 | return 1; |
215 | } | |
216 | ||
0c04c389 | 217 | int |
218 | storeDirMapBitTest(int fn) | |
219 | { | |
220 | int dirn = fn >> SWAP_DIR_SHIFT; | |
221 | int filn = fn & SWAP_FILE_MASK; | |
f1dc9b30 | 222 | return file_map_bit_test(Config.cacheSwap.swapDirs[dirn].map, filn); |
0c04c389 | 223 | } |
224 | ||
596dddc1 | 225 | void |
226 | storeDirMapBitSet(int fn) | |
227 | { | |
228 | int dirn = fn >> SWAP_DIR_SHIFT; | |
229 | int filn = fn & SWAP_FILE_MASK; | |
f1dc9b30 | 230 | file_map_bit_set(Config.cacheSwap.swapDirs[dirn].map, filn); |
596dddc1 | 231 | } |
232 | ||
233 | void | |
234 | storeDirMapBitReset(int fn) | |
235 | { | |
236 | int dirn = fn >> SWAP_DIR_SHIFT; | |
237 | int filn = fn & SWAP_FILE_MASK; | |
f1dc9b30 | 238 | file_map_bit_reset(Config.cacheSwap.swapDirs[dirn].map, filn); |
596dddc1 | 239 | } |
240 | ||
241 | int | |
242 | storeDirMapAllocate(void) | |
243 | { | |
a2899918 | 244 | int dirn = storeDirSelectSwapDir(); |
f1dc9b30 | 245 | SwapDir *SD = &Config.cacheSwap.swapDirs[dirn]; |
596dddc1 | 246 | int filn = file_map_allocate(SD->map, SD->suggest); |
6cf028ab | 247 | SD->suggest = filn + 1; |
a7e9d816 | 248 | return (dirn << SWAP_DIR_SHIFT) | (filn & SWAP_FILE_MASK); |
596dddc1 | 249 | } |
250 | ||
251 | char * | |
252 | storeSwapDir(int dirn) | |
253 | { | |
6d80d9a6 | 254 | assert(0 <= dirn && dirn < Config.cacheSwap.n_configured); |
f1dc9b30 | 255 | return Config.cacheSwap.swapDirs[dirn].path; |
596dddc1 | 256 | } |
4683e377 | 257 | |
5608850b | 258 | int |
259 | storeDirNumber(int swap_file_number) | |
260 | { | |
261 | return swap_file_number >> SWAP_DIR_SHIFT; | |
262 | } | |
263 | ||
c932b107 | 264 | int |
265 | storeDirProperFileno(int dirn, int fn) | |
266 | { | |
267 | return (dirn << SWAP_DIR_SHIFT) | (fn & SWAP_FILE_MASK); | |
268 | } | |
269 | ||
b109de6b | 270 | /* |
271 | * An entry written to the swap log MUST have the following | |
272 | * properties. | |
273 | * 1. It MUST be a public key. It does no good to log | |
274 | * a public ADD, change the key, then log a private | |
275 | * DEL. So we need to log a DEL before we change a | |
276 | * key from public to private. | |
277 | * 2. It MUST have a valid (> -1) swap_file_number. | |
278 | */ | |
4683e377 | 279 | void |
5830cdb3 | 280 | storeDirSwapLog(const StoreEntry * e, int op) |
4683e377 | 281 | { |
95dcd2b8 | 282 | int dirn = e->swap_file_number >> SWAP_DIR_SHIFT; |
1ffc4484 | 283 | SwapDir *sd; |
f1dc9b30 | 284 | assert(dirn < Config.cacheSwap.n_configured); |
d46a87a8 | 285 | assert(!EBIT_TEST(e->flags, KEY_PRIVATE)); |
b109de6b | 286 | assert(e->swap_file_number >= 0); |
6c57e268 | 287 | /* |
288 | * icons and such; don't write them to the swap log | |
289 | */ | |
d46a87a8 | 290 | if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) |
6c57e268 | 291 | return; |
b109de6b | 292 | assert(op > SWAP_LOG_NOP && op < SWAP_LOG_MAX); |
07304bf9 | 293 | debug(20, 3) ("storeDirSwapLog: %s %s %08X\n", |
b109de6b | 294 | swap_log_op_str[op], |
07304bf9 | 295 | storeKeyText(e->key), |
296 | e->swap_file_number); | |
1ffc4484 | 297 | sd = &Config.cacheSwap.swapDirs[dirn]; |
200ba06e | 298 | sd->log.write(sd, e, op); |
5608850b | 299 | } |
76fefb77 | 300 | |
301 | void | |
c932b107 | 302 | storeDirUpdateSwapSize(int fn, size_t size, int sign) |
76fefb77 | 303 | { |
f1dc9b30 | 304 | int dirn = (fn >> SWAP_DIR_SHIFT) % Config.cacheSwap.n_configured; |
c932b107 | 305 | int k = ((size + 1023) >> 10) * sign; |
f1dc9b30 | 306 | Config.cacheSwap.swapDirs[dirn].cur_size += k; |
76fefb77 | 307 | store_swap_size += k; |
0faf70d0 | 308 | if (sign > 0) |
309 | n_disk_objects++; | |
310 | else if (sign < 0) | |
311 | n_disk_objects--; | |
76fefb77 | 312 | } |
c932b107 | 313 | |
314 | void | |
3e347513 | 315 | storeDirStats(StoreEntry * sentry) |
c932b107 | 316 | { |
c932b107 | 317 | storeAppendPrintf(sentry, "Store Directory Statistics:\n"); |
3f6c0fb2 | 318 | storeAppendPrintf(sentry, "Store Entries : %d\n", |
319 | memInUse(MEM_STOREENTRY)); | |
320 | storeAppendPrintf(sentry, "Maximum Swap Size : %8d KB\n", | |
321 | Config.Swap.maxSize); | |
322 | storeAppendPrintf(sentry, "Current Store Swap Size: %8d KB\n", | |
323 | store_swap_size); | |
dd8037ab | 324 | storeAppendPrintf(sentry, "Current Capacity : %d%% used, %d%% free\n", |
325 | percent((int) store_swap_size, (int) Config.Swap.maxSize), | |
38d04788 | 326 | percent((int) (Config.Swap.maxSize - store_swap_size), (int) Config.Swap.maxSize)); |
b2c141d4 | 327 | storeUfsDirStats(sentry); /* XXX */ |
c932b107 | 328 | } |
e3ef2b09 | 329 | |
5d406e78 | 330 | int |
331 | storeDirMapBitsInUse(void) | |
332 | { | |
333 | int i; | |
334 | int n = 0; | |
335 | for (i = 0; i < Config.cacheSwap.n_configured; i++) | |
336 | n += Config.cacheSwap.swapDirs[i].map->n_files_in_map; | |
337 | return n; | |
338 | } | |
339 | ||
f4e3fa54 | 340 | void |
341 | storeDirConfigure(void) | |
342 | { | |
343 | SwapDir *SD; | |
f4e3fa54 | 344 | int i; |
f4e3fa54 | 345 | Config.Swap.maxSize = 0; |
346 | for (i = 0; i < Config.cacheSwap.n_configured; i++) { | |
5942e8d4 | 347 | SD = &Config.cacheSwap.swapDirs[i];; |
348 | Config.Swap.maxSize += SD->max_size; | |
8b108705 | 349 | if (NULL == SD->map) |
350 | SD->map = file_map_create(); | |
f4e3fa54 | 351 | } |
352 | } | |
353 | ||
354 | void | |
355 | storeDirDiskFull(int fn) | |
356 | { | |
357 | int dirn = fn >> SWAP_DIR_SHIFT; | |
358 | SwapDir *SD = &Config.cacheSwap.swapDirs[dirn]; | |
359 | assert(0 <= dirn && dirn < Config.cacheSwap.n_configured); | |
360 | SD->max_size = SD->cur_size; | |
5942e8d4 | 361 | debug(20, 1) ("WARNING: Shrinking cache_dir #%d to %d KB\n", |
f4e3fa54 | 362 | dirn, SD->cur_size); |
363 | } | |
95dcd2b8 | 364 | |
365 | void | |
366 | storeDirOpenSwapLogs(void) | |
367 | { | |
b2c141d4 | 368 | int dirn; |
369 | SwapDir *sd; | |
370 | for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { | |
371 | sd = &Config.cacheSwap.swapDirs[dirn]; | |
372 | sd->log.open(sd); | |
373 | } | |
95dcd2b8 | 374 | } |
375 | ||
376 | void | |
377 | storeDirCloseSwapLogs(void) | |
378 | { | |
b2c141d4 | 379 | int dirn; |
380 | SwapDir *sd; | |
381 | for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { | |
382 | sd = &Config.cacheSwap.swapDirs[dirn]; | |
383 | sd->log.close(sd); | |
384 | } | |
95dcd2b8 | 385 | } |
386 | ||
b2c141d4 | 387 | /* |
388 | * storeDirWriteCleanLogs | |
389 | * | |
390 | * Writes a "clean" swap log file from in-memory metadata. | |
391 | */ | |
392 | #define CLEAN_BUF_SZ 16384 | |
393 | int | |
394 | storeDirWriteCleanLogs(int reopen) | |
95dcd2b8 | 395 | { |
b2c141d4 | 396 | StoreEntry *e = NULL; |
397 | int n = 0; | |
e812ecfc | 398 | struct timeval start; |
399 | double dt; | |
b2c141d4 | 400 | SwapDir *sd; |
401 | int dirn; | |
402 | int N = Config.cacheSwap.n_configured; | |
2b906e48 | 403 | #if HEAP_REPLACEMENT |
404 | int node; | |
405 | #else | |
b2c141d4 | 406 | dlink_node *m; |
2b906e48 | 407 | #endif |
b2c141d4 | 408 | if (store_dirs_rebuilding) { |
409 | debug(20, 1) ("Not currently OK to rewrite swap log.\n"); | |
410 | debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.\n"); | |
411 | return 0; | |
412 | } | |
413 | debug(20, 1) ("storeDirWriteCleanLogs: Starting...\n"); | |
e812ecfc | 414 | getCurrentTime(); |
415 | start = current_time; | |
b2c141d4 | 416 | for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { |
417 | sd = &Config.cacheSwap.swapDirs[dirn]; | |
418 | if (sd->log.clean.open(sd) < 0) { | |
419 | debug(20, 1) ("log.clean.open() failed for dir #%d\n", sd->index); | |
420 | continue; | |
421 | } | |
422 | } | |
2b906e48 | 423 | #if HEAP_REPLACEMENT |
7e3ce7b9 | 424 | if (NULL == store_heap) |
425 | return 0; | |
2b906e48 | 426 | for (node = 0; node < heap_nodes(store_heap); node++) |
427 | #else | |
428 | for (m = store_list.tail; m; m = m->prev) | |
429 | #endif | |
430 | { | |
431 | #if HEAP_REPLACEMENT | |
432 | e = (StoreEntry *) heap_peep(store_heap, node); | |
433 | #else | |
b2c141d4 | 434 | e = m->data; |
2b906e48 | 435 | #endif |
b2c141d4 | 436 | if (e->swap_file_number < 0) |
437 | continue; | |
438 | if (e->swap_status != SWAPOUT_DONE) | |
439 | continue; | |
440 | if (e->swap_file_sz <= 0) | |
441 | continue; | |
442 | if (EBIT_TEST(e->flags, RELEASE_REQUEST)) | |
443 | continue; | |
444 | if (EBIT_TEST(e->flags, KEY_PRIVATE)) | |
445 | continue; | |
446 | if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) | |
447 | continue; | |
448 | dirn = storeDirNumber(e->swap_file_number); | |
449 | sd = &Config.cacheSwap.swapDirs[dirn]; | |
450 | if (NULL == sd->log.clean.write) | |
451 | continue; | |
1df87a8c | 452 | sd->log.clean.write(e, sd); |
b2c141d4 | 453 | if ((++n & 0xFFFF) == 0) { |
454 | getCurrentTime(); | |
455 | debug(20, 1) (" %7d entries written so far.\n", n); | |
456 | } | |
457 | } | |
458 | /* flush */ | |
459 | for (dirn = 0; dirn < N; dirn++) { | |
460 | sd = &Config.cacheSwap.swapDirs[dirn]; | |
461 | if (NULL == sd->log.clean.write) | |
462 | continue; | |
463 | sd->log.clean.write(NULL, sd); | |
464 | } | |
465 | if (reopen) | |
466 | storeDirOpenSwapLogs(); | |
e812ecfc | 467 | getCurrentTime(); |
468 | dt = tvSubDsec(start, current_time); | |
b2c141d4 | 469 | debug(20, 1) (" Finished. Wrote %d entries.\n", n); |
e812ecfc | 470 | debug(20, 1) (" Took %3.1f seconds (%6.1f entries/sec).\n", |
471 | dt, (double) n / (dt > 0.0 ? dt : 1.0)); | |
b2c141d4 | 472 | return n; |
95dcd2b8 | 473 | } |
b2c141d4 | 474 | #undef CLEAN_BUF_SZ |