]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_dir.cc
MODIO_1 commit. This change (including documentation) implements a more
[thirdparty/squid.git] / src / store_dir.cc
CommitLineData
f1dc9b30 1
2/*
cd748f27 3 * $Id: store_dir.cc,v 1.107 2000/05/03 17:15:43 adrian 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
efd900cb 15 * the Regents of the University of California. Please see the
16 * COPYRIGHT file for full details. Squid incorporates software
17 * developed and/or copyrighted by other sources. Please see the
18 * 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
cd748f27 38static int storeDirValidSwapDirSize(int, size_t);
d141c677 39static void storeDirLRUWalkInitHead(SwapDir * sd);
40static void *storeDirLRUWalkNext(SwapDir * sd);
41
9838d6c8 42void
43storeDirInit(void)
596dddc1 44{
b2c141d4 45 int i;
46 SwapDir *sd;
47 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
48 sd = &Config.cacheSwap.swapDirs[i];
49 sd->init(sd);
50 }
85407535 51}
52
53void
54storeCreateSwapDirectories(void)
596dddc1 55{
b2c141d4 56 int i;
57 SwapDir *sd;
58 pid_t pid;
59 int status;
60 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
61 if (fork())
62 continue;
63 sd = &Config.cacheSwap.swapDirs[i];
64 sd->newfs(sd);
65 exit(0);
66 }
67 do {
68#ifdef _SQUID_NEXT_
69 pid = wait3(&status, WNOHANG, NULL);
70#else
71 pid = waitpid(-1, &status, 0);
72#endif
73 } while (pid > 0 || (pid < 0 && errno == EINTR));
596dddc1 74}
75
cd748f27 76/*
77 * Determine whether the given directory can handle this object
78 * size
79 *
80 * Note: if the object size is -1, then the only swapdirs that
81 * will return true here are ones that have max_obj_size = -1,
82 * ie any-sized-object swapdirs. This is a good thing.
83 */
84static int
85storeDirValidSwapDirSize(int swapdir, size_t objsize)
86{
87 /*
88 * If the swapdir's max_obj_size is -1, then it definitely can
89 */
90 if (Config.cacheSwap.swapDirs[swapdir].max_objsize == -1)
91 return 1;
92 /*
93 * Else, make sure that the max object size is larger than objsize
94 */
95 if (Config.cacheSwap.swapDirs[swapdir].max_objsize > objsize)
96 return 1;
97 else
98 return 0;
99}
100
101
102#if UNUSED /* Squid-2..4.DEVEL3 code */
d141c677 103/*
104 * This new selection scheme simply does round-robin on all SwapDirs.
105 * A SwapDir is skipped if it is over the max_size (100%) limit. If
106 * all SwapDir's are above the limit, then the first dirn that we
107 * checked is returned. Note that 'dirn' is guaranteed to advance even
108 * if all SwapDirs are full.
109 *
110 * XXX This function does NOT account for the read_only flag!
111 */
112static int
113storeDirSelectSwapDir(void)
114{
115 static int dirn = 0;
116 int i;
117 SwapDir *sd;
118 /*
119 * yes, the '<=' is intentional. If all dirs are full we want to
120 * make sure 'dirn' advances every time this gets called, otherwise
121 * we get stuck on one dir.
122 */
123 for (i = 0; i <= Config.cacheSwap.n_configured; i++) {
124 if (++dirn >= Config.cacheSwap.n_configured)
125 dirn = 0;
126 sd = &Config.cacheSwap.swapDirs[dirn];
127 if (sd->cur_size > sd->max_size)
128 continue;
129 return dirn;
130 }
131 return dirn;
132}
960a01e3 133
d141c677 134#if USE_DISKD && EXPERIMENTAL
135/*
136 * This fileno selection function returns a fileno on the least
137 * busy SwapDir. Ties are broken by selecting the SwapDir with
138 * the most free space.
139 */
5a5c22d3 140static int
141storeDirSelectSwapDir(void)
142{
143 SwapDir *SD;
144 int min_away = 10000;
d141c677 145 int min_size = 1 << 30;
5a5c22d3 146 int dirn = 0;
147 int i;
148 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
149 SD = &Config.cacheSwap.swapDirs[i];
150 if (SD->cur_size > SD->max_size)
151 continue;
152 if (SD->u.diskd.away > min_away)
153 continue;
154 if (SD->cur_size > min_size)
155 continue;
156 if (SD->flags.read_only)
157 continue;
158 min_away = SD->u.diskd.away;
159 min_size = SD->cur_size;
160 dirn = i;
161 }
162 return dirn;
163}
d141c677 164#endif
5a5c22d3 165
cd748f27 166#endif /* Squid-2.4.DEVEL3 code */
167
a2899918 168/*
cd748f27 169 * Spread load across all of the store directories
170 *
171 * Note: We should modify this later on to prefer sticking objects
172 * in the *tightest fit* swapdir to conserve space, along with the
173 * actual swapdir usage. But for now, this hack will do while
174 * testing, so you should order your swapdirs in the config file
175 * from smallest maxobjsize to unlimited (-1) maxobjsize.
176 *
177 * We also have to choose nleast == nconf since we need to consider
178 * ALL swapdirs, regardless of state. Again, this is a hack while
179 * we sort out the real usefulness of this algorithm.
a2899918 180 */
cd748f27 181int
182storeDirSelectSwapDir(const StoreEntry *e)
a2899918 183{
cd748f27 184 size_t objsize;
185 size_t least_size;
186 size_t least_objsize;
187 int least_load = 1000;
188 int load;
189 int dirn = -1;
190 int i;
a2899918 191 SwapDir *SD;
cd748f27 192
193 /* Calculate the object size */
194 objsize = objectLen(e);
195 if (objsize != -1)
196 objsize += e->mem_obj->swap_hdr_sz;
197 /* Initial defaults */
198 least_size = Config.cacheSwap.swapDirs[0].cur_size;
199 least_objsize = Config.cacheSwap.swapDirs[0].max_objsize;
200 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
201 SD = &Config.cacheSwap.swapDirs[i];
72615e4a 202 SD->flags.selected = 0;
cd748f27 203 if (SD->flags.read_only)
204 continue;
205 /* Valid for object size check */
206 if (!storeDirValidSwapDirSize(i, objsize))
207 continue;
208 load = SD->checkobj(SD, e);
209 if (load < 0)
72615e4a 210 continue;
cd748f27 211 if (SD->cur_size > SD->max_size)
212 continue;
213 if (load > least_load)
214 continue;
215 if ((least_objsize > 0) && (objsize > least_objsize))
216 continue;
217 /* Only use leastsize if the load is equal */
218 if ((load == least_load) && (SD->cur_size > least_size))
219 continue;
220 least_load = load;
221 least_size = SD->cur_size;
222 dirn = i;
a2899918 223 }
596dddc1 224
cd748f27 225 if (dirn >= 0)
226 Config.cacheSwap.swapDirs[dirn].flags.selected = 1;
0c04c389 227
cd748f27 228 return dirn;
596dddc1 229}
230
596dddc1 231
596dddc1 232
233char *
234storeSwapDir(int dirn)
235{
6d80d9a6 236 assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
f1dc9b30 237 return Config.cacheSwap.swapDirs[dirn].path;
596dddc1 238}
4683e377 239
b109de6b 240/*
241 * An entry written to the swap log MUST have the following
242 * properties.
243 * 1. It MUST be a public key. It does no good to log
244 * a public ADD, change the key, then log a private
245 * DEL. So we need to log a DEL before we change a
246 * key from public to private.
cd748f27 247 * 2. It MUST have a valid (> -1) swap_filen.
b109de6b 248 */
4683e377 249void
5830cdb3 250storeDirSwapLog(const StoreEntry * e, int op)
4683e377 251{
1ffc4484 252 SwapDir *sd;
d46a87a8 253 assert(!EBIT_TEST(e->flags, KEY_PRIVATE));
cd748f27 254 assert(e->swap_filen >= 0);
6c57e268 255 /*
256 * icons and such; don't write them to the swap log
257 */
d46a87a8 258 if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
6c57e268 259 return;
b109de6b 260 assert(op > SWAP_LOG_NOP && op < SWAP_LOG_MAX);
cd748f27 261 debug(20, 3) ("storeDirSwapLog: %s %s %d %08X\n",
b109de6b 262 swap_log_op_str[op],
07304bf9 263 storeKeyText(e->key),
cd748f27 264 e->swap_dirn,
265 e->swap_filen);
266 sd = &Config.cacheSwap.swapDirs[e->swap_dirn];
200ba06e 267 sd->log.write(sd, e, op);
5608850b 268}
76fefb77 269
270void
cd748f27 271storeDirUpdateSwapSize(SwapDir *SD, size_t size, int sign)
76fefb77 272{
c932b107 273 int k = ((size + 1023) >> 10) * sign;
cd748f27 274 SD->cur_size += k;
76fefb77 275 store_swap_size += k;
0faf70d0 276 if (sign > 0)
277 n_disk_objects++;
278 else if (sign < 0)
279 n_disk_objects--;
76fefb77 280}
c932b107 281
282void
3e347513 283storeDirStats(StoreEntry * sentry)
c932b107 284{
cd748f27 285 int i;
286 SwapDir *SD;
287
c932b107 288 storeAppendPrintf(sentry, "Store Directory Statistics:\n");
3f6c0fb2 289 storeAppendPrintf(sentry, "Store Entries : %d\n",
290 memInUse(MEM_STOREENTRY));
291 storeAppendPrintf(sentry, "Maximum Swap Size : %8d KB\n",
292 Config.Swap.maxSize);
293 storeAppendPrintf(sentry, "Current Store Swap Size: %8d KB\n",
294 store_swap_size);
dd8037ab 295 storeAppendPrintf(sentry, "Current Capacity : %d%% used, %d%% free\n",
296 percent((int) store_swap_size, (int) Config.Swap.maxSize),
38d04788 297 percent((int) (Config.Swap.maxSize - store_swap_size), (int) Config.Swap.maxSize));
e3ef2b09 298
cd748f27 299 /* Now go through each swapdir, calling its statfs routine */
300 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
301 storeAppendPrintf(sentry, "\n");
302 SD = &(Config.cacheSwap.swapDirs[i]);
303 storeAppendPrintf(sentry, "Store Directory #%d (%s): %s\n", i, SD->type,
304 storeSwapDir(i));
305 SD->statfs(SD, sentry);
306 }
5d406e78 307}
308
f4e3fa54 309void
310storeDirConfigure(void)
311{
312 SwapDir *SD;
f4e3fa54 313 int i;
f4e3fa54 314 Config.Swap.maxSize = 0;
315 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
5942e8d4 316 SD = &Config.cacheSwap.swapDirs[i];;
317 Config.Swap.maxSize += SD->max_size;
c6844e77 318 SD->low_size = (int) (((float) SD->max_size *
319 (float) Config.Swap.lowWaterMark) / 100.0);
f4e3fa54 320 }
321}
322
323void
cd748f27 324storeDirDiskFull(sdirno dirn)
f4e3fa54 325{
f4e3fa54 326 SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
327 assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
328 SD->max_size = SD->cur_size;
5942e8d4 329 debug(20, 1) ("WARNING: Shrinking cache_dir #%d to %d KB\n",
f4e3fa54 330 dirn, SD->cur_size);
331}
95dcd2b8 332
333void
334storeDirOpenSwapLogs(void)
335{
b2c141d4 336 int dirn;
337 SwapDir *sd;
338 for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
339 sd = &Config.cacheSwap.swapDirs[dirn];
340 sd->log.open(sd);
341 }
95dcd2b8 342}
343
344void
345storeDirCloseSwapLogs(void)
346{
b2c141d4 347 int dirn;
348 SwapDir *sd;
349 for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
350 sd = &Config.cacheSwap.swapDirs[dirn];
351 sd->log.close(sd);
352 }
95dcd2b8 353}
354
b2c141d4 355/*
356 * storeDirWriteCleanLogs
357 *
358 * Writes a "clean" swap log file from in-memory metadata.
cd748f27 359 * This is a rewrite of the original function to troll each
360 * StoreDir and write the logs, and flush at the end of
361 * the run. Thanks goes to Eric Stern, since this solution
362 * came out of his COSS code.
b2c141d4 363 */
364#define CLEAN_BUF_SZ 16384
365int
366storeDirWriteCleanLogs(int reopen)
95dcd2b8 367{
b2c141d4 368 StoreEntry *e = NULL;
369 int n = 0;
e812ecfc 370 struct timeval start;
371 double dt;
b2c141d4 372 SwapDir *sd;
373 int dirn;
2b906e48 374#if HEAP_REPLACEMENT
375 int node;
2b906e48 376#endif
b2c141d4 377 if (store_dirs_rebuilding) {
378 debug(20, 1) ("Not currently OK to rewrite swap log.\n");
379 debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.\n");
380 return 0;
381 }
382 debug(20, 1) ("storeDirWriteCleanLogs: Starting...\n");
e812ecfc 383 getCurrentTime();
384 start = current_time;
b2c141d4 385 for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
386 sd = &Config.cacheSwap.swapDirs[dirn];
387 if (sd->log.clean.open(sd) < 0) {
388 debug(20, 1) ("log.clean.open() failed for dir #%d\n", sd->index);
389 continue;
390 }
b2c141d4 391 if (NULL == sd->log.clean.write)
392 continue;
cd748f27 393#if HEAP_REPLACEMENT
394 if (NULL == sd->repl.heap.heap)
395 continue;
396#endif
397#if HEAP_REPLACEMENT
398 for (node = 0; node < heap_nodes(sd->repl.heap.heap); node++)
d141c677 399#else
cd748f27 400 storeDirLRUWalkInitHead(sd);
401 while ((e = storeDirLRUWalkNext(sd)) != NULL)
402#endif
403 {
404#if HEAP_REPLACEMENT
405 e = (StoreEntry *) heap_peep(sd->repl.heap.heap, node);
406#endif
407 if (e->swap_filen < 0)
d141c677 408 continue;
409 if (e->swap_status != SWAPOUT_DONE)
410 continue;
411 if (e->swap_file_sz <= 0)
412 continue;
413 if (EBIT_TEST(e->flags, RELEASE_REQUEST))
414 continue;
415 if (EBIT_TEST(e->flags, KEY_PRIVATE))
416 continue;
417 if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
418 continue;
419 sd->log.clean.write(e, sd);
420 if ((++n & 0xFFFF) == 0) {
421 getCurrentTime();
422 debug(20, 1) (" %7d entries written so far.\n", n);
423 }
424 }
cd748f27 425 /* Flush */
426 sd->log.clean.write(NULL, sd);
427 }
b2c141d4 428 if (reopen)
429 storeDirOpenSwapLogs();
e812ecfc 430 getCurrentTime();
431 dt = tvSubDsec(start, current_time);
b2c141d4 432 debug(20, 1) (" Finished. Wrote %d entries.\n", n);
e812ecfc 433 debug(20, 1) (" Took %3.1f seconds (%6.1f entries/sec).\n",
434 dt, (double) n / (dt > 0.0 ? dt : 1.0));
b2c141d4 435 return n;
95dcd2b8 436}
b2c141d4 437#undef CLEAN_BUF_SZ
d141c677 438
cd748f27 439/*
440 * sync all avaliable fs'es ..
441 */
442void
443storeDirSync(void)
444{
445 int i;
446 SwapDir *SD;
447
448 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
449 SD = &Config.cacheSwap.swapDirs[i];
450 if (SD->sync != NULL)
451 SD->sync(SD);
452 }
453}
454
455/*
456 * handle callbacks all avaliable fs'es ..
457 */
458void
459storeDirCallback(void)
460{
461 int i;
462 SwapDir *SD;
463
464 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
465 SD = &Config.cacheSwap.swapDirs[i];
466 if (SD->callback != NULL)
467 SD->callback(SD);
468 }
469}
470
471#if 0 /* from Squid-2.4.DEVEL3 */
d141c677 472void
473storeDirLRUDelete(StoreEntry * e)
474{
475 SwapDir *sd;
cd748f27 476 if (e->swap_filen < 0)
d141c677 477 return;
cd748f27 478 sd = &Config.cacheSwap.swapDirs[e->swap_dirn];
479 dlinkDelete(&e->lru, &sd->repl.lru.list);
d141c677 480}
481
482void
483storeDirLRUAdd(StoreEntry * e)
484{
485 SwapDir *sd;
486 if (e->swap_file_number < 0)
487 return;
cd748f27 488 sd = &Config.cacheSwap.swapDirs[e->swap_dirn];
489 dlinkAdd(e, &e->lru, &sd->repl.lru.list);
d141c677 490}
cd748f27 491#endif /* from Squid-2.4.DEVEL3 */
d141c677 492
493static void
494storeDirLRUWalkInitHead(SwapDir * sd)
495{
cd748f27 496 sd->repl.lru.walker = sd->repl.lru.list.head;
d141c677 497}
498
499static void *
500storeDirLRUWalkNext(SwapDir * sd)
501{
502 void *p;
cd748f27 503 if (NULL == sd->repl.lru.walker)
d141c677 504 return NULL;
cd748f27 505 p = sd->repl.lru.walker->data;
506 sd->repl.lru.walker = sd->repl.lru.walker->next;
d141c677 507 return p;
508}