5 * DEBUG: section 47 Store COSS Directory Routines
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36 #include "squid-old.h"
37 #include "CossSwapDir.h"
40 #include "store_coss.h"
44 #include "StoreSwapLogData.h"
45 #include "DiskIO/DiskIOModule.h"
46 #include "DiskIO/DiskIOStrategy.h"
47 #include "DiskIO/ReadRequest.h"
48 #include "ConfigOption.h"
49 #include "StoreFScoss.h"
51 #include "swap_log_op.h"
52 #include "SquidMath.h"
54 #define STORE_META_BUFSZ 4096
57 /* static int last_coss_pick_index = -1; */
58 MemAllocator
*coss_index_pool
= NULL
;
60 typedef struct _RebuildState RebuildState
;
62 struct _RebuildState
{
72 struct _store_rebuild_data counts
;
75 static char *storeCossDirSwapLogFile(SwapDir
*, const char *);
76 static EVH storeCossRebuildFromSwapLog
;
77 static void storeCossDirRebuild(CossSwapDir
* sd
);
78 static void storeCossDirCloseTmpSwapLog(CossSwapDir
* sd
);
79 static FILE *storeCossDirOpenTmpSwapLog(CossSwapDir
*, int *, int *);
82 storeCossDirSwapLogFile(SwapDir
* sd
, const char *ext
)
84 LOCAL_ARRAY(char, path
, MAXPATHLEN
);
85 LOCAL_ARRAY(char, pathtmp
, MAXPATHLEN
);
86 LOCAL_ARRAY(char, digit
, 32);
89 if (Config
.Log
.swap
) {
90 xstrncpy(pathtmp
, sd
->path
, MAXPATHLEN
- 64);
93 while ((pathtmp2
= strchr(pathtmp2
, '/')) != NULL
)
96 while (strlen(pathtmp
) && pathtmp
[strlen(pathtmp
) - 1] == '.')
97 pathtmp
[strlen(pathtmp
) - 1] = '\0';
99 for (pathtmp2
= pathtmp
; *pathtmp2
== '.'; pathtmp2
++);
100 snprintf(path
, MAXPATHLEN
- 64, Config
.Log
.swap
, pathtmp2
);
102 if (strncmp(path
, Config
.Log
.swap
, MAXPATHLEN
- 64) == 0) {
104 snprintf(digit
, 32, "%02d", sd
->index
);
105 strncat(path
, digit
, 3);
108 xstrncpy(path
, sd
->path
, MAXPATHLEN
- 64);
109 strcat(path
, "/swap.state");
113 strncat(path
, ext
, 16);
119 CossSwapDir::openLog()
122 logPath
= storeCossDirSwapLogFile(this, NULL
);
123 swaplog_fd
= file_open(logPath
, O_WRONLY
| O_CREAT
| O_BINARY
);
125 if (swaplog_fd
< 0) {
126 debugs(47, 1, "" << logPath
<< ": " << xstrerror());
127 fatal("storeCossDirOpenSwapLog: Failed to open swap log.");
130 debugs(47, 3, "Cache COSS Dir #" << index
<< " log opened on FD " << swaplog_fd
);
134 CossSwapDir::closeLog()
136 if (swaplog_fd
< 0) /* not open */
139 file_close(swaplog_fd
);
141 debugs(47, 3, "Cache COSS Dir #" << index
<< " log closed on FD " << swaplog_fd
);
147 CossSwapDir::ioCompletedNotification()
149 if (theFile
->error()) {
150 debugs(47, 1, "" << path
<< ": " << xstrerror());
151 fatal("storeCossDirInit: Failed to open a COSS file.");
156 CossSwapDir::closeCompleted()
162 CossSwapDir::readCompleted(const char *buf
, int len
, int errflag
, RefCount
<ReadRequest
> aRequest
)
164 CossRead
* cossRead
= dynamic_cast<CossRead
*>(aRequest
.getRaw());
166 StoreIOState::Pointer sio
= cossRead
->sio
;
168 StoreIOState::STRCB
*callback
= sio
->read
.callback
;
170 CossState
*cstate
= dynamic_cast<CossState
*>(sio
.getRaw());
173 debugs(79, 3, "storeCossReadDone: fileno " << sio
->swap_filen
<< ", len " << len
);
174 cstate
->flags
.reading
= 0;
177 StoreFScoss::GetInstance().stats
.read
.fail
++;
181 debugs(79, 1, "storeCossReadDone: error: " << xstrerror());
183 debugs(79, 1, "storeCossReadDone: got failure (" << errflag
<< ")");
188 StoreFScoss::GetInstance().stats
.read
.success
++;
190 if (cstate
->readbuffer
== NULL
) {
191 cstate
->readbuffer
= (char *)xmalloc(cstate
->st_size
);
192 p
= storeCossMemPointerFromDiskOffset(storeCossFilenoToDiskOffset(sio
->swap_filen
),
194 memcpy(cstate
->readbuffer
, p
, cstate
->st_size
);
198 memcpy(cstate
->requestbuf
, &cstate
->readbuffer
[cstate
->requestoffset
],
200 rlen
= (size_t) cstate
->requestlen
;
204 sio
->read
.callback
= NULL
;
206 if (cbdataReferenceValidDone(sio
->read
.callback_data
, &cbdata
))
207 callback(cbdata
, cstate
->requestbuf
, rlen
, sio
);
211 CossSwapDir::writeCompleted(int errflag
, size_t len
, RefCount
<WriteRequest
> writeRequest
)
213 CossWrite
* cossWrite
= dynamic_cast<CossWrite
*>(writeRequest
.getRaw());
216 debugs(79, 3, "storeCossWriteMemBufDone: buf " << cossWrite
->membuf
<< ", len " << len
);
220 StoreFScoss::GetInstance().stats
.stripe_write
.fail
++;
221 debugs(79, 1, "storeCossWriteMemBufDone: got failure (" << errflag
<< ")");
222 debugs(79, 1, "size=" << cossWrite
->membuf
->diskend
- cossWrite
->membuf
->diskstart
);
224 StoreFScoss::GetInstance().stats
.stripe_write
.success
++;
228 dlinkDelete(&cossWrite
->membuf
->node
, &membufs
);
229 cbdataFree(cossWrite
->membuf
);
230 StoreFScoss::GetInstance().stats
.stripes
--;
234 CossSwapDir::changeIO(DiskIOModule
*module
)
236 DiskIOStrategy
*anIO
= module
->createStrategy();
238 ioModule
= xstrdup(module
->type());
242 /* Change the IO Options */
244 if (currentIOOptions
== NULL
)
245 currentIOOptions
= new ConfigOptionVector();
247 if (currentIOOptions
->options
.size() > 3)
248 delete currentIOOptions
->options
.pop_back();
250 /* TODO: factor out these 4 lines */
251 ConfigOption
*ioOptions
= NULL
;
254 ioOptions
= io
->getOptionTree();
257 currentIOOptions
->options
.push_back(ioOptions
);
261 CossSwapDir::optionIOParse(char const *option
, const char *value
, int reconfiguring
)
263 if (strcmp(option
, "IOEngine") != 0)
267 /* silently ignore this */
273 DiskIOModule
*module
= DiskIOModule::Find(value
);
284 CossSwapDir::optionIODump(StoreEntry
* e
) const
286 storeAppendPrintf(e
, " IOEngine=%s", ioModule
);
290 CossSwapDir::getOptionTree() const
292 ConfigOption
*parentResult
= SwapDir::getOptionTree();
294 if (currentIOOptions
== NULL
)
295 currentIOOptions
= new ConfigOptionVector();
297 currentIOOptions
->options
.push_back(parentResult
);
299 currentIOOptions
->options
.push_back(new ConfigOptionAdapter
<CossSwapDir
>(*const_cast<CossSwapDir
*>(this), &CossSwapDir::optionIOParse
, &CossSwapDir::optionIODump
));
301 currentIOOptions
->options
.push_back(
302 new ConfigOptionAdapter
<CossSwapDir
>(*const_cast<CossSwapDir
*>(this),
303 &CossSwapDir::optionBlockSizeParse
,
304 &CossSwapDir::optionBlockSizeDump
));
307 ConfigOption
*ioOptions
= NULL
;
310 ioOptions
= io
->getOptionTree();
313 currentIOOptions
->options
.push_back(ioOptions
);
315 ConfigOption
* result
= currentIOOptions
;
317 currentIOOptions
= NULL
;
325 /* FIXME: SwapDirs aren't refcounted. We call IORequestor calls, which
326 * are refcounted. SO, we up our count once to avoid implicit delete's.
331 storeCossDirRebuild(this);
332 theFile
= io
->newFile(stripePath());
333 theFile
->open(O_RDWR
| O_CREAT
, 0644, this);
337 * fs.blksize is normally determined by calling statvfs() etc,
338 * but we just set it here. It is used in accounting the
339 * total store size, and is reported in cachemgr 'storedir'
342 fs
.blksize
= 1 << blksz_bits
;
346 storeCossRemove(CossSwapDir
* sd
, StoreEntry
* e
)
348 CossIndexNode
*coss_node
= (CossIndexNode
*)e
->repl
.data
;
350 dlinkDelete(&coss_node
->node
, &sd
->cossindex
);
351 coss_index_pool
->freeOne(coss_node
);
356 storeCossAdd(CossSwapDir
* sd
, StoreEntry
* e
)
358 CossIndexNode
*coss_node
= (CossIndexNode
*)coss_index_pool
->alloc();
359 assert(!e
->repl
.data
);
360 e
->repl
.data
= coss_node
;
361 dlinkAdd(e
, &coss_node
->node
, &sd
->cossindex
);
366 storeCossRebuildComplete(void *data
)
368 RebuildState
*rb
= (RebuildState
*)data
;
369 CossSwapDir
*sd
= rb
->sd
;
371 StoreController::store_dirs_rebuilding
--;
372 storeCossDirCloseTmpSwapLog(rb
->sd
);
373 storeRebuildComplete(&rb
->counts
);
378 storeCossRebuildFromSwapLog(void *data
)
380 RebuildState
*rb
= (RebuildState
*)data
;
381 StoreEntry
*e
= NULL
;
383 size_t ss
= sizeof(StoreSwapLogData
);
386 /* load a number of objects per invocation */
388 for (int aCount
= 0; aCount
< rb
->speed
; aCount
++) {
389 if (fread(&s
, ss
, 1, rb
->log
) != 1) {
390 debugs(47, 1, "Done reading " << rb
->sd
->path
<< " swaplog (" << rb
->n_read
<< " entries)");
393 storeCossRebuildComplete(rb
);
399 if (s
.op
<= SWAP_LOG_NOP
)
402 if (s
.op
>= SWAP_LOG_MAX
)
405 debugs(47, 3, "storeCossRebuildFromSwapLog: " <<
406 swap_log_op_str
[(int) s
.op
] << " " << storeKeyText(s
.key
) <<
407 " "<< std::setfill('0') << std::hex
<< std::uppercase
<<
408 std::setw(8) << s
.swap_filen
);
410 if (s
.op
== SWAP_LOG_ADD
) {
412 } else if (s
.op
== SWAP_LOG_DEL
) {
413 /* Delete unless we already have a newer copy */
416 (s
.key
)) != NULL
&& s
.lastref
> e
->lastref
) {
418 * Make sure we don't unlink the file, it might be
419 * in use by a subsequent entry. Also note that
420 * we don't have to subtract from cur_size because
421 * adding to cur_size happens in the cleanup procedure.
426 if (e
->swap_filen
> -1) {
431 /* Fake an unlink here, this is a bad hack :( */
432 storeCossRemove(rb
->sd
, e
);
433 rb
->counts
.objcount
--;
434 rb
->counts
.cancelcount
++;
438 x
= log(static_cast<double>(++rb
->counts
.bad_log_op
)) / log(10.0);
440 if (0.0 == x
- (double)
442 debugs(47, 1, "WARNING: " << rb
->counts
.bad_log_op
<< " invalid swap log entries found");
444 rb
->counts
.invalid
++;
449 if ((++rb
->counts
.scancount
& 0xFFF) == 0) {
453 if (0 == fstat(fileno(rb
->log
), &sb
))
454 storeRebuildProgress(rb
->sd
->index
,
455 (int) sb
.st_size
/ ss
, rb
->n_read
);
458 if (EBIT_TEST(s
.flags
, KEY_PRIVATE
)) {
459 rb
->counts
.badflags
++;
467 /* key already exists, current entry is newer */
468 /* keep old, ignore new */
469 rb
->counts
.dupcount
++;
473 rb
->counts
.objcount
++;
475 e
= rb
->sd
->addDiskRestore(s
.key
,
484 (int) rb
->flags
.clean
);
486 storeDirSwapLog(e
, SWAP_LOG_ADD
);
489 eventAdd("storeCossRebuild", storeCossRebuildFromSwapLog
, rb
, 0.0, 1);
492 /* Add a new object to the cache with empty memory copy and pointer to disk
493 * use to rebuild store from disk. */
495 CossSwapDir::addDiskRestore(const cache_key
*const key
,
497 uint64_t swap_file_sz
,
506 StoreEntry
*e
= NULL
;
507 debugs(47, 5, "storeCossAddDiskRestore: " << storeKeyText(key
) <<
508 ", fileno="<< std::setfill('0') << std::hex
<< std::uppercase
<<
509 std::setw(8) << file_number
);
511 /* if you call this you'd better be sure file_number is not
513 e
= new StoreEntry();
514 e
->store_status
= STORE_OK
;
515 e
->swap_dirn
= index
;
516 e
->setMemStatus(NOT_IN_MEMORY
);
517 e
->swap_status
= SWAPOUT_DONE
;
518 e
->swap_filen
= file_number
;
519 e
->swap_file_sz
= swap_file_sz
;
521 e
->lastref
= lastref
;
522 e
->timestamp
= timestamp
;
523 e
->expires
= expires
;
524 e
->lastmod
= lastmod
;
525 e
->refcount
= refcount
;
527 EBIT_SET(e
->flags
, ENTRY_CACHABLE
);
528 EBIT_CLR(e
->flags
, RELEASE_REQUEST
);
529 EBIT_CLR(e
->flags
, KEY_PRIVATE
);
530 e
->ping_status
= PING_NONE
;
531 EBIT_CLR(e
->flags
, ENTRY_VALIDATED
);
532 cur_size
+= fs
.blksize
* sizeInBlocks(e
->swap_file_sz
);
534 e
->hashInsert(key
); /* do it after we clear KEY_PRIVATE */
535 storeCossAdd(this, e
);
536 assert(e
->swap_filen
>= 0);
540 CBDATA_TYPE(RebuildState
);
542 storeCossDirRebuild(CossSwapDir
* sd
)
548 CBDATA_INIT_TYPE(RebuildState
);
549 rb
= cbdataAlloc(RebuildState
);
551 rb
->speed
= opt_foreground_rebuild
? 1 << 30 : 50;
552 rb
->flags
.clean
= (unsigned int) clean
;
554 * If the swap.state file exists in the cache_dir, then
555 * we'll use storeCossRebuildFromSwapLog().
557 fp
= storeCossDirOpenTmpSwapLog(sd
, &clean
, &zero
);
558 debugs(47, 1, "Rebuilding COSS storage in " << sd
->path
<< " (" << (clean
? "CLEAN" : "DIRTY") << ")");
560 StoreController::store_dirs_rebuilding
++;
562 if (!clean
|| fp
== NULL
) {
563 /* COSS cannot yet rebuild from a dirty state. If the log
564 * is dirty then the COSS contents is thrown away.
565 * Why? I guess it is because some contents will be lost,
566 * and COSS cannot verify this..
573 * XXX Make sure we don't trigger an assertion if this is the first
574 * storedir, since if we are, this call will cause storeRebuildComplete
575 * to prematurely complete the rebuild process, and then some other
576 * storedir will try to rebuild and eventually die.
578 eventAdd("storeCossRebuildComplete", storeCossRebuildComplete
, rb
, 0.0, 0);
583 eventAdd("storeCossRebuild", storeCossRebuildFromSwapLog
, rb
, 0.0, 1);
587 storeCossDirCloseTmpSwapLog(CossSwapDir
* sd
)
589 char *swaplog_path
= xstrdup(storeCossDirSwapLogFile(sd
, NULL
));
590 char *new_path
= xstrdup(storeCossDirSwapLogFile(sd
, ".new"));
592 file_close(sd
->swaplog_fd
);
594 if (xrename(new_path
, swaplog_path
) < 0) {
595 fatal("storeCossDirCloseTmpSwapLog: rename failed");
598 anfd
= file_open(swaplog_path
, O_WRONLY
| O_CREAT
| O_BINARY
);
601 debugs(50, 1, "" << swaplog_path
<< ": " << xstrerror());
602 fatal("storeCossDirCloseTmpSwapLog: Failed to open swap log.");
605 safe_free(swaplog_path
);
607 sd
->swaplog_fd
= anfd
;
608 debugs(47, 3, "Cache COSS Dir #" << sd
->index
<< " log opened on FD " << anfd
);
612 storeCossDirOpenTmpSwapLog(CossSwapDir
* sd
, int *clean_flag
, int *zero_flag
)
614 char *swaplog_path
= xstrdup(storeCossDirSwapLogFile(sd
, NULL
));
615 char *clean_path
= xstrdup(storeCossDirSwapLogFile(sd
, ".last-clean"));
616 char *new_path
= xstrdup(storeCossDirSwapLogFile(sd
, ".new"));
620 struct stat clean_sb
;
624 if (::stat(swaplog_path
, &log_sb
) < 0) {
625 debugs(50, 1, "Cache COSS Dir #" << sd
->index
<< ": No log file");
626 safe_free(swaplog_path
);
627 safe_free(clean_path
);
632 *zero_flag
= log_sb
.st_size
== 0 ? 1 : 0;
633 /* close the existing write-only FD */
635 if (sd
->swaplog_fd
>= 0)
636 file_close(sd
->swaplog_fd
);
638 /* open a write-only FD for the new log */
639 anfd
= file_open(new_path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
);
642 debugs(50, 1, "" << new_path
<< ": " << xstrerror());
643 fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
646 sd
->swaplog_fd
= anfd
;
647 /* open a read-only stream of the old log */
648 fp
= fopen(swaplog_path
, "rb");
651 debugs(50, 0, "" << swaplog_path
<< ": " << xstrerror());
652 fatal("Failed to open swap log for reading");
655 memset(&clean_sb
, '\0', sizeof(struct stat
));
657 if (::stat(clean_path
, &clean_sb
) < 0)
659 else if (clean_sb
.st_mtime
< log_sb
.st_mtime
)
664 safeunlink(clean_path
, 1);
666 safe_free(swaplog_path
);
668 safe_free(clean_path
);
675 class CossCleanLog
: public SwapDir::CleanLog
679 CossCleanLog(CossSwapDir
*);
680 virtual const StoreEntry
*nextEntry();
681 virtual void write(StoreEntry
const &);
692 #define CLEAN_BUF_SZ 16384
694 CossCleanLog::CossCleanLog(CossSwapDir
*aSwapDir
) : cur(NULL
),newLog(NULL
),cln(NULL
),outbuf(NULL
),
695 outbuf_offset(0), fd(-1),current(NULL
), sd(aSwapDir
)
699 * Begin the process to write clean cache state. For COSS this means
700 * opening some log files and allocating write buffers. Return 0 if
701 * we succeed, and assign the 'func' and 'data' return pointers.
704 CossSwapDir::writeCleanStart()
706 CossCleanLog
*state
= new CossCleanLog(this);
712 state
->newLog
= xstrdup(storeCossDirSwapLogFile(this, ".clean"));
713 state
->fd
= file_open(state
->newLog
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
);
717 xfree(state
->newLog
);
722 state
->cur
= xstrdup(storeCossDirSwapLogFile(this, NULL
));
723 state
->cln
= xstrdup(storeCossDirSwapLogFile(this, ".last-clean"));
724 state
->outbuf
= (char *)xcalloc(CLEAN_BUF_SZ
, 1);
725 state
->outbuf_offset
= 0;
726 ::unlink(state
->cln
);
727 state
->current
= cossindex
.tail
;
728 debugs(50, 3, "storeCOssDirWriteCleanLogs: opened " << state
->newLog
<< ", FD " << state
->fd
);
731 if (::stat(state
->cur
, &sb
) == 0)
732 fchmod(state
->fd
, sb
.st_mode
);
741 /* RBC 20050101 - I think there is a race condition here,
742 * *current can be freed as its not ref counted, if/when
743 * the store overruns the log writer
746 CossCleanLog::nextEntry()
748 const StoreEntry
*entry
;
753 entry
= (const StoreEntry
*) current
->data
;
755 current
= current
->prev
;
761 * "write" an entry to the clean log file.
764 CossCleanLog::write(StoreEntry
const &e
)
766 CossCleanLog
*state
= this;
768 static size_t ss
= sizeof(StoreSwapLogData
);
769 s
.op
= (char) SWAP_LOG_ADD
;
770 s
.swap_filen
= e
.swap_filen
;
771 s
.timestamp
= e
.timestamp
;
772 s
.lastref
= e
.lastref
;
773 s
.expires
= e
.expires
;
774 s
.lastmod
= e
.lastmod
;
775 s
.swap_file_sz
= e
.swap_file_sz
;
776 s
.refcount
= e
.refcount
;
778 memcpy(&s
.key
, e
.key
, SQUID_MD5_DIGEST_LENGTH
);
779 memcpy(outbuf
+ outbuf_offset
, &s
, ss
);
783 if (outbuf_offset
+ ss
> CLEAN_BUF_SZ
) {
784 if (FD_WRITE_METHOD(fd
, outbuf
, outbuf_offset
) < 0) {
785 debugs(50, 0, "storeCossDirWriteCleanLogs: " << newLog
<< ": write: " << xstrerror());
786 debugs(50, 0, "storeCossDirWriteCleanLogs: Current swap logfile not replaced.");
800 CossSwapDir::writeCleanDone()
802 CossCleanLog
*state
= (CossCleanLog
*)cleanLog
;
810 if (FD_WRITE_METHOD(state
->fd
, state
->outbuf
, state
->outbuf_offset
) < 0) {
811 debugs(50, 0, "storeCossDirWriteCleanLogs: " << state
->newLog
<< ": write: " << xstrerror());
812 debugs(50, 0, "storeCossDirWriteCleanLogs: Current swap logfile not replaced.");
813 file_close(state
->fd
);
815 ::unlink(state
->newLog
);
818 safe_free(state
->outbuf
);
820 * You can't rename open files on Microsoft "operating systems"
821 * so we have to close before renaming.
824 /* save the fd value for a later test */
825 int anfd
= state
->fd
;
828 if (state
->fd
>= 0) {
829 #if _SQUID_OS2_ || _SQUID_WINDOWS_
830 file_close(state
->fd
);
834 xrename(state
->newLog
, state
->cur
);
837 /* touch a timestamp file if we're not still validating */
838 if (StoreController::store_dirs_rebuilding
)
843 file_close(file_open(state
->cln
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
));
846 safe_free(state
->cur
);
848 safe_free(state
->newLog
);
850 safe_free(state
->cln
);
853 file_close(state
->fd
);
863 FreeObject(void *address
)
865 StoreSwapLogData
*anObject
= static_cast <StoreSwapLogData
*>(address
);
870 CossSwapDir::logEntry(const StoreEntry
& e
, int op
) const
872 StoreSwapLogData
*s
= new StoreSwapLogData
;
874 s
->swap_filen
= e
.swap_filen
;
875 s
->timestamp
= e
.timestamp
;
876 s
->lastref
= e
.lastref
;
877 s
->expires
= e
.expires
;
878 s
->lastmod
= e
.lastmod
;
879 s
->swap_file_sz
= e
.swap_file_sz
;
880 s
->refcount
= e
.refcount
;
882 memcpy(s
->key
, e
.key
, SQUID_MD5_DIGEST_LENGTH
);
883 file_write(swaplog_fd
,
886 sizeof(StoreSwapLogData
),
893 CossSwapDir::create()
895 debugs (47, 3, "Creating swap space in " << path
);
900 if (::stat(path
, &swap_sb
) < 0) {
901 debugs (47, 2, "COSS swap space space being allocated.");
912 /* should check here for directories instead of files, and for file size
913 * TODO - if nothing changes, there is nothing to do
915 swap
= open(stripePath(), O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, 0600);
917 /* TODO just set the file size */
919 Must(maxSize() % sizeof(block
) == 0);
920 memset(block
, '\0', sizeof(block
));
922 for (uint64_t offset
= 0; offset
< maxSize(); offset
+= sizeof(block
)) {
923 if (write (swap
, block
, sizeof(block
)) != sizeof(block
)) {
924 debugs (47, 0, "Failed to create COSS swap space in " << path
);
932 /* we are shutting down, flush all membufs to disk */
933 CossSwapDir::~CossSwapDir()
948 safe_free(stripe_path
);
952 CossSwapDir::canStore(const StoreEntry
&e
, int64_t diskSpaceNeeded
, int &load
) const
954 if (!SwapDir::canStore(e
, diskSpaceNeeded
, load
))
962 * storeCossDirCallback - do the IO completions
965 CossSwapDir::callback()
967 return io
->callback();
970 /* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */
973 CossSwapDir::statfs(StoreEntry
& sentry
) const
975 storeAppendPrintf(&sentry
, "\n");
976 storeAppendPrintf(&sentry
, "Maximum Size: %"PRIu64
" KB\n", maxSize() >> 10);
977 storeAppendPrintf(&sentry
, "Current Size: %.2f KB\n", currentSize() / 1024.0);
978 storeAppendPrintf(&sentry
, "Percent Used: %0.2f%%\n",
979 Math::doublePercent(currentSize(), maxSize()) );
980 storeAppendPrintf(&sentry
, "Number of object collisions: %d\n", (int) numcollisions
);
982 /* is this applicable? I Hope not .. */
983 storeAppendPrintf(sentry
, "Filemap bits in use: %d of %d (%d%%)\n",
984 SD
->map
->numFilesInMap(), SD
->map
->capacity(),
985 Math::intPercent(SD
->map
->numFilesInMap(), SD
->map
->capacity()));
988 // storeAppendPrintf(&sentry, "Pending operations: %d out of %d\n", io->aq.aq_numpending, MAX_ASYNCOP);
989 storeAppendPrintf(&sentry
, "Flags:");
992 storeAppendPrintf(&sentry
, " SELECTED");
995 storeAppendPrintf(&sentry
, " READ-ONLY");
997 storeAppendPrintf(&sentry
, "\n");
1001 CossSwapDir::parse(int anIndex
, char *aPath
)
1003 const int i
= GetInteger();
1005 fatal("storeCossDirParse: invalid size value");
1009 path
= xstrdup(aPath
);
1011 max_size
= static_cast<uint64_t>(i
) << 20; // MBytes to Bytes
1016 changeIO(DiskIOModule::FindDefault());
1018 /* Enforce maxobjsize being set to something */
1019 if (max_objsize
== -1)
1020 fatal("COSS requires max-size to be set to something other than -1!\n");
1022 if (max_objsize
> COSS_MEMBUF_SZ
)
1023 fatalf("COSS max-size option must be less than COSS_MEMBUF_SZ (%d)\n",
1026 // check that we won't overflow sfileno later.
1027 const uint64_t max_offset
= (uint64_t)SwapFilenMax
<< blksz_bits
;
1029 if (maxSize() > max_offset
) {
1030 debugs(47, 0, "COSS block-size = " << (1<<blksz_bits
) << " bytes");
1031 debugs(47,0, "COSS largest file offset = " << (max_offset
>> 10) << " KB");
1032 debugs(47, 0, "COSS cache_dir size = " << (maxSize() >> 10) << " KB");
1033 fatal("COSS cache_dir size exceeds largest offset\n");
1039 CossSwapDir::reconfigure()
1041 const int i
= GetInteger();
1043 fatal("storeCossDirParse: invalid size value");
1045 const uint64_t size
= static_cast<uint64_t>(i
) << 20; // MBytes to Bytes
1047 if (size
== maxSize())
1048 debugs(3, 1, "Cache COSS dir '" << path
<< "' size remains unchanged at " << i
<< " MB");
1050 debugs(3, 1, "Cache COSS dir '" << path
<< "' size changed to " << i
<< " MB");
1054 /* Enforce maxobjsize being set to something */
1055 if (max_objsize
== -1)
1056 fatal("COSS requires max-size to be set to something other than -1!\n");
1060 CossSwapDir::swappedOut(const StoreEntry
&e
)
1062 cur_size
+= fs
.blksize
* sizeInBlocks(e
.swap_file_sz
);
1067 CossSwapDir::dump(StoreEntry
&entry
)const
1069 storeAppendPrintf(&entry
, " %"PRIu64
, maxSize() >> 20);
1070 dumpOptions(&entry
);
1073 CossSwapDir::CossSwapDir() : SwapDir ("coss"), swaplog_fd(-1), count(0), current_membuf (NULL
), current_offset(0), numcollisions(0), blksz_bits(0), io (NULL
), ioModule(NULL
), currentIOOptions(new ConfigOptionVector()), stripe_path(NULL
), cur_size(0), n_disk_objects(0)
1075 membufs
.head
= NULL
;
1076 membufs
.tail
= NULL
;
1077 cossindex
.head
= NULL
;
1078 cossindex
.tail
= NULL
;
1079 blksz_mask
= (1 << blksz_bits
) - 1;
1084 CossSwapDir::optionBlockSizeParse(const char *option
, const char *value
, int reconfiguring
)
1088 if (strcmp(option
, "block-size") != 0)
1094 int blksz
= atoi(value
);
1096 if (blksz
== (1 << blksz_bits
))
1100 if (reconfiguring
) {
1101 debugs(47, 0, "WARNING: cannot change COSS block-size while Squid is running");
1116 fatal("COSS block-size must be a power of 2\n");
1119 fatal("COSS block-size must be 8192 or smaller\n");
1123 blksz_mask
= (1 << blksz_bits
) - 1;
1129 CossSwapDir::optionBlockSizeDump(StoreEntry
* e
) const
1131 storeAppendPrintf(e
, " block-size=%d", 1 << blksz_bits
);
1135 CossSwapDir::search(String
const url
, HttpRequest
*)
1138 fatal ("Cannot search by url yet\n");
1140 return new StoreSearchCoss (this);
1144 CossSwapDir::stripePath() const
1147 String result
= path
;
1148 result
.append("/stripe");
1149 const_cast<CossSwapDir
*>(this)->stripe_path
= xstrdup(result
.termedBuf());
1155 CBDATA_CLASS_INIT(StoreSearchCoss
);
1156 StoreSearchCoss::StoreSearchCoss(RefCount
<CossSwapDir
> aSwapDir
) : sd(aSwapDir
), callback (NULL
), cbdata(NULL
), _done (false), current(NULL
), next_(sd
->cossindex
.tail
)
1158 /* TODO: this races with the store as does the cleanlog stuff.
1159 * FIXME by making coss_nodes ref counted */
1163 StoreSearchCoss::StoreSearchCoss(StoreSearchCoss const &);
1166 StoreSearchCoss::~StoreSearchCoss()
1170 StoreSearchCoss::next(void (callback
)(void *cbdata
), void *cbdata
)
1177 StoreSearchCoss::next()
1182 next_
= next_
->prev
;
1187 return current
!= NULL
;
1191 StoreSearchCoss::error() const
1197 StoreSearchCoss::isDone() const
1203 StoreSearchCoss::currentItem()
1208 return static_cast<StoreEntry
*>( current
->data
);