]> git.ipfire.org Git - thirdparty/squid.git/blame - src/fs/coss/store_dir_coss.cc
MODIO_1 commit. This change (including documentation) implements a more
[thirdparty/squid.git] / src / fs / coss / store_dir_coss.cc
CommitLineData
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
42extern void storeCossFlushMemBufs(SwapDir *SD);
43
44int n_coss_dirs = 0;
45/* static int last_coss_pick_index = -1; */
46int coss_initialised = 0;
47MemPool * coss_membuf_pool = NULL;
48MemPool * coss_state_pool = NULL;
49
50typedef struct _RebuildState RebuildState;
51struct _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
73static char *storeCossDirSwapLogFile(SwapDir *, const char *);
74static EVH storeCossRebuildFromSwapLog;
75static 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);
85static void storeCossDirRebuild(SwapDir * sd);
86static void storeCossDirCloseTmpSwapLog(SwapDir * sd);
87static FILE *storeCossDirOpenTmpSwapLog(SwapDir *, int *, int *);
88static STLOGOPEN storeCossDirOpenSwapLog;
89static STINIT storeCossDirInit;
90static STLOGCLEANOPEN storeCossDirWriteCleanOpen;
91static void storeCossDirWriteCleanClose(SwapDir * sd);
92static STLOGCLEANWRITE storeCossDirWriteCleanEntry;
93static STLOGCLOSE storeCossDirCloseSwapLog;
94static STLOGWRITE storeCossDirSwapLog;
95static STNEWFS storeCossDirNewfs;
96static STCHECKOBJ storeCossDirCheckObj;
97static void storeCossDirShutdown(SwapDir * sd);
98static void storeCossDirParse(SwapDir *, int, char *);
99static void storeCossDirReconfigure(SwapDir *, int, char *);
100
101static char *
102storeCossDirSwapLogFile(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
130static void
131storeCossDirOpenSwapLog(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
146static void
147storeCossDirCloseSwapLog(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
158static void
159storeCossDirInit(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
168static void
169storeCossRebuildFromSwapLog(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. */
264static StoreEntry *
265storeCossAddDiskRestore(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
308static void
309storeCossDirRebuild(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
354static void
355storeCossDirCloseTmpSwapLog(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
382static FILE *
383storeCossDirOpenTmpSwapLog(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
431struct _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 */
446static int
447storeCossDirWriteCleanOpen(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 */
477static void
478storeCossDirWriteCleanEntry(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
517static void
518storeCossDirWriteCleanClose(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
568static void
569storeCossDirSwapLog(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
592static void
593storeCossDirNewfs(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
599static void
600storeCossDirShutdown(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 */
629int
630storeCossDirCheckObj(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
643void
644storeCossDirStats(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
668static void
669storeCossDirParse(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
743static void
744storeCossDirReconfigure(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
772void
773storeCossDirDump(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
783SwapDir *
784storeCossDirPick(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 */
826static void
827storeCossDirDone(void)
828{
829 memPoolDestroy(coss_membuf_pool);
830 memPoolDestroy(coss_state_pool);
831 coss_initialised = 0;
832}
833
834void
835storeFsSetup_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