]>
Commit | Line | Data |
---|---|---|
cd748f27 | 1 | |
2 | /* | |
3 | * $Id: store_dir_coss.cc,v 1.1 2000/05/03 17:15:47 adrian Exp $ | |
4 | * | |
5 | * DEBUG: section 81 Store COSS Directory Routines | |
6 | * AUTHOR: Eric Stern | |
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 | #include "store_coss.h" | |
39 | ||
40 | #define STORE_META_BUFSZ 4096 | |
41 | ||
42 | extern void storeCossFlushMemBufs(SwapDir *SD); | |
43 | ||
44 | int n_coss_dirs = 0; | |
45 | /* static int last_coss_pick_index = -1; */ | |
46 | int coss_initialised = 0; | |
47 | MemPool * coss_membuf_pool = NULL; | |
48 | MemPool * coss_state_pool = NULL; | |
49 | ||
50 | typedef struct _RebuildState RebuildState; | |
51 | struct _RebuildState { | |
52 | SwapDir *sd; | |
53 | int n_read; | |
54 | FILE *log; | |
55 | int speed; | |
56 | int curlvl1; | |
57 | int curlvl2; | |
58 | struct { | |
59 | unsigned int need_to_validate:1; | |
60 | unsigned int clean:1; | |
61 | unsigned int init:1; | |
62 | } flags; | |
63 | int done; | |
64 | int in_dir; | |
65 | int fn; | |
66 | struct dirent *entry; | |
67 | DIR *td; | |
68 | char fullpath[SQUID_MAXPATHLEN]; | |
69 | char fullfilename[SQUID_MAXPATHLEN]; | |
70 | struct _store_rebuild_data counts; | |
71 | }; | |
72 | ||
73 | static char *storeCossDirSwapLogFile(SwapDir *, const char *); | |
74 | static EVH storeCossRebuildFromSwapLog; | |
75 | static StoreEntry *storeCossAddDiskRestore(SwapDir *SD,const cache_key *key, | |
76 | int file_number, | |
77 | size_t swap_file_sz, | |
78 | time_t expires, | |
79 | time_t timestamp, | |
80 | time_t lastref, | |
81 | time_t lastmod, | |
82 | u_num32 refcount, | |
83 | u_short flags, | |
84 | int clean); | |
85 | static void storeCossDirRebuild(SwapDir * sd); | |
86 | static void storeCossDirCloseTmpSwapLog(SwapDir * sd); | |
87 | static FILE *storeCossDirOpenTmpSwapLog(SwapDir *, int *, int *); | |
88 | static STLOGOPEN storeCossDirOpenSwapLog; | |
89 | static STINIT storeCossDirInit; | |
90 | static STLOGCLEANOPEN storeCossDirWriteCleanOpen; | |
91 | static void storeCossDirWriteCleanClose(SwapDir * sd); | |
92 | static STLOGCLEANWRITE storeCossDirWriteCleanEntry; | |
93 | static STLOGCLOSE storeCossDirCloseSwapLog; | |
94 | static STLOGWRITE storeCossDirSwapLog; | |
95 | static STNEWFS storeCossDirNewfs; | |
96 | static STCHECKOBJ storeCossDirCheckObj; | |
97 | static void storeCossDirShutdown(SwapDir * sd); | |
98 | static void storeCossDirParse(SwapDir *, int, char *); | |
99 | static void storeCossDirReconfigure(SwapDir *, int, char *); | |
100 | ||
101 | static char * | |
102 | storeCossDirSwapLogFile(SwapDir * sd, const char *ext) | |
103 | { | |
104 | LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); | |
105 | LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN); | |
106 | LOCAL_ARRAY(char, digit, 32); | |
107 | char *pathtmp2; | |
108 | if (Config.Log.swap) { | |
109 | xstrncpy(pathtmp, sd->path, SQUID_MAXPATHLEN - 64); | |
110 | while (index(pathtmp,'/')) | |
111 | *index(pathtmp,'/')='.'; | |
112 | while (strlen(pathtmp) && pathtmp[strlen(pathtmp)-1]=='.') | |
113 | pathtmp[strlen(pathtmp)-1]= '\0'; | |
114 | for(pathtmp2 = pathtmp; *pathtmp2 == '.'; pathtmp2++); | |
115 | snprintf(path, SQUID_MAXPATHLEN-64, Config.Log.swap, pathtmp2); | |
116 | if (strncmp(path, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) { | |
117 | strcat(path, "."); | |
118 | snprintf(digit, 32, "%02d", sd->index); | |
119 | strncat(path, digit, 3); | |
120 | } | |
121 | } else { | |
122 | xstrncpy(path, sd->path, SQUID_MAXPATHLEN - 64); | |
123 | strcat(path, "/swap.state"); | |
124 | } | |
125 | if (ext) | |
126 | strncat(path, ext, 16); | |
127 | return path; | |
128 | } | |
129 | ||
130 | static void | |
131 | storeCossDirOpenSwapLog(SwapDir * sd) | |
132 | { | |
133 | CossInfo *cs = (CossInfo *)sd->fsdata; | |
134 | char *path; | |
135 | int fd; | |
136 | path = storeCossDirSwapLogFile(sd, NULL); | |
137 | fd = file_open(path, O_WRONLY | O_CREAT); | |
138 | if (fd < 0) { | |
139 | debug(81, 1) ("%s: %s\n", path, xstrerror()); | |
140 | fatal("storeCossDirOpenSwapLog: Failed to open swap log."); | |
141 | } | |
142 | debug(81, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, fd); | |
143 | cs->swaplog_fd = fd; | |
144 | } | |
145 | ||
146 | static void | |
147 | storeCossDirCloseSwapLog(SwapDir * sd) | |
148 | { | |
149 | CossInfo *cs = (CossInfo *)sd->fsdata; | |
150 | if (cs->swaplog_fd < 0) /* not open */ | |
151 | return; | |
152 | file_close(cs->swaplog_fd); | |
153 | debug(81, 3) ("Cache COSS Dir #%d log closed on FD %d\n", | |
154 | sd->index, cs->swaplog_fd); | |
155 | cs->swaplog_fd = -1; | |
156 | } | |
157 | ||
158 | static void | |
159 | storeCossDirInit(SwapDir * sd) | |
160 | { | |
161 | CossInfo *cs = (CossInfo *)sd->fsdata; | |
162 | storeCossDirOpenSwapLog(sd); | |
163 | storeCossDirRebuild(sd); | |
164 | cs->fd = file_open(sd->path, O_RDWR | O_CREAT); | |
165 | n_coss_dirs++; | |
166 | } | |
167 | ||
168 | static void | |
169 | storeCossRebuildFromSwapLog(void *data) | |
170 | { | |
171 | RebuildState *rb = data; | |
172 | StoreEntry *e = NULL; | |
173 | storeSwapLogData s; | |
174 | size_t ss = sizeof(storeSwapLogData); | |
175 | int count; | |
176 | double x; | |
177 | assert(rb != NULL); | |
178 | /* load a number of objects per invocation */ | |
179 | for (count = 0; count < rb->speed; count++) { | |
180 | if (fread(&s, ss, 1, rb->log) != 1) { | |
181 | debug(81, 1) ("Done reading %s swaplog (%d entries)\n", | |
182 | rb->sd->path, rb->n_read); | |
183 | fclose(rb->log); | |
184 | rb->log = NULL; | |
185 | store_dirs_rebuilding--; | |
186 | storeCossDirCloseTmpSwapLog(rb->sd); | |
187 | storeRebuildComplete(&rb->counts); | |
188 | cbdataFree(rb); | |
189 | return; | |
190 | } | |
191 | rb->n_read++; | |
192 | if (s.op <= SWAP_LOG_NOP) | |
193 | continue; | |
194 | if (s.op >= SWAP_LOG_MAX) | |
195 | continue; | |
196 | debug(20, 3) ("storeCossRebuildFromSwapLog: %s %s %08X\n", | |
197 | swap_log_op_str[(int) s.op], | |
198 | storeKeyText(s.key), | |
199 | s.swap_filen); | |
200 | if (s.op == SWAP_LOG_ADD) { | |
201 | (void) 0; | |
202 | } else if (s.op == SWAP_LOG_DEL) { | |
203 | if ((e = storeGet(s.key)) != NULL) { | |
204 | /* | |
205 | * Make sure we don't unlink the file, it might be | |
206 | * in use by a subsequent entry. Also note that | |
207 | * we don't have to subtract from store_swap_size | |
208 | * because adding to store_swap_size happens in | |
209 | * the cleanup procedure. | |
210 | */ | |
211 | storeExpireNow(e); | |
212 | storeReleaseRequest(e); | |
213 | if (e->swap_filen > -1) { | |
214 | e->swap_filen = -1; | |
215 | } | |
216 | storeRelease(e); | |
217 | /* Fake an unlink here, this is a bad hack :( */ | |
218 | dlinkDelete(&e->repl.lru, &rb->sd->repl.lru.list); | |
219 | rb->counts.objcount--; | |
220 | rb->counts.cancelcount++; | |
221 | } | |
222 | continue; | |
223 | } else { | |
224 | x = log(++rb->counts.bad_log_op) / log(10.0); | |
225 | if (0.0 == x - (double) (int) x) | |
226 | debug(20, 1) ("WARNING: %d invalid swap log entries found\n", | |
227 | rb->counts.bad_log_op); | |
228 | rb->counts.invalid++; | |
229 | continue; | |
230 | } | |
231 | if ((++rb->counts.scancount & 0xFFFF) == 0) | |
232 | debug(20, 3) (" %7d %s Entries read so far.\n", | |
233 | rb->counts.scancount, rb->sd->path); | |
234 | if (EBIT_TEST(s.flags, KEY_PRIVATE)) { | |
235 | rb->counts.badflags++; | |
236 | continue; | |
237 | } | |
238 | e = storeGet(s.key); | |
239 | if (e) { | |
240 | /* key already exists, current entry is newer */ | |
241 | /* keep old, ignore new */ | |
242 | rb->counts.dupcount++; | |
243 | continue; | |
244 | } | |
245 | /* update store_swap_size */ | |
246 | rb->counts.objcount++; | |
247 | e = storeCossAddDiskRestore(rb->sd,s.key, | |
248 | s.swap_filen, | |
249 | s.swap_file_sz, | |
250 | s.expires, | |
251 | s.timestamp, | |
252 | s.lastref, | |
253 | s.lastmod, | |
254 | s.refcount, | |
255 | s.flags, | |
256 | (int) rb->flags.clean); | |
257 | storeDirSwapLog(e, SWAP_LOG_ADD); | |
258 | } | |
259 | eventAdd("storeCossRebuild", storeCossRebuildFromSwapLog, rb, 0.0, 1); | |
260 | } | |
261 | ||
262 | /* Add a new object to the cache with empty memory copy and pointer to disk | |
263 | * use to rebuild store from disk. */ | |
264 | static StoreEntry * | |
265 | storeCossAddDiskRestore(SwapDir *SD, const cache_key * key, | |
266 | int file_number, | |
267 | size_t swap_file_sz, | |
268 | time_t expires, | |
269 | time_t timestamp, | |
270 | time_t lastref, | |
271 | time_t lastmod, | |
272 | u_num32 refcount, | |
273 | u_short flags, | |
274 | int clean) | |
275 | { | |
276 | StoreEntry *e = NULL; | |
277 | debug(20, 5) ("storeCossAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number); | |
278 | /* if you call this you'd better be sure file_number is not | |
279 | * already in use! */ | |
280 | e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL); | |
281 | e->store_status = STORE_OK; | |
282 | e->swap_dirn = SD->index; | |
283 | storeSetMemStatus(e, NOT_IN_MEMORY); | |
284 | e->swap_status = SWAPOUT_DONE; | |
285 | e->swap_filen = file_number; | |
286 | e->swap_file_sz = swap_file_sz; | |
287 | e->lock_count = 0; | |
288 | #if !HEAP_REPLACEMENT | |
289 | e->refcount = 0; | |
290 | #endif | |
291 | e->lastref = lastref; | |
292 | e->timestamp = timestamp; | |
293 | e->expires = expires; | |
294 | e->lastmod = lastmod; | |
295 | e->refcount = refcount; | |
296 | e->flags = flags; | |
297 | EBIT_SET(e->flags, ENTRY_CACHABLE); | |
298 | EBIT_CLR(e->flags, RELEASE_REQUEST); | |
299 | EBIT_CLR(e->flags, KEY_PRIVATE); | |
300 | e->ping_status = PING_NONE; | |
301 | EBIT_CLR(e->flags, ENTRY_VALIDATED); | |
302 | storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */ | |
303 | dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); | |
304 | e->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_NOTIFY); | |
305 | return e; | |
306 | } | |
307 | ||
308 | static void | |
309 | storeCossDirRebuild(SwapDir * sd) | |
310 | { | |
311 | RebuildState *rb = xcalloc(1, sizeof(*rb)); | |
312 | int clean = 0; | |
313 | int zero = 0; | |
314 | FILE *fp; | |
315 | EVH *func = NULL; | |
316 | rb->sd = sd; | |
317 | rb->speed = opt_foreground_rebuild ? 1 << 30 : 50; | |
318 | /* | |
319 | * If the swap.state file exists in the cache_dir, then | |
320 | * we'll use storeCossRebuildFromSwapLog(). | |
321 | */ | |
322 | fp = storeCossDirOpenTmpSwapLog(sd, &clean, &zero); | |
323 | debug(20, 1) ("Rebuilding COSS storage in %s (%s)\n", | |
324 | sd->path, clean ? "CLEAN" : "DIRTY"); | |
325 | if (!clean || fp == NULL) { | |
326 | /* COSS cannot yet rebuild from a dirty state. If the log | |
327 | * is dirty then the COSS contents is thrown away. | |
328 | * Why? I guess it is because some contents will be lost, | |
329 | * and COSS cannot verify this.. | |
330 | */ | |
331 | if (fp != NULL) | |
332 | fclose(fp); | |
333 | storeCossDirCloseTmpSwapLog(rb->sd); | |
334 | /* | |
335 | * XXX Make sure we don't trigger an assertion if this is the first | |
336 | * storedir, since if we are, this call will cause storeRebuildComplete | |
337 | * to prematurely complete the rebuild process, and then some other | |
338 | * storedir will try to rebuild and eventually die. | |
339 | */ | |
340 | store_dirs_rebuilding++; | |
341 | storeRebuildComplete(&rb->counts); | |
342 | store_dirs_rebuilding--; | |
343 | xfree(rb); | |
344 | return; | |
345 | } | |
346 | func = storeCossRebuildFromSwapLog; | |
347 | rb->log = fp; | |
348 | rb->flags.clean = (unsigned int) clean; | |
349 | store_dirs_rebuilding++; | |
350 | cbdataAdd(rb, cbdataXfree, 0); | |
351 | eventAdd("storeCossRebuild", func, rb, 0.0, 1); | |
352 | } | |
353 | ||
354 | static void | |
355 | storeCossDirCloseTmpSwapLog(SwapDir * sd) | |
356 | { | |
357 | CossInfo *cs = (CossInfo *)sd->fsdata; | |
358 | char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL)); | |
359 | char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new")); | |
360 | int fd; | |
361 | file_close(cs->swaplog_fd); | |
362 | #ifdef _SQUID_OS2_ | |
363 | if (unlink(swaplog_path) < 0) { | |
364 | debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); | |
365 | fatal("storeCossDirCloseTmpSwapLog: unlink failed"); | |
366 | } | |
367 | #endif | |
368 | if (xrename(new_path, swaplog_path) < 0) { | |
369 | fatal("storeCossDirCloseTmpSwapLog: rename failed"); | |
370 | } | |
371 | fd = file_open(swaplog_path, O_WRONLY | O_CREAT); | |
372 | if (fd < 0) { | |
373 | debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror()); | |
374 | fatal("storeCossDirCloseTmpSwapLog: Failed to open swap log."); | |
375 | } | |
376 | safe_free(swaplog_path); | |
377 | safe_free(new_path); | |
378 | cs->swaplog_fd = fd; | |
379 | debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, fd); | |
380 | } | |
381 | ||
382 | static FILE * | |
383 | storeCossDirOpenTmpSwapLog(SwapDir * sd, int *clean_flag, int *zero_flag) | |
384 | { | |
385 | CossInfo *cs = (CossInfo *)sd->fsdata; | |
386 | char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL)); | |
387 | char *clean_path = xstrdup(storeCossDirSwapLogFile(sd, ".last-clean")); | |
388 | char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new")); | |
389 | struct stat log_sb; | |
390 | struct stat clean_sb; | |
391 | FILE *fp; | |
392 | int fd; | |
393 | if (stat(swaplog_path, &log_sb) < 0) { | |
394 | debug(47, 1) ("Cache COSS Dir #%d: No log file\n", sd->index); | |
395 | safe_free(swaplog_path); | |
396 | safe_free(clean_path); | |
397 | safe_free(new_path); | |
398 | return NULL; | |
399 | } | |
400 | *zero_flag = log_sb.st_size == 0 ? 1 : 0; | |
401 | /* close the existing write-only FD */ | |
402 | if (cs->swaplog_fd >= 0) | |
403 | file_close(cs->swaplog_fd); | |
404 | /* open a write-only FD for the new log */ | |
405 | fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC); | |
406 | if (fd < 0) { | |
407 | debug(50, 1) ("%s: %s\n", new_path, xstrerror()); | |
408 | fatal("storeDirOpenTmpSwapLog: Failed to open swap log."); | |
409 | } | |
410 | cs->swaplog_fd = fd; | |
411 | /* open a read-only stream of the old log */ | |
412 | fp = fopen(swaplog_path, "r"); | |
413 | if (fp == NULL) { | |
414 | debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); | |
415 | fatal("Failed to open swap log for reading"); | |
416 | } | |
417 | memset(&clean_sb, '\0', sizeof(struct stat)); | |
418 | if (stat(clean_path, &clean_sb) < 0) | |
419 | *clean_flag = 0; | |
420 | else if (clean_sb.st_mtime < log_sb.st_mtime) | |
421 | *clean_flag = 0; | |
422 | else | |
423 | *clean_flag = 1; | |
424 | safeunlink(clean_path, 1); | |
425 | safe_free(swaplog_path); | |
426 | safe_free(clean_path); | |
427 | safe_free(new_path); | |
428 | return fp; | |
429 | } | |
430 | ||
431 | struct _clean_state { | |
432 | char *cur; | |
433 | char *new; | |
434 | char *cln; | |
435 | char *outbuf; | |
436 | off_t outbuf_offset; | |
437 | int fd; | |
438 | }; | |
439 | ||
440 | #define CLEAN_BUF_SZ 16384 | |
441 | /* | |
442 | * Begin the process to write clean cache state. For COSS this means | |
443 | * opening some log files and allocating write buffers. Return 0 if | |
444 | * we succeed, and assign the 'func' and 'data' return pointers. | |
445 | */ | |
446 | static int | |
447 | storeCossDirWriteCleanOpen(SwapDir * sd) | |
448 | { | |
449 | struct _clean_state *state = xcalloc(1, sizeof(*state)); | |
450 | struct stat sb; | |
451 | sd->log.clean.write = NULL; | |
452 | sd->log.clean.state = NULL; | |
453 | state->cur = xstrdup(storeCossDirSwapLogFile(sd, NULL)); | |
454 | state->new = xstrdup(storeCossDirSwapLogFile(sd, ".clean")); | |
455 | state->cln = xstrdup(storeCossDirSwapLogFile(sd, ".last-clean")); | |
456 | state->outbuf = xcalloc(CLEAN_BUF_SZ, 1); | |
457 | state->outbuf_offset = 0; | |
458 | unlink(state->new); | |
459 | unlink(state->cln); | |
460 | state->fd = file_open(state->new, O_WRONLY | O_CREAT | O_TRUNC); | |
461 | if (state->fd < 0) | |
462 | return -1; | |
463 | debug(20, 3) ("storeCOssDirWriteCleanLogs: opened %s, FD %d\n", | |
464 | state->new, state->fd); | |
465 | #if HAVE_FCHMOD | |
466 | if (stat(state->cur, &sb) == 0) | |
467 | fchmod(state->fd, sb.st_mode); | |
468 | #endif | |
469 | sd->log.clean.write = storeCossDirWriteCleanEntry; | |
470 | sd->log.clean.state = state; | |
471 | return 0; | |
472 | } | |
473 | ||
474 | /* | |
475 | * "write" an entry to the clean log file. | |
476 | */ | |
477 | static void | |
478 | storeCossDirWriteCleanEntry(const StoreEntry * e, SwapDir * sd) | |
479 | { | |
480 | storeSwapLogData s; | |
481 | static size_t ss = sizeof(storeSwapLogData); | |
482 | struct _clean_state *state = sd->log.clean.state; | |
483 | if (NULL == e) { | |
484 | storeCossDirWriteCleanClose(sd); | |
485 | return; | |
486 | } | |
487 | memset(&s, '\0', ss); | |
488 | s.op = (char) SWAP_LOG_ADD; | |
489 | s.swap_filen = e->swap_filen; | |
490 | s.timestamp = e->timestamp; | |
491 | s.lastref = e->lastref; | |
492 | s.expires = e->expires; | |
493 | s.lastmod = e->lastmod; | |
494 | s.swap_file_sz = e->swap_file_sz; | |
495 | s.refcount = e->refcount; | |
496 | s.flags = e->flags; | |
497 | xmemcpy(&s.key, e->key, MD5_DIGEST_CHARS); | |
498 | xmemcpy(state->outbuf + state->outbuf_offset, &s, ss); | |
499 | state->outbuf_offset += ss; | |
500 | /* buffered write */ | |
501 | if (state->outbuf_offset + ss > CLEAN_BUF_SZ) { | |
502 | if (write(state->fd, state->outbuf, state->outbuf_offset) < 0) { | |
503 | debug(50, 0) ("storeCossDirWriteCleanLogs: %s: write: %s\n", | |
504 | state->new, xstrerror()); | |
505 | debug(20, 0) ("storeCossDirWriteCleanLogs: Current swap logfile not replaced.\n"); | |
506 | file_close(state->fd); | |
507 | state->fd = -1; | |
508 | unlink(state->new); | |
509 | safe_free(state); | |
510 | sd->log.clean.state = NULL; | |
511 | sd->log.clean.write = NULL; | |
512 | } | |
513 | state->outbuf_offset = 0; | |
514 | } | |
515 | } | |
516 | ||
517 | static void | |
518 | storeCossDirWriteCleanClose(SwapDir * sd) | |
519 | { | |
520 | struct _clean_state *state = sd->log.clean.state; | |
521 | if (state->fd < 0) | |
522 | return; | |
523 | if (write(state->fd, state->outbuf, state->outbuf_offset) < 0) { | |
524 | debug(50, 0) ("storeCossDirWriteCleanLogs: %s: write: %s\n", | |
525 | state->new, xstrerror()); | |
526 | debug(20, 0) ("storeCossDirWriteCleanLogs: Current swap logfile " | |
527 | "not replaced.\n"); | |
528 | file_close(state->fd); | |
529 | state->fd = -1; | |
530 | unlink(state->new); | |
531 | } | |
532 | safe_free(state->outbuf); | |
533 | /* | |
534 | * You can't rename open files on Microsoft "operating systems" | |
535 | * so we have to close before renaming. | |
536 | */ | |
537 | storeCossDirCloseSwapLog(sd); | |
538 | /* rename */ | |
539 | if (state->fd >= 0) { | |
540 | #ifdef _SQUID_OS2_ | |
541 | file_close(state->fd); | |
542 | state->fd = -1; | |
543 | if (unlink(cur) < 0) | |
544 | debug(50, 0) ("storeCossDirWriteCleanLogs: unlinkd failed: %s, %s\n", | |
545 | xstrerror(), cur); | |
546 | #endif | |
547 | xrename(state->new, state->cur); | |
548 | } | |
549 | /* touch a timestamp file if we're not still validating */ | |
550 | if (store_dirs_rebuilding) | |
551 | (void) 0; | |
552 | else if (state->fd < 0) | |
553 | (void) 0; | |
554 | else | |
555 | file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC)); | |
556 | /* close */ | |
557 | safe_free(state->cur); | |
558 | safe_free(state->new); | |
559 | safe_free(state->cln); | |
560 | if (state->fd >= 0) | |
561 | file_close(state->fd); | |
562 | state->fd = -1; | |
563 | safe_free(state); | |
564 | sd->log.clean.state = NULL; | |
565 | sd->log.clean.write = NULL; | |
566 | } | |
567 | ||
568 | static void | |
569 | storeCossDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op) | |
570 | { | |
571 | CossInfo *cs = (CossInfo *)sd->fsdata; | |
572 | storeSwapLogData *s = xcalloc(1, sizeof(storeSwapLogData)); | |
573 | s->op = (char) op; | |
574 | s->swap_filen = e->swap_filen; | |
575 | s->timestamp = e->timestamp; | |
576 | s->lastref = e->lastref; | |
577 | s->expires = e->expires; | |
578 | s->lastmod = e->lastmod; | |
579 | s->swap_file_sz = e->swap_file_sz; | |
580 | s->refcount = e->refcount; | |
581 | s->flags = e->flags; | |
582 | xmemcpy(s->key, e->key, MD5_DIGEST_CHARS); | |
583 | file_write(cs->swaplog_fd, | |
584 | -1, | |
585 | s, | |
586 | sizeof(storeSwapLogData), | |
587 | NULL, | |
588 | NULL, | |
589 | xfree); | |
590 | } | |
591 | ||
592 | static void | |
593 | storeCossDirNewfs(SwapDir * sd) | |
594 | { | |
595 | debug(47, 3) ("Creating swap space in %s\n", sd->path); | |
596 | } | |
597 | ||
598 | // we are shutting down, flush all membufs to disk | |
599 | static void | |
600 | storeCossDirShutdown(SwapDir *SD) | |
601 | { | |
602 | CossInfo *cs = (CossInfo *)SD->fsdata; | |
603 | CossMemBuf *t; | |
604 | ||
605 | // we need to do this synchronously! | |
606 | for (t = cs->membufs; t; t = t->next) { | |
607 | lseek(cs->fd, t->diskstart, SEEK_SET); | |
608 | write(cs->fd, t->buffer, COSS_MEMBUF_SZ); | |
609 | } | |
610 | file_close(cs->fd); | |
611 | cs->fd = -1; | |
612 | ||
613 | if (cs->swaplog_fd > -1) { | |
614 | file_close(cs->swaplog_fd); | |
615 | cs->swaplog_fd = -1; | |
616 | } | |
617 | ||
618 | n_coss_dirs--; | |
619 | } | |
620 | ||
621 | /* | |
622 | * storeCossDirCheckObj | |
623 | * | |
624 | * This routine is called by storeDirSelectSwapDir to see if the given | |
625 | * object is able to be stored on this filesystem. COSS filesystems will | |
626 | * not store everything. We don't check for maxobjsize here since its | |
627 | * done by the upper layers. | |
628 | */ | |
629 | int | |
630 | storeCossDirCheckObj(SwapDir *SD, const StoreEntry *e) | |
631 | { | |
632 | /* Check if the object is a special object, we can't cache these */ | |
633 | if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) | |
634 | return -1; | |
635 | ||
636 | /* Otherwise, we're ok */ | |
637 | /* Return 900 (90%) load */ | |
638 | return 900; | |
639 | } | |
640 | ||
641 | /* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */ | |
642 | ||
643 | void | |
644 | storeCossDirStats(SwapDir *SD, StoreEntry * sentry) | |
645 | { | |
646 | CossInfo *cs = (CossInfo *)SD->fsdata; | |
647 | ||
648 | storeAppendPrintf(sentry, "\n"); | |
649 | storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size); | |
650 | storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size); | |
651 | storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n", | |
652 | 100.0 * SD->cur_size / SD->max_size); | |
653 | storeAppendPrintf(sentry, "Number of object collisions: %d\n", (int)cs->numcollisions); | |
654 | #if 0 | |
655 | /* is this applicable? I Hope not .. */ | |
656 | storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n", | |
657 | SD->map->n_files_in_map, SD->map->max_n_files, | |
658 | percent(SD->map->n_files_in_map, SD->map->max_n_files)); | |
659 | #endif | |
660 | storeAppendPrintf(sentry, "Flags:"); | |
661 | if (SD->flags.selected) | |
662 | storeAppendPrintf(sentry, " SELECTED"); | |
663 | if (SD->flags.read_only) | |
664 | storeAppendPrintf(sentry, " READ-ONLY"); | |
665 | storeAppendPrintf(sentry, "\n"); | |
666 | } | |
667 | ||
668 | static void | |
669 | storeCossDirParse(SwapDir *sd, int index, char *path) | |
670 | { | |
671 | char *token; | |
672 | unsigned int i; | |
673 | unsigned int size; | |
674 | unsigned int read_only = 0; | |
675 | CossInfo *cs; | |
676 | ||
677 | i = GetInteger(); | |
678 | size = i << 10; /* Mbytes to Kbytes */ | |
679 | if (size <= 0) | |
680 | fatal("storeCossDirParse: invalid size value"); | |
681 | if ((token = strtok(NULL, w_space))) | |
682 | if (!strcasecmp(token, "read-only")) | |
683 | read_only = 1; | |
684 | ||
685 | cs = xmalloc(sizeof(CossInfo)); | |
686 | if (cs == NULL) | |
687 | fatal("storeCossDirParse: couldn't xmalloc() CossInfo!\n"); | |
688 | ||
689 | sd->index = index; | |
690 | sd->path = xstrdup(path); | |
691 | sd->max_size = size; | |
692 | sd->fsdata = cs; | |
693 | ||
694 | cs->fd = -1; | |
695 | cs->swaplog_fd = -1; | |
696 | sd->flags.read_only = read_only; | |
697 | ||
698 | sd->init = storeCossDirInit; | |
699 | sd->newfs = storeCossDirNewfs; | |
700 | sd->dump = storeCossDirDump; | |
701 | sd->freefs = storeCossDirShutdown; | |
702 | sd->dblcheck = NULL; | |
703 | sd->statfs = storeCossDirStats; | |
704 | sd->maintainfs = NULL; | |
705 | sd->checkobj = storeCossDirCheckObj; | |
706 | sd->refobj = NULL; /* LRU is done in storeCossRead */ | |
707 | sd->unrefobj = NULL; | |
708 | sd->callback = NULL; | |
709 | sd->sync = NULL; /* should we make it call the coss sync? */ | |
710 | ||
711 | sd->obj.create = storeCossCreate; | |
712 | sd->obj.open = storeCossOpen; | |
713 | sd->obj.close = storeCossClose; | |
714 | sd->obj.read = storeCossRead; | |
715 | sd->obj.write = storeCossWrite; | |
716 | sd->obj.unlink = storeCossUnlink; | |
717 | ||
718 | sd->log.open = storeCossDirOpenSwapLog; | |
719 | sd->log.close = storeCossDirCloseSwapLog; | |
720 | sd->log.write = storeCossDirSwapLog; | |
721 | sd->log.clean.open = storeCossDirWriteCleanOpen; | |
722 | sd->log.clean.write = storeCossDirWriteCleanEntry; | |
723 | ||
724 | cs->current_offset = 0; | |
725 | cs->fd = -1; | |
726 | cs->swaplog_fd = -1; | |
727 | cs->numcollisions = 0; | |
728 | cs->membufs = memPoolAlloc(coss_membuf_pool); | |
729 | cs->membufs->diskstart = 0; | |
730 | cs->membufs->diskend = COSS_MEMBUF_SZ; | |
731 | cs->membufs->lockcount = 0; | |
732 | cs->membufs->flags.full = 0; | |
733 | cs->membufs->flags.writing = 0; | |
734 | cs->membufs->next = NULL; | |
735 | cs->membufs->SD = sd; | |
736 | cs->current_membuf = cs->membufs; | |
737 | ||
738 | sd->repl.lru.list.head = NULL; | |
739 | sd->repl.lru.list.tail = NULL; | |
740 | } | |
741 | ||
742 | ||
743 | static void | |
744 | storeCossDirReconfigure(SwapDir *sd, int index, char *path) | |
745 | { | |
746 | char *token; | |
747 | unsigned int i; | |
748 | unsigned int size; | |
749 | unsigned int read_only = 0; | |
750 | ||
751 | i = GetInteger(); | |
752 | size = i << 10; /* Mbytes to Kbytes */ | |
753 | if (size <= 0) | |
754 | fatal("storeCossDirParse: invalid size value"); | |
755 | if ((token = strtok(NULL, w_space))) | |
756 | if (!strcasecmp(token, "read-only")) | |
757 | read_only = 1; | |
758 | ||
759 | if (size == sd->max_size) | |
760 | debug (3, 1) ("Cache COSS dir '%s' size remains unchanged at %d KB\n", path, size); | |
761 | else { | |
762 | debug (3, 1) ("Cache COSS dir '%s' size changed to %d KB\n", path, size); | |
763 | sd->max_size = size; | |
764 | } | |
765 | ||
766 | if (read_only != sd->flags.read_only) { | |
767 | debug (3, 1) ("Cache COSS dir '%s' now %s\n", path, read_only ? "Read-Only" : "Read-Write"); | |
768 | sd->flags.read_only = read_only; | |
769 | } | |
770 | } | |
771 | ||
772 | void | |
773 | storeCossDirDump(StoreEntry * entry, const char *name, SwapDir * s) | |
774 | { | |
775 | storeAppendPrintf(entry, "%s %s %s %d\n", | |
776 | name, | |
777 | s->type, | |
778 | s->path, | |
779 | s->max_size >> 20); | |
780 | } | |
781 | ||
782 | #if 0 | |
783 | SwapDir * | |
784 | storeCossDirPick(void) | |
785 | { | |
786 | int i,choosenext = 0; | |
787 | SwapDir *SD; | |
788 | ||
789 | if (n_coss_dirs == 0) | |
790 | return NULL; | |
791 | for (i = 0; i < Config.cacheSwap.n_configured; i++) { | |
792 | SD = &Config.cacheSwap.swapDirs[i]; | |
793 | if (SD->type == SWAPDIR_COSS) { | |
794 | if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) { | |
795 | last_coss_pick_index = i; | |
796 | return SD; | |
797 | } else if (choosenext) { | |
798 | last_coss_pick_index = i; | |
799 | return SD; | |
800 | } else if (last_coss_pick_index == i) { | |
801 | choosenext = 1; | |
802 | } | |
803 | } | |
804 | } | |
805 | for (i = 0; i < Config.cacheSwap.n_configured; i++) { | |
806 | SD = &Config.cacheSwap.swapDirs[i]; | |
807 | if (SD->type == SWAPDIR_COSS) { | |
808 | if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) { | |
809 | last_coss_pick_index = i; | |
810 | return SD; | |
811 | } else if (choosenext) { | |
812 | last_coss_pick_index = i; | |
813 | return SD; | |
814 | } else if (last_coss_pick_index == i) { | |
815 | choosenext = 1; | |
816 | } | |
817 | } | |
818 | } | |
819 | return NULL; | |
820 | } | |
821 | #endif | |
822 | ||
823 | /* | |
824 | * initial setup/done code | |
825 | */ | |
826 | static void | |
827 | storeCossDirDone(void) | |
828 | { | |
829 | memPoolDestroy(coss_membuf_pool); | |
830 | memPoolDestroy(coss_state_pool); | |
831 | coss_initialised = 0; | |
832 | } | |
833 | ||
834 | void | |
835 | storeFsSetup_coss(storefs_entry_t *storefs) | |
836 | { | |
837 | assert(!coss_initialised); | |
838 | ||
839 | storefs->parsefunc = storeCossDirParse; | |
840 | storefs->reconfigurefunc = storeCossDirReconfigure; | |
841 | storefs->donefunc = storeCossDirDone; | |
842 | coss_membuf_pool = memPoolCreate("COSS Membuf data", sizeof(CossMemBuf)); | |
843 | coss_state_pool = memPoolCreate("COSS IO State data", sizeof(CossState)); | |
844 | coss_initialised = 1; | |
845 | } | |
846 |