]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/store_dir.cc
3 * $Id: store_dir.cc,v 1.99 1999/12/01 04:28:08 wessels Exp $
5 * DEBUG: section 47 Store Directory Routines
6 * AUTHOR: Duane Wessels
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
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.
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.
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.
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.
38 const char *SwapDirType
[] =
49 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++) {
50 sd
= &Config
.cacheSwap
.swapDirs
[i
];
56 storeCreateSwapDirectories(void)
62 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++) {
65 sd
= &Config
.cacheSwap
.swapDirs
[i
];
71 pid
= wait3(&status
, WNOHANG
, NULL
);
73 pid
= waitpid(-1, &status
, 0);
75 } while (pid
> 0 || (pid
< 0 && errno
== EINTR
));
79 *Spread load across least 3/4 of the store directories
82 storeDirSelectSwapDir(void)
84 double least_used
= 1.0;
85 double high
= (double) Config
.Swap
.highWaterMark
/ 100.0;
90 static int nleast
= 0;
92 static int *dirq
= NULL
;
93 static double *diru
= NULL
;
95 * Handle simplest case of a single swap directory immediately
97 if (Config
.cacheSwap
.n_configured
== 1)
100 * Initialise dirq on the first call or on change of number of dirs
102 if (nconf
!= Config
.cacheSwap
.n_configured
) {
103 nconf
= Config
.cacheSwap
.n_configured
;
104 nleast
= (nconf
* 3) / 4;
106 dirq
= (int *) xmalloc(sizeof(int) * nleast
);
108 diru
= (double *) xmalloc(sizeof(double) * nconf
);
109 for (j
= 0; j
< nleast
; j
++)
113 * Scan for a non-negative dirn in the dirq array and return that one
116 for (j
= 0; j
< nleast
; j
++) {
124 * If we found a valid dirn return it
129 * Now for the real guts of the algorithm - building the dirq array
131 for (i
= 0; i
< nconf
; i
++) {
133 SD
= &Config
.cacheSwap
.swapDirs
[i
];
134 SD
->flags
.selected
= 0;
135 if (SD
->flags
.read_only
)
137 u
= (double) SD
->cur_size
/ SD
->max_size
;
142 for (j
= 0; j
< nleast
; j
++) {
146 for (i
= 0; i
< nconf
; i
++) {
147 if (diru
[i
] < least_used
) {
148 least_used
= diru
[i
];
156 /* set selected flag for debugging/cachemgr only */
157 Config
.cacheSwap
.swapDirs
[dirn
].flags
.selected
= 1;
160 * Setup default return of 0 if no least found
170 storeDirValidFileno(int fn
, int flag
)
172 int dirn
= fn
>> SWAP_DIR_SHIFT
;
173 int filn
= fn
& SWAP_FILE_MASK
;
174 if (dirn
> Config
.cacheSwap
.n_configured
)
181 * If flag is set it means out-of-range file number should
182 * be considered invalid.
185 if (filn
> Config
.cacheSwap
.swapDirs
[dirn
].map
->max_n_files
)
191 storeDirMapBitTest(int fn
)
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
);
199 storeDirMapBitSet(int fn
)
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
);
207 storeDirMapBitReset(int fn
)
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
);
215 storeDirMapAllocate(void)
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
);
225 storeSwapDir(int dirn
)
227 assert(0 <= dirn
&& dirn
< Config
.cacheSwap
.n_configured
);
228 return Config
.cacheSwap
.swapDirs
[dirn
].path
;
232 storeDirNumber(int swap_file_number
)
234 return swap_file_number
>> SWAP_DIR_SHIFT
;
238 storeDirProperFileno(int dirn
, int fn
)
240 return (dirn
<< SWAP_DIR_SHIFT
) | (fn
& SWAP_FILE_MASK
);
244 * An entry written to the swap log MUST have the following
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.
253 storeDirSwapLog(const StoreEntry
* e
, int op
)
255 int dirn
= e
->swap_file_number
>> SWAP_DIR_SHIFT
;
257 assert(dirn
< Config
.cacheSwap
.n_configured
);
258 assert(!EBIT_TEST(e
->flags
, KEY_PRIVATE
));
259 assert(e
->swap_file_number
>= 0);
261 * icons and such; don't write them to the swap log
263 if (EBIT_TEST(e
->flags
, ENTRY_SPECIAL
))
265 assert(op
> SWAP_LOG_NOP
&& op
< SWAP_LOG_MAX
);
266 debug(20, 3) ("storeDirSwapLog: %s %s %08X\n",
268 storeKeyText(e
->key
),
269 e
->swap_file_number
);
270 sd
= &Config
.cacheSwap
.swapDirs
[dirn
];
271 sd
->log
.write(sd
, e
, op
);
275 storeDirUpdateSwapSize(int fn
, size_t size
, int sign
)
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
;
288 storeDirStats(StoreEntry
* sentry
)
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",
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 */
304 storeDirMapBitsInUse(void)
308 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++)
309 n
+= Config
.cacheSwap
.swapDirs
[i
].map
->n_files_in_map
;
314 storeDirConfigure(void)
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
;
323 SD
->map
= file_map_create();
328 storeDirDiskFull(int fn
)
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",
339 storeDirOpenSwapLogs(void)
343 for (dirn
= 0; dirn
< Config
.cacheSwap
.n_configured
; dirn
++) {
344 sd
= &Config
.cacheSwap
.swapDirs
[dirn
];
350 storeDirCloseSwapLogs(void)
354 for (dirn
= 0; dirn
< Config
.cacheSwap
.n_configured
; dirn
++) {
355 sd
= &Config
.cacheSwap
.swapDirs
[dirn
];
361 * storeDirWriteCleanLogs
363 * Writes a "clean" swap log file from in-memory metadata.
365 #define CLEAN_BUF_SZ 16384
367 storeDirWriteCleanLogs(int reopen
)
369 StoreEntry
*e
= NULL
;
371 struct timeval start
;
375 int N
= Config
.cacheSwap
.n_configured
;
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");
386 debug(20, 1) ("storeDirWriteCleanLogs: Starting...\n");
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
);
397 for (node
= 0; node
< heap_nodes(store_heap
); node
++)
399 for (m
= store_list
.tail
; m
; m
= m
->prev
)
403 e
= (StoreEntry
*) heap_peep(store_heap
, node
);
407 if (e
->swap_file_number
< 0)
409 if (e
->swap_status
!= SWAPOUT_DONE
)
411 if (e
->swap_file_sz
<= 0)
413 if (EBIT_TEST(e
->flags
, RELEASE_REQUEST
))
415 if (EBIT_TEST(e
->flags
, KEY_PRIVATE
))
417 if (EBIT_TEST(e
->flags
, ENTRY_SPECIAL
))
419 dirn
= storeDirNumber(e
->swap_file_number
);
420 sd
= &Config
.cacheSwap
.swapDirs
[dirn
];
421 if (NULL
== sd
->log
.clean
.write
)
423 sd
->log
.clean
.write(e
, sd
);
424 if ((++n
& 0xFFFF) == 0) {
426 debug(20, 1) (" %7d entries written so far.\n", n
);
430 for (dirn
= 0; dirn
< N
; dirn
++) {
431 sd
= &Config
.cacheSwap
.swapDirs
[dirn
];
432 if (NULL
== sd
->log
.clean
.write
)
434 sd
->log
.clean
.write(NULL
, sd
);
437 storeDirOpenSwapLogs();
439 dt
= tvSubDsec(start
, current_time
);
440 debug(20, 1) (" Finished. Wrote %d entries.\n", n
);
441 debug(20, 1) (" Took %3.1f seconds (%6.1f entries/sec).\n",
442 dt
, (double) n
/ (dt
> 0.0 ? dt
: 1.0));