]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_dir.cc
This alternate storeDirSelectSwapDir() function is optimized for
[thirdparty/squid.git] / src / store_dir.cc
CommitLineData
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 38const char *SwapDirType[] =
39{
40 "ufs",
41 "!ERROR!"
42};
43
9838d6c8 44void
45storeDirInit(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
55void
56storeCreateSwapDirectories(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 78static int
79storeDirSelectSwapDir(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 */
107static int
108storeDirSelectSwapDir(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 196int
8b108705 197storeDirValidFileno(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 217int
218storeDirMapBitTest(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 225void
226storeDirMapBitSet(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
233void
234storeDirMapBitReset(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
241int
242storeDirMapAllocate(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
251char *
252storeSwapDir(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 258int
259storeDirNumber(int swap_file_number)
260{
261 return swap_file_number >> SWAP_DIR_SHIFT;
262}
263
c932b107 264int
265storeDirProperFileno(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 279void
5830cdb3 280storeDirSwapLog(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
301void
c932b107 302storeDirUpdateSwapSize(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
314void
3e347513 315storeDirStats(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 330int
331storeDirMapBitsInUse(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 340void
341storeDirConfigure(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
354void
355storeDirDiskFull(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
365void
366storeDirOpenSwapLogs(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
376void
377storeDirCloseSwapLogs(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
393int
394storeDirWriteCleanLogs(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