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