[prev in list] [next in list] [prev in thread] [next in thread]
List: squid-dev
Subject: [PATCH] Refactor ufscommon into individual include/code files
From: Kinkie <gkinkie () gmail ! com>
Date: 2012-07-31 22:20:29
Message-ID: CA+Y8hcOK_ZOX0gbWOpBEhZLLXjgQXSnBTGP_0YTUCE0pVcuShg () mail ! gmail ! com
[Download RAW message or body]
Hi all,
the attached patch splits ufscommon.h and .cc into specific-purpose
files, as per squid standard, and reconnects the dots.
There are no functional changes, but it removes a few FIXMEs in the
code. Test-suite-tested.
I'm not sure if this is the right time to merge, or if it's better to
wait after 3.2 ships, but here goes.
--
/kinkie
["ufscommon-refactor-v1.patch" (application/octet-stream)]
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: kinkie@squid-cache.org-20120731221707-c3qlkezbeu90q9qg
# target_branch: ../trunk
# testament_sha1: 9113122de7e30c9adcf59a57ff518dec8525b0ca
# timestamp: 2012-08-01 00:17:11 +0200
# base_revision_id: kinkie@squid-cache.org-20120724085954-\
# lfixpilhl2g8k5ev
#
# Begin patch
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2012-07-18 16:21:47 +0000
+++ src/Makefile.am 2012-07-25 20:56:12 +0000
@@ -15,7 +15,7 @@
DNSSOURCE = dns_internal.cc
DNSHELPER =
endif
-
+
DNSSOURCE += \
SquidDns.h \
DnsLookupDetails.h \
=== modified file 'src/fs/Makefile.am'
--- src/fs/Makefile.am 2011-09-10 16:38:36 +0000
+++ src/fs/Makefile.am 2012-07-31 21:49:03 +0000
@@ -24,9 +24,17 @@
ufs/StoreFSufs.cc \
ufs/store_dir_ufs.cc \
ufs/store_io_ufs.cc \
- ufs/ufscommon.cci \
- ufs/ufscommon.cc \
- ufs/ufscommon.h
+ ufs/UFSSwapDir.cc \
+ ufs/UFSSwapDir.h \
+ ufs/UFSStrategy.cc \
+ ufs/UFSStrategy.h \
+ ufs/UFSStoreState.h \
+ ufs/StoreSearchUFS.h \
+ ufs/StoreSearchUFS.cc \
+ ufs/UFSSwapLogParser.h \
+ ufs/UFSSwapLogParser.cc \
+ ufs/RebuildState.h \
+ ufs/RebuildState.cc
librock_la_SOURCES = \
rock/RockDbCell.h \
=== modified file 'src/fs/Module.cc'
--- src/fs/Module.cc 2012-01-20 18:55:04 +0000
+++ src/fs/Module.cc 2012-07-31 21:45:27 +0000
@@ -2,7 +2,7 @@
#include "Module.h"
#if defined(HAVE_FS_UFS) || defined(HAVE_FS_AUFS) || defined(HAVE_FS_DISKD)
#include "fs/ufs/StoreFSufs.h"
-#include "fs/ufs/ufscommon.h"
+#include "fs/ufs/UFSSwapDir.h"
#endif
#if HAVE_FS_COSS
=== modified file 'src/fs/aufs/StoreFSaufs.cc'
--- src/fs/aufs/StoreFSaufs.cc 2012-01-20 18:55:04 +0000
+++ src/fs/aufs/StoreFSaufs.cc 2012-07-31 21:45:27 +0000
@@ -45,8 +45,7 @@
#include "fs/ufs/StoreFSufs.h"
-/** \todo FIXME: break UFSSwapDir out so we don't need all the guff */
-#include "fs/ufs/ufscommon.h"
+#include "fs/ufs/UFSSwapDir.h"
/**
\defgroup AUFS AUFS Storage Filesystem (UFS Based)
=== modified file 'src/fs/diskd/StoreFSdiskd.cc'
--- src/fs/diskd/StoreFSdiskd.cc 2012-01-20 18:55:04 +0000
+++ src/fs/diskd/StoreFSdiskd.cc 2012-07-25 20:56:12 +0000
@@ -42,9 +42,7 @@
#endif
#include "fs/ufs/StoreFSufs.h"
-
-/** \todo FIXME: break UFSSwapDir out so we don;t need all the extras */
-#include "fs/ufs/ufscommon.h"
+#include "fs/ufs/UFSSwapDir.h"
/**
\defgroup diskd diskd Storage Filesystem (UFS Based)
=== added file 'src/fs/ufs/RebuildState.cc'
--- src/fs/ufs/RebuildState.cc 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/RebuildState.cc 2012-07-31 21:03:40 +0000
@@ -0,0 +1,540 @@
+/*
+ * RebuildState.cc
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+#include "RebuildState.h"
+#include "SquidTime.h"
+#include "StoreSwapLogData.h"
+#include "UFSSwapLogParser.h"
+
+CBDATA_CLASS_INIT(RebuildState);
+
+
+RebuildState::RebuildState (RefCount<UFSSwapDir> aSwapDir) : sd \
(aSwapDir),LogParser(NULL), e(NULL), fromLog(true), _done (false) +{
+ /*
+ * If the swap.state file exists in the cache_dir, then
+ * we'll use commonUfsDirRebuildFromSwapLog(), otherwise we'll
+ * use commonUfsDirRebuildFromDirectory() to open up each file
+ * and suck in the meta data.
+ */
+ int clean = 0;
+ int zeroLengthLog = 0;
+ FILE *fp = sd->openTmpSwapLog(&clean, &zeroLengthLog);
+
+ if (fp && !zeroLengthLog)
+ LogParser = UFSSwapLogParser::GetUFSSwapLogParser(fp);
+
+ if (LogParser == NULL ) {
+ fromLog = false;
+
+ if (fp != NULL)
+ fclose(fp);
+
+ } else {
+ fromLog = true;
+ flags.clean = (unsigned int) clean;
+ }
+
+ if (!clean)
+ flags.need_to_validate = 1;
+
+ debugs(47, DBG_IMPORTANT, "Rebuilding storage in " << sd->path << " (" <<
+ (clean ? "clean log" : (LogParser ? "dirty log" : "no log")) << ")");
+}
+
+RebuildState::~RebuildState()
+{
+ sd->closeTmpSwapLog();
+
+ if (LogParser)
+ delete LogParser;
+}
+
+void
+RebuildState::RebuildStep(void *data)
+{
+ RebuildState *rb = (RebuildState *)data;
+ rb->rebuildStep();
+
+ if (!rb->isDone())
+ eventAdd("storeRebuild", RebuildStep, rb, 0.01, 1);
+ else {
+ -- StoreController::store_dirs_rebuilding;
+ storeRebuildComplete(&rb->counts);
+ delete rb;
+ }
+}
+
+/// load entries from swap.state or files until we run out of entries or time
+void
+RebuildState::rebuildStep()
+{
+ currentEntry(NULL);
+
+ // Balance our desire to maximize the number of entries processed at once
+ // (and, hence, minimize overheads and total rebuild time) with a
+ // requirement to also process Coordinator events, disk I/Os, etc.
+ const int maxSpentMsec = 50; // keep small: most RAM I/Os are under 1ms
+ const timeval loopStart = current_time;
+
+ const int totalEntries = LogParser ? LogParser->SwapLogEntries() : -1;
+
+ while (!isDone()) {
+ if (fromLog)
+ rebuildFromSwapLog();
+ else
+ rebuildFromDirectory();
+
+ // TODO: teach storeRebuildProgress to handle totalEntries <= 0
+ if (totalEntries > 0 && (n_read % 4000 == 0))
+ storeRebuildProgress(sd->index, totalEntries, n_read);
+
+ if (opt_foreground_rebuild)
+ continue; // skip "few entries at a time" check below
+
+ getCurrentTime();
+ const double elapsedMsec = tvSubMsec(loopStart, current_time);
+ if (elapsedMsec > maxSpentMsec || elapsedMsec < 0) {
+ debugs(47, 5, HERE << "pausing after " << n_read << " entries in " <<
+ elapsedMsec << "ms; " << (elapsedMsec/n_read) << "ms per entry");
+ break;
+ }
+ }
+}
+
+/// process one cache file
+void
+RebuildState::rebuildFromDirectory()
+{
+ cache_key key[SQUID_MD5_DIGEST_LENGTH];
+
+ struct stat sb;
+ int fd = -1;
+ assert(this != NULL);
+ debugs(47, 3, "commonUfsDirRebuildFromDirectory: DIR #" << sd->index);
+
+ assert(fd == -1);
+ sfileno filn = 0;
+ int size;
+ fd = getNextFile(&filn, &size);
+
+ if (fd == -2) {
+ debugs(47, DBG_IMPORTANT, "Done scanning " << sd->path << " dir (" <<
+ n_read << " entries)");
+ _done = true;
+ return;
+ } else if (fd < 0) {
+ return;
+ }
+
+ assert(fd > -1);
+ /* lets get file stats here */
+
+ ++n_read;
+
+ if (fstat(fd, &sb) < 0) {
+ debugs(47, 1, "commonUfsDirRebuildFromDirectory: fstat(FD " << fd << "): " \
<< xstrerror()); + file_close(fd);
+ --store_open_disk_fd;
+ fd = -1;
+ return;
+ }
+
+ MemBuf buf;
+ buf.init(SM_PAGE_SIZE, SM_PAGE_SIZE);
+ if (!storeRebuildLoadEntry(fd, sd->index, buf, counts))
+ return;
+
+ StoreEntry tmpe;
+ const bool loaded = storeRebuildParseEntry(buf, tmpe, key, counts,
+ (int64_t)sb.st_size);
+
+ file_close(fd);
+ --store_open_disk_fd;
+ fd = -1;
+
+ if (!loaded) {
+ // XXX: shouldn't this be a call to commonUfsUnlink?
+ sd->unlinkFile(filn); // should we unlink in all failure cases?
+ return;
+ }
+
+ if (!storeRebuildKeepEntry(tmpe, key, counts))
+ return;
+
+ ++counts.objcount;
+ // tmpe.dump(5);
+ currentEntry(sd->addDiskRestore(key,
+ filn,
+ tmpe.swap_file_sz,
+ tmpe.expires,
+ tmpe.timestamp,
+ tmpe.lastref,
+ tmpe.lastmod,
+ tmpe.refcount, /* refcount */
+ tmpe.flags, /* flags */
+ (int) flags.clean));
+ storeDirSwapLog(currentEntry(), SWAP_LOG_ADD);
+}
+
+StoreEntry *
+RebuildState::currentEntry() const
+{
+ return e;
+}
+
+void
+RebuildState::currentEntry(StoreEntry *newValue)
+{
+ e = newValue;
+}
+
+/// process one swap log entry
+void
+RebuildState::rebuildFromSwapLog()
+{
+ StoreSwapLogData swapData;
+
+ if (LogParser->ReadRecord(swapData) != 1) {
+ debugs(47, 1, "Done reading " << sd->path << " swaplog (" << n_read << " \
entries)"); + LogParser->Close();
+ delete LogParser;
+ LogParser = NULL;
+ _done = true;
+ return;
+ }
+
+ ++n_read;
+
+ if (!swapData.sane()) {
+ ++counts.invalid;
+ return;
+ }
+
+ /*
+ * BC: during 2.4 development, we changed the way swap file
+ * numbers are assigned and stored. The high 16 bits used
+ * to encode the SD index number. There used to be a call
+ * to storeDirProperFileno here that re-assigned the index
+ * bits. Now, for backwards compatibility, we just need
+ * to mask it off.
+ */
+ swapData.swap_filen &= 0x00FFFFFF;
+
+ debugs(47, 3, "commonUfsDirRebuildFromSwapLog: " <<
+ swap_log_op_str[(int) swapData.op] << " " <<
+ storeKeyText(swapData.key) << " "<< std::setfill('0') <<
+ std::hex << std::uppercase << std::setw(8) <<
+ swapData.swap_filen);
+
+ if (swapData.op == SWAP_LOG_ADD) {
+ (void) 0;
+ } else if (swapData.op == SWAP_LOG_DEL) {
+ /* Delete unless we already have a newer copy anywhere in any store */
+ /* this needs to become
+ * 1) unpack url
+ * 2) make synthetic request with headers ?? or otherwise search
+ * for a matching object in the store
+ * TODO FIXME change to new async api
+ */
+ currentEntry (Store::Root().get(swapData.key));
+
+ if (currentEntry() != NULL && swapData.lastref >= e->lastref) {
+ undoAdd();
+ --counts.objcount;
+ ++counts.cancelcount;
+ }
+ return;
+ } else {
+ const double
+ x = ::log(static_cast<double>(++counts.bad_log_op)) / ::log(10.0);
+
+ if (0.0 == x - (double) (int) x)
+ debugs(47, 1, "WARNING: " << counts.bad_log_op << " invalid swap log \
entries found"); +
+ ++counts.invalid;
+
+ return;
+ }
+
+ ++counts.scancount; // XXX: should not this be incremented earlier?
+
+ if (!sd->validFileno(swapData.swap_filen, 0)) {
+ ++counts.invalid;
+ return;
+ }
+
+ if (EBIT_TEST(swapData.flags, KEY_PRIVATE)) {
+ ++counts.badflags;
+ return;
+ }
+
+ /* this needs to become
+ * 1) unpack url
+ * 2) make synthetic request with headers ?? or otherwise search
+ * for a matching object in the store
+ * TODO FIXME change to new async api
+ */
+ currentEntry (Store::Root().get(swapData.key));
+
+ int used; /* is swapfile already in use? */
+
+ used = sd->mapBitTest(swapData.swap_filen);
+
+ /* If this URL already exists in the cache, does the swap log
+ * appear to have a newer entry? Compare 'lastref' from the
+ * swap log to e->lastref. */
+ /* is the log entry newer than current entry? */
+ int disk_entry_newer = currentEntry() ? (swapData.lastref > \
currentEntry()->lastref ? 1 : 0) : 0; +
+ if (used && !disk_entry_newer) {
+ /* log entry is old, ignore it */
+ ++counts.clashcount;
+ return;
+ } else if (used && currentEntry() && currentEntry()->swap_filen == \
swapData.swap_filen && currentEntry()->swap_dirn == sd->index) { + /* swapfile \
taken, same URL, newer, update meta */ +
+ if (currentEntry()->store_status == STORE_OK) {
+ currentEntry()->lastref = swapData.timestamp;
+ currentEntry()->timestamp = swapData.timestamp;
+ currentEntry()->expires = swapData.expires;
+ currentEntry()->lastmod = swapData.lastmod;
+ currentEntry()->flags = swapData.flags;
+ currentEntry()->refcount += swapData.refcount;
+ sd->dereference(*currentEntry());
+ } else {
+ debug_trap("commonUfsDirRebuildFromSwapLog: bad condition");
+ debugs(47, 1, "\tSee " << __FILE__ << ":" << __LINE__);
+ }
+ return;
+ } else if (used) {
+ /* swapfile in use, not by this URL, log entry is newer */
+ /* This is sorta bad: the log entry should NOT be newer at this
+ * point. If the log is dirty, the filesize check should have
+ * caught this. If the log is clean, there should never be a
+ * newer entry. */
+ debugs(47, 1, "WARNING: newer swaplog entry for dirno " <<
+ sd->index << ", fileno "<< std::setfill('0') << std::hex <<
+ std::uppercase << std::setw(8) << swapData.swap_filen);
+
+ /* I'm tempted to remove the swapfile here just to be safe,
+ * but there is a bad race condition in the NOVM version if
+ * the swapfile has recently been opened for writing, but
+ * not yet opened for reading. Because we can't map
+ * swapfiles back to StoreEntrys, we don't know the state
+ * of the entry using that file. */
+ /* We'll assume the existing entry is valid, probably because
+ * were in a slow rebuild and the the swap file number got taken
+ * and the validation procedure hasn't run. */
+ assert(flags.need_to_validate);
+ ++counts.clashcount;
+ return;
+ } else if (currentEntry() && !disk_entry_newer) {
+ /* key already exists, current entry is newer */
+ /* keep old, ignore new */
+ ++counts.dupcount;
+ return;
+ } else if (currentEntry()) {
+ /* key already exists, this swapfile not being used */
+ /* junk old, load new */
+ undoAdd();
+ --counts.objcount;
+ ++counts.dupcount;
+ } else {
+ /* URL doesnt exist, swapfile not in use */
+ /* load new */
+ (void) 0;
+ }
+
+ ++counts.objcount;
+
+ currentEntry(sd->addDiskRestore(swapData.key,
+ swapData.swap_filen,
+ swapData.swap_file_sz,
+ swapData.expires,
+ swapData.timestamp,
+ swapData.lastref,
+ swapData.lastmod,
+ swapData.refcount,
+ swapData.flags,
+ (int) flags.clean));
+
+ storeDirSwapLog(currentEntry(), SWAP_LOG_ADD);
+}
+
+/// undo the effects of adding an entry in rebuildFromSwapLog()
+void
+RebuildState::undoAdd()
+{
+ StoreEntry *added = currentEntry();
+ assert(added);
+ currentEntry(NULL);
+
+ // TODO: Why bother with these two if we are going to release?!
+ added->expireNow();
+ added->releaseRequest();
+
+ if (added->swap_filen > -1) {
+ UFSSwapDir *sde = dynamic_cast<UFSSwapDir *>(INDEXSD(added->swap_dirn));
+ assert(sde);
+ sde->undoAddDiskRestore(added);
+ }
+
+ added->release();
+}
+
+int
+RebuildState::getNextFile(sfileno * filn_p, int *size)
+{
+ int fd = -1;
+ int dirs_opened = 0;
+ debugs(47, 3, "commonUfsDirGetNextFile: flag=" << flags.init << ", " <<
+ sd->index << ": /"<< std::setfill('0') << std::hex <<
+ std::uppercase << std::setw(2) << curlvl1 << "/" << std::setw(2) <<
+ curlvl2);
+
+ if (done)
+ return -2;
+
+ while (fd < 0 && done == 0) {
+ fd = -1;
+
+ if (0 == flags.init) { /* initialize, open first file */
+ done = 0;
+ curlvl1 = 0;
+ curlvl2 = 0;
+ in_dir = 0;
+ flags.init = 1;
+ assert(Config.cacheSwap.n_configured > 0);
+ }
+
+ if (0 == in_dir) { /* we need to read in a new directory */
+ snprintf(fullpath, MAXPATHLEN, "%s/%02X/%02X",
+ sd->path,
+ curlvl1, curlvl2);
+
+ if (dirs_opened)
+ return -1;
+
+ td = opendir(fullpath);
+
+ ++dirs_opened;
+
+ if (td == NULL) {
+ debugs(47, 1, "commonUfsDirGetNextFile: opendir: " << fullpath << ": \
" << xstrerror()); + } else {
+ entry = readdir(td); /* skip . and .. */
+ entry = readdir(td);
+
+ if (entry == NULL && errno == ENOENT)
+ debugs(47, 1, "commonUfsDirGetNextFile: directory does not \
exist!."); + debugs(47, 3, "commonUfsDirGetNextFile: Directory " << \
fullpath); + }
+ }
+
+ if (td != NULL && (entry = readdir(td)) != NULL) {
+ ++in_dir;
+
+ if (sscanf(entry->d_name, "%x", &fn) != 1) {
+ debugs(47, 3, "commonUfsDirGetNextFile: invalid " << entry->d_name);
+ continue;
+ }
+
+ if (!UFSSwapDir::FilenoBelongsHere(fn, sd->index, curlvl1, curlvl2)) {
+ debugs(47, 3, "commonUfsDirGetNextFile: "<< std::setfill('0') <<
+ std::hex << std::uppercase << std::setw(8) << fn <<
+ " does not belong in " << std::dec << sd->index << "/" <<
+ curlvl1 << "/" << curlvl2);
+
+ continue;
+ }
+
+ if (sd->mapBitTest(fn)) {
+ debugs(47, 3, "commonUfsDirGetNextFile: Locked, continuing with \
next."); + continue;
+ }
+
+ snprintf(fullfilename, MAXPATHLEN, "%s/%s",
+ fullpath, entry->d_name);
+ debugs(47, 3, "commonUfsDirGetNextFile: Opening " << fullfilename);
+ fd = file_open(fullfilename, O_RDONLY | O_BINARY);
+
+ if (fd < 0)
+ debugs(47, 1, "commonUfsDirGetNextFile: " << fullfilename << ": " << \
xstrerror()); + else
+ ++store_open_disk_fd;
+
+ continue;
+ }
+
+ if (td != NULL)
+ closedir(td);
+
+ td = NULL;
+
+ in_dir = 0;
+
+ if (sd->validL2(++curlvl2))
+ continue;
+
+ curlvl2 = 0;
+
+ if (sd->validL1(++curlvl1))
+ continue;
+
+ curlvl1 = 0;
+
+ done = 1;
+ }
+
+ *filn_p = fn;
+ return fd;
+}
+
+bool
+RebuildState::error() const
+{
+ return false;
+}
+
+bool
+RebuildState::isDone() const
+{
+ return _done;
+}
+
+StoreEntry *
+RebuildState::currentItem()
+{
+ return currentEntry();
+}
+
=== added file 'src/fs/ufs/RebuildState.h'
--- src/fs/ufs/RebuildState.h 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/RebuildState.h 2012-07-31 22:15:40 +0000
@@ -0,0 +1,97 @@
+/*
+ * RebuildState.h
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_FS_UFS_REBUILDSTATE_H
+#define SQUID_FS_UFS_REBUILDSTATE_H
+
+class StoreEntry;
+class UFSSwapLogParser;
+
+#include "RefCount.h"
+#include "UFSSwapDir.h"
+#include "structs.h"
+
+/// \ingroup UFS
+class RebuildState : public RefCountable
+{
+
+public:
+ static EVH RebuildStep;
+
+ RebuildState(RefCount<UFSSwapDir> sd);
+ ~RebuildState();
+
+ virtual bool error() const;
+ virtual bool isDone() const;
+ virtual StoreEntry *currentItem();
+
+ RefCount<UFSSwapDir> sd;
+ int n_read;
+ /* FILE *log;*/
+ UFSSwapLogParser *LogParser;
+ int curlvl1;
+ int curlvl2;
+
+ struct {
+ unsigned int need_to_validate:1;
+ unsigned int clean:1;
+ unsigned int init:1;
+ } flags;
+ int in_dir;
+ int done;
+ int fn;
+
+ dirent_t *entry;
+ DIR *td;
+ char fullpath[MAXPATHLEN];
+ char fullfilename[MAXPATHLEN];
+
+ struct _store_rebuild_data counts;
+
+private:
+ CBDATA_CLASS2(RebuildState);
+ void rebuildFromDirectory();
+ void rebuildFromSwapLog();
+ void rebuildStep();
+ void undoAdd();
+ int getNextFile(sfileno *, int *size);
+ StoreEntry *currentEntry() const;
+ void currentEntry(StoreEntry *);
+ StoreEntry *e;
+ bool fromLog;
+ bool _done;
+ /// \bug (callback) should be hidden behind a proper human readable name
+ void (callback)(void *cbdata);
+ void *cbdata;
+};
+
+
+#endif /* SQUID_FS_UFS_REBUILDSTATE_H */
=== modified file 'src/fs/ufs/StoreFSufs.cc'
--- src/fs/ufs/StoreFSufs.cc 2012-01-20 18:55:04 +0000
+++ src/fs/ufs/StoreFSufs.cc 2012-07-31 22:17:07 +0000
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* DEBUG: section 47 Store Directory Routines
* AUTHOR: Robert Collins
*
@@ -41,13 +39,11 @@
#endif
#include "fs/ufs/StoreFSufs.h"
+#include "fs/ufs/UFSSwapDir.h"
#if 0
#include "DiskIO/DiskIOModule.h"
#endif
-/** \todo FIXME: break UFSSwapDir out so we don't build all the extras */
-#include "fs/ufs/ufscommon.h"
-
/* Unused variable: */
StoreFSufs<UFSSwapDir> *UfsInstance_foo = NULL;
=== added file 'src/fs/ufs/StoreSearchUFS.cc'
--- src/fs/ufs/StoreSearchUFS.cc 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/StoreSearchUFS.cc 2012-07-26 17:45:44 +0000
@@ -0,0 +1,92 @@
+/*
+ * StoreSearchUFS.cc
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+
+#include "cbdata.h"
+#include "StoreSearchUFS.h"
+#include "UFSSwapDir.h"
+
+CBDATA_CLASS_INIT(StoreSearchUFS);
+StoreSearchUFS::StoreSearchUFS(RefCount<UFSSwapDir> aSwapDir) : sd(aSwapDir), walker \
(sd->repl->WalkInit(sd->repl)), current (NULL), _done (false) +{}
+
+/* do not link
+StoreSearchUFS::StoreSearchUFS(StoreSearchUFS const &);
+*/
+
+StoreSearchUFS::~StoreSearchUFS()
+{
+ walker->Done(walker);
+ walker = NULL;
+}
+
+void
+StoreSearchUFS::next(void (aCallback)(void *cbdata), void *aCallbackArgs)
+{
+ next();
+ aCallback(aCallbackArgs);
+}
+
+bool
+StoreSearchUFS::next()
+{
+ /* the walker API doesn't make sense. the store entries referred to are already \
readwrite + * from their hash table entries
+ */
+
+ if (walker)
+ current = const_cast<StoreEntry *>(walker->Next(walker));
+
+ if (current == NULL)
+ _done = true;
+
+ return current != NULL;
+}
+
+bool
+StoreSearchUFS::error() const
+{
+ return false;
+}
+
+bool
+StoreSearchUFS::isDone() const
+{
+ return _done;
+}
+
+StoreEntry *
+StoreSearchUFS::currentItem()
+{
+ return current;
+}
+
=== added file 'src/fs/ufs/StoreSearchUFS.h'
--- src/fs/ufs/StoreSearchUFS.h 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/StoreSearchUFS.h 2012-07-31 22:15:40 +0000
@@ -0,0 +1,79 @@
+/*
+ * StoreSearchUFS.h
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_FS_UFS_STORESEARCHUFS_H
+#define SQUID_FS_UFS_STORESEARCHUFS_H
+
+#include "StoreSearch.h"
+#include "UFSSwapDir.h"
+
+/// \ingroup UFS
+class StoreSearchUFS : public StoreSearch
+{
+
+public:
+ StoreSearchUFS(RefCount<UFSSwapDir> sd);
+ StoreSearchUFS(StoreSearchUFS const &);
+ virtual ~StoreSearchUFS();
+
+ /** \todo Iterator API - garh, wrong place */
+ /**
+ * callback the client when a new StoreEntry is available
+ * or an error occurs
+ */
+ virtual void next(void (callback)(void *cbdata), void *cbdata);
+
+ /**
+ \retval true if a new StoreEntry is immediately available
+ \retval false if a new StoreEntry is NOT immediately available
+ */
+ virtual bool next();
+
+ virtual bool error() const;
+ virtual bool isDone() const;
+ virtual StoreEntry *currentItem();
+
+ RefCount<UFSSwapDir> sd;
+ RemovalPolicyWalker *walker;
+
+private:
+ CBDATA_CLASS2(StoreSearchUFS);
+ /// \bug (callback) should be hidden behind a proper human readable name
+ void (callback)(void *cbdata);
+ void *cbdata;
+ StoreEntry * current;
+ bool _done;
+};
+
+
+
+
+#endif /* SQUID_FS_UFS_STORESEARCHUFS_H */
=== added file 'src/fs/ufs/UFSStoreState.h'
--- src/fs/ufs/UFSStoreState.h 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/UFSStoreState.h 2012-07-31 22:15:40 +0000
@@ -0,0 +1,129 @@
+/*
+ * UFSStoreState.h
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_FS_UFS_UFSSTORESTATE_H
+#define SQUID_FS_UFS_UFSSTORESTATE_H
+
+#include "DiskIO/IORequestor.h"
+#include "StoreIOState.h"
+
+/// \ingroup UFS
+class UFSStoreState : public StoreIOState, public IORequestor
+{
+
+public:
+ void * operator new (size_t);
+ void operator delete (void *);
+ UFSStoreState(SwapDir * SD, StoreEntry * anEntry, STIOCB * callback_, void \
*callback_data_); + ~UFSStoreState();
+ virtual void close(int how);
+ virtual void closeCompleted();
+ // protected:
+ virtual void ioCompletedNotification();
+ virtual void readCompleted(const char *buf, int len, int errflag, \
RefCount<ReadRequest>); + virtual void writeCompleted(int errflag, size_t len, \
RefCount<WriteRequest>); + RefCount<DiskFile> theFile;
+ bool opening;
+ bool creating;
+ bool closing;
+ bool reading;
+ bool writing;
+ void read_(char *buf, size_t size, off_t offset, STRCB * callback, void \
*callback_data); + void write(char const *buf, size_t size, off_t offset, FREE * \
free_func); +
+protected:
+ virtual void doCloseCallback (int errflag);
+
+ class _queued_read
+ {
+
+ public:
+ MEMPROXY_CLASS(UFSStoreState::_queued_read);
+ char *buf;
+ size_t size;
+ off_t offset;
+ STRCB *callback;
+ void *callback_data;
+
+ };
+
+ class _queued_write
+ {
+
+ public:
+ MEMPROXY_CLASS(UFSStoreState::_queued_write);
+ char const *buf;
+ size_t size;
+ off_t offset;
+ FREE *free_func;
+
+ };
+
+ /** \todo These should be in the IO strategy */
+
+ struct {
+ /**
+ * DPW 2006-05-24
+ * the write_draining flag is used to avoid recursion inside
+ * the UFSStoreState::drainWriteQueue() method.
+ */
+ bool write_draining;
+ /**
+ * DPW 2006-05-24
+ * The try_closing flag is set by UFSStoreState::tryClosing()
+ * when UFSStoreState wants to close the file, but cannot
+ * because of pending I/Os. If set, UFSStoreState will
+ * try to close again in the I/O callbacks.
+ */
+ bool try_closing;
+ } flags;
+ link_list *pending_reads;
+ link_list *pending_writes;
+ void queueRead(char *, size_t, off_t, STRCB *, void *);
+ void queueWrite(char const *, size_t, off_t, FREE *);
+ bool kickReadQueue();
+ void drainWriteQueue();
+ void tryClosing();
+ char *read_buf;
+
+private:
+ CBDATA_CLASS(UFSStoreState);
+ void openDone();
+ void freePending();
+ void doWrite();
+};
+
+MEMPROXY_CLASS_INLINE(UFSStoreState::_queued_read);
+MEMPROXY_CLASS_INLINE(UFSStoreState::_queued_write);
+
+
+
+#endif /* SQUID_FS_UFS_UFSSTORESTATE_H */
=== added file 'src/fs/ufs/UFSStrategy.cc'
--- src/fs/ufs/UFSStrategy.cc 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/UFSStrategy.cc 2012-07-31 22:17:07 +0000
@@ -0,0 +1,182 @@
+/*
+ * UFSStrategy.cc
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#include "squid.h"
+
+#include "DiskIO/DiskIOStrategy.h"
+#include "UFSStrategy.h"
+#include "UFSStoreState.h"
+#include "UFSSwapDir.h"
+
+
+bool
+UFSStrategy::shedLoad()
+{
+ return io->shedLoad();
+}
+
+int
+UFSStrategy::load()
+{
+ return io->load();
+}
+
+UFSStrategy::UFSStrategy (DiskIOStrategy *anIO) : io(anIO)
+{}
+
+UFSStrategy::~UFSStrategy ()
+{
+ delete io;
+}
+
+StoreIOState::Pointer
+UFSStrategy::createState(SwapDir *SD, StoreEntry *e, StoreIOState::STIOCB * \
aCallback, void *callback_data) const +{
+ return new UFSStoreState (SD, e, aCallback, callback_data);
+}
+
+DiskFile::Pointer
+UFSStrategy::newFile (char const *path)
+{
+ return io->newFile(path);
+}
+
+
+void
+UFSStrategy::unlinkFile(char const *path)
+{
+ io->unlinkFile(path);
+}
+
+StoreIOState::Pointer
+UFSStrategy::open(SwapDir * SD, StoreEntry * e, StoreIOState::STFNCB * \
file_callback, + StoreIOState::STIOCB * aCallback, void \
*callback_data) +{
+ assert (((UFSSwapDir *)SD)->IO == this);
+ debugs(79, 3, "UFSStrategy::open: fileno "<< std::setfill('0') << std::hex << \
std::uppercase << std::setw(8) << e->swap_filen); +
+ /* to consider: make createstate a private UFSStrategy call */
+ StoreIOState::Pointer sio = createState (SD, e, aCallback, callback_data);
+
+ sio->mode |= O_RDONLY;
+
+ UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw());
+
+ assert (state);
+
+ char *path = ((UFSSwapDir *)SD)->fullPath(e->swap_filen, NULL);
+
+ DiskFile::Pointer myFile = newFile (path);
+
+ if (myFile.getRaw() == NULL)
+ return NULL;
+
+ state->theFile = myFile;
+
+ state->opening = true;
+
+ myFile->open (sio->mode, 0644, state);
+
+ if (myFile->error())
+ return NULL;
+
+ return sio;
+}
+
+StoreIOState::Pointer
+UFSStrategy::create(SwapDir * SD, StoreEntry * e, StoreIOState::STFNCB * \
file_callback, + StoreIOState::STIOCB * aCallback, void \
*callback_data) +{
+ assert (((UFSSwapDir *)SD)->IO == this);
+ /* Allocate a number */
+ sfileno filn = ((UFSSwapDir *)SD)->mapBitAllocate();
+ debugs(79, 3, "UFSStrategy::create: fileno "<< std::setfill('0') << std::hex << \
std::uppercase << std::setw(8) << filn); +
+ /* Shouldn't we handle a 'bitmap full' error here? */
+
+ StoreIOState::Pointer sio = createState (SD, e, aCallback, callback_data);
+
+ sio->mode |= O_WRONLY | O_CREAT | O_TRUNC;
+
+ sio->swap_filen = filn;
+
+ UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw());
+
+ assert (state);
+
+ char *path = ((UFSSwapDir *)SD)->fullPath(filn, NULL);
+
+ DiskFile::Pointer myFile = newFile (path);
+
+ if (myFile.getRaw() == NULL) {
+ ((UFSSwapDir *)SD)->mapBitReset (filn);
+ return NULL;
+ }
+
+ state->theFile = myFile;
+
+ state->creating = true;
+
+ myFile->create (state->mode, 0644, state);
+
+ if (myFile->error()) {
+ ((UFSSwapDir *)SD)->mapBitReset (filn);
+ return NULL;
+ }
+
+ /* now insert into the replacement policy */
+ ((UFSSwapDir *)SD)->replacementAdd(e);
+
+ return sio;
+}
+
+int
+UFSStrategy::callback()
+{
+ return io->callback();
+}
+
+void
+UFSStrategy::init()
+{
+ io->init();
+}
+
+void
+UFSStrategy::sync()
+{
+ io->sync();
+}
+
+void
+UFSStrategy::statfs(StoreEntry & sentry)const
+{
+ io->statfs(sentry);
+}
=== added file 'src/fs/ufs/UFSStrategy.h'
--- src/fs/ufs/UFSStrategy.h 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/UFSStrategy.h 2012-07-31 22:15:40 +0000
@@ -0,0 +1,85 @@
+/*
+ * UFSStrategy.h
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_FS_UFS_UFSSTRATEGY_H
+#define SQUID_FS_UFS_UFSSTRATEGY_H
+
+class Swapdir;
+class StoreEntry;
+class DiskIOStrategy;
+
+#include "DiskIO/DiskFile.h"
+#include "StoreIOState.h"
+
+/// \ingroup UFS
+class UFSStrategy
+{
+
+public:
+ UFSStrategy (DiskIOStrategy *);
+ virtual ~UFSStrategy ();
+ /* Not implemented */
+ UFSStrategy (UFSStrategy const &);
+ UFSStrategy &operator=(UFSStrategy const &);
+
+ virtual bool shedLoad();
+
+ virtual int load();
+
+ StoreIOState::Pointer createState(SwapDir *SD, StoreEntry *e, \
StoreIOState::STIOCB * callback, void *callback_data) const; + /* UFS specific */
+ virtual RefCount<DiskFile> newFile (char const *path);
+ StoreIOState::Pointer open(SwapDir *, StoreEntry *, StoreIOState::STFNCB *,
+ StoreIOState::STIOCB *, void *);
+ StoreIOState::Pointer create(SwapDir *, StoreEntry *, StoreIOState::STFNCB *,
+ StoreIOState::STIOCB *, void *);
+
+ virtual void unlinkFile (char const *);
+ virtual void sync();
+
+ virtual int callback();
+
+ /** Init per-instance logic */
+ virtual void init();
+
+ /** cachemgr output on the IO instance stats */
+ virtual void statfs(StoreEntry & sentry)const;
+
+ /** The io strategy in use */
+ DiskIOStrategy *io;
+protected:
+
+ friend class UFSSwapDir;
+};
+
+
+
+#endif /* SQUID_FS_UFS_UFSSTRATEGY_H */
=== added file 'src/fs/ufs/UFSSwapDir.cc'
--- src/fs/ufs/UFSSwapDir.cc 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/UFSSwapDir.cc 2012-07-31 22:17:07 +0000
@@ -0,0 +1,1421 @@
+/*
+ * UFSSwapDir.cc
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#include "squid-old.h"
+
+#define CLEAN_BUF_SZ 16384
+
+#include "ConfigOption.h"
+#include "DiskIO/DiskIOModule.h"
+#include "FileMap.h"
+#include "fde.h"
+#include "Parsing.h"
+#include "protos.h"
+#include "RebuildState.h"
+#include "SquidMath.h"
+#include "DiskIO/DiskIOStrategy.h"
+#include "StoreSearchUFS.h"
+#include "StoreSwapLogData.h"
+#include "SquidTime.h"
+#include "StatCounters.h"
+#include "UFSSwapDir.h"
+
+
+int UFSSwapDir::NumberOfUFSDirs = 0;
+int *UFSSwapDir::UFSDirToGlobalDirMapping = NULL;
+
+class UFSCleanLog : public SwapDir::CleanLog
+{
+
+public:
+ UFSCleanLog(SwapDir *);
+ virtual const StoreEntry *nextEntry();
+ virtual void write(StoreEntry const &);
+ char *cur;
+ char *newLog;
+ char *cln;
+ char *outbuf;
+ off_t outbuf_offset;
+ int fd;
+ RemovalPolicyWalker *walker;
+ SwapDir *sd;
+};
+
+
+UFSCleanLog::UFSCleanLog(SwapDir *aSwapDir) : \
cur(NULL),newLog(NULL),cln(NULL),outbuf(NULL), + outbuf_offset(0), \
fd(-1),walker(NULL), sd(aSwapDir) +{}
+
+
+/*
+ * Get the next entry that is a candidate for clean log writing
+ */
+const StoreEntry *
+UFSCleanLog::nextEntry()
+{
+ const StoreEntry *entry = NULL;
+
+ if (walker)
+ entry = walker->Next(walker);
+
+ return entry;
+}
+
+/*
+ * "write" an entry to the clean log file.
+ */
+void
+UFSCleanLog::write(StoreEntry const &e)
+{
+ StoreSwapLogData s;
+ static size_t ss = sizeof(StoreSwapLogData);
+ s.op = (char) SWAP_LOG_ADD;
+ s.swap_filen = e.swap_filen;
+ s.timestamp = e.timestamp;
+ s.lastref = e.lastref;
+ s.expires = e.expires;
+ s.lastmod = e.lastmod;
+ s.swap_file_sz = e.swap_file_sz;
+ s.refcount = e.refcount;
+ s.flags = e.flags;
+ memcpy(&s.key, e.key, SQUID_MD5_DIGEST_LENGTH);
+ s.finalize();
+ memcpy(outbuf + outbuf_offset, &s, ss);
+ outbuf_offset += ss;
+ /* buffered write */
+
+ if (outbuf_offset + ss >= CLEAN_BUF_SZ) {
+ if (FD_WRITE_METHOD(fd, outbuf, outbuf_offset) < 0) {
+ /* XXX This error handling should probably move up to the caller */
+ debugs(50, 0, "storeDirWriteCleanLogs: " << newLog << ": write: " << \
xstrerror()); + debugs(50, 0, "storeDirWriteCleanLogs: Current swap \
logfile not replaced."); + file_close(fd);
+ fd = -1;
+ unlink(newLog);
+ sd->cleanLog = NULL;
+ delete this;
+ return;
+ }
+
+ outbuf_offset = 0;
+ }
+}
+
+
+
+
+
+/*
+ * storeUfsDirCheckObj
+ *
+ * This routine is called by storeDirSelectSwapDir to see if the given
+ * object is able to be stored on this filesystem. UFS filesystems will
+ * happily store anything as long as the LRU time isn't too small.
+ */
+bool
+UFSSwapDir::canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const
+{
+ if (!SwapDir::canStore(e, diskSpaceNeeded, load))
+ return false;
+
+ if (IO->shedLoad())
+ return false;
+
+ load = IO->load();
+ return true;
+}
+
+static void
+FreeObject(void *address)
+{
+ StoreSwapLogData *anObject = static_cast <StoreSwapLogData *>(address);
+ delete anObject;
+}
+
+static QS rev_int_sort;
+static int
+rev_int_sort(const void *A, const void *B)
+{
+ const int *i1 = (const int *)A;
+ const int *i2 = (const int *)B;
+ return *i2 - *i1;
+}
+
+
+
+/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */
+
+void
+UFSSwapDir::parseSizeL1L2()
+{
+ int i = GetInteger();
+ if (i <= 0)
+ fatal("UFSSwapDir::parseSizeL1L2: invalid size value");
+
+ const uint64_t size = static_cast<uint64_t>(i) << 20; // MBytes to Bytes
+
+ /* just reconfigure it */
+ if (reconfiguring) {
+ if (size == maxSize())
+ debugs(3, 2, "Cache dir '" << path << "' size remains unchanged at " << \
i << " MB"); + else
+ debugs(3, 1, "Cache dir '" << path << "' size changed to " << i << " \
MB"); + }
+
+ max_size = size;
+
+ l1 = GetInteger();
+
+ if (l1 <= 0)
+ fatal("UFSSwapDir::parseSizeL1L2: invalid level 1 directories value");
+
+ l2 = GetInteger();
+
+ if (l2 <= 0)
+ fatal("UFSSwapDir::parseSizeL1L2: invalid level 2 directories value");
+}
+
+/*
+ * storeUfsDirReconfigure
+ *
+ * This routine is called when the given swapdir needs reconfiguring
+ */
+
+void
+UFSSwapDir::reconfigure()
+{
+ parseSizeL1L2();
+ parseOptions(1);
+}
+
+/*
+ * storeUfsDirParse
+ *
+ * Called when a *new* fs is being setup.
+ */
+void
+UFSSwapDir::parse (int anIndex, char *aPath)
+{
+ index = anIndex;
+ path = xstrdup(aPath);
+
+ parseSizeL1L2();
+
+ /* Initialise replacement policy stuff */
+ repl = createRemovalPolicy(Config.replPolicy);
+
+ parseOptions(0);
+}
+
+void
+UFSSwapDir::changeIO(DiskIOModule *module)
+{
+ DiskIOStrategy *anIO = module->createStrategy();
+ safe_free(ioType);
+ ioType = xstrdup(module->type());
+
+ delete IO->io;
+ IO->io = anIO;
+ /* Change the IO Options */
+
+ if (currentIOOptions && currentIOOptions->options.size() > 2)
+ delete currentIOOptions->options.pop_back();
+
+ /* TODO: factor out these 4 lines */
+ ConfigOption *ioOptions = IO->io->getOptionTree();
+
+ if (ioOptions)
+ currentIOOptions->options.push_back(ioOptions);
+}
+
+bool
+UFSSwapDir::optionIOParse(char const *option, const char *value, int isaReconfig)
+{
+ if (strcmp(option, "IOEngine") != 0)
+ return false;
+
+ if (isaReconfig)
+ /* silently ignore this */
+ return true;
+
+ if (!value)
+ self_destruct();
+
+ DiskIOModule *module = DiskIOModule::Find(value);
+
+ if (!module)
+ self_destruct();
+
+ changeIO(module);
+
+ return true;
+}
+
+void
+UFSSwapDir::optionIODump(StoreEntry * e) const
+{
+ storeAppendPrintf(e, " IOEngine=%s", ioType);
+}
+
+ConfigOption *
+UFSSwapDir::getOptionTree() const
+{
+ ConfigOption *parentResult = SwapDir::getOptionTree();
+
+ if (currentIOOptions == NULL)
+ currentIOOptions = new ConfigOptionVector();
+
+ currentIOOptions->options.push_back(parentResult);
+
+ currentIOOptions->options.push_back(new \
ConfigOptionAdapter<UFSSwapDir>(*const_cast<UFSSwapDir *>(this), \
&UFSSwapDir::optionIOParse, &UFSSwapDir::optionIODump)); +
+ if (ConfigOption *ioOptions = IO->io->getOptionTree())
+ currentIOOptions->options.push_back(ioOptions);
+
+ ConfigOption* result = currentIOOptions;
+
+ currentIOOptions = NULL;
+
+ return result;
+}
+
+/*
+ * Initial setup / end destruction
+ */
+void
+UFSSwapDir::init()
+{
+ debugs(47, 3, "Initialising UFS SwapDir engine.");
+ /* Parsing must be finished by now - force to NULL, don't delete */
+ currentIOOptions = NULL;
+ static int started_clean_event = 0;
+ static const char *errmsg =
+ "\tFailed to verify one of the swap directories, Check cache.log\n"
+ "\tfor details. Run 'squid -z' to create swap directories\n"
+ "\tif needed, or if running Squid for the first time.";
+ IO->init();
+
+ if (verifyCacheDirs())
+ fatal(errmsg);
+
+ openLog();
+
+ rebuild();
+
+ if (!started_clean_event) {
+ eventAdd("UFS storeDirClean", CleanEvent, NULL, 15.0, 1);
+ started_clean_event = 1;
+ }
+
+ (void) storeDirGetBlkSize(path, &fs.blksize);
+}
+
+void
+UFSSwapDir::create()
+{
+ debugs(47, 3, "Creating swap space in " << path);
+ createDirectory(path, 0);
+ createSwapSubDirs();
+}
+
+UFSSwapDir::UFSSwapDir(char const *aType, const char *anIOType) : SwapDir(aType), \
IO(NULL), map(new FileMap()), suggest(0), swaplog_fd (-1), currentIOOptions(new \
ConfigOptionVector()), ioType(xstrdup(anIOType)), cur_size(0), n_disk_objects(0) +{
+ /* modulename is only set to disk modules that are built, by configure,
+ * so the Find call should never return NULL here.
+ */
+ IO = new UFSStrategy(DiskIOModule::Find(anIOType)->createStrategy());
+}
+
+UFSSwapDir::~UFSSwapDir()
+{
+ if (swaplog_fd > -1) {
+ file_close(swaplog_fd);
+ swaplog_fd = -1;
+ }
+
+ delete map;
+
+ if (IO)
+ delete IO;
+
+ IO = NULL;
+
+ safe_free(ioType);
+}
+
+void
+UFSSwapDir::dumpEntry(StoreEntry &e) const
+{
+ debugs(47, 0, "UFSSwapDir::dumpEntry: FILENO "<< std::setfill('0') << std::hex \
<< std::uppercase << std::setw(8) << e.swap_filen); + debugs(47, 0, \
"UFSSwapDir::dumpEntry: PATH " << fullPath(e.swap_filen, NULL) ); + e.dump(0);
+}
+
+/*
+ * UFSSwapDir::doubleCheck
+ *
+ * This is called by storeCleanup() if -S was given on the command line.
+ */
+bool
+UFSSwapDir::doubleCheck(StoreEntry & e)
+{
+
+ struct stat sb;
+
+ if (::stat(fullPath(e.swap_filen, NULL), &sb) < 0) {
+ debugs(47, 0, "UFSSwapDir::doubleCheck: MISSING SWAP FILE");
+ dumpEntry(e);
+ return true;
+ }
+
+ if ((off_t)e.swap_file_sz != sb.st_size) {
+ debugs(47, 0, "UFSSwapDir::doubleCheck: SIZE MISMATCH");
+ debugs(47, 0, "UFSSwapDir::doubleCheck: ENTRY SIZE: " << e.swap_file_sz << \
", FILE SIZE: " << sb.st_size); + dumpEntry(e);
+ return true;
+ }
+
+ return false;
+}
+
+void
+UFSSwapDir::statfs(StoreEntry & sentry) const
+{
+ int totl_kb = 0;
+ int free_kb = 0;
+ int totl_in = 0;
+ int free_in = 0;
+ int x;
+ storeAppendPrintf(&sentry, "First level subdirectories: %d\n", l1);
+ storeAppendPrintf(&sentry, "Second level subdirectories: %d\n", l2);
+ storeAppendPrintf(&sentry, "Maximum Size: %" PRIu64 " KB\n", maxSize() >> 10);
+ storeAppendPrintf(&sentry, "Current Size: %.2f KB\n", currentSize() / 1024.0);
+ storeAppendPrintf(&sentry, "Percent Used: %0.2f%%\n",
+ Math::doublePercent(currentSize(), maxSize()));
+ storeAppendPrintf(&sentry, "Filemap bits in use: %d of %d (%d%%)\n",
+ map->numFilesInMap(), map->capacity(),
+ Math::intPercent(map->numFilesInMap(), map->capacity()));
+ x = storeDirGetUFSStats(path, &totl_kb, &free_kb, &totl_in, &free_in);
+
+ if (0 == x) {
+ storeAppendPrintf(&sentry, "Filesystem Space in use: %d/%d KB (%d%%)\n",
+ totl_kb - free_kb,
+ totl_kb,
+ Math::intPercent(totl_kb - free_kb, totl_kb));
+ storeAppendPrintf(&sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n",
+ totl_in - free_in,
+ totl_in,
+ Math::intPercent(totl_in - free_in, totl_in));
+ }
+
+ storeAppendPrintf(&sentry, "Flags:");
+
+ if (flags.selected)
+ storeAppendPrintf(&sentry, " SELECTED");
+
+ if (flags.read_only)
+ storeAppendPrintf(&sentry, " READ-ONLY");
+
+ storeAppendPrintf(&sentry, "\n");
+
+ IO->statfs(sentry);
+}
+
+void
+UFSSwapDir::maintain()
+{
+ /* We can't delete objects while rebuilding swap */
+
+ /* XXX FIXME each store should start maintaining as it comes online. */
+
+ if (StoreController::store_dirs_rebuilding)
+ return;
+
+ StoreEntry *e = NULL;
+
+ int removed = 0;
+
+ RemovalPurgeWalker *walker;
+
+ double f = (double) (currentSize() - minSize()) / (maxSize() - minSize());
+
+ f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f;
+
+ int max_scan = (int) (f * 400.0 + 100.0);
+
+ int max_remove = (int) (f * 70.0 + 10.0);
+
+ /*
+ * This is kinda cheap, but so we need this priority hack?
+ */
+
+ debugs(47, 3, "storeMaintainSwapSpace: f=" << f << ", max_scan=" << max_scan << \
", max_remove=" << max_remove ); +
+ walker = repl->PurgeInit(repl, max_scan);
+
+ while (1) {
+ if (currentSize() < minSize())
+ break;
+
+ if (removed >= max_remove)
+ break;
+
+ e = walker->Next(walker);
+
+ if (!e)
+ break; /* no more objects */
+
+ ++removed;
+
+ e->release();
+ }
+
+ walker->Done(walker);
+ debugs(47, (removed ? 2 : 3), "UFSSwapDir::maintain: " << path <<
+ " removed " << removed << "/" << max_remove << " f=" <<
+ std::setprecision(4) << f << " max_scan=" << max_scan);
+}
+
+/*
+ * UFSSwapDir::reference
+ *
+ * This routine is called whenever an object is referenced, so we can
+ * maintain replacement information within the storage fs.
+ */
+void
+UFSSwapDir::reference(StoreEntry &e)
+{
+ debugs(47, 3, "UFSSwapDir::reference: referencing " << &e << " " << e.swap_dirn \
<< "/" << e.swap_filen); +
+ if (repl->Referenced)
+ repl->Referenced(repl, &e, &e.repl);
+}
+
+/*
+ * UFSSwapDir::dereference
+ * This routine is called whenever the last reference to an object is
+ * removed, to maintain replacement information within the storage fs.
+ */
+bool
+UFSSwapDir::dereference(StoreEntry & e)
+{
+ debugs(47, 3, "UFSSwapDir::dereference: referencing " << &e << " " << \
e.swap_dirn << "/" << e.swap_filen); +
+ if (repl->Dereferenced)
+ repl->Dereferenced(repl, &e, &e.repl);
+
+ return true; // keep e in the global store_table
+}
+
+StoreIOState::Pointer
+UFSSwapDir::createStoreIO(StoreEntry &e, StoreIOState::STFNCB * file_callback, \
StoreIOState::STIOCB * aCallback, void *callback_data) +{
+ return IO->create (this, &e, file_callback, aCallback, callback_data);
+}
+
+StoreIOState::Pointer
+UFSSwapDir::openStoreIO(StoreEntry &e, StoreIOState::STFNCB * file_callback, \
StoreIOState::STIOCB * aCallback, void *callback_data) +{
+ return IO->open (this, &e, file_callback, aCallback, callback_data);
+}
+
+int
+UFSSwapDir::mapBitTest(sfileno filn)
+{
+ return map->testBit(filn);
+}
+
+void
+UFSSwapDir::mapBitSet(sfileno filn)
+{
+ map->setBit(filn);
+}
+
+void
+UFSSwapDir::mapBitReset(sfileno filn)
+{
+ /*
+ * We have to test the bit before calling clearBit as
+ * it doesn't do bounds checking and blindly assumes
+ * filn is a valid file number, but it might not be because
+ * the map is dynamic in size. Also clearing an already clear
+ * bit puts the map counter of-of-whack.
+ */
+
+ if (map->testBit(filn))
+ map->clearBit(filn);
+}
+
+int
+UFSSwapDir::mapBitAllocate()
+{
+ int fn;
+ fn = map->allocate(suggest);
+ map->setBit(fn);
+ suggest = fn + 1;
+ return fn;
+}
+
+char *
+UFSSwapDir::swapSubDir(int subdirn)const
+{
+ LOCAL_ARRAY(char, fullfilename, MAXPATHLEN);
+ assert(0 <= subdirn && subdirn < l1);
+ snprintf(fullfilename, MAXPATHLEN, "%s/%02X", path, subdirn);
+ return fullfilename;
+}
+
+int
+UFSSwapDir::createDirectory(const char *aPath, int should_exist)
+{
+ int created = 0;
+
+ struct stat st;
+ getCurrentTime();
+
+ if (0 == ::stat(aPath, &st)) {
+ if (S_ISDIR(st.st_mode)) {
+ debugs(47, (should_exist ? 3 : 1), aPath << " exists");
+ } else {
+ fatalf("Swap directory %s is not a directory.", aPath);
+ }
+
+#if _SQUID_MSWIN_
+
+ } else if (0 == mkdir(aPath)) {
+#else
+
+ } else if (0 == mkdir(aPath, 0755)) {
+#endif
+ debugs(47, (should_exist ? 1 : 3), aPath << " created");
+ created = 1;
+ } else {
+ fatalf("Failed to make swap directory %s: %s",
+ aPath, xstrerror());
+ }
+
+ return created;
+}
+
+bool
+UFSSwapDir::pathIsDirectory(const char *aPath)const
+{
+
+ struct stat sb;
+
+ if (::stat(aPath, &sb) < 0) {
+ debugs(47, 0, "" << aPath << ": " << xstrerror());
+ return false;
+ }
+
+ if (S_ISDIR(sb.st_mode) == 0) {
+ debugs(47, 0, "" << aPath << " is not a directory");
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * This function is called by commonUfsDirInit(). If this returns < 0,
+ * then Squid exits, complains about swap directories not
+ * existing, and instructs the admin to run 'squid -z'
+ */
+bool
+UFSSwapDir::verifyCacheDirs()
+{
+ if (!pathIsDirectory(path))
+ return true;
+
+ for (int j = 0; j < l1; ++j) {
+ char const *aPath = swapSubDir(j);
+
+ if (!pathIsDirectory(aPath))
+ return true;
+ }
+
+ return false;
+}
+
+void
+UFSSwapDir::createSwapSubDirs()
+{
+ LOCAL_ARRAY(char, name, MAXPATHLEN);
+
+ for (int i = 0; i < l1; ++i) {
+ snprintf(name, MAXPATHLEN, "%s/%02X", path, i);
+
+ int should_exist;
+
+ if (createDirectory(name, 0))
+ should_exist = 0;
+ else
+ should_exist = 1;
+
+ debugs(47, 1, "Making directories in " << name);
+
+ for (int k = 0; k < l2; ++k) {
+ snprintf(name, MAXPATHLEN, "%s/%02X/%02X", path, i, k);
+ createDirectory(name, should_exist);
+ }
+ }
+}
+
+char *
+UFSSwapDir::logFile(char const *ext) const
+{
+ LOCAL_ARRAY(char, lpath, MAXPATHLEN);
+ LOCAL_ARRAY(char, pathtmp, MAXPATHLEN);
+ LOCAL_ARRAY(char, digit, 32);
+ char *pathtmp2;
+
+ if (Config.Log.swap) {
+ xstrncpy(pathtmp, path, MAXPATHLEN - 64);
+ pathtmp2 = pathtmp;
+
+ while ((pathtmp2 = strchr(pathtmp2, '/')) != NULL)
+ *pathtmp2 = '.';
+
+ while (strlen(pathtmp) && pathtmp[strlen(pathtmp) - 1] == '.')
+ pathtmp[strlen(pathtmp) - 1] = '\0';
+
+ for (pathtmp2 = pathtmp; *pathtmp2 == '.'; ++pathtmp2);
+ snprintf(lpath, MAXPATHLEN - 64, Config.Log.swap, pathtmp2);
+
+ if (strncmp(lpath, Config.Log.swap, MAXPATHLEN - 64) == 0) {
+ strcat(lpath, ".");
+ snprintf(digit, 32, "%02d", index);
+ strncat(lpath, digit, 3);
+ }
+ } else {
+ xstrncpy(lpath, path, MAXPATHLEN - 64);
+ strcat(lpath, "/swap.state");
+ }
+
+ if (ext)
+ strncat(lpath, ext, 16);
+
+ return lpath;
+}
+
+void
+UFSSwapDir::openLog()
+{
+ char *logPath;
+ logPath = logFile();
+ swaplog_fd = file_open(logPath, O_WRONLY | O_CREAT | O_BINARY);
+
+ if (swaplog_fd < 0) {
+ debugs(50, 1, "" << logPath << ": " << xstrerror());
+ fatal("commonUfsDirOpenSwapLog: Failed to open swap log.");
+ }
+
+ debugs(50, 3, "Cache Dir #" << index << " log opened on FD " << swaplog_fd);
+
+ if (0 == NumberOfUFSDirs)
+ assert(NULL == UFSDirToGlobalDirMapping);
+
+ ++NumberOfUFSDirs;
+
+ assert(NumberOfUFSDirs <= Config.cacheSwap.n_configured);
+}
+
+void
+UFSSwapDir::closeLog()
+{
+ if (swaplog_fd < 0) /* not open */
+ return;
+
+ file_close(swaplog_fd);
+
+ debugs(47, 3, "Cache Dir #" << index << " log closed on FD " << swaplog_fd);
+
+ swaplog_fd = -1;
+
+ --NumberOfUFSDirs;
+
+ assert(NumberOfUFSDirs >= 0);
+
+ if (0 == NumberOfUFSDirs)
+ safe_free(UFSDirToGlobalDirMapping);
+}
+
+bool
+UFSSwapDir::validL1(int anInt) const
+{
+ return anInt < l1;
+}
+
+bool
+UFSSwapDir::validL2(int anInt) const
+{
+ return anInt < l2;
+}
+
+/* Add a new object to the cache with empty memory copy and pointer to disk
+ * use to rebuild store from disk. */
+StoreEntry *
+UFSSwapDir::addDiskRestore(const cache_key * key,
+ sfileno file_number,
+ uint64_t swap_file_sz,
+ time_t expires,
+ time_t timestamp,
+ time_t lastref,
+ time_t lastmod,
+ uint32_t refcount,
+ uint16_t newFlags,
+ int clean)
+{
+ StoreEntry *e = NULL;
+ debugs(47, 5, "commonUfsAddDiskRestore: " << storeKeyText(key) <<
+ ", fileno="<< std::setfill('0') << std::hex << std::uppercase << \
std::setw(8) << file_number); + /* if you call this you'd better be sure \
file_number is not + * already in use! */
+ e = new StoreEntry();
+ e->store_status = STORE_OK;
+ e->setMemStatus(NOT_IN_MEMORY);
+ e->swap_status = SWAPOUT_DONE;
+ e->swap_filen = file_number;
+ e->swap_dirn = index;
+ e->swap_file_sz = swap_file_sz;
+ e->lock_count = 0;
+ e->lastref = lastref;
+ e->timestamp = timestamp;
+ e->expires = expires;
+ e->lastmod = lastmod;
+ e->refcount = refcount;
+ e->flags = newFlags;
+ EBIT_SET(e->flags, ENTRY_CACHABLE);
+ EBIT_CLR(e->flags, RELEASE_REQUEST);
+ EBIT_CLR(e->flags, KEY_PRIVATE);
+ e->ping_status = PING_NONE;
+ EBIT_CLR(e->flags, ENTRY_VALIDATED);
+ mapBitSet(e->swap_filen);
+ cur_size += fs.blksize * sizeInBlocks(e->swap_file_sz);
+ ++n_disk_objects;
+ e->hashInsert(key); /* do it after we clear KEY_PRIVATE */
+ replacementAdd (e);
+ return e;
+}
+
+void
+UFSSwapDir::undoAddDiskRestore(StoreEntry *e)
+{
+ debugs(47, 5, HERE << *e);
+ replacementRemove(e); // checks swap_dirn so do it before we invalidate it
+ // Do not unlink the file as it might be used by a subsequent entry.
+ mapBitReset(e->swap_filen);
+ e->swap_filen = -1;
+ e->swap_dirn = -1;
+ cur_size -= fs.blksize * sizeInBlocks(e->swap_file_sz);
+ --n_disk_objects;
+}
+
+void
+UFSSwapDir::rebuild()
+{
+ ++StoreController::store_dirs_rebuilding;
+ eventAdd("storeRebuild", RebuildState::RebuildStep, new RebuildState(this), 0.0, \
1); +}
+
+void
+UFSSwapDir::closeTmpSwapLog()
+{
+ char *swaplog_path = xstrdup(logFile(NULL));
+ char *new_path = xstrdup(logFile(".new"));
+ int fd;
+ file_close(swaplog_fd);
+
+ if (xrename(new_path, swaplog_path) < 0) {
+ debugs(50, DBG_IMPORTANT, "ERROR: " << swaplog_path << ": " << xstrerror());
+ fatalf("Failed to rename log file %s to %s.new", swaplog_path, \
swaplog_path); + }
+
+ fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY);
+
+ if (fd < 0) {
+ debugs(50, DBG_IMPORTANT, "ERROR: " << swaplog_path << ": " << xstrerror());
+ fatalf("Failed to open swap log %s", swaplog_path);
+ }
+
+ safe_free(swaplog_path);
+ safe_free(new_path);
+ swaplog_fd = fd;
+ debugs(47, 3, "Cache Dir #" << index << " log opened on FD " << fd);
+}
+
+FILE *
+UFSSwapDir::openTmpSwapLog(int *clean_flag, int *zero_flag)
+{
+ char *swaplog_path = xstrdup(logFile(NULL));
+ char *clean_path = xstrdup(logFile(".last-clean"));
+ char *new_path = xstrdup(logFile(".new"));
+
+ struct stat log_sb;
+
+ struct stat clean_sb;
+ FILE *fp;
+ int fd;
+
+ if (::stat(swaplog_path, &log_sb) < 0) {
+ debugs(47, 1, "Cache Dir #" << index << ": No log file");
+ safe_free(swaplog_path);
+ safe_free(clean_path);
+ safe_free(new_path);
+ return NULL;
+ }
+
+ *zero_flag = log_sb.st_size == 0 ? 1 : 0;
+ /* close the existing write-only FD */
+
+ if (swaplog_fd >= 0)
+ file_close(swaplog_fd);
+
+ /* open a write-only FD for the new log */
+ fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
+
+ if (fd < 0) {
+ debugs(50, 1, "" << new_path << ": " << xstrerror());
+ fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
+ }
+
+ swaplog_fd = fd;
+
+ {
+ const StoreSwapLogHeader header;
+ MemBuf buf;
+ buf.init(header.record_size, header.record_size);
+ buf.append(reinterpret_cast<const char*>(&header), sizeof(header));
+ // Pad to keep in sync with UFSSwapDir::writeCleanStart().
+ memset(buf.space(), 0, header.gapSize());
+ buf.appended(header.gapSize());
+ file_write(swaplog_fd, -1, buf.content(), buf.contentSize(),
+ NULL, NULL, buf.freeFunc());
+ }
+
+ /* open a read-only stream of the old log */
+ fp = fopen(swaplog_path, "rb");
+
+ if (fp == NULL) {
+ debugs(50, 0, "" << swaplog_path << ": " << xstrerror());
+ fatal("Failed to open swap log for reading");
+ }
+
+ memset(&clean_sb, '\0', sizeof(struct stat));
+
+ if (::stat(clean_path, &clean_sb) < 0)
+ *clean_flag = 0;
+ else if (clean_sb.st_mtime < log_sb.st_mtime)
+ *clean_flag = 0;
+ else
+ *clean_flag = 1;
+
+ safeunlink(clean_path, 1);
+
+ safe_free(swaplog_path);
+
+ safe_free(clean_path);
+
+ safe_free(new_path);
+
+ return fp;
+}
+
+/*
+ * Begin the process to write clean cache state. For AUFS this means
+ * opening some log files and allocating write buffers. Return 0 if
+ * we succeed, and assign the 'func' and 'data' return pointers.
+ */
+int
+UFSSwapDir::writeCleanStart()
+{
+ UFSCleanLog *state = new UFSCleanLog(this);
+ StoreSwapLogHeader header;
+#if HAVE_FCHMOD
+
+ struct stat sb;
+#endif
+
+ cleanLog = NULL;
+ state->newLog = xstrdup(logFile(".clean"));
+ state->fd = file_open(state->newLog, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
+
+ if (state->fd < 0) {
+ xfree(state->newLog);
+ delete state;
+ return -1;
+ }
+
+ state->cur = xstrdup(logFile(NULL));
+ state->cln = xstrdup(logFile(".last-clean"));
+ state->outbuf = (char *)xcalloc(CLEAN_BUF_SZ, 1);
+ state->outbuf_offset = 0;
+ /*copy the header */
+ memcpy(state->outbuf, &header, sizeof(StoreSwapLogHeader));
+ // Leave a gap to keep in sync with UFSSwapDir::openTmpSwapLog().
+ memset(state->outbuf + sizeof(StoreSwapLogHeader), 0, header.gapSize());
+ state->outbuf_offset += header.record_size;
+
+ state->walker = repl->WalkInit(repl);
+ ::unlink(state->cln);
+ debugs(47, 3, "storeDirWriteCleanLogs: opened " << state->newLog << ", FD " << \
state->fd); +#if HAVE_FCHMOD
+
+ if (::stat(state->cur, &sb) == 0)
+ fchmod(state->fd, sb.st_mode);
+
+#endif
+
+
+ cleanLog = state;
+ return 0;
+}
+
+void
+UFSSwapDir::writeCleanDone()
+{
+ UFSCleanLog *state = (UFSCleanLog *)cleanLog;
+ int fd;
+
+ if (NULL == state)
+ return;
+
+ if (state->fd < 0)
+ return;
+
+ state->walker->Done(state->walker);
+
+ if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) {
+ debugs(50, 0, "storeDirWriteCleanLogs: " << state->newLog << ": write: " << \
xstrerror()); + debugs(50, 0, "storeDirWriteCleanLogs: Current swap logfile \
not replaced."); + file_close(state->fd);
+ state->fd = -1;
+ ::unlink(state->newLog);
+ }
+
+ safe_free(state->outbuf);
+ /*
+ * You can't rename open files on Microsoft "operating systems"
+ * so we have to close before renaming.
+ */
+ closeLog();
+ /* save the fd value for a later test */
+ fd = state->fd;
+ /* rename */
+
+ if (state->fd >= 0) {
+#if _SQUID_OS2_ || _SQUID_WINDOWS_
+ file_close(state->fd);
+ state->fd = -1;
+#endif
+
+ xrename(state->newLog, state->cur);
+ }
+
+ /* touch a timestamp file if we're not still validating */
+ if (StoreController::store_dirs_rebuilding)
+ (void) 0;
+ else if (fd < 0)
+ (void) 0;
+ else
+ file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY));
+
+ /* close */
+ safe_free(state->cur);
+
+ safe_free(state->newLog);
+
+ safe_free(state->cln);
+
+ if (state->fd >= 0)
+ file_close(state->fd);
+
+ state->fd = -1;
+
+ delete state;
+
+ cleanLog = NULL;
+}
+
+void
+UFSSwapDir::CleanEvent(void *unused)
+{
+ static int swap_index = 0;
+ int i;
+ int j = 0;
+ int n = 0;
+ /*
+ * Assert that there are UFS cache_dirs configured, otherwise
+ * we should never be called.
+ */
+ assert(NumberOfUFSDirs);
+
+ if (NULL == UFSDirToGlobalDirMapping) {
+ SwapDir *sd;
+ /*
+ * Initialize the little array that translates UFS cache_dir
+ * number into the Config.cacheSwap.swapDirs array index.
+ */
+ UFSDirToGlobalDirMapping = (int *)xcalloc(NumberOfUFSDirs, \
sizeof(*UFSDirToGlobalDirMapping)); +
+ for (i = 0, n = 0; i < Config.cacheSwap.n_configured; ++i) {
+ /* This is bogus, the controller should just clean each instance once */
+ sd = dynamic_cast <SwapDir *>(INDEXSD(i));
+
+ if (!UFSSwapDir::IsUFSDir(sd))
+ continue;
+
+ UFSSwapDir *usd = dynamic_cast<UFSSwapDir *>(sd);
+
+ assert (usd);
+
+ UFSDirToGlobalDirMapping[n] = i;
+ ++n;
+
+ j += (usd->l1 * usd->l2);
+ }
+
+ assert(n == NumberOfUFSDirs);
+ /*
+ * Start the commonUfsDirClean() swap_index with a random
+ * value. j equals the total number of UFS level 2
+ * swap directories
+ */
+ swap_index = (int) (squid_random() % j);
+ }
+
+ /* if the rebuild is finished, start cleaning directories. */
+ if (0 == StoreController::store_dirs_rebuilding) {
+ n = DirClean(swap_index);
+ ++swap_index;
+ }
+
+ eventAdd("storeDirClean", CleanEvent, NULL,
+ 15.0 * exp(-0.25 * n), 1);
+}
+
+int
+UFSSwapDir::IsUFSDir(SwapDir * sd)
+{
+ UFSSwapDir *mySD = dynamic_cast<UFSSwapDir *>(sd);
+ return mySD ? 1 : 0 ;
+}
+
+/*
+ * Does swapfile number 'fn' belong in cachedir #F0,
+ * level1 dir #F1, level2 dir #F2?
+ * XXX: this is broken - it assumes all cache dirs use the same
+ * l1 and l2 scheme. -RBC 20021215. Partial fix is in place -
+ * if not UFSSwapDir return 0;
+ */
+int
+UFSSwapDir::FilenoBelongsHere(int fn, int F0, int F1, int F2)
+{
+ int D1, D2;
+ int L1, L2;
+ int filn = fn;
+ assert(F0 < Config.cacheSwap.n_configured);
+ assert (UFSSwapDir::IsUFSDir (dynamic_cast<SwapDir *>(INDEXSD(F0))));
+ UFSSwapDir *sd = dynamic_cast<UFSSwapDir *>(INDEXSD(F0));
+
+ if (!sd)
+ return 0;
+
+ L1 = sd->l1;
+
+ L2 = sd->l2;
+
+ D1 = ((filn / L2) / L2) % L1;
+
+ if (F1 != D1)
+ return 0;
+
+ D2 = (filn / L2) % L2;
+
+ if (F2 != D2)
+ return 0;
+
+ return 1;
+}
+
+
+int
+UFSSwapDir::validFileno(sfileno filn, int flag) const
+{
+ if (filn < 0)
+ return 0;
+
+ /*
+ * If flag is set it means out-of-range file number should
+ * be considered invalid.
+ */
+ if (flag)
+ if (filn > map->capacity())
+ return 0;
+
+ return 1;
+}
+
+
+
+/*
+ * UFSSwapDir::unlinkFile
+ *
+ * This routine unlinks a file and pulls it out of the bitmap.
+ * It used to be in commonUfsUnlink(), however an interface change
+ * forced this bit of code here. Eeek.
+ */
+void
+UFSSwapDir::unlinkFile(sfileno f)
+{
+ debugs(79, 3, "UFSSwapDir::unlinkFile: unlinking fileno " << std::setfill('0') \
<< + std::hex << std::uppercase << std::setw(8) << f << " '" <<
+ fullPath(f,NULL) << "'");
+ /* commonUfsDirMapBitReset(this, f); */
+ IO->unlinkFile(fullPath(f,NULL));
+}
+
+bool
+UFSSwapDir::unlinkdUseful() const
+{
+ // unlinkd may be useful only in workers
+ return IamWorkerProcess() && IO->io->unlinkdUseful();
+}
+
+void
+UFSSwapDir::unlink(StoreEntry & e)
+{
+ debugs(79, 3, "storeUfsUnlink: dirno " << index << ", fileno "<<
+ std::setfill('0') << std::hex << std::uppercase << std::setw(8) << \
e.swap_filen); + if (e.swap_status == SWAPOUT_DONE) {
+ cur_size -= fs.blksize * sizeInBlocks(e.swap_file_sz);
+ --n_disk_objects;
+ }
+ replacementRemove(&e);
+ mapBitReset(e.swap_filen);
+ UFSSwapDir::unlinkFile(e.swap_filen);
+}
+
+/*
+ * Add and remove the given StoreEntry from the replacement policy in
+ * use.
+ */
+
+void
+UFSSwapDir::replacementAdd(StoreEntry * e)
+{
+ debugs(47, 4, "UFSSwapDir::replacementAdd: added node " << e << " to dir " << \
index); + repl->Add(repl, e, &e->repl);
+}
+
+
+void
+UFSSwapDir::replacementRemove(StoreEntry * e)
+{
+ StorePointer SD;
+
+ if (e->swap_dirn < 0)
+ return;
+
+ SD = INDEXSD(e->swap_dirn);
+
+ assert (dynamic_cast<UFSSwapDir *>(SD.getRaw()) == this);
+
+ debugs(47, 4, "UFSSwapDir::replacementRemove: remove node " << e << " from dir " \
<< index); +
+ repl->Remove(repl, e, &e->repl);
+}
+
+void
+UFSSwapDir::dump(StoreEntry & entry) const
+{
+ storeAppendPrintf(&entry, " %" PRIu64 " %d %d", maxSize() >> 20, l1, l2);
+ dumpOptions(&entry);
+}
+
+char *
+UFSSwapDir::fullPath(sfileno filn, char *fullpath) const
+{
+ LOCAL_ARRAY(char, fullfilename, MAXPATHLEN);
+ int L1 = l1;
+ int L2 = l2;
+
+ if (!fullpath)
+ fullpath = fullfilename;
+
+ fullpath[0] = '\0';
+
+ snprintf(fullpath, MAXPATHLEN, "%s/%02X/%02X/%08X",
+ path,
+ ((filn / L2) / L2) % L1,
+ (filn / L2) % L2,
+ filn);
+
+ return fullpath;
+}
+
+int
+UFSSwapDir::callback()
+{
+ return IO->callback();
+}
+
+void
+UFSSwapDir::sync()
+{
+ IO->sync();
+}
+
+void
+UFSSwapDir::swappedOut(const StoreEntry &e)
+{
+ cur_size += fs.blksize * sizeInBlocks(e.swap_file_sz);
+ ++n_disk_objects;
+}
+
+StoreSearch *
+UFSSwapDir::search(String const url, HttpRequest *request)
+{
+ if (url.size())
+ fatal ("Cannot search by url yet\n");
+
+ return new StoreSearchUFS (this);
+}
+
+void
+UFSSwapDir::logEntry(const StoreEntry & e, int op) const
+{
+ StoreSwapLogData *s = new StoreSwapLogData;
+ s->op = (char) op;
+ s->swap_filen = e.swap_filen;
+ s->timestamp = e.timestamp;
+ s->lastref = e.lastref;
+ s->expires = e.expires;
+ s->lastmod = e.lastmod;
+ s->swap_file_sz = e.swap_file_sz;
+ s->refcount = e.refcount;
+ s->flags = e.flags;
+ memcpy(s->key, e.key, SQUID_MD5_DIGEST_LENGTH);
+ s->finalize();
+ file_write(swaplog_fd,
+ -1,
+ s,
+ sizeof(StoreSwapLogData),
+ NULL,
+ NULL,
+ FreeObject);
+}
+
+
+int
+UFSSwapDir::DirClean(int swap_index)
+{
+ DIR *dir_pointer = NULL;
+
+ LOCAL_ARRAY(char, p1, MAXPATHLEN + 1);
+ LOCAL_ARRAY(char, p2, MAXPATHLEN + 1);
+
+ int files[20];
+ int swapfileno;
+ int fn; /* same as swapfileno, but with dirn bits set */
+ int n = 0;
+ int k = 0;
+ int N0, N1, N2;
+ int D0, D1, D2;
+ UFSSwapDir *SD;
+ N0 = NumberOfUFSDirs;
+ D0 = UFSDirToGlobalDirMapping[swap_index % N0];
+ SD = dynamic_cast<UFSSwapDir *>(INDEXSD(D0));
+ assert (SD);
+ N1 = SD->l1;
+ D1 = (swap_index / N0) % N1;
+ N2 = SD->l2;
+ D2 = ((swap_index / N0) / N1) % N2;
+ snprintf(p1, MAXPATHLEN, "%s/%02X/%02X",
+ SD->path, D1, D2);
+ debugs(36, 3, "storeDirClean: Cleaning directory " << p1);
+ dir_pointer = opendir(p1);
+
+ if (dir_pointer == NULL) {
+ if (errno == ENOENT) {
+ debugs(36, 0, "storeDirClean: WARNING: Creating " << p1);
+#if _SQUID_MSWIN_
+
+ if (mkdir(p1) == 0)
+#else
+
+ if (mkdir(p1, 0777) == 0)
+#endif
+
+ return 0;
+ }
+
+ debugs(50, 0, "storeDirClean: " << p1 << ": " << xstrerror());
+ safeunlink(p1, 1);
+ return 0;
+ }
+
+ dirent_t *de;
+ while ((de = readdir(dir_pointer)) != NULL && k < 20) {
+ if (sscanf(de->d_name, "%X", &swapfileno) != 1)
+ continue;
+
+ fn = swapfileno; /* XXX should remove this cruft ! */
+
+ if (SD->validFileno(fn, 1))
+ if (SD->mapBitTest(fn))
+ if (UFSSwapDir::FilenoBelongsHere(fn, D0, D1, D2))
+ continue;
+
+ files[k] = swapfileno;
+ ++k;
+ }
+
+ closedir(dir_pointer);
+
+ if (k == 0)
+ return 0;
+
+ qsort(files, k, sizeof(int), rev_int_sort);
+
+ if (k > 10)
+ k = 10;
+
+ for (n = 0; n < k; ++n) {
+ debugs(36, 3, "storeDirClean: Cleaning file "<< std::setfill('0') << \
std::hex << std::uppercase << std::setw(8) << files[n]); + snprintf(p2, \
MAXPATHLEN + 1, "%s/%08X", p1, files[n]); + safeunlink(p2, 0);
+ ++statCounter.swap.files_cleaned;
+ }
+
+ debugs(36, 3, "Cleaned " << k << " unused files from " << p1);
+ return k;
+}
+
=== added file 'src/fs/ufs/UFSSwapDir.h'
--- src/fs/ufs/UFSSwapDir.h 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/UFSSwapDir.h 2012-07-31 22:15:40 +0000
@@ -0,0 +1,151 @@
+/*
+ * UFSSwapDir.h
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#ifndef SQUID_FS_UFS_UFSSWAPDIR_H
+#define SQUID_FS_UFS_UFSSWAPDIR_H
+
+class HttpRequest;
+class ConfigOptionVector;
+class FileMap;
+class DiskIOModule;
+
+#include "SquidString.h"
+#include "Store.h"
+#include "StoreIOState.h"
+#include "StoreSearch.h"
+#include "SwapDir.h"
+#include "swap_log_op.h"
+#include "UFSStrategy.h"
+
+/// \ingroup UFS
+class UFSSwapDir : public SwapDir
+{
+
+public:
+ static int IsUFSDir(SwapDir* sd);
+ static int DirClean(int swap_index);
+ static int FilenoBelongsHere(int fn, int F0, int F1, int F2);
+
+ UFSSwapDir(char const *aType, const char *aModuleType);
+ virtual void init();
+ virtual void create();
+ virtual void dump(StoreEntry &) const;
+ ~UFSSwapDir();
+ virtual StoreSearch *search(String const url, HttpRequest *);
+ virtual bool doubleCheck(StoreEntry &);
+ virtual bool unlinkdUseful() const;
+ virtual void unlink(StoreEntry &);
+ virtual void statfs(StoreEntry &)const;
+ virtual void maintain();
+ virtual bool canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) \
const; + virtual void reference(StoreEntry &);
+ virtual bool dereference(StoreEntry &);
+ virtual StoreIOState::Pointer createStoreIO(StoreEntry &, StoreIOState::STFNCB \
*, StoreIOState::STIOCB *, void *); + virtual StoreIOState::Pointer \
openStoreIO(StoreEntry &, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *); + \
virtual void openLog(); + virtual void closeLog();
+ virtual int writeCleanStart();
+ virtual void writeCleanDone();
+ virtual void logEntry(const StoreEntry & e, int op) const;
+ virtual void parse(int index, char *path);
+ virtual void reconfigure();
+ virtual int callback();
+ virtual void sync();
+ virtual void swappedOut(const StoreEntry &e);
+ virtual uint64_t currentSize() const { return cur_size; }
+ virtual uint64_t currentCount() const { return n_disk_objects; }
+
+ void unlinkFile(sfileno f);
+ // move down when unlink is a virtual method
+ //protected:
+ UFSStrategy *IO;
+ char *fullPath(sfileno, char *) const;
+ /* temp */
+ void closeTmpSwapLog();
+ FILE *openTmpSwapLog(int *clean_flag, int *zero_flag);
+ char *swapSubDir(int subdirn) const;
+ int mapBitTest(sfileno filn);
+ void mapBitReset(sfileno filn);
+ void mapBitSet(sfileno filn);
+ StoreEntry *addDiskRestore(const cache_key * key,
+ sfileno file_number,
+ uint64_t swap_file_sz,
+ time_t expires,
+ time_t timestamp,
+ time_t lastref,
+ time_t lastmod,
+ uint32_t refcount,
+ uint16_t flags,
+ int clean);
+ /// Undo the effects of UFSSwapDir::addDiskRestore().
+ void undoAddDiskRestore(StoreEntry *e);
+ int validFileno(sfileno filn, int flag) const;
+ int mapBitAllocate();
+ virtual ConfigOption *getOptionTree() const;
+
+ void *fsdata;
+
+ bool validL2(int) const;
+ bool validL1(int) const;
+
+ void replacementAdd(StoreEntry *e);
+ void replacementRemove(StoreEntry *e);
+
+protected:
+ FileMap *map;
+ int suggest;
+ int l1;
+ int l2;
+
+private:
+ void parseSizeL1L2();
+ static int NumberOfUFSDirs;
+ static int * UFSDirToGlobalDirMapping;
+ bool pathIsDirectory(const char *path)const;
+ int swaplog_fd;
+ static EVH CleanEvent;
+ bool verifyCacheDirs();
+ void rebuild();
+ int createDirectory(const char *path, int);
+ void createSwapSubDirs();
+ void dumpEntry(StoreEntry &) const;
+ char *logFile(char const *ext = NULL)const;
+ void changeIO(DiskIOModule *);
+ bool optionIOParse(char const *option, const char *value, int reconfiguring);
+ void optionIODump(StoreEntry * e) const;
+ mutable ConfigOptionVector *currentIOOptions;
+ char const *ioType;
+ uint64_t cur_size; ///< currently used space in the storage area
+ uint64_t n_disk_objects; ///< total number of objects stored
+};
+
+
+
+#endif /* SQUID_FS_UFS_UFSSWAPDIR_H */
=== added file 'src/fs/ufs/UFSSwapLogParser.cc'
--- src/fs/ufs/UFSSwapLogParser.cc 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/UFSSwapLogParser.cc 2012-07-31 21:23:21 +0000
@@ -0,0 +1,204 @@
+/*
+ * UFSSwapLogParser.cc
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+
+#include "md5.h"
+#include "StoreSwapLogData.h"
+#include "swap_log_op.h"
+#include "UFSSwapLogParser.h"
+
+/// Parse a swap header entry created on a system with 32-bit size_t and sfileno
+/// this is typical of 32-bit systems without large file support
+/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still.
+class UFSSwapLogParser_v1_32bs:public UFSSwapLogParser
+{
+public:
+ /// version 1 cache swap.state entry with 32-bit size_t (swap_file_sz)
+ /// time_t an sfileno have no variation from the v1 baseline format
+ struct StoreSwapLogDataOld {
+ char op;
+ sfileno swap_filen;
+ time_t timestamp;
+ time_t lastref;
+ time_t expires;
+ time_t lastmod;
+ uint32_t swap_file_sz;
+ uint16_t refcount;
+ uint16_t flags;
+ unsigned char key[SQUID_MD5_DIGEST_LENGTH];
+ };
+ UFSSwapLogParser_v1_32bs(FILE *fp):UFSSwapLogParser(fp) {
+ record_size = sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld);
+ }
+ /// Convert the on-disk 32-bit format to our current format while reading
+ bool ReadRecord(StoreSwapLogData &swapData) {
+ UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld readData;
+ int bytes = sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld);
+
+ assert(log);
+
+ if (fread(&readData, bytes, 1, log) != 1) {
+ return false;
+ }
+ swapData.op = readData.op;
+ swapData.swap_filen = readData.swap_filen;
+ swapData.timestamp = readData.timestamp;
+ swapData.lastref = readData.lastref;
+ swapData.expires = readData.expires;
+ swapData.lastmod = readData.lastmod;
+ swapData.swap_file_sz = readData.swap_file_sz;
+ swapData.refcount = readData.refcount;
+ swapData.flags = readData.flags;
+ memcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH);
+ return true;
+ }
+};
+
+/// swap.state v2 log parser
+class UFSSwapLogParser_v2: public UFSSwapLogParser
+{
+public:
+ UFSSwapLogParser_v2(FILE *fp): UFSSwapLogParser(fp) {
+ record_size = sizeof(StoreSwapLogData);
+ }
+ bool ReadRecord(StoreSwapLogData &swapData) {
+ assert(log);
+ return fread(&swapData, sizeof(StoreSwapLogData), 1, log) == 1;
+ }
+};
+
+
+UFSSwapLogParser *UFSSwapLogParser::GetUFSSwapLogParser(FILE *fp)
+{
+ StoreSwapLogHeader header;
+
+ assert(fp);
+
+ if (fread(&header, sizeof(StoreSwapLogHeader), 1, fp) != 1)
+ return NULL;
+
+ if (header.op != SWAP_LOG_VERSION) {
+ debugs(47, 1, "Old swap file detected...");
+ fseek(fp, 0, SEEK_SET);
+ return new UFSSwapLogParser_v1_32bs(fp); // Um. 32-bits except time_t, and \
can't determine that. + }
+
+ debugs(47, 2, "Swap file version: " << header.version);
+
+ if (header.version == 1) {
+ if (fseek(fp, header.record_size, SEEK_SET) != 0)
+ return NULL;
+
+ debugs(47, DBG_IMPORTANT, "Rejecting swap file v1 to avoid cache " <<
+ "index corruption. Forcing a full cache index rebuild. " <<
+ "See Squid bug #3441.");
+ return NULL;
+
+#if UNUSED_CODE
+ // baseline
+ // 32-bit sfileno
+ // native time_t (hopefully 64-bit)
+ // 64-bit file size
+ if (header.record_size == sizeof(StoreSwapLogData)) {
+ debugs(47, 1, "Version 1 of swap file with LFS support detected... ");
+ return new UFSSwapLogParser_v1(fp);
+ }
+
+ // which means we have a 3-way grid of permutations to import (yuck!)
+ // 1) sfileno 32-bit / 64-bit (64-bit was broken)
+ // 2) time_t 32-bit / 64-bit
+ // 3) size_t 32-bit / 64-bit (32-bit was pre-LFS)
+
+ // 32-bit systems...
+ // only LFS (size_t) differs from baseline
+ if (header.record_size == sizeof(struct \
UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld)) { + debugs(47, 1, "Version \
1 (32-bit) swap file without LFS support detected... "); + return new \
UFSSwapLogParser_v1_32bs(fp); + }
+ // LFS (size_t) and timestamps (time_t) differs from baseline
+ if (header.record_size == sizeof(struct \
UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld)) { + debugs(47, 1, \
"Version 1 (32-bit) swap file with short timestamps and without LFS support \
detected... "); + return new UFSSwapLogParser_v1_32bst(fp);
+ }
+ // No downgrade for 64-bit timestamps to 32-bit.
+
+ // 64-bit systems
+ // sfileno was 64-bit for a some builds
+ if (header.record_size == sizeof(struct \
UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld)) { + debugs(47, 1, \
"Version 1 (64-bit) swap file with broken sfileno detected... "); + return \
new UFSSwapLogParser_v1_64bfn(fp); + }
+ // NP: 64-bit system with 32-bit size_t/time_t are not handled.
+
+ debugs(47, 1, "WARNING: The swap file has wrong format!... ");
+ debugs(47, 1, "NOTE: Cannot safely downgrade caches to short (32-bit) \
timestamps."); + return NULL;
+#endif
+ }
+
+ if (header.version >= 2) {
+ if (!header.sane()) {
+ debugs(47, DBG_IMPORTANT, "ERROR: Corrupted v" << header.version <<
+ " swap file header.");
+ return NULL;
+ }
+
+ if (fseek(fp, header.record_size, SEEK_SET) != 0)
+ return NULL;
+
+ if (header.version == 2)
+ return new UFSSwapLogParser_v2(fp);
+ }
+
+ // TODO: v3: write to disk in network-order bytes for the larger fields?
+
+ debugs(47, DBG_IMPORTANT, "Unknown swap file version: " << header.version);
+ return NULL;
+}
+
+int UFSSwapLogParser::SwapLogEntries()
+{
+ struct stat sb;
+
+ if (log_entries >= 0)
+ return log_entries;
+
+ if (log && record_size && 0 == fstat(fileno(log), &sb)) {
+ log_entries = sb.st_size/record_size;
+ return log_entries;
+ }
+
+ return 0;
+}
+
+
+
=== added file 'src/fs/ufs/UFSSwapLogParser.h'
--- src/fs/ufs/UFSSwapLogParser.h 1970-01-01 00:00:00 +0000
+++ src/fs/ufs/UFSSwapLogParser.h 2012-07-31 22:15:40 +0000
@@ -0,0 +1,66 @@
+/*
+ * UFSSwapLogParser.h
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_FS_UFS_UFSSWAPLOGPARSER_H
+#define SQUID_FS_UFS_UFSSWAPLOGPARSER_H
+
+class StoreSwapLogData;
+
+#include <stdio.h>
+/// \ingroup UFS
+class UFSSwapLogParser
+{
+
+public:
+ FILE *log;
+ int log_entries;
+ int record_size;
+
+ UFSSwapLogParser(FILE *fp):log(fp),log_entries(-1), record_size(0) {
+ }
+ virtual ~UFSSwapLogParser() {};
+
+ static UFSSwapLogParser *GetUFSSwapLogParser(FILE *fp);
+
+ virtual bool ReadRecord(StoreSwapLogData &swapData) = 0;
+ int SwapLogEntries();
+ void Close() {
+ if (log) {
+ fclose(log);
+ log = NULL;
+ }
+ }
+};
+
+
+
+
+#endif /* SQUID_FS_UFS_UFSSWAPLOGPARSER_H */
=== modified file 'src/fs/ufs/store_dir_ufs.cc'
--- src/fs/ufs/store_dir_ufs.cc 2012-07-23 15:34:12 +0000
+++ src/fs/ufs/store_dir_ufs.cc 2012-07-31 21:45:27 +0000
@@ -36,7 +36,6 @@
#include "squid-old.h"
#include "Store.h"
#include "fde.h"
-#include "ufscommon.h"
#include "StoreSwapLogData.h"
#include "ConfigOption.h"
#include "DiskIO/DiskIOStrategy.h"
@@ -49,1423 +48,5 @@
#include "SwapDir.h"
#include "swap_log_op.h"
-int UFSSwapDir::NumberOfUFSDirs = 0;
-int *UFSSwapDir::UFSDirToGlobalDirMapping = NULL;
-
-/*
- * storeUfsDirCheckObj
- *
- * This routine is called by storeDirSelectSwapDir to see if the given
- * object is able to be stored on this filesystem. UFS filesystems will
- * happily store anything as long as the LRU time isn't too small.
- */
-bool
-UFSSwapDir::canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const
-{
- if (!SwapDir::canStore(e, diskSpaceNeeded, load))
- return false;
-
- if (IO->shedLoad())
- return false;
-
- load = IO->load();
- return true;
-}
-
-
-/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */
-
-void
-UFSSwapDir::parseSizeL1L2()
-{
- int i = GetInteger();
- if (i <= 0)
- fatal("UFSSwapDir::parseSizeL1L2: invalid size value");
-
- const uint64_t size = static_cast<uint64_t>(i) << 20; // MBytes to Bytes
-
- /* just reconfigure it */
- if (reconfiguring) {
- if (size == maxSize())
- debugs(3, 2, "Cache dir '" << path << "' size remains unchanged at " << \
i << " MB");
- else
- debugs(3, 1, "Cache dir '" << path << "' size changed to " << i << " \
MB");
- }
-
- max_size = size;
-
- l1 = GetInteger();
-
- if (l1 <= 0)
- fatal("UFSSwapDir::parseSizeL1L2: invalid level 1 directories value");
-
- l2 = GetInteger();
-
- if (l2 <= 0)
- fatal("UFSSwapDir::parseSizeL1L2: invalid level 2 directories value");
-}
-
-/*
- * storeUfsDirReconfigure
- *
- * This routine is called when the given swapdir needs reconfiguring
- */
-
-void
-UFSSwapDir::reconfigure()
-{
- parseSizeL1L2();
- parseOptions(1);
-}
-
-/*
- * storeUfsDirParse
- *
- * Called when a *new* fs is being setup.
- */
-void
-UFSSwapDir::parse (int anIndex, char *aPath)
-{
- index = anIndex;
- path = xstrdup(aPath);
-
- parseSizeL1L2();
-
- /* Initialise replacement policy stuff */
- repl = createRemovalPolicy(Config.replPolicy);
-
- parseOptions(0);
-}
-
-void
-UFSSwapDir::changeIO(DiskIOModule *module)
-{
- DiskIOStrategy *anIO = module->createStrategy();
- safe_free(ioType);
- ioType = xstrdup(module->type());
-
- delete IO->io;
- IO->io = anIO;
- /* Change the IO Options */
-
- if (currentIOOptions && currentIOOptions->options.size() > 2)
- delete currentIOOptions->options.pop_back();
-
- /* TODO: factor out these 4 lines */
- ConfigOption *ioOptions = IO->io->getOptionTree();
-
- if (ioOptions)
- currentIOOptions->options.push_back(ioOptions);
-}
-
-bool
-UFSSwapDir::optionIOParse(char const *option, const char *value, int isaReconfig)
-{
- if (strcmp(option, "IOEngine") != 0)
- return false;
-
- if (isaReconfig)
- /* silently ignore this */
- return true;
-
- if (!value)
- self_destruct();
-
- DiskIOModule *module = DiskIOModule::Find(value);
-
- if (!module)
- self_destruct();
-
- changeIO(module);
-
- return true;
-}
-
-void
-UFSSwapDir::optionIODump(StoreEntry * e) const
-{
- storeAppendPrintf(e, " IOEngine=%s", ioType);
-}
-
-ConfigOption *
-UFSSwapDir::getOptionTree() const
-{
- ConfigOption *parentResult = SwapDir::getOptionTree();
-
- if (currentIOOptions == NULL)
- currentIOOptions = new ConfigOptionVector();
-
- currentIOOptions->options.push_back(parentResult);
-
- currentIOOptions->options.push_back(new \
ConfigOptionAdapter<UFSSwapDir>(*const_cast<UFSSwapDir *>(this), \
&UFSSwapDir::optionIOParse, &UFSSwapDir::optionIODump));
-
- if (ConfigOption *ioOptions = IO->io->getOptionTree())
- currentIOOptions->options.push_back(ioOptions);
-
- ConfigOption* result = currentIOOptions;
-
- currentIOOptions = NULL;
-
- return result;
-}
-
-/*
- * Initial setup / end destruction
- */
-void
-UFSSwapDir::init()
-{
- debugs(47, 3, "Initialising UFS SwapDir engine.");
- /* Parsing must be finished by now - force to NULL, don't delete */
- currentIOOptions = NULL;
- static int started_clean_event = 0;
- static const char *errmsg =
- "\tFailed to verify one of the swap directories, Check cache.log\n"
- "\tfor details. Run 'squid -z' to create swap directories\n"
- "\tif needed, or if running Squid for the first time.";
- IO->init();
-
- if (verifyCacheDirs())
- fatal(errmsg);
-
- openLog();
-
- rebuild();
-
- if (!started_clean_event) {
- eventAdd("UFS storeDirClean", CleanEvent, NULL, 15.0, 1);
- started_clean_event = 1;
- }
-
- (void) storeDirGetBlkSize(path, &fs.blksize);
-}
-
-void
-UFSSwapDir::create()
-{
- debugs(47, 3, "Creating swap space in " << path);
- createDirectory(path, 0);
- createSwapSubDirs();
-}
-
-UFSSwapDir::UFSSwapDir(char const *aType, const char *anIOType) : SwapDir(aType), \
IO(NULL), map(new FileMap()), suggest(0), swaplog_fd (-1), currentIOOptions(new \
ConfigOptionVector()), ioType(xstrdup(anIOType)), cur_size(0), \
n_disk_objects(0)
-{
- /* modulename is only set to disk modules that are built, by configure,
- * so the Find call should never return NULL here.
- */
- IO = new UFSStrategy(DiskIOModule::Find(anIOType)->createStrategy());
-}
-
-UFSSwapDir::~UFSSwapDir()
-{
- if (swaplog_fd > -1) {
- file_close(swaplog_fd);
- swaplog_fd = -1;
- }
-
- delete map;
-
- if (IO)
- delete IO;
-
- IO = NULL;
-
- safe_free(ioType);
-}
-
-void
-UFSSwapDir::dumpEntry(StoreEntry &e) const
-{
- debugs(47, 0, "UFSSwapDir::dumpEntry: FILENO "<< std::setfill('0') << std::hex \
<< std::uppercase << std::setw(8) << e.swap_filen);
- debugs(47, 0, "UFSSwapDir::dumpEntry: PATH " << fullPath(e.swap_filen, NULL) \
);
- e.dump(0);
-}
-
-/*
- * UFSSwapDir::doubleCheck
- *
- * This is called by storeCleanup() if -S was given on the command line.
- */
-bool
-UFSSwapDir::doubleCheck(StoreEntry & e)
-{
-
- struct stat sb;
-
- if (::stat(fullPath(e.swap_filen, NULL), &sb) < 0) {
- debugs(47, 0, "UFSSwapDir::doubleCheck: MISSING SWAP FILE");
- dumpEntry(e);
- return true;
- }
-
- if ((off_t)e.swap_file_sz != sb.st_size) {
- debugs(47, 0, "UFSSwapDir::doubleCheck: SIZE MISMATCH");
- debugs(47, 0, "UFSSwapDir::doubleCheck: ENTRY SIZE: " << e.swap_file_sz << \
", FILE SIZE: " << sb.st_size);
- dumpEntry(e);
- return true;
- }
-
- return false;
-}
-
-void
-UFSSwapDir::statfs(StoreEntry & sentry) const
-{
- int totl_kb = 0;
- int free_kb = 0;
- int totl_in = 0;
- int free_in = 0;
- int x;
- storeAppendPrintf(&sentry, "First level subdirectories: %d\n", l1);
- storeAppendPrintf(&sentry, "Second level subdirectories: %d\n", l2);
- storeAppendPrintf(&sentry, "Maximum Size: %" PRIu64 " KB\n", maxSize() >> 10);
- storeAppendPrintf(&sentry, "Current Size: %.2f KB\n", currentSize() / 1024.0);
- storeAppendPrintf(&sentry, "Percent Used: %0.2f%%\n",
- Math::doublePercent(currentSize(), maxSize()));
- storeAppendPrintf(&sentry, "Filemap bits in use: %d of %d (%d%%)\n",
- map->numFilesInMap(), map->capacity(),
- Math::intPercent(map->numFilesInMap(), map->capacity()));
- x = storeDirGetUFSStats(path, &totl_kb, &free_kb, &totl_in, &free_in);
-
- if (0 == x) {
- storeAppendPrintf(&sentry, "Filesystem Space in use: %d/%d KB (%d%%)\n",
- totl_kb - free_kb,
- totl_kb,
- Math::intPercent(totl_kb - free_kb, totl_kb));
- storeAppendPrintf(&sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n",
- totl_in - free_in,
- totl_in,
- Math::intPercent(totl_in - free_in, totl_in));
- }
-
- storeAppendPrintf(&sentry, "Flags:");
-
- if (flags.selected)
- storeAppendPrintf(&sentry, " SELECTED");
-
- if (flags.read_only)
- storeAppendPrintf(&sentry, " READ-ONLY");
-
- storeAppendPrintf(&sentry, "\n");
-
- IO->statfs(sentry);
-}
-
-void
-UFSSwapDir::maintain()
-{
- /* We can't delete objects while rebuilding swap */
-
- /* XXX FIXME each store should start maintaining as it comes online. */
-
- if (StoreController::store_dirs_rebuilding)
- return;
-
- StoreEntry *e = NULL;
-
- int removed = 0;
-
- RemovalPurgeWalker *walker;
-
- double f = (double) (currentSize() - minSize()) / (maxSize() - minSize());
-
- f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f;
-
- int max_scan = (int) (f * 400.0 + 100.0);
-
- int max_remove = (int) (f * 70.0 + 10.0);
-
- /*
- * This is kinda cheap, but so we need this priority hack?
- */
-
- debugs(47, 3, "storeMaintainSwapSpace: f=" << f << ", max_scan=" << max_scan << \
", max_remove=" << max_remove );
-
- walker = repl->PurgeInit(repl, max_scan);
-
- while (1) {
- if (currentSize() < minSize())
- break;
-
- if (removed >= max_remove)
- break;
-
- e = walker->Next(walker);
-
- if (!e)
- break; /* no more objects */
-
- ++removed;
-
- e->release();
- }
-
- walker->Done(walker);
- debugs(47, (removed ? 2 : 3), "UFSSwapDir::maintain: " << path <<
- " removed " << removed << "/" << max_remove << " f=" <<
- std::setprecision(4) << f << " max_scan=" << max_scan);
-}
-
-/*
- * UFSSwapDir::reference
- *
- * This routine is called whenever an object is referenced, so we can
- * maintain replacement information within the storage fs.
- */
-void
-UFSSwapDir::reference(StoreEntry &e)
-{
- debugs(47, 3, "UFSSwapDir::reference: referencing " << &e << " " << e.swap_dirn \
<< "/" << e.swap_filen);
-
- if (repl->Referenced)
- repl->Referenced(repl, &e, &e.repl);
-}
-
-/*
- * UFSSwapDir::dereference
- * This routine is called whenever the last reference to an object is
- * removed, to maintain replacement information within the storage fs.
- */
-bool
-UFSSwapDir::dereference(StoreEntry & e)
-{
- debugs(47, 3, "UFSSwapDir::dereference: referencing " << &e << " " << \
e.swap_dirn << "/" << e.swap_filen);
-
- if (repl->Dereferenced)
- repl->Dereferenced(repl, &e, &e.repl);
-
- return true; // keep e in the global store_table
-}
-
-StoreIOState::Pointer
-UFSSwapDir::createStoreIO(StoreEntry &e, StoreIOState::STFNCB * file_callback, \
StoreIOState::STIOCB * aCallback, void *callback_data)
-{
- return IO->create (this, &e, file_callback, aCallback, callback_data);
-}
-
-StoreIOState::Pointer
-UFSSwapDir::openStoreIO(StoreEntry &e, StoreIOState::STFNCB * file_callback, \
StoreIOState::STIOCB * aCallback, void *callback_data)
-{
- return IO->open (this, &e, file_callback, aCallback, callback_data);
-}
-
-int
-UFSSwapDir::mapBitTest(sfileno filn)
-{
- return map->testBit(filn);
-}
-
-void
-UFSSwapDir::mapBitSet(sfileno filn)
-{
- map->setBit(filn);
-}
-
-void
-UFSSwapDir::mapBitReset(sfileno filn)
-{
- /*
- * We have to test the bit before calling clearBit as
- * it doesn't do bounds checking and blindly assumes
- * filn is a valid file number, but it might not be because
- * the map is dynamic in size. Also clearing an already clear
- * bit puts the map counter of-of-whack.
- */
-
- if (map->testBit(filn))
- map->clearBit(filn);
-}
-
-int
-UFSSwapDir::mapBitAllocate()
-{
- int fn;
- fn = map->allocate(suggest);
- map->setBit(fn);
- suggest = fn + 1;
- return fn;
-}
-
-char *
-UFSSwapDir::swapSubDir(int subdirn)const
-{
- LOCAL_ARRAY(char, fullfilename, MAXPATHLEN);
- assert(0 <= subdirn && subdirn < l1);
- snprintf(fullfilename, MAXPATHLEN, "%s/%02X", path, subdirn);
- return fullfilename;
-}
-
-int
-UFSSwapDir::createDirectory(const char *aPath, int should_exist)
-{
- int created = 0;
-
- struct stat st;
- getCurrentTime();
-
- if (0 == ::stat(aPath, &st)) {
- if (S_ISDIR(st.st_mode)) {
- debugs(47, (should_exist ? 3 : 1), aPath << " exists");
- } else {
- fatalf("Swap directory %s is not a directory.", aPath);
- }
-
-#if _SQUID_MSWIN_
-
- } else if (0 == mkdir(aPath)) {
-#else
-
- } else if (0 == mkdir(aPath, 0755)) {
-#endif
- debugs(47, (should_exist ? 1 : 3), aPath << " created");
- created = 1;
- } else {
- fatalf("Failed to make swap directory %s: %s",
- aPath, xstrerror());
- }
-
- return created;
-}
-
-bool
-UFSSwapDir::pathIsDirectory(const char *aPath)const
-{
-
- struct stat sb;
-
- if (::stat(aPath, &sb) < 0) {
- debugs(47, 0, "" << aPath << ": " << xstrerror());
- return false;
- }
-
- if (S_ISDIR(sb.st_mode) == 0) {
- debugs(47, 0, "" << aPath << " is not a directory");
- return false;
- }
-
- return true;
-}
-
-/*
- * This function is called by commonUfsDirInit(). If this returns < 0,
- * then Squid exits, complains about swap directories not
- * existing, and instructs the admin to run 'squid -z'
- */
-bool
-UFSSwapDir::verifyCacheDirs()
-{
- if (!pathIsDirectory(path))
- return true;
-
- for (int j = 0; j < l1; ++j) {
- char const *aPath = swapSubDir(j);
-
- if (!pathIsDirectory(aPath))
- return true;
- }
-
- return false;
-}
-
-void
-UFSSwapDir::createSwapSubDirs()
-{
- LOCAL_ARRAY(char, name, MAXPATHLEN);
-
- for (int i = 0; i < l1; ++i) {
- snprintf(name, MAXPATHLEN, "%s/%02X", path, i);
-
- int should_exist;
-
- if (createDirectory(name, 0))
- should_exist = 0;
- else
- should_exist = 1;
-
- debugs(47, 1, "Making directories in " << name);
-
- for (int k = 0; k < l2; ++k) {
- snprintf(name, MAXPATHLEN, "%s/%02X/%02X", path, i, k);
- createDirectory(name, should_exist);
- }
- }
-}
-
-char *
-UFSSwapDir::logFile(char const *ext) const
-{
- LOCAL_ARRAY(char, lpath, MAXPATHLEN);
- LOCAL_ARRAY(char, pathtmp, MAXPATHLEN);
- LOCAL_ARRAY(char, digit, 32);
- char *pathtmp2;
-
- if (Config.Log.swap) {
- xstrncpy(pathtmp, path, MAXPATHLEN - 64);
- pathtmp2 = pathtmp;
-
- while ((pathtmp2 = strchr(pathtmp2, '/')) != NULL)
- *pathtmp2 = '.';
-
- while (strlen(pathtmp) && pathtmp[strlen(pathtmp) - 1] == '.')
- pathtmp[strlen(pathtmp) - 1] = '\0';
-
- for (pathtmp2 = pathtmp; *pathtmp2 == '.'; ++pathtmp2);
- snprintf(lpath, MAXPATHLEN - 64, Config.Log.swap, pathtmp2);
-
- if (strncmp(lpath, Config.Log.swap, MAXPATHLEN - 64) == 0) {
- strcat(lpath, ".");
- snprintf(digit, 32, "%02d", index);
- strncat(lpath, digit, 3);
- }
- } else {
- xstrncpy(lpath, path, MAXPATHLEN - 64);
- strcat(lpath, "/swap.state");
- }
-
- if (ext)
- strncat(lpath, ext, 16);
-
- return lpath;
-}
-
-void
-UFSSwapDir::openLog()
-{
- char *logPath;
- logPath = logFile();
- swaplog_fd = file_open(logPath, O_WRONLY | O_CREAT | O_BINARY);
-
- if (swaplog_fd < 0) {
- debugs(50, 1, "" << logPath << ": " << xstrerror());
- fatal("commonUfsDirOpenSwapLog: Failed to open swap log.");
- }
-
- debugs(50, 3, "Cache Dir #" << index << " log opened on FD " << swaplog_fd);
-
- if (0 == NumberOfUFSDirs)
- assert(NULL == UFSDirToGlobalDirMapping);
-
- ++NumberOfUFSDirs;
-
- assert(NumberOfUFSDirs <= Config.cacheSwap.n_configured);
-}
-
-void
-UFSSwapDir::closeLog()
-{
- if (swaplog_fd < 0) /* not open */
- return;
-
- file_close(swaplog_fd);
-
- debugs(47, 3, "Cache Dir #" << index << " log closed on FD " << swaplog_fd);
-
- swaplog_fd = -1;
-
- --NumberOfUFSDirs;
-
- assert(NumberOfUFSDirs >= 0);
-
- if (0 == NumberOfUFSDirs)
- safe_free(UFSDirToGlobalDirMapping);
-}
-
-bool
-UFSSwapDir::validL1(int anInt) const
-{
- return anInt < l1;
-}
-
-bool
-UFSSwapDir::validL2(int anInt) const
-{
- return anInt < l2;
-}
-
-/* Add a new object to the cache with empty memory copy and pointer to disk
- * use to rebuild store from disk. */
-StoreEntry *
-UFSSwapDir::addDiskRestore(const cache_key * key,
- sfileno file_number,
- uint64_t swap_file_sz,
- time_t expires,
- time_t timestamp,
- time_t lastref,
- time_t lastmod,
- uint32_t refcount,
- uint16_t newFlags,
- int clean)
-{
- StoreEntry *e = NULL;
- debugs(47, 5, "commonUfsAddDiskRestore: " << storeKeyText(key) <<
- ", fileno="<< std::setfill('0') << std::hex << std::uppercase << \
std::setw(8) << file_number);
- /* if you call this you'd better be sure file_number is not
- * already in use! */
- e = new StoreEntry();
- e->store_status = STORE_OK;
- e->setMemStatus(NOT_IN_MEMORY);
- e->swap_status = SWAPOUT_DONE;
- e->swap_filen = file_number;
- e->swap_dirn = index;
- e->swap_file_sz = swap_file_sz;
- e->lock_count = 0;
- e->lastref = lastref;
- e->timestamp = timestamp;
- e->expires = expires;
- e->lastmod = lastmod;
- e->refcount = refcount;
- e->flags = newFlags;
- EBIT_SET(e->flags, ENTRY_CACHABLE);
- EBIT_CLR(e->flags, RELEASE_REQUEST);
- EBIT_CLR(e->flags, KEY_PRIVATE);
- e->ping_status = PING_NONE;
- EBIT_CLR(e->flags, ENTRY_VALIDATED);
- mapBitSet(e->swap_filen);
- cur_size += fs.blksize * sizeInBlocks(e->swap_file_sz);
- ++n_disk_objects;
- e->hashInsert(key); /* do it after we clear KEY_PRIVATE */
- replacementAdd (e);
- return e;
-}
-
-void
-UFSSwapDir::undoAddDiskRestore(StoreEntry *e)
-{
- debugs(47, 5, HERE << *e);
- replacementRemove(e); // checks swap_dirn so do it before we invalidate it
- // Do not unlink the file as it might be used by a subsequent entry.
- mapBitReset(e->swap_filen);
- e->swap_filen = -1;
- e->swap_dirn = -1;
- cur_size -= fs.blksize * sizeInBlocks(e->swap_file_sz);
- --n_disk_objects;
-}
-
-void
-UFSSwapDir::rebuild()
-{
- ++StoreController::store_dirs_rebuilding;
- eventAdd("storeRebuild", RebuildState::RebuildStep, new RebuildState(this), 0.0, \
1);
-}
-
-void
-UFSSwapDir::closeTmpSwapLog()
-{
- char *swaplog_path = xstrdup(logFile(NULL));
- char *new_path = xstrdup(logFile(".new"));
- int fd;
- file_close(swaplog_fd);
-
- if (xrename(new_path, swaplog_path) < 0) {
- debugs(50, DBG_IMPORTANT, "ERROR: " << swaplog_path << ": " << xstrerror());
- fatalf("Failed to rename log file %s to %s.new", swaplog_path, \
swaplog_path);
- }
-
- fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY);
-
- if (fd < 0) {
- debugs(50, DBG_IMPORTANT, "ERROR: " << swaplog_path << ": " << xstrerror());
- fatalf("Failed to open swap log %s", swaplog_path);
- }
-
- safe_free(swaplog_path);
- safe_free(new_path);
- swaplog_fd = fd;
- debugs(47, 3, "Cache Dir #" << index << " log opened on FD " << fd);
-}
-
-FILE *
-UFSSwapDir::openTmpSwapLog(int *clean_flag, int *zero_flag)
-{
- char *swaplog_path = xstrdup(logFile(NULL));
- char *clean_path = xstrdup(logFile(".last-clean"));
- char *new_path = xstrdup(logFile(".new"));
-
- struct stat log_sb;
-
- struct stat clean_sb;
- FILE *fp;
- int fd;
-
- if (::stat(swaplog_path, &log_sb) < 0) {
- debugs(47, 1, "Cache Dir #" << index << ": No log file");
- safe_free(swaplog_path);
- safe_free(clean_path);
- safe_free(new_path);
- return NULL;
- }
-
- *zero_flag = log_sb.st_size == 0 ? 1 : 0;
- /* close the existing write-only FD */
-
- if (swaplog_fd >= 0)
- file_close(swaplog_fd);
-
- /* open a write-only FD for the new log */
- fd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
-
- if (fd < 0) {
- debugs(50, 1, "" << new_path << ": " << xstrerror());
- fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
- }
-
- swaplog_fd = fd;
-
- {
- const StoreSwapLogHeader header;
- MemBuf buf;
- buf.init(header.record_size, header.record_size);
- buf.append(reinterpret_cast<const char*>(&header), sizeof(header));
- // Pad to keep in sync with UFSSwapDir::writeCleanStart().
- memset(buf.space(), 0, header.gapSize());
- buf.appended(header.gapSize());
- file_write(swaplog_fd, -1, buf.content(), buf.contentSize(),
- NULL, NULL, buf.freeFunc());
- }
-
- /* open a read-only stream of the old log */
- fp = fopen(swaplog_path, "rb");
-
- if (fp == NULL) {
- debugs(50, 0, "" << swaplog_path << ": " << xstrerror());
- fatal("Failed to open swap log for reading");
- }
-
- memset(&clean_sb, '\0', sizeof(struct stat));
-
- if (::stat(clean_path, &clean_sb) < 0)
- *clean_flag = 0;
- else if (clean_sb.st_mtime < log_sb.st_mtime)
- *clean_flag = 0;
- else
- *clean_flag = 1;
-
- safeunlink(clean_path, 1);
-
- safe_free(swaplog_path);
-
- safe_free(clean_path);
-
- safe_free(new_path);
-
- return fp;
-}
-
-class UFSCleanLog : public SwapDir::CleanLog
-{
-
-public:
- UFSCleanLog(SwapDir *);
- virtual const StoreEntry *nextEntry();
- virtual void write(StoreEntry const &);
- char *cur;
- char *newLog;
- char *cln;
- char *outbuf;
- off_t outbuf_offset;
- int fd;
- RemovalPolicyWalker *walker;
- SwapDir *sd;
-};
-
#define CLEAN_BUF_SZ 16384
-
-UFSCleanLog::UFSCleanLog(SwapDir *aSwapDir) : \
cur(NULL),newLog(NULL),cln(NULL),outbuf(NULL),
- outbuf_offset(0), fd(-1),walker(NULL), sd(aSwapDir)
-{}
-
-/*
- * Begin the process to write clean cache state. For AUFS this means
- * opening some log files and allocating write buffers. Return 0 if
- * we succeed, and assign the 'func' and 'data' return pointers.
- */
-int
-UFSSwapDir::writeCleanStart()
-{
- UFSCleanLog *state = new UFSCleanLog(this);
- StoreSwapLogHeader header;
-#if HAVE_FCHMOD
-
- struct stat sb;
-#endif
-
- cleanLog = NULL;
- state->newLog = xstrdup(logFile(".clean"));
- state->fd = file_open(state->newLog, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
-
- if (state->fd < 0) {
- xfree(state->newLog);
- delete state;
- return -1;
- }
-
- state->cur = xstrdup(logFile(NULL));
- state->cln = xstrdup(logFile(".last-clean"));
- state->outbuf = (char *)xcalloc(CLEAN_BUF_SZ, 1);
- state->outbuf_offset = 0;
- /*copy the header */
- memcpy(state->outbuf, &header, sizeof(StoreSwapLogHeader));
- // Leave a gap to keep in sync with UFSSwapDir::openTmpSwapLog().
- memset(state->outbuf + sizeof(StoreSwapLogHeader), 0, header.gapSize());
- state->outbuf_offset += header.record_size;
-
- state->walker = repl->WalkInit(repl);
- ::unlink(state->cln);
- debugs(47, 3, "storeDirWriteCleanLogs: opened " << state->newLog << ", FD " << \
state->fd);
-#if HAVE_FCHMOD
-
- if (::stat(state->cur, &sb) == 0)
- fchmod(state->fd, sb.st_mode);
-
-#endif
-
-
- cleanLog = state;
- return 0;
-}
-
-/*
- * Get the next entry that is a candidate for clean log writing
- */
-const StoreEntry *
-UFSCleanLog::nextEntry()
-{
- const StoreEntry *entry = NULL;
-
- if (walker)
- entry = walker->Next(walker);
-
- return entry;
-}
-
-/*
- * "write" an entry to the clean log file.
- */
-void
-UFSCleanLog::write(StoreEntry const &e)
-{
- StoreSwapLogData s;
- static size_t ss = sizeof(StoreSwapLogData);
- s.op = (char) SWAP_LOG_ADD;
- s.swap_filen = e.swap_filen;
- s.timestamp = e.timestamp;
- s.lastref = e.lastref;
- s.expires = e.expires;
- s.lastmod = e.lastmod;
- s.swap_file_sz = e.swap_file_sz;
- s.refcount = e.refcount;
- s.flags = e.flags;
- memcpy(&s.key, e.key, SQUID_MD5_DIGEST_LENGTH);
- s.finalize();
- memcpy(outbuf + outbuf_offset, &s, ss);
- outbuf_offset += ss;
- /* buffered write */
-
- if (outbuf_offset + ss >= CLEAN_BUF_SZ) {
- if (FD_WRITE_METHOD(fd, outbuf, outbuf_offset) < 0) {
- /* XXX This error handling should probably move up to the caller */
- debugs(50, 0, "storeDirWriteCleanLogs: " << newLog << ": write: " << \
xstrerror());
- debugs(50, 0, "storeDirWriteCleanLogs: Current swap logfile not \
replaced.");
- file_close(fd);
- fd = -1;
- unlink(newLog);
- sd->cleanLog = NULL;
- delete this;
- return;
- }
-
- outbuf_offset = 0;
- }
-}
-
-void
-UFSSwapDir::writeCleanDone()
-{
- UFSCleanLog *state = (UFSCleanLog *)cleanLog;
- int fd;
-
- if (NULL == state)
- return;
-
- if (state->fd < 0)
- return;
-
- state->walker->Done(state->walker);
-
- if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) {
- debugs(50, 0, "storeDirWriteCleanLogs: " << state->newLog << ": write: " << \
xstrerror());
- debugs(50, 0, "storeDirWriteCleanLogs: Current swap logfile not replaced.");
- file_close(state->fd);
- state->fd = -1;
- ::unlink(state->newLog);
- }
-
- safe_free(state->outbuf);
- /*
- * You can't rename open files on Microsoft "operating systems"
- * so we have to close before renaming.
- */
- closeLog();
- /* save the fd value for a later test */
- fd = state->fd;
- /* rename */
-
- if (state->fd >= 0) {
-#if _SQUID_OS2_ || _SQUID_WINDOWS_
- file_close(state->fd);
- state->fd = -1;
-#endif
-
- xrename(state->newLog, state->cur);
- }
-
- /* touch a timestamp file if we're not still validating */
- if (StoreController::store_dirs_rebuilding)
- (void) 0;
- else if (fd < 0)
- (void) 0;
- else
- file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY));
-
- /* close */
- safe_free(state->cur);
-
- safe_free(state->newLog);
-
- safe_free(state->cln);
-
- if (state->fd >= 0)
- file_close(state->fd);
-
- state->fd = -1;
-
- delete state;
-
- cleanLog = NULL;
-}
-
-static void
-FreeObject(void *address)
-{
- StoreSwapLogData *anObject = static_cast <StoreSwapLogData *>(address);
- delete anObject;
-}
-
-void
-UFSSwapDir::logEntry(const StoreEntry & e, int op) const
-{
- StoreSwapLogData *s = new StoreSwapLogData;
- s->op = (char) op;
- s->swap_filen = e.swap_filen;
- s->timestamp = e.timestamp;
- s->lastref = e.lastref;
- s->expires = e.expires;
- s->lastmod = e.lastmod;
- s->swap_file_sz = e.swap_file_sz;
- s->refcount = e.refcount;
- s->flags = e.flags;
- memcpy(s->key, e.key, SQUID_MD5_DIGEST_LENGTH);
- s->finalize();
- file_write(swaplog_fd,
- -1,
- s,
- sizeof(StoreSwapLogData),
- NULL,
- NULL,
- FreeObject);
-}
-
-static QS rev_int_sort;
-static int
-rev_int_sort(const void *A, const void *B)
-{
- const int *i1 = (const int *)A;
- const int *i2 = (const int *)B;
- return *i2 - *i1;
-}
-
-int
-UFSSwapDir::DirClean(int swap_index)
-{
- DIR *dir_pointer = NULL;
-
- LOCAL_ARRAY(char, p1, MAXPATHLEN + 1);
- LOCAL_ARRAY(char, p2, MAXPATHLEN + 1);
-
- int files[20];
- int swapfileno;
- int fn; /* same as swapfileno, but with dirn bits set */
- int n = 0;
- int k = 0;
- int N0, N1, N2;
- int D0, D1, D2;
- UFSSwapDir *SD;
- N0 = NumberOfUFSDirs;
- D0 = UFSDirToGlobalDirMapping[swap_index % N0];
- SD = dynamic_cast<UFSSwapDir *>(INDEXSD(D0));
- assert (SD);
- N1 = SD->l1;
- D1 = (swap_index / N0) % N1;
- N2 = SD->l2;
- D2 = ((swap_index / N0) / N1) % N2;
- snprintf(p1, MAXPATHLEN, "%s/%02X/%02X",
- SD->path, D1, D2);
- debugs(36, 3, "storeDirClean: Cleaning directory " << p1);
- dir_pointer = opendir(p1);
-
- if (dir_pointer == NULL) {
- if (errno == ENOENT) {
- debugs(36, 0, "storeDirClean: WARNING: Creating " << p1);
-#if _SQUID_MSWIN_
-
- if (mkdir(p1) == 0)
-#else
-
- if (mkdir(p1, 0777) == 0)
-#endif
-
- return 0;
- }
-
- debugs(50, 0, "storeDirClean: " << p1 << ": " << xstrerror());
- safeunlink(p1, 1);
- return 0;
- }
-
- dirent_t *de;
- while ((de = readdir(dir_pointer)) != NULL && k < 20) {
- if (sscanf(de->d_name, "%X", &swapfileno) != 1)
- continue;
-
- fn = swapfileno; /* XXX should remove this cruft ! */
-
- if (SD->validFileno(fn, 1))
- if (SD->mapBitTest(fn))
- if (UFSSwapDir::FilenoBelongsHere(fn, D0, D1, D2))
- continue;
-
- files[k] = swapfileno;
- ++k;
- }
-
- closedir(dir_pointer);
-
- if (k == 0)
- return 0;
-
- qsort(files, k, sizeof(int), rev_int_sort);
-
- if (k > 10)
- k = 10;
-
- for (n = 0; n < k; ++n) {
- debugs(36, 3, "storeDirClean: Cleaning file "<< std::setfill('0') << \
std::hex << std::uppercase << std::setw(8) << files[n]);
- snprintf(p2, MAXPATHLEN + 1, "%s/%08X", p1, files[n]);
- safeunlink(p2, 0);
- ++statCounter.swap.files_cleaned;
- }
-
- debugs(36, 3, "Cleaned " << k << " unused files from " << p1);
- return k;
-}
-
-void
-UFSSwapDir::CleanEvent(void *unused)
-{
- static int swap_index = 0;
- int i;
- int j = 0;
- int n = 0;
- /*
- * Assert that there are UFS cache_dirs configured, otherwise
- * we should never be called.
- */
- assert(NumberOfUFSDirs);
-
- if (NULL == UFSDirToGlobalDirMapping) {
- SwapDir *sd;
- /*
- * Initialize the little array that translates UFS cache_dir
- * number into the Config.cacheSwap.swapDirs array index.
- */
- UFSDirToGlobalDirMapping = (int *)xcalloc(NumberOfUFSDirs, \
sizeof(*UFSDirToGlobalDirMapping));
-
- for (i = 0, n = 0; i < Config.cacheSwap.n_configured; ++i) {
- /* This is bogus, the controller should just clean each instance once */
- sd = dynamic_cast <SwapDir *>(INDEXSD(i));
-
- if (!UFSSwapDir::IsUFSDir(sd))
- continue;
-
- UFSSwapDir *usd = dynamic_cast<UFSSwapDir *>(sd);
-
- assert (usd);
-
- UFSDirToGlobalDirMapping[n] = i;
- ++n;
-
- j += (usd->l1 * usd->l2);
- }
-
- assert(n == NumberOfUFSDirs);
- /*
- * Start the commonUfsDirClean() swap_index with a random
- * value. j equals the total number of UFS level 2
- * swap directories
- */
- swap_index = (int) (squid_random() % j);
- }
-
- /* if the rebuild is finished, start cleaning directories. */
- if (0 == StoreController::store_dirs_rebuilding) {
- n = DirClean(swap_index);
- ++swap_index;
- }
-
- eventAdd("storeDirClean", CleanEvent, NULL,
- 15.0 * exp(-0.25 * n), 1);
-}
-
-int
-UFSSwapDir::IsUFSDir(SwapDir * sd)
-{
- UFSSwapDir *mySD = dynamic_cast<UFSSwapDir *>(sd);
- return mySD ? 1 : 0 ;
-}
-
-/*
- * Does swapfile number 'fn' belong in cachedir #F0,
- * level1 dir #F1, level2 dir #F2?
- * XXX: this is broken - it assumes all cache dirs use the same
- * l1 and l2 scheme. -RBC 20021215. Partial fix is in place -
- * if not UFSSwapDir return 0;
- */
-int
-UFSSwapDir::FilenoBelongsHere(int fn, int F0, int F1, int F2)
-{
- int D1, D2;
- int L1, L2;
- int filn = fn;
- assert(F0 < Config.cacheSwap.n_configured);
- assert (UFSSwapDir::IsUFSDir (dynamic_cast<SwapDir *>(INDEXSD(F0))));
- UFSSwapDir *sd = dynamic_cast<UFSSwapDir *>(INDEXSD(F0));
-
- if (!sd)
- return 0;
-
- L1 = sd->l1;
-
- L2 = sd->l2;
-
- D1 = ((filn / L2) / L2) % L1;
-
- if (F1 != D1)
- return 0;
-
- D2 = (filn / L2) % L2;
-
- if (F2 != D2)
- return 0;
-
- return 1;
-}
-
-
-int
-UFSSwapDir::validFileno(sfileno filn, int flag) const
-{
- if (filn < 0)
- return 0;
-
- /*
- * If flag is set it means out-of-range file number should
- * be considered invalid.
- */
- if (flag)
- if (filn > map->capacity())
- return 0;
-
- return 1;
-}
-
-
-
-/*
- * UFSSwapDir::unlinkFile
- *
- * This routine unlinks a file and pulls it out of the bitmap.
- * It used to be in commonUfsUnlink(), however an interface change
- * forced this bit of code here. Eeek.
- */
-void
-UFSSwapDir::unlinkFile(sfileno f)
-{
- debugs(79, 3, "UFSSwapDir::unlinkFile: unlinking fileno " << std::setfill('0') \
<<
- std::hex << std::uppercase << std::setw(8) << f << " '" <<
- fullPath(f,NULL) << "'");
- /* commonUfsDirMapBitReset(this, f); */
- IO->unlinkFile(fullPath(f,NULL));
-}
-
-bool
-UFSSwapDir::unlinkdUseful() const
-{
- // unlinkd may be useful only in workers
- return IamWorkerProcess() && IO->io->unlinkdUseful();
-}
-
-void
-UFSSwapDir::unlink(StoreEntry & e)
-{
- debugs(79, 3, "storeUfsUnlink: dirno " << index << ", fileno "<<
- std::setfill('0') << std::hex << std::uppercase << std::setw(8) << \
e.swap_filen);
- if (e.swap_status == SWAPOUT_DONE) {
- cur_size -= fs.blksize * sizeInBlocks(e.swap_file_sz);
- --n_disk_objects;
- }
- replacementRemove(&e);
- mapBitReset(e.swap_filen);
- UFSSwapDir::unlinkFile(e.swap_filen);
-}
-
-/*
- * Add and remove the given StoreEntry from the replacement policy in
- * use.
- */
-
-void
-UFSSwapDir::replacementAdd(StoreEntry * e)
-{
- debugs(47, 4, "UFSSwapDir::replacementAdd: added node " << e << " to dir " << \
index);
- repl->Add(repl, e, &e->repl);
-}
-
-
-void
-UFSSwapDir::replacementRemove(StoreEntry * e)
-{
- StorePointer SD;
-
- if (e->swap_dirn < 0)
- return;
-
- SD = INDEXSD(e->swap_dirn);
-
- assert (dynamic_cast<UFSSwapDir *>(SD.getRaw()) == this);
-
- debugs(47, 4, "UFSSwapDir::replacementRemove: remove node " << e << " from dir " \
<< index);
-
- repl->Remove(repl, e, &e->repl);
-}
-
-void
-UFSSwapDir::dump(StoreEntry & entry) const
-{
- storeAppendPrintf(&entry, " %" PRIu64 " %d %d", maxSize() >> 20, l1, l2);
- dumpOptions(&entry);
-}
-
-char *
-UFSSwapDir::fullPath(sfileno filn, char *fullpath) const
-{
- LOCAL_ARRAY(char, fullfilename, MAXPATHLEN);
- int L1 = l1;
- int L2 = l2;
-
- if (!fullpath)
- fullpath = fullfilename;
-
- fullpath[0] = '\0';
-
- snprintf(fullpath, MAXPATHLEN, "%s/%02X/%02X/%08X",
- path,
- ((filn / L2) / L2) % L1,
- (filn / L2) % L2,
- filn);
-
- return fullpath;
-}
-
-int
-UFSSwapDir::callback()
-{
- return IO->callback();
-}
-
-void
-UFSSwapDir::sync()
-{
- IO->sync();
-}
-
-void
-UFSSwapDir::swappedOut(const StoreEntry &e)
-{
- cur_size += fs.blksize * sizeInBlocks(e.swap_file_sz);
- ++n_disk_objects;
-}
-
-StoreSearch *
-UFSSwapDir::search(String const url, HttpRequest *request)
-{
- if (url.size())
- fatal ("Cannot search by url yet\n");
-
- return new StoreSearchUFS (this);
-}
-
-CBDATA_CLASS_INIT(StoreSearchUFS);
-StoreSearchUFS::StoreSearchUFS(RefCount<UFSSwapDir> aSwapDir) : sd(aSwapDir), walker \
(sd->repl->WalkInit(sd->repl)), current (NULL), _done (false)
-{}
-
-/* do not link
-StoreSearchUFS::StoreSearchUFS(StoreSearchUFS const &);
-*/
-
-StoreSearchUFS::~StoreSearchUFS()
-{
- walker->Done(walker);
- walker = NULL;
-}
-
-void
-StoreSearchUFS::next(void (aCallback)(void *cbdata), void *aCallbackArgs)
-{
- next();
- aCallback(aCallbackArgs);
-}
-
-bool
-StoreSearchUFS::next()
-{
- /* the walker API doesn't make sense. the store entries referred to are already \
readwrite
- * from their hash table entries
- */
-
- if (walker)
- current = const_cast<StoreEntry *>(walker->Next(walker));
-
- if (current == NULL)
- _done = true;
-
- return current != NULL;
-}
-
-bool
-StoreSearchUFS::error() const
-{
- return false;
-}
-
-bool
-StoreSearchUFS::isDone() const
-{
- return _done;
-}
-
-StoreEntry *
-StoreSearchUFS::currentItem()
-{
- return current;
-}
=== modified file 'src/fs/ufs/store_io_ufs.cc'
--- src/fs/ufs/store_io_ufs.cc 2012-01-20 18:55:04 +0000
+++ src/fs/ufs/store_io_ufs.cc 2012-07-31 21:45:27 +0000
@@ -35,7 +35,6 @@
#include "squid-old.h"
#include "Store.h"
-#include "ufscommon.h"
#include "Generic.h"
#include "DiskIO/DiskFile.h"
#include "DiskIO/DiskIOStrategy.h"
@@ -43,45 +42,9 @@
#include "DiskIO/WriteRequest.h"
#include "SwapDir.h"
-
-bool
-UFSStrategy::shedLoad()
-{
- return io->shedLoad();
-}
-
-int
-UFSStrategy::load()
-{
- return io->load();
-}
-
-UFSStrategy::UFSStrategy (DiskIOStrategy *anIO) : io(anIO)
-{}
-
-UFSStrategy::~UFSStrategy ()
-{
- delete io;
-}
-
-StoreIOState::Pointer
-UFSStrategy::createState(SwapDir *SD, StoreEntry *e, StoreIOState::STIOCB * \
aCallback, void *callback_data) const
-{
- return new UFSStoreState (SD, e, aCallback, callback_data);
-}
-
-DiskFile::Pointer
-UFSStrategy::newFile (char const *path)
-{
- return io->newFile(path);
-}
-
-
-void
-UFSStrategy::unlinkFile(char const *path)
-{
- io->unlinkFile(path);
-}
+#include "UFSStrategy.h"
+#include "UFSStoreState.h"
+
CBDATA_CLASS_INIT(UFSStoreState);
@@ -554,109 +517,3 @@
linklistPush(&pending_writes, q);
}
-StoreIOState::Pointer
-UFSStrategy::open(SwapDir * SD, StoreEntry * e, StoreIOState::STFNCB * \
file_callback,
- StoreIOState::STIOCB * aCallback, void *callback_data)
-{
- assert (((UFSSwapDir *)SD)->IO == this);
- debugs(79, 3, "UFSStrategy::open: fileno "<< std::setfill('0') << std::hex << \
std::uppercase << std::setw(8) << e->swap_filen);
-
- /* to consider: make createstate a private UFSStrategy call */
- StoreIOState::Pointer sio = createState (SD, e, aCallback, callback_data);
-
- sio->mode |= O_RDONLY;
-
- UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw());
-
- assert (state);
-
- char *path = ((UFSSwapDir *)SD)->fullPath(e->swap_filen, NULL);
-
- DiskFile::Pointer myFile = newFile (path);
-
- if (myFile.getRaw() == NULL)
- return NULL;
-
- state->theFile = myFile;
-
- state->opening = true;
-
- myFile->open (sio->mode, 0644, state);
-
- if (myFile->error())
- return NULL;
-
- return sio;
-}
-
-StoreIOState::Pointer
-UFSStrategy::create(SwapDir * SD, StoreEntry * e, StoreIOState::STFNCB * \
file_callback,
- StoreIOState::STIOCB * aCallback, void *callback_data)
-{
- assert (((UFSSwapDir *)SD)->IO == this);
- /* Allocate a number */
- sfileno filn = ((UFSSwapDir *)SD)->mapBitAllocate();
- debugs(79, 3, "UFSStrategy::create: fileno "<< std::setfill('0') << std::hex << \
std::uppercase << std::setw(8) << filn);
-
- /* Shouldn't we handle a 'bitmap full' error here? */
-
- StoreIOState::Pointer sio = createState (SD, e, aCallback, callback_data);
-
- sio->mode |= O_WRONLY | O_CREAT | O_TRUNC;
-
- sio->swap_filen = filn;
-
- UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw());
-
- assert (state);
-
- char *path = ((UFSSwapDir *)SD)->fullPath(filn, NULL);
-
- DiskFile::Pointer myFile = newFile (path);
-
- if (myFile.getRaw() == NULL) {
- ((UFSSwapDir *)SD)->mapBitReset (filn);
- return NULL;
- }
-
- state->theFile = myFile;
-
- state->creating = true;
-
- myFile->create (state->mode, 0644, state);
-
- if (myFile->error()) {
- ((UFSSwapDir *)SD)->mapBitReset (filn);
- return NULL;
- }
-
- /* now insert into the replacement policy */
- ((UFSSwapDir *)SD)->replacementAdd(e);
-
- return sio;
-}
-
-int
-UFSStrategy::callback()
-{
- return io->callback();
-}
-
-void
-UFSStrategy::init()
-{
- io->init();
-}
-
-void
-UFSStrategy::sync()
-{
- io->sync();
-}
-
-void
-UFSStrategy::statfs(StoreEntry & sentry)const
-{
- io->statfs(sentry);
-}
-
=== removed file 'src/fs/ufs/ufscommon.cc'
--- src/fs/ufs/ufscommon.cc 2012-07-23 07:02:06 +0000
+++ src/fs/ufs/ufscommon.cc 1970-01-01 00:00:00 +0000
@@ -1,841 +0,0 @@
-/*
- * $Id$
- *
- * DEBUG: section 47 Store Directory Routines
- * AUTHOR: Robert Collins
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
- */
-
-#include "squid.h"
-#include "ufscommon.h"
-#include "Store.h"
-#include "fde.h"
-#include "SquidTime.h"
-#include "StoreMeta.h"
-#include "Generic.h"
-#include "StoreMetaUnpacker.h"
-#include "RefCount.h"
-#include "StoreSwapLogData.h"
-#include "swap_log_op.h"
-
-
-CBDATA_CLASS_INIT(RebuildState);
-
-/// Parse a swap header entry created on a system with 32-bit size_t and sfileno
-/// this is typical of 32-bit systems without large file support
-/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still.
-class UFSSwapLogParser_v1_32bs:public UFSSwapLogParser
-{
-public:
- /// version 1 cache swap.state entry with 32-bit size_t (swap_file_sz)
- /// time_t an sfileno have no variation from the v1 baseline format
- struct StoreSwapLogDataOld {
- char op;
- sfileno swap_filen;
- time_t timestamp;
- time_t lastref;
- time_t expires;
- time_t lastmod;
- uint32_t swap_file_sz;
- uint16_t refcount;
- uint16_t flags;
- unsigned char key[SQUID_MD5_DIGEST_LENGTH];
- };
- UFSSwapLogParser_v1_32bs(FILE *fp):UFSSwapLogParser(fp) {
- record_size = sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld);
- }
- /// Convert the on-disk 32-bit format to our current format while reading
- bool ReadRecord(StoreSwapLogData &swapData) {
- UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld readData;
- int bytes = sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld);
-
- assert(log);
-
- if (fread(&readData, bytes, 1, log) != 1) {
- return false;
- }
- swapData.op = readData.op;
- swapData.swap_filen = readData.swap_filen;
- swapData.timestamp = readData.timestamp;
- swapData.lastref = readData.lastref;
- swapData.expires = readData.expires;
- swapData.lastmod = readData.lastmod;
- swapData.swap_file_sz = readData.swap_file_sz;
- swapData.refcount = readData.refcount;
- swapData.flags = readData.flags;
- memcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH);
- return true;
- }
-};
-
-#if UNUSED_CODE
-/// Parse a swap header entry created on a system with 32-bit size_t, time_t and \
sfileno
-/// this is typical of 32-bit systems without large file support and with old \
kernels
-/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still.
-class UFSSwapLogParser_v1_32bst:public UFSSwapLogParser
-{
-public:
- /// version 1 cache swap.state entry with 32-bit size_t (swap_file_sz)
- /// time_t also differs
- /// sfileno has no variation from the v1 baseline format
- struct StoreSwapLogDataOld {
- char op;
- sfileno swap_filen;
- int32_t timestamp;
- int32_t lastref;
- int32_t expires;
- int32_t lastmod;
- uint32_t swap_file_sz;
- uint16_t refcount;
- uint16_t flags;
- unsigned char key[SQUID_MD5_DIGEST_LENGTH];
- };
- UFSSwapLogParser_v1_32bst(FILE *fp):UFSSwapLogParser(fp) {
- record_size = sizeof(UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld);
- }
- /// Convert the on-disk 32-bit format to our current format while reading
- bool ReadRecord(StoreSwapLogData &swapData) {
- UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld readData;
- int bytes = sizeof(UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld);
-
- assert(log);
-
- if (fread(&readData, bytes, 1, log) != 1) {
- return false;
- }
- swapData.op = readData.op;
- swapData.swap_filen = readData.swap_filen;
- swapData.timestamp = readData.timestamp;
- swapData.lastref = readData.lastref;
- swapData.expires = readData.expires;
- swapData.lastmod = readData.lastmod;
- swapData.swap_file_sz = readData.swap_file_sz;
- swapData.refcount = readData.refcount;
- swapData.flags = readData.flags;
- memcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH);
- return true;
- }
-};
-
-/// Parse a swap header entry created on a system with 64-bit size_t and sfileno
-/// this is typical of 64-bit systems prior to this patch fixing sfileno to 32-bits
-/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still.
-class UFSSwapLogParser_v1_64bfn:public UFSSwapLogParser
-{
-public:
- /// version 1 cache swap.state entry with 64-bit sfileno
- struct StoreSwapLogDataOld {
- char op;
- int64_t swap_filen;
- time_t timestamp;
- time_t lastref;
- time_t expires;
- time_t lastmod;
- uint64_t swap_file_sz;
- uint16_t refcount;
- uint16_t flags;
- unsigned char key[SQUID_MD5_DIGEST_LENGTH];
- };
- UFSSwapLogParser_v1_64bfn(FILE *fp):UFSSwapLogParser(fp) {
- record_size = sizeof(UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld);
- }
- /// Convert the on-disk 64-bit format to our current format while reading
- bool ReadRecord(StoreSwapLogData &swapData) {
- UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld readData;
- int bytes = sizeof(UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld);
-
- assert(log);
-
- if (fread(&readData, bytes, 1, log) != 1) {
- return false;
- }
- swapData.op = readData.op;
- if ((readData.swap_filen>>32) != 0) {
- fatalf("File ID on record is greater than maximum cache file ID.");
- }
- swapData.swap_filen = (int32_t)readData.swap_filen;
- swapData.timestamp = readData.timestamp;
- swapData.lastref = readData.lastref;
- swapData.expires = readData.expires;
- swapData.lastmod = readData.lastmod;
- swapData.swap_file_sz = readData.swap_file_sz;
- swapData.refcount = readData.refcount;
- swapData.flags = readData.flags;
- memcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH);
- return true;
- }
-};
-
-class UFSSwapLogParser_v1:public UFSSwapLogParser
-{
-public:
- UFSSwapLogParser_v1(FILE *fp):UFSSwapLogParser(fp) {
- record_size = sizeof(StoreSwapLogData);
- }
- bool ReadRecord(StoreSwapLogData &swapData);
-};
-
-
-bool UFSSwapLogParser_v1::ReadRecord(StoreSwapLogData &swapData)
-{
- int bytes = sizeof(StoreSwapLogData);
-
- assert(log);
-
- if (fread(&swapData, bytes, 1, log) != 1) {
- return false;
- }
- return true;
-}
-#endif /* UNUSED_CODE */
-
-/// swap.state v2 log parser
-class UFSSwapLogParser_v2: public UFSSwapLogParser
-{
-public:
- UFSSwapLogParser_v2(FILE *fp): UFSSwapLogParser(fp) {
- record_size = sizeof(StoreSwapLogData);
- }
- bool ReadRecord(StoreSwapLogData &swapData) {
- assert(log);
- return fread(&swapData, sizeof(StoreSwapLogData), 1, log) == 1;
- }
-};
-
-
-UFSSwapLogParser *UFSSwapLogParser::GetUFSSwapLogParser(FILE *fp)
-{
- StoreSwapLogHeader header;
-
- assert(fp);
-
- if (fread(&header, sizeof(StoreSwapLogHeader), 1, fp) != 1)
- return NULL;
-
- if (header.op != SWAP_LOG_VERSION) {
- debugs(47, 1, "Old swap file detected...");
- fseek(fp, 0, SEEK_SET);
- return new UFSSwapLogParser_v1_32bs(fp); // Um. 32-bits except time_t, and \
can't determine that.
- }
-
- debugs(47, 2, "Swap file version: " << header.version);
-
- if (header.version == 1) {
- if (fseek(fp, header.record_size, SEEK_SET) != 0)
- return NULL;
-
- debugs(47, DBG_IMPORTANT, "Rejecting swap file v1 to avoid cache " <<
- "index corruption. Forcing a full cache index rebuild. " <<
- "See Squid bug #3441.");
- return NULL;
-
-#if UNUSED_CODE
- // baseline
- // 32-bit sfileno
- // native time_t (hopefully 64-bit)
- // 64-bit file size
- if (header.record_size == sizeof(StoreSwapLogData)) {
- debugs(47, 1, "Version 1 of swap file with LFS support detected... ");
- return new UFSSwapLogParser_v1(fp);
- }
-
- // which means we have a 3-way grid of permutations to import (yuck!)
- // 1) sfileno 32-bit / 64-bit (64-bit was broken)
- // 2) time_t 32-bit / 64-bit
- // 3) size_t 32-bit / 64-bit (32-bit was pre-LFS)
-
- // 32-bit systems...
- // only LFS (size_t) differs from baseline
- if (header.record_size == sizeof(struct \
UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld)) {
- debugs(47, 1, "Version 1 (32-bit) swap file without LFS support \
detected... ");
- return new UFSSwapLogParser_v1_32bs(fp);
- }
- // LFS (size_t) and timestamps (time_t) differs from baseline
- if (header.record_size == sizeof(struct \
UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld)) {
- debugs(47, 1, "Version 1 (32-bit) swap file with short timestamps and \
without LFS support detected... ");
- return new UFSSwapLogParser_v1_32bst(fp);
- }
- // No downgrade for 64-bit timestamps to 32-bit.
-
- // 64-bit systems
- // sfileno was 64-bit for a some builds
- if (header.record_size == sizeof(struct \
UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld)) {
- debugs(47, 1, "Version 1 (64-bit) swap file with broken sfileno \
detected... ");
- return new UFSSwapLogParser_v1_64bfn(fp);
- }
- // NP: 64-bit system with 32-bit size_t/time_t are not handled.
-
- debugs(47, 1, "WARNING: The swap file has wrong format!... ");
- debugs(47, 1, "NOTE: Cannot safely downgrade caches to short (32-bit) \
timestamps.");
- return NULL;
-#endif
- }
-
- if (header.version >= 2) {
- if (!header.sane()) {
- debugs(47, DBG_IMPORTANT, "ERROR: Corrupted v" << header.version <<
- " swap file header.");
- return NULL;
- }
-
- if (fseek(fp, header.record_size, SEEK_SET) != 0)
- return NULL;
-
- if (header.version == 2)
- return new UFSSwapLogParser_v2(fp);
- }
-
- // TODO: v3: write to disk in network-order bytes for the larger fields?
-
- debugs(47, DBG_IMPORTANT, "Unknown swap file version: " << header.version);
- return NULL;
-}
-
-int UFSSwapLogParser::SwapLogEntries()
-{
- struct stat sb;
-
- if (log_entries >= 0)
- return log_entries;
-
- if (log && record_size && 0 == fstat(fileno(log), &sb)) {
- log_entries = sb.st_size/record_size;
- return log_entries;
- }
-
- return 0;
-}
-
-
-
-
-RebuildState::RebuildState (RefCount<UFSSwapDir> aSwapDir) : sd \
(aSwapDir),LogParser(NULL), e(NULL), fromLog(true), _done (false)
-{
- /*
- * If the swap.state file exists in the cache_dir, then
- * we'll use commonUfsDirRebuildFromSwapLog(), otherwise we'll
- * use commonUfsDirRebuildFromDirectory() to open up each file
- * and suck in the meta data.
- */
- int clean = 0;
- int zeroLengthLog = 0;
- FILE *fp = sd->openTmpSwapLog(&clean, &zeroLengthLog);
-
- if (fp && !zeroLengthLog)
- LogParser = UFSSwapLogParser::GetUFSSwapLogParser(fp);
-
- if (LogParser == NULL ) {
- fromLog = false;
-
- if (fp != NULL)
- fclose(fp);
-
- } else {
- fromLog = true;
- flags.clean = (unsigned int) clean;
- }
-
- if (!clean)
- flags.need_to_validate = 1;
-
- debugs(47, DBG_IMPORTANT, "Rebuilding storage in " << sd->path << " (" <<
- (clean ? "clean log" : (LogParser ? "dirty log" : "no log")) << ")");
-}
-
-RebuildState::~RebuildState()
-{
- sd->closeTmpSwapLog();
-
- if (LogParser)
- delete LogParser;
-}
-
-void
-RebuildState::RebuildStep(void *data)
-{
- RebuildState *rb = (RebuildState *)data;
- rb->rebuildStep();
-
- if (!rb->isDone())
- eventAdd("storeRebuild", RebuildStep, rb, 0.01, 1);
- else {
- -- StoreController::store_dirs_rebuilding;
- storeRebuildComplete(&rb->counts);
- delete rb;
- }
-}
-
-/// load entries from swap.state or files until we run out of entries or time
-void
-RebuildState::rebuildStep()
-{
- currentEntry(NULL);
-
- // Balance our desire to maximize the number of entries processed at once
- // (and, hence, minimize overheads and total rebuild time) with a
- // requirement to also process Coordinator events, disk I/Os, etc.
- const int maxSpentMsec = 50; // keep small: most RAM I/Os are under 1ms
- const timeval loopStart = current_time;
-
- const int totalEntries = LogParser ? LogParser->SwapLogEntries() : -1;
-
- while (!isDone()) {
- if (fromLog)
- rebuildFromSwapLog();
- else
- rebuildFromDirectory();
-
- // TODO: teach storeRebuildProgress to handle totalEntries <= 0
- if (totalEntries > 0 && (n_read % 4000 == 0))
- storeRebuildProgress(sd->index, totalEntries, n_read);
-
- if (opt_foreground_rebuild)
- continue; // skip "few entries at a time" check below
-
- getCurrentTime();
- const double elapsedMsec = tvSubMsec(loopStart, current_time);
- if (elapsedMsec > maxSpentMsec || elapsedMsec < 0) {
- debugs(47, 5, HERE << "pausing after " << n_read << " entries in " <<
- elapsedMsec << "ms; " << (elapsedMsec/n_read) << "ms per entry");
- break;
- }
- }
-}
-
-/// process one cache file
-void
-RebuildState::rebuildFromDirectory()
-{
- cache_key key[SQUID_MD5_DIGEST_LENGTH];
-
- struct stat sb;
- int fd = -1;
- assert(this != NULL);
- debugs(47, 3, "commonUfsDirRebuildFromDirectory: DIR #" << sd->index);
-
- assert(fd == -1);
- sfileno filn = 0;
- int size;
- fd = getNextFile(&filn, &size);
-
- if (fd == -2) {
- debugs(47, DBG_IMPORTANT, "Done scanning " << sd->path << " dir (" <<
- n_read << " entries)");
- _done = true;
- return;
- } else if (fd < 0) {
- return;
- }
-
- assert(fd > -1);
- /* lets get file stats here */
-
- ++n_read;
-
- if (fstat(fd, &sb) < 0) {
- debugs(47, 1, "commonUfsDirRebuildFromDirectory: fstat(FD " << fd << "): " \
<< xstrerror());
- file_close(fd);
- --store_open_disk_fd;
- fd = -1;
- return;
- }
-
- MemBuf buf;
- buf.init(SM_PAGE_SIZE, SM_PAGE_SIZE);
- if (!storeRebuildLoadEntry(fd, sd->index, buf, counts))
- return;
-
- StoreEntry tmpe;
- const bool loaded = storeRebuildParseEntry(buf, tmpe, key, counts,
- (int64_t)sb.st_size);
-
- file_close(fd);
- --store_open_disk_fd;
- fd = -1;
-
- if (!loaded) {
- // XXX: shouldn't this be a call to commonUfsUnlink?
- sd->unlinkFile(filn); // should we unlink in all failure cases?
- return;
- }
-
- if (!storeRebuildKeepEntry(tmpe, key, counts))
- return;
-
- ++counts.objcount;
- // tmpe.dump(5);
- currentEntry(sd->addDiskRestore(key,
- filn,
- tmpe.swap_file_sz,
- tmpe.expires,
- tmpe.timestamp,
- tmpe.lastref,
- tmpe.lastmod,
- tmpe.refcount, /* refcount */
- tmpe.flags, /* flags */
- (int) flags.clean));
- storeDirSwapLog(currentEntry(), SWAP_LOG_ADD);
-}
-
-StoreEntry *
-RebuildState::currentEntry() const
-{
- return e;
-}
-
-void
-RebuildState::currentEntry(StoreEntry *newValue)
-{
- e = newValue;
-}
-
-/// process one swap log entry
-void
-RebuildState::rebuildFromSwapLog()
-{
- StoreSwapLogData swapData;
-
- if (LogParser->ReadRecord(swapData) != 1) {
- debugs(47, 1, "Done reading " << sd->path << " swaplog (" << n_read << " \
entries)");
- LogParser->Close();
- delete LogParser;
- LogParser = NULL;
- _done = true;
- return;
- }
-
- ++n_read;
-
- if (!swapData.sane()) {
- ++counts.invalid;
- return;
- }
-
- /*
- * BC: during 2.4 development, we changed the way swap file
- * numbers are assigned and stored. The high 16 bits used
- * to encode the SD index number. There used to be a call
- * to storeDirProperFileno here that re-assigned the index
- * bits. Now, for backwards compatibility, we just need
- * to mask it off.
- */
- swapData.swap_filen &= 0x00FFFFFF;
-
- debugs(47, 3, "commonUfsDirRebuildFromSwapLog: " <<
- swap_log_op_str[(int) swapData.op] << " " <<
- storeKeyText(swapData.key) << " "<< std::setfill('0') <<
- std::hex << std::uppercase << std::setw(8) <<
- swapData.swap_filen);
-
- if (swapData.op == SWAP_LOG_ADD) {
- (void) 0;
- } else if (swapData.op == SWAP_LOG_DEL) {
- /* Delete unless we already have a newer copy anywhere in any store */
- /* this needs to become
- * 1) unpack url
- * 2) make synthetic request with headers ?? or otherwise search
- * for a matching object in the store
- * TODO FIXME change to new async api
- */
- currentEntry (Store::Root().get(swapData.key));
-
- if (currentEntry() != NULL && swapData.lastref >= e->lastref) {
- undoAdd();
- --counts.objcount;
- ++counts.cancelcount;
- }
- return;
- } else {
- const double
- x = ::log(static_cast<double>(++counts.bad_log_op)) / ::log(10.0);
-
- if (0.0 == x - (double) (int) x)
- debugs(47, 1, "WARNING: " << counts.bad_log_op << " invalid swap log \
entries found");
-
- ++counts.invalid;
-
- return;
- }
-
- ++counts.scancount; // XXX: should not this be incremented earlier?
-
- if (!sd->validFileno(swapData.swap_filen, 0)) {
- ++counts.invalid;
- return;
- }
-
- if (EBIT_TEST(swapData.flags, KEY_PRIVATE)) {
- ++counts.badflags;
- return;
- }
-
- /* this needs to become
- * 1) unpack url
- * 2) make synthetic request with headers ?? or otherwise search
- * for a matching object in the store
- * TODO FIXME change to new async api
- */
- currentEntry (Store::Root().get(swapData.key));
-
- int used; /* is swapfile already in use? */
-
- used = sd->mapBitTest(swapData.swap_filen);
-
- /* If this URL already exists in the cache, does the swap log
- * appear to have a newer entry? Compare 'lastref' from the
- * swap log to e->lastref. */
- /* is the log entry newer than current entry? */
- int disk_entry_newer = currentEntry() ? (swapData.lastref > \
currentEntry()->lastref ? 1 : 0) : 0;
-
- if (used && !disk_entry_newer) {
- /* log entry is old, ignore it */
- ++counts.clashcount;
- return;
- } else if (used && currentEntry() && currentEntry()->swap_filen == \
swapData.swap_filen && currentEntry()->swap_dirn == sd->index) {
- /* swapfile taken, same URL, newer, update meta */
-
- if (currentEntry()->store_status == STORE_OK) {
- currentEntry()->lastref = swapData.timestamp;
- currentEntry()->timestamp = swapData.timestamp;
- currentEntry()->expires = swapData.expires;
- currentEntry()->lastmod = swapData.lastmod;
- currentEntry()->flags = swapData.flags;
- currentEntry()->refcount += swapData.refcount;
- sd->dereference(*currentEntry());
- } else {
- debug_trap("commonUfsDirRebuildFromSwapLog: bad condition");
- debugs(47, 1, "\tSee " << __FILE__ << ":" << __LINE__);
- }
- return;
- } else if (used) {
- /* swapfile in use, not by this URL, log entry is newer */
- /* This is sorta bad: the log entry should NOT be newer at this
- * point. If the log is dirty, the filesize check should have
- * caught this. If the log is clean, there should never be a
- * newer entry. */
- debugs(47, 1, "WARNING: newer swaplog entry for dirno " <<
- sd->index << ", fileno "<< std::setfill('0') << std::hex <<
- std::uppercase << std::setw(8) << swapData.swap_filen);
-
- /* I'm tempted to remove the swapfile here just to be safe,
- * but there is a bad race condition in the NOVM version if
- * the swapfile has recently been opened for writing, but
- * not yet opened for reading. Because we can't map
- * swapfiles back to StoreEntrys, we don't know the state
- * of the entry using that file. */
- /* We'll assume the existing entry is valid, probably because
- * were in a slow rebuild and the the swap file number got taken
- * and the validation procedure hasn't run. */
- assert(flags.need_to_validate);
- ++counts.clashcount;
- return;
- } else if (currentEntry() && !disk_entry_newer) {
- /* key already exists, current entry is newer */
- /* keep old, ignore new */
- ++counts.dupcount;
- return;
- } else if (currentEntry()) {
- /* key already exists, this swapfile not being used */
- /* junk old, load new */
- undoAdd();
- --counts.objcount;
- ++counts.dupcount;
- } else {
- /* URL doesnt exist, swapfile not in use */
- /* load new */
- (void) 0;
- }
-
- ++counts.objcount;
-
- currentEntry(sd->addDiskRestore(swapData.key,
- swapData.swap_filen,
- swapData.swap_file_sz,
- swapData.expires,
- swapData.timestamp,
- swapData.lastref,
- swapData.lastmod,
- swapData.refcount,
- swapData.flags,
- (int) flags.clean));
-
- storeDirSwapLog(currentEntry(), SWAP_LOG_ADD);
-}
-
-/// undo the effects of adding an entry in rebuildFromSwapLog()
-void
-RebuildState::undoAdd()
-{
- StoreEntry *added = currentEntry();
- assert(added);
- currentEntry(NULL);
-
- // TODO: Why bother with these two if we are going to release?!
- added->expireNow();
- added->releaseRequest();
-
- if (added->swap_filen > -1) {
- UFSSwapDir *sde = dynamic_cast<UFSSwapDir *>(INDEXSD(added->swap_dirn));
- assert(sde);
- sde->undoAddDiskRestore(added);
- }
-
- added->release();
-}
-
-int
-RebuildState::getNextFile(sfileno * filn_p, int *size)
-{
- int fd = -1;
- int dirs_opened = 0;
- debugs(47, 3, "commonUfsDirGetNextFile: flag=" << flags.init << ", " <<
- sd->index << ": /"<< std::setfill('0') << std::hex <<
- std::uppercase << std::setw(2) << curlvl1 << "/" << std::setw(2) <<
- curlvl2);
-
- if (done)
- return -2;
-
- while (fd < 0 && done == 0) {
- fd = -1;
-
- if (0 == flags.init) { /* initialize, open first file */
- done = 0;
- curlvl1 = 0;
- curlvl2 = 0;
- in_dir = 0;
- flags.init = 1;
- assert(Config.cacheSwap.n_configured > 0);
- }
-
- if (0 == in_dir) { /* we need to read in a new directory */
- snprintf(fullpath, MAXPATHLEN, "%s/%02X/%02X",
- sd->path,
- curlvl1, curlvl2);
-
- if (dirs_opened)
- return -1;
-
- td = opendir(fullpath);
-
- ++dirs_opened;
-
- if (td == NULL) {
- debugs(47, 1, "commonUfsDirGetNextFile: opendir: " << fullpath << ": \
" << xstrerror());
- } else {
- entry = readdir(td); /* skip . and .. */
- entry = readdir(td);
-
- if (entry == NULL && errno == ENOENT)
- debugs(47, 1, "commonUfsDirGetNextFile: directory does not \
exist!.");
- debugs(47, 3, "commonUfsDirGetNextFile: Directory " << fullpath);
- }
- }
-
- if (td != NULL && (entry = readdir(td)) != NULL) {
- ++in_dir;
-
- if (sscanf(entry->d_name, "%x", &fn) != 1) {
- debugs(47, 3, "commonUfsDirGetNextFile: invalid " << entry->d_name);
- continue;
- }
-
- if (!UFSSwapDir::FilenoBelongsHere(fn, sd->index, curlvl1, curlvl2)) {
- debugs(47, 3, "commonUfsDirGetNextFile: "<< std::setfill('0') <<
- std::hex << std::uppercase << std::setw(8) << fn <<
- " does not belong in " << std::dec << sd->index << "/" <<
- curlvl1 << "/" << curlvl2);
-
- continue;
- }
-
- if (sd->mapBitTest(fn)) {
- debugs(47, 3, "commonUfsDirGetNextFile: Locked, continuing with \
next.");
- continue;
- }
-
- snprintf(fullfilename, MAXPATHLEN, "%s/%s",
- fullpath, entry->d_name);
- debugs(47, 3, "commonUfsDirGetNextFile: Opening " << fullfilename);
- fd = file_open(fullfilename, O_RDONLY | O_BINARY);
-
- if (fd < 0)
- debugs(47, 1, "commonUfsDirGetNextFile: " << fullfilename << ": " << \
xstrerror());
- else
- ++store_open_disk_fd;
-
- continue;
- }
-
- if (td != NULL)
- closedir(td);
-
- td = NULL;
-
- in_dir = 0;
-
- if (sd->validL2(++curlvl2))
- continue;
-
- curlvl2 = 0;
-
- if (sd->validL1(++curlvl1))
- continue;
-
- curlvl1 = 0;
-
- done = 1;
- }
-
- *filn_p = fn;
- return fd;
-}
-
-bool
-RebuildState::error() const
-{
- return false;
-}
-
-bool
-RebuildState::isDone() const
-{
- return _done;
-}
-
-StoreEntry *
-RebuildState::currentItem()
-{
- return currentEntry();
-}
-
-#if !_USE_INLINE_
-#include "ufscommon.cci"
-#endif
=== removed file 'src/fs/ufs/ufscommon.cci'
--- src/fs/ufs/ufscommon.cci 2009-01-21 03:47:47 +0000
+++ src/fs/ufs/ufscommon.cci 1970-01-01 00:00:00 +0000
@@ -1,34 +0,0 @@
-/*
- * $Id$
- *
- * DEBUG: section 47 Store Directory Routines
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
=== removed file 'src/fs/ufs/ufscommon.h'
--- src/fs/ufs/ufscommon.h 2012-07-20 23:11:02 +0000
+++ src/fs/ufs/ufscommon.h 1970-01-01 00:00:00 +0000
@@ -1,425 +0,0 @@
-/*
- * $Id$
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-#ifndef SQUID_UFSCOMMON_H
-#define SQUID_UFSCOMMON_H
-
-
-#define DefaultLevelOneDirs 16
-#define DefaultLevelTwoDirs 256
-#define STORE_META_BUFSZ 4096
-
-class UFSStrategy;
-class ConfigOptionVector;
-class DiskIOModule;
-class StoreSearch;
-class FileMap;
-
-#include "SwapDir.h"
-
-/// \ingroup UFS
-class UFSSwapDir : public SwapDir
-{
-
-public:
- static int IsUFSDir(SwapDir* sd);
- static int DirClean(int swap_index);
- static int FilenoBelongsHere(int fn, int F0, int F1, int F2);
-
- UFSSwapDir(char const *aType, const char *aModuleType);
- virtual void init();
- virtual void create();
- virtual void dump(StoreEntry &) const;
- ~UFSSwapDir();
- virtual StoreSearch *search(String const url, HttpRequest *);
- virtual bool doubleCheck(StoreEntry &);
- virtual bool unlinkdUseful() const;
- virtual void unlink(StoreEntry &);
- virtual void statfs(StoreEntry &)const;
- virtual void maintain();
- virtual bool canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) \
const;
- virtual void reference(StoreEntry &);
- virtual bool dereference(StoreEntry &);
- virtual StoreIOState::Pointer createStoreIO(StoreEntry &, StoreIOState::STFNCB \
*, StoreIOState::STIOCB *, void *);
- virtual StoreIOState::Pointer openStoreIO(StoreEntry &, StoreIOState::STFNCB *, \
StoreIOState::STIOCB *, void *);
- virtual void openLog();
- virtual void closeLog();
- virtual int writeCleanStart();
- virtual void writeCleanDone();
- virtual void logEntry(const StoreEntry & e, int op) const;
- virtual void parse(int index, char *path);
- virtual void reconfigure();
- virtual int callback();
- virtual void sync();
- virtual void swappedOut(const StoreEntry &e);
- virtual uint64_t currentSize() const { return cur_size; }
- virtual uint64_t currentCount() const { return n_disk_objects; }
-
- void unlinkFile(sfileno f);
- // move down when unlink is a virtual method
- //protected:
- UFSStrategy *IO;
- char *fullPath(sfileno, char *) const;
- /* temp */
- void closeTmpSwapLog();
- FILE *openTmpSwapLog(int *clean_flag, int *zero_flag);
- char *swapSubDir(int subdirn) const;
- int mapBitTest(sfileno filn);
- void mapBitReset(sfileno filn);
- void mapBitSet(sfileno filn);
- StoreEntry *addDiskRestore(const cache_key * key,
- sfileno file_number,
- uint64_t swap_file_sz,
- time_t expires,
- time_t timestamp,
- time_t lastref,
- time_t lastmod,
- uint32_t refcount,
- uint16_t flags,
- int clean);
- /// Undo the effects of UFSSwapDir::addDiskRestore().
- void undoAddDiskRestore(StoreEntry *e);
- int validFileno(sfileno filn, int flag) const;
- int mapBitAllocate();
- virtual ConfigOption *getOptionTree() const;
-
- void *fsdata;
-
- bool validL2(int) const;
- bool validL1(int) const;
-
- void replacementAdd(StoreEntry *e);
- void replacementRemove(StoreEntry *e);
-
-protected:
- FileMap *map;
- int suggest;
- int l1;
- int l2;
-
-private:
- void parseSizeL1L2();
- static int NumberOfUFSDirs;
- static int * UFSDirToGlobalDirMapping;
- bool pathIsDirectory(const char *path)const;
- int swaplog_fd;
- static EVH CleanEvent;
- bool verifyCacheDirs();
- void rebuild();
- int createDirectory(const char *path, int);
- void createSwapSubDirs();
- void dumpEntry(StoreEntry &) const;
- char *logFile(char const *ext = NULL)const;
- void changeIO(DiskIOModule *);
- bool optionIOParse(char const *option, const char *value, int reconfiguring);
- void optionIODump(StoreEntry * e) const;
- mutable ConfigOptionVector *currentIOOptions;
- char const *ioType;
- uint64_t cur_size; ///< currently used space in the storage area
- uint64_t n_disk_objects; ///< total number of objects stored
-};
-
-#include "RefCount.h"
-#include "DiskIO/IORequestor.h"
-
-/**
- * UFS dir specific IO calls
- *
- \todo This should be whittled away.
- * DiskIOModule should be providing the entire needed API.
- */
-
-class DiskIOStrategy;
-
-class DiskFile;
-
-/// \ingroup UFS
-class UFSStrategy
-{
-
-public:
- UFSStrategy (DiskIOStrategy *);
- virtual ~UFSStrategy ();
- /* Not implemented */
- UFSStrategy (UFSStrategy const &);
- UFSStrategy &operator=(UFSStrategy const &);
-
- virtual bool shedLoad();
-
- virtual int load();
-
- StoreIOState::Pointer createState(SwapDir *SD, StoreEntry *e, \
StoreIOState::STIOCB * callback, void *callback_data) const;
- /* UFS specific */
- virtual RefCount<DiskFile> newFile (char const *path);
- StoreIOState::Pointer open(SwapDir *, StoreEntry *, StoreIOState::STFNCB *,
- StoreIOState::STIOCB *, void *);
- StoreIOState::Pointer create(SwapDir *, StoreEntry *, StoreIOState::STFNCB *,
- StoreIOState::STIOCB *, void *);
-
- virtual void unlinkFile (char const *);
- virtual void sync();
-
- virtual int callback();
-
- /** Init per-instance logic */
- virtual void init();
-
- /** cachemgr output on the IO instance stats */
- virtual void statfs(StoreEntry & sentry)const;
-
- /** The io strategy in use */
- DiskIOStrategy *io;
-protected:
-
- friend class UFSSwapDir;
-};
-
-/** Common ufs-store-dir logic */
-
-class ReadRequest;
-
-/// \ingroup UFS
-class UFSStoreState : public StoreIOState, public IORequestor
-{
-
-public:
- void * operator new (size_t);
- void operator delete (void *);
- UFSStoreState(SwapDir * SD, StoreEntry * anEntry, STIOCB * callback_, void \
*callback_data_);
- ~UFSStoreState();
- virtual void close(int how);
- virtual void closeCompleted();
- // protected:
- virtual void ioCompletedNotification();
- virtual void readCompleted(const char *buf, int len, int errflag, \
RefCount<ReadRequest>);
- virtual void writeCompleted(int errflag, size_t len, RefCount<WriteRequest>);
- RefCount<DiskFile> theFile;
- bool opening;
- bool creating;
- bool closing;
- bool reading;
- bool writing;
- void read_(char *buf, size_t size, off_t offset, STRCB * callback, void \
*callback_data);
- void write(char const *buf, size_t size, off_t offset, FREE * free_func);
-
-protected:
- virtual void doCloseCallback (int errflag);
-
- class _queued_read
- {
-
- public:
- MEMPROXY_CLASS(UFSStoreState::_queued_read);
- char *buf;
- size_t size;
- off_t offset;
- STRCB *callback;
- void *callback_data;
-
- };
-
- class _queued_write
- {
-
- public:
- MEMPROXY_CLASS(UFSStoreState::_queued_write);
- char const *buf;
- size_t size;
- off_t offset;
- FREE *free_func;
-
- };
-
- /** \todo These should be in the IO strategy */
-
- struct {
- /**
- * DPW 2006-05-24
- * the write_draining flag is used to avoid recursion inside
- * the UFSStoreState::drainWriteQueue() method.
- */
- bool write_draining;
- /**
- * DPW 2006-05-24
- * The try_closing flag is set by UFSStoreState::tryClosing()
- * when UFSStoreState wants to close the file, but cannot
- * because of pending I/Os. If set, UFSStoreState will
- * try to close again in the I/O callbacks.
- */
- bool try_closing;
- } flags;
- link_list *pending_reads;
- link_list *pending_writes;
- void queueRead(char *, size_t, off_t, STRCB *, void *);
- void queueWrite(char const *, size_t, off_t, FREE *);
- bool kickReadQueue();
- void drainWriteQueue();
- void tryClosing();
- char *read_buf;
-
-private:
- CBDATA_CLASS(UFSStoreState);
- void openDone();
- void freePending();
- void doWrite();
-};
-
-MEMPROXY_CLASS_INLINE(UFSStoreState::_queued_read);
-MEMPROXY_CLASS_INLINE(UFSStoreState::_queued_write);
-
-
-#include "StoreSearch.h"
-
-/// \ingroup UFS
-class StoreSearchUFS : public StoreSearch
-{
-
-public:
- StoreSearchUFS(RefCount<UFSSwapDir> sd);
- StoreSearchUFS(StoreSearchUFS const &);
- virtual ~StoreSearchUFS();
-
- /** \todo Iterator API - garh, wrong place */
- /**
- * callback the client when a new StoreEntry is available
- * or an error occurs
- */
- virtual void next(void (callback)(void *cbdata), void *cbdata);
-
- /**
- \retval true if a new StoreEntry is immediately available
- \retval false if a new StoreEntry is NOT immediately available
- */
- virtual bool next();
-
- virtual bool error() const;
- virtual bool isDone() const;
- virtual StoreEntry *currentItem();
-
- RefCount<UFSSwapDir> sd;
- RemovalPolicyWalker *walker;
-
-private:
- CBDATA_CLASS2(StoreSearchUFS);
- /// \bug (callback) should be hidden behind a proper human readable name
- void (callback)(void *cbdata);
- void *cbdata;
- StoreEntry * current;
- bool _done;
-};
-
-
-class StoreSwapLogData;
-
-/// \ingroup UFS
-class UFSSwapLogParser
-{
-
-public:
- FILE *log;
- int log_entries;
- int record_size;
-
- UFSSwapLogParser(FILE *fp):log(fp),log_entries(-1), record_size(0) {
- }
- virtual ~UFSSwapLogParser() {};
-
- static UFSSwapLogParser *GetUFSSwapLogParser(FILE *fp);
-
- virtual bool ReadRecord(StoreSwapLogData &swapData) = 0;
- int SwapLogEntries();
- void Close() {
- if (log) {
- fclose(log);
- log = NULL;
- }
- }
-};
-
-
-/// \ingroup UFS
-class RebuildState : public RefCountable
-{
-
-public:
- static EVH RebuildStep;
-
- RebuildState(RefCount<UFSSwapDir> sd);
- ~RebuildState();
-
- virtual bool error() const;
- virtual bool isDone() const;
- virtual StoreEntry *currentItem();
-
- RefCount<UFSSwapDir> sd;
- int n_read;
- /* FILE *log;*/
- UFSSwapLogParser *LogParser;
- int curlvl1;
- int curlvl2;
-
- struct {
- unsigned int need_to_validate:1;
- unsigned int clean:1;
- unsigned int init:1;
- } flags;
- int in_dir;
- int done;
- int fn;
-
- dirent_t *entry;
- DIR *td;
- char fullpath[MAXPATHLEN];
- char fullfilename[MAXPATHLEN];
-
- struct _store_rebuild_data counts;
-
-private:
- CBDATA_CLASS2(RebuildState);
- void rebuildFromDirectory();
- void rebuildFromSwapLog();
- void rebuildStep();
- void undoAdd();
- int getNextFile(sfileno *, int *size);
- StoreEntry *currentEntry() const;
- void currentEntry(StoreEntry *);
- StoreEntry *e;
- bool fromLog;
- bool _done;
- /// \bug (callback) should be hidden behind a proper human readable name
- void (callback)(void *cbdata);
- void *cbdata;
-};
-
-#if _USE_INLINE_
-#include "ufscommon.cci"
-#endif
-
-#endif /* SQUID_UFSCOMMON_H */
=== modified file 'src/tests/testCoss.cc'
--- src/tests/testCoss.cc 2012-01-20 18:55:04 +0000
+++ src/tests/testCoss.cc 2012-07-31 21:45:27 +0000
@@ -4,7 +4,6 @@
#include "Store.h"
#include "SwapDir.h"
#include "DiskIO/DiskIOModule.h"
-#include "fs/ufs/ufscommon.h"
#include "fs/coss/CossSwapDir.h"
#include "Mem.h"
#include "MemObject.h"
=== modified file 'src/tests/testDiskIO.cc'
--- src/tests/testDiskIO.cc 2012-01-20 18:55:04 +0000
+++ src/tests/testDiskIO.cc 2012-07-31 21:45:27 +0000
@@ -5,7 +5,6 @@
#include "Store.h"
#include "SwapDir.h"
#include "DiskIO/DiskIOModule.h"
-#include "fs/ufs/ufscommon.h"
#if 0 // AYJ: COSS in Squid-3 is disabled.
#include "fs/coss/CossSwapDir.h"
#endif
=== modified file 'src/tests/testNull.cc'
--- src/tests/testNull.cc 2012-01-20 18:55:04 +0000
+++ src/tests/testNull.cc 2012-07-31 21:45:27 +0000
@@ -4,7 +4,6 @@
#include "Store.h"
#include "SwapDir.h"
#include "DiskIO/DiskIOModule.h"
-#include "fs/ufs/ufscommon.h"
#include "fs/null/store_null.h"
#include "Mem.h"
#include "MemObject.h"
=== modified file 'src/tests/testUfs.cc'
--- src/tests/testUfs.cc 2012-01-20 18:55:04 +0000
+++ src/tests/testUfs.cc 2012-07-31 21:45:27 +0000
@@ -1,15 +1,16 @@
#define SQUID_UNIT_TEST 1
#include "squid.h"
-#include "testUfs.h"
-#include "Store.h"
-#include "SwapDir.h"
+
#include "DiskIO/DiskIOModule.h"
-#include "fs/ufs/ufscommon.h"
+#include "HttpHeader.h"
+#include "HttpReply.h"
#include "Mem.h"
#include "MemObject.h"
-#include "HttpHeader.h"
-#include "HttpReply.h"
#include "testStoreSupport.h"
+#include "testUfs.h"
+#include "Store.h"
+#include "SwapDir.h"
+#include "fs/ufs/UFSSwapDir.h"
#if HAVE_STDEXCEPT
#include <stdexcept>
# Begin bundle
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
jChjZdUjGP2Jabab//F3JFOFCQ2zX32w
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic