]> git.ipfire.org Git - thirdparty/squid.git/blame - src/fs/coss/store_dir_coss.cc
Fixing abuse of struct in_addr in auth_digest authenticate to
[thirdparty/squid.git] / src / fs / coss / store_dir_coss.cc
CommitLineData
a4b8110e 1
cd748f27 2/*
59b2d47f 3 * $Id: store_dir_coss.cc,v 1.46 2003/07/22 15:23:10 robertc Exp $
cd748f27 4 *
17bb3486 5 * DEBUG: section 47 Store COSS Directory Routines
cd748f27 6 * AUTHOR: Eric Stern
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
cd748f27 9 * ----------------------------------------------------------
10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
cd748f27 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"
e6ccf245 37#include "Store.h"
cd748f27 38
39#include "store_coss.h"
528b2c61 40#include "fde.h"
d3b3ab85 41#include "SwapDir.h"
51ee7c82 42#include "StoreSwapLogData.h"
cd748f27 43
44#define STORE_META_BUFSZ 4096
45
cd748f27 46int n_coss_dirs = 0;
47/* static int last_coss_pick_index = -1; */
6a566b9c 48MemPool *coss_index_pool = NULL;
cd748f27 49
50typedef struct _RebuildState RebuildState;
62e76326 51
52struct _RebuildState
53{
d3b3ab85 54 CossSwapDir *sd;
cd748f27 55 int n_read;
56 FILE *log;
57 int speed;
62e76326 58
59 struct
60 {
61
62unsigned int clean:
63 1;
64 }
65
66 flags;
67
cd748f27 68 struct _store_rebuild_data counts;
69};
70
71static char *storeCossDirSwapLogFile(SwapDir *, const char *);
72static EVH storeCossRebuildFromSwapLog;
d3b3ab85 73static StoreEntry *storeCossAddDiskRestore(CossSwapDir * SD, const cache_key * key,
62e76326 74 int file_number,
75 size_t swap_file_sz,
76 time_t expires,
77 time_t timestamp,
78 time_t lastref,
79 time_t lastmod,
80 u_int32_t refcount,
81 u_int16_t flags,
82 int clean);
d3b3ab85 83static void storeCossDirRebuild(CossSwapDir * sd);
84static void storeCossDirCloseTmpSwapLog(CossSwapDir * sd);
85static FILE *storeCossDirOpenTmpSwapLog(CossSwapDir *, int *, int *);
cd748f27 86
87static char *
88storeCossDirSwapLogFile(SwapDir * sd, const char *ext)
89{
90 LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN);
91 LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN);
92 LOCAL_ARRAY(char, digit, 32);
93 char *pathtmp2;
62e76326 94
cd748f27 95 if (Config.Log.swap) {
62e76326 96 xstrncpy(pathtmp, sd->path, SQUID_MAXPATHLEN - 64);
97 pathtmp2 = pathtmp;
98
99 while ((pathtmp2 = strchr(pathtmp2, '/')) != NULL)
100 *pathtmp2 = '.';
101
102 while (strlen(pathtmp) && pathtmp[strlen(pathtmp) - 1] == '.')
103 pathtmp[strlen(pathtmp) - 1] = '\0';
104
105 for (pathtmp2 = pathtmp; *pathtmp2 == '.'; pathtmp2++)
106
107 ;
108 snprintf(path, SQUID_MAXPATHLEN - 64, Config.Log.swap, pathtmp2);
109
110 if (strncmp(path, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) {
111 strcat(path, ".");
112 snprintf(digit, 32, "%02d", sd->index);
113 strncat(path, digit, 3);
114 }
cd748f27 115 } else {
62e76326 116 xstrncpy(path, sd->path, SQUID_MAXPATHLEN - 64);
117 strcat(path, "/swap.state");
cd748f27 118 }
62e76326 119
cd748f27 120 if (ext)
62e76326 121 strncat(path, ext, 16);
122
cd748f27 123 return path;
124}
125
d3b3ab85 126void
127CossSwapDir::openLog()
cd748f27 128{
d3b3ab85 129 char *logPath;
130 logPath = storeCossDirSwapLogFile(this, NULL);
131 swaplog_fd = file_open(logPath, O_WRONLY | O_CREAT | O_BINARY);
62e76326 132
d3b3ab85 133 if (swaplog_fd < 0) {
62e76326 134 debug(47, 1) ("%s: %s\n", logPath, xstrerror());
135 fatal("storeCossDirOpenSwapLog: Failed to open swap log.");
cd748f27 136 }
62e76326 137
d3b3ab85 138 debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", index, swaplog_fd);
cd748f27 139}
140
d3b3ab85 141void
142CossSwapDir::closeLog()
cd748f27 143{
d3b3ab85 144 if (swaplog_fd < 0) /* not open */
62e76326 145 return;
146
d3b3ab85 147 file_close(swaplog_fd);
62e76326 148
99cce4cb 149 debug(47, 3) ("Cache COSS Dir #%d log closed on FD %d\n",
62e76326 150 index, swaplog_fd);
151
d3b3ab85 152 swaplog_fd = -1;
cd748f27 153}
154
d3b3ab85 155void
156CossSwapDir::init()
157{
158 a_file_setupqueue(&aq);
159 openLog();
160 storeCossDirRebuild(this);
161 fd = file_open(path, O_RDWR | O_CREAT);
62e76326 162
d3b3ab85 163 if (fd < 0) {
62e76326 164 debug(47, 1) ("%s: %s\n", path, xstrerror());
165 fatal("storeCossDirInit: Failed to open a COSS directory.");
697c29aa 166 }
62e76326 167
cd748f27 168 n_coss_dirs++;
d3b3ab85 169 (void) storeDirGetBlkSize(path, &fs.blksize);
cd748f27 170}
171
6a566b9c 172void
d3b3ab85 173storeCossRemove(CossSwapDir * sd, StoreEntry * e)
6a566b9c 174{
e6ccf245 175 CossIndexNode *coss_node = (CossIndexNode *)e->repl.data;
6a566b9c 176 e->repl.data = NULL;
d3b3ab85 177 dlinkDelete(&coss_node->node, &sd->cossindex);
6a566b9c 178 memPoolFree(coss_index_pool, coss_node);
d3b3ab85 179 sd->count -= 1;
6a566b9c 180}
181
182void
d3b3ab85 183storeCossAdd(CossSwapDir * sd, StoreEntry * e)
6a566b9c 184{
e6ccf245 185 CossIndexNode *coss_node = (CossIndexNode *)memPoolAlloc(coss_index_pool);
6a566b9c 186 assert(!e->repl.data);
187 e->repl.data = coss_node;
d3b3ab85 188 dlinkAdd(e, &coss_node->node, &sd->cossindex);
189 sd->count += 1;
6a566b9c 190}
191
192static void
193storeCossRebuildComplete(void *data)
194{
e6ccf245 195 RebuildState *rb = (RebuildState *)data;
d3b3ab85 196 CossSwapDir *sd = rb->sd;
6a566b9c 197 storeCossStartMembuf(sd);
198 store_dirs_rebuilding--;
199 storeCossDirCloseTmpSwapLog(rb->sd);
200 storeRebuildComplete(&rb->counts);
201 cbdataFree(rb);
202}
203
cd748f27 204static void
205storeCossRebuildFromSwapLog(void *data)
206{
e6ccf245 207 RebuildState *rb = (RebuildState *)data;
cd748f27 208 StoreEntry *e = NULL;
51ee7c82 209 StoreSwapLogData s;
210 size_t ss = sizeof(StoreSwapLogData);
cd748f27 211 double x;
212 assert(rb != NULL);
213 /* load a number of objects per invocation */
62e76326 214
d3b3ab85 215 for (int aCount = 0; aCount < rb->speed; aCount++) {
62e76326 216 if (fread(&s, ss, 1, rb->log) != 1) {
217 debug(47, 1) ("Done reading %s swaplog (%d entries)\n",
218 rb->sd->path, rb->n_read);
219 fclose(rb->log);
220 rb->log = NULL;
221 storeCossRebuildComplete(rb);
222 return;
223 }
224
225 rb->n_read++;
226
227 if (s.op <= SWAP_LOG_NOP)
228 continue;
229
230 if (s.op >= SWAP_LOG_MAX)
231 continue;
232
233 debug(47, 3) ("storeCossRebuildFromSwapLog: %s %s %08X\n",
234 swap_log_op_str[(int) s.op],
235 storeKeyText(s.key),
236 s.swap_filen);
237
238 if (s.op == SWAP_LOG_ADD) {
239 (void) 0;
240 } else if (s.op == SWAP_LOG_DEL) {
241 /* Delete unless we already have a newer copy */
242
243 if ((e = storeGet(s.key)) != NULL && s.lastref > e->lastref) {
244 /*
245 * Make sure we don't unlink the file, it might be
246 * in use by a subsequent entry. Also note that
247 * we don't have to subtract from store_swap_size
248 * because adding to store_swap_size happens in
249 * the cleanup procedure.
250 */
251 storeExpireNow(e);
252 storeReleaseRequest(e);
253
254 if (e->swap_filen > -1) {
255 e->swap_filen = -1;
256 }
257
258 storeRelease(e);
259 /* Fake an unlink here, this is a bad hack :( */
260 storeCossRemove(rb->sd, e);
261 rb->counts.objcount--;
262 rb->counts.cancelcount++;
263 }
264
265 continue;
266 } else {
267 x = log(++rb->counts.bad_log_op) / log(10.0);
268
269 if (0.0 == x - (double) (int) x)
270 debug(47, 1) ("WARNING: %d invalid swap log entries found\n",
271 rb->counts.bad_log_op);
272
273 rb->counts.invalid++;
274
275 continue;
276 }
277
278 if ((++rb->counts.scancount & 0xFFF) == 0) {
279
280 struct stat sb;
281
282 if (0 == fstat(fileno(rb->log), &sb))
283 storeRebuildProgress(rb->sd->index,
284 (int) sb.st_size / ss, rb->n_read);
285 }
286
287 if (EBIT_TEST(s.flags, KEY_PRIVATE)) {
288 rb->counts.badflags++;
289 continue;
290 }
291
292 e = storeGet(s.key);
293
294 if (e) {
295 /* key already exists, current entry is newer */
296 /* keep old, ignore new */
297 rb->counts.dupcount++;
298 continue;
299 }
300
301 /* update store_swap_size */
302 rb->counts.objcount++;
303
304 e = storeCossAddDiskRestore(rb->sd, s.key,
305 s.swap_filen,
306 s.swap_file_sz,
307 s.expires,
308 s.timestamp,
309 s.lastref,
310 s.lastmod,
311 s.refcount,
312 s.flags,
313 (int) rb->flags.clean);
314
315 storeDirSwapLog(e, SWAP_LOG_ADD);
cd748f27 316 }
62e76326 317
cd748f27 318 eventAdd("storeCossRebuild", storeCossRebuildFromSwapLog, rb, 0.0, 1);
319}
320
321/* Add a new object to the cache with empty memory copy and pointer to disk
322 * use to rebuild store from disk. */
323static StoreEntry *
d3b3ab85 324storeCossAddDiskRestore(CossSwapDir * SD, const cache_key * key,
62e76326 325 int file_number,
326 size_t swap_file_sz,
327 time_t expires,
328 time_t timestamp,
329 time_t lastref,
330 time_t lastmod,
331 u_int32_t refcount,
332 u_int16_t flags,
333 int clean)
cd748f27 334{
335 StoreEntry *e = NULL;
99cce4cb 336 debug(47, 5) ("storeCossAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number);
62e76326 337 /* if you call this you'd better be sure file_number is not
cd748f27 338 * already in use! */
339 e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL);
340 e->store_status = STORE_OK;
341 e->swap_dirn = SD->index;
342 storeSetMemStatus(e, NOT_IN_MEMORY);
343 e->swap_status = SWAPOUT_DONE;
344 e->swap_filen = file_number;
345 e->swap_file_sz = swap_file_sz;
346 e->lock_count = 0;
cd748f27 347 e->lastref = lastref;
348 e->timestamp = timestamp;
349 e->expires = expires;
350 e->lastmod = lastmod;
351 e->refcount = refcount;
352 e->flags = flags;
353 EBIT_SET(e->flags, ENTRY_CACHABLE);
354 EBIT_CLR(e->flags, RELEASE_REQUEST);
355 EBIT_CLR(e->flags, KEY_PRIVATE);
356 e->ping_status = PING_NONE;
357 EBIT_CLR(e->flags, ENTRY_VALIDATED);
358 storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */
6a566b9c 359 storeCossAdd(SD, e);
cd748f27 360 e->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_NOTIFY);
361 return e;
362}
363
28c60158 364CBDATA_TYPE(RebuildState);
cd748f27 365static void
d3b3ab85 366storeCossDirRebuild(CossSwapDir * sd)
cd748f27 367{
28c60158 368 RebuildState *rb;
cd748f27 369 int clean = 0;
370 int zero = 0;
371 FILE *fp;
372 EVH *func = NULL;
28c60158 373 CBDATA_INIT_TYPE(RebuildState);
72711e31 374 rb = cbdataAlloc(RebuildState);
cd748f27 375 rb->sd = sd;
376 rb->speed = opt_foreground_rebuild ? 1 << 30 : 50;
6a566b9c 377 func = storeCossRebuildFromSwapLog;
378 rb->flags.clean = (unsigned int) clean;
cd748f27 379 /*
380 * If the swap.state file exists in the cache_dir, then
381 * we'll use storeCossRebuildFromSwapLog().
382 */
383 fp = storeCossDirOpenTmpSwapLog(sd, &clean, &zero);
99cce4cb 384 debug(47, 1) ("Rebuilding COSS storage in %s (%s)\n",
62e76326 385 sd->path, clean ? "CLEAN" : "DIRTY");
6a566b9c 386 rb->log = fp;
387 store_dirs_rebuilding++;
62e76326 388
cd748f27 389 if (!clean || fp == NULL) {
62e76326 390 /* COSS cannot yet rebuild from a dirty state. If the log
391 * is dirty then the COSS contents is thrown away.
392 * Why? I guess it is because some contents will be lost,
393 * and COSS cannot verify this..
394 */
395
396 if (fp != NULL)
397 fclose(fp);
398
399 /*
400 * XXX Make sure we don't trigger an assertion if this is the first
401 * storedir, since if we are, this call will cause storeRebuildComplete
402 * to prematurely complete the rebuild process, and then some other
403 * storedir will try to rebuild and eventually die.
404 */
405 eventAdd("storeCossRebuildComplete", storeCossRebuildComplete, rb, 0.0, 0);
406
407 return;
cd748f27 408 }
62e76326 409
cd748f27 410 eventAdd("storeCossRebuild", func, rb, 0.0, 1);
411}
412
413static void
d3b3ab85 414storeCossDirCloseTmpSwapLog(CossSwapDir * sd)
cd748f27 415{
cd748f27 416 char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL));
417 char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new"));
d3b3ab85 418 int anfd;
419 file_close(sd->swaplog_fd);
3d37fe17 420#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_)
62e76326 421
cd748f27 422 if (unlink(swaplog_path) < 0) {
62e76326 423 debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror());
424 fatal("storeCossDirCloseTmpSwapLog: unlink failed");
cd748f27 425 }
62e76326 426
cd748f27 427#endif
428 if (xrename(new_path, swaplog_path) < 0) {
62e76326 429 fatal("storeCossDirCloseTmpSwapLog: rename failed");
cd748f27 430 }
62e76326 431
d3b3ab85 432 anfd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY);
62e76326 433
d3b3ab85 434 if (anfd < 0) {
62e76326 435 debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror());
436 fatal("storeCossDirCloseTmpSwapLog: Failed to open swap log.");
cd748f27 437 }
62e76326 438
cd748f27 439 safe_free(swaplog_path);
440 safe_free(new_path);
d3b3ab85 441 sd->swaplog_fd = anfd;
442 debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, anfd);
cd748f27 443}
444
445static FILE *
d3b3ab85 446storeCossDirOpenTmpSwapLog(CossSwapDir * sd, int *clean_flag, int *zero_flag)
cd748f27 447{
cd748f27 448 char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL));
449 char *clean_path = xstrdup(storeCossDirSwapLogFile(sd, ".last-clean"));
450 char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new"));
62e76326 451
cd748f27 452 struct stat log_sb;
62e76326 453
cd748f27 454 struct stat clean_sb;
455 FILE *fp;
d3b3ab85 456 int anfd;
62e76326 457
cd748f27 458 if (stat(swaplog_path, &log_sb) < 0) {
62e76326 459 debug(50, 1) ("Cache COSS Dir #%d: No log file\n", sd->index);
460 safe_free(swaplog_path);
461 safe_free(clean_path);
462 safe_free(new_path);
463 return NULL;
cd748f27 464 }
62e76326 465
cd748f27 466 *zero_flag = log_sb.st_size == 0 ? 1 : 0;
467 /* close the existing write-only FD */
62e76326 468
d3b3ab85 469 if (sd->swaplog_fd >= 0)
62e76326 470 file_close(sd->swaplog_fd);
471
cd748f27 472 /* open a write-only FD for the new log */
d3b3ab85 473 anfd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
62e76326 474
d3b3ab85 475 if (anfd < 0) {
62e76326 476 debug(50, 1) ("%s: %s\n", new_path, xstrerror());
477 fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
cd748f27 478 }
62e76326 479
d3b3ab85 480 sd->swaplog_fd = anfd;
cd748f27 481 /* open a read-only stream of the old log */
3d37fe17 482 fp = fopen(swaplog_path, "rb");
62e76326 483
cd748f27 484 if (fp == NULL) {
62e76326 485 debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror());
486 fatal("Failed to open swap log for reading");
cd748f27 487 }
62e76326 488
cd748f27 489 memset(&clean_sb, '\0', sizeof(struct stat));
62e76326 490
cd748f27 491 if (stat(clean_path, &clean_sb) < 0)
62e76326 492 *clean_flag = 0;
cd748f27 493 else if (clean_sb.st_mtime < log_sb.st_mtime)
62e76326 494 *clean_flag = 0;
cd748f27 495 else
62e76326 496 *clean_flag = 1;
497
cd748f27 498 safeunlink(clean_path, 1);
62e76326 499
cd748f27 500 safe_free(swaplog_path);
62e76326 501
cd748f27 502 safe_free(clean_path);
62e76326 503
cd748f27 504 safe_free(new_path);
62e76326 505
cd748f27 506 return fp;
507}
508
62e76326 509class CossCleanLog : public SwapDir::CleanLog
510{
511
512public:
d3b3ab85 513 CossCleanLog(SwapDir *);
514 virtual const StoreEntry *nextEntry();
515 virtual void write(StoreEntry const &);
cd748f27 516 char *cur;
e6ccf245 517 char *newLog;
cd748f27 518 char *cln;
519 char *outbuf;
520 off_t outbuf_offset;
521 int fd;
6a566b9c 522 dlink_node *current;
d3b3ab85 523 SwapDir *sd;
cd748f27 524};
525
526#define CLEAN_BUF_SZ 16384
d3b3ab85 527
528CossCleanLog::CossCleanLog(SwapDir *aSwapDir) : cur(NULL),newLog(NULL),cln(NULL),outbuf(NULL),
62e76326 529 outbuf_offset(0), fd(-1),current(NULL), sd(aSwapDir)
530{}
d3b3ab85 531
cd748f27 532/*
533 * Begin the process to write clean cache state. For COSS this means
534 * opening some log files and allocating write buffers. Return 0 if
535 * we succeed, and assign the 'func' and 'data' return pointers.
536 */
d3b3ab85 537int
538CossSwapDir::writeCleanStart()
cd748f27 539{
d3b3ab85 540 CossCleanLog *state = new CossCleanLog(this);
1f56cfef 541#if HAVE_FCHMOD
62e76326 542
cd748f27 543 struct stat sb;
1f56cfef 544#endif
62e76326 545
d3b3ab85 546 state->newLog = xstrdup(storeCossDirSwapLogFile(this, ".clean"));
e6ccf245 547 state->fd = file_open(state->newLog, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
d3b3ab85 548 cleanLog = NULL;
62e76326 549
81928dfe 550 if (state->fd < 0) {
62e76326 551 xfree(state->newLog);
552 delete state;
553 return -1;
81928dfe 554 }
62e76326 555
d3b3ab85 556 state->cur = xstrdup(storeCossDirSwapLogFile(this, NULL));
557 state->cln = xstrdup(storeCossDirSwapLogFile(this, ".last-clean"));
e6ccf245 558 state->outbuf = (char *)xcalloc(CLEAN_BUF_SZ, 1);
cd748f27 559 state->outbuf_offset = 0;
d3b3ab85 560 ::unlink(state->cln);
561 state->current = cossindex.tail;
99cce4cb 562 debug(50, 3) ("storeCOssDirWriteCleanLogs: opened %s, FD %d\n",
62e76326 563 state->newLog, state->fd);
cd748f27 564#if HAVE_FCHMOD
62e76326 565
cd748f27 566 if (stat(state->cur, &sb) == 0)
62e76326 567 fchmod(state->fd, sb.st_mode);
568
cd748f27 569#endif
62e76326 570
d3b3ab85 571 cleanLog = state;
6a566b9c 572
cd748f27 573 return 0;
574}
575
d3b3ab85 576const StoreEntry *
577CossCleanLog::nextEntry()
6a566b9c 578{
6a566b9c 579 const StoreEntry *entry;
62e76326 580
d3b3ab85 581 if (!current)
62e76326 582 return NULL;
583
d3b3ab85 584 entry = (const StoreEntry *) current->data;
62e76326 585
d3b3ab85 586 current = current->prev;
62e76326 587
6a566b9c 588 return entry;
589}
590
cd748f27 591/*
592 * "write" an entry to the clean log file.
593 */
d3b3ab85 594void
595CossCleanLog::write(StoreEntry const &e)
cd748f27 596{
d3b3ab85 597 CossCleanLog *state = this;
51ee7c82 598 StoreSwapLogData s;
599 static size_t ss = sizeof(StoreSwapLogData);
cd748f27 600 s.op = (char) SWAP_LOG_ADD;
d3b3ab85 601 s.swap_filen = e.swap_filen;
602 s.timestamp = e.timestamp;
603 s.lastref = e.lastref;
604 s.expires = e.expires;
605 s.lastmod = e.lastmod;
606 s.swap_file_sz = e.swap_file_sz;
607 s.refcount = e.refcount;
608 s.flags = e.flags;
609 xmemcpy(&s.key, e.key, MD5_DIGEST_CHARS);
cd748f27 610 xmemcpy(state->outbuf + state->outbuf_offset, &s, ss);
611 state->outbuf_offset += ss;
612 /* buffered write */
62e76326 613
cd748f27 614 if (state->outbuf_offset + ss > CLEAN_BUF_SZ) {
62e76326 615 if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) {
616 debug(50, 0) ("storeCossDirWriteCleanLogs: %s: write: %s\n",
617 state->newLog, xstrerror());
618 debug(50, 0) ("storeCossDirWriteCleanLogs: Current swap logfile not replaced.\n");
619 file_close(state->fd);
620 state->fd = -1;
621 unlink(state->newLog);
622 delete state;
623 sd->cleanLog = NULL;
624 return;
625 }
626
627 state->outbuf_offset = 0;
cd748f27 628 }
629}
630
d3b3ab85 631void
632CossSwapDir::writeCleanDone()
cd748f27 633{
d3b3ab85 634 CossCleanLog *state = (CossCleanLog *)cleanLog;
62e76326 635
a7d542ee 636 if (NULL == state)
62e76326 637 return;
638
cd748f27 639 if (state->fd < 0)
62e76326 640 return;
641
d0ef8ea8 642 if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) {
62e76326 643 debug(50, 0) ("storeCossDirWriteCleanLogs: %s: write: %s\n",
644 state->newLog, xstrerror());
645 debug(50, 0) ("storeCossDirWriteCleanLogs: Current swap logfile "
646 "not replaced.\n");
647 file_close(state->fd);
648 state->fd = -1;
649 ::unlink(state->newLog);
cd748f27 650 }
62e76326 651
cd748f27 652 safe_free(state->outbuf);
653 /*
654 * You can't rename open files on Microsoft "operating systems"
655 * so we have to close before renaming.
656 */
d3b3ab85 657 closeLog();
3d37fe17 658 /* save the fd value for a later test */
d3b3ab85 659 int anfd = state->fd;
cd748f27 660 /* rename */
62e76326 661
cd748f27 662 if (state->fd >= 0) {
3d37fe17 663#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_)
62e76326 664 file_close(state->fd);
665 state->fd = -1;
666
667 if (unlink(state->cur) < 0)
668 debug(50, 0) ("storeCossDirWriteCleanLogs: unlinkd failed: %s, %s\n",
669 xstrerror(), state->cur);
670
cd748f27 671#endif
62e76326 672
673 xrename(state->newLog, state->cur);
cd748f27 674 }
62e76326 675
cd748f27 676 /* touch a timestamp file if we're not still validating */
677 if (store_dirs_rebuilding)
62e76326 678 (void) 0;
d3b3ab85 679 else if (anfd < 0)
62e76326 680 (void) 0;
cd748f27 681 else
62e76326 682 file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY));
683
cd748f27 684 /* close */
685 safe_free(state->cur);
62e76326 686
e6ccf245 687 safe_free(state->newLog);
62e76326 688
cd748f27 689 safe_free(state->cln);
62e76326 690
cd748f27 691 if (state->fd >= 0)
62e76326 692 file_close(state->fd);
693
cd748f27 694 state->fd = -1;
62e76326 695
d3b3ab85 696 delete state;
62e76326 697
d3b3ab85 698 cleanLog = NULL;
cd748f27 699}
700
d3b3ab85 701void
702CossSwapDir::logEntry(const StoreEntry & e, int op) const
cd748f27 703{
51ee7c82 704 StoreSwapLogData *s = new StoreSwapLogData;
cd748f27 705 s->op = (char) op;
d3b3ab85 706 s->swap_filen = e.swap_filen;
707 s->timestamp = e.timestamp;
708 s->lastref = e.lastref;
709 s->expires = e.expires;
710 s->lastmod = e.lastmod;
711 s->swap_file_sz = e.swap_file_sz;
712 s->refcount = e.refcount;
713 s->flags = e.flags;
714 xmemcpy(s->key, e.key, MD5_DIGEST_CHARS);
715 file_write(swaplog_fd,
62e76326 716 -1,
717 s,
51ee7c82 718 sizeof(StoreSwapLogData),
62e76326 719 NULL,
720 NULL,
51ee7c82 721 &FreeObject<StoreSwapLogData>);
cd748f27 722}
723
d3b3ab85 724void
725CossSwapDir::newFileSystem()
cd748f27 726{
d3b3ab85 727 debug(47, 3) ("Creating swap space in %s\n", path);
728 debug (47,0)("COSS autocreation is not implemented. Please create the file manually\n");
cd748f27 729}
730
a4b8110e 731/* we are shutting down, flush all membufs to disk */
d3b3ab85 732CossSwapDir::~CossSwapDir()
cd748f27 733{
d3b3ab85 734 sync(); /* This'll call a_file_syncqueue() */
735 a_file_closequeue(&aq);
736 file_close(fd);
737 fd = -1;
cd748f27 738
d3b3ab85 739 closeLog();
cd748f27 740 n_coss_dirs--;
741}
742
743/*
744 * storeCossDirCheckObj
745 *
746 * This routine is called by storeDirSelectSwapDir to see if the given
747 * object is able to be stored on this filesystem. COSS filesystems will
748 * not store everything. We don't check for maxobjsize here since its
749 * done by the upper layers.
750 */
751int
d3b3ab85 752CossSwapDir::canStore(StoreEntry const &e)const
cd748f27 753{
0dbabb56 754 int loadav;
755
a4b8110e 756 /* Check if the object is a special object, we can't cache these */
62e76326 757
d3b3ab85 758 if (EBIT_TEST(e.flags, ENTRY_SPECIAL))
62e76326 759 return -1;
cd748f27 760
a4b8110e 761 /* Otherwise, we're ok */
0dbabb56 762 /* Return load, cs->aq.aq_numpending out of MAX_ASYNCOP */
d3b3ab85 763 loadav = aq.aq_numpending * 1000 / MAX_ASYNCOP;
62e76326 764
0dbabb56 765 return loadav;
cd748f27 766}
a4b8110e 767
0e23343f 768/*
769 * storeCossDirCallback - do the IO completions
770 */
d3b3ab85 771int
772CossSwapDir::callback()
0e23343f 773{
d3b3ab85 774 return a_file_callback(&aq);
0e23343f 775}
776
cd748f27 777/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */
778
d3b3ab85 779void
780CossSwapDir::statfs(StoreEntry & sentry) const
cd748f27 781{
d3b3ab85 782 storeAppendPrintf(&sentry, "\n");
783 storeAppendPrintf(&sentry, "Maximum Size: %d KB\n", max_size);
784 storeAppendPrintf(&sentry, "Current Size: %d KB\n", cur_size);
785 storeAppendPrintf(&sentry, "Percent Used: %0.2f%%\n",
62e76326 786 100.0 * cur_size / max_size);
d3b3ab85 787 storeAppendPrintf(&sentry, "Number of object collisions: %d\n", (int) numcollisions);
cd748f27 788#if 0
789 /* is this applicable? I Hope not .. */
790 storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n",
62e76326 791 SD->map->n_files_in_map, SD->map->max_n_files,
792 percent(SD->map->n_files_in_map, SD->map->max_n_files));
cd748f27 793#endif
62e76326 794
d3b3ab85 795 storeAppendPrintf(&sentry, "Pending operations: %d out of %d\n", aq.aq_numpending, MAX_ASYNCOP);
796 storeAppendPrintf(&sentry, "Flags:");
62e76326 797
d3b3ab85 798 if (flags.selected)
62e76326 799 storeAppendPrintf(&sentry, " SELECTED");
800
d3b3ab85 801 if (flags.read_only)
62e76326 802 storeAppendPrintf(&sentry, " READ-ONLY");
803
d3b3ab85 804 storeAppendPrintf(&sentry, "\n");
cd748f27 805}
806
d3b3ab85 807void
808CossSwapDir::parse(int anIndex, char *aPath)
cd748f27 809{
cd748f27 810 unsigned int i;
811 unsigned int size;
cd748f27 812
813 i = GetInteger();
814 size = i << 10; /* Mbytes to Kbytes */
62e76326 815
cd748f27 816 if (size <= 0)
62e76326 817 fatal("storeCossDirParse: invalid size value");
cd748f27 818
d3b3ab85 819 index = anIndex;
62e76326 820
d3b3ab85 821 path = xstrdup(aPath);
62e76326 822
d3b3ab85 823 max_size = size;
824
59b2d47f 825 parseOptions(0);
62e76326 826
c94af0b9 827 /* Enforce maxobjsize being set to something */
d3b3ab85 828 if (max_objsize == -1)
62e76326 829 fatal("COSS requires max-size to be set to something other than -1!\n");
cd748f27 830}
831
832
d3b3ab85 833void
834CossSwapDir::reconfigure(int index, char *path)
cd748f27 835{
cd748f27 836 unsigned int i;
837 unsigned int size;
cd748f27 838
839 i = GetInteger();
840 size = i << 10; /* Mbytes to Kbytes */
62e76326 841
cd748f27 842 if (size <= 0)
62e76326 843 fatal("storeCossDirParse: invalid size value");
cd748f27 844
d3b3ab85 845 if (size == (size_t)max_size)
62e76326 846 debug(3, 1) ("Cache COSS dir '%s' size remains unchanged at %d KB\n", path, size);
cd748f27 847 else {
62e76326 848 debug(3, 1) ("Cache COSS dir '%s' size changed to %d KB\n", path, size);
849 max_size = size;
cd748f27 850 }
62e76326 851
59b2d47f 852 parseOptions(1);
c94af0b9 853 /* Enforce maxobjsize being set to something */
62e76326 854
d3b3ab85 855 if (max_objsize == -1)
62e76326 856 fatal("COSS requires max-size to be set to something other than -1!\n");
cd748f27 857}
858
859void
d3b3ab85 860CossSwapDir::dump(StoreEntry &entry)const
cd748f27 861{
59b2d47f 862 storeAppendPrintf(&entry, " %d", max_size >> 20);
863 dumpOptions(&entry);
cd748f27 864}
865
6a566b9c 866#if OLD_UNUSED_CODE
cd748f27 867SwapDir *
868storeCossDirPick(void)
869{
a4b8110e 870 int i, choosenext = 0;
cd748f27 871 SwapDir *SD;
a4b8110e 872
cd748f27 873 if (n_coss_dirs == 0)
62e76326 874 return NULL;
875
cd748f27 876 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
62e76326 877 SD = &Config.cacheSwap.swapDirs[i];
878
879 if (SD->type == SWAPDIR_COSS) {
880 if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) {
881 last_coss_pick_index = i;
882 return SD;
883 } else if (choosenext) {
884 last_coss_pick_index = i;
885 return SD;
886 } else if (last_coss_pick_index == i) {
887 choosenext = 1;
888 }
889 }
cd748f27 890 }
62e76326 891
cd748f27 892 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
62e76326 893 SD = &Config.cacheSwap.swapDirs[i];
894
895 if (SD->type == SWAPDIR_COSS) {
896 if ((last_coss_pick_index == -1) || (n_coss_dirs == 1)) {
897 last_coss_pick_index = i;
898 return SD;
899 } else if (choosenext) {
900 last_coss_pick_index = i;
901 return SD;
902 } else if (last_coss_pick_index == i) {
903 choosenext = 1;
904 }
905 }
cd748f27 906 }
62e76326 907
a4b8110e 908 return NULL;
cd748f27 909}
62e76326 910
cd748f27 911#endif
59b2d47f 912CossSwapDir::CossSwapDir() : SwapDir ("coss"), fd (-1), swaplog_fd(-1), count(0), current_membuf (NULL), current_offset(0), numcollisions(0)
d3b3ab85 913{
914 membufs.head = NULL;
915 membufs.tail = NULL;
916 cossindex.head = NULL;
917 cossindex.tail = NULL;
918}
919