]> git.ipfire.org Git - thirdparty/squid.git/blame - src/fs/coss/store_dir_coss.cc
DW:
[thirdparty/squid.git] / src / fs / coss / store_dir_coss.cc
CommitLineData
a4b8110e 1
cd748f27 2/*
a4b8110e 3 * $Id: store_dir_coss.cc,v 1.2 2000/05/12 00:29:19 wessels Exp $
cd748f27 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
a4b8110e 42extern void storeCossFlushMemBufs(SwapDir * SD);
cd748f27 43
44int n_coss_dirs = 0;
45/* static int last_coss_pick_index = -1; */
46int coss_initialised = 0;
a4b8110e 47MemPool *coss_membuf_pool = NULL;
48MemPool *coss_state_pool = NULL;
cd748f27 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;
a4b8110e 75static StoreEntry *storeCossAddDiskRestore(SwapDir * SD, const cache_key * key,
cd748f27 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) {
a4b8110e 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 }
cd748f27 121 } else {
a4b8110e 122 xstrncpy(path, sd->path, SQUID_MAXPATHLEN - 64);
123 strcat(path, "/swap.state");
cd748f27 124 }
125 if (ext)
a4b8110e 126 strncat(path, ext, 16);
cd748f27 127 return path;
128}
129
130static void
131storeCossDirOpenSwapLog(SwapDir * sd)
132{
a4b8110e 133 CossInfo *cs = (CossInfo *) sd->fsdata;
cd748f27 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{
a4b8110e 149 CossInfo *cs = (CossInfo *) sd->fsdata;
cd748f27 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{
a4b8110e 161 CossInfo *cs = (CossInfo *) sd->fsdata;
cd748f27 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 }
a4b8110e 216 storeRelease(e);
217 /* Fake an unlink here, this is a bad hack :( */
cd748f27 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++;
a4b8110e 247 e = storeCossAddDiskRestore(rb->sd, s.key,
cd748f27 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 *
a4b8110e 265storeCossAddDiskRestore(SwapDir * SD, const cache_key * key,
cd748f27 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) {
a4b8110e 326 /* COSS cannot yet rebuild from a dirty state. If the log
cd748f27 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);
a4b8110e 334 /*
cd748f27 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 */
a4b8110e 340 store_dirs_rebuilding++;
341 storeRebuildComplete(&rb->counts);
342 store_dirs_rebuilding--;
cd748f27 343 xfree(rb);
a4b8110e 344 return;
cd748f27 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{
a4b8110e 357 CossInfo *cs = (CossInfo *) sd->fsdata;
cd748f27 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{
a4b8110e 385 CossInfo *cs = (CossInfo *) sd->fsdata;
cd748f27 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{
a4b8110e 571 CossInfo *cs = (CossInfo *) sd->fsdata;
cd748f27 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
a4b8110e 598/* we are shutting down, flush all membufs to disk */
cd748f27 599static void
a4b8110e 600storeCossDirShutdown(SwapDir * SD)
cd748f27 601{
a4b8110e 602 CossInfo *cs = (CossInfo *) SD->fsdata;
cd748f27 603 CossMemBuf *t;
604
a4b8110e 605 /* we need to do this synchronously! */
cd748f27 606 for (t = cs->membufs; t; t = t->next) {
a4b8110e 607 lseek(cs->fd, t->diskstart, SEEK_SET);
608 write(cs->fd, t->buffer, COSS_MEMBUF_SZ);
cd748f27 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 }
cd748f27 617 n_coss_dirs--;
618}
619
620/*
621 * storeCossDirCheckObj
622 *
623 * This routine is called by storeDirSelectSwapDir to see if the given
624 * object is able to be stored on this filesystem. COSS filesystems will
625 * not store everything. We don't check for maxobjsize here since its
626 * done by the upper layers.
627 */
628int
a4b8110e 629storeCossDirCheckObj(SwapDir * SD, const StoreEntry * e)
cd748f27 630{
a4b8110e 631 /* Check if the object is a special object, we can't cache these */
632 if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
633 return -1;
cd748f27 634
a4b8110e 635 /* Otherwise, we're ok */
636 /* Return 900 (90%) load */
637 return 900;
cd748f27 638}
a4b8110e 639
cd748f27 640/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */
641
642void
a4b8110e 643storeCossDirStats(SwapDir * SD, StoreEntry * sentry)
cd748f27 644{
a4b8110e 645 CossInfo *cs = (CossInfo *) SD->fsdata;
646
cd748f27 647 storeAppendPrintf(sentry, "\n");
648 storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size);
649 storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size);
650 storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n",
a4b8110e 651 100.0 * SD->cur_size / SD->max_size);
652 storeAppendPrintf(sentry, "Number of object collisions: %d\n", (int) cs->numcollisions);
cd748f27 653#if 0
654 /* is this applicable? I Hope not .. */
655 storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n",
a4b8110e 656 SD->map->n_files_in_map, SD->map->max_n_files,
657 percent(SD->map->n_files_in_map, SD->map->max_n_files));
cd748f27 658#endif
659 storeAppendPrintf(sentry, "Flags:");
660 if (SD->flags.selected)
a4b8110e 661 storeAppendPrintf(sentry, " SELECTED");
cd748f27 662 if (SD->flags.read_only)
a4b8110e 663 storeAppendPrintf(sentry, " READ-ONLY");
cd748f27 664 storeAppendPrintf(sentry, "\n");
665}
666
667static void
a4b8110e 668storeCossDirParse(SwapDir * sd, int index, char *path)
cd748f27 669{
670 char *token;
671 unsigned int i;
672 unsigned int size;
673 unsigned int read_only = 0;
674 CossInfo *cs;
675
676 i = GetInteger();
677 size = i << 10; /* Mbytes to Kbytes */
678 if (size <= 0)
679 fatal("storeCossDirParse: invalid size value");
680 if ((token = strtok(NULL, w_space)))
681 if (!strcasecmp(token, "read-only"))
682 read_only = 1;
683
684 cs = xmalloc(sizeof(CossInfo));
685 if (cs == NULL)
686 fatal("storeCossDirParse: couldn't xmalloc() CossInfo!\n");
687
688 sd->index = index;
689 sd->path = xstrdup(path);
690 sd->max_size = size;
691 sd->fsdata = cs;
692
693 cs->fd = -1;
694 cs->swaplog_fd = -1;
695 sd->flags.read_only = read_only;
696
697 sd->init = storeCossDirInit;
698 sd->newfs = storeCossDirNewfs;
699 sd->dump = storeCossDirDump;
700 sd->freefs = storeCossDirShutdown;
701 sd->dblcheck = NULL;
702 sd->statfs = storeCossDirStats;
703 sd->maintainfs = NULL;
704 sd->checkobj = storeCossDirCheckObj;
a4b8110e 705 sd->refobj = NULL; /* LRU is done in storeCossRead */
cd748f27 706 sd->unrefobj = NULL;
707 sd->callback = NULL;
a4b8110e 708 sd->sync = NULL; /* should we make it call the coss sync? */
cd748f27 709
710 sd->obj.create = storeCossCreate;
711 sd->obj.open = storeCossOpen;
712 sd->obj.close = storeCossClose;
713 sd->obj.read = storeCossRead;
714 sd->obj.write = storeCossWrite;
715 sd->obj.unlink = storeCossUnlink;
716
717 sd->log.open = storeCossDirOpenSwapLog;
718 sd->log.close = storeCossDirCloseSwapLog;
719 sd->log.write = storeCossDirSwapLog;
720 sd->log.clean.open = storeCossDirWriteCleanOpen;
721 sd->log.clean.write = storeCossDirWriteCleanEntry;
722
723 cs->current_offset = 0;
724 cs->fd = -1;
725 cs->swaplog_fd = -1;
726 cs->numcollisions = 0;
727 cs->membufs = memPoolAlloc(coss_membuf_pool);
728 cs->membufs->diskstart = 0;
729 cs->membufs->diskend = COSS_MEMBUF_SZ;
730 cs->membufs->lockcount = 0;
731 cs->membufs->flags.full = 0;
732 cs->membufs->flags.writing = 0;
733 cs->membufs->next = NULL;
734 cs->membufs->SD = sd;
735 cs->current_membuf = cs->membufs;
736
737 sd->repl.lru.list.head = NULL;
738 sd->repl.lru.list.tail = NULL;
739}
740
741
742static void
a4b8110e 743storeCossDirReconfigure(SwapDir * sd, int index, char *path)
cd748f27 744{
745 char *token;
746 unsigned int i;
747 unsigned int size;
748 unsigned int read_only = 0;
749
750 i = GetInteger();
751 size = i << 10; /* Mbytes to Kbytes */
752 if (size <= 0)
753 fatal("storeCossDirParse: invalid size value");
754 if ((token = strtok(NULL, w_space)))
755 if (!strcasecmp(token, "read-only"))
756 read_only = 1;
757
758 if (size == sd->max_size)
a4b8110e 759 debug(3, 1) ("Cache COSS dir '%s' size remains unchanged at %d KB\n", path, size);
cd748f27 760 else {
a4b8110e 761 debug(3, 1) ("Cache COSS dir '%s' size changed to %d KB\n", path, size);
762 sd->max_size = size;
cd748f27 763 }
764
765 if (read_only != sd->flags.read_only) {
a4b8110e 766 debug(3, 1) ("Cache COSS dir '%s' now %s\n", path, read_only ? "Read-Only" : "Read-Write");
767 sd->flags.read_only = read_only;
cd748f27 768 }
769}
770
771void
772storeCossDirDump(StoreEntry * entry, const char *name, SwapDir * s)
773{
774 storeAppendPrintf(entry, "%s %s %s %d\n",
775 name,
a4b8110e 776 s->type,
cd748f27 777 s->path,
778 s->max_size >> 20);
779}
780
781#if 0
782SwapDir *
783storeCossDirPick(void)
784{
a4b8110e 785 int i, choosenext = 0;
cd748f27 786 SwapDir *SD;
a4b8110e 787
cd748f27 788 if (n_coss_dirs == 0)
a4b8110e 789 return NULL;
cd748f27 790 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
791 SD = &Config.cacheSwap.swapDirs[i];
a4b8110e 792 if (SD->type == SWAPDIR_COSS) {
793 if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) {
794 last_coss_pick_index = i;
795 return SD;
796 } else if (choosenext) {
797 last_coss_pick_index = i;
798 return SD;
799 } else if (last_coss_pick_index == i) {
800 choosenext = 1;
801 }
802 }
cd748f27 803 }
804 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
805 SD = &Config.cacheSwap.swapDirs[i];
a4b8110e 806 if (SD->type == SWAPDIR_COSS) {
807 if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) {
808 last_coss_pick_index = i;
809 return SD;
810 } else if (choosenext) {
811 last_coss_pick_index = i;
812 return SD;
813 } else if (last_coss_pick_index == i) {
814 choosenext = 1;
815 }
816 }
cd748f27 817 }
a4b8110e 818 return NULL;
cd748f27 819}
820#endif
821
822/*
823 * initial setup/done code
824 */
825static void
826storeCossDirDone(void)
827{
828 memPoolDestroy(coss_membuf_pool);
829 memPoolDestroy(coss_state_pool);
830 coss_initialised = 0;
831}
832
833void
a4b8110e 834storeFsSetup_coss(storefs_entry_t * storefs)
cd748f27 835{
836 assert(!coss_initialised);
837
838 storefs->parsefunc = storeCossDirParse;
839 storefs->reconfigurefunc = storeCossDirReconfigure;
840 storefs->donefunc = storeCossDirDone;
841 coss_membuf_pool = memPoolCreate("COSS Membuf data", sizeof(CossMemBuf));
842 coss_state_pool = memPoolCreate("COSS IO State data", sizeof(CossState));
843 coss_initialised = 1;
844}