[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