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