]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
apply unify io patch to simplify IO code for diskd/aufs/ufs
authorrobertc <>
Fri, 27 Dec 2002 17:26:32 +0000 (17:26 +0000)
committerrobertc <>
Fri, 27 Dec 2002 17:26:32 +0000 (17:26 +0000)
41 files changed:
configure.in
src/Makefile.am
src/Store.h
src/StoreClient.h
src/StoreIOState.cc [new file with mode: 0644]
src/StoreIOState.h [new file with mode: 0644]
src/SwapDir.cc [new file with mode: 0644]
src/SwapDir.h [new file with mode: 0644]
src/authenticate.cc
src/cache_cf.cc
src/client_side_reply.cc
src/fs/aufs/async_io.cc
src/fs/aufs/store_asyncufs.h
src/fs/aufs/store_dir_aufs.cc
src/fs/aufs/store_io_aufs.cc
src/fs/coss/store_coss.h
src/fs/coss/store_dir_coss.cc
src/fs/coss/store_io_coss.cc
src/fs/diskd/diskd.cc
src/fs/diskd/store_dir_diskd.cc
src/fs/diskd/store_diskd.h
src/fs/diskd/store_io_diskd.cc
src/fs/null/store_null.cc
src/fs/ufs/store_dir_ufs.cc
src/fs/ufs/store_io_ufs.cc
src/fs/ufs/store_ufs.h
src/protos.h
src/squid.h
src/stat.cc
src/store.cc
src/store_client.cc
src/store_dir.cc
src/store_io.cc
src/store_rebuild.cc
src/store_swapin.cc
src/store_swapout.cc
src/structs.h
src/typedefs.h
src/ufscommon.cc
src/ufscommon.h
test-suite/Makefile.am

index 146835df691b95c1ef62bcc70c8afc3eb4d7a249..35e42a1b48b90378c9968f95b9479cc906ae2d25 100644 (file)
@@ -3,7 +3,7 @@ dnl  Configuration input file for Squid
 dnl
 dnl  Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
 dnl
-dnl  $Id: configure.in,v 1.307 2002/12/06 23:19:12 hno Exp $
+dnl  $Id: configure.in,v 1.308 2002/12/27 10:26:32 robertc Exp $
 dnl
 dnl
 dnl
@@ -11,9 +11,9 @@ AC_INIT
 AC_PREREQ(2.52)
 AC_CONFIG_SRCDIR([src/main.cc])
 AC_CONFIG_AUX_DIR(cfgaux)
-AM_INIT_AUTOMAKE(squid, 3.0-DEVEL)
+AM_INIT_AUTOMAKE(squid, 3.0-DEVEL-unifyio)
 AM_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.307 $)dnl
+AC_REVISION($Revision: 1.308 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AM_MAINTAINER_MODE
 
@@ -362,6 +362,7 @@ AC_SUBST(STORE_LIBS)
 dnl remove all but diskd - its the only module that needs to recurse
 dnl into the sub directory
 STORE_MODULE_SUBDIRS=
+UFS_FOUND=
 for fs in $STORE_MODULES none; do
     case "$fs" in
     diskd)
@@ -379,8 +380,20 @@ for fs in $STORE_MODULES none; do
            with_aio=yes
        fi
        ;;
+    ufs)
+        UFS_FOUND="true"
     esac
 done
+
+if test -z "$UFS_FOUND"; then
+   echo "adding UFS, as it contains core logic for diskd and aufs"
+   STORE_OBJS="$STORE_OBJS fs/libufs.a"
+   AC_SUBST(STORE_OBJS)
+   STORE_LIBS="$STORE_LIBS libufs.a"
+   AC_SUBST(STORE_LIBS)
+   STORE_MODULES="$STORE_MODULES ufs"
+fi
+  
 AC_SUBST(STORE_MODULES)
 AC_SUBST(STORE_MODULE_SUBDIRS)
 
index 7dc50d5b35de216ed263f410939659432889a8c9..3a56044fdd8d1b904f1a1678dd20505009e671ea 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.am,v 1.44 2002/12/15 09:00:42 robertc Exp $
+#  $Id: Makefile.am,v 1.45 2002/12/27 10:26:33 robertc Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -214,6 +214,8 @@ squid_SOURCES = \
        Store.h \
        store_io.cc \
        StoreIOBuffer.h \
+       StoreIOState.cc \
+       StoreIOState.h \
        store_client.cc \
        StoreClient.h \
        store_digest.cc \
@@ -225,6 +227,8 @@ squid_SOURCES = \
        store_swapmeta.cc \
        store_swapout.cc \
        structs.h \
+       SwapDir.cc \
+       SwapDir.h \
        tools.cc \
        typedefs.h \
        ufscommon.cc \
@@ -259,7 +263,7 @@ squid_LDADD = \
        @SSLLIB@ \
        -lmiscutil \
        @XTRA_LIBS@
-squid_DEPENDENCIES = $(top_builddir)/lib/libmiscutil.a
+squid_DEPENDENCIES = $(top_builddir)/lib/libmiscutil.a @STORE_OBJS@
 
 unlinkd_SOURCES = unlinkd.cc
 unlinkd_CXXFLAGS = -DUNLINK_DAEMON
index 249942cc43f435320b7a18b3ed3e48ccd9f697be..e338dd4abc8c8d6e7931a531a5f14759790d3f28 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: Store.h,v 1.3 2002/10/15 08:03:29 robertc Exp $
+ * $Id: Store.h,v 1.4 2002/12/27 10:26:33 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -149,6 +149,7 @@ SQUIDCEXTERN void storeHeapPositionUpdate(StoreEntry *, SwapDir *);
 SQUIDCEXTERN void storeSwapFileNumberSet(StoreEntry * e, sfileno filn);
 SQUIDCEXTERN void storeFsInit(void);
 SQUIDCEXTERN void storeFsDone(void);
+typedef void STSETUP(storefs_entry_t *);
 SQUIDCEXTERN void storeFsAdd(const char *, STSETUP *);
 SQUIDCEXTERN void storeReplAdd(const char *, REMOVALPOLICYCREATE *);
 
index e6be253a199e15feb99df0bfaa951cdd9fc4a8ed..06067f0c167ac1e48a8a9d3782053cc4e4adf0fa 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: StoreClient.h,v 1.3 2002/10/14 07:35:00 hno Exp $
+ * $Id: StoreClient.h,v 1.4 2002/12/27 10:26:33 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -60,7 +60,7 @@ struct _store_client {
     void *owner;
 #endif
     StoreEntry *entry;         /* ptr to the parent StoreEntry, argh! */
-    storeIOState *swapin_sio;
+    StoreIOState::Pointer swapin_sio;
     struct {
        unsigned int disk_io_pending:1;
        unsigned int store_copying:1;
diff --git a/src/StoreIOState.cc b/src/StoreIOState.cc
new file mode 100644 (file)
index 0000000..e335091
--- /dev/null
@@ -0,0 +1,66 @@
+
+/*
+ * $Id: StoreIOState.cc,v 1.1 2002/12/27 10:26:33 robertc Exp $
+ *
+ * DEBUG: section ??    Swap Dir base object
+ * 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.
+ *
+ */
+
+#include "squid.h"
+#include "StoreIOState.h"
+    
+void *
+storeIOState::operator new (size_t amount)
+{
+    assert(0);
+    return (void *)1;
+}
+
+void 
+storeIOState::operator delete (void *address){assert (0);}
+
+storeIOState::storeIOState()
+{
+    mode = O_BINARY;
+}
+
+off_t
+storeIOState::offset() const
+{
+    return offset_;
+}
+
+storeIOState::~storeIOState()
+{
+    if (read.callback_data)
+       cbdataReferenceDone(read.callback_data);
+    if (callback_data)
+       cbdataReferenceDone(callback_data);
+}
diff --git a/src/StoreIOState.h b/src/StoreIOState.h
new file mode 100644 (file)
index 0000000..f080072
--- /dev/null
@@ -0,0 +1,76 @@
+
+/*
+ * $Id: StoreIOState.h,v 1.1 2002/12/27 10:26:33 robertc Exp $
+ *
+ *
+ * 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_STOREIOSTATE_H
+#define SQUID_STOREIOSTATE_H
+
+#include "RefCount.h"
+class storeIOState : public RefCountable{
+public:
+
+    /* storeIOState does not get mempooled - it's children do */
+    void *operator new (size_t amount);
+    void operator delete (void *address);
+    void deleteSelf() const = 0;
+    virtual ~storeIOState();
+
+    storeIOState();
+
+    off_t offset() const;
+
+    virtual void read_(char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data) = 0;
+    virtual void write(char *buf, size_t size, off_t offset, FREE * free_func) = 0;
+    virtual void close() = 0;
+    
+    sdirno swap_dirn;
+    sfileno swap_filen;
+    StoreEntry *e;             /* Need this so the FS layers can play god */
+    mode_t mode;
+    off_t offset_;             /* current on-disk offset pointer */
+    STFNCB *file_callback;     /* called on delayed sfileno assignments */
+    STIOCB *callback;
+    void *callback_data;
+    struct {
+       STRCB *callback;
+       void *callback_data;
+    } read;
+    struct {
+       unsigned int closing:1; /* debugging aid */
+    } flags;
+};
+
+class StoreIOState {
+    typedef RefCount<storeIOState> Pointer;
+};
+
+#endif /* SQUID_STOREIOSTATE_H */
diff --git a/src/SwapDir.cc b/src/SwapDir.cc
new file mode 100644 (file)
index 0000000..136fa51
--- /dev/null
@@ -0,0 +1,123 @@
+
+/*
+ * $Id: SwapDir.cc,v 1.1 2002/12/27 10:26:33 robertc Exp $
+ *
+ * DEBUG: section ??    Swap Dir base object
+ * 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.
+ *
+ */
+
+#include "squid.h"
+#include "SwapDir.h"
+#include "Store.h"
+
+SwapDir *
+SwapDir::Factory (_storefs_entry const &fs)
+{
+    SwapDir *result = fs.newfunc();
+    result->type = fs.typestr;
+    return result;
+}
+
+SwapDir::~SwapDir() {
+    xfree(path);
+}
+
+void
+SwapDir::newFileSystem(){}
+
+void
+SwapDir::dump(StoreEntry &)const{}
+
+bool
+SwapDir::doubleCheck(StoreEntry &)
+{
+    return false;
+}
+
+void
+SwapDir::unlink(StoreEntry &){}
+
+void
+SwapDir::statfs(StoreEntry &)const {}
+
+void
+SwapDir::maintainfs(){}
+
+void
+SwapDir::reference(StoreEntry &){}
+
+void
+SwapDir::dereference(StoreEntry &){}
+
+int
+SwapDir::callback()
+{
+    return 0;
+}
+
+void
+SwapDir::sync(){}
+
+/* Move to StoreEntry ? */
+bool
+SwapDir::canLog(StoreEntry const &e)const
+{
+    if (e.swap_filen < 0)
+       return false;
+    if (e.swap_status != SWAPOUT_DONE)
+       return false;
+    if (e.swap_file_sz <= 0)
+       return false;
+    if (EBIT_TEST(e.flags, RELEASE_REQUEST))
+       return false;
+    if (EBIT_TEST(e.flags, KEY_PRIVATE))
+       return false;
+    if (EBIT_TEST(e.flags, ENTRY_SPECIAL))
+       return false;
+    return true;
+}
+
+void
+SwapDir::openLog(){}
+
+void
+SwapDir::closeLog(){}
+
+int
+SwapDir::writeCleanStart()
+{
+    return 0;
+}
+
+void
+SwapDir::writeCleanDone(){}
+
+void
+SwapDir::logEntry(const StoreEntry & e, int op) const{}
diff --git a/src/SwapDir.h b/src/SwapDir.h
new file mode 100644 (file)
index 0000000..2d7d03a
--- /dev/null
@@ -0,0 +1,101 @@
+
+/*
+ * $Id: SwapDir.h,v 1.1 2002/12/27 10:26:33 robertc Exp $
+ *
+ *
+ * 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_SWAPDIR_H
+#define SQUID_SWAPDIR_H
+
+#include "StoreIOState.h"
+
+/* Store dir configuration routines */
+/* SwapDir *sd, char *path ( + char *opt later when the strtok mess is gone) */
+typedef void STFSSTARTUP(void);
+typedef void STFSSHUTDOWN(void);
+typedef SwapDir *STFSNEW(void);
+struct SwapDir {
+public:
+    static SwapDir *Factory (_storefs_entry const &fs);
+    SwapDir() : max_objsize (-1){
+       fs.blksize = 1024;
+    }
+    virtual ~SwapDir();
+    virtual void reconfigure(int, char *) = 0;
+    const char *type;
+    int cur_size;
+    int low_size;
+    int max_size;
+    char *path;
+    int index;                 /* This entry's index into the swapDirs array */
+    ssize_t max_objsize;
+    RemovalPolicy *repl;
+    int removals;
+    int scanned;
+    struct {
+       unsigned int selected:1;
+       unsigned int read_only:1;
+    } flags;
+    virtual void init() = 0;   /* Initialise the fs */
+    virtual void newFileSystem();      /* Create a new fs */
+    virtual void dump(StoreEntry &)const;      /* Dump fs config snippet */
+    virtual bool doubleCheck(StoreEntry &);    /* Double check the obj integrity */
+    virtual void statfs(StoreEntry &) const;   /* Dump fs statistics */
+    virtual void maintainfs(); /* Replacement maintainence */
+    /* <0 == error. > 1000 == error */
+    virtual int canStore(StoreEntry const &)const = 0; /* Check if the fs will store an object */
+    /* These two are notifications */
+    virtual void reference(StoreEntry &);      /* Reference this object */
+    virtual void dereference(StoreEntry &);    /* Unreference this object */
+    virtual int callback();    /* Handle pending callbacks */
+    virtual void sync();       /* Sync the store prior to shutdown */
+    virtual StoreIOState::Pointer createStoreIO(StoreEntry &, STFNCB *, STIOCB *, void *) = 0;
+    virtual StoreIOState::Pointer openStoreIO(StoreEntry &, STFNCB *, STIOCB *, void *) = 0;
+    virtual void unlink (StoreEntry &);
+    bool canLog(StoreEntry const &e)const;
+    virtual void openLog();
+    virtual void closeLog();
+    virtual void logEntry(const StoreEntry & e, int op) const;
+    class CleanLog {
+      public:
+       virtual ~CleanLog(){}
+       virtual const StoreEntry *nextEntry() = 0;
+       virtual void write(StoreEntry const &) = 0;
+    };
+    CleanLog *cleanLog;
+    virtual int writeCleanStart();
+    virtual void writeCleanDone();
+    virtual void parse(int index, char *path) = 0;
+    struct {
+       int blksize;
+    } fs;
+};
+
+#endif /* SQUID_SWAPDIR_H */
index 4225b932e4fa1f0d9e0ecdba76cabb1de1bce32c..a0fe402c282d2dff48548dd5e13b66b39d7d8dc6 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: authenticate.cc,v 1.46 2002/10/15 09:25:33 robertc Exp $
+ * $Id: authenticate.cc,v 1.47 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 29    Authenticator
  * AUTHOR:  Robert Collins
@@ -207,7 +207,7 @@ AuthUser::operator new (size_t byteCount)
     assert (byteCount == sizeof (AuthUser));
     if (!pool)
        pool = memPoolCreate("Authenticate User Data", sizeof (auth_user_t));
-    return static_cast<auth_user_t *> (memPoolAlloc(pool));
+    return memPoolAlloc(pool);
 }
 
 AuthUser::AuthUser (const char *scheme) :
index 3d063d56899031c28a847bf1b8ede6df3e52eb32..6e27c4f8415a7203d8bc939ab66a17733f8a2e32 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cache_cf.cc,v 1.423 2002/12/07 01:55:22 hno Exp $
+ * $Id: cache_cf.cc,v 1.424 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 3     Configuration File Parsing
  * AUTHOR: Harvest Derived
@@ -36,6 +36,7 @@
 #include "squid.h"
 #include "authenticate.h"
 #include "Store.h"
+#include "SwapDir.h"
 
 #if SQUID_SNMP
 #include "snmp.h"
@@ -59,9 +60,9 @@ static const char *const B_GBYTES_STR = "GB";
 static const char *const list_sep = ", \t\n\r";
 
 static void parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *value, int reconfiguring);
-static void dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd);
+static void dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir const * sd);
 static void parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring);
-static void dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd);
+static void dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir const * sd);
 static struct cache_dir_option common_cachedir_options[] =
 {
     {"read-only", parse_cachedir_option_readonly, dump_cachedir_option_readonly},
@@ -253,8 +254,9 @@ update_maxobjsize(void)
     ssize_t ms = -1;
 
     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-       if (Config.cacheSwap.swapDirs[i].max_objsize > ms)
-           ms = Config.cacheSwap.swapDirs[i].max_objsize;
+       assert (Config.cacheSwap.swapDirs[i]);
+       if (Config.cacheSwap.swapDirs[i]->max_objsize > ms)
+           ms = Config.cacheSwap.swapDirs[i]->max_objsize;
     }
     store_maxobjsize = ms;
 }
@@ -1096,7 +1098,7 @@ free_http_header_replace(header_mangler header[])
 #endif
 
 void
-dump_cachedir_options(StoreEntry * entry, struct cache_dir_option *options, SwapDir * sd)
+dump_cachedir_options(StoreEntry * entry, struct cache_dir_option *options, SwapDir const * sd)
 {
     struct cache_dir_option *option;
     if (!options)
@@ -1110,11 +1112,11 @@ dump_cachedir(StoreEntry * entry, const char *name, _SquidConfig::_cacheSwap swa
 {
     SwapDir *s;
     int i;
+    assert (entry);
     for (i = 0; i < swap.n_configured; i++) {
-       s = swap.swapDirs + i;
+       s = swap.swapDirs[i];
        storeAppendPrintf(entry, "%s %s %s", name, s->type, s->path);
-       if (s->dump)
-           s->dump(entry, s);
+       s->dump(*entry);
        dump_cachedir_options(entry, common_cachedir_options, s);
        storeAppendPrintf(entry, "\n");
     }
@@ -1217,13 +1219,13 @@ allocate_new_swapdir(_SquidConfig::_cacheSwap * swap)
 {
     if (swap->swapDirs == NULL) {
        swap->n_allocated = 4;
-       swap->swapDirs = static_cast<SwapDir *>(xcalloc(swap->n_allocated, sizeof(SwapDir)));
+       swap->swapDirs = static_cast<SwapDir **>(xcalloc(swap->n_allocated, sizeof(SwapDir *)));
     }
     if (swap->n_allocated == swap->n_configured) {
-       SwapDir *tmp;
+       SwapDir **tmp;
        swap->n_allocated <<= 1;
-       tmp = static_cast<SwapDir *>(xcalloc(swap->n_allocated, sizeof(SwapDir)));
-       xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir));
+       tmp = static_cast<SwapDir **>(xcalloc(swap->n_allocated, sizeof(SwapDir *)));
+       xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir *));
        xfree(swap->swapDirs);
        swap->swapDirs = tmp;
     }
@@ -1275,14 +1277,15 @@ parse_cachedir(_SquidConfig::_cacheSwap * swap)
      */
 
     for (i = 0; i < swap->n_configured; i++) {
-       if (0 == strcasecmp(path_str, swap->swapDirs[i].path)) {
+       assert (swap->swapDirs[i]);
+       if (0 == strcasecmp(path_str, swap->swapDirs[i]->path)) {
            /* This is a little weird, you'll appreciate it later */
            fs = find_fstype(type_str);
            if (fs < 0) {
                fatalf("Unknown cache_dir type '%s'\n", type_str);
            }
-           sd = swap->swapDirs + i;
-           storefs_list[fs].reconfigurefunc(sd, i, path_str);
+           sd = swap->swapDirs[i];
+           sd->reconfigure (i, path_str);
            update_maxobjsize();
            return;
        }
@@ -1296,14 +1299,11 @@ parse_cachedir(_SquidConfig::_cacheSwap * swap)
        fatalf("Unknown cache_dir type '%s'\n", type_str);
     }
     allocate_new_swapdir(swap);
-    sd = swap->swapDirs + swap->n_configured;
-    sd->type = storefs_list[fs].typestr;
-    /* defaults in case fs implementation fails to set these */
-    sd->max_objsize = -1;
-    sd->fs.blksize = 1024;
+    swap->swapDirs[swap->n_configured] = SwapDir::Factory(storefs_list[fs]);
+    sd = swap->swapDirs[swap->n_configured];
     /* parse the FS parameters and options */
-    storefs_list[fs].parsefunc(sd, swap->n_configured, path_str);
-    swap->n_configured++;
+    sd->parse(swap->n_configured, path_str);
+    ++swap->n_configured;
     /* Update the max object size */
     update_maxobjsize();
 }
@@ -1320,7 +1320,7 @@ parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *val
 }
 
 static void
-dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd)
+dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir const * sd)
 {
     if (sd->flags.read_only)
        storeAppendPrintf(e, " %s", option);
@@ -1343,7 +1343,7 @@ parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *valu
 }
 
 static void
-dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd)
+dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir const * sd)
 {
     if (sd->max_objsize != -1)
        storeAppendPrintf(e, " %s=%ld", option, (long int) sd->max_objsize);
@@ -1395,15 +1395,14 @@ parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int recon
 static void
 free_cachedir(_SquidConfig::_cacheSwap * swap)
 {
-    SwapDir *s;
     int i;
     /* DON'T FREE THESE FOR RECONFIGURE */
     if (reconfiguring)
        return;
     for (i = 0; i < swap->n_configured; i++) {
-       s = swap->swapDirs + i;
-       s->freefs(s);
-       xfree(s->path);
+       SwapDir * s = swap->swapDirs[i];
+       swap->swapDirs[i] = NULL;
+       delete s;
     }
     safe_free(swap->swapDirs);
     swap->swapDirs = NULL;
index 39ff5b288a4cf5221971dc7d46830f6a971a50ad..6b0c3dd32f4f287a925d76d2360508415678ff1c 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side_reply.cc,v 1.26 2002/11/15 14:18:30 hno Exp $
+ * $Id: client_side_reply.cc,v 1.27 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 88    Client-side Reply Routines
  * AUTHOR: Robert Collins (Originally Duane Wessels in client_side.c)
@@ -540,7 +540,15 @@ clientCacheHit(void *data, StoreIOBuffer result)
        clientProcessMiss(context);
        return;
     }
-    assert(result.length > 0);
+    if (result.length == 0) {
+       /* the store couldn't get enough data from the file for us to id the
+        * object
+        */
+       /* treat as a miss */
+       http->logType = LOG_TCP_MISS;
+       clientProcessMiss(context);
+       return;
+    }
     mem = e->mem_obj;
     assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));
     /* update size of the request */
index fe8d3854b86883aa654c928654f0139c46aedad5..3f4fdf8ad1962f8dc5c6f34e46d49d611d4d58e6 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: async_io.cc,v 1.19 2002/11/15 13:16:31 hno Exp $
+ * $Id: async_io.cc,v 1.20 2002/12/27 10:26:35 robertc Exp $
  *
  * DEBUG: section 32    Asynchronous Disk I/O
  * AUTHOR: Pete Bentley <pete@demon.net>
@@ -293,7 +293,7 @@ aioTruncate(const char *path, off_t length, AIOCB * callback, void *callback_dat
 
 
 int
-aioCheckCallbacks(SwapDir * SD)
+AUFSSwapDir::callback()
 {
     squidaio_result_t *resultp;
     squidaio_ctrl_t *ctrlp;
@@ -380,14 +380,14 @@ aioStats(StoreEntry * sentry)
 
 /* Flush all pending I/O */
 void
-aioSync(SwapDir * SD)
+AUFSSwapDir::sync()
 {
     if (!initialised)
        return;                 /* nothing to do then */
     /* Flush all pending operations */
     debug(32, 1) ("aioSync: flushing pending I/O operations\n");
     do {
-       aioCheckCallbacks(SD);
+       callback();
     } while (squidaio_sync());
     debug(32, 1) ("aioSync: done\n");
 }
index f8c61349221ad2cca971435345208274fc81c82a..167f5218e3414a1c4b686ee7bfc61be5b2a2ca80 100644 (file)
@@ -76,56 +76,102 @@ void aioRead(int, int offset, int size, AIOCB *, void *);
 void aioStat(char *, struct stat *, AIOCB *, void *);
 void aioUnlink(const char *, AIOCB *, void *);
 void aioTruncate(const char *, off_t length, AIOCB *, void *);
-int aioCheckCallbacks(SwapDir *);
-void aioSync(SwapDir *);
 int aioQueueSize(void);
 
-struct _squidaiostate_t {
+#include "ufscommon.h"
+
+class AufsIO;
+class AUFSFile : public DiskFile {
+  public:
+    virtual void deleteSelf() const;
+    void * operator new (size_t);
+    void operator delete (void *);
+    AUFSFile (char const *path, AufsIO *);
+    ~AUFSFile();
+    virtual void open (int, mode_t, IORequestor::Pointer);
+    virtual void create (int, mode_t, IORequestor::Pointer);
+    virtual void read(char *, off_t, size_t);
+    virtual void write(char const *buf, size_t size, off_t offset, FREE *free_func);
+    void close();
+    virtual bool error() const;
+    virtual int getFD() const { return fd;}
+    virtual bool canRead() const;
+    virtual bool canWrite() const;
+  private:
+#if ASYNC_READ
+static AIOCB ReadDone;
+#else
+static DRCB ReadDone;
+#endif
+#if ASYNC_WRITE
+static AIOCB WriteDone;
+#else
+static DWCB WriteDone;
+#endif
+    int fd;
+    bool errorOccured;
+    char const *path_;
+    AufsIO* IO;
+    static AIOCB OpenDone;
+    void openDone(int fd, const char *buf, int aio_return, int aio_errno);
+    IORequestor::Pointer ioRequestor;
+    CBDATA_CLASS(AUFSFile);
+    void doClose();
+    
+    void readDone(int fd, const char *buf, int len, int errflag);
+    void writeDone (int fd, int errflag, size_t len);
+};
+
+class squidaiostate_t : public UFSStoreState {
+  public:
+    virtual void deleteSelf() const {delete this;}
+    void * operator new (size_t);
+    void operator delete (void *);
+    squidaiostate_t(SwapDir *, StoreEntry *, STIOCB *, void *);
+    ~squidaiostate_t();
+
+    void close();
     int fd;
     struct {
-       unsigned int close_request:1;
-       unsigned int reading:1;
-       unsigned int writing:1;
-       unsigned int opening:1;
        unsigned int write_kicking:1;
        unsigned int read_kicking:1;
        unsigned int inreaddone:1;
     } flags;
-    char *read_buf;
-    link_list *pending_writes;
-    link_list *pending_reads;
+    void ioCompletedNotification();
+    void closeCompleted();
+    void readCompleted(const char *buf, int len, int errflag);
+    void writeCompleted(int errflag, size_t len);
+    void writeDone(int fd, int errflag, size_t len);
+  private:
+    CBDATA_CLASS(squidaiostate_t);
+    void openDone();
 };
 
-struct _queued_write {
-    char *buf;
-    size_t size;
-    off_t offset;
-    FREE *free_func;
-};
-
-struct _queued_read {
-    char *buf;
-    size_t size;
-    off_t offset;
-    STRCB *callback;
-    void *callback_data;
-};
-
-typedef struct _squidaiostate_t squidaiostate_t;
-
-/* The squidaio_state memory pools */
-extern MemPool *squidaio_state_pool;
-extern MemPool *aufs_qread_pool;
-extern MemPool *aufs_qwrite_pool;
-
 /*
  * Store IO stuff
  */
-extern STOBJCREATE storeAufsCreate;
-extern STOBJOPEN storeAufsOpen;
-extern STOBJCLOSE storeAufsClose;
-extern STOBJREAD storeAufsRead;
-extern STOBJWRITE storeAufsWrite;
-extern STOBJUNLINK storeAufsUnlink;
+#include "SwapDir.h"
+class AUFSSwapDir : public UFSSwapDir
+{
+public:
+  virtual void dump(StoreEntry &)const;
+  virtual void unlink(StoreEntry &);
+  virtual int canStore(StoreEntry const &)const;
+  virtual int callback();
+  virtual void sync();
+  virtual void parse (int index, char *path);
+  virtual void reconfigure(int, char *);
+  virtual void unlinkFile(char const *);
+};
+
+class AufsIO : public UFSStrategy
+{
+public:
+   virtual bool shedLoad();
+   virtual void deleteSelf() const;
+   virtual StoreIOState::Pointer createState(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data) const;
+   virtual DiskFile::Pointer newFile(char const *path);
+   static AufsIO Instance;
+};
 
 #endif
index e0b89e6c9d60170e122434666ba482bb5ae97f23..45cf1efa8ea6debf7c135ebf0c999d7894e816e2 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_dir_aufs.cc,v 1.52 2002/11/10 02:29:58 hno Exp $
+ * $Id: store_dir_aufs.cc,v 1.53 2002/12/27 10:26:35 robertc Exp $
  *
  * DEBUG: section 47    Store Directory Routines
  * AUTHOR: Duane Wessels
 
 #include "store_asyncufs.h"
 #include "ufscommon.h"
+#include "SwapDir.h"
 
-MemPool *squidaio_state_pool = NULL;
 MemPool *aufs_qread_pool = NULL;
 MemPool *aufs_qwrite_pool = NULL;
 static int asyncufs_initialised = 0;
 
-static STDUMP storeAufsDirDump;
-static STCHECKOBJ storeAufsDirCheckObj;
-static void storeAufsDirIOUnlinkFile(char *path);
-
-
 /* The MAIN externally visible function */
 STSETUP storeFsSetup_aufs;
 
@@ -60,15 +55,15 @@ STSETUP storeFsSetup_aufs;
  * happily store anything as long as the LRU time isn't too small.
  */
 int
-storeAufsDirCheckObj(SwapDir * SD, const StoreEntry * e)
+AUFSSwapDir::canStore(StoreEntry const &e) const
 {
     int loadav;
     int ql;
 
 #if OLD_UNUSED_CODE
-    if (storeAufsDirExpiredReferenceAge(SD) < 300) {
+    if (storeAufsDirExpiredReferenceAge(this) < 300) {
        debug(47, 3) ("storeAufsDirCheckObj: NO: LRU Age = %d\n",
-           storeAufsDirExpiredReferenceAge(SD));
+           storeAufsDirExpiredReferenceAge(this));
        /* store_check_cachable_hist.no.lru_age_too_low++; */
        return -1;
     }
@@ -82,7 +77,7 @@ storeAufsDirCheckObj(SwapDir * SD, const StoreEntry * e)
 }
 
 void
-storeAufsDirIOUnlinkFile(char *path)
+AUFSSwapDir::unlinkFile(char const *path)
 {
 #if USE_TRUNCATE_NOT_UNLINK
     aioTruncate(path, NULL, NULL);
@@ -107,117 +102,31 @@ static struct cache_dir_option options[] =
  *
  * This routine is called when the given swapdir needs reconfiguring 
  */
-static void
-storeAufsDirReconfigure(SwapDir * sd, int index, char *path)
+void
+AUFSSwapDir::reconfigure(int anIndex, char *aPath)
 {
-    int i;
-    int size;
-    int l1;
-    int l2;
-
-    i = GetInteger();
-    size = i << 10;            /* Mbytes to kbytes */
-    if (size <= 0)
-       fatal("storeAufsDirReconfigure: invalid size value");
-    i = GetInteger();
-    l1 = i;
-    if (l1 <= 0)
-       fatal("storeAufsDirReconfigure: invalid level 1 directories value");
-    i = GetInteger();
-    l2 = i;
-    if (l2 <= 0)
-       fatal("storeAufsDirReconfigure: invalid level 2 directories value");
-
-    /* just reconfigure it */
-    if (size == sd->max_size)
-       debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n",
-           path, size);
-    else
-       debug(3, 1) ("Cache dir '%s' size changed to %d KB\n",
-           path, size);
-    sd->max_size = size;
-
-    parse_cachedir_options(sd, options, 0);
-
-    return;
+    UFSSwapDir::reconfigure (anIndex, aPath);
+
+    parse_cachedir_options(this, options, 0);
 }
 
 void
-storeAufsDirDump(StoreEntry * entry, SwapDir * s)
+AUFSSwapDir::dump(StoreEntry & entry) const
 {
-    commonUfsDirDump(entry, s);
-    dump_cachedir_options(entry, options, s);
+    UFSSwapDir::dump(entry);
+    dump_cachedir_options(&entry, options, this);
 }
 
 /*
  * storeAufsDirParse *
  * Called when a *new* fs is being setup.
  */
-static void
-storeAufsDirParse(SwapDir * sd, int index, char *path)
+void
+AUFSSwapDir::parse(int anIndex, char *aPath)
 {
-    int i;
-    int size;
-    int l1;
-    int l2;
-    squidufsinfo_t *aioinfo;
-
-    i = GetInteger();
-    size = i << 10;            /* Mbytes to kbytes */
-    if (size <= 0)
-       fatal("storeAufsDirParse: invalid size value");
-    i = GetInteger();
-    l1 = i;
-    if (l1 <= 0)
-       fatal("storeAufsDirParse: invalid level 1 directories value");
-    i = GetInteger();
-    l2 = i;
-    if (l2 <= 0)
-       fatal("storeAufsDirParse: invalid level 2 directories value");
-
-    aioinfo = (squidufsinfo_t *)xmalloc(sizeof(squidufsinfo_t));
-    if (aioinfo == NULL)
-       fatal("storeAufsDirParse: couldn't xmalloc() squidufsinfo_t!\n");
-
-    sd->index = index;
-    sd->path = xstrdup(path);
-    sd->max_size = size;
-    sd->fsdata = aioinfo;
-    aioinfo->l1 = l1;
-    aioinfo->l2 = l2;
-    aioinfo->swaplog_fd = -1;
-    aioinfo->map = NULL;       /* Debugging purposes */
-    aioinfo->suggest = 0;
-    aioinfo->io.storeDirUnlinkFile = storeAufsDirIOUnlinkFile;
-    sd->init = commonUfsDirInit;
-    sd->newfs = commonUfsDirNewfs;
-    sd->dump = storeAufsDirDump;
-    sd->freefs = commonUfsDirFree;
-    sd->dblcheck = commonUfsCleanupDoubleCheck;
-    sd->statfs = commonUfsDirStats;
-    sd->maintainfs = commonUfsDirMaintain;
-    sd->checkobj = storeAufsDirCheckObj;
-    sd->refobj = commonUfsDirRefObj;
-    sd->unrefobj = commonUfsDirUnrefObj;
-    sd->callback = aioCheckCallbacks;
-    sd->sync = aioSync;
-    sd->obj.create = storeAufsCreate;
-    sd->obj.open = storeAufsOpen;
-    sd->obj.close = storeAufsClose;
-    sd->obj.read = storeAufsRead;
-    sd->obj.write = storeAufsWrite;
-    sd->obj.unlink = storeAufsUnlink;
-    sd->log.open = commonUfsDirOpenSwapLog;
-    sd->log.close = commonUfsDirCloseSwapLog;
-    sd->log.write = commonUfsDirSwapLog;
-    sd->log.clean.start = commonUfsDirWriteCleanStart;
-    sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry;
-    sd->log.clean.done = commonUfsDirWriteCleanDone;
-
-    parse_cachedir_options(sd, options, 0);
-
-    /* Initialise replacement policy stuff */
-    sd->repl = createRemovalPolicy(Config.replPolicy);
+    UFSSwapDir::parse(anIndex, aPath);
+
+    parse_cachedir_options(this, options, 0);
 }
 
 /*
@@ -227,24 +136,25 @@ static void
 storeAufsDirDone(void)
 {
     aioDone();
-    memPoolDestroy(&squidaio_state_pool);
     memPoolDestroy(&aufs_qread_pool);
     memPoolDestroy(&aufs_qwrite_pool);
     asyncufs_initialised = 0;
 }
 
+static SwapDir *
+storeAufsNew(void)
+{
+    AUFSSwapDir *result = new AUFSSwapDir;
+    result->IO = &AufsIO::Instance;
+    return result;
+}
+
 void
 storeFsSetup_aufs(storefs_entry_t * storefs)
 {
     assert(!asyncufs_initialised);
-    storefs->parsefunc = storeAufsDirParse;
-    storefs->reconfigurefunc = storeAufsDirReconfigure;
     storefs->donefunc = storeAufsDirDone;
-    squidaio_state_pool = memPoolCreate("AUFS IO State data", sizeof(squidaiostate_t));
-    aufs_qread_pool = memPoolCreate("AUFS Queued read data",
-       sizeof(queued_read));
-    aufs_qwrite_pool = memPoolCreate("AUFS Queued write data",
-       sizeof(queued_write));
+    storefs->newfunc = storeAufsNew;
 
     asyncufs_initialised = 1;
     aioInit();
index 7ceebdebd18914f9d9a2bbdfc5dfbad484372596..f908d2f873c6bdf992b762f163dd8cc6fed450fe 100644 (file)
 #include "store_asyncufs.h"
 #include "Store.h"
 #include "ufscommon.h"
+#include "SwapDir.h"
 
-#if ASYNC_READ
-static AIOCB storeAufsReadDone;
-#else
-static DRCB storeAufsReadDone;
-#endif
-#if ASYNC_WRITE
-static AIOCB storeAufsWriteDone;
-#else
-static DWCB storeAufsWriteDone;
-#endif
 static void storeAufsIOCallback(storeIOState * sio, int errflag);
-static AIOCB storeAufsOpenDone;
 static int storeAufsNeedCompletetion(storeIOState *);
-static int storeAufsKickWriteQueue(storeIOState * sio);
-static CBDUNL storeAufsIOFreeEntry;
-
-CBDATA_TYPE(storeIOState);
 
 /* === PUBLIC =========================================================== */
 
-/* open for reading */
-storeIOState *
-storeAufsOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
-    STIOCB * callback, void *callback_data)
+
+
+CBDATA_CLASS_INIT(squidaiostate_t);
+
+void *
+squidaiostate_t::operator new (size_t)
+{
+    CBDATA_INIT_TYPE(squidaiostate_t);
+    squidaiostate_t *result = cbdataAlloc(squidaiostate_t);
+    /* Mark result as being owned - we want the refcounter to do the delete
+     * call */
+    cbdataReference(result);
+    return result;
+}
+void
+squidaiostate_t::operator delete (void *address)
+{
+    squidaiostate_t *t = static_cast<squidaiostate_t *>(address);
+    cbdataFree(address);
+    /* And allow the memory to be freed */
+    cbdataReferenceDone (t);
+}
+    
+squidaiostate_t::squidaiostate_t(SwapDir * SD, StoreEntry * anEntry, STIOCB * callback_, void *callback_data_)
+{
+    swap_filen = anEntry->swap_filen;
+    swap_dirn = SD->index;
+    mode = O_BINARY;
+    callback = callback_;
+    callback_data = cbdataReference(callback_data_);
+    e = anEntry;
+    fd = -1;
+}
+
+AufsIO AufsIO::Instance;
+bool
+AufsIO::shedLoad()
 {
-    sfileno f = e->swap_filen;
-    char *path = commonUfsDirFullPath(SD, f, NULL);
-    storeIOState *sio;
-#if !ASYNC_OPEN
-    int fd;
-#endif
-    debug(79, 3) ("storeAufsOpen: fileno %08X\n", f);
     /*
      * we should detect some 'too many files open' condition and return
      * NULL here.
      */
 #ifdef MAGIC2
     if (aioQueueSize() > MAGIC2)
-       return NULL;
+       return true;
 #endif
+    return false;
+}
+void
+AufsIO::deleteSelf() const
+{
+    /* do nothing, we use a single instance */
+}
+
+StoreIOState::Pointer
+AufsIO::createState(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data) const
+{
+    return new squidaiostate_t (SD, e, callback, callback_data);
+}
+
+DiskFile::Pointer
+AufsIO::newFile (char const *path)
+{
+    return new AUFSFile (path, this);
+}
+
+CBDATA_CLASS_INIT(AUFSFile);
+void *
+AUFSFile::operator new (size_t)
+{
+    CBDATA_INIT_TYPE(AUFSFile);
+    AUFSFile *result = cbdataAlloc(AUFSFile);
+    /* Mark result as being owned - we want the refcounter to do the delete
+     * call */
+    cbdataReference(result);
+    return result;
+}
+void
+AUFSFile::operator delete (void *address)
+{
+    AUFSFile *t = static_cast<AUFSFile *>(address);
+    cbdataFree(address);
+    /* And allow the memory to be freed */
+    cbdataReferenceDone (t);
+}
+
+void
+AUFSFile::deleteSelf() const {delete this;}
+
+AUFSFile::AUFSFile (char const *aPath, AufsIO *anIO):fd(-1), errorOccured (false), IO(anIO) {
+    assert (aPath);
+    debug (79,0)("UFSFile::UFSFile: %s\n", aPath);
+    path_ = xstrdup (aPath);
+}
+
+AUFSFile::~AUFSFile()
+{
+    safe_free (path_);
+    doClose();
+}
+
+void
+AUFSFile::open (int flags, mode_t mode, IORequestor::Pointer callback)
+{
 #if !ASYNC_OPEN
-    fd = file_open(path, O_RDONLY | O_BINARY);
+    fd = file_open(path_, flags);
     if (fd < 0) {
-       debug(79, 3) ("storeAufsOpen: got failure (%d)\n", errno);
-       return NULL;
+       debug(79, 3) ("AUFSFile::open: got failure (%d)\n", errno);
+       errorOccured = true;
+       return;
     }
 #endif
-    CBDATA_INIT_TYPE_FREECB(storeIOState, storeAufsIOFreeEntry);
-    sio = cbdataAlloc(storeIOState);
-    sio->fsstate = memPoolAlloc(squidaio_state_pool);
-    ((squidaiostate_t *) (sio->fsstate))->fd = -1;
-    ((squidaiostate_t *) (sio->fsstate))->flags.opening = 1;
-    sio->swap_filen = f;
-    sio->swap_dirn = SD->index;
-    sio->mode = O_RDONLY | O_BINARY;
-    sio->callback = callback;
-    sio->callback_data = cbdataReference(callback_data);
-    sio->e = e;
     Opening_FD++;
+    ioRequestor = callback;
 #if ASYNC_OPEN
-    aioOpen(path, O_RDONLY | O_BINARY, 0644, storeAufsOpenDone, sio);
+    aioOpen(path_, flags, mode, AUFSFile::OpenDone, this);
 #else
-    storeAufsOpenDone(fd, sio, fd, 0);
+    openDone(fd, NULL, fd, 0);
 #endif
-    return sio;
 }
 
-/* open for creating */
-storeIOState *
-storeAufsCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data)
+void
+AUFSFile::read(char *buf, off_t offset, size_t size)
 {
-    char *path;
-    storeIOState *sio;
-    sfileno filn;
-    sdirno dirn;
-#if !ASYNC_CREATE
-    int fd;
+    assert (fd > -1);
+    assert (ioRequestor.getRaw());
+#if ASYNC_READ
+    aioRead(fd, offset, size, ReadDone, this);
+#else
+    file_read(fd, buf, size, offset, ReadDone, this);
 #endif
+}
 
-    /* Allocate a number */
-    dirn = SD->index;
-    filn = commonUfsDirMapBitAllocate(SD);
-    path = commonUfsDirFullPath(SD, filn, NULL);
-
-    debug(79, 3) ("storeAufsCreate: fileno %08X\n", filn);
-    /*
-     * we should detect some 'too many files open' condition and return
-     * NULL here.
-     */
-#ifdef MAGIC2
-    if (aioQueueSize() > MAGIC2)
-       return NULL;
-#endif
+void
+AUFSFile::create (int flags, mode_t mode, IORequestor::Pointer callback)
+{
 #if !ASYNC_CREATE
-    fd = file_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
+    int fd = file_open(path_, flags);
     if (fd < 0) {
        debug(79, 3) ("storeAufsCreate: got failure (%d)\n", errno);
-       return NULL;
+       errorOccured = true;
+       return;
     }
 #endif
-    CBDATA_INIT_TYPE_FREECB(storeIOState, storeAufsIOFreeEntry);
-    sio = cbdataAlloc(storeIOState);
-    sio->fsstate = memPoolAlloc(squidaio_state_pool);
-    ((squidaiostate_t *) (sio->fsstate))->fd = -1;
-    ((squidaiostate_t *) (sio->fsstate))->flags.opening = 1;
-    sio->swap_filen = filn;
-    sio->swap_dirn = dirn;
-    sio->mode = O_WRONLY | O_BINARY;
-    sio->callback = callback;
-    sio->callback_data = cbdataReference(callback_data);
-    sio->e = (StoreEntry *) e;
     Opening_FD++;
+    ioRequestor = callback;
 #if ASYNC_CREATE
-    aioOpen(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644, storeAufsOpenDone, sio);
+    aioOpen(path_, flags, mode, AUFSFile::OpenDone, this);
 #else
-    storeAufsOpenDone(fd, sio, fd, 0);
+    openDone (fd, NULL, fd, 0);
 #endif
+}
 
-    /* now insert into the replacement policy */
-    commonUfsDirReplAdd(SD, e);
-    return sio;
+bool
+AUFSFile::error() const
+{
+    return errorOccured;
+}
 
+void
+AUFSFile::OpenDone(int fd, void *cbdata, const char *buf, int aio_return, int aio_errno)
+{
+    AUFSFile *myFile = static_cast<AUFSFile *>(cbdata);
+    myFile->openDone (fd, buf, aio_return, aio_errno);
 }
 
+void
+AUFSFile::openDone(int unused, const char *unused2, int anFD, int errflag)
+{
+    debug(79, 3) ("AUFSFile::openDone: FD %d, errflag %d\n", anFD, errflag);
+    Opening_FD--;
 
+    fd = anFD;
+    if (errflag || fd < 0) {
+       errno = errflag;
+       debug(79, 0) ("AUFSFile::openDone: %s\n", xstrerror());
+       debug(79, 1) ("\t%s\n", path_);
+       errorOccured = true;
+    } else {
+       store_open_disk_fd++;
+       commSetCloseOnExec(fd);
+       fd_open(fd, FD_FILE, path_);
+    }
+    
+    debug(79, 3) ("AUFSFile::openDone: exiting\n");
 
-/* Close */
-void
-storeAufsClose(SwapDir * SD, storeIOState * sio)
+    IORequestor::Pointer t = ioRequestor;
+    t->ioCompletedNotification();
+}
+
+void AUFSFile::doClose()
 {
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
-    debug(79, 3) ("storeAufsClose: dirno %d, fileno %08X, FD %d\n",
-       sio->swap_dirn, sio->swap_filen, aiostate->fd);
-    if (storeAufsNeedCompletetion(sio)) {
-       aiostate->flags.close_request = 1;
-       return;
+    if (fd > -1) {
+       aioClose(fd);
+       fd_close(fd);
+       store_open_disk_fd--;
+       fd = -1;
     }
-    storeAufsIOCallback(sio, DISK_OK);
 }
 
+/* open for reading */
+StoreIOState::Pointer
+storeAufsOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
+    STIOCB * callback, void *callback_data)
+{
+    UFSStrategy *IO = dynamic_cast <UFSStrategy *>(((AUFSSwapDir *)SD)->IO);
+    assert (IO);
+    return IO->open (SD, e, file_callback, callback, callback_data);
+}
+
+/* open for creating */
+StoreIOState::Pointer
+storeAufsCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data)
+{
+    UFSStrategy *IO = dynamic_cast <UFSStrategy *>(((AUFSSwapDir *)SD)->IO);
+    assert (IO);
+    return IO->create (SD, e, file_callback, callback, callback_data);
+}
 
-/* Read */
+/* Close */
 void
-storeAufsRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
-{
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
-    assert(sio->read.callback == NULL);
-    assert(sio->read.callback_data == NULL);
-    assert(!aiostate->flags.reading);
-    if (aiostate->fd < 0) {
-       struct _queued_read *q;
-       debug(79, 3) ("storeAufsRead: queueing read because FD < 0\n");
-       assert(aiostate->flags.opening);
-       assert(aiostate->pending_reads == NULL);
-       q = (struct _queued_read *)memPoolAlloc(aufs_qread_pool);
-       q->buf = buf;
-       q->size = size;
-       q->offset = offset;
-       q->callback = callback;
-       q->callback_data = cbdataReference(callback_data);
-       linklistPush(&(aiostate->pending_reads), q);
+squidaiostate_t::close()
+{
+    debug(79, 3) ("storeAufsClose: dirno %d, fileno %08X, FD %d\n",
+       swap_dirn, swap_filen, fd);
+    /* mark the object to be closed on the next io that completes */
+    if (storeAufsNeedCompletetion(this)) {
+       closing = true;
        return;
     }
-    sio->read.callback = callback;
-    sio->read.callback_data = cbdataReference(callback_data);
-    aiostate->read_buf = buf;
-    debug(79, 3) ("storeAufsRead: dirno %d, fileno %08X, FD %d\n",
-       sio->swap_dirn, sio->swap_filen, aiostate->fd);
-    sio->offset = offset;
-    aiostate->flags.reading = 1;
-#if ASYNC_READ
-    aioRead(aiostate->fd, offset, size, storeAufsReadDone, sio);
-#else
-    file_read(aiostate->fd, buf, size, offset, storeAufsReadDone, sio);
-#endif
+    storeAufsIOCallback(this, DISK_OK);
 }
 
+bool
+AUFSFile::canRead() const
+{
+    debug (79,3)("AUFSFile::canRead: fd is %d\n",fd);
+    return fd > -1;
+}
 
-/* Write */
 void
-storeAufsWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func)
-{
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
-    debug(79, 3) ("storeAufsWrite: dirno %d, fileno %08X, FD %d\n",
-       sio->swap_dirn, sio->swap_filen, aiostate->fd);
-    if (aiostate->fd < 0) {
-       /* disk file not opened yet */
-       struct _queued_write *q;
-       assert(aiostate->flags.opening);
-       q = (struct _queued_write *)memPoolAlloc(aufs_qwrite_pool);
-       q->buf = buf;
-       q->size = size;
-       q->offset = offset;
-       q->free_func = free_func;
-       linklistPush(&(aiostate->pending_writes), q);
-       return;
-    }
+AUFSFile::write(char const *buf, size_t size, off_t offset, FREE *free_func)
+{
+    debug(79, 3) ("storeAufsWrite: FD %d\n", fd);
 #if ASYNC_WRITE
-    if (aiostate->flags.writing) {
-       struct _queued_write *q;
-       debug(79, 3) ("storeAufsWrite: queuing write\n");
-       q = (struct _queued_write *)memPoolAlloc(aufs_qwrite_pool);
-       q->buf = buf;
-       q->size = size;
-       q->offset = offset;
-       q->free_func = free_func;
-       linklistPush(&(aiostate->pending_writes), q);
-       return;
-    }
-    aiostate->flags.writing = 1;
-    aioWrite(aiostate->fd, offset, buf, size, storeAufsWriteDone, sio,
+    aioWrite(fd, offset, (char *)buf, size, WriteDone, this,
        free_func);
 #else
-    file_write(aiostate->fd, offset, buf, size, storeAufsWriteDone, sio,
+    file_write(fd, offset, (char *)buf, size, WriteDone, this,
        free_func);
 #endif
 }
 
+bool
+AUFSFile::canWrite() const {
+    return fd > -1;
+}
+
 /* Unlink */
 void
-storeAufsUnlink(SwapDir * SD, StoreEntry * e)
+AUFSSwapDir::unlink(StoreEntry & e)
 {
-    debug(79, 3) ("storeAufsUnlink: dirno %d, fileno %08X\n", SD->index, e->swap_filen);
-    commonUfsDirReplRemove(e);
-    commonUfsDirMapBitReset(SD, e->swap_filen);
-    commonUfsDirUnlinkFile(SD, e->swap_filen);
+    debug(79, 3) ("storeAufsUnlink: dirno %d, fileno %08X\n", index, e.swap_filen);
+    replacementRemove(&e);
+    mapBitReset(e.swap_filen);
+    UFSSwapDir::unlinkFile(e.swap_filen);
 }
 
 /*  === STATIC =========================================================== */
 
-static int
-storeAufsKickWriteQueue(storeIOState * sio)
+#if ASYNC_READ
+void
+AUFSFile::ReadDone(int fd, void *my_data, const char *buf, int len, int errflag)
+#else
+void
+AUFSFile::ReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
+#endif
 {
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
-    struct _queued_write *q = (struct _queued_write *)linklistShift(&aiostate->pending_writes);
-    if (NULL == q)
-       return 0;
-    debug(79, 3) ("storeAufsKickWriteQueue: writing queued chunk of %ld bytes\n",
-       (long int) q->size);
-    storeAufsWrite(INDEXSD(sio->swap_dirn), sio, q->buf, q->size, q->offset, q->free_func);
-    memPoolFree(aufs_qwrite_pool, q);
-    return 1;
+    AUFSFile *myFile = static_cast<AUFSFile *>(my_data);
+    assert (myFile);
+    myFile->readDone (fd, buf, len, errflag); 
 }
 
-static int
-storeAufsKickReadQueue(storeIOState * sio)
+void
+AUFSFile::readDone(int rvfd, const char *buf, int len, int errflag)
 {
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
-    struct _queued_read *q = (struct _queued_read *)linklistShift(&(aiostate->pending_reads));
-    void *cbdata;
-    if (NULL == q)
-       return 0;
-    debug(79, 3) ("storeAufsKickReadQueue: reading queued request of %ld bytes\n",
-       (long int) q->size);
-    if (cbdataReferenceValidDone(q->callback_data, &cbdata))
-       storeAufsRead(INDEXSD(sio->swap_dirn), sio, q->buf, q->size, q->offset, q->callback, cbdata);
-    memPoolFree(aufs_qread_pool, q);
-    return 1;
-}
+    debug (79,3)("AUFSFile::readDone: FD %d\n",rvfd);
+    assert (fd == rvfd);
 
-static void
-storeAufsOpenDone(int unused, void *my_data, const char *unused2, int fd, int errflag)
-{
-    storeIOState *sio = (storeIOState *)my_data;
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
-    debug(79, 3) ("storeAufsOpenDone: FD %d, errflag %d\n", fd, errflag);
-    Opening_FD--;
-    aiostate->flags.opening = 0;
-    if (errflag || fd < 0) {
-       errno = errflag;
-       debug(79, 0) ("storeAufsOpenDone: %s\n", xstrerror());
-       debug(79, 1) ("\t%s\n", commonUfsDirFullPath(INDEXSD(sio->swap_dirn), sio->swap_filen, NULL));
-       storeAufsIOCallback(sio, DISK_ERROR);
-       return;
-    }
-    store_open_disk_fd++;
-    aiostate->fd = fd;
-    commSetCloseOnExec(fd);
-    fd_open(fd, FD_FILE, commonUfsDirFullPath(INDEXSD(sio->swap_dirn), sio->swap_filen, NULL));
-    if (FILE_MODE(sio->mode) == O_WRONLY) {
-       if (storeAufsKickWriteQueue(sio))
-           return;
-    } else if ((FILE_MODE(sio->mode) == O_RDONLY) && !aiostate->flags.close_request) {
-       if (storeAufsKickReadQueue(sio))
-           return;
-    }
-    if (aiostate->flags.close_request)
-       storeAufsIOCallback(sio, errflag);
-    debug(79, 3) ("storeAufsOpenDone: exiting\n");
-}
-
-#if ASYNC_READ
-static void
-storeAufsReadDone(int fd, void *my_data, const char *buf, int len, int errflag)
-#else
-static void
-storeAufsReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
-#endif
-{
-    storeIOState *sio = (storeIOState *)my_data;
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
-    STRCB *callback = sio->read.callback;
-    void *cbdata;
     ssize_t rlen;
-    int inreaddone = aiostate->flags.inreaddone;       /* Protect from callback loops */
-    debug(79, 3) ("storeAufsReadDone: dirno %d, fileno %08X, FD %d, len %d\n",
-       sio->swap_dirn, sio->swap_filen, fd, len);
-    aiostate->flags.inreaddone = 1;
-    aiostate->flags.reading = 0;
     if (errflag) {
-       debug(79, 3) ("storeAufsReadDone: got failure (%d)\n", errflag);
+       debug(79, 3) ("AUFSFile::readDone: got failure (%d)\n", errflag);
        rlen = -1;
     } else {
        rlen = (ssize_t) len;
-       sio->offset += len;
     }
 #if ASYNC_READ
     /* translate errflag from errno to Squid disk error */
@@ -335,33 +323,87 @@ storeAufsReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
     if (errflag == DISK_EOF)
        errflag = DISK_OK;      /* EOF is signalled by len == 0, not errors... */
 #endif
+    ioRequestor->readCompleted(buf, rlen, errflag);
+}
+
+void
+squidaiostate_t::readCompleted(const char *buf, int len, int errflag)
+{
+    int localinreaddone = flags.inreaddone;    /* Protect from callback loops */
+    flags.inreaddone = 1;
+    reading = false;
+    debug(79, 3) ("squidaiostate_t::readCompleted: dirno %d, fileno %08X, len %d\n",
+       swap_dirn, swap_filen, len);
+    if (len > 0)
+       offset_ += len;
+
+    STRCB *callback = read.callback;
     assert(callback);
-    sio->read.callback = NULL;
-    if (!aiostate->flags.close_request && cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) {
-#if ASYNC_READ
-       if (rlen > 0)
-           memcpy(aiostate->read_buf, buf, rlen);
-#endif
-       callback(cbdata, aiostate->read_buf, rlen);
+    read.callback = NULL;
+    void *cbdata;
+    if (!closing && cbdataReferenceValidDone(read.callback_data, &cbdata)) {
+       if (len > 0 && read_buf != buf)
+           memcpy(read_buf, buf, len);
+       callback(cbdata, read_buf, len);
     }
-    aiostate->flags.inreaddone = 0;
-    if (aiostate->flags.close_request && !inreaddone)
-       storeAufsIOCallback(sio, errflag);
+
+    flags.inreaddone = 0;
+    if (closing && !localinreaddone)
+       storeAufsIOCallback(this, errflag);
 }
+  
+
+void
+squidaiostate_t::writeCompleted(int errflag, size_t len)
+{
+    debug(79, 3) ("storeAufsWriteDone: dirno %d, fileno %08X, len %ld, err=%d\n",
+       swap_dirn, swap_filen, (long int) len, errflag);
+    writing = false;
+    if (errflag) {
+       debug(79, 0) ("storeAufsWriteDone: got failure (%d)\n", errflag);
+       storeAufsIOCallback(this, errflag);
+       return;
+    }
+    offset_ += len;
 
 #if ASYNC_WRITE
-static void
-storeAufsWriteDone(int fd, void *my_data, int len, int errflag)
+    if (!kickWriteQueue())
+       0;
+    else if (closing)
+       storeAufsIOCallback(this, errflag);
 #else
-static void
-storeAufsWriteDone(int fd, int errflag, size_t len, void *my_data)
+    if (!flags.write_kicking) {
+       flags.write_kicking = 1;
+       while (kickWriteQueue())
+           (void) 0;
+       flags.write_kicking = 0;
+       if (closing)
+           storeAufsIOCallback(this, errflag);
+    }
+#endif
+}
+
+void
+AUFSFile::
+#if ASYNC_WRITE
+WriteDone(int fd, void *my_data, int len, int errflag)
+#else
+WriteDone(int fd, int errflag, size_t len, void *my_data)
 #endif
 {
+    AUFSFile *aFile = static_cast<AUFSFile *>(my_data);
+    assert (aFile);
+    aFile->writeDone (fd, errflag, len);
+}
+
+void
+AUFSFile::writeDone (int rvfd, int errflag, size_t len)
+{
+    assert (rvfd == fd);
     static int loop_detect = 0;
-    storeIOState *sio = (storeIOState *)my_data;
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
-    debug(79, 3) ("storeAufsWriteDone: dirno %d, fileno %08X, FD %d, len %ld, err=%d\n",
-       sio->swap_dirn, sio->swap_filen, fd, (long int) len, errflag);
+    debug(79, 3) ("storeAufsWriteDone: FD %d, len %ld, err=%d\n",
+       fd, (long int) len, errflag);
+
 #if ASYNC_WRITE
     /* Translate from errno to Squid disk error */
     errno = errflag;
@@ -371,37 +413,16 @@ storeAufsWriteDone(int fd, int errflag, size_t len, void *my_data)
        errflag = DISK_OK;
 #endif
     assert(++loop_detect < 10);
-    aiostate->flags.writing = 0;
-    if (errflag) {
-       debug(79, 0) ("storeAufsWriteDone: got failure (%d)\n", errflag);
-       storeAufsIOCallback(sio, errflag);
-       loop_detect--;
-       return;
-    }
-    sio->offset += len;
-#if ASYNC_WRITE
-    if (!storeAufsKickWriteQueue(sio))
-       0;
-    else if (aiostate->flags.close_request)
-       storeAufsIOCallback(sio, errflag);
-#else
-    if (!aiostate->flags.write_kicking) {
-       aiostate->flags.write_kicking = 1;
-       while (storeAufsKickWriteQueue(sio))
-           (void) 0;
-       aiostate->flags.write_kicking = 0;
-       if (aiostate->flags.close_request)
-           storeAufsIOCallback(sio, errflag);
-    }
-#endif
-    loop_detect--;
+
+    ioRequestor->writeCompleted(errflag, len);
+    --loop_detect;
 }
 
 static void
 storeAufsIOCallback(storeIOState * sio, int errflag)
 {
     STIOCB *callback = sio->callback;
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
+    squidaiostate_t *aiostate = dynamic_cast<squidaiostate_t *>(sio);
     int fd = aiostate->fd;
     debug(79, 3) ("storeAufsIOCallback: errflag=%d\n", errflag);
     debug(79, 9) ("%s:%d\n", __FILE__, __LINE__);
@@ -413,15 +434,12 @@ storeAufsIOCallback(storeIOState * sio, int errflag)
     }
     debug(79, 9) ("%s:%d\n", __FILE__, __LINE__);
     aiostate->fd = -1;
-    cbdataFree(sio);
-    if (aiostate->flags.opening)
+    if (aiostate->opening || aiostate->creating)
        Opening_FD--;
     if (fd < 0)
        return;
     debug(79, 9) ("%s:%d\n", __FILE__, __LINE__);
-    aioClose(fd);
-    fd_close(fd);
-    store_open_disk_fd--;
+    aiostate->theFile = NULL;
     debug(79, 9) ("%s:%d\n", __FILE__, __LINE__);
 }
 
@@ -429,13 +447,13 @@ storeAufsIOCallback(storeIOState * sio, int errflag)
 static int
 storeAufsNeedCompletetion(storeIOState * sio)
 {
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
+    squidaiostate_t *aiostate = dynamic_cast<squidaiostate_t *>(sio);
 
-    if (aiostate->flags.writing)
+    if (aiostate->writing)
+       return true;
+    if (aiostate->creating && FILE_MODE(sio->mode) == O_WRONLY)
        return 1;
-    if (aiostate->flags.opening && FILE_MODE(sio->mode) == O_WRONLY)
-       return 1;
-    if (aiostate->flags.reading)
+    if (aiostate->reading)
        return 1;
     if (aiostate->flags.inreaddone)
        return 1;
@@ -449,25 +467,48 @@ storeAufsNeedCompletetion(storeIOState * sio)
  * The actuall SIO is managed by cbdata so we do not need
  * to bother with that.
  */
-static void
-storeAufsIOFreeEntry(void *siop)
-{
-    storeIOState *sio = (storeIOState *) siop;
-    squidaiostate_t *aiostate = (squidaiostate_t *) sio->fsstate;
-    struct _queued_write *qw;
-    struct _queued_read *qr;
-    while ((qw = (struct _queued_write *)linklistShift(&aiostate->pending_writes))) {
-       if (qw->free_func)
-           qw->free_func(qw->buf);
-       memPoolFree(aufs_qwrite_pool, qw);
+squidaiostate_t::~squidaiostate_t()
+{
+}
+
+void
+squidaiostate_t::ioCompletedNotification()
+{
+    if (opening) {
+       opening = false;
+       openDone();
+       return;
     }
-    while ((qr = (struct _queued_read *)linklistShift(&aiostate->pending_reads))) {
-       cbdataReferenceDone(qr->callback_data);
-       memPoolFree(aufs_qread_pool, qr);
+    if (creating) {
+       creating = false;
+       openDone();
+       return;
+    }
+    assert (0);
+}
+
+void
+squidaiostate_t::closeCompleted()
+{
+    assert (0);
+}
+
+void 
+squidaiostate_t::openDone()
+{
+    if (theFile->error()) {
+       storeAufsIOCallback(this, DISK_ERROR);
+       return;
+    }
+    fd = theFile->getFD();
+    if (FILE_MODE(mode) == O_WRONLY) {
+       if (kickWriteQueue())
+           return;
+    } else if ((FILE_MODE(mode) == O_RDONLY) && !closing) {
+       if (kickReadQueue())
+           return;
     }
-    if (sio->read.callback_data)
-       cbdataReferenceDone(sio->read.callback_data);
-    if (sio->callback_data)
-       cbdataReferenceDone(sio->callback_data);
-    memPoolFree(squidaio_state_pool, aiostate);
+    if (closing)
+       storeAufsIOCallback(this, theFile->error() ? -1 : 0);
+    debug(79, 3) ("squidaiostate_t::openDone: exiting\n");
 }
index 0dd4f41e5c9fc83454c381192515cd2b0709735c..630f46ef8939a9d071a8787d89d5a43629e206bb 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __COSS_H__
 #define __COSS_H__
 
+#include "SwapDir.h"
+
 #ifndef COSS_MEMBUF_SZ
 #define        COSS_MEMBUF_SZ  1048576
 #endif
 #define COSS_ALLOC_NOTIFY              0
 #define COSS_ALLOC_ALLOCATE            1
 #define COSS_ALLOC_REALLOC             2
-
+class CossSwapDir;
 struct _cossmembuf {
     dlink_node node;
     size_t diskstart;          /* in blocks */
     size_t diskend;            /* in blocks */
-    SwapDir *SD;
+    CossSwapDir *SD;
     int lockcount;
     char buffer[COSS_MEMBUF_SZ];
     struct _cossmembuf_flags {
@@ -33,21 +35,6 @@ struct _cossmembuf {
     } flags;
 };
 
-
-/* Per-storedir info */
-struct _cossinfo {
-    dlink_list membufs;
-    struct _cossmembuf *current_membuf;
-    size_t current_offset;     /* in Blocks */
-    int fd;
-    int swaplog_fd;
-    int numcollisions;
-    dlink_list index;
-    int count;
-    async_queue_t aq;
-    dlink_node *walk_current;
-};
-
 struct _cossindex {
     /* Note: the dlink_node MUST be the first member of the structure.
      * This member is later pointer typecasted to coss_index_node *.
@@ -56,8 +43,16 @@ struct _cossindex {
 };
 
 
+
 /* Per-storeiostate info */
-struct _cossstate {
+class CossState : public storeIOState {
+public:
+    virtual void deleteSelf() const {delete this;}
+    void * operator new (size_t);
+    void operator delete (void *);
+    CossState(CossSwapDir *);
+    ~CossState();
+
     char *readbuffer;
     char *requestbuf;
     size_t requestlen;
@@ -67,33 +62,60 @@ struct _cossstate {
        unsigned int reading:1;
        unsigned int writing:1;
     } flags;
+    size_t st_size;
+    void read_(char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data);
+    void write(char *buf, size_t size, off_t offset, FREE * free_func);
+    void close();
+
+    CossSwapDir *SD;
+private:
+    static MemPool *Pool;
 };
 
 typedef struct _cossmembuf CossMemBuf;
-typedef struct _cossinfo CossInfo;
-typedef struct _cossstate CossState;
 typedef struct _cossindex CossIndexNode;
 
 /* Whether the coss system has been setup or not */
 extern int coss_initialised;
 extern MemPool *coss_membuf_pool;
-extern MemPool *coss_state_pool;
 extern MemPool *coss_index_pool;
 
-/*
- * Store IO stuff
- */
-extern STOBJCREATE storeCossCreate;
-extern STOBJOPEN storeCossOpen;
-extern STOBJCLOSE storeCossClose;
-extern STOBJREAD storeCossRead;
-extern STOBJWRITE storeCossWrite;
-extern STOBJUNLINK storeCossUnlink;
-extern STSYNC storeCossSync;
-
-extern off_t storeCossAllocate(SwapDir * SD, const StoreEntry * e, int which);
-extern void storeCossAdd(SwapDir *, StoreEntry *);
-extern void storeCossRemove(SwapDir *, StoreEntry *);
-extern void storeCossStartMembuf(SwapDir * SD);
+class CossSwapDir : public SwapDir 
+{
+public:
+    CossSwapDir();
+    virtual void init();
+    virtual void newFileSystem();
+    virtual void dump(StoreEntry &)const;
+    ~CossSwapDir();
+    virtual void unlink (StoreEntry &);
+    virtual void statfs (StoreEntry &)const;
+    virtual int canStore(StoreEntry const &)const;
+    virtual int callback();
+    virtual void sync();
+    virtual StoreIOState::Pointer createStoreIO(StoreEntry &, STFNCB *, STIOCB *, void *);
+    virtual StoreIOState::Pointer openStoreIO(StoreEntry &, STFNCB *, 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 (int, char *);
+//private:
+    int fd;
+    int swaplog_fd;
+    int count;
+    dlink_list membufs;
+    struct _cossmembuf *current_membuf;
+    size_t current_offset;     /* in Blocks */
+    int numcollisions;
+    dlink_list cossindex;
+    async_queue_t aq;
+};
 
+extern off_t storeCossAllocate(CossSwapDir * SD, const StoreEntry * e, int which);
+extern void storeCossAdd(CossSwapDir *, StoreEntry *);
+extern void storeCossRemove(CossSwapDir *, StoreEntry *);
+extern void storeCossStartMembuf(CossSwapDir * SD);
 #endif
index 98e3559e2a2b8f7c3a4db589a5efb0679e640194..09b255c081b5d7dc9f3e730adde314626020d611 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_dir_coss.cc,v 1.40 2002/10/15 08:03:33 robertc Exp $
+ * $Id: store_dir_coss.cc,v 1.41 2002/12/27 10:26:36 robertc Exp $
  *
  * DEBUG: section 47    Store COSS Directory Routines
  * AUTHOR: Eric Stern
 
 #include "async_io.h"
 #include "store_coss.h"
+#include "SwapDir.h"
 
 #define STORE_META_BUFSZ 4096
 
 int n_coss_dirs = 0;
 /* static int last_coss_pick_index = -1; */
 int coss_initialised = 0;
-MemPool *coss_state_pool = NULL;
 MemPool *coss_index_pool = NULL;
 
 typedef struct _RebuildState RebuildState;
 struct _RebuildState {
-    SwapDir *sd;
+    CossSwapDir *sd;
     int n_read;
     FILE *log;
     int speed;
@@ -62,7 +62,7 @@ struct _RebuildState {
 
 static char *storeCossDirSwapLogFile(SwapDir *, const char *);
 static EVH storeCossRebuildFromSwapLog;
-static StoreEntry *storeCossAddDiskRestore(SwapDir * SD, const cache_key * key,
+static StoreEntry *storeCossAddDiskRestore(CossSwapDir * SD, const cache_key * key,
     int file_number,
     size_t swap_file_sz,
     time_t expires,
@@ -72,24 +72,9 @@ static StoreEntry *storeCossAddDiskRestore(SwapDir * SD, const cache_key * key,
     u_int32_t refcount,
     u_int16_t flags,
     int clean);
-static void storeCossDirRebuild(SwapDir * sd);
-static void storeCossDirCloseTmpSwapLog(SwapDir * sd);
-static FILE *storeCossDirOpenTmpSwapLog(SwapDir *, int *, int *);
-static STLOGOPEN storeCossDirOpenSwapLog;
-static STINIT storeCossDirInit;
-static STLOGCLEANSTART storeCossDirWriteCleanStart;
-static STLOGCLEANNEXTENTRY storeCossDirCleanLogNextEntry;
-static STLOGCLEANWRITE storeCossDirWriteCleanEntry;
-static STLOGCLEANDONE storeCossDirWriteCleanDone;
-static STLOGCLOSE storeCossDirCloseSwapLog;
-static STLOGWRITE storeCossDirSwapLog;
-static STNEWFS storeCossDirNewfs;
-static STCHECKOBJ storeCossDirCheckObj;
-static STFREE storeCossDirShutdown;
-static STFSPARSE storeCossDirParse;
-static STFSRECONFIGURE storeCossDirReconfigure;
-static STDUMP storeCossDirDump;
-static STCALLBACK storeCossDirCallback;
+static void storeCossDirRebuild(CossSwapDir * sd);
+static void storeCossDirCloseTmpSwapLog(CossSwapDir * sd);
+static FILE *storeCossDirOpenTmpSwapLog(CossSwapDir *, int *, int *);
 
 /* The "only" externally visible function */
 STSETUP storeFsSetup_coss;
@@ -124,77 +109,70 @@ storeCossDirSwapLogFile(SwapDir * sd, const char *ext)
     return path;
 }
 
-static void
-storeCossDirOpenSwapLog(SwapDir * sd)
+void
+CossSwapDir::openLog()
 {
-    CossInfo *cs = (CossInfo *) sd->fsdata;
-    char *path;
-    int fd;
-    path = storeCossDirSwapLogFile(sd, NULL);
-    fd = file_open(path, O_WRONLY | O_CREAT | O_BINARY);
-    if (fd < 0) {
-       debug(47, 1) ("%s: %s\n", path, xstrerror());
+    char *logPath;
+    logPath = storeCossDirSwapLogFile(this, NULL);
+    swaplog_fd = file_open(logPath, O_WRONLY | O_CREAT | O_BINARY);
+    if (swaplog_fd < 0) {
+       debug(47, 1) ("%s: %s\n", logPath, xstrerror());
        fatal("storeCossDirOpenSwapLog: Failed to open swap log.");
     }
-    debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, fd);
-    cs->swaplog_fd = fd;
+    debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", index, swaplog_fd);
 }
 
-static void
-storeCossDirCloseSwapLog(SwapDir * sd)
+void
+CossSwapDir::closeLog()
 {
-    CossInfo *cs = (CossInfo *) sd->fsdata;
-    if (cs->swaplog_fd < 0)    /* not open */
+    if (swaplog_fd < 0)        /* not open */
        return;
-    file_close(cs->swaplog_fd);
+    file_close(swaplog_fd);
     debug(47, 3) ("Cache COSS Dir #%d log closed on FD %d\n",
-       sd->index, cs->swaplog_fd);
-    cs->swaplog_fd = -1;
+       index, swaplog_fd);
+    swaplog_fd = -1;
 }
 
-static void
-storeCossDirInit(SwapDir * sd)
-{
-    CossInfo *cs = (CossInfo *) sd->fsdata;
-    a_file_setupqueue(&cs->aq);
-    storeCossDirOpenSwapLog(sd);
-    storeCossDirRebuild(sd);
-    cs->fd = file_open(sd->path, O_RDWR | O_CREAT);
-    if (cs->fd < 0) {
-       debug(47, 1) ("%s: %s\n", sd->path, xstrerror());
+void
+CossSwapDir::init()
+{
+    a_file_setupqueue(&aq);
+    openLog();
+    storeCossDirRebuild(this);
+    fd = file_open(path, O_RDWR | O_CREAT);
+    if (fd < 0) {
+       debug(47, 1) ("%s: %s\n", path, xstrerror());
        fatal("storeCossDirInit: Failed to open a COSS directory.");
     }
     n_coss_dirs++;
-    (void) storeDirGetBlkSize(sd->path, &sd->fs.blksize);
+    (void) storeDirGetBlkSize(path, &fs.blksize);
 }
 
 void
-storeCossRemove(SwapDir * sd, StoreEntry * e)
+storeCossRemove(CossSwapDir * sd, StoreEntry * e)
 {
-    CossInfo *cs = (CossInfo *) sd->fsdata;
     CossIndexNode *coss_node = (CossIndexNode *)e->repl.data;
     e->repl.data = NULL;
-    dlinkDelete(&coss_node->node, &cs->index);
+    dlinkDelete(&coss_node->node, &sd->cossindex);
     memPoolFree(coss_index_pool, coss_node);
-    cs->count -= 1;
+    sd->count -= 1;
 }
 
 void
-storeCossAdd(SwapDir * sd, StoreEntry * e)
+storeCossAdd(CossSwapDir * sd, StoreEntry * e)
 {
-    CossInfo *cs = (CossInfo *) sd->fsdata;
     CossIndexNode *coss_node = (CossIndexNode *)memPoolAlloc(coss_index_pool);
     assert(!e->repl.data);
     e->repl.data = coss_node;
-    dlinkAdd(e, &coss_node->node, &cs->index);
-    cs->count += 1;
+    dlinkAdd(e, &coss_node->node, &sd->cossindex);
+    sd->count += 1;
 }
 
 static void
 storeCossRebuildComplete(void *data)
 {
     RebuildState *rb = (RebuildState *)data;
-    SwapDir *sd = rb->sd;
+    CossSwapDir *sd = rb->sd;
     storeCossStartMembuf(sd);
     store_dirs_rebuilding--;
     storeCossDirCloseTmpSwapLog(rb->sd);
@@ -209,11 +187,10 @@ storeCossRebuildFromSwapLog(void *data)
     StoreEntry *e = NULL;
     storeSwapLogData s;
     size_t ss = sizeof(storeSwapLogData);
-    int count;
     double x;
     assert(rb != NULL);
     /* load a number of objects per invocation */
-    for (count = 0; count < rb->speed; count++) {
+    for (int aCount = 0; aCount < rb->speed; aCount++) {
        if (fread(&s, ss, 1, rb->log) != 1) {
            debug(47, 1) ("Done reading %s swaplog (%d entries)\n",
                rb->sd->path, rb->n_read);
@@ -299,7 +276,7 @@ storeCossRebuildFromSwapLog(void *data)
 /* Add a new object to the cache with empty memory copy and pointer to disk
  * use to rebuild store from disk. */
 static StoreEntry *
-storeCossAddDiskRestore(SwapDir * SD, const cache_key * key,
+storeCossAddDiskRestore(CossSwapDir * SD, const cache_key * key,
     int file_number,
     size_t swap_file_sz,
     time_t expires,
@@ -341,7 +318,7 @@ storeCossAddDiskRestore(SwapDir * SD, const cache_key * key,
 
 CBDATA_TYPE(RebuildState);
 static void
-storeCossDirRebuild(SwapDir * sd)
+storeCossDirRebuild(CossSwapDir * sd)
 {
     RebuildState *rb;
     int clean = 0;
@@ -384,13 +361,12 @@ storeCossDirRebuild(SwapDir * sd)
 }
 
 static void
-storeCossDirCloseTmpSwapLog(SwapDir * sd)
+storeCossDirCloseTmpSwapLog(CossSwapDir * sd)
 {
-    CossInfo *cs = (CossInfo *) sd->fsdata;
     char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL));
     char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new"));
-    int fd;
-    file_close(cs->swaplog_fd);
+    int anfd;
+    file_close(sd->swaplog_fd);
 #if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_)
     if (unlink(swaplog_path) < 0) {
        debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror());
@@ -400,46 +376,45 @@ storeCossDirCloseTmpSwapLog(SwapDir * sd)
     if (xrename(new_path, swaplog_path) < 0) {
        fatal("storeCossDirCloseTmpSwapLog: rename failed");
     }
-    fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY);
-    if (fd < 0) {
+    anfd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY);
+    if (anfd < 0) {
        debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror());
        fatal("storeCossDirCloseTmpSwapLog: Failed to open swap log.");
     }
     safe_free(swaplog_path);
     safe_free(new_path);
-    cs->swaplog_fd = fd;
-    debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, fd);
+    sd->swaplog_fd = anfd;
+    debug(47, 3) ("Cache COSS Dir #%d log opened on FD %d\n", sd->index, anfd);
 }
 
 static FILE *
-storeCossDirOpenTmpSwapLog(SwapDir * sd, int *clean_flag, int *zero_flag)
+storeCossDirOpenTmpSwapLog(CossSwapDir * sd, int *clean_flag, int *zero_flag)
 {
-    CossInfo *cs = (CossInfo *) sd->fsdata;
     char *swaplog_path = xstrdup(storeCossDirSwapLogFile(sd, NULL));
     char *clean_path = xstrdup(storeCossDirSwapLogFile(sd, ".last-clean"));
     char *new_path = xstrdup(storeCossDirSwapLogFile(sd, ".new"));
     struct stat log_sb;
     struct stat clean_sb;
     FILE *fp;
-    int fd;
+    int anfd;
     if (stat(swaplog_path, &log_sb) < 0) {
        debug(50, 1) ("Cache COSS Dir #%d: No log file\n", sd->index);
-       safe_free(swaplog_path);
+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 (cs->swaplog_fd >= 0)
-       file_close(cs->swaplog_fd);
+    if (sd->swaplog_fd >= 0)
+       file_close(sd->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) {
+    anfd = file_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
+    if (anfd < 0) {
        debug(50, 1) ("%s: %s\n", new_path, xstrerror());
        fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
     }
-    cs->swaplog_fd = fd;
+    sd->swaplog_fd = anfd;
     /* open a read-only stream of the old log */
     fp = fopen(swaplog_path, "rb");
     if (fp == NULL) {
@@ -460,7 +435,11 @@ storeCossDirOpenTmpSwapLog(SwapDir * sd, int *clean_flag, int *zero_flag)
     return fp;
 }
 
-struct _clean_state {
+class CossCleanLog : public SwapDir::CleanLog {
+  public:
+    CossCleanLog(SwapDir *);
+    virtual const StoreEntry *nextEntry();
+    virtual void write(StoreEntry const &);
     char *cur;
     char *newLog;
     char *cln;
@@ -468,83 +447,84 @@ struct _clean_state {
     off_t outbuf_offset;
     int fd;
     dlink_node *current;
+    SwapDir *sd;
 };
 
 #define CLEAN_BUF_SZ 16384
+
+CossCleanLog::CossCleanLog(SwapDir *aSwapDir) : cur(NULL),newLog(NULL),cln(NULL),outbuf(NULL),
+  outbuf_offset(0), fd(-1),current(NULL), sd(aSwapDir)
+{
+}
+
 /*
  * Begin the process to write clean cache state.  For COSS this means
  * opening some log files and allocating write buffers.  Return 0 if
  * we succeed, and assign the 'func' and 'data' return pointers.
  */
-static int
-storeCossDirWriteCleanStart(SwapDir * sd)
+int
+CossSwapDir::writeCleanStart()
 {
-    CossInfo *cs = (CossInfo *) sd->fsdata;
-    struct _clean_state *state = (struct _clean_state *)xcalloc(1, sizeof(*state));
+    CossCleanLog *state = new CossCleanLog(this);
 #if HAVE_FCHMOD
     struct stat sb;
 #endif
-    state->newLog = xstrdup(storeCossDirSwapLogFile(sd, ".clean"));
+    state->newLog = xstrdup(storeCossDirSwapLogFile(this, ".clean"));
     state->fd = file_open(state->newLog, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
+    cleanLog = NULL;
     if (state->fd < 0) {
        xfree(state->newLog);
-       xfree(state);
+       delete state;
        return -1;
     }
-    sd->log.clean.write = NULL;
-    sd->log.clean.state = NULL;
-    state->cur = xstrdup(storeCossDirSwapLogFile(sd, NULL));
-    state->cln = xstrdup(storeCossDirSwapLogFile(sd, ".last-clean"));
+    state->cur = xstrdup(storeCossDirSwapLogFile(this, NULL));
+    state->cln = xstrdup(storeCossDirSwapLogFile(this, ".last-clean"));
     state->outbuf = (char *)xcalloc(CLEAN_BUF_SZ, 1);
     state->outbuf_offset = 0;
-    unlink(state->cln);
-    state->current = cs->index.tail;
+    ::unlink(state->cln);
+    state->current = cossindex.tail;
     debug(50, 3) ("storeCOssDirWriteCleanLogs: opened %s, FD %d\n",
        state->newLog, state->fd);
 #if HAVE_FCHMOD
     if (stat(state->cur, &sb) == 0)
        fchmod(state->fd, sb.st_mode);
 #endif
-    sd->log.clean.write = storeCossDirWriteCleanEntry;
-    sd->log.clean.state = state;
+    cleanLog = state;
 
     return 0;
 }
 
-static const StoreEntry *
-storeCossDirCleanLogNextEntry(SwapDir * sd)
+const StoreEntry *
+CossCleanLog::nextEntry()
 {
-    struct _clean_state *state = (struct _clean_state *)sd->log.clean.state;
     const StoreEntry *entry;
-    if (!state)
-       return NULL;
-    if (!state->current)
+    if (!current)
        return NULL;
-    entry = (const StoreEntry *) state->current->data;
-    state->current = state->current->prev;
+    entry = (const StoreEntry *) current->data;
+    current = current->prev;
     return entry;
 }
 
 /*
  * "write" an entry to the clean log file.
  */
-static void
-storeCossDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e)
+void
+CossCleanLog::write(StoreEntry const &e)
 {
+    CossCleanLog *state = this;
     storeSwapLogData s;
     static size_t ss = sizeof(storeSwapLogData);
-    struct _clean_state *state = (struct _clean_state *)sd->log.clean.state;
     memset(&s, '\0', ss);
     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;
-    xmemcpy(&s.key, e->key, MD5_DIGEST_CHARS);
+    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;
+    xmemcpy(&s.key, e.key, MD5_DIGEST_CHARS);
     xmemcpy(state->outbuf + state->outbuf_offset, &s, ss);
     state->outbuf_offset += ss;
     /* buffered write */
@@ -556,20 +536,18 @@ storeCossDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e)
            file_close(state->fd);
            state->fd = -1;
            unlink(state->newLog);
-           safe_free(state);
-           sd->log.clean.state = NULL;
-           sd->log.clean.write = NULL;
+           delete state;
+           sd->cleanLog = NULL;
            return;
        }
        state->outbuf_offset = 0;
     }
 }
 
-static void
-storeCossDirWriteCleanDone(SwapDir * sd)
+void
+CossSwapDir::writeCleanDone()
 {
-    int fd;
-    struct _clean_state *state = (struct _clean_state *)sd->log.clean.state;
+    CossCleanLog *state = (CossCleanLog *)cleanLog;
     if (NULL == state)
        return;
     if (state->fd < 0)
@@ -581,16 +559,16 @@ storeCossDirWriteCleanDone(SwapDir * sd)
            "not replaced.\n");
        file_close(state->fd);
        state->fd = -1;
-       unlink(state->newLog);
+       ::unlink(state->newLog);
     }
     safe_free(state->outbuf);
     /*
      * You can't rename open files on Microsoft "operating systems"
      * so we have to close before renaming.
      */
-    storeCossDirCloseSwapLog(sd);
+    closeLog();
     /* save the fd value for a later test */
-    fd = state->fd;
+    int anfd = state->fd;
     /* rename */
     if (state->fd >= 0) {
 #if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_)
@@ -605,7 +583,7 @@ storeCossDirWriteCleanDone(SwapDir * sd)
     /* touch a timestamp file if we're not still validating */
     if (store_dirs_rebuilding)
        (void) 0;
-    else if (fd < 0)
+    else if (anfd < 0)
        (void) 0;
     else
        file_close(file_open(state->cln, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY));
@@ -616,9 +594,8 @@ storeCossDirWriteCleanDone(SwapDir * sd)
     if (state->fd >= 0)
        file_close(state->fd);
     state->fd = -1;
-    safe_free(state);
-    sd->log.clean.state = NULL;
-    sd->log.clean.write = NULL;
+    delete state;
+    cleanLog = NULL;
 }
 
 static void
@@ -627,22 +604,21 @@ storeSwapLogDataFree(void *s)
     memFree(s, MEM_SWAP_LOG_DATA);
 }
 
-static void
-storeCossDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op)
+void
+CossSwapDir::logEntry(const StoreEntry & e, int op) const
 {
-    CossInfo *cs = (CossInfo *) sd->fsdata;
     storeSwapLogData *s = (storeSwapLogData *)memAllocate(MEM_SWAP_LOG_DATA);
     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;
-    xmemcpy(s->key, e->key, MD5_DIGEST_CHARS);
-    file_write(cs->swaplog_fd,
+    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;
+    xmemcpy(s->key, e.key, MD5_DIGEST_CHARS);
+    file_write(swaplog_fd,
        -1,
        s,
        sizeof(storeSwapLogData),
@@ -651,27 +627,22 @@ storeCossDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op)
        (FREE *) storeSwapLogDataFree);
 }
 
-static void
-storeCossDirNewfs(SwapDir * sd)
+void
+CossSwapDir::newFileSystem()
 {
-    debug(47, 3) ("Creating swap space in %s\n", sd->path);
+    debug(47, 3) ("Creating swap space in %s\n", path);
+    debug (47,0)("COSS autocreation is not implemented. Please create the file manually\n");
 }
 
 /* we are shutting down, flush all membufs to disk */
-static void
-storeCossDirShutdown(SwapDir * SD)
+CossSwapDir::~CossSwapDir()
 {
-    CossInfo *cs = (CossInfo *) SD->fsdata;
+    sync();                            /* This'll call a_file_syncqueue() */
+    a_file_closequeue(&aq);
+    file_close(fd);
+    fd = -1;
 
-    storeCossSync(SD);         /* This'll call a_file_syncqueue() */
-    a_file_closequeue(&cs->aq);
-    file_close(cs->fd);
-    cs->fd = -1;
-
-    if (cs->swaplog_fd > -1) {
-       file_close(cs->swaplog_fd);
-       cs->swaplog_fd = -1;
-    }
+    closeLog();
     n_coss_dirs--;
 }
 
@@ -684,131 +655,79 @@ storeCossDirShutdown(SwapDir * SD)
  * done by the upper layers.
  */
 int
-storeCossDirCheckObj(SwapDir * SD, const StoreEntry * e)
+CossSwapDir::canStore(StoreEntry const &e)const
 {
-    CossInfo *cs = (CossInfo *) SD->fsdata;
     int loadav;
 
     /* Check if the object is a special object, we can't cache these */
-    if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
+    if (EBIT_TEST(e.flags, ENTRY_SPECIAL))
        return -1;
 
     /* Otherwise, we're ok */
     /* Return load, cs->aq.aq_numpending out of MAX_ASYNCOP */
-    loadav = cs->aq.aq_numpending * 1000 / MAX_ASYNCOP;
+    loadav = aq.aq_numpending * 1000 / MAX_ASYNCOP;
     return loadav;
 }
 
-
 /*
  * storeCossDirCallback - do the IO completions
  */
-static int
-storeCossDirCallback(SwapDir * SD)
+int
+CossSwapDir::callback()
 {
-    CossInfo *cs = (CossInfo *) SD->fsdata;
-
-    return a_file_callback(&cs->aq);
+    return a_file_callback(&aq);
 }
 
 /* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */
 
-static void
-storeCossDirStats(SwapDir * SD, StoreEntry * sentry)
+void
+CossSwapDir::statfs(StoreEntry & sentry) const
 {
-    CossInfo *cs = (CossInfo *) SD->fsdata;
-
-    storeAppendPrintf(sentry, "\n");
-    storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size);
-    storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size);
-    storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n",
-       100.0 * SD->cur_size / SD->max_size);
-    storeAppendPrintf(sentry, "Number of object collisions: %d\n", (int) cs->numcollisions);
+    storeAppendPrintf(&sentry, "\n");
+    storeAppendPrintf(&sentry, "Maximum Size: %d KB\n", max_size);
+    storeAppendPrintf(&sentry, "Current Size: %d KB\n", cur_size);
+    storeAppendPrintf(&sentry, "Percent Used: %0.2f%%\n",
+       100.0 * cur_size / max_size);
+    storeAppendPrintf(&sentry, "Number of object collisions: %d\n", (int) numcollisions);
 #if 0
     /* is this applicable? I Hope not .. */
     storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n",
        SD->map->n_files_in_map, SD->map->max_n_files,
        percent(SD->map->n_files_in_map, SD->map->max_n_files));
 #endif
-    storeAppendPrintf(sentry, "Pending operations: %d out of %d\n", cs->aq.aq_numpending, MAX_ASYNCOP);
-    storeAppendPrintf(sentry, "Flags:");
-    if (SD->flags.selected)
-       storeAppendPrintf(sentry, " SELECTED");
-    if (SD->flags.read_only)
-       storeAppendPrintf(sentry, " READ-ONLY");
-    storeAppendPrintf(sentry, "\n");
+    storeAppendPrintf(&sentry, "Pending operations: %d out of %d\n", aq.aq_numpending, MAX_ASYNCOP);
+    storeAppendPrintf(&sentry, "Flags:");
+    if (flags.selected)
+       storeAppendPrintf(&sentry, " SELECTED");
+    if (flags.read_only)
+       storeAppendPrintf(&sentry, " READ-ONLY");
+    storeAppendPrintf(&sentry, "\n");
 }
 
-static void
-storeCossDirParse(SwapDir * sd, int index, char *path)
+void
+CossSwapDir::parse(int anIndex, char *aPath)
 {
     unsigned int i;
     unsigned int size;
-    CossInfo *cs;
 
     i = GetInteger();
     size = i << 10;            /* Mbytes to Kbytes */
     if (size <= 0)
        fatal("storeCossDirParse: invalid size value");
 
-    cs = (CossInfo *)xmalloc(sizeof(CossInfo));
-    if (cs == NULL)
-       fatal("storeCossDirParse: couldn't xmalloc() CossInfo!\n");
-
-    sd->index = index;
-    sd->path = xstrdup(path);
-    sd->max_size = size;
-    sd->fsdata = cs;
-
-    cs->fd = -1;
-    cs->swaplog_fd = -1;
-
-    sd->init = storeCossDirInit;
-    sd->newfs = storeCossDirNewfs;
-    sd->dump = storeCossDirDump;
-    sd->freefs = storeCossDirShutdown;
-    sd->dblcheck = NULL;
-    sd->statfs = storeCossDirStats;
-    sd->maintainfs = NULL;
-    sd->checkobj = storeCossDirCheckObj;
-    sd->refobj = NULL;         /* LRU is done in storeCossRead */
-    sd->unrefobj = NULL;
-    sd->callback = storeCossDirCallback;
-    sd->sync = storeCossSync;
-
-    sd->obj.create = storeCossCreate;
-    sd->obj.open = storeCossOpen;
-    sd->obj.close = storeCossClose;
-    sd->obj.read = storeCossRead;
-    sd->obj.write = storeCossWrite;
-    sd->obj.unlink = storeCossUnlink;
-
-    sd->log.open = storeCossDirOpenSwapLog;
-    sd->log.close = storeCossDirCloseSwapLog;
-    sd->log.write = storeCossDirSwapLog;
-    sd->log.clean.start = storeCossDirWriteCleanStart;
-    sd->log.clean.write = storeCossDirWriteCleanEntry;
-    sd->log.clean.nextentry = storeCossDirCleanLogNextEntry;
-    sd->log.clean.done = storeCossDirWriteCleanDone;
-
-    cs->current_offset = 0;
-    cs->fd = -1;
-    cs->swaplog_fd = -1;
-    cs->numcollisions = 0;
-    cs->membufs.head = cs->membufs.tail = NULL;                /* set when the rebuild completes */
-    cs->current_membuf = NULL;
-    cs->index.head = NULL;
-    cs->index.tail = NULL;
-
-    parse_cachedir_options(sd, NULL, 0);
+    index = anIndex;
+    path = xstrdup(aPath);
+    max_size = size;
+
+    parse_cachedir_options(this, NULL, 0);
     /* Enforce maxobjsize being set to something */
-    if (sd->max_objsize == -1)
+    if (max_objsize == -1)
        fatal("COSS requires max-size to be set to something other than -1!\n");
 }
 
 
-static void
-storeCossDirReconfigure(SwapDir * sd, int index, char *path)
+void
+CossSwapDir::reconfigure(int index, char *path)
 {
     unsigned int i;
     unsigned int size;
@@ -818,24 +737,24 @@ storeCossDirReconfigure(SwapDir * sd, int index, char *path)
     if (size <= 0)
        fatal("storeCossDirParse: invalid size value");
 
-    if (size == (size_t)sd->max_size)
+    if (size == (size_t)max_size)
        debug(3, 1) ("Cache COSS dir '%s' size remains unchanged at %d KB\n", path, size);
     else {
        debug(3, 1) ("Cache COSS dir '%s' size changed to %d KB\n", path, size);
-       sd->max_size = size;
+       max_size = size;
     }
-    parse_cachedir_options(sd, NULL, 1);
+    parse_cachedir_options(this, NULL, 1);
     /* Enforce maxobjsize being set to something */
-    if (sd->max_objsize == -1)
+    if (max_objsize == -1)
        fatal("COSS requires max-size to be set to something other than -1!\n");
 }
 
 void
-storeCossDirDump(StoreEntry * entry, SwapDir * s)
+CossSwapDir::dump(StoreEntry &entry)const
 {
-    storeAppendPrintf(entry, " %d",
-       s->max_size >> 20);
-    dump_cachedir_options(entry, NULL, s);
+    storeAppendPrintf(&entry, " %d",
+       max_size >> 20);
+    dump_cachedir_options(&entry, NULL, this);
 }
 
 #if OLD_UNUSED_CODE
@@ -885,20 +804,32 @@ storeCossDirPick(void)
 static void
 storeCossDirDone(void)
 {
-    memPoolDestroy(&coss_state_pool);
 /*  memPoolDestroy(&coss_index_pool);  XXX Should be here? */
     coss_initialised = 0;
 }
 
+static SwapDir *
+storeCossNew(void)
+{
+    SwapDir *result = new CossSwapDir;
+    return result;
+}
+
+CossSwapDir::CossSwapDir() : fd (-1), swaplog_fd(-1), count(0), current_membuf (NULL), current_offset(0), numcollisions(0)
+{
+    membufs.head = NULL;
+    membufs.tail = NULL;
+    cossindex.head = NULL;
+    cossindex.tail = NULL;
+}
+
 void
 storeFsSetup_coss(storefs_entry_t * storefs)
 {
     assert(!coss_initialised);
 
-    storefs->parsefunc = storeCossDirParse;
-    storefs->reconfigurefunc = storeCossDirReconfigure;
     storefs->donefunc = storeCossDirDone;
-    coss_state_pool = memPoolCreate("COSS IO State data", sizeof(CossState));
+    storefs->newfunc = storeCossNew;
     coss_index_pool = memPoolCreate("COSS index data", sizeof(CossIndexNode));
     coss_initialised = 1;
 }
index 92399b05c15cdaaf1ac2149567ba4b70c01312b4..f1b4c01838f0f50b62513415e9335545ba4c4664 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_io_coss.cc,v 1.19 2002/10/13 20:35:25 robertc Exp $
+ * $Id: store_io_coss.cc,v 1.20 2002/12/27 10:26:36 robertc Exp $
  *
  * DEBUG: section 79    Storage Manager COSS Interface
  * AUTHOR: Eric Stern
 #include <aio.h>
 #include "async_io.h"
 #include "store_coss.h"
+#include "SwapDir.h"
 
 static DWCB storeCossWriteMemBufDone;
 static DRCB storeCossReadDone;
 static void storeCossIOCallback(storeIOState * sio, int errflag);
-static char *storeCossMemPointerFromDiskOffset(SwapDir * SD, size_t offset, CossMemBuf ** mb);
-static void storeCossMemBufLock(SwapDir * SD, storeIOState * e);
-static void storeCossMemBufUnlock(SwapDir * SD, storeIOState * e);
-static void storeCossWriteMemBuf(SwapDir * SD, CossMemBuf * t);
-static void storeCossWriteMemBufDone(int fd, int errflag, size_t len, void *my_data);
-static CossMemBuf *storeCossCreateMemBuf(SwapDir * SD, size_t start,
+static char *storeCossMemPointerFromDiskOffset(CossSwapDir * SD, size_t offset, CossMemBuf ** mb);
+static void storeCossMemBufLock(CossSwapDir * SD, storeIOState * e);
+static void storeCossMemBufUnlock(CossSwapDir * SD, storeIOState * e);
+static void storeCossWriteMemBuf(CossSwapDir * SD, CossMemBuf * t);
+static void storeCossWriteMemBufDone(int, int errflag, size_t len, void *my_data);
+static CossMemBuf *storeCossCreateMemBuf(CossSwapDir * SD, size_t start,
     sfileno curfn, int *collision);
-static CBDUNL storeCossIOFreeEntry;
 
-CBDATA_TYPE(storeIOState);
 CBDATA_TYPE(CossMemBuf);
 
 /* === PUBLIC =========================================================== */
 
+MemPool *CossState::Pool = NULL; 
+
+void *
+CossState::operator new (size_t)
+{
+    if (!Pool)
+       Pool = memPoolCreate("Squid COSS State Data", sizeof (CossState));
+    return memPoolAlloc(Pool);
+}
+void
+CossState::operator delete (void *address)
+{
+    memPoolFree (Pool, address);
+}
+    
+CossState::CossState(CossSwapDir *aCSD):SD (aCSD)
+{
+}
+
+
 /*
  * This routine sucks. I want to rewrite it when possible, and I also think
  * that we should check after creatmembuf() to see if the object has a
@@ -64,9 +84,8 @@ CBDATA_TYPE(CossMemBuf);
  * -- Adrian
  */
 off_t
-storeCossAllocate(SwapDir * SD, const StoreEntry * e, int which)
+storeCossAllocate(CossSwapDir * SD, const StoreEntry * e, int which)
 {
-    CossInfo *cs = (CossInfo *) SD->fsdata;
     CossMemBuf *newmb;
     off_t retofs;
     size_t allocsize;
@@ -90,35 +109,35 @@ storeCossAllocate(SwapDir * SD, const StoreEntry * e, int which)
     assert(which != COSS_ALLOC_NOTIFY);
 
     /* Check if we have overflowed the disk .. */
-    if ((cs->current_offset + allocsize) > (size_t)(SD->max_size << 10)) {
+    if ((SD->current_offset + allocsize) > (size_t)(SD->max_size << 10)) {
        /*
         * tried to allocate past the end of the disk, so wrap
         * back to the beginning
         */
-       cs->current_membuf->flags.full = 1;
-       cs->current_membuf->diskend = cs->current_offset - 1;
-       cs->current_offset = 0; /* wrap back to beginning */
+       SD->current_membuf->flags.full = 1;
+       SD->current_membuf->diskend = SD->current_offset - 1;
+       SD->current_offset = 0; /* wrap back to beginning */
        debug(79, 2) ("storeCossAllocate: wrap to 0\n");
 
        newmb = storeCossCreateMemBuf(SD, 0, checkf, &coll);
-       cs->current_membuf = newmb;
+       SD->current_membuf = newmb;
 
        /* Check if we have overflowed the MemBuf */
-    } else if ((cs->current_offset + allocsize) > cs->current_membuf->diskend) {
+    } else if ((SD->current_offset + allocsize) > SD->current_membuf->diskend) {
        /*
         * Skip the blank space at the end of the stripe. start over.
         */
-       cs->current_membuf->flags.full = 1;
-       cs->current_offset = cs->current_membuf->diskend + 1;
+       SD->current_membuf->flags.full = 1;
+       SD->current_offset = SD->current_membuf->diskend + 1;
        debug(79, 2) ("storeCossAllocate: New offset - %ld\n",
-           (long int) cs->current_offset);
-       newmb = storeCossCreateMemBuf(SD, cs->current_offset, checkf, &coll);
-       cs->current_membuf = newmb;
+           (long int) SD->current_offset);
+       newmb = storeCossCreateMemBuf(SD, SD->current_offset, checkf, &coll);
+       SD->current_membuf = newmb;
     }
     /* If we didn't get a collision, then update the current offset and return it */
     if (coll == 0) {
-       retofs = cs->current_offset;
-       cs->current_offset = retofs + allocsize;
+       retofs = SD->current_offset;
+       SD->current_offset = retofs + allocsize;
        return retofs;
     } else {
        debug(79, 3) ("storeCossAllocate: Collision\n");
@@ -127,45 +146,40 @@ storeCossAllocate(SwapDir * SD, const StoreEntry * e, int which)
 }
 
 void
-storeCossUnlink(SwapDir * SD, StoreEntry * e)
+CossSwapDir::unlink(StoreEntry & e)
 {
-    debug(79, 3) ("storeCossUnlink: offset %d\n", e->swap_filen);
-    storeCossRemove(SD, e);
+    debug(79, 3) ("storeCossUnlink: offset %d\n", e.swap_filen);
+    storeCossRemove(this, &e);
 }
 
-
-storeIOState *
-storeCossCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data)
+StoreIOState::Pointer
+CossSwapDir::createStoreIO(StoreEntry &e, STFNCB * file_callback, STIOCB * callback, void *callback_data)
 {
     CossState *cstate;
-    storeIOState *sio;
-
-    CBDATA_INIT_TYPE_FREECB(storeIOState, storeCossIOFreeEntry);
-    sio = cbdataAlloc(storeIOState);
-    cstate = (CossState *)memPoolAlloc(coss_state_pool);
-    sio->fsstate = cstate;
-    sio->offset = 0;
+    StoreIOState::Pointer sio = new CossState(this);
+    cstate = dynamic_cast<CossState *>(sio.getRaw());
+    sio->offset_ = 0;
     sio->mode = O_WRONLY | O_BINARY;
 
     /*
      * If we get handed an object with a size of -1,
      * the squid code is broken
      */
-    assert(e->mem_obj->object_sz != -1);
+    assert(e.mem_obj->object_sz != -1);
 
     /*
      * this one is kinda strange - Eric called storeCossAllocate(), then
      * storeCossOpen(O_RDONLY) .. weird. Anyway, I'm allocating this now.
      */
-    sio->st_size = objectLen(e) + e->mem_obj->swap_hdr_sz;
-    sio->swap_dirn = SD->index;
-    sio->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_ALLOCATE);
-    debug(79, 3) ("storeCossCreate: offset %d, size %ld, end %ld\n", sio->swap_filen, (long int) sio->st_size, (long int) (sio->swap_filen + sio->st_size));
+    cstate->st_size = objectLen(&e) + e.mem_obj->swap_hdr_sz;
+    sio->swap_dirn = index;
+    sio->swap_filen = storeCossAllocate(this, &e, COSS_ALLOC_ALLOCATE);
+    debug(79, 3) ("storeCossCreate: offset %d, size %ld, end %ld\n", sio->swap_filen, (long int) cstate->st_size, (long int) (sio->swap_filen + cstate->st_size));
 
     sio->callback = callback;
     sio->file_callback = file_callback;
     sio->callback_data = cbdataReference(callback_data);
-    sio->e = (StoreEntry *) e;
+    sio->e = &e;
 
     cstate->flags.writing = 0;
     cstate->flags.reading = 0;
@@ -173,48 +187,44 @@ storeCossCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * c
     cstate->reqdiskoffset = -1;
 
     /* Now add it into the index list */
-    storeCossAdd(SD, e);
+    storeCossAdd(this, &e);
 
-    storeCossMemBufLock(SD, sio);
+    storeCossMemBufLock(this, sio.getRaw());
     return sio;
 }
 
-storeIOState *
-storeCossOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
+StoreIOState::Pointer
+CossSwapDir::openStoreIO(StoreEntry & e, STFNCB * file_callback,
     STIOCB * callback, void *callback_data)
 {
-    storeIOState *sio;
     char *p;
     CossState *cstate;
-    sfileno f = e->swap_filen;
-    CossInfo *cs = (CossInfo *) SD->fsdata;
+    sfileno f = e.swap_filen;
 
     debug(79, 3) ("storeCossOpen: offset %d\n", f);
 
-    CBDATA_INIT_TYPE_FREECB(storeIOState, storeCossIOFreeEntry);
-    sio = cbdataAlloc(storeIOState);
-    cstate = (CossState *)memPoolAlloc(coss_state_pool);
+    StoreIOState::Pointer sio = new CossState (this);
+    cstate = dynamic_cast<CossState *>(sio.getRaw());
 
-    sio->fsstate = cstate;
     sio->swap_filen = f;
-    sio->swap_dirn = SD->index;
-    sio->offset = 0;
+    sio->swap_dirn = index;
+    sio->offset_ = 0;
     sio->mode = O_RDONLY | O_BINARY;
     sio->callback = callback;
     sio->file_callback = file_callback;
     sio->callback_data = cbdataReference(callback_data);
-    sio->st_size = e->swap_file_sz;
-    sio->e = e;
+    cstate->st_size = e.swap_file_sz;
+    sio->e = &e;
 
     cstate->flags.writing = 0;
     cstate->flags.reading = 0;
     cstate->readbuffer = NULL;
     cstate->reqdiskoffset = -1;
-    p = storeCossMemPointerFromDiskOffset(SD, f, NULL);
+    p = storeCossMemPointerFromDiskOffset(this, f, NULL);
     /* make local copy so we don't have to lock membuf */
     if (p) {
-       cstate->readbuffer = (char *)xmalloc(sio->st_size);
-       xmemcpy(cstate->readbuffer, p, sio->st_size);
+       cstate->readbuffer = (char *)xmalloc(cstate->st_size);
+       xmemcpy(cstate->readbuffer, p, cstate->st_size);
     } else {
        /* Do the allocation */
        /* this is the first time we've been called on a new sio
@@ -228,29 +238,28 @@ storeCossOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
         */
        cstate->reqdiskoffset = sio->swap_filen;
        sio->swap_filen = -1;
-       sio->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_REALLOC);
+       sio->swap_filen = storeCossAllocate(this, &e, COSS_ALLOC_REALLOC);
        if (sio->swap_filen == -1) {
            /* We have to clean up neatly .. */
-           cbdataFree(sio);
-           cs->numcollisions++;
-           debug(79, 2) ("storeCossOpen: Reallocation of %d/%d failed\n", e->swap_dirn, e->swap_filen);
+           numcollisions++;
+           debug(79, 2) ("storeCossOpen: Reallocation of %d/%d failed\n", e.swap_dirn, e.swap_filen);
            /* XXX XXX XXX Will squid call storeUnlink for this object? */
            return NULL;
        }
        /* Notify the upper levels that we've changed file number */
-       sio->file_callback(sio->callback_data, 0, sio);
+       sio->file_callback(sio->callback_data, 0, sio.getRaw());
 
        /*
         * lock the buffer so it doesn't get swapped out on us
         * this will get unlocked in storeCossReadDone
         */
-       storeCossMemBufLock(SD, sio);
+       storeCossMemBufLock(this, sio.getRaw());
 
        /*
         * Do the index magic to keep the disk and memory LRUs identical
         */
-       storeCossRemove(SD, e);
-       storeCossAdd(SD, e);
+       storeCossRemove(this, &e);
+       storeCossAdd(this, &e);
 
        /*
         * Since we've reallocated a spot for this object, we need to
@@ -262,54 +271,53 @@ storeCossOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
 }
 
 void
-storeCossClose(SwapDir * SD, storeIOState * sio)
+CossState::close()
 {
-    debug(79, 3) ("storeCossClose: offset %d\n", sio->swap_filen);
-    if (FILE_MODE(sio->mode) == O_WRONLY)
-       storeCossMemBufUnlock(SD, sio);
-    storeCossIOCallback(sio, 0);
+    debug(79, 3) ("storeCossClose: offset %d\n", swap_filen);
+    if (FILE_MODE(mode) == O_WRONLY)
+       storeCossMemBufUnlock(SD, this);
+    storeCossIOCallback(this, 0);
 }
 
 void
-storeCossRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
+CossState::read_(char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
 {
     char *p;
-    CossState *cstate = (CossState *) sio->fsstate;
-    CossInfo *cs = (CossInfo *) SD->fsdata;
+    CossSwapDir *SD = (CossSwapDir *)INDEXSD(swap_dirn);
 
-    assert(sio->read.callback == NULL);
-    assert(sio->read.callback_data == NULL);
-    sio->read.callback = callback;
-    sio->read.callback_data = cbdataReference(callback_data);
+    assert(read.callback == NULL);
+    assert(read.callback_data == NULL);
+    read.callback = callback;
+    read.callback_data = cbdataReference(callback_data);
     debug(79, 3) ("storeCossRead: offset %ld\n", (long int) offset);
-    sio->offset = offset;
-    cstate->flags.reading = 1;
-    if ((offset + size) > sio->st_size)
-       size = sio->st_size - offset;
-    cstate->requestlen = size;
-    cstate->requestbuf = buf;
-    cstate->requestoffset = offset;
-    if (cstate->readbuffer == NULL) {
-       p = storeCossMemPointerFromDiskOffset(SD, sio->swap_filen, NULL);
+    offset_ = offset;
+    flags.reading = 1;
+    if ((offset + size) > st_size)
+       size = st_size - offset;
+    requestlen = size;
+    requestbuf = buf;
+    requestoffset = offset;
+    if (readbuffer == NULL) {
+       p = storeCossMemPointerFromDiskOffset(SD, swap_filen, NULL);
        /* Remember we need to translate the block offset to a disk offset! */
-       a_file_read(&cs->aq, cs->fd,
+       a_file_read(&SD->aq, SD->fd,
            p,
-           sio->st_size,
-           cstate->reqdiskoffset,
+           st_size,
+           reqdiskoffset,
            storeCossReadDone,
-           sio);
-       cstate->reqdiskoffset = 0;      /* XXX */
+           this);
+       reqdiskoffset = 0;      /* XXX */
     } else {
-       storeCossReadDone(cs->fd,
-           cstate->readbuffer,
-           sio->st_size,
+       storeCossReadDone(SD->fd,
+           readbuffer,
+           st_size,
            0,
-           sio);
+           this);
     }
 }
 
 void
-storeCossWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func)
+CossState::write(char *buf, size_t size, off_t offset, FREE * free_func)
 {
     char *dest;
     CossMemBuf *membuf;
@@ -319,14 +327,15 @@ storeCossWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t o
      * If we get handed an object with a size of -1,
      * the squid code is broken
      */
-    assert(sio->e->mem_obj->object_sz != -1);
+    assert(e->mem_obj->object_sz != -1);
 
-    debug(79, 3) ("storeCossWrite: offset %ld, len %lu\n", (long int) sio->offset, (unsigned long int) size);
-    diskoffset = sio->swap_filen + sio->offset;
+    debug(79, 3) ("storeCossWrite: offset %ld, len %lu\n", (long int) offset_, (unsigned long int) size);
+    diskoffset = swap_filen + offset_;
+    CossSwapDir *SD = (CossSwapDir *)INDEXSD(swap_dirn);
     dest = storeCossMemPointerFromDiskOffset(SD, diskoffset, &membuf);
     assert(dest != NULL);
     xmemcpy(dest, buf, size);
-    sio->offset += size;
+    offset_ += size;
     if (free_func)
        (free_func) (buf);
 }
@@ -335,30 +344,30 @@ storeCossWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t o
 /*  === STATIC =========================================================== */
 
 static void
-storeCossReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
+storeCossReadDone(int rvfd, const char *buf, int len, int errflag, void *my_data)
 {
     storeIOState *sio = (storeIOState *)my_data;
     char *p;
     STRCB *callback = sio->read.callback;
     void *cbdata;
-    SwapDir *SD = INDEXSD(sio->swap_dirn);
-    CossState *cstate = (CossState *) sio->fsstate;
+    CossSwapDir *SD = (CossSwapDir *)INDEXSD(sio->swap_dirn);
+    CossState *cstate = dynamic_cast<CossState *>(sio);
     ssize_t rlen;
 
     debug(79, 3) ("storeCossReadDone: fileno %d, FD %d, len %d\n",
-       sio->swap_filen, fd, len);
+       sio->swap_filen, rvfd, len);
     cstate->flags.reading = 0;
     if (errflag) {
        debug(79, 3) ("storeCossReadDone: got failure (%d)\n", errflag);
        rlen = -1;
     } else {
        if (cstate->readbuffer == NULL) {
-           cstate->readbuffer = (char *)xmalloc(sio->st_size);
+           cstate->readbuffer = (char *)xmalloc(cstate->st_size);
            p = storeCossMemPointerFromDiskOffset(SD, sio->swap_filen, NULL);
-           xmemcpy(cstate->readbuffer, p, sio->st_size);
+           xmemcpy(cstate->readbuffer, p, cstate->st_size);
            storeCossMemBufUnlock(SD, sio);
        }
-       sio->offset += len;
+       sio->offset_ += len;
        xmemcpy(cstate->requestbuf, &cstate->readbuffer[cstate->requestoffset],
            cstate->requestlen);
        rlen = (size_t) cstate->requestlen;
@@ -372,7 +381,7 @@ storeCossReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
 static void
 storeCossIOCallback(storeIOState * sio, int errflag)
 {
-    CossState *cstate = (CossState *) sio->fsstate;
+    CossState *cstate = dynamic_cast<CossState *>(sio);
     STIOCB *callback = sio->callback;
     void *cbdata;
     debug(79, 3) ("storeCossIOCallback: errflag=%d\n", errflag);
@@ -384,13 +393,12 @@ storeCossIOCallback(storeIOState * sio, int errflag)
 }
 
 static char *
-storeCossMemPointerFromDiskOffset(SwapDir * SD, size_t offset, CossMemBuf ** mb)
+storeCossMemPointerFromDiskOffset(CossSwapDir * SD, size_t offset, CossMemBuf ** mb)
 {
     CossMemBuf *t;
     dlink_node *m;
-    CossInfo *cs = (CossInfo *) SD->fsdata;
 
-    for (m = cs->membufs.head; m; m = m->next) {
+    for (m = SD->membufs.head; m; m = m->next) {
        t = (CossMemBuf *)m->data;
        if ((offset >= t->diskstart) && (offset <= t->diskend)) {
            if (mb)
@@ -405,13 +413,12 @@ storeCossMemPointerFromDiskOffset(SwapDir * SD, size_t offset, CossMemBuf ** mb)
 }
 
 static void
-storeCossMemBufLock(SwapDir * SD, storeIOState * e)
+storeCossMemBufLock(CossSwapDir * SD, storeIOState * e)
 {
     CossMemBuf *t;
     dlink_node *m;
-    CossInfo *cs = (CossInfo *) SD->fsdata;
 
-    for (m = cs->membufs.head; m; m = m->next) {
+    for (m = SD->membufs.head; m; m = m->next) {
        t = (CossMemBuf *)m->data;
        if (((size_t)e->swap_filen >= t->diskstart) && ((size_t)e->swap_filen <= t->diskend)) {
            debug(79, 3) ("storeCossMemBufLock: locking %p, lockcount %d\n", t, t->lockcount);
@@ -423,13 +430,12 @@ storeCossMemBufLock(SwapDir * SD, storeIOState * e)
 }
 
 static void
-storeCossMemBufUnlock(SwapDir * SD, storeIOState * e)
+storeCossMemBufUnlock(CossSwapDir * SD, storeIOState * e)
 {
     CossMemBuf *t;
     dlink_node *m, *n;
-    CossInfo *cs = (CossInfo *) SD->fsdata;
 
-    for (m = cs->membufs.head; m; m = n) {
+    for (m = SD->membufs.head; m; m = n) {
        /*
         * Note that storeCossWriteMemBuf() might call storeCossWriteMemBufDone
         * immediately (if the write finishes immediately, of course!) which
@@ -447,65 +453,61 @@ storeCossMemBufUnlock(SwapDir * SD, storeIOState * e)
 }
 
 void
-storeCossSync(SwapDir * SD)
+CossSwapDir::sync()
 {
-    CossInfo *cs = (CossInfo *) SD->fsdata;
     CossMemBuf *t;
     dlink_node *m;
     int end;
 
     /* First, flush pending IO ops */
-    a_file_syncqueue(&cs->aq);
+    a_file_syncqueue(&aq);
 
     /* Then, flush any in-memory partial membufs */
-    if (!cs->membufs.head)
+    if (!membufs.head)
        return;
-    for (m = cs->membufs.head; m; m = m->next) {
+    for (m = membufs.head; m; m = m->next) {
        t = (CossMemBuf *)m->data;
        if (t->flags.writing)
            sleep(5);           /* XXX EEEWWW! */
-       lseek(cs->fd, t->diskstart, SEEK_SET);
-       end = (t == cs->current_membuf) ? cs->current_offset : t->diskend;
-       FD_WRITE_METHOD(cs->fd, t->buffer, end - t->diskstart);
+       lseek(fd, t->diskstart, SEEK_SET);
+       end = (t == current_membuf) ? current_offset : t->diskend;
+       FD_WRITE_METHOD(fd, t->buffer, end - t->diskstart);
     }
 }
 
 static void
-storeCossWriteMemBuf(SwapDir * SD, CossMemBuf * t)
+storeCossWriteMemBuf(CossSwapDir * SD, CossMemBuf * t)
 {
-    CossInfo *cs = (CossInfo *) SD->fsdata;
     debug(79, 3) ("storeCossWriteMemBuf: offset %ld, len %ld\n",
        (long int) t->diskstart, (long int) (t->diskend - t->diskstart));
     t->flags.writing = 1;
     /* Remember that diskstart/diskend are block offsets! */
-    a_file_write(&cs->aq, cs->fd, t->diskstart, &t->buffer,
+    a_file_write(&SD->aq, SD->fd, t->diskstart, &t->buffer,
        t->diskend - t->diskstart, storeCossWriteMemBufDone, t, NULL);
 }
 
 
 static void
-storeCossWriteMemBufDone(int fd, int errflag, size_t len, void *my_data)
+storeCossWriteMemBufDone(int rvfd, int errflag, size_t len, void *my_data)
 {
     CossMemBuf *t = (CossMemBuf *)my_data;
-    CossInfo *cs = (CossInfo *) t->SD->fsdata;
 
     debug(79, 3) ("storeCossWriteMemBufDone: buf %p, len %ld\n", t, (long int) len);
     if (errflag)
        debug(79, 0) ("storeCossMemBufWriteDone: got failure (%d)\n", errflag);
 
-    dlinkDelete(&t->node, &cs->membufs);
+    dlinkDelete(&t->node, &t->SD->membufs);
     cbdataFree(t);
 }
 
 static CossMemBuf *
-storeCossCreateMemBuf(SwapDir * SD, size_t start,
+storeCossCreateMemBuf(CossSwapDir * SD, size_t start,
     sfileno curfn, int *collision)
 {
     CossMemBuf *newmb, *t;
     StoreEntry *e;
     dlink_node *m, *prev;
     int numreleased = 0;
-    CossInfo *cs = (CossInfo *) SD->fsdata;
 
     CBDATA_INIT_TYPE_FREECB(CossMemBuf, NULL);
     newmb = cbdataAlloc(CossMemBuf);
@@ -518,10 +520,10 @@ storeCossCreateMemBuf(SwapDir * SD, size_t start,
     newmb->lockcount = 0;
     newmb->SD = SD;
     /* XXX This should be reversed, with the new buffer last in the chain */
-    dlinkAdd(newmb, &newmb->node, &cs->membufs);
+    dlinkAdd(newmb, &newmb->node, &SD->membufs);
 
     /* Print out the list of membufs */
-    for (m = cs->membufs.head; m; m = m->next) {
+    for (m = SD->membufs.head; m; m = m->next) {
        t = (CossMemBuf *)m->data;
        debug(79, 3) ("storeCossCreateMemBuf: membuflist %ld lockcount %d\n", (long int) t->diskstart, t->lockcount);
     }
@@ -529,7 +531,7 @@ storeCossCreateMemBuf(SwapDir * SD, size_t start,
     /*
      * Kill objects from the tail to make space for a new chunk
      */
-    for (m = cs->index.tail; m; m = prev) {
+    for (m = SD->cossindex.tail; m; m = prev) {
        prev = m->prev;
        e = (StoreEntry *)m->data;
        if (curfn == e->swap_filen)
@@ -550,19 +552,16 @@ storeCossCreateMemBuf(SwapDir * SD, size_t start,
  * Creates the initial membuf after rebuild
  */
 void
-storeCossStartMembuf(SwapDir * sd)
+storeCossStartMembuf(CossSwapDir * sd)
 {
-    CossInfo *cs = (CossInfo *) sd->fsdata;
-    CossMemBuf *newmb = storeCossCreateMemBuf(sd, cs->current_offset, -1, NULL);
-    assert(!cs->current_membuf);
-    cs->current_membuf = newmb;
+    CossMemBuf *newmb = storeCossCreateMemBuf(sd, sd->current_offset, -1, NULL);
+    assert(!sd->current_membuf);
+    sd->current_membuf = newmb;
 }
 
 /*
  * Clean up any references from the SIO before it get's released.
  */
-static void
-storeCossIOFreeEntry(void *sio)
+CossState::~CossState()
 {
-    memPoolFree(coss_state_pool, ((storeIOState *) sio)->fsstate);
 }
index c83b96cb07b06a1a2309a9b3359b239dda00be6c..f001979054f69b99941d5a294bfa29a31b2911de 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: diskd.cc,v 1.11 2002/10/13 20:35:26 robertc Exp $
+ * $Id: diskd.cc,v 1.12 2002/12/27 10:26:37 robertc Exp $
  *
  * DEBUG: section --    External DISKD process implementation.
  * AUTHOR: Harvest Derived
@@ -224,10 +224,12 @@ msg_handle(diomsg * r, int rl, diomsg * s)
     s->callback_data = r->callback_data;
     s->shm_offset = r->shm_offset;
     s->id = r->id;
+    s->newstyle = r->newstyle;
     if (s->shm_offset > -1)
        buf = shmbuf + s->shm_offset;
     switch (r->mtype) {
     case _MQD_OPEN:
+    case _MQD_CREATE:
        s->status = do_open(r, rl, buf);
        break;
     case _MQD_CLOSE:
index e0486b7bea776241b0c7ef052db3743ba09c3a30..72f26dfbd6f2704f8509d5d6a06a3f5fd7adb473 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_dir_diskd.cc,v 1.73 2002/10/28 08:53:37 adrian Exp $
+ * $Id: store_dir_diskd.cc,v 1.74 2002/12/27 10:26:37 robertc Exp $
  *
  * DEBUG: section 47    Store Directory Routines
  * AUTHOR: Duane Wessels
 
 #include "ufscommon.h"
 
+#include "SwapDir.h"
+
 diskd_stats_t diskd_stats;
 
-MemPool *diskd_state_pool = NULL;
 static int diskd_initialised = 0;
 
-static STINIT storeDiskdDirInit;
-static STDUMP storeDiskdDirDump;
-static STCHECKOBJ storeDiskdDirCheckObj;
-static void storeDiskdDirStats(SwapDir *, StoreEntry *);
 static void storeDiskdStats(StoreEntry * sentry);
-static void storeDiskdDirSync(SwapDir *);
-static void storeDiskdDirIOUnlinkFile(char *path);
 
 /* The only externally visible interface */
 STSETUP storeFsSetup_diskd;
 
-static void
-storeDiskdDirInit(SwapDir * sd)
+
+
+void
+DiskdSwapDir::init()
 {
     int x;
-    int i;
     int rfd;
     int ikey;
     const char *args[5];
     char skey1[32];
     char skey2[32];
     char skey3[32];
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata;
+    DiskdIO *DIO = dynamic_cast<DiskdIO *>(IO);
 
-    ikey = (getpid() << 10) + (sd->index << 2);
+    ikey = (getpid() << 10) + (index << 2);
     ikey &= 0x7fffffff;
-    diskdinfo->smsgid = msgget((key_t) ikey, 0700 | IPC_CREAT);
-    if (diskdinfo->smsgid < 0) {
+    DIO->smsgid = msgget((key_t) ikey, 0700 | IPC_CREAT);
+    if (DIO->smsgid < 0) {
        debug(50, 0) ("storeDiskdInit: msgget: %s\n", xstrerror());
        fatal("msgget failed");
     }
-    diskdinfo->rmsgid = msgget((key_t) (ikey + 1), 0700 | IPC_CREAT);
-    if (diskdinfo->rmsgid < 0) {
+    DIO->rmsgid = msgget((key_t) (ikey + 1), 0700 | IPC_CREAT);
+    if (DIO->rmsgid < 0) {
        debug(50, 0) ("storeDiskdInit: msgget: %s\n", xstrerror());
        fatal("msgget failed");
     }
-    diskdinfo->shm.nbufs = (int)(diskdinfo->magic2 * 1.3);
-    diskdinfo->shm.id = shmget((key_t) (ikey + 2),
-       diskdinfo->shm.nbufs * SHMBUF_BLKSZ, 0600 | IPC_CREAT);
-    if (diskdinfo->shm.id < 0) {
-       debug(50, 0) ("storeDiskdInit: shmget: %s\n", xstrerror());
-       fatal("shmget failed");
-    }
-    diskdinfo->shm.buf = (char *)shmat(diskdinfo->shm.id, NULL, 0);
-    if (diskdinfo->shm.buf == (void *) -1) {
-       debug(50, 0) ("storeDiskdInit: shmat: %s\n", xstrerror());
-       fatal("shmat failed");
-    }
-    diskdinfo->shm.inuse_map = (char *)xcalloc((diskdinfo->shm.nbufs + 7) / 8, 1);
-    diskd_stats.shmbuf_count += diskdinfo->shm.nbufs;
-    for (i = 0; i < diskdinfo->shm.nbufs; i++) {
-       CBIT_SET(diskdinfo->shm.inuse_map, i);
-       storeDiskdShmPut(sd, i * SHMBUF_BLKSZ);
-    }
+    DIO->shm.init(ikey, DIO->magic2);
     snprintf(skey1, 32, "%d", ikey);
     snprintf(skey2, 32, "%d", ikey + 1);
     snprintf(skey3, 32, "%d", ikey + 2);
@@ -116,16 +95,16 @@ storeDiskdDirInit(SwapDir * sd)
        args,
        "diskd",
        &rfd,
-       &diskdinfo->wfd);
+       &DIO->wfd);
     if (x < 0)
        fatalf("execl: %s", Config.Program.diskd);
-    if (rfd != diskdinfo->wfd)
+    if (rfd != DIO->wfd)
        comm_close(rfd);
-    fd_note(diskdinfo->wfd, "squid -> diskd");
-    commSetTimeout(diskdinfo->wfd, -1, NULL, NULL);
-    commSetNonBlocking(diskdinfo->wfd);
+    fd_note(DIO->wfd, "squid -> diskd");
+    commSetTimeout(DIO->wfd, -1, NULL, NULL);
+    commSetNonBlocking(DIO->wfd);
     
-    commonUfsDirInit (sd);
+    UFSSwapDir::init();
     
     comm_quick_poll_required();
 }
@@ -162,18 +141,18 @@ storeDiskdStats(StoreEntry * sentry)
  * Sync any pending data. We just sit around and read the queue
  * until the data has finished writing.
  */
-static void
-storeDiskdDirSync(SwapDir * SD)
+void
+DiskdSwapDir::sync()
 {
     static time_t lastmsg = 0;
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata;
-    while (diskdinfo->away > 0) {
+    DiskdIO *DIO = dynamic_cast<DiskdIO *>(IO);
+    while (DIO->away > 0) {
        if (squid_curtime > lastmsg) {
            debug(47, 1) ("storeDiskdDirSync: %d messages away\n",
-               diskdinfo->away);
+               DIO->away);
            lastmsg = squid_curtime;
        }
-       storeDiskdDirCallback(SD);
+       callback();
     }
 }
 
@@ -186,14 +165,14 @@ storeDiskdDirSync(SwapDir * SD)
  * don't get a message.
  */
 int
-storeDiskdDirCallback(SwapDir * SD)
+DiskdSwapDir::callback()
 {
     diomsg M;
     int x;
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata;
     int retval = 0;
 
-    if (diskdinfo->away >= diskdinfo->magic2) {
+    DiskdIO *DIO = dynamic_cast<DiskdIO *>(IO);
+    if (DIO->away >= DIO->magic2) {
        diskd_stats.block_queue_len++;
        retval = 1;             /* We might not have anything to do, but our queue
                                 * is full.. */
@@ -206,7 +185,7 @@ storeDiskdDirCallback(SwapDir * SD)
 #ifdef ALWAYS_ZERO_BUFFERS
        memset(&M, '\0', sizeof(M));
 #endif
-       x = msgrcv(diskdinfo->rmsgid, &M, msg_snd_rcv_sz, 0, IPC_NOWAIT);
+       x = msgrcv(DIO->rmsgid, &M, msg_snd_rcv_sz, 0, IPC_NOWAIT);
        if (x < 0)
            break;
        else if (x != msg_snd_rcv_sz) {
@@ -215,11 +194,11 @@ storeDiskdDirCallback(SwapDir * SD)
            break;
        }
        diskd_stats.recv_count++;
-       diskdinfo->away--;
+       --DIO->away;
        storeDiskdHandle(&M);
        retval = 1;             /* Return that we've actually done some work */
        if (M.shm_offset > -1)
-           storeDiskdShmPut(SD, (off_t) M.shm_offset);
+           DIO->shm.put ((off_t) M.shm_offset);
     }
     return retval;
 }
@@ -232,19 +211,15 @@ storeDiskdDirCallback(SwapDir * SD)
  * happily store anything as long as the LRU time isn't too small.
  */
 int
-storeDiskdDirCheckObj(SwapDir * SD, const StoreEntry * e)
+DiskdSwapDir::canStore(StoreEntry const &e)const
 {
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata;
-    /* Check the queue length */
-    if (diskdinfo->away >= diskdinfo->magic1)
+    if (IO->shedLoad())
        return -1;
-    /* Calculate the storedir load relative to magic2 on a scale of 0 .. 1000 */
-    /* the parse function guarantees magic2 is positivie */
-    return diskdinfo->away * 1000 / diskdinfo->magic2;
+    return IO->load();
 }
 
 void
-storeDiskdDirIOUnlinkFile(char *path)
+DiskdSwapDir::unlinkFile(char const *path)
 {
 #if USE_UNLINKD
     unlinkdUnlink(path);
@@ -256,69 +231,25 @@ storeDiskdDirIOUnlinkFile(char *path)
                
 }
 
-/*
- * SHM manipulation routines
- */
-
-void *
-storeDiskdShmGet(SwapDir * sd, off_t * shm_offset)
-{
-    char *buf = NULL;
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata;
-    int i;
-    for (i = 0; i < diskdinfo->shm.nbufs; i++) {
-       if (CBIT_TEST(diskdinfo->shm.inuse_map, i))
-           continue;
-       CBIT_SET(diskdinfo->shm.inuse_map, i);
-       *shm_offset = i * SHMBUF_BLKSZ;
-       buf = diskdinfo->shm.buf + (*shm_offset);
-       break;
-    }
-    assert(buf);
-    assert(buf >= diskdinfo->shm.buf);
-    assert(buf < diskdinfo->shm.buf + (diskdinfo->shm.nbufs * SHMBUF_BLKSZ));
-    diskd_stats.shmbuf_count++;
-    if (diskd_stats.max_shmuse < diskd_stats.shmbuf_count)
-       diskd_stats.max_shmuse = diskd_stats.shmbuf_count;
-    return buf;
-}
-
-void
-storeDiskdShmPut(SwapDir * sd, off_t offset)
-{
-    int i;
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata;
-    assert(offset >= 0);
-    assert(offset < diskdinfo->shm.nbufs * SHMBUF_BLKSZ);
-    i = offset / SHMBUF_BLKSZ;
-    assert(i < diskdinfo->shm.nbufs);
-    assert(CBIT_TEST(diskdinfo->shm.inuse_map, i));
-    CBIT_CLR(diskdinfo->shm.inuse_map, i);
-    diskd_stats.shmbuf_count--;
-}
-
-
-
-
 /* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */
 
 void
-storeDiskdDirStats(SwapDir * SD, StoreEntry * sentry)
+DiskdSwapDir::statfs(StoreEntry & sentry)const
 {
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata;
-    commonUfsDirStats (SD, sentry);
-    storeAppendPrintf(sentry, "Pending operations: %d\n", diskdinfo->away);
+    UFSSwapDir::statfs (sentry);
+    DiskdIO *DIO = dynamic_cast<DiskdIO *>(IO);
+    storeAppendPrintf(&sentry, "Pending operations: %d\n", DIO->away);
 }
 
 static void
 storeDiskdDirParseQ1(SwapDir * sd, const char *name, const char *value, int reconfiguring)
 {
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata;
-    int old_magic1 = diskdinfo->magic1;
-    diskdinfo->magic1 = atoi(value);
+    DiskdIO *IO = dynamic_cast<DiskdIO *>(((DiskdSwapDir *)sd)->IO);
+    int old_magic1 = IO->magic1;
+    IO->magic1 = atoi(value);
     if (!reconfiguring)
        return;
-    if (old_magic1 < diskdinfo->magic1) {
+    if (old_magic1 < IO->magic1) {
        /*
        * This is because shm.nbufs is computed at startup, when
        * we call shmget().  We can't increase the Q1/Q2 parameters
@@ -327,45 +258,46 @@ storeDiskdDirParseQ1(SwapDir * sd, const char *name, const char *value, int reco
        * will cause an assertion in storeDiskdShmGet().
        */
        debug(3, 1) ("WARNING: cannot increase cache_dir '%s' Q1 value while Squid is running.\n", sd->path);
-       diskdinfo->magic1 = old_magic1;
+       IO->magic1 = old_magic1;
        return;
     }
-    if (old_magic1 != diskdinfo->magic1)
+    if (old_magic1 != IO->magic1)
        debug(3, 1) ("cache_dir '%s' new Q1 value '%d'\n",
-           sd->path, diskdinfo->magic1);
+           sd->path, IO->magic1);
 }
 
 static void
-storeDiskdDirDumpQ1(StoreEntry * e, const char *option, SwapDir * sd)
+storeDiskdDirDumpQ1(StoreEntry * e, const char *option, SwapDir const * sd)
 {
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata;
-    storeAppendPrintf(e, " Q1=%d", diskdinfo->magic1);
+    DiskdIO *IO = dynamic_cast<DiskdIO *>(((DiskdSwapDir *)sd)->IO);
+    storeAppendPrintf(e, " Q1=%d", IO->magic1);
 }
 
 static void
 storeDiskdDirParseQ2(SwapDir * sd, const char *name, const char *value, int reconfiguring)
 {
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata;
-    int old_magic2 = diskdinfo->magic2;
-    diskdinfo->magic2 = atoi(value);
+    DiskdIO *IO = dynamic_cast<DiskdIO *>(((DiskdSwapDir *)sd)->IO);
+    assert (IO);
+    int old_magic2 = IO->magic2;
+    IO->magic2 = atoi(value);
     if (!reconfiguring)
        return;
-    if (old_magic2 < diskdinfo->magic2) {
+    if (old_magic2 < IO->magic2) {
        /* See comments in Q1 function above */
        debug(3, 1) ("WARNING: cannot increase cache_dir '%s' Q2 value while Squid is running.\n", sd->path);
-       diskdinfo->magic2 = old_magic2;
+       IO->magic2 = old_magic2;
        return;
     }
-    if (old_magic2 != diskdinfo->magic2)
+    if (old_magic2 != IO->magic2)
        debug(3, 1) ("cache_dir '%s' new Q2 value '%d'\n",
-           sd->path, diskdinfo->magic2);
+           sd->path, IO->magic2);
 }
 
 static void
-storeDiskdDirDumpQ2(StoreEntry * e, const char *option, SwapDir * sd)
+storeDiskdDirDumpQ2(StoreEntry * e, const char *option, SwapDir const * sd)
 {
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata;
-    storeAppendPrintf(e, " Q2=%d", diskdinfo->magic2);
+    DiskdIO *IO = dynamic_cast<DiskdIO *>(((DiskdSwapDir *)sd)->IO);
+    storeAppendPrintf(e, " Q2=%d", IO->magic2);
 }
 
 struct cache_dir_option options[] =
@@ -384,43 +316,19 @@ struct cache_dir_option options[] =
  *
  * This routine is called when the given swapdir needs reconfiguring 
  */
-static void
-storeDiskdDirReconfigure(SwapDir * sd, int index, char *path)
+void
+DiskdSwapDir::reconfigure(int anIndex, char *aPath)
 {
-    int i;
-    int size;
-    int l1;
-    int l2;
-
-    i = GetInteger();
-    size = i << 10;            /* Mbytes to kbytes */
-    if (size <= 0)
-       fatal("storeDiskdDirReconfigure: invalid size value");
-    i = GetInteger();
-    l1 = i;
-    if (l1 <= 0)
-       fatal("storeDiskdDirReconfigure: invalid level 1 directories value");
-    i = GetInteger();
-    l2 = i;
-    if (l2 <= 0)
-       fatal("storeDiskdDirReconfigure: invalid level 2 directories value");
-
-    /* just reconfigure it */
-    if (size == sd->max_size)
-       debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n",
-           path, size);
-    else
-       debug(3, 1) ("Cache dir '%s' size changed to %d KB\n",
-           path, size);
-    sd->max_size = size;
-    parse_cachedir_options(sd, options, 1);
+    UFSSwapDir::reconfigure (anIndex, aPath);
+
+    parse_cachedir_options(this, options, 1);
 }
 
 void
-storeDiskdDirDump(StoreEntry * entry, SwapDir * s)
+DiskdSwapDir::dump(StoreEntry & entry)const
 {
-    commonUfsDirDump (entry, s);
-    dump_cachedir_options(entry, options, s);
+    UFSSwapDir::dump (entry);
+    dump_cachedir_options(&entry, options, this);
 }
 
 /*
@@ -428,69 +336,12 @@ storeDiskdDirDump(StoreEntry * entry, SwapDir * s)
  *
  * Called when a *new* fs is being setup.
  */
-static void
-storeDiskdDirParse(SwapDir * sd, int index, char *path)
+void
+DiskdSwapDir::parse(int anIndex, char *aPath)
 {
-    int i;
-    int size;
-    int l1;
-    int l2;
-    diskdinfo_t *diskdinfo;
-
-    i = GetInteger();
-    size = i << 10;            /* Mbytes to kbytes */
-    if (size <= 0)
-       fatal("storeDiskdDirParse: invalid size value");
-    i = GetInteger();
-    l1 = i;
-    if (l1 <= 0)
-       fatal("storeDiskdDirParse: invalid level 1 directories value");
-    i = GetInteger();
-    l2 = i;
-    if (l2 <= 0)
-       fatal("storeDiskdDirParse: invalid level 2 directories value");
-
-    sd->fsdata = diskdinfo = (diskdinfo_t *)xcalloc(1, sizeof(*diskdinfo));
-    sd->index = index;
-    sd->path = xstrdup(path);
-    sd->max_size = size;
-    diskdinfo->commondata.l1 = l1;
-    diskdinfo->commondata.l2 = l2;
-    diskdinfo->commondata.swaplog_fd = -1;
-    diskdinfo->commondata.map = NULL;  /* Debugging purposes */
-    diskdinfo->commondata.suggest = 0;
-    diskdinfo->commondata.io.storeDirUnlinkFile = storeDiskdDirIOUnlinkFile;
-    diskdinfo->magic1 = 64;
-    diskdinfo->magic2 = 72;
-    sd->init = storeDiskdDirInit;
-    sd->newfs = commonUfsDirNewfs;
-    sd->dump = storeDiskdDirDump;
-    sd->freefs = commonUfsDirFree;
-    sd->dblcheck = commonUfsCleanupDoubleCheck;
-    sd->statfs = storeDiskdDirStats;
-    sd->maintainfs = commonUfsDirMaintain;
-    sd->checkobj = storeDiskdDirCheckObj;
-    sd->refobj = commonUfsDirRefObj;
-    sd->unrefobj = commonUfsDirUnrefObj;
-    sd->callback = storeDiskdDirCallback;
-    sd->sync = storeDiskdDirSync;
-    sd->obj.create = storeDiskdCreate;
-    sd->obj.open = storeDiskdOpen;
-    sd->obj.close = storeDiskdClose;
-    sd->obj.read = storeDiskdRead;
-    sd->obj.write = storeDiskdWrite;
-    sd->obj.unlink = storeDiskdUnlink;
-    sd->log.open = commonUfsDirOpenSwapLog;
-    sd->log.close = commonUfsDirCloseSwapLog;
-    sd->log.write = commonUfsDirSwapLog;
-    sd->log.clean.start = commonUfsDirWriteCleanStart;
-    sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry;
-    sd->log.clean.done = commonUfsDirWriteCleanDone;
-
-    parse_cachedir_options(sd, options, 0);
-
-    /* Initialise replacement policy stuff */
-    sd->repl = createRemovalPolicy(Config.replPolicy);
+    UFSSwapDir::parse(anIndex, aPath);
+
+    parse_cachedir_options(this, options, 0);
 }
 
 /*
@@ -499,18 +350,23 @@ storeDiskdDirParse(SwapDir * sd, int index, char *path)
 static void
 storeDiskdDirDone(void)
 {
-    memPoolDestroy(&diskd_state_pool);
     diskd_initialised = 0;
 }
 
+static SwapDir *
+storeDiskdNew(void)
+{
+    DiskdSwapDir *result = new DiskdSwapDir;
+    result->IO = new DiskdIO;
+    return result;
+}
+
 void
 storeFsSetup_diskd(storefs_entry_t * storefs)
 {
     assert(!diskd_initialised);
-    storefs->parsefunc = storeDiskdDirParse;
-    storefs->reconfigurefunc = storeDiskdDirReconfigure;
     storefs->donefunc = storeDiskdDirDone;
-    diskd_state_pool = memPoolCreate("DISKD IO State data", sizeof(diskdstate_t));
+    storefs->newfunc = storeDiskdNew;
     memset(&diskd_stats, '\0', sizeof(diskd_stats));
     cachemgrRegister("diskd", "DISKD Stats", storeDiskdStats, 0, 1);
     debug(47, 1) ("diskd started\n");
index 8833fabc053eec94a9b918d8de65c9775283c726..a1a9f4ed7aaf97fb658caaee2cd16eeea0019840 100644 (file)
  * is 75% of SHMBUFS. magic1 is the number of messages away which we
  * stop allowing open/create for.
  */
-
-struct _diskdinfo_t {
-    /* MUST BE FIRST */
-    squidufsinfo_t commondata;
-    int smsgid;
-    int rmsgid;
-    int wfd;
-    int away;
-    struct {
-       char *buf;
-       char *inuse_map;
-       int id;
-       int nbufs;
-    } shm;
-    int magic1;
-    int magic2;
+typedef struct _diomsg diomsg;
+class DiskdIO;
+class DiskdFile : public DiskFile {
+  public:
+    virtual void deleteSelf() const;
+    void * operator new (size_t);
+    void operator delete (void *);
+    DiskdFile (char const *path, DiskdIO *);
+    ~DiskdFile();
+    virtual void open (int, mode_t, IORequestor::Pointer);
+    virtual void create (int, mode_t, IORequestor::Pointer);
+    virtual void read(char *, off_t, size_t);
+    virtual void write(char const *buf, size_t size, off_t offset, FREE *free_func);
+    virtual void close ();
+    virtual bool error() const;
+    virtual bool canRead() const;
+
+    /* Temporary */
+    int getID() const {return id;}
+    void completed (diomsg *);
+      
+  private:
+    int id;
+    char const *path_;
+    bool errorOccured;
+    DiskdIO *IO;
+    IORequestor::Pointer ioRequestor;
+    CBDATA_CLASS(DiskdFile); 
+    void openDone(diomsg *);
+    void createDone (diomsg *);
+    void readDone (diomsg *);
+    void writeDone (diomsg *);
+    void closeDone (diomsg *);
+    int mode;
+    void notifyClient();
+    bool canNotifyClient() const;
 };
 
-struct _diskdstate_t {
+class SharedMemory{
+public:
+    void put(off_t);
+    void *get(off_t *);
+    void init (int ikey, int magic2);
+    int nbufs;
+    char *buf;
+    char *inuse_map;
     int id;
-    struct {
-       unsigned int close_request:1;
-       unsigned int reading:1;
-       unsigned int writing:1;
-    } flags;
-    char *read_buf;
+};
+
+class diskdstate_t : public UFSStoreState {
+  public:
+    virtual void deleteSelf() const {delete this;}
+    void * operator new (size_t);
+    void operator delete (void *);
+    diskdstate_t(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data);
+    ~diskdstate_t();
+
+    void close();
+    
+    void ioCompletedNotification();
+    void readCompleted(const char *buf, int len, int errflag);
+    void writeCompleted(int errflag, size_t len);
+    void closeCompleted();
+  private:
+    CBDATA_CLASS(diskdstate_t);
+    void doCallback(int);
 };
 
 enum {
     _MQD_NOP,
     _MQD_OPEN,
+    _MQD_CREATE,
     _MQD_CLOSE,
     _MQD_READ,
     _MQD_WRITE,
     _MQD_UNLINK
 };
 
-typedef struct _diomsg {
+struct _diomsg {
     mtyp_t mtype;
     int id;
     int seq_no;
-    void *callback_data;
+    void * callback_data;
     int size;
     int offset;
     int status;
+    bool newstyle;
     int shm_offset;
-} diomsg;
+};
 
 struct _diskd_stats {
     int open_fail_queue_len;
@@ -81,32 +123,48 @@ struct _diskd_stats {
 };
 
 typedef struct _diskd_stats diskd_stats_t;
-typedef struct _diskdinfo_t diskdinfo_t;
-typedef struct _diskdstate_t diskdstate_t;
 
-static const int msg_snd_rcv_sz = sizeof(diomsg) - sizeof(mtyp_t);
 
-/* The diskd_state memory pool */
-extern MemPool *diskd_state_pool;
+static const int msg_snd_rcv_sz = sizeof(diomsg) - sizeof(mtyp_t);
 
-extern void storeDiskdShmPut(SwapDir *, off_t);
-extern void *storeDiskdShmGet(SwapDir *, off_t *);
 extern void storeDiskdHandle(diomsg * M);
-extern int storeDiskdDirCallback(SwapDir *);
 
-
-/*
- * Store IO stuff
- */
-extern STOBJCREATE storeDiskdCreate;
-extern STOBJOPEN storeDiskdOpen;
-extern STOBJCLOSE storeDiskdClose;
-extern STOBJREAD storeDiskdRead;
-extern STOBJWRITE storeDiskdWrite;
-extern STOBJUNLINK storeDiskdUnlink;
+#include "SwapDir.h"
+class DiskdSwapDir : public UFSSwapDir
+{
+public:
+    virtual void init();
+    virtual void dump(StoreEntry &)const;
+    virtual void unlink(StoreEntry &);
+    virtual void statfs (StoreEntry &) const;
+    virtual int canStore(StoreEntry const &) const;
+    virtual int callback();
+    virtual void sync();
+    virtual void parse (int index, char *path);
+    virtual void reconfigure (int, char *);
+    virtual void unlinkFile(char const *);
+};
 
 #define SHMBUF_BLKSZ SM_PAGE_SIZE
 
 extern diskd_stats_t diskd_stats;
+class DiskdIO : public UFSStrategy
+{
+public:
+    DiskdIO();
+    virtual bool shedLoad();
+    virtual void deleteSelf() const;
+    virtual void openFailed();
+    virtual int load();
+    virtual StoreIOState::Pointer createState(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data) const;
+    virtual DiskFile::Pointer newFile (char const *path);
+    int away;
+    int magic1;
+    int magic2;
+    int smsgid;
+    int rmsgid;
+    int wfd;
+    SharedMemory shm;
+};
 
 #endif
index d97d0384f96e66851ec7277a5acdf6d9283f37c4..35e6114cdff665898bf618a22cb8bdaa80c62bba 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_io_diskd.cc,v 1.29 2002/10/13 20:35:26 robertc Exp $
+ * $Id: store_io_diskd.cc,v 1.30 2002/12/27 10:26:37 robertc Exp $
  *
  * DEBUG: section 79    Squid-side DISKD I/O functions.
  * AUTHOR: Duane Wessels
 #include <sys/shm.h>
 
 #include "store_diskd.h"
+#include "SwapDir.h"
 
-static int storeDiskdSend(int, SwapDir *, int, storeIOState *, int, int, off_t);
-static void storeDiskdIOCallback(storeIOState * sio, int errflag);
-static CBDUNL storeDiskdIOFreeEntry;
-
-CBDATA_TYPE(storeIOState);
+static int storeDiskdSend(int, DiskdIO *, int, StoreIOState::Pointer, int, int, off_t);
+static int storeDiskdSend(int, DiskdIO *, int, DiskdFile *, int, int, off_t);
 
 /* === PUBLIC =========================================================== */
+DiskdIO::DiskdIO() : away (0), magic1(64), magic2(72)
+{
+}
 
-storeIOState *
-storeDiskdOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
-    STIOCB * callback, void *callback_data)
+bool
+DiskdIO::shedLoad()
 {
-    sfileno f = e->swap_filen;
-    int x;
-    storeIOState *sio;
-    char *buf;
-    diskdstate_t *diskdstate;
-    off_t shm_offset;
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata;
-    debug(79, 3) ("storeDiskdOpen: fileno %08X\n", f);
     /*
      * Fail on open() if there are too many requests queued.
      */
-    if (diskdinfo->away > diskdinfo->magic1) {
-       debug(79, 3) ("storeDiskdOpen: FAILING, too many requests away\n");
-       diskd_stats.open_fail_queue_len++;
-       return NULL;
+    if (away > magic1) {
+       debug(79, 3) ("storeDiskdIO::sheLoad: Shedding, too many requests away\n");
+
+       return true;
+    }
+    return false;
+}
+
+int
+DiskdIO::load()
+{
+    /* Calculate the storedir load relative to magic2 on a scale of 0 .. 1000 */
+    /* the parse function guarantees magic2 is positivie */
+    return away * 1000 / magic2;
+}
+
+void
+DiskdIO::deleteSelf() const
+{
+    /* do nothing, we use a single instance */
+}
+
+void
+DiskdIO::openFailed()
+{
+    diskd_stats.open_fail_queue_len++;
+}
+
+StoreIOState::Pointer
+DiskdIO::createState(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data) const
+{
+    return new diskdstate_t (SD, e, callback, callback_data);
+}
+
+DiskFile::Pointer
+DiskdIO::newFile (char const *path)
+{
+    return new DiskdFile (path, this);
+}
+
+
+/*
+ * SHM manipulation routines
+ */
+void
+SharedMemory::put (off_t offset)
+{
+    int i;
+    assert(offset >= 0);
+    assert(offset < nbufs * SHMBUF_BLKSZ);
+    i = offset / SHMBUF_BLKSZ;
+    assert(i < nbufs);
+    assert(CBIT_TEST(inuse_map, i));
+    CBIT_CLR(inuse_map, i);
+    --diskd_stats.shmbuf_count;
+}
+
+void *
+SharedMemory::get (off_t * shm_offset)
+{
+    char *aBuf = NULL;
+    int i;
+    for (i = 0; i < nbufs; i++) {
+       if (CBIT_TEST(inuse_map, i))
+           continue;
+       CBIT_SET(inuse_map, i);
+       *shm_offset = i * SHMBUF_BLKSZ;
+       aBuf = buf + (*shm_offset);
+       break;
     }
-    CBDATA_INIT_TYPE_FREECB(storeIOState, storeDiskdIOFreeEntry);
-    sio = cbdataAlloc(storeIOState);
-    sio->fsstate = diskdstate = (diskdstate_t *)memPoolAlloc(diskd_state_pool);
-
-    sio->swap_filen = f;
-    sio->swap_dirn = SD->index;
-    sio->mode = O_RDONLY | O_BINARY;
-    sio->callback = callback;
-    sio->callback_data = cbdataReference(callback_data);
-    sio->e = e;
-
-    diskdstate->flags.writing = 0;
-    diskdstate->flags.reading = 0;
-    diskdstate->flags.close_request = 0;
-    diskdstate->id = diskd_stats.sio_id++;
-
-    buf = (char *)storeDiskdShmGet(SD, &shm_offset);
-    xstrncpy(buf, commonUfsDirFullPath(SD, f, NULL), SHMBUF_BLKSZ);
-    x = storeDiskdSend(_MQD_OPEN,
-       SD,
-       diskdstate->id,
-       sio,
+    assert(aBuf);
+    assert(aBuf >= buf);
+    assert(aBuf < buf + (nbufs * SHMBUF_BLKSZ));
+    diskd_stats.shmbuf_count++;
+    if (diskd_stats.max_shmuse < diskd_stats.shmbuf_count)
+       diskd_stats.max_shmuse = diskd_stats.shmbuf_count;
+    return aBuf;
+}
+
+void
+SharedMemory::init(int ikey, int magic2)
+{
+    nbufs = (int)(magic2 * 1.3);
+    id = shmget((key_t) (ikey + 2),
+       nbufs * SHMBUF_BLKSZ, 0600 | IPC_CREAT);
+    if (id < 0) {
+       debug(50, 0) ("storeDiskdInit: shmget: %s\n", xstrerror());
+       fatal("shmget failed");
+    }
+    buf = (char *)shmat(id, NULL, 0);
+    if (buf == (void *) -1) {
+       debug(50, 0) ("storeDiskdInit: shmat: %s\n", xstrerror());
+       fatal("shmat failed");
+    }
+    inuse_map = (char *)xcalloc((nbufs + 7) / 8, 1);
+    diskd_stats.shmbuf_count += nbufs;
+    for (int i = 0; i < nbufs; i++) {
+       CBIT_SET(inuse_map, i);
+       put (i * SHMBUF_BLKSZ);
+    }
+}
+
+CBDATA_CLASS_INIT(DiskdFile);
+
+void *
+DiskdFile::operator new (size_t)
+{
+    CBDATA_INIT_TYPE(DiskdFile);
+    DiskdFile *result = cbdataAlloc(DiskdFile);
+    /* Mark result as being owned - we want the refcounter to do the delete
+     * call */
+    cbdataReference(result);
+    debug (0,0)("diskdFile with base %p allocating\n", result);
+    return result;
+}
+void
+DiskdFile::operator delete (void *address)
+{
+    debug (0,0)("diskdFile with base %p deleting\n",address);
+    DiskdFile *t = static_cast<DiskdFile *>(address);
+    cbdataFree(address);
+    /* And allow the memory to be freed */
+    cbdataReferenceDone (t);
+}
+
+void
+DiskdFile::deleteSelf() const {delete this;}
+
+DiskdFile::DiskdFile (char const *aPath, DiskdIO *anIO) : errorOccured (false), IO(anIO)
+{
+    assert (aPath);
+    debug (79,0)("DiskdFile::DiskdFile: %s\n", aPath);
+    path_ = xstrdup (aPath);
+    id = diskd_stats.sio_id++;
+}
+
+DiskdFile::~DiskdFile()
+{
+    safe_free (path_);
+}
+
+void
+DiskdFile::open (int flags, mode_t aMode, IORequestor::Pointer callback)
+{
+    debug (79,0)("DiskdFile::open: %p opening for %p\n", this, callback.getRaw());
+    assert (ioRequestor.getRaw() == NULL);
+    ioRequestor = callback;
+    assert (callback.getRaw());
+    mode = flags;
+    off_t shm_offset;
+    char *buf = (char *)IO->shm.get(&shm_offset);
+    xstrncpy(buf, path_, SHMBUF_BLKSZ);
+    int x = storeDiskdSend(_MQD_OPEN,
+       IO,
+       id,
+       this,
        strlen(buf) + 1,
-       O_RDONLY,
+       mode,
        shm_offset);
     if (x < 0) {
-       debug(79, 1) ("storeDiskdSend OPEN: %s\n", xstrerror());
-       storeDiskdShmPut(SD, shm_offset);
-       cbdataReferenceDone(sio->callback_data);
-       cbdataFree(sio);
-       return NULL;
+       errorOccured = true;
+       IO->shm.put (shm_offset);
+       ioRequestor->ioCompletedNotification();
+       ioRequestor = NULL;
     }
     diskd_stats.open.ops++;
-    return sio;
 }
 
-storeIOState *
-storeDiskdCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
-    STIOCB * callback, void *callback_data)
-{
-    sfileno f;
-    int x;
-    storeIOState *sio;
-    char *buf;
+void
+DiskdFile::create (int flags, mode_t aMode, IORequestor::Pointer callback){
+    debug (79,0)("DiskdFile::create: %p creating for %p\n", this, callback.getRaw());
+    assert (ioRequestor.getRaw() == NULL);
+    ioRequestor = callback;
+    assert (callback.getRaw());
+    mode = flags;
     off_t shm_offset;
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata;
-    diskdstate_t *diskdstate;
-    /*
-     * Fail on open() if there are too many requests queued.
-     */
-    if (diskdinfo->away > diskdinfo->magic1) {
-       diskd_stats.open_fail_queue_len++;
-       return NULL;
-    }
-    /* Allocate a number */
-    f = commonUfsDirMapBitAllocate(SD);
-    debug(79, 3) ("storeDiskdCreate: fileno %08X\n", f);
-
-    CBDATA_INIT_TYPE_FREECB(storeIOState, storeDiskdIOFreeEntry);
-    sio = cbdataAlloc(storeIOState);
-    sio->fsstate = diskdstate = (diskdstate_t *)memPoolAlloc(diskd_state_pool);
-
-    sio->swap_filen = f;
-    sio->swap_dirn = SD->index;
-    sio->mode = O_WRONLY | O_CREAT | O_TRUNC;
-    sio->callback = callback;
-    sio->callback_data = cbdataReference(callback_data);
-    sio->e = e;
-
-    diskdstate->flags.writing = 0;
-    diskdstate->flags.reading = 0;
-    diskdstate->flags.close_request = 0;
-    diskdstate->id = diskd_stats.sio_id++;
-
-    buf = (char *)storeDiskdShmGet(SD, &shm_offset);
-    xstrncpy(buf, commonUfsDirFullPath(SD, f, NULL), SHMBUF_BLKSZ);
-    x = storeDiskdSend(_MQD_OPEN,
-       SD,
-       diskdstate->id,
-       sio,
-       strlen(buf) + 1,
-       sio->mode,
-       shm_offset);
+    char *buf = (char *)IO->shm.get(&shm_offset);
+    xstrncpy(buf, path_, SHMBUF_BLKSZ);
+    int x = storeDiskdSend(_MQD_CREATE,
+                          IO,
+                          id,
+                          this,
+                          strlen(buf) + 1,
+                          mode,
+                          shm_offset);
     if (x < 0) {
-       debug(79, 1) ("storeDiskdSend OPEN: %s\n", xstrerror());
-       storeDiskdShmPut(SD, shm_offset);
-       cbdataReferenceDone(sio->callback_data);
-       cbdataFree(sio);
-       return NULL;
+       errorOccured = true;
+       IO->shm.put (shm_offset);
+       debug(79, 1) ("storeDiskdSend CREATE: %s\n", xstrerror());
+       notifyClient();
+       ioRequestor = NULL;
+       return;
     }
-    commonUfsDirReplAdd(SD, e);
     diskd_stats.create.ops++;
-    return sio;
 }
 
+void
+DiskdFile::read(char *buf, off_t offset, size_t size)
+{
+    assert (ioRequestor.getRaw() != NULL);
+    off_t shm_offset;
+    char *rbuf = (char *)IO->shm.get(&shm_offset);
+    assert(rbuf);
+    int x = storeDiskdSend(_MQD_READ,
+       IO,
+        id,
+       this,
+       (int) size,
+       (int) offset,
+       shm_offset);
+    if (x < 0) {
+       errorOccured = true;
+       IO->shm.put (shm_offset);
+       debug(79, 1) ("storeDiskdSend READ: %s\n", xstrerror());
+       notifyClient();
+       ioRequestor = NULL;
+       return;
+    }
+    diskd_stats.read.ops++;
+}
 
 void
-storeDiskdClose(SwapDir * SD, storeIOState * sio)
+DiskdFile::close()
 {
-    int x;
-    diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate;
-    debug(79, 3) ("storeDiskdClose: dirno %d, fileno %08X\n", SD->index,
-       sio->swap_filen);
-    x = storeDiskdSend(_MQD_CLOSE,
-       SD,
-       diskdstate->id,
-       sio,
+    debug (79,0)("DiskdFile::close: %p closing for %p\n", this, ioRequestor.getRaw());
+    assert (ioRequestor.getRaw());
+    int x = storeDiskdSend(_MQD_CLOSE,
+       IO,
+       id,
+       this,
        0,
        0,
        -1);
     if (x < 0) {
+       errorOccured = true;
        debug(79, 1) ("storeDiskdSend CLOSE: %s\n", xstrerror());
-       storeDiskdIOCallback(sio, DISK_ERROR);
+       notifyClient();
+       ioRequestor = NULL;
+       return;
     }
-    diskdstate->flags.close_request = 1;
     diskd_stats.close.ops++;
 }
 
+bool
+DiskdFile::error() const
+{
+    return errorOccured;
+}
+
+bool
+DiskdFile::canRead() const
+{
+    return !error();
+}
+
+bool
+DiskdFile::canNotifyClient() const
+{
+    if (!ioRequestor.getRaw()) {
+       debug (79,3)("DiskdFile::canNotifyClient: No ioRequestor to notify\n");
+       return false;
+    }
+    return true;
+}
+
 void
-storeDiskdRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
+DiskdFile::notifyClient()
 {
-    int x;
-    off_t shm_offset;
-    char *rbuf;
-    diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate;
-    debug(79, 3) ("storeDiskdRead: dirno %d, fileno %08X\n", sio->swap_dirn, sio->swap_filen);
-    assert(!diskdstate->flags.close_request);
-    if (!cbdataReferenceValid(sio))
-       return;
-    if (diskdstate->flags.reading) {
-       debug(79, 1) ("storeDiskdRead: already reading!\n");
+    if (!canNotifyClient()) {
        return;
     }
-    assert(sio->read.callback == NULL);
-    assert(sio->read.callback_data == NULL);
-    sio->read.callback = callback;
-    sio->read.callback_data = cbdataReference(callback_data);
-    diskdstate->read_buf = buf;        /* the one passed from above */
-    sio->offset = offset;
-    diskdstate->flags.reading = 1;
-    rbuf = (char *)storeDiskdShmGet(SD, &shm_offset);
-    assert(rbuf);
-    x = storeDiskdSend(_MQD_READ,
-       SD,
-       diskdstate->id,
-       sio,
-       (int) size,
-       (int) offset,
-       shm_offset);
-    if (x < 0) {
-       debug(79, 1) ("storeDiskdSend READ: %s\n", xstrerror());
-       storeDiskdShmPut(SD, shm_offset);
-       storeDiskdIOCallback(sio, DISK_ERROR);
+    ioRequestor->ioCompletedNotification();
+}
+
+void
+DiskdFile::completed(diomsg *M)
+{
+    assert (M->newstyle);
+    switch (M->mtype) {
+       case _MQD_OPEN:
+           openDone(M);
+           break;
+       case _MQD_CREATE:
+           createDone(M);
+           break;
+       case _MQD_CLOSE:
+           closeDone(M);
+           break;
+       case _MQD_READ:
+           readDone(M);
+           break;
+       case _MQD_WRITE:
+           writeDone(M);
+           break;
+       case _MQD_UNLINK:
+           assert (0);
+           break;
+       default:
+           assert(0);
+           break;
+       }
+}
+
+void
+DiskdFile::openDone(diomsg *M) {
+    statCounter.syscalls.disk.opens++;
+    debug(79, 3) ("storeDiskdOpenDone: status %d\n", M->status);
+    assert (FILE_MODE(mode) == O_RDONLY);
+    if (M->status < 0) {
+       diskd_stats.open.fail++;
+       errorOccured = true;
+    } else {
+       diskd_stats.open.success++;
     }
-    diskd_stats.read.ops++;
+    notifyClient();
 }
 
 void
-storeDiskdWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func)
+DiskdFile::createDone(diomsg *M) {
+    statCounter.syscalls.disk.opens++;
+    debug(79, 3) ("storeDiskdCreateDone: status %d\n", M->status);
+    if (M->status < 0) {
+       diskd_stats.create.fail++;
+       errorOccured = true;
+    } else {
+       diskd_stats.create.success++;
+    }
+    notifyClient();
+}
+
+CBDATA_CLASS_INIT(diskdstate_t);
+
+void *
+diskdstate_t::operator new (size_t)
 {
-    int x;
-    char *sbuf;
-    off_t shm_offset;
-    diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate;
-    debug(79, 3) ("storeDiskdWrite: dirno %d, fileno %08X\n", SD->index, sio->swap_filen);
-    assert(!diskdstate->flags.close_request);
-    if (!cbdataReferenceValid(sio)) {
-       free_func(buf);
+    CBDATA_INIT_TYPE(diskdstate_t);
+    diskdstate_t *result = cbdataAlloc(diskdstate_t);
+    /* Mark result as being owned - we want the refcounter to do the delete
+     * call */
+    cbdataReference(result);
+    debug (0,0)("diskdstate with base %p allocating\n", result);
+    return result;
+}
+
+void
+diskdstate_t::operator delete (void *address)
+{
+    debug (0,0)("diskdstate with base %p deleting\n",address);
+    diskdstate_t *t = static_cast<diskdstate_t *>(address);
+    cbdataFree(address);
+    /* And allow the memory to be freed */
+    cbdataReferenceDone (t);
+}
+
+diskdstate_t::diskdstate_t(SwapDir *SD, StoreEntry *e_, STIOCB * callback_, void *callback_data_)
+{
+    swap_filen = e_->swap_filen;
+    swap_dirn = SD->index;
+    mode = O_BINARY;
+    callback = callback_;
+    callback_data = cbdataReference(callback_data_);
+    e = e_;
+}
+
+/*
+ * We can't pass memFree() as a free function here, because we need to free
+ * the fsdata variable ..
+ */
+diskdstate_t::~diskdstate_t()
+{
+}
+
+void
+diskdstate_t::ioCompletedNotification()
+{
+    if (opening) {
+       opening = false;
+       debug(79, 3) ("storeDiskdOpenDone: dirno %d, fileno %08x status %d\n",
+                     swap_dirn, swap_filen, theFile->error());
+       assert (FILE_MODE(mode) == O_RDONLY);
+       if (theFile->error()) {
+           doCallback(DISK_ERROR);
+       }
        return;
     }
-    diskdstate->flags.writing = 1;
-    sbuf = (char *)storeDiskdShmGet(SD, &shm_offset);
+    if (creating) {
+       creating = false;
+       debug(79, 3) ("storeDiskdCreateDone: dirno %d, fileno %08x status %d\n",
+                     swap_dirn, swap_filen, theFile->error());
+       if (theFile->error()) {
+           doCallback(DISK_ERROR);
+       }
+       return;
+    }
+    assert (!closing);
+    debug(79, 3) ("diskd::ioCompleted: dirno %d, fileno %08x status %d\n",                      swap_dirn, swap_filen, theFile->error());
+    /* Ok, notification past open means an error has occured */
+    assert (theFile->error());
+    doCallback(DISK_ERROR);
+}
+
+void
+diskdstate_t::closeCompleted()
+{
+    assert (closing);
+    debug(79, 3) ("storeDiskdCloseDone: dirno %d, fileno %08x status %d\n",
+       swap_dirn, swap_filen, theFile->error());
+    if (theFile->error()) {
+       doCallback(DISK_ERROR);
+    } else {
+       doCallback(DISK_OK);
+    }
+}
+void
+diskdstate_t::close()
+{
+    debug(79, 3) ("storeDiskdClose: dirno %d, fileno %08X\n", swap_dirn,
+       swap_filen);
+    closing = true;
+    ((DiskdFile *)theFile.getRaw())->close();
+}
+
+void
+DiskdFile::write(char const *buf, size_t size, off_t offset, FREE *free_func)
+{
+    off_t shm_offset;
+    char *sbuf = (char *)IO->shm.get(&shm_offset);
     xmemcpy(sbuf, buf, size);
     if (free_func)
-       free_func(buf);
-    x = storeDiskdSend(_MQD_WRITE,
-       SD,
-       diskdstate->id,
-       sio,
+       free_func(const_cast<char *>(buf));
+    int x = storeDiskdSend(_MQD_WRITE,
+       IO,
+        id,
+       this,
        (int) size,
        (int) offset,
        shm_offset);
     if (x < 0) {
+       errorOccured = true;
        debug(79, 1) ("storeDiskdSend WRITE: %s\n", xstrerror());
-       storeDiskdShmPut(SD, shm_offset);
-       storeDiskdIOCallback(sio, DISK_ERROR);
+       IO->shm.put (shm_offset);
+       notifyClient();
+       ioRequestor = NULL;
+       return;
     }
     diskd_stats.write.ops++;
 }
-
+  
 void
-storeDiskdUnlink(SwapDir * SD, StoreEntry * e)
+DiskdSwapDir::unlink(StoreEntry & e)
 {
     int x;
     off_t shm_offset;
     char *buf;
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)SD->fsdata;
 
-    debug(79, 3) ("storeDiskdUnlink: dirno %d, fileno %08X\n", SD->index,
-       e->swap_filen);
-    commonUfsDirReplRemove(e);
-    commonUfsDirMapBitReset(SD, e->swap_filen);
-    if (diskdinfo->away >= diskdinfo->magic1) {
+    debug(79, 3) ("storeDiskdUnlink: dirno %d, fileno %08X\n", index,
+       e.swap_filen);
+    replacementRemove(&e);
+    mapBitReset(e.swap_filen);
+    if (IO->shedLoad()) {
        /* Damn, we need to issue a sync unlink here :( */
        debug(79, 2) ("storeDiskUnlink: Out of queue space, sync unlink\n");
-       commonUfsDirUnlinkFile(SD, e->swap_filen);
+        UFSSwapDir::unlinkFile(e.swap_filen);
        return;
     }
     /* We can attempt a diskd unlink */
-    buf = (char *)storeDiskdShmGet(SD, &shm_offset);
-    xstrncpy(buf, commonUfsDirFullPath(SD, e->swap_filen, NULL), SHMBUF_BLKSZ);
+    buf = (char *)((DiskdIO *)IO)->shm.get(&shm_offset);
+    xstrncpy(buf, fullPath(e.swap_filen, NULL), SHMBUF_BLKSZ);
     x = storeDiskdSend(_MQD_UNLINK,
-       SD,
-       e->swap_filen,
-       NULL,
+       (DiskdIO *)IO,
+       e.swap_filen,
+       (StoreIOState::Pointer )NULL,
        0,
        0,
        shm_offset);
     if (x < 0) {
        debug(79, 1) ("storeDiskdSend UNLINK: %s\n", xstrerror());
-       unlink(buf);            /* XXX EWW! */
-       storeDiskdShmPut(SD, shm_offset);
+       ::unlink(buf);          /* XXX EWW! */
+       ((DiskdIO *)IO)->shm.put (shm_offset);
     }
     diskd_stats.unlink.ops++;
 }
@@ -300,93 +546,90 @@ storeDiskdUnlink(SwapDir * SD, StoreEntry * e)
 
 /*  === STATIC =========================================================== */
 
-static void
-storeDiskdOpenDone(diomsg * M)
-{
-    storeIOState *sio = (storeIOState *)M->callback_data;
-    statCounter.syscalls.disk.opens++;
-    debug(79, 3) ("storeDiskdOpenDone: dirno %d, fileno %08x status %d\n",
-       sio->swap_dirn, sio->swap_filen, M->status);
-    if (M->status < 0) {
-       FILE_MODE(sio->mode) == O_RDONLY ? diskd_stats.open.fail++ : diskd_stats.create.fail++;
-       storeDiskdIOCallback(sio, DISK_ERROR);
-    } else {
-       FILE_MODE(sio->mode) == O_RDONLY ? diskd_stats.open.success++ : diskd_stats.create.success++;
-    }
-}
-
-static void
-storeDiskdCloseDone(diomsg * M)
+void
+DiskdFile::closeDone(diomsg * M)
 {
-    storeIOState *sio = (storeIOState *)M->callback_data;
     statCounter.syscalls.disk.closes++;
-    debug(79, 3) ("storeDiskdCloseDone: dirno %d, fileno %08x status %d\n",
-       sio->swap_dirn, sio->swap_filen, M->status);
+    debug(79, 3) ("storeDiskdCloseDone: status %d\n", M->status);
     if (M->status < 0) {
        diskd_stats.close.fail++;
-       storeDiskdIOCallback(sio, DISK_ERROR);
-       return;
+       errorOccured = true;
+    } else {
+       diskd_stats.close.success++;
     }
-    diskd_stats.close.success++;
-    storeDiskdIOCallback(sio, DISK_OK);
+    if (canNotifyClient())
+       ioRequestor->closeCompleted();
+    ioRequestor = NULL;
 }
 
-static void
-storeDiskdReadDone(diomsg * M)
+void
+DiskdFile::readDone(diomsg * M)
 {
-    storeIOState *sio = (storeIOState *)M->callback_data;
-    STRCB *callback = sio->read.callback;
-    void *cbdata;
-    SwapDir *sd = INDEXSD(sio->swap_dirn);
-    diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate;
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata;
-    char *their_buf = diskdstate->read_buf;
-    char *sbuf;
-    size_t len;
     statCounter.syscalls.disk.reads++;
-    diskdstate->flags.reading = 0;
-    debug(79, 3) ("storeDiskdReadDone: dirno %d, fileno %08x status %d\n",
-       sio->swap_dirn, sio->swap_filen, M->status);
+    debug(79, 3) ("DiskdFile::readDone: status %d\n", M->status);
+
     if (M->status < 0) {
        diskd_stats.read.fail++;
-       storeDiskdIOCallback(sio, DISK_ERROR);
+       errorOccured = true;
+       ioRequestor->readCompleted(NULL, -1, DISK_ERROR);
        return;
     }
     diskd_stats.read.success++;
-    sbuf = diskdinfo->shm.buf + M->shm_offset;
-    len = M->status;
-    sio->offset += len;
+
+    ioRequestor->readCompleted (IO->shm.buf + M->shm_offset,  M->status, DISK_OK);
+}
+
+void
+diskdstate_t::readCompleted(const char *buf, int len, int errflag)
+{
+    reading = false;
+    debug(79, 3) ("storeDiskdReadDone: dirno %d, fileno %08x len %d\n",
+       swap_dirn, swap_filen, len);
+    if (len > 0)
+       offset_ += len;
+
+    STRCB *callback = read.callback;
     assert(callback);
-    sio->read.callback = NULL;
-    if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata)) {
-       assert(!diskdstate->flags.close_request);
+    read.callback = NULL;
+    void *cbdata;
+    if (cbdataReferenceValidDone(read.callback_data, &cbdata)) {
+       assert (!closing);
        /*
         * Only copy the data if the callback is still valid,
         * if it isn't valid then the request should have been
         * aborted.
         *   -- adrian
         */
-       xmemcpy(their_buf, sbuf, len);  /* yucky copy */
-       callback(cbdata, their_buf, len);
+       if (len > 0 && read_buf != buf)
+           memcpy(read_buf, buf, len);
+       callback(cbdata, read_buf, len);
     }
 }
 
-static void
-storeDiskdWriteDone(diomsg * M)
+void
+diskdstate_t::writeCompleted(int errflag, size_t len)
 {
-    storeIOState *sio = (storeIOState *)M->callback_data;
-    diskdstate_t *diskdstate = (diskdstate_t *)sio->fsstate;
-    statCounter.syscalls.disk.writes++;
-    diskdstate->flags.writing = 0;
+    writing = false;
     debug(79, 3) ("storeDiskdWriteDone: dirno %d, fileno %08x status %d\n",
-       sio->swap_dirn, sio->swap_filen, M->status);
+       swap_dirn, swap_filen, len);
+    offset_ += len;
+    if (errflag)
+       doCallback(DISK_ERROR);
+}
+
+void
+DiskdFile::writeDone(diomsg *M)
+{
+    statCounter.syscalls.disk.writes++;
+    debug(79, 3) ("storeDiskdWriteDone: status %d\n", M->status);
     if (M->status < 0) {
+       errorOccured = true;
        diskd_stats.write.fail++;
-       storeDiskdIOCallback(sio, DISK_ERROR);
+       ioRequestor->writeCompleted (DISK_ERROR,0);
        return;
     }
     diskd_stats.write.success++;
-    sio->offset += M->status;
+    ioRequestor->writeCompleted (DISK_OK,M->status);
 }
 
 static void
@@ -404,19 +647,25 @@ storeDiskdUnlinkDone(diomsg * M)
 void
 storeDiskdHandle(diomsg * M)
 {
-    if (cbdataReferenceValid(M->callback_data)) {
-       switch (M->mtype) {
+    if (!cbdataReferenceValid (M->callback_data)) {
+       debug(79, 3) ("storeDiskdHandle: Invalid callback_data %p\n",
+           M->callback_data);
+       cbdataReferenceDone (M->callback_data);
+       return;
+    }
+    
+
+    if (M->newstyle) {
+       DiskdFile *theFile = (DiskdFile *)M->callback_data;
+       theFile->completed (M);
+    } else 
+    switch (M->mtype) {
        case _MQD_OPEN:
-           storeDiskdOpenDone(M);
-           break;
+       case _MQD_CREATE:
        case _MQD_CLOSE:
-           storeDiskdCloseDone(M);
-           break;
        case _MQD_READ:
-           storeDiskdReadDone(M);
-           break;
        case _MQD_WRITE:
-           storeDiskdWriteDone(M);
+           assert (0);
            break;
        case _MQD_UNLINK:
            storeDiskdUnlinkDone(M);
@@ -425,66 +674,53 @@ storeDiskdHandle(diomsg * M)
            assert(0);
            break;
        }
-    } else {
-       debug(79, 3) ("storeDiskdHandle: Invalid callback_data %p\n",
-           M->callback_data);
-       /*
-        * The read operation has its own callback.  If we don't
-        * call storeDiskdReadDone(), then we must make sure the
-        * callback_data gets unlocked!
-        */
-       if (_MQD_READ == M->mtype) {
-           /* XXX This cannot be the correct approach. This
-            * is most likely the wrong place for this. It should
-            * be done before the sio becomes invalid, not here.
-            */
-           storeIOState *sio = (storeIOState *)M->callback_data;
-           cbdataReferenceDone(sio->read.callback_data);
-       }
-    }
-    cbdataReferenceDone(M->callback_data);
+    cbdataReferenceDone (M->callback_data);
 }
 
-static void
-storeDiskdIOCallback(storeIOState * sio, int errflag)
+void
+diskdstate_t::doCallback(int errflag)
 {
+    if (!this || !cbdataReferenceValid(this)) {
+       debug (79, 0) ("storeDiskdIOCallback: invalid siocb %p\n",this);
+       return;
+    }
     void *cbdata;
-    STIOCB *callback = sio->callback;
+    STIOCB *theCallback = callback;
     debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag);
-    sio->callback = NULL;
-    if (cbdataReferenceValidDone(sio->callback_data, &cbdata))
-       callback(cbdata, errflag, sio);
-    cbdataFree(sio);
+    callback = NULL;
+    if (cbdataReferenceValidDone(callback_data, &cbdata) && theCallback)
+       theCallback(cbdata, errflag, this);
 }
 
-static int
-storeDiskdSend(int mtype, SwapDir * sd, int id, storeIOState * sio, int size, int offset, off_t shm_offset)
+int
+storeDiskdSend(int mtype, DiskdIO *IO, int id, DiskdFile *theFile, int size, int offset, off_t shm_offset)
 {
     int x;
     diomsg M;
     static int send_errors = 0;
     static int last_seq_no = 0;
     static int seq_no = 0;
-    diskdinfo_t *diskdinfo = (diskdinfo_t *)sd->fsdata;
     M.mtype = mtype;
-    M.callback_data = cbdataReference(sio);
+    M.callback_data = cbdataReference(theFile);
     M.size = size;
     M.offset = offset;
     M.status = -1;
     M.shm_offset = (int) shm_offset;
     M.id = id;
     M.seq_no = ++seq_no;
+    M.newstyle = true;
     if (M.seq_no < last_seq_no)
        debug(79, 1) ("WARNING: sequencing out of order\n");
-    x = msgsnd(diskdinfo->smsgid, &M, msg_snd_rcv_sz, IPC_NOWAIT);
+    x = msgsnd(IO->smsgid, &M, msg_snd_rcv_sz, IPC_NOWAIT);
     last_seq_no = M.seq_no;
     if (0 == x) {
        diskd_stats.sent_count++;
-       diskdinfo->away++;
+       IO->away++;
     } else {
        debug(79, 1) ("storeDiskdSend: msgsnd: %s\n", xstrerror());
        cbdataReferenceDone(M.callback_data);
        assert(++send_errors < 100);
+       IO->shm.put (shm_offset);
     }
     /*
      * We have to drain the queue here if necessary.  If we don't,
@@ -497,7 +733,7 @@ storeDiskdSend(int mtype, SwapDir * sd, int id, storeIOState * sio, int size, in
      * we're "blocking" on this SD we can also handle callbacks
      * from other SDs that might be ready.
      */
-    while (diskdinfo->away > diskdinfo->magic2) {
+    while (IO->away > IO->magic2) {
        struct timeval delay =
        {0, 1};
        select(0, NULL, NULL, NULL, &delay);
@@ -508,13 +744,55 @@ storeDiskdSend(int mtype, SwapDir * sd, int id, storeIOState * sio, int size, in
     return x;
 }
 
-
-/*
- * We can't pass memFree() as a free function here, because we need to free
- * the fsstate variable ..
- */
-static void
-storeDiskdIOFreeEntry(void *sio)
+static int
+storeDiskdSend(int mtype, DiskdIO *IO, int id, StoreIOState::Pointer sio, int size, int offset, off_t shm_offset)
 {
-    memPoolFree(diskd_state_pool, ((storeIOState *) sio)->fsstate);
+    int x;
+    diomsg M;
+    static int send_errors = 0;
+    static int last_seq_no = 0;
+    static int seq_no = 0;
+    M.mtype = mtype;
+    M.callback_data = cbdataReference(sio.getRaw());
+    M.size = size;
+    M.offset = offset;
+    M.status = -1;
+    M.shm_offset = (int) shm_offset;
+    M.id = id;
+    M.seq_no = ++seq_no;
+    M.newstyle = false;
+    if (M.seq_no < last_seq_no)
+       debug(79, 1) ("WARNING: sequencing out of order\n");
+    x = msgsnd(IO->smsgid, &M, msg_snd_rcv_sz, IPC_NOWAIT);
+    last_seq_no = M.seq_no;
+    if (0 == x) {
+       diskd_stats.sent_count++;
+       IO->away++;
+    } else {
+       debug(79, 1) ("storeDiskdSend: msgsnd: %s\n", xstrerror());
+       cbdataReferenceDone(M.callback_data);
+       assert(++send_errors < 100);
+    }
+    /*
+     * We have to drain the queue here if necessary.  If we don't,
+     * then we can have a lot of messages in the queue (probably
+     * up to 2*magic1) and we can run out of shared memory buffers.
+     */
+    /*
+     * Note that we call storeDirCallback (for all SDs), rather
+     * than storeDiskdDirCallback for just this SD, so that while
+     * we're "blocking" on this SD we can also handle callbacks
+     * from other SDs that might be ready.
+     */
+    while (IO->away > IO->magic2) {
+       struct timeval delay =
+       {0, 1};
+       select(0, NULL, NULL, NULL, &delay);
+       storeDirCallback();
+       if (delay.tv_usec < 1000000)
+           delay.tv_usec <<= 1;
+    }
+    return x;
 }
+
+
index 15e68a8ebefcf20478e1d7612379ab60fe31445b..2708215b37324571da5f0410e89ef9bc5ce2c95b 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_null.cc,v 1.3 2002/04/16 22:43:05 wessels Exp $
+ * $Id: store_null.cc,v 1.4 2002/12/27 10:26:38 robertc Exp $
  *
  * DEBUG: section 47    Store Directory Routines
  * AUTHOR: Duane Wessels
 #include <sys/statvfs.h>
 #endif
 #endif
+#include "SwapDir.h"
+#include "Store.h"
+
+class NullSwapDir : public SwapDir 
+{
+public:
+    virtual void init();
+    virtual int canStore(StoreEntry const &)const;
+    virtual StoreIOState::Pointer createStoreIO(StoreEntry &, STFNCB *, STIOCB *, void *);
+    virtual StoreIOState::Pointer openStoreIO(StoreEntry &, STFNCB *, STIOCB *, void *);
+    virtual void parse(int, char*);
+    virtual void reconfigure (int, char *);
+};
 
 static int null_initialised = 0;
-static void storeNullDirInit(SwapDir * sd);
-static void storeNullDirStats(SwapDir * SD, StoreEntry * sentry);
-static STCHECKOBJ storeNullDirCheckObj;
-static STFSRECONFIGURE storeNullDirReconfigure;
-static STLOGCLEANSTART storeNullDirWriteCleanStart;
-static STLOGCLEANDONE storeNullDirWriteCleanDone;
 static EVH storeNullDirRebuildComplete;
 
 /* The only externally visible interface */
 STSETUP storeFsSetup_null;
 
-static void
-storeNullDirReconfigure(SwapDir * sd, int index, char *path)
+void
+NullSwapDir::reconfigure(int index, char *path)
 {
     (void) 0;
 }
@@ -64,20 +71,35 @@ storeNullDirDone(void)
     null_initialised = 0;
 }
 
-static void
-storeNullDirStats(SwapDir * SD, StoreEntry * sentry)
+static SwapDir *
+storeNullNew(void)
 {
-    (void) 0;
+    SwapDir *result = new NullSwapDir;
+    return result;
 }
 
-static void
-storeNullDirInit(SwapDir * sd)
+void
+NullSwapDir::init()
 {
     store_dirs_rebuilding++;
     eventAdd("storeNullDirRebuildComplete", storeNullDirRebuildComplete,
        NULL, 0.0, 1);
 }
 
+StoreIOState::Pointer
+NullSwapDir::createStoreIO(StoreEntry &, STFNCB *, STIOCB *, void *)
+{
+    fatal ("Attempt to get a StoreIO from the NULL store!\n");
+    return NULL;
+}
+
+StoreIOState::Pointer
+NullSwapDir::openStoreIO(StoreEntry &, STFNCB *, STIOCB *, void *)
+{
+    fatal ("Attempt to get a StoreIO from the NULL store!\n");
+    return NULL;
+}
+
 static void
 storeNullDirRebuildComplete(void *unused)
 {
@@ -87,35 +109,18 @@ storeNullDirRebuildComplete(void *unused)
     storeRebuildComplete(&counts);
 }
 
-static int
-storeNullDirCheckObj(SwapDir * SD, const StoreEntry * e)
+int
+NullSwapDir::canStore(StoreEntry const &)const
 {
     return -1;
 }
 
-static int
-storeNullDirWriteCleanStart(SwapDir * unused)
-{
-    return 0;
-}
-
-static void
-storeNullDirWriteCleanDone(SwapDir * unused)
-{
-    (void) 0;
-}
-
-static void
-storeNullDirParse(SwapDir * sd, int index, char *path)
+void
+NullSwapDir::parse(int anIndex, char *aPath)
 {
-    sd->index = index;
-    sd->path = xstrdup(path);
-    sd->statfs = storeNullDirStats;
-    sd->init = storeNullDirInit;
-    sd->checkobj = storeNullDirCheckObj;
-    sd->log.clean.start = storeNullDirWriteCleanStart;
-    sd->log.clean.done = storeNullDirWriteCleanDone;
-    parse_cachedir_options(sd, NULL, 0);
+    index = anIndex;
+    path = xstrdup(aPath);
+    parse_cachedir_options(this, NULL, 0);
 }
 
 /* Setup and register the store module */
@@ -124,8 +129,7 @@ void
 storeFsSetup_null(storefs_entry_t * storefs)
 {
     assert(!null_initialised);
-    storefs->parsefunc = storeNullDirParse;
-    storefs->reconfigurefunc = storeNullDirReconfigure;
     storefs->donefunc = storeNullDirDone;
+    storefs->newfunc = storeNullNew;
     null_initialised = 1;
 }
index 74dd6c28d9c7ed18ead78c973ad012f4d95bb364..af94ce50066a9b6d171074db5da563007e1c1e0e 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_dir_ufs.cc,v 1.51 2002/10/13 20:35:27 robertc Exp $
+ * $Id: store_dir_ufs.cc,v 1.52 2002/12/27 10:26:39 robertc Exp $
  *
  * DEBUG: section 47    Store Directory Routines
  * AUTHOR: Duane Wessels
 #include "store_ufs.h"
 #include "ufscommon.h"
 
-MemPool *ufs_state_pool = NULL;
+#include "SwapDir.h"
 static int ufs_initialised = 0;
 
-static STDUMP storeUfsDirDump;
-static STCHECKOBJ storeUfsDirCheckObj;
-static void storeUfsDirIOUnlinkFile(char *path);
+int UFSSwapDir::NumberOfUFSDirs = 0;
+int *UFSSwapDir::UFSDirToGlobalDirMapping = NULL;
 
 STSETUP storeFsSetup_ufs;
 
@@ -56,14 +55,14 @@ STSETUP storeFsSetup_ufs;
  * happily store anything as long as the LRU time isn't too small.
  */
 int
-storeUfsDirCheckObj(SwapDir * SD, const StoreEntry * e)
+UfsSwapDir::canStore(StoreEntry const &e)const
 {
     /* Return 999 (99.9%) constant load */
     return 999;
 }
 
 void
-storeUfsDirIOUnlinkFile(char *path)
+UfsSwapDir::unlinkFile(char const *path)
 {
 #if USE_UNLINKD
     unlinkdUnlink(path);
@@ -90,44 +89,45 @@ static struct cache_dir_option options[] =
  *
  * This routine is called when the given swapdir needs reconfiguring 
  */
-static void
-storeUfsDirReconfigure(SwapDir * sd, int index, char *path)
+void
+UfsSwapDir::reconfigure(int anIndex, char *aPath)
+{
+    UFSSwapDir::reconfigure (anIndex, aPath);
+    parse_cachedir_options(this, options, 1);
+}
+
+void
+UFSSwapDir::reconfigure(int index, char *path)
 {
     int i;
     int size;
-    int l1;
-    int l2;
 
     i = GetInteger();
     size = i << 10;            /* Mbytes to kbytes */
     if (size <= 0)
-       fatal("storeUfsDirReconfigure: invalid size value");
-    i = GetInteger();
-    l1 = i;
+       fatal("storeDiskdDirReconfigure: invalid size value");
+    l1 = GetInteger();
     if (l1 <= 0)
-       fatal("storeUfsDirReconfigure: invalid level 1 directories value");
-    i = GetInteger();
-    l2 = i;
+       fatal("storeDiskdDirReconfigure: invalid level 1 directories value");
+    l2 = GetInteger();
     if (l2 <= 0)
-       fatal("storeUfsDirReconfigure: invalid level 2 directories value");
+       fatal("storeDiskdDirReconfigure: invalid level 2 directories value");
 
     /* just reconfigure it */
-    if (size == sd->max_size)
+    if (size == max_size)
        debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n",
            path, size);
     else
        debug(3, 1) ("Cache dir '%s' size changed to %d KB\n",
            path, size);
-    sd->max_size = size;
-
-    parse_cachedir_options(sd, options, 1);
+    max_size = size;
 }
 
 void
-storeUfsDirDump(StoreEntry * entry, SwapDir * s)
+UfsSwapDir::dump(StoreEntry & entry)const
 {
-    commonUfsDirDump (entry, s);
-    dump_cachedir_options(entry, options, s);
+    UFSSwapDir::dump (entry);
+    dump_cachedir_options(&entry, options, this);
 }
 
 /*
@@ -135,90 +135,1063 @@ storeUfsDirDump(StoreEntry * entry, SwapDir * s)
  *
  * Called when a *new* fs is being setup.
  */
-static void
-storeUfsDirParse(SwapDir * sd, int index, char *path)
+void
+UfsSwapDir::parse(int anIndex, char *aPath)
 {
-    int i;
-    int size;
-    int l1;
-    int l2;
-    squidufsinfo_t *ufsinfo;
+    UFSSwapDir::parse (anIndex, aPath);
 
-    i = GetInteger();
-    size = i << 10;            /* Mbytes to kbytes */
-    if (size <= 0)
-       fatal("storeUfsDirParse: invalid size value");
-    i = GetInteger();
-    l1 = i;
+    parse_cachedir_options(this, options, 1);
+}
+
+void
+UFSSwapDir::parse (int anIndex, char *aPath)
+{
+    max_size = GetInteger() << 10;             /* Mbytes to kbytes */
+    if (max_size <= 0)
+       fatal("storeAufsDirParse: invalid size value");
+    l1 = GetInteger();
     if (l1 <= 0)
-       fatal("storeUfsDirParse: invalid level 1 directories value");
-    i = GetInteger();
-    l2 = i;
+       fatal("storeAufsDirParse: invalid level 1 directories value");
+    l2 = GetInteger();
     if (l2 <= 0)
-       fatal("storeUfsDirParse: invalid level 2 directories value");
-
-    ufsinfo = (squidufsinfo_t *)xmalloc(sizeof(squidufsinfo_t));
-    if (ufsinfo == NULL)
-       fatal("storeUfsDirParse: couldn't xmalloc() squidufsinfo_t!\n");
-
-    sd->index = index;
-    sd->path = xstrdup(path);
-    sd->max_size = size;
-    sd->fsdata = ufsinfo;
-    ufsinfo->l1 = l1;
-    ufsinfo->l2 = l2;
-    ufsinfo->swaplog_fd = -1;
-    ufsinfo->map = NULL;       /* Debugging purposes */
-    ufsinfo->suggest = 0;
-    ufsinfo->io.storeDirUnlinkFile = storeUfsDirIOUnlinkFile;
-    sd->init = commonUfsDirInit;
-    sd->newfs = commonUfsDirNewfs;
-    sd->dump = storeUfsDirDump;
-    sd->freefs = commonUfsDirFree;
-    sd->dblcheck = commonUfsCleanupDoubleCheck;
-    sd->statfs = commonUfsDirStats;
-    sd->maintainfs = commonUfsDirMaintain;
-    sd->checkobj = storeUfsDirCheckObj;
-    sd->refobj = commonUfsDirRefObj;
-    sd->unrefobj = commonUfsDirUnrefObj;
-    sd->callback = NULL;
-    sd->sync = NULL;
-    sd->obj.create = storeUfsCreate;
-    sd->obj.open = storeUfsOpen;
-    sd->obj.close = storeUfsClose;
-    sd->obj.read = storeUfsRead;
-    sd->obj.write = storeUfsWrite;
-    sd->obj.unlink = storeUfsUnlink;
-    sd->log.open = commonUfsDirOpenSwapLog;
-    sd->log.close = commonUfsDirCloseSwapLog;
-    sd->log.write = commonUfsDirSwapLog;
-    sd->log.clean.start = commonUfsDirWriteCleanStart;
-    sd->log.clean.nextentry = commonUfsDirCleanLogNextEntry;
-    sd->log.clean.done = commonUfsDirWriteCleanDone;
-
-    parse_cachedir_options(sd, options, 1);
+       fatal("storeAufsDirParse: invalid level 2 directories value");
+
+    index = anIndex;
+    path = xstrdup(aPath);
 
     /* Initialise replacement policy stuff */
-    sd->repl = createRemovalPolicy(Config.replPolicy);
+    repl = createRemovalPolicy(Config.replPolicy);
 }
 
 /*
  * Initial setup / end destruction
  */
+void
+UFSSwapDir::init()
+{
+    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.";
+    initBitmap();
+    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::newFileSystem()
+{
+    debug(47, 3) ("Creating swap space in %s\n", path);
+    createDirectory(path, 0);
+    createSwapSubDirs();
+}
+
+UFSSwapDir::UFSSwapDir() : IO(NULL), map(NULL), suggest(0), swaplog_fd (-1) {}
+
+UFSSwapDir::~UFSSwapDir()
+{
+    if (swaplog_fd > -1) {
+       file_close(swaplog_fd);
+       swaplog_fd = -1;
+    }
+    filemapFreeMemory(map);
+    if (IO)
+       IO->deleteSelf();
+    IO = NULL;
+}
+
 static void
 storeUfsDirDone(void)
 {
-    memPoolDestroy(&ufs_state_pool);
     ufs_initialised = 0;
 }
 
+static SwapDir *
+storeUfsNew(void)
+{
+    UfsSwapDir *result = new UfsSwapDir;
+    result->IO = &UfsIO::Instance;
+    return result;
+}
+
 void
 storeFsSetup_ufs(storefs_entry_t * storefs)
 {
     assert(!ufs_initialised);
-    storefs->parsefunc = storeUfsDirParse;
-    storefs->reconfigurefunc = storeUfsDirReconfigure;
     storefs->donefunc = storeUfsDirDone;
-    ufs_state_pool = memPoolCreate("UFS IO State data", sizeof(ufsstate_t));
+    storefs->newfunc = storeUfsNew;
     ufs_initialised = 1;
 }
+
+void
+UFSSwapDir::dumpEntry(StoreEntry &e) const
+{
+    debug(47, 0) ("UFSSwapDir::dumpEntry: FILENO %08X\n", e.swap_filen);
+    debug(47, 0) ("UFSSwapDir::dumpEntry: PATH %s\n",
+       fullPath(e.swap_filen, NULL));
+    storeEntryDump(&e, 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) {
+       debug(47, 0) ("UFSSwapDir::doubleCheck: MISSING SWAP FILE\n");
+       dumpEntry(e);
+       return true;
+    }
+    if ((off_t)e.swap_file_sz != sb.st_size) {
+       debug(47, 0) ("UFSSwapDir::doubleCheck: SIZE MISMATCH\n");
+       debug(47, 0) ("UFSSwapDir::doubleCheck: ENTRY SIZE: %ld, FILE SIZE: %ld\n",
+           (long int) e.swap_file_sz, (long int) 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: %d KB\n", max_size);
+    storeAppendPrintf(&sentry, "Current Size: %d KB\n", cur_size);
+    storeAppendPrintf(&sentry, "Percent Used: %0.2f%%\n",
+       100.0 * cur_size / max_size);
+    storeAppendPrintf(&sentry, "Filemap bits in use: %d of %d (%d%%)\n",
+       map->n_files_in_map, map->max_n_files,
+       percent(map->n_files_in_map, map->max_n_files));
+    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,
+           percent(totl_kb - free_kb, totl_kb));
+       storeAppendPrintf(&sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n",
+           totl_in - free_in,
+           totl_in,
+           percent(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");
+}
+
+void
+UFSSwapDir::maintainfs()
+{
+    StoreEntry *e = NULL;
+    int removed = 0;
+    int max_scan;
+    int max_remove;
+    double f;
+    RemovalPurgeWalker *walker;
+    /* We can't delete objects while rebuilding swap */
+    if (store_dirs_rebuilding) {
+       return;
+    } else {
+       f = (double) (cur_size - low_size) / (max_size - low_size);
+       f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f;
+       max_scan = (int) (f * 400.0 + 100.0);
+       max_remove = (int) (f * 70.0 + 10.0);
+       /*
+        * This is kinda cheap, but so we need this priority hack?
+        */
+    }
+    debug(47, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n",
+       f, max_scan, max_remove);
+    walker = repl->PurgeInit(repl, max_scan);
+    while (1) {
+       if (cur_size < low_size)
+           break;
+       if (removed >= max_remove)
+           break;
+       e = walker->Next(walker);
+       if (!e)
+           break;              /* no more objects */
+       removed++;
+       storeRelease(e);
+    }
+    walker->Done(walker);
+    debug(47, (removed ? 2 : 3)) ("UFSSwapDir::maintainfs: %s removed %d/%d f=%.03f max_scan=%d\n",
+       path, removed, max_remove, f, 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)
+{
+    debug(47, 3) ("UFSSwapDir::reference: referencing %p %d/%d\n", &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.
+ */
+void
+UFSSwapDir::dereference(StoreEntry & e)
+{
+    debug(47, 3) ("UFSSwapDir::dereference: referencing %p %d/%d\n", &e, e.swap_dirn,
+       e.swap_filen);
+    if (repl->Dereferenced)
+       repl->Dereferenced(repl, &e, &e.repl);
+}
+
+StoreIOState::Pointer
+UFSSwapDir::createStoreIO(StoreEntry &e, STFNCB * file_callback, STIOCB * callback, void *callback_data)
+{
+    return IO->create (this, &e, file_callback, callback, callback_data);
+}
+
+StoreIOState::Pointer
+UFSSwapDir::openStoreIO(StoreEntry &e, STFNCB * file_callback, STIOCB * callback, void *callback_data)
+{
+    return IO->open (this, &e, file_callback, callback, callback_data);
+}
+
+int
+UFSSwapDir::mapBitTest(sfileno filn)
+{
+    return file_map_bit_test(map, filn);
+}
+
+void
+UFSSwapDir::mapBitSet(sfileno filn)
+{
+    file_map_bit_set(map, filn);
+}
+
+void
+UFSSwapDir::mapBitReset(sfileno filn)
+{
+    /*
+     * We have to test the bit before calling file_map_bit_reset.
+     * file_map_bit_reset doesn't do bounds checking.  It 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 (file_map_bit_test(map, filn))
+       file_map_bit_reset(map, filn);
+}
+
+int
+UFSSwapDir::mapBitAllocate()
+{
+    int fn;
+    fn = file_map_allocate(map, suggest);
+    file_map_bit_set(map, fn);
+    suggest = fn + 1;
+    return fn;
+}
+
+/*
+ * Initialise the asyncufs bitmap
+ *
+ * If there already is a bitmap, and the numobjects is larger than currently
+ * configured, we allocate a new bitmap and 'grow' the old one into it.
+ */
+void
+UFSSwapDir::initBitmap()
+{
+    if (map == NULL) {
+       /* First time */
+       map = file_map_create();
+    } else if (map->max_n_files) {
+       /* it grew, need to expand */
+       /* XXX We don't need it anymore .. */
+    }
+    /* else it shrunk, and we leave the old one in place */
+}
+
+char *
+UFSSwapDir::swapSubDir(int subdirn)const
+{
+    LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
+    assert(0 <= subdirn && subdirn < l1);
+    snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%02X", path, subdirn);
+    return fullfilename;
+}
+
+int
+UFSSwapDir::createDirectory(const char *path, int should_exist)
+{
+    int created = 0;
+    struct stat st;
+    getCurrentTime();
+    if (0 == stat(path, &st)) {
+       if (S_ISDIR(st.st_mode)) {
+           debug(47, should_exist ? 3 : 1) ("%s exists\n", path);
+       } else {
+           fatalf("Swap directory %s is not a directory.", path);
+       }
+#ifdef _SQUID_MSWIN_
+    } else if (0 == mkdir(path)) {
+#else
+    } else if (0 == mkdir(path, 0755)) {
+#endif
+       debug(47, should_exist ? 1 : 3) ("%s created\n", path);
+       created = 1;
+    } else {
+       fatalf("Failed to make swap directory %s: %s",
+           path, xstrerror());
+    }
+    return created;
+}
+
+bool
+UFSSwapDir::pathIsDirectory(const char *path)const
+{
+    struct stat sb;
+    if (stat(path, &sb) < 0) {
+       debug(47, 0) ("%s: %s\n", path, xstrerror());
+       return false;
+    }
+    if (S_ISDIR(sb.st_mode) == 0) {
+       debug(47, 0) ("%s is not a directory\n", path);
+       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()
+{
+    int i, k;
+    int should_exist;
+    LOCAL_ARRAY(char, name, MAXPATHLEN);
+    for (i = 0; i < l1; i++) {
+       snprintf(name, MAXPATHLEN, "%s/%02X", path, i);
+       if (createDirectory(name, 0))
+           should_exist = 0;
+       else
+           should_exist = 1;
+       debug(47, 1) ("Making directories in %s\n", name);
+       for (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, SQUID_MAXPATHLEN);
+    LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN);
+    LOCAL_ARRAY(char, digit, 32);
+    char *pathtmp2;
+    if (Config.Log.swap) {
+       xstrncpy(pathtmp, path, SQUID_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, SQUID_MAXPATHLEN - 64, Config.Log.swap, pathtmp2);
+       if (strncmp(lpath, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) {
+           strcat(lpath, ".");
+           snprintf(digit, 32, "%02d", index);
+           strncat(lpath, digit, 3);
+       }
+    } else {
+       xstrncpy(lpath, path, SQUID_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) {
+       debug(50, 1) ("%s: %s\n", logPath, xstrerror());
+       fatal("commonUfsDirOpenSwapLog: Failed to open swap log.");
+    }
+    debug(50, 3) ("Cache Dir #%d log opened on FD %d\n", index, 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);
+    debug(47, 3) ("Cache Dir #%d log closed on FD %d\n",
+       index, 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,
+    size_t swap_file_sz,
+    time_t expires,
+    time_t timestamp,
+    time_t lastref,
+    time_t lastmod,
+    u_int32_t refcount,
+    u_int16_t flags,
+    int clean)
+{
+    StoreEntry *e = NULL;
+    debug(47, 5) ("commonUfsAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number);
+    /* if you call this you'd better be sure file_number is not 
+     * already in use! */
+    e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL);
+    e->store_status = STORE_OK;
+    storeSetMemStatus(e, 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 = flags;
+    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);
+    storeHashInsert(e, key);   /* do it after we clear KEY_PRIVATE */
+    replacementAdd (e);
+    return e;
+}
+
+void
+UFSSwapDir::rebuild()
+{
+    int clean = 0;
+    int zero = 0;
+    FILE *fp;
+    EVH *func = NULL;
+    RebuildState *rb = new RebuildState;
+    rb->sd = this;
+    rb->speed = opt_foreground_rebuild ? 1 << 30 : 50;
+    /*
+     * 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.
+     */
+    fp = openTmpSwapLog(&clean, &zero);
+    if (fp == NULL || zero) {
+       if (fp != NULL)
+           fclose(fp);
+       func = RebuildState::RebuildFromDirectory;
+    } else {
+       func = RebuildState::RebuildFromSwapLog;
+       rb->log = fp;
+       rb->flags.clean = (unsigned int) clean;
+    }
+    if (!clean)
+       rb->flags.need_to_validate = 1;
+    debug(47, 1) ("Rebuilding storage in %s (%s)\n",
+       path, clean ? "CLEAN" : "DIRTY");
+    store_dirs_rebuilding++;
+    eventAdd("storeRebuild", func, rb, 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 defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_)
+    if (unlink(swaplog_path) < 0) {
+       debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror());
+       fatal("commonUfsDirCloseTmpSwapLog: unlink failed");
+    }
+#endif
+    if (xrename(new_path, swaplog_path) < 0) {
+       fatal("commonUfsDirCloseTmpSwapLog: rename failed");
+    }
+    fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY);
+    if (fd < 0) {
+       debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror());
+       fatal("commonUfsDirCloseTmpSwapLog: Failed to open swap log.");
+    }
+    safe_free(swaplog_path);
+    safe_free(new_path);
+    swaplog_fd = fd;
+    debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", index, 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) {
+       debug(47, 1) ("Cache Dir #%d: No log file\n", index);
+       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) {
+       debug(50, 1) ("%s: %s\n", new_path, xstrerror());
+       fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
+    }
+    swaplog_fd = fd;
+    /* open a read-only stream of the old log */
+    fp = fopen(swaplog_path, "rb");
+    if (fp == NULL) {
+       debug(50, 0) ("%s: %s\n", 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
+
+/*
+ * 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.
+ */
+
+UFSCleanLog::UFSCleanLog(SwapDir *aSwapDir) : cur(NULL),newLog(NULL),cln(NULL),outbuf(NULL),
+  outbuf_offset(0), fd(-1),walker(NULL), sd(aSwapDir)
+{
+}
+
+int
+UFSSwapDir::writeCleanStart()
+{
+    UFSCleanLog *state = new UFSCleanLog(this);
+#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;
+    state->walker = repl->WalkInit(repl);
+    ::unlink(state->cln);
+    debug(47, 3) ("storeDirWriteCleanLogs: opened %s, FD %d\n",
+       state->newLog, 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);
+    memset(&s, '\0', ss);
+    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;
+    xmemcpy(&s.key, e.key, MD5_DIGEST_CHARS);
+    UFSCleanLog *state = this;
+    xmemcpy(state->outbuf + state->outbuf_offset, &s, ss);
+    state->outbuf_offset += ss;
+    /* buffered write */
+    if (state->outbuf_offset + ss > CLEAN_BUF_SZ) {
+       if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) {
+           debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
+               state->newLog, xstrerror());
+           debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n");
+           file_close(state->fd);
+           state->fd = -1;
+           unlink(state->newLog);
+           delete state;
+           sd->cleanLog = NULL;
+           return;
+       }
+       state->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) {
+       debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
+           state->newLog, xstrerror());
+       debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile "
+           "not replaced.\n");
+       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 defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_)
+       file_close(state->fd);
+       state->fd = -1;
+       if (unlink(state->cur) < 0)
+           debug(50, 0) ("storeDirWriteCleanLogs: unlinkd failed: %s, %s\n",
+               xstrerror(), state->cur);
+#endif
+       xrename(state->newLog, state->cur);
+    }
+    /* touch a timestamp file if we're not still validating */
+    if (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
+storeSwapLogDataFree(void *s)
+{
+    memFree(s, MEM_SWAP_LOG_DATA);
+}
+
+void
+UFSSwapDir::logEntry(const StoreEntry & e, int op) const
+{
+    storeSwapLogData *s = (storeSwapLogData *)memAllocate(MEM_SWAP_LOG_DATA);
+    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;
+    xmemcpy(s->key, e.key, MD5_DIGEST_CHARS);
+    file_write(swaplog_fd,
+       -1,
+       s,
+       sizeof(storeSwapLogData),
+       NULL,
+       NULL,
+       (FREE *) storeSwapLogDataFree);
+}
+
+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 *dp = NULL;
+    struct dirent *de = NULL;
+    LOCAL_ARRAY(char, p1, MAXPATHLEN + 1);
+    LOCAL_ARRAY(char, p2, MAXPATHLEN + 1);
+#if USE_TRUNCATE
+    struct stat sb;
+#endif
+    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, SQUID_MAXPATHLEN, "%s/%02X/%02X",
+       SD->path, D1, D2);
+    debug(36, 3) ("storeDirClean: Cleaning directory %s\n", p1);
+    dp = opendir(p1);
+    if (dp == NULL) {
+       if (errno == ENOENT) {
+           debug(36, 0) ("storeDirClean: WARNING: Creating %s\n", p1);
+#ifdef _SQUID_MSWIN_
+           if (mkdir(p1) == 0)
+#else
+           if (mkdir(p1, 0777) == 0)
+#endif
+               return 0;
+       }
+       debug(50, 0) ("storeDirClean: %s: %s\n", p1, xstrerror());
+       safeunlink(p1, 1);
+       return 0;
+    }
+    while ((de = readdir(dp)) != 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;
+#if USE_TRUNCATE
+       if (!stat(de->d_name, &sb))
+           if (sb.st_size == 0)
+               continue;
+#endif
+       files[k++] = swapfileno;
+    }
+    closedir(dp);
+    if (k == 0)
+       return 0;
+    qsort(files, k, sizeof(int), rev_int_sort);
+    if (k > 10)
+       k = 10;
+    for (n = 0; n < k; n++) {
+       debug(36, 3) ("storeDirClean: Cleaning file %08X\n", files[n]);
+       snprintf(p2, MAXPATHLEN + 1, "%s/%08X", p1, files[n]);
+#if USE_TRUNCATE
+       truncate(p2, 0);
+#else
+       safeunlink(p2, 0);
+#endif
+       statCounter.swap.files_cleaned++;
+    }
+    debug(36, 3) ("Cleaned %d unused files from %s\n", k, 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++) {
+           sd = INDEXSD(i);
+           if (!UFSSwapDir::IsUFSDir(sd))
+               continue;
+           UFSSwapDir *usd = dynamic_cast<UFSSwapDir *>(sd);
+           assert (usd);
+           UFSDirToGlobalDirMapping[n++] = i;
+           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 (0 == 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 (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->max_n_files)
+           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)
+{
+    debug(79, 3) ("UFSSwapDir::unlinkFile: unlinking fileno %08X\n", f);
+    /* commonUfsDirMapBitReset(this, f); */
+    unlinkFile(fullPath(f, NULL));
+}
+
+/*
+ * Add and remove the given StoreEntry from the replacement policy in
+ * use.
+ */
+
+void
+UFSSwapDir::replacementAdd(StoreEntry * e)
+{
+    debug(47, 4) ("UFSSwapDir::replacementAdd: added node %p to dir %d\n", e,
+       index);
+    repl->Add(repl, e, &e->repl);
+}
+
+
+void
+UFSSwapDir::replacementRemove(StoreEntry * e)
+{
+    SwapDir *SD;
+    if (e->swap_dirn < 0)
+       return;
+    SD = INDEXSD(e->swap_dirn);
+    assert (dynamic_cast<UFSSwapDir *>(SD) == this);
+    debug(47, 4) ("UFSSwapDir::replacementRemove: remove node %p from dir %d\n", e,
+       index);
+    repl->Remove(repl, e, &e->repl);
+}
+
+void
+UFSSwapDir::dump(StoreEntry & entry) const
+{
+    storeAppendPrintf(&entry, " %d %d %d",
+       max_size >> 10,
+       l1,
+       l2);
+}
+
+char *
+UFSSwapDir::fullPath(sfileno filn, char *fullpath) const
+{
+    LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
+    int L1 = l1;
+    int L2 = l2;
+    if (!fullpath)
+       fullpath = fullfilename;
+    fullpath[0] = '\0';
+    snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X/%08X",
+       path,
+       ((filn / L2) / L2) % L1,
+       (filn / L2) % L2,
+       filn);
+    return fullpath;
+}
index c13ff039116554b2b1d5163df85bb8e53a8bbcc5..e53320a3a26817ec6e611c9a370cc1ea37eb2a00 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_io_ufs.cc,v 1.13 2002/10/13 20:35:27 robertc Exp $
+ * $Id: store_io_ufs.cc,v 1.14 2002/12/27 10:26:39 robertc Exp $
  *
  * DEBUG: section 79    Storage Manager UFS Interface
  * AUTHOR: Duane Wessels
 #include "Store.h"
 #include "ufscommon.h"
 
+#include "SwapDir.h"
 
-static DRCB storeUfsReadDone;
-static DWCB storeUfsWriteDone;
-static void storeUfsIOCallback(storeIOState * sio, int errflag);
-static CBDUNL storeUfsIOFreeEntry;
+UfsIO UfsIO::Instance;
+bool
+UfsIO::shedLoad()
+{
+    return false;
+}
+void
+UfsIO::deleteSelf() const
+{
+    /* Do nothing, we use a single instance */
+}
+
+StoreIOState::Pointer
+UfsIO::createState(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data) const
+{
+    return new ufsstate_t (SD, e, callback, callback_data);
+}
+
+DiskFile::Pointer 
+UfsIO::newFile (char const *path)
+{
+    return new UFSFile (path);
+}
 
-CBDATA_TYPE(storeIOState);
+CBDATA_CLASS_INIT(ufsstate_t);
 
-/* === PUBLIC =========================================================== */
+void *
+ufsstate_t::operator new (size_t)
+{
+    CBDATA_INIT_TYPE(ufsstate_t);
+    ufsstate_t *result = cbdataAlloc(ufsstate_t);
+    /* Mark result as being owned - we want the refcounter to do the delete
+     * call */
+    cbdataReference(result);
+    return result;
+}
+void
+ufsstate_t::operator delete (void *address)
+{
+    ufsstate_t *t = static_cast<ufsstate_t *>(address);
+    cbdataFree(address);
+    /* And allow the memory to be freed */
+    cbdataReferenceDone (t);
+}
+    
+ufsstate_t::ufsstate_t(SwapDir * SD, StoreEntry * anEntry, STIOCB * callback_, void *callback_data_) 
+{
+    swap_filen = anEntry->swap_filen;
+    swap_dirn = SD->index;
+    mode = O_BINARY;
+    callback = callback_;
+    callback_data = cbdataReference(callback_data_);
+    e = anEntry;
+}
 
-storeIOState *
-storeUfsOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
-    STIOCB * callback, void *callback_data)
+CBDATA_CLASS_INIT(UFSFile);
+void *
+UFSFile::operator new (size_t)
 {
-    sfileno f = e->swap_filen;
-    char *path = commonUfsDirFullPath(SD, f, NULL);
-    storeIOState *sio;
-    struct stat sb;
-    int fd;
-    debug(79, 3) ("storeUfsOpen: fileno %08X\n", f);
-    fd = file_open(path, O_RDONLY | O_BINARY);
+    CBDATA_INIT_TYPE(UFSFile);
+    UFSFile *result = cbdataAlloc(UFSFile);
+    /* Mark result as being owned - we want the refcounter to do the delete
+     * call */
+    cbdataReference(result);
+    return result;
+}
+void
+UFSFile::operator delete (void *address)
+{
+    UFSFile *t = static_cast<UFSFile *>(address);
+    cbdataFree(address);
+    /* And allow the memory to be freed */
+    cbdataReferenceDone (t);
+}
+
+void
+UFSFile::deleteSelf() const {delete this;}
+
+UFSFile::UFSFile (char const *aPath) : fd (-1)
+{
+    assert (aPath);
+    debug (79,0)("UFSFile::UFSFile: %s\n", aPath);
+    path_ = xstrdup (aPath);
+}
+
+UFSFile::~UFSFile()
+{
+    safe_free (path_);
+    doClose();
+}
+
+void
+UFSFile::open (int flags, mode_t mode, IORequestor::Pointer callback)
+{
+    /* Simulate async calls */
+    fd = file_open(path_ , flags);
+    ioRequestor = callback;
     if (fd < 0) {
-       debug(79, 3) ("storeUfsOpen: got failure (%d)\n", errno);
-       return NULL;
+       debug(79, 3) ("UFSFile::open: got failure (%d)\n", errno);
+    } else {
+       store_open_disk_fd++;
+        debug(79, 3) ("UFSFile::open: opened FD %d\n", fd);
     }
-    debug(79, 3) ("storeUfsOpen: opened FD %d\n", fd);
-    CBDATA_INIT_TYPE_FREECB(storeIOState, storeUfsIOFreeEntry);
-    sio = cbdataAlloc(storeIOState);
-    sio->fsstate = memPoolAlloc(ufs_state_pool);
-
-    sio->swap_filen = f;
-    sio->swap_dirn = SD->index;
-    sio->mode = O_RDONLY | O_BINARY;
-    sio->callback = callback;
-    sio->callback_data = cbdataReference(callback_data);
-    sio->e = e;
-    ((ufsstate_t *) (sio->fsstate))->fd = fd;
-    ((ufsstate_t *) (sio->fsstate))->flags.writing = 0;
-    ((ufsstate_t *) (sio->fsstate))->flags.reading = 0;
-    ((ufsstate_t *) (sio->fsstate))->flags.close_request = 0;
-    if (fstat(fd, &sb) == 0)
-       sio->st_size = sb.st_size;
-    store_open_disk_fd++;
-
-    /* We should update the heap/dlink position here ! */
-    return sio;
+    callback->ioCompletedNotification();
 }
 
-storeIOState *
-storeUfsCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * callback, void *callback_data)
+void
+UFSFile::create (int flags, mode_t mode, IORequestor::Pointer callback)
 {
-    storeIOState *sio;
-    int fd;
-    int mode = (O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
-    char *path;
-    squidufsinfo_t *ufsinfo = (squidufsinfo_t *) SD->fsdata;
-    sfileno filn;
-    sdirno dirn;
+    /* We use the same logic path for open */
+    open(flags, mode, callback);
+}
 
-    /* Allocate a number */
-    dirn = SD->index;
-    filn = commonUfsDirMapBitAllocate(SD);
-    ufsinfo->suggest = filn + 1;
-    /* Shouldn't we handle a 'bitmap full' error here? */
-    path = commonUfsDirFullPath(SD, filn, NULL);
 
-    debug(79, 3) ("storeUfsCreate: fileno %08X\n", filn);
-    fd = file_open(path, mode);
-    if (fd < 0) {
-       debug(79, 3) ("storeUfsCreate: got failure (%d)\n", errno);
-       return NULL;
+void UFSFile::doClose()
+{
+    if (fd > -1) {
+       file_close(fd);
+       store_open_disk_fd--;
+       fd = -1;
     }
-    debug(79, 3) ("storeUfsCreate: opened FD %d\n", fd);
-    CBDATA_INIT_TYPE_FREECB(storeIOState, storeUfsIOFreeEntry);
-    sio = cbdataAlloc(storeIOState);
-    sio->fsstate = memPoolAlloc(ufs_state_pool);
+}
 
-    sio->swap_filen = filn;
-    sio->swap_dirn = dirn;
-    sio->mode = mode;
-    sio->callback = callback;
-    sio->callback_data = cbdataReference(callback_data);
-    sio->e = (StoreEntry *) e;
-    ((ufsstate_t *) (sio->fsstate))->fd = fd;
-    ((ufsstate_t *) (sio->fsstate))->flags.writing = 0;
-    ((ufsstate_t *) (sio->fsstate))->flags.reading = 0;
-    ((ufsstate_t *) (sio->fsstate))->flags.close_request = 0;
-    store_open_disk_fd++;
+void
+UFSFile::close ()
+{
+    debug (79,0)("UFSFile::close: %p closing for %p\n", this, ioRequestor.getRaw());
+    doClose();
+    assert (ioRequestor.getRaw());
+    ioRequestor->closeCompleted();
+}
 
-    /* now insert into the replacement policy */
-    commonUfsDirReplAdd(SD, e);
-    return sio;
+bool
+UFSFile::canRead() const
+{
+    return fd > -1;
+}
+
+bool
+UFSFile::error() const
+{
+    if (fd < 0)
+       return true;
+    return false;
 }
 
 void
-storeUfsClose(SwapDir * SD, storeIOState * sio)
+ufsstate_t::ioCompletedNotification()
 {
-    ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate;
+    if (opening) {
+       opening = false;
+       /* There is no 'opened' callback */
+       return;
+    }
+    if (creating) {
+       creating = false;
+       return;
+    }
+    assert(0);
+}
 
-    debug(79, 3) ("storeUfsClose: dirno %d, fileno %08X, FD %d\n",
-       sio->swap_dirn, sio->swap_filen, ufsstate->fd);
-    if (ufsstate->flags.reading || ufsstate->flags.writing) {
-       ufsstate->flags.close_request = 1;
+void
+ufsstate_t::closeCompleted()
+{
+    doCallback(theFile->error() ? 0 : -1);
+}
+
+void
+ufsstate_t::close()
+{
+    debug(79, 3) ("storeUfsClose: dirno %d, fileno %08X\n",
+       swap_dirn, swap_filen);
+    closing = true;
+    if (!(reading || writing)) {
+        ((UFSFile *)theFile.getRaw())->close();
+    }
+}
+
+void
+UFSStoreState::read_(char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
+{
+    assert(read.callback == NULL);
+    assert(read.callback_data == NULL);
+    assert(!reading);
+    assert(!closing);
+    assert (callback);
+    if (!theFile->canRead()) {
+       debug(79, 3) ("UFSStoreState::read_: queueing read because theFile can't read\n");
+       queueRead (buf, size, offset, callback, callback_data);
        return;
     }
-    storeUfsIOCallback(sio, 0);
+    read.callback = callback;
+    read.callback_data = cbdataReference(callback_data);
+    debug(79, 3) ("UFSStoreState::read_: dirno %d, fileno %08X\n",
+       swap_dirn, swap_filen);
+    offset_ = offset;
+    read_buf = buf;
+    reading = true;
+    theFile->read(buf, offset, size);
 }
 
 void
-storeUfsRead(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
-{
-    ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate;
-
-    assert(sio->read.callback == NULL);
-    assert(sio->read.callback_data == NULL);
-    sio->read.callback = callback;
-    sio->read.callback_data = cbdataReference(callback_data);
-    debug(79, 3) ("storeUfsRead: dirno %d, fileno %08X, FD %d\n",
-       sio->swap_dirn, sio->swap_filen, ufsstate->fd);
-    sio->offset = offset;
-    ufsstate->flags.reading = 1;
-    file_read(ufsstate->fd,
-       buf,
-       size,
-       offset,
-       storeUfsReadDone,
-       sio);
+UFSFile::read(char *buf, off_t offset, size_t size)
+{
+    assert (fd > -1);
+    assert (ioRequestor.getRaw());
+    file_read(fd, buf, size, offset, ReadDone, this);
+}
+void
+UFSFile::ReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
+{
+    UFSFile *myFile = static_cast<UFSFile *>(my_data);
+    assert (myFile);
+    myFile->readDone (fd, buf, len, errflag);
 }
 
 void
-storeUfsWrite(SwapDir * SD, storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func)
+UFSFile::write(char const *buf, size_t size, off_t offset, FREE *free_func)
 {
-    ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate;
-    debug(79, 3) ("storeUfsWrite: dirn %d, fileno %08X, FD %d\n", sio->swap_dirn, sio->swap_filen, ufsstate->fd);
-    ufsstate->flags.writing = 1;
-    file_write(ufsstate->fd,
+    debug(79, 3) ("storeUfsWrite: FD %d\n",fd);
+    file_write(fd,
        offset,
-       buf,
+       (char *)buf,
        size,
-       storeUfsWriteDone,
-       sio,
+       WriteDone,
+       this,
        free_func);
 }
 
 void
-storeUfsUnlink(SwapDir * SD, StoreEntry * e)
+UFSStoreState::write(char *buf, size_t size, off_t offset, FREE * free_func)
+{
+    debug(79, 3) ("UFSStoreState::write: dirn %d, fileno %08X\n", swap_dirn, swap_filen);
+    if (!theFile->canWrite() || writing) {
+       assert(creating || writing);
+       queueWrite(buf, size, offset, free_func);
+       return;
+    }
+    writing = true;
+    theFile->write(buf,size,offset,free_func);
+}
+
+void
+UfsSwapDir::unlink(StoreEntry & e)
 {
-    debug(79, 3) ("storeUfsUnlink: fileno %08X\n", e->swap_filen);
-    commonUfsDirReplRemove(e);
-    commonUfsDirMapBitReset(SD, e->swap_filen);
-    commonUfsDirUnlinkFile(SD, e->swap_filen);
+    debug(79, 3) ("storeUfsUnlink: fileno %08X\n", e.swap_filen);
+    replacementRemove(&e);
+    mapBitReset(e.swap_filen);
+    UFSSwapDir::unlinkFile(e.swap_filen);
 }
 
 /*  === STATIC =========================================================== */
 
-static void
-storeUfsReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
+void
+UFSFile::readDone(int rvfd, const char *buf, int len, int errflag)
 {
-    storeIOState *sio = (storeIOState *)my_data;
-    ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate;
-    STRCB *callback;
-    void *cbdata;
-    ssize_t rlen;
+    debug (79,3)("UFSFile::readDone: FD %d\n",rvfd);
+    assert (fd == rvfd);
 
-    debug(79, 3) ("storeUfsReadDone: dirno %d, fileno %08X, FD %d, len %d\n",
-       sio->swap_dirn, sio->swap_filen, fd, len);
-    ufsstate->flags.reading = 0;
+    ssize_t rlen;
     if (errflag) {
-       debug(79, 3) ("storeUfsReadDone: got failure (%d)\n", errflag);
+       debug(79, 3) ("UFSFile::readDone: got failure (%d)\n", errflag);
        rlen = -1;
     } else {
        rlen = (ssize_t) len;
-       sio->offset += len;
     }
-    assert(sio->read.callback);
-    assert(sio->read.callback_data);
-    callback = sio->read.callback;
-    sio->read.callback = NULL;
-    if (cbdataReferenceValidDone(sio->read.callback_data, &cbdata))
-       callback(cbdata, buf, (size_t) rlen);
-}
-
-static void
-storeUfsWriteDone(int fd, int errflag, size_t len, void *my_data)
-{
-    storeIOState *sio = (storeIOState *)my_data;
-    ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate;
-    debug(79, 3) ("storeUfsWriteDone: dirno %d, fileno %08X, FD %d, len %ld\n",
-       sio->swap_dirn, sio->swap_filen, fd, (long int) len);
-    ufsstate->flags.writing = 0;
+    if (errflag == DISK_EOF)
+       errflag = DISK_OK;      /* EOF is signalled by len == 0, not errors... */
+    ioRequestor->readCompleted(buf, rlen, errflag);
+}
+
+void
+ufsstate_t::readCompleted(const char *buf, int len, int errflag)
+{
+
+    reading = false;
+    debug(79, 3) ("storeUfsReadDone: dirno %d, fileno %08X, len %d\n",
+       swap_dirn, swap_filen, len);
+    if (len > 0)
+       offset_ += len;
+    STRCB *callback = read.callback;
+    assert(callback);
+    read.callback = NULL;
+    void *cbdata;
+    if (!closing && cbdataReferenceValidDone(read.callback_data, &cbdata)) {
+       if (len > 0 && read_buf != buf)
+           memcpy(read_buf, buf, len);
+       callback(cbdata, read_buf, len);
+    }
+    if (closing)
+       fatal("Sync ufs doesn't support overlapped close and read calls\n");
+}
+
+void
+UFSFile::WriteDone (int fd, int errflag, size_t len, void *me)
+{
+    UFSFile *aFile = static_cast<UFSFile *>(me);
+    aFile->writeDone (fd, errflag, len);
+}
+
+void
+UFSFile::writeDone(int rvfd, int errflag, size_t len)
+{
+    assert (rvfd == fd);
+    debug(79, 3) ("storeUfsWriteDone: FD %d, len %ld\n",
+       fd, (long int) len);
     if (errflag) {
        debug(79, 0) ("storeUfsWriteDone: got failure (%d)\n", errflag);
-       storeUfsIOCallback(sio, errflag);
+       doClose();
+       ioRequestor->writeCompleted (DISK_ERROR,0);
        return;
     }
-    sio->offset += len;
-    if (ufsstate->flags.close_request)
-       storeUfsIOCallback(sio, errflag);
+    ioRequestor->writeCompleted(DISK_OK, len);
 }
 
-static void
-storeUfsIOCallback(storeIOState * sio, int errflag)
+void
+ufsstate_t::writeCompleted(int errflag, size_t len)
+{
+    debug(79, 3) ("storeUfsWriteDone: dirno %d, fileno %08X, len %ld\n",
+       swap_dirn, swap_filen, (long int) len);
+    writing = false;
+    if (theFile->error())
+       doCallback(DISK_ERROR);
+    offset_ += len;
+    if (closing)
+        ((UFSFile *)theFile.getRaw())->close();
+}
+
+void
+ufsstate_t::doCallback(int errflag)
 {
-    ufsstate_t *ufsstate = (ufsstate_t *) sio->fsstate;
-    void *cbdata;
     debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag);
-    if (ufsstate->fd > -1) {
-       file_close(ufsstate->fd);
-       store_open_disk_fd--;
-    }
-    if (cbdataReferenceValidDone(sio->callback_data, &cbdata))
-       sio->callback(cbdata, errflag, sio);
-    sio->callback = NULL;
-    cbdataFree(sio);
+    /* We are finished with the file */
+    theFile = NULL;
+    void *cbdata;
+    if (cbdataReferenceValidDone(callback_data, &cbdata))
+       callback(cbdata, errflag, this);
+    callback = NULL;
 }
 
 
 /*
  * Clean up any references from the SIO before it get's released.
  */
-static void
-storeUfsIOFreeEntry(void *sio)
+ufsstate_t::~ufsstate_t()
+{}
+
+
+
+/* ============= THE REAL UFS CODE ================ */
+
+UFSStoreState::UFSStoreState() : opening (false), creating (false), closing (false), reading(false), writing(false), pending_reads(NULL), pending_writes (NULL){}
+UFSStoreState::~UFSStoreState()
+{
+    _queued_read *qr;
+    while ((qr = (_queued_read *)linklistShift(&pending_reads))) {
+       cbdataReferenceDone(qr->callback_data);
+       delete qr;
+    }
+
+    struct _queued_write *qw;
+    while ((qw = (struct _queued_write *)linklistShift(&pending_writes))) {
+       if (qw->free_func)
+           qw->free_func(qw->buf);
+       delete qw;
+    }
+}
+
+bool
+UFSStoreState::kickReadQueue()
+{
+    _queued_read *q = (_queued_read *)linklistShift(&pending_reads);
+    if (NULL == q)
+       return false;
+    debug(79, 3) ("UFSStoreState::kickReadQueue: reading queued request of %ld bytes\n",
+       (long int) q->size);
+    void *cbdata;
+    if (cbdataReferenceValidDone(q->callback_data, &cbdata))
+       read_(q->buf, q->size, q->offset, q->callback, cbdata);
+    delete q;
+    return true;
+}
+
+MemPool * UFSStoreState::_queued_read::Pool = NULL;
+
+void *
+UFSStoreState::_queued_read::operator new(size_t size)
+{
+    if (!Pool)
+       Pool = memPoolCreate("AUFS Queued read data",sizeof (_queued_read));
+    return memPoolAlloc (Pool);
+}
+
+void
+UFSStoreState::_queued_read::operator delete (void *address)
+{
+    memPoolFree (Pool, address);
+}
+
+void
+UFSStoreState::queueRead(char *buf, size_t size, off_t offset, STRCB *callback, void *callback_data)
+{
+    debug(79, 3) ("UFSStoreState::queueRead: queueing read\n");
+    assert(opening);
+    assert (pending_reads == NULL);
+    _queued_read *q = new _queued_read;
+    q->buf = buf;
+    q->size = size;
+    q->offset = offset;
+    q->callback = callback;
+    q->callback_data = cbdataReference(callback_data);
+    linklistPush(&pending_reads, q);
+}
+
+MemPool * UFSStoreState::_queued_write::Pool = NULL;
+
+void *
+UFSStoreState::_queued_write::operator new(size_t size)
+{
+    if (!Pool)
+       Pool = memPoolCreate("AUFS Queued write data",sizeof (_queued_write));
+    return memPoolAlloc (Pool);
+}
+
+void
+UFSStoreState::_queued_write::operator delete (void *address)
+{
+    memPoolFree (Pool, address);
+}
+
+bool
+UFSStoreState::kickWriteQueue()
 {
-    memPoolFree(ufs_state_pool, ((storeIOState *) sio)->fsstate);
+    _queued_write *q = (_queued_write *)linklistShift(&pending_writes);
+    if (NULL == q)
+       return false;
+    debug(79, 3) ("storeAufsKickWriteQueue: writing queued chunk of %ld bytes\n",
+       (long int) q->size);
+    write(q->buf, q->size, q->offset, q->free_func);
+    delete q;
+    return true;
+}
+
+void
+UFSStoreState::queueWrite(char *buf, size_t size, off_t offset, FREE * free_func)
+{
+    debug(79, 3) ("UFSStoreState::queueWrite: queuing write\n");
+    struct _queued_write *q;
+    q = new _queued_write;
+    q->buf = buf;
+    q->size = size;
+    q->offset = offset;
+    q->free_func = free_func;
+    linklistPush(&pending_writes, q);
+}
+
+StoreIOState::Pointer
+UFSStrategy::open(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
+                 STIOCB * callback, void *callback_data)
+{
+    assert (((UfsSwapDir *)SD)->IO == this);
+    debug(79, 3) ("UFSStrategy::open: fileno %08X\n", e->swap_filen);
+    if (shedLoad()) {
+       openFailed();
+       return NULL;
+    }
+    /* to consider: make createstate a private UFSStrategy call */
+    StoreIOState::Pointer sio = createState (SD, e, callback, 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);
+    
+    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, STFNCB * file_callback,
+                 STIOCB * callback, void *callback_data)
+{
+    assert (((UfsSwapDir *)SD)->IO == this);
+    /* Allocate a number */
+    sfileno filn = ((UFSSwapDir *)SD)->mapBitAllocate();
+    debug(79, 3) ("UFSStrategy::create: fileno %08X\n", filn);
+    if (shedLoad()) {
+       openFailed();
+       ((UFSSwapDir *)SD)->mapBitReset (filn);
+       return NULL;
+    }
+    
+    /* Shouldn't we handle a 'bitmap full' error here? */
+
+    StoreIOState::Pointer sio = createState (SD, e, callback, 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);
+    
+    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;
 }
index 8568c00218e7151c6f277b0046ebf89b9b3b669b..210809a16ca1a9696e8be709a35f20818e6ab823 100644 (file)
@@ -7,28 +7,74 @@
 #ifndef __STORE_UFS_H__
 #define __STORE_UFS_H__
 
-struct _ufsstate_t {
+#include "ufscommon.h"
+class UFSFile : public DiskFile {
+  public:
+    void *operator new(size_t);
+    void operator delete(void *);
+    virtual void deleteSelf() const;
+    UFSFile (char const *path);
+    ~UFSFile();
+    virtual void open (int, mode_t, IORequestor::Pointer);
+    virtual void create (int, mode_t, IORequestor::Pointer);
+    virtual void read(char *, off_t, size_t);
+    virtual void write(char const *buf, size_t size, off_t offset, FREE *free_func);
+    virtual void close ();
+    virtual bool error() const;
+    virtual int getFD() const { return fd;}
+    virtual bool canRead() const;
+  private:
+    static DRCB ReadDone;
+    static DWCB WriteDone;
+    CBDATA_CLASS(UFSFile);
     int fd;
-    struct {
-       unsigned int close_request:1;
-       unsigned int reading:1;
-       unsigned int writing:1;
-    } flags;
+    char const *path_;
+    IORequestor::Pointer ioRequestor;
+    void doClose();
+    void readDone(int fd, const char *buf, int len, int errflag);
+    void writeDone(int fd, int errflag, size_t len);
 };
 
-typedef struct _ufsstate_t ufsstate_t;
+class ufsstate_t : public UFSStoreState {
+  public:
+    virtual void deleteSelf() const {delete this;}
+    void * operator new (size_t);
+    void operator delete (void *);
+    ufsstate_t(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data);
+    ~ufsstate_t();
+    void close();
+    void ioCompletedNotification();
+    void readCompleted(const char *buf, int len, int errflag);
+    void writeCompleted(int errflag, size_t len);
+    void closeCompleted();
+  private:
+    CBDATA_CLASS(ufsstate_t);
+    void doCallback (int);
+};
 
-/* The ufs_state memory pool */
-extern MemPool *ufs_state_pool;
 
+#include "SwapDir.h"
 /*
  * Store IO stuff
  */
-extern STOBJCREATE storeUfsCreate;
-extern STOBJOPEN storeUfsOpen;
-extern STOBJCLOSE storeUfsClose;
-extern STOBJREAD storeUfsRead;
-extern STOBJWRITE storeUfsWrite;
-extern STOBJUNLINK storeUfsUnlink;
+/* For things that aren't factored well yet */
+class UfsSwapDir: public UFSSwapDir {
+    virtual void dump(StoreEntry &)const;
+    virtual void unlink(StoreEntry &);
+    virtual int canStore(StoreEntry const&)const;
+    virtual void parse (int index, char *path);
+    virtual void reconfigure (int, char *);
+    virtual void unlinkFile (char const *);
+};
+
+class UfsIO : public UFSStrategy
+{
+public:
+   virtual bool shedLoad();
+   virtual void deleteSelf() const;
+   virtual StoreIOState::Pointer createState(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data) const;
+   virtual DiskFile::Pointer newFile (char const *path);
+   static UfsIO Instance;
+};
 
 #endif
index 280c3b5033c423eb6973b471a1ffcf19bd5e1387..b0e6f11921507fcf55d1ada94e518b99195869be 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.457 2002/11/15 13:29:20 hno Exp $
+ * $Id: protos.h,v 1.458 2002/12/27 10:26:33 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -103,7 +103,7 @@ SQUIDCEXTERN void parse_wordlist(wordlist ** list);
 SQUIDCEXTERN void requirePathnameExists(const char *name, const char *path);
 SQUIDCEXTERN void parse_time_t(time_t * var);
 SQUIDCEXTERN void parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int reconfiguring);
-SQUIDCEXTERN void dump_cachedir_options(StoreEntry * e, struct cache_dir_option *options, SwapDir * sd);
+SQUIDCEXTERN void dump_cachedir_options(StoreEntry * e, struct cache_dir_option *options, SwapDir const * sd);
 SQUIDCEXTERN void parse_sockaddr_in_list_token(sockaddr_in_list **, char *);
 
 
@@ -852,13 +852,12 @@ SQUIDCEXTERN void storeFsSetup(void);
 SQUIDCEXTERN void storeReplSetup(void);
 
 /* store_io.c */
-SQUIDCEXTERN storeIOState *storeCreate(StoreEntry *, STFNCB *, STIOCB *, void *);
-SQUIDCEXTERN storeIOState *storeOpen(StoreEntry *, STFNCB *, STIOCB *, void *);
-SQUIDCEXTERN void storeClose(storeIOState *);
-SQUIDCEXTERN void storeRead(storeIOState *, char *, size_t, off_t, STRCB *, void *);
-SQUIDCEXTERN void storeWrite(storeIOState *, char *, size_t, off_t, FREE *);
+SQUIDCEXTERN StoreIOState::Pointer storeCreate(StoreEntry *, STFNCB *, STIOCB *, void *);
+SQUIDCEXTERN StoreIOState::Pointer storeOpen(StoreEntry *, STFNCB *, STIOCB *, void *);
+SQUIDCEXTERN void storeClose(StoreIOState::Pointer);
+SQUIDCEXTERN void storeRead(StoreIOState::Pointer, char *, size_t, off_t, STRCB *, void *);
+SQUIDCEXTERN void storeWrite(StoreIOState::Pointer, char *, size_t, off_t, FREE *);
 SQUIDCEXTERN void storeUnlink(StoreEntry *);
-SQUIDCEXTERN off_t storeOffset(storeIOState *);
 
 /*
  * store_log.c
index a0c6b399e50986405ad4d7d000fbce1a685ed454..8a8095e5edba72f820c036230ada1a17bb5436ef 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: squid.h,v 1.227 2002/11/10 02:04:39 hno Exp $
+ * $Id: squid.h,v 1.228 2002/12/27 10:26:33 robertc Exp $
  *
  * AUTHOR: Duane Wessels
  *
@@ -412,7 +412,7 @@ extern "C" {
 /*
  * I'm sick of having to keep doing this ..
  */
-#define INDEXSD(i)   (&Config.cacheSwap.swapDirs[(i)])
+#define INDEXSD(i)   (Config.cacheSwap.swapDirs[(i)])
 
 #define FD_READ_METHOD(fd, buf, len) (*fd_table[fd].read_method)(fd, buf, len)
 #define FD_WRITE_METHOD(fd, buf, len) (*fd_table[fd].write_method)(fd, buf, len)
index 828013548380a5e69018da0d725051d900573015..975113bb60065d57c254f95de9b8c03c9cec3099 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: stat.cc,v 1.363 2002/10/25 01:00:42 adrian Exp $
+ * $Id: stat.cc,v 1.364 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 18    Cache Manager Statistics
  * AUTHOR: Harvest Derived
@@ -278,9 +278,9 @@ statStoreEntry(StoreEntry * s, StoreEntry * e)
        storeAppendPrintf(s, "\tinmem_hi: %d\n", (int) mem->inmem_hi);
        storeAppendPrintf(s, "\tswapout: %d bytes queued\n",
            (int) mem->swapout.queue_offset);
-       if (mem->swapout.sio)
+       if (mem->swapout.sio.getRaw())
            storeAppendPrintf(s, "\tswapout: %d bytes written\n",
-               (int) storeOffset(mem->swapout.sio));
+               (int) mem->swapout.sio->offset());
        for (i = 0, node = mem->clients.head; node; node = node->next, i++)
            storeClientDumpStats((store_client *)node->data, s, i);
     }
index 3ba1d0bd593ea8a8a917f0639c3ad67c6546f9d4..05c7ce772e04e7f2e67cbefe65759395f5f232fa 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store.cc,v 1.551 2002/10/15 09:25:33 robertc Exp $
+ * $Id: store.cc,v 1.552 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 20    Storage Manager
  * AUTHOR: Harvest Derived
@@ -36,6 +36,7 @@
 #include "squid.h"
 #include "Store.h"
 #include "StoreClient.h"
+#include "SwapDir.h"
 
 #define REBUILD_TIMESTAMP_DELTA_MAX 2
 
@@ -268,14 +269,9 @@ storePurgeMem(StoreEntry * e)
 static void
 storeEntryReferenced(StoreEntry * e)
 {
-    SwapDir *SD;
-
     /* Notify the fs that we're referencing this object again */
-    if (e->swap_dirn > -1) {
-       SD = INDEXSD(e->swap_dirn);
-       if (SD->refobj)
-           SD->refobj(SD, e);
-    }
+    if (e->swap_dirn > -1)
+       INDEXSD(e->swap_dirn)->reference(*e);
     /* Notify the memory cache that we're referencing this object again */
     if (e->mem_obj) {
        if (mem_policy->Referenced)
@@ -286,14 +282,9 @@ storeEntryReferenced(StoreEntry * e)
 static void
 storeEntryDereferenced(StoreEntry * e)
 {
-    SwapDir *SD;
-
     /* Notify the fs that we're not referencing this object any more */
-    if (e->swap_filen > -1) {
-       SD = INDEXSD(e->swap_dirn);
-       if (SD->unrefobj != NULL)
-           SD->unrefobj(SD, e);
-    }
+    if (e->swap_filen > -1)
+       INDEXSD(e->swap_dirn)->dereference(*e);
     /* Notify the memory cache that we're not referencing this object any more */
     if (e->mem_obj) {
        if (mem_policy->Dereferenced)
@@ -888,7 +879,6 @@ storeGetMemSpace(int size)
 /*
  * This routine is to be called by main loop in main.c.
  * It removes expired objects on only one bucket for each time called.
- * returns the number of objects removed
  *
  * This should get called 1/s from main().
  */
@@ -907,8 +897,7 @@ storeMaintainSwapSpace(void *datanotused)
        /* XXX FixMe: This should be done "in parallell" on the different
         * cache_dirs, not one at a time.
         */
-       if (SD->maintainfs != NULL)
-           SD->maintainfs(SD);
+       SD->maintainfs();
     }
     if (store_swap_size > Config.Swap.maxSize) {
        if (squid_curtime - last_warn_time > 10) {
@@ -963,7 +952,7 @@ storeRelease(StoreEntry * e)
        storeUnlink(e);
        if (e->swap_status == SWAPOUT_DONE)
            if (EBIT_TEST(e->flags, ENTRY_VALIDATED))
-               storeDirUpdateSwapSize(&Config.cacheSwap.swapDirs[e->swap_dirn], e->swap_file_sz, -1);
+               storeDirUpdateSwapSize(INDEXSD(e->swap_dirn), e->swap_file_sz, -1);
        if (!EBIT_TEST(e->flags, KEY_PRIVATE))
            storeDirSwapLog(e, SWAP_LOG_DEL);
 #if 0
index 170bad8c37b09d5460c84204807e082ffd590fc1..53f04054820dd49c8d1746856ab10e39a92fb545 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_client.cc,v 1.118 2002/10/15 08:03:30 robertc Exp $
+ * $Id: store_client.cc,v 1.119 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 20    Storage Manager Client-Side Interface
  * AUTHOR: Duane Wessels
@@ -301,7 +301,7 @@ storeClientCopy3(StoreEntry * e, store_client * sc)
      * if needed.
      */
 
-    if (STORE_DISK_CLIENT == sc->type && NULL == sc->swapin_sio) {
+    if (STORE_DISK_CLIENT == sc->type && sc->swapin_sio.getRaw() == NULL) {
        debug(20, 3) ("storeClientCopy3: Need to open swap in file\n");
        /* gotta open the swapin file */
        if (storeTooManyDiskFilesOpen()) {
@@ -311,7 +311,7 @@ storeClientCopy3(StoreEntry * e, store_client * sc)
        } else if (!sc->flags.disk_io_pending) {
            /* Don't set store_io_pending here */
            storeSwapInStart(sc);
-           if (NULL == sc->swapin_sio) {
+           if (sc->swapin_sio == NULL) {
                storeClientCallback(sc, -1);
                return;
            }
@@ -357,7 +357,7 @@ storeClientFileRead(store_client * sc)
            sc);
     } else {
        if (sc->entry->swap_status == SWAPOUT_WRITING)
-           assert(storeOffset(mem->swapout.sio) > sc->copyInto.offset + (off_t)mem->swap_hdr_sz);
+           assert(mem->swapout.sio->offset() > sc->copyInto.offset + (off_t)mem->swap_hdr_sz);
        storeRead(sc->swapin_sio,
            sc->copyInto.data,
            sc->copyInto.length,
@@ -542,9 +542,9 @@ storeUnregister(store_client * sc, StoreEntry * e, void *data)
     mem->nclients--;
     if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE)
        storeSwapOut(e);
-    if (sc->swapin_sio) {
+    if (sc->swapin_sio.getRaw()) {
        storeClose(sc->swapin_sio);
-       cbdataReferenceDone(sc->swapin_sio);
+       sc->swapin_sio = NULL;
        statCounter.swap.ins++;
     }
     if (NULL != sc->callback) {
@@ -581,7 +581,7 @@ storeLowestMemReaderOffset(const StoreEntry * entry)
        if (sc->type != STORE_MEM_CLIENT)
            continue;
        if (sc->type == STORE_DISK_CLIENT)
-           if (NULL != sc->swapin_sio)
+           if (sc->swapin_sio.getRaw())
                continue;
        if (sc->copyInto.offset < lowest)
            lowest = sc->copyInto.offset;
index ce405865e0312a3cfa9c44d7c5c5d517dd3ff77b..be2baf223a40d396c9471706990e6c8b1f1239c5 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_dir.cc,v 1.139 2002/10/15 08:03:30 robertc Exp $
+ * $Id: store_dir.cc,v 1.140 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 47    Store Directory Routines
  * AUTHOR: Duane Wessels
@@ -35,6 +35,7 @@
 
 #include "squid.h"
 #include "Store.h"
+#include "SwapDir.h"
 
 #if HAVE_STATVFS
 #if HAVE_SYS_STATVFS_H
@@ -60,11 +61,8 @@ void
 storeDirInit(void)
 {
     int i;
-    SwapDir *sd;
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-       sd = &Config.cacheSwap.swapDirs[i];
-       sd->init(sd);
-    }
+    for (i = 0; i < Config.cacheSwap.n_configured; i++)
+       INDEXSD(i)->init();
     if (0 == strcasecmp(Config.store_dir_select_algorithm, "round-robin")) {
        storeDirSelectSwapDir = storeDirSelectSwapDirRoundRobin;
        debug(47, 1) ("Using Round Robin store dir selection\n");
@@ -78,15 +76,12 @@ void
 storeCreateSwapDirectories(void)
 {
     int i;
-    SwapDir *sd;
     pid_t pid;
     int status;
     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
        if (fork())
            continue;
-       sd = &Config.cacheSwap.swapDirs[i];
-       if (NULL != sd->newfs)
-           sd->newfs(sd);
+       INDEXSD(i)->newFileSystem();
        exit(0);
     }
     do {
@@ -112,7 +107,7 @@ storeDirValidSwapDirSize(int swapdir, ssize_t objsize)
     /*
      * If the swapdir's max_obj_size is -1, then it definitely can
      */
-    if (Config.cacheSwap.swapDirs[swapdir].max_objsize == -1)
+    if (INDEXSD(swapdir)->max_objsize == -1)
        return 1;
 
     /*
@@ -120,13 +115,13 @@ storeDirValidSwapDirSize(int swapdir, ssize_t objsize)
      * can't store it
      */
     if ((objsize == -1) &&
-       (Config.cacheSwap.swapDirs[swapdir].max_objsize != -1))
+       (INDEXSD(swapdir)->max_objsize != -1))
        return 0;
 
     /*
      * Else, make sure that the max object size is larger than objsize
      */
-    if (Config.cacheSwap.swapDirs[swapdir].max_objsize > objsize)
+    if (INDEXSD(swapdir)->max_objsize > objsize)
        return 1;
     else
        return 0;
@@ -149,7 +144,7 @@ storeDirSelectSwapDirRoundRobin(const StoreEntry * e)
     for (i = 0; i <= Config.cacheSwap.n_configured; i++) {
        if (++dirn >= Config.cacheSwap.n_configured)
            dirn = 0;
-       sd = &Config.cacheSwap.swapDirs[dirn];
+       sd = INDEXSD(dirn);
        if (sd->flags.read_only)
            continue;
        if (sd->cur_size > sd->max_size)
@@ -157,7 +152,7 @@ storeDirSelectSwapDirRoundRobin(const StoreEntry * e)
        if (!storeDirValidSwapDirSize(i, objsize))
            continue;
        /* check for error or overload condition */
-       load = sd->checkobj(sd, e);
+       load = sd->canStore(*e);
        if (load < 0 || load > 1000) {
            continue;
        }
@@ -196,9 +191,9 @@ storeDirSelectSwapDirLeastLoad(const StoreEntry * e)
     if (objsize != -1)
        objsize += e->mem_obj->swap_hdr_sz;
     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-       SD = &Config.cacheSwap.swapDirs[i];
+       SD = INDEXSD(i);
        SD->flags.selected = 0;
-       load = SD->checkobj(SD, e);
+       load = SD->canStore(*e);
        if (load < 0 || load > 1000) {
            continue;
        }
@@ -227,7 +222,7 @@ storeDirSelectSwapDirLeastLoad(const StoreEntry * e)
        dirn = i;
     }
     if (dirn >= 0)
-       Config.cacheSwap.swapDirs[dirn].flags.selected = 1;
+       INDEXSD(dirn)->flags.selected = 1;
     return dirn;
 }
 
@@ -237,7 +232,7 @@ char *
 storeSwapDir(int dirn)
 {
     assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
-    return Config.cacheSwap.swapDirs[dirn].path;
+    return INDEXSD(dirn)->path;
 }
 
 /*
@@ -252,7 +247,7 @@ storeSwapDir(int dirn)
 void
 storeDirSwapLog(const StoreEntry * e, int op)
 {
-    SwapDir *sd;
+    assert (e);
     assert(!EBIT_TEST(e->flags, KEY_PRIVATE));
     assert(e->swap_filen >= 0);
     /*
@@ -266,8 +261,7 @@ storeDirSwapLog(const StoreEntry * e, int op)
        e->getMD5Text(),
        e->swap_dirn,
        e->swap_filen);
-    sd = &Config.cacheSwap.swapDirs[e->swap_dirn];
-    sd->log.write(sd, e, op);
+    INDEXSD(e->swap_dirn)->logEntry(*e, op);
 }
 
 void
@@ -288,6 +282,7 @@ storeDirStats(StoreEntry * sentry)
 {
     int i;
     SwapDir *SD;
+    assert (sentry);
 
     storeAppendPrintf(sentry, "Store Directory Statistics:\n");
     storeAppendPrintf(sentry, "Store Entries          : %lu\n",
@@ -304,12 +299,12 @@ storeDirStats(StoreEntry * sentry)
     /* Now go through each swapdir, calling its statfs routine */
     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
        storeAppendPrintf(sentry, "\n");
-       SD = &(Config.cacheSwap.swapDirs[i]);
+       SD = INDEXSD(i);
        storeAppendPrintf(sentry, "Store Directory #%d (%s): %s\n", i, SD->type,
            storeSwapDir(i));
        storeAppendPrintf(sentry, "FS Block Size %d Bytes\n",
            SD->fs.blksize);
-       SD->statfs(SD, sentry);
+       SD->statfs(*sentry);
        if (SD->repl) {
            storeAppendPrintf(sentry, "Removal policy: %s\n", SD->repl->_type);
            if (SD->repl->Stats)
@@ -325,7 +320,7 @@ storeDirConfigure(void)
     int i;
     Config.Swap.maxSize = 0;
     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-       SD = &Config.cacheSwap.swapDirs[i];
+       SD = INDEXSD(i);
        Config.Swap.maxSize += SD->max_size;
        SD->low_size = (int) (((float) SD->max_size *
                (float) Config.Swap.lowWaterMark) / 100.0);
@@ -335,7 +330,7 @@ storeDirConfigure(void)
 void
 storeDirDiskFull(sdirno dirn)
 {
-    SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
+    SwapDir *SD = INDEXSD(dirn);
     assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
     if (SD->cur_size >= SD->max_size)
        return;
@@ -347,25 +342,15 @@ storeDirDiskFull(sdirno dirn)
 void
 storeDirOpenSwapLogs(void)
 {
-    int dirn;
-    SwapDir *sd;
-    for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-       sd = &Config.cacheSwap.swapDirs[dirn];
-       if (sd->log.open)
-           sd->log.open(sd);
-    }
+    for (int dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn)
+       INDEXSD(dirn)->openLog();
 }
 
 void
 storeDirCloseSwapLogs(void)
 {
-    int dirn;
-    SwapDir *sd;
-    for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-       sd = &Config.cacheSwap.swapDirs[dirn];
-       if (sd->log.close)
-           sd->log.close(sd);
-    }
+    for (int dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn)
+       INDEXSD(dirn)->closeLog();
 }
 
 /*
@@ -377,7 +362,6 @@ storeDirCloseSwapLogs(void)
  *  the run. Thanks goes to Eric Stern, since this solution
  *  came out of his COSS code.
  */
-#define CLEAN_BUF_SZ 16384
 int
 storeDirWriteCleanLogs(int reopen)
 {
@@ -397,35 +381,28 @@ storeDirWriteCleanLogs(int reopen)
     getCurrentTime();
     start = current_time;
     for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-       sd = &Config.cacheSwap.swapDirs[dirn];
-       if (sd->log.clean.start(sd) < 0) {
+       sd = INDEXSD(dirn);
+       if (sd->writeCleanStart() < 0) {
            debug(20, 1) ("log.clean.start() failed for dir #%d\n", sd->index);
            continue;
        }
     }
+    /* This writes all logs in parallel. It seems to me to be more efficient
+     * to write them sequentially. - RBC 20021214
+     */
     while (notdone) {
        notdone = 0;
        for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-           sd = &Config.cacheSwap.swapDirs[dirn];
-           if (NULL == sd->log.clean.write)
+           sd = INDEXSD(dirn);
+           if (NULL == sd->cleanLog)
                continue;
-           e = sd->log.clean.nextentry(sd);
+           e = sd->cleanLog->nextEntry();
            if (!e)
                continue;
            notdone = 1;
-           if (e->swap_filen < 0)
+           if (!sd->canLog(*e))
                continue;
-           if (e->swap_status != SWAPOUT_DONE)
-               continue;
-           if (e->swap_file_sz <= 0)
-               continue;
-           if (EBIT_TEST(e->flags, RELEASE_REQUEST))
-               continue;
-           if (EBIT_TEST(e->flags, KEY_PRIVATE))
-               continue;
-           if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
-               continue;
-           sd->log.clean.write(sd, e);
+           sd->cleanLog->write(*e);
            if ((++n & 0xFFFF) == 0) {
                getCurrentTime();
                debug(20, 1) ("  %7d entries written so far.\n", n);
@@ -433,10 +410,8 @@ storeDirWriteCleanLogs(int reopen)
        }
     }
     /* Flush */
-    for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
-       sd = &Config.cacheSwap.swapDirs[dirn];
-       sd->log.clean.done(sd);
-    }
+    for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++)
+       INDEXSD(dirn)->writeCleanDone();
     if (reopen)
        storeDirOpenSwapLogs();
     getCurrentTime();
@@ -446,7 +421,6 @@ storeDirWriteCleanLogs(int reopen)
        dt, (double) n / (dt > 0.0 ? dt : 1.0));
     return n;
 }
-#undef CLEAN_BUF_SZ
 
 /*
  * sync all avaliable fs'es ..
@@ -454,14 +428,8 @@ storeDirWriteCleanLogs(int reopen)
 void
 storeDirSync(void)
 {
-    int i;
-    SwapDir *SD;
-
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-       SD = &Config.cacheSwap.swapDirs[i];
-       if (SD->sync != NULL)
-           SD->sync(SD);
-    }
+    for (int i = 0; i < Config.cacheSwap.n_configured; ++i)
+       INDEXSD(i)->sync();
 }
 
 /*
@@ -478,10 +446,9 @@ storeDirCallback(void)
        for (i = 0; i < Config.cacheSwap.n_configured; i++) {
            if (ndir >= Config.cacheSwap.n_configured)
                ndir = ndir % Config.cacheSwap.n_configured;
-           SD = &Config.cacheSwap.swapDirs[ndir++];
-           if (NULL == SD->callback)
-               continue;
-           j += SD->callback(SD);
+           SD = INDEXSD(ndir);
+           ++ndir;
+           j += SD->callback();
        }
     } while (j > 0);
     ndir++;
index 1b7da2b6ef5822771148df6bbe6edf2a386c99da..c57d281c9cf6e8f164c2a8ffb10efac6c8256f94 100644 (file)
@@ -1,6 +1,6 @@
 #include "squid.h"
 #include "Store.h"
-
+#include "SwapDir.h"
 
 static struct {
     struct {
@@ -19,13 +19,13 @@ OBJH storeIOStats;
  * to what will be stored in this object, to allow the filesystem
  * to select different polices depending on object size or type.
  */
-storeIOState *
+StoreIOState::Pointer
 storeCreate(StoreEntry * e, STIOCB * file_callback, STIOCB * close_callback, void *callback_data)
 {
+    assert (e);
     ssize_t objsize;
     sdirno dirn;
     SwapDir *SD;
-    storeIOState *sio;
 
     store_io_stats.create.calls++;
     /* This is just done for logging purposes */
@@ -44,64 +44,53 @@ storeCreate(StoreEntry * e, STIOCB * file_callback, STIOCB * close_callback, voi
        return NULL;
     }
     debug(20, 2) ("storeCreate: Selected dir '%d' for obj size '%ld'\n", dirn, (long int) objsize);
-    SD = &Config.cacheSwap.swapDirs[dirn];
+    SD = INDEXSD(dirn);
 
     /* Now that we have a fs to use, call its storeCreate function */
-    sio = SD->obj.create(SD, e, file_callback, close_callback, callback_data);
-    if (NULL == sio)
+    StoreIOState::Pointer sio = SD->createStoreIO(*e, file_callback, close_callback, callback_data);
+    if (sio == NULL)
        store_io_stats.create.create_fail++;
     else
        store_io_stats.create.success++;
     return sio;
 }
 
-
 /*
  * storeOpen() is purely for reading ..
  */
-storeIOState *
+StoreIOState::Pointer
 storeOpen(StoreEntry * e, STFNCB * file_callback, STIOCB * callback,
     void *callback_data)
 {
-    SwapDir *SD = &Config.cacheSwap.swapDirs[e->swap_dirn];
-    return SD->obj.open(SD, e, file_callback, callback, callback_data);
+    return INDEXSD(e->swap_dirn)->openStoreIO(*e, file_callback, callback, callback_data);
 }
 
 void
-storeClose(storeIOState * sio)
+storeClose(StoreIOState::Pointer sio)
 {
-    SwapDir *SD = &Config.cacheSwap.swapDirs[sio->swap_dirn];
     if (sio->flags.closing)
        return;
     sio->flags.closing = 1;
-    SD->obj.close(SD, sio);
+    sio->close();
 }
 
 void
-storeRead(storeIOState * sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
+storeRead(StoreIOState::Pointer sio, char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
 {
-    SwapDir *SD = &Config.cacheSwap.swapDirs[sio->swap_dirn];
-    SD->obj.read(SD, sio, buf, size, offset, callback, callback_data);
+    sio->read_(buf, size, offset, callback, callback_data);
 }
 
 void
-storeWrite(storeIOState * sio, char *buf, size_t size, off_t offset, FREE * free_func)
+storeWrite(StoreIOState::Pointer sio, char *buf, size_t size, off_t offset, FREE * free_func)
 {
-    SwapDir *SD = &Config.cacheSwap.swapDirs[sio->swap_dirn];
-    SD->obj.write(SD, sio, buf, size, offset, free_func);
+    sio->write(buf,size,offset,free_func);
 }
 
 void
 storeUnlink(StoreEntry * e)
 {
-    SwapDir *SD = INDEXSD(e->swap_dirn);
-    SD->obj.unlink(SD, e);
-}
-
-off_t
-storeOffset(storeIOState * sio)
-{
-    return sio->offset;
+    assert (e);
+    INDEXSD(e->swap_dirn)->unlink(*e);
 }
 
 /*
index 6c955934a5586c478d5a3c1a02acb7e01176c8da..ad6a6564bc56750126548d0d605444440ecfcc54 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_rebuild.cc,v 1.78 2002/10/13 20:35:05 robertc Exp $
+ * $Id: store_rebuild.cc,v 1.79 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 20    Store Rebuild Routines
  * AUTHOR: Duane Wessels
@@ -35,6 +35,7 @@
 
 #include "squid.h"
 #include "Store.h"
+#include "SwapDir.h"
 
 static struct _store_rebuild_data counts;
 static struct timeval rebuild_start;
@@ -52,8 +53,8 @@ static store_rebuild_progress *RebuildProgress = NULL;
 static int
 storeCleanupDoubleCheck(StoreEntry * e)
 {
-    SwapDir *SD = &Config.cacheSwap.swapDirs[e->swap_dirn];
-    return (SD->dblcheck(SD, e));
+    SwapDir *SD = INDEXSD(e->swap_dirn);
+    return (SD->doubleCheck(*e));
 }
 
 static void
@@ -100,7 +101,7 @@ storeCleanup(void *datanotused)
             * Only set the file bit if we know its a valid entry
             * otherwise, set it in the validation procedure
             */
-           storeDirUpdateSwapSize(&Config.cacheSwap.swapDirs[e->swap_dirn], e->swap_file_sz, 1);
+           storeDirUpdateSwapSize(INDEXSD(e->swap_dirn), e->swap_file_sz, 1);
            if ((++validnum & 0x3FFFF) == 0)
                debug(20, 1) ("  %7d Entries Validated so far.\n", validnum);
        }
index eda42b44363162b9ead111f18fa805ab2e89a325..6fb75a76d8a7d04aa28ecb24e7115638aa17d50d 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_swapin.cc,v 1.32 2002/10/15 08:03:30 robertc Exp $
+ * $Id: store_swapin.cc,v 1.33 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 20    Storage Manager Swapin Functions
  * AUTHOR: Duane Wessels
@@ -44,7 +44,6 @@ void
 storeSwapInStart(store_client * sc)
 {
     StoreEntry *e = sc->entry;
-    storeIOState *sio;
     assert(e->mem_status == NOT_IN_MEMORY);
     if (!EBIT_TEST(e->flags, ENTRY_VALIDATED)) {
        /* We're still reloading and haven't validated this entry yet */
@@ -64,8 +63,7 @@ storeSwapInStart(store_client * sc)
     assert(e->mem_obj != NULL);
     debug(20, 3) ("storeSwapInStart: Opening fileno %08X\n",
        e->swap_filen);
-    sio = storeOpen(e, storeSwapInFileNotify, storeSwapInFileClosed, sc);
-    sc->swapin_sio = cbdataReference(sio);
+    sc->swapin_sio = storeOpen(e, storeSwapInFileNotify, storeSwapInFileClosed, sc);
 }
 
 static void
@@ -80,7 +78,7 @@ storeSwapInFileClosed(void *data, int errflag, storeIOState * sio)
        sio, errflag);
     if (errflag)
        result.flags.error = 1;
-    cbdataReferenceDone(sc->swapin_sio);
+    sc->swapin_sio = NULL;
     if ((callback = sc->callback)) {
        assert(errflag <= 0);
        sc->callback = NULL;
index 470ee442ac49affe399dbd20bfecbb904aa56b1c..57de1ac07272918e4e1ec9e1f55357abbc57b6bf 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_swapout.cc,v 1.90 2002/10/15 08:03:31 robertc Exp $
+ * $Id: store_swapout.cc,v 1.91 2002/12/27 10:26:33 robertc Exp $
  *
  * DEBUG: section 20    Storage Manager Swapout Functions
  * AUTHOR: Duane Wessels
@@ -36,6 +36,7 @@
 #include "squid.h"
 #include "StoreClient.h"
 #include "Store.h"
+#include "SwapDir.h"
 
 static off_t storeSwapOutObjectBytesOnDisk(const MemObject *);
 static void storeSwapOutStart(StoreEntry * e);
@@ -51,7 +52,7 @@ storeSwapOutStart(StoreEntry * e)
     int swap_hdr_sz = 0;
     tlv *tlv_list;
     char *buf;
-    storeIOState *sio;
+    StoreIOState::Pointer sio;
     assert(mem);
     /* Build the swap metadata, so the filesystem will know how much
      * metadata there is to store
@@ -67,8 +68,8 @@ storeSwapOutStart(StoreEntry * e)
     c = cbdataAlloc(generic_cbdata);
     c->data = e;
     sio = storeCreate(e, storeSwapOutFileNotify, storeSwapOutFileClosed, c);
-    mem->swapout.sio = cbdataReference(sio);
-    if (NULL == mem->swapout.sio) {
+    mem->swapout.sio = sio;
+    if (mem->swapout.sio == NULL) {
        e->swap_status = SWAPOUT_NONE;
        cbdataFree(c);
        xfree(buf);
@@ -128,9 +129,9 @@ storeSwapOut(StoreEntry * e)
        (int) mem->inmem_hi);
     debug(20, 7) ("storeSwapOut: swapout.queue_offset = %d\n",
        (int) mem->swapout.queue_offset);
-    if (mem->swapout.sio)
-       debug(20, 7) ("storeSwapOut: storeOffset() = %d\n",
-           (int) storeOffset(mem->swapout.sio));
+    if (mem->swapout.sio.getRaw())
+       debug(20, 7) ("storeSwapOut: offset() = %d\n",
+           (int) mem->swapout.sio->offset());
     assert(mem->inmem_hi >= mem->swapout.queue_offset);
     lowest_offset = storeLowestMemReaderOffset(e);
     debug(20, 7) ("storeSwapOut: lowest_offset = %d\n",
@@ -227,7 +228,7 @@ storeSwapOut(StoreEntry * e)
            return;
        /* ENTRY_CACHABLE will be cleared and we'll never get here again */
     }
-    if (NULL == mem->swapout.sio)
+    if (mem->swapout.sio == NULL)
        return;
     do {
        /*
@@ -268,7 +269,7 @@ storeSwapOut(StoreEntry * e)
            if (swapout_size < SM_PAGE_SIZE)
                break;
     } while (swapout_size > 0);
-    if (NULL == mem->swapout.sio)
+    if (mem->swapout.sio == NULL)
        /* oops, we're not swapping out any more */
        return;
     if (e->store_status == STORE_OK) {
@@ -288,7 +289,7 @@ storeSwapOutFileClose(StoreEntry * e)
     MemObject *mem = e->mem_obj;
     assert(mem != NULL);
     debug(20, 3) ("storeSwapOutFileClose: %s\n", e->getMD5Text());
-    debug(20, 3) ("storeSwapOutFileClose: sio = %p\n", mem->swapout.sio);
+    debug(20, 3) ("storeSwapOutFileClose: sio = %p\n", mem->swapout.sio.getRaw());
     if (mem->swapout.sio == NULL)
        return;
     storeClose(mem->swapout.sio);
@@ -322,7 +323,7 @@ storeSwapOutFileClosed(void *data, int errflag, storeIOState * sio)
            storeUrl(e), e->swap_dirn, e->swap_filen);
        e->swap_file_sz = objectLen(e) + mem->swap_hdr_sz;
        e->swap_status = SWAPOUT_DONE;
-       storeDirUpdateSwapSize(&Config.cacheSwap.swapDirs[e->swap_dirn], e->swap_file_sz, 1);
+       storeDirUpdateSwapSize(INDEXSD(e->swap_dirn), e->swap_file_sz, 1);
        if (storeCheckCachable(e)) {
            storeLog(STORE_LOG_SWAPOUT, e);
            storeDirSwapLog(e, SWAP_LOG_ADD);
@@ -330,7 +331,7 @@ storeSwapOutFileClosed(void *data, int errflag, storeIOState * sio)
        statCounter.swap.outs++;
     }
     debug(20, 3) ("storeSwapOutFileClosed: %s:%d\n", __FILE__, __LINE__);
-    cbdataReferenceDone(mem->swapout.sio);
+    mem->swapout.sio = NULL;
     storeUnlockObject(e);
 }
 
@@ -341,7 +342,7 @@ static off_t
 storeSwapOutObjectBytesOnDisk(const MemObject * mem)
 {
     /*
-     * NOTE: storeOffset() represents the disk file size,
+     * NOTE: offset() represents the disk file size,
      * not the amount of object data on disk.
      * 
      * If we don't have at least 'swap_hdr_sz' bytes
@@ -351,10 +352,9 @@ storeSwapOutObjectBytesOnDisk(const MemObject * mem)
      * meaning we haven't even opened the swapout file
      * yet.
      */
-    off_t nwritten;
     if (mem->swapout.sio == NULL)
        return 0;
-    nwritten = storeOffset(mem->swapout.sio);
+    off_t nwritten = mem->swapout.sio->offset();
     if (nwritten <= (off_t)mem->swap_hdr_sz)
        return 0;
     return nwritten - mem->swap_hdr_sz;
@@ -367,7 +367,7 @@ int
 storeSwapOutAble(const StoreEntry * e)
 {
     dlink_node *node;
-    if (e->mem_obj->swapout.sio != NULL)
+    if (e->mem_obj->swapout.sio.getRaw() != NULL)
        return 1;
     if (e->mem_obj->inmem_lo > 0)
        return 0;
index cbbeea60fe53dbf790e2fdf4ff5170ca1836fac9..1f47584df90dba675ed0abcef2bd8fd15426c99f 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.440 2002/12/19 09:57:09 robertc Exp $
+ * $Id: structs.h,v 1.441 2002/12/27 10:26:34 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -546,7 +546,7 @@ struct _SquidConfig {
     } Ftp;
     refresh_t *Refresh;
     struct _cacheSwap {
-       SwapDir *swapDirs;
+       SwapDir **swapDirs;
        int n_allocated;
        int n_configured;
     } cacheSwap;
@@ -1367,6 +1367,10 @@ struct _RemovalPurgeWalker {
     void (*Done) (RemovalPurgeWalker * walker);
 };
 
+/* TODO: Move this include and the memobject header to another file
+ * - see the fix_ranges branch 
+ */
+#include "StoreIOState.h"
 /* This structure can be freed while object is purged out from memory */
 struct _MemObject {
     method_t method;
@@ -1379,7 +1383,7 @@ struct _MemObject {
     struct {
        off_t queue_offset;     /* relative to in-mem data */
        mem_node *memnode;      /* which node we're currently paging out */
-       storeIOState *sio;
+       StoreIOState::Pointer sio;
     } swapout;
     HttpReply *reply;
     request_t *request;
@@ -1402,61 +1406,6 @@ struct _MemObject {
     const char *vary_headers;
 };
 
-struct _SwapDir {
-    const char *type;
-    int cur_size;
-    int low_size;
-    int max_size;
-    char *path;
-    int index;                 /* This entry's index into the swapDirs array */
-    ssize_t max_objsize;
-    RemovalPolicy *repl;
-    int removals;
-    int scanned;
-    struct {
-       unsigned int selected:1;
-       unsigned int read_only:1;
-    } flags;
-    STINIT *init;              /* Initialise the fs */
-    STNEWFS *newfs;            /* Create a new fs */
-    STDUMP *dump;              /* Dump fs config snippet */
-    STFREE *freefs;            /* Free the fs data */
-    STDBLCHECK *dblcheck;      /* Double check the obj integrity */
-    STSTATFS *statfs;          /* Dump fs statistics */
-    STMAINTAINFS *maintainfs;  /* Replacement maintainence */
-    STCHECKOBJ *checkobj;      /* Check if the fs will store an object */
-    /* These two are notifications */
-    STREFOBJ *refobj;          /* Reference this object */
-    STUNREFOBJ *unrefobj;      /* Unreference this object */
-    STCALLBACK *callback;      /* Handle pending callbacks */
-    STSYNC *sync;              /* Sync the directory */
-    struct {
-       STOBJCREATE *create;
-       STOBJOPEN *open;
-       STOBJCLOSE *close;
-       STOBJREAD *read;
-       STOBJWRITE *write;
-       STOBJUNLINK *unlink;
-    } obj;
-    struct {
-       STLOGOPEN *open;
-       STLOGCLOSE *close;
-       STLOGWRITE *write;
-       struct {
-           STLOGCLEANSTART *start;
-           STLOGCLEANNEXTENTRY *nextentry;
-           STLOGCLEANWRITE *write;
-           STLOGCLEANDONE *done;
-           void *state;
-       } clean;
-       int writes_since_clean;
-    } log;
-    struct {
-       int blksize;
-    } fs;
-    void *fsdata;
-};
-
 /* To hard to pull this into another file just yet.
  * SO, we stop globals.c seeing it 
  */
@@ -1499,25 +1448,6 @@ struct _link_list {
     struct _link_list *next;
 };
 
-struct _storeIOState {
-    sdirno swap_dirn;
-    sfileno swap_filen;
-    StoreEntry *e;             /* Need this so the FS layers can play god */
-    mode_t mode;
-    size_t st_size;            /* do stat(2) after read open */
-    off_t offset;              /* current on-disk offset pointer */
-    STFNCB *file_callback;     /* called on delayed sfileno assignments */
-    STIOCB *callback;
-    void *callback_data;
-    struct {
-       STRCB *callback;
-       void *callback_data;
-    } read;
-    struct {
-       unsigned int closing:1; /* debugging aid */
-    } flags;
-    void *fsstate;
-};
 
 struct _request_t {
     method_t method;
@@ -1985,9 +1915,8 @@ struct _store_rebuild_data {
 
 struct _storefs_entry {
     const char *typestr;
-    STFSPARSE *parsefunc;
-    STFSRECONFIGURE *reconfigurefunc;
     STFSSHUTDOWN *donefunc;
+    STFSNEW *newfunc;
 };
 
 /*
@@ -2031,7 +1960,7 @@ struct _Logfile {
 struct cache_dir_option {
     const char *name;
     void (*parse) (SwapDir * sd, const char *option, const char *value, int reconfiguring);
-    void (*dump) (StoreEntry * e, const char *option, SwapDir * sd);
+    void (*dump) (StoreEntry * e, const char *option, SwapDir const * sd);
 };
 
 #endif /* SQUID_STRUCTS_H */
index 20cfced7465742678db865fe4b01980f127d603c..c68b5e74033b6a2dae47226aa813ecfeb7b72247 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: typedefs.h,v 1.143 2002/12/06 23:19:16 hno Exp $
+ * $Id: typedefs.h,v 1.144 2002/12/27 10:26:34 robertc Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -137,7 +137,7 @@ typedef struct _mem_hdr mem_hdr;
 typedef struct _store_client store_client;
 typedef struct _MemObject MemObject;
 typedef struct _StoreEntry StoreEntry;
-typedef struct _SwapDir SwapDir;
+class SwapDir;
 typedef struct _helper_flags helper_flags;
 typedef struct _helper_stateful_flags helper_stateful_flags;
 typedef struct _http_state_flags http_state_flags;
@@ -171,9 +171,7 @@ typedef struct _helper_stateful_server helper_stateful_server;
 typedef struct _helper_request helper_request;
 typedef struct _helper_stateful_request helper_stateful_request;
 typedef struct _generic_cbdata generic_cbdata;
-typedef struct _storeIOState storeIOState;
-typedef struct _queued_read queued_read;
-typedef struct _queued_write queued_write;
+class storeIOState;
 typedef struct _link_list link_list;
 typedef struct _storefs_entry storefs_entry_t;
 typedef struct _storerepl_entry storerepl_entry_t;
@@ -248,42 +246,8 @@ typedef void HLPSONEQ(void *);
 typedef void HLPCMDOPTS(int *argc, char **argv);
 typedef void IDNSCB(void *, rfc1035_rr *, int);
 
-typedef void STINIT(SwapDir *);
-typedef void STNEWFS(SwapDir *);
-typedef void STDUMP(StoreEntry *, SwapDir *);
-typedef void STFREE(SwapDir *);
-typedef int STDBLCHECK(SwapDir *, StoreEntry *);
-typedef void STSTATFS(SwapDir *, StoreEntry *);
-typedef void STMAINTAINFS(SwapDir *);
-typedef int STCHECKOBJ(SwapDir *, const StoreEntry *);
-typedef void STREFOBJ(SwapDir *, StoreEntry *);
-typedef void STUNREFOBJ(SwapDir *, StoreEntry *);
-typedef void STSETUP(storefs_entry_t *);
-typedef void STDONE(void);
-typedef int STCALLBACK(SwapDir *);
-typedef void STSYNC(SwapDir *);
-
-typedef storeIOState *STOBJCREATE(SwapDir *, StoreEntry *, STFNCB *, STIOCB *, void *);
-typedef storeIOState *STOBJOPEN(SwapDir *, StoreEntry *, STFNCB *, STIOCB *, void *);
-typedef void STOBJCLOSE(SwapDir *, storeIOState *);
-typedef void STOBJREAD(SwapDir *, storeIOState *, char *, size_t, off_t, STRCB *, void *);
-typedef void STOBJWRITE(SwapDir *, storeIOState *, char *, size_t, off_t, FREE *);
-typedef void STOBJUNLINK(SwapDir *, StoreEntry *);
-
-typedef void STLOGOPEN(SwapDir *);
-typedef void STLOGCLOSE(SwapDir *);
-typedef void STLOGWRITE(const SwapDir *, const StoreEntry *, int);
-typedef int STLOGCLEANSTART(SwapDir *);
-typedef const StoreEntry *STLOGCLEANNEXTENTRY(SwapDir *);
-typedef void STLOGCLEANWRITE(SwapDir *, const StoreEntry *);
-typedef void STLOGCLEANDONE(SwapDir *);
-
-/* Store dir configuration routines */
-/* SwapDir *sd, char *path ( + char *opt later when the strtok mess is gone) */
-typedef void STFSPARSE(SwapDir *, int, char *);
-typedef void STFSRECONFIGURE(SwapDir *, int, char *);
-typedef void STFSSTARTUP(void);
 typedef void STFSSHUTDOWN(void);
+typedef SwapDir *STFSNEW(void);
 
 typedef double hbase_f(double);
 typedef void StatHistBinDumper(StoreEntry *, int idx, double val, double size, int count);
index 8c7b6d03308365e472d0b4af0561e31e2ab77a94..f64c5af1f0069630fdda5555d8b47c1f5f573a69 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ufscommon.cc,v 1.4 2002/10/15 08:03:31 robertc Exp $
+ * $Id: ufscommon.cc,v 1.5 2002/12/27 10:26:34 robertc Exp $
  *
  * DEBUG: section 47    Store Directory Routines
  * AUTHOR: Duane Wessels
 
 #include "ufscommon.h"
 #include "Store.h"
+#include "RefCount.h"
 
-typedef struct _RebuildState RebuildState;
-struct _RebuildState {
-    SwapDir *sd;
-    int n_read;
-    FILE *log;
-    int speed;
-    int curlvl1;
-    int curlvl2;
-    struct {
-       unsigned int need_to_validate:1;
-       unsigned int clean:1;
-       unsigned int init:1;
-    } flags;
-    int done;
-    int in_dir;
-    int fn;
-    struct dirent *entry;
-    DIR *td;
-    char fullpath[SQUID_MAXPATHLEN];
-    char fullfilename[SQUID_MAXPATHLEN];
-    struct _store_rebuild_data counts;
-};
+CBDATA_CLASS_INIT(RebuildState);
 
-static int n_dirs = 0;
-static int *dir_index = NULL;
-#if 0
-MemPool *squidaio_state_pool = NULL;
-MemPool *aufs_qread_pool = NULL;
-MemPool *aufs_qwrite_pool = NULL;
-static int asyncufs_initialised = 0;
-#endif
-static int commonUfsFilenoBelongsHere(int fn, int F0, int F1, int F2);
-static char *commonUfsDirSwapSubDir(SwapDir *, int subdirn);
-static int commonUfsDirCreateDirectory(const char *path, int);
-static int commonUfsDirVerifyCacheDirs(SwapDir * sd);
-static int commonUfsDirVerifyDirectory(const char *path);
-static void commonUfsDirCreateSwapSubDirs(SwapDir *);
-static int commonUfsDirMapBitTest(SwapDir * SD, sfileno filn);
-static char *commonUfsDirSwapLogFile(SwapDir *, const char *);
-static EVH commonUfsDirRebuildFromDirectory;
-static EVH commonUfsDirRebuildFromSwapLog;
-static int commonUfsDirGetNextFile(RebuildState *, sfileno *, int *size);
-static StoreEntry *commonUfsDirAddDiskRestore(SwapDir * SD, const cache_key * key,
-    sfileno file_number,
-    size_t swap_file_sz,
-    time_t expires,
-    time_t timestamp,
-    time_t lastref,
-    time_t lastmod,
-    u_int32_t refcount,
-    u_int16_t flags,
-    int clean);
-static void commonUfsDirRebuild(SwapDir * sd);
-static void commonUfsDirCloseTmpSwapLog(SwapDir * sd);
-static FILE *commonUfsDirOpenTmpSwapLog(SwapDir *, int *, int *);
-#if 0
-static STLOGOPEN commonUfsDirOpenSwapLog;
-static STINIT commonUfsDirInit;
-static STFREE commonUfsDirFree;
-static STLOGCLEANSTART commonUfsDirWriteCleanStart;
-static STLOGCLEANNEXTENTRY commonUfsDirCleanLogNextEntry;
-#endif
-static STLOGCLEANWRITE commonUfsDirWriteCleanEntry;
-#if 0
-static STLOGCLEANDONE commonUfsDirWriteCleanDone;
-static STLOGCLOSE commonUfsDirCloseSwapLog;
-static STLOGWRITE commonUfsDirSwapLog;
-static STNEWFS commonUfsDirNewfs;
-static STCHECKOBJ commonUfsDirCheckObj;
-#endif
-static QS rev_int_sort;
-static void commonUfsDirMapBitSet(SwapDir * SD, sfileno filn);
-static EVH commonUfsDirCleanEvent;
-static int commonUfsDirClean(int swap_index);
-static int commonUfsDirIs(SwapDir * sd);
-#if 0
-static int commonUfsCleanupDoubleCheck(SwapDir *, StoreEntry *);
-#endif
-static void commonUfsDirInitBitmap(SwapDir *);
-static int commonUfsDirValidFileno(SwapDir * SD, sfileno filn, int flag);
-static int commonUfsDirMapBitTest(SwapDir * SD, sfileno filn);
-void commonUfsDirMapBitReset(SwapDir * SD, sfileno filn);
-
-#if 0
-
-/* The MAIN externally visible function */
-STSETUP storeFsSetup_aufs;
-
-/*
- * These functions were ripped straight out of the heart of store_dir.c.
- * They assume that the given filenum is on a asyncufs partiton, which may or
- * may not be true.. 
- * XXX this evilness should be tidied up at a later date!
- */
-
-#endif
-int
-commonUfsDirMapBitTest(SwapDir * SD, sfileno filn)
-{
-    squidufsinfo_t *ioinfo;
-    ioinfo = (squidufsinfo_t *) SD->fsdata;
-    return file_map_bit_test(ioinfo->map, filn);
-}
-
-void
-commonUfsDirMapBitSet(SwapDir * SD, sfileno filn)
-{
-    squidufsinfo_t *ioinfo;
-    ioinfo = (squidufsinfo_t *) SD->fsdata;
-    file_map_bit_set(ioinfo->map, filn);
-}
-
-void
-commonUfsDirMapBitReset(SwapDir * SD, sfileno filn)
-{
-    squidufsinfo_t *ioinfo;
-    ioinfo = (squidufsinfo_t *) SD->fsdata;
-    /*
-     * We have to test the bit before calling file_map_bit_reset.
-     * file_map_bit_reset doesn't do bounds checking.  It 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 (file_map_bit_test(ioinfo->map, filn))
-       file_map_bit_reset(ioinfo->map, filn);
-}
-
-int
-commonUfsDirMapBitAllocate(SwapDir * SD)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata;
-    int fn;
-    fn = file_map_allocate(ioinfo->map, ioinfo->suggest);
-    file_map_bit_set(ioinfo->map, fn);
-    ioinfo->suggest = fn + 1;
-    return fn;
-}
-
-/*
- * Initialise the asyncufs bitmap
- *
- * If there already is a bitmap, and the numobjects is larger than currently
- * configured, we allocate a new bitmap and 'grow' the old one into it.
- */
-void
-commonUfsDirInitBitmap(SwapDir * sd)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata;
-
-    if (ioinfo->map == NULL) {
-       /* First time */
-       ioinfo->map = file_map_create();
-    } else if (ioinfo->map->max_n_files) {
-       /* it grew, need to expand */
-       /* XXX We don't need it anymore .. */
-    }
-    /* else it shrunk, and we leave the old one in place */
-}
-
-char *
-commonUfsDirSwapSubDir(SwapDir * sd, int subdirn)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata;
-
-    LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
-    assert(0 <= subdirn && subdirn < ioinfo->l1);
-    snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%02X", sd->path, subdirn);
-    return fullfilename;
-}
-
-int
-commonUfsDirCreateDirectory(const char *path, int should_exist)
+void *
+RebuildState::operator new (size_t size)
 {
-    int created = 0;
-    struct stat st;
-    getCurrentTime();
-    if (0 == stat(path, &st)) {
-       if (S_ISDIR(st.st_mode)) {
-           debug(47, should_exist ? 3 : 1) ("%s exists\n", path);
-       } else {
-           fatalf("Swap directory %s is not a directory.", path);
-       }
-#ifdef _SQUID_MSWIN_
-    } else if (0 == mkdir(path)) {
-#else
-    } else if (0 == mkdir(path, 0755)) {
-#endif
-       debug(47, should_exist ? 1 : 3) ("%s created\n", path);
-       created = 1;
-    } else {
-       fatalf("Failed to make swap directory %s: %s",
-           path, xstrerror());
-    }
-    return created;
-}
-
-int
-commonUfsDirVerifyDirectory(const char *path)
-{
-    struct stat sb;
-    if (stat(path, &sb) < 0) {
-       debug(47, 0) ("%s: %s\n", path, xstrerror());
-       return -1;
-    }
-    if (S_ISDIR(sb.st_mode) == 0) {
-       debug(47, 0) ("%s is not a directory\n", path);
-       return -1;
-    }
-    return 0;
-}
-
-/*
- * 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'
- */
-int
-commonUfsDirVerifyCacheDirs(SwapDir * sd)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata;
-    int j;
-    const char *path = sd->path;
-
-    if (commonUfsDirVerifyDirectory(path) < 0)
-       return -1;
-    for (j = 0; j < ioinfo->l1; j++) {
-       path = commonUfsDirSwapSubDir(sd, j);
-       if (commonUfsDirVerifyDirectory(path) < 0)
-           return -1;
-    }
-    return 0;
+    assert (size == sizeof(RebuildState));
+    CBDATA_INIT_TYPE(RebuildState);
+    RebuildState *result = cbdataAlloc(RebuildState);
+    /* Mark result as being owned - we want the refcounter to do the delete
+     * call */
+    cbdataReference(result);
+    return result;
 }
-
 void
-commonUfsDirCreateSwapSubDirs(SwapDir * sd)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata;
-    int i, k;
-    int should_exist;
-    LOCAL_ARRAY(char, name, MAXPATHLEN);
-    for (i = 0; i < ioinfo->l1; i++) {
-       snprintf(name, MAXPATHLEN, "%s/%02X", sd->path, i);
-       if (commonUfsDirCreateDirectory(name, 0))
-           should_exist = 0;
-       else
-           should_exist = 1;
-       debug(47, 1) ("Making directories in %s\n", name);
-       for (k = 0; k < ioinfo->l2; k++) {
-           snprintf(name, MAXPATHLEN, "%s/%02X/%02X", sd->path, i, k);
-           commonUfsDirCreateDirectory(name, should_exist);
-       }
-    }
-}
-
-char *
-commonUfsDirSwapLogFile(SwapDir * sd, const char *ext)
+RebuildState::operator delete (void *address)
 {
-    LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN);
-    LOCAL_ARRAY(char, pathtmp, SQUID_MAXPATHLEN);
-    LOCAL_ARRAY(char, digit, 32);
-    char *pathtmp2;
-    if (Config.Log.swap) {
-       xstrncpy(pathtmp, sd->path, SQUID_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(path, SQUID_MAXPATHLEN - 64, Config.Log.swap, pathtmp2);
-       if (strncmp(path, Config.Log.swap, SQUID_MAXPATHLEN - 64) == 0) {
-           strcat(path, ".");
-           snprintf(digit, 32, "%02d", sd->index);
-           strncat(path, digit, 3);
-       }
-    } else {
-       xstrncpy(path, sd->path, SQUID_MAXPATHLEN - 64);
-       strcat(path, "/swap.state");
-    }
-    if (ext)
-       strncat(path, ext, 16);
-    return path;
+    RebuildState *t = static_cast<RebuildState *>(address);
+    cbdataFree(address);
+    /* And allow the memory to be freed */
+    cbdataReferenceDone (t);
 }
 
 void
-commonUfsDirOpenSwapLog(SwapDir * sd)
+RebuildState::deleteSelf() const
 {
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata;
-    char *path;
-    int fd;
-    path = commonUfsDirSwapLogFile(sd, NULL);
-    fd = file_open(path, O_WRONLY | O_CREAT | O_BINARY);
-    if (fd < 0) {
-       debug(50, 1) ("%s: %s\n", path, xstrerror());
-       fatal("commonUfsDirOpenSwapLog: Failed to open swap log.");
-    }
-    debug(50, 3) ("Cache Dir #%d log opened on FD %d\n", sd->index, fd);
-    ioinfo->swaplog_fd = fd;
-    if (0 == n_dirs)
-       assert(NULL == dir_index);
-    ++n_dirs;
-    assert(n_dirs <= Config.cacheSwap.n_configured);
+    delete this;
 }
 
-void
-commonUfsDirCloseSwapLog(SwapDir * sd)
+RebuildState::~RebuildState()
 {
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata;
-    if (ioinfo->swaplog_fd < 0)        /* not open */
-       return;
-    file_close(ioinfo->swaplog_fd);
-    debug(47, 3) ("Cache Dir #%d log closed on FD %d\n",
-       sd->index, ioinfo->swaplog_fd);
-    ioinfo->swaplog_fd = -1;
-    n_dirs--;
-    assert(n_dirs >= 0);
-    if (0 == n_dirs)
-       safe_free(dir_index);
+    store_dirs_rebuilding--;
+    sd->closeTmpSwapLog();
+    storeRebuildComplete(&counts);
 }
 
 void
-commonUfsDirInit(SwapDir * sd)
+RebuildState::RebuildFromDirectory(void *data)
 {
-    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.";
-    commonUfsDirInitBitmap(sd);
-    if (commonUfsDirVerifyCacheDirs(sd) < 0)
-       fatal(errmsg);
-    commonUfsDirOpenSwapLog(sd);
-    commonUfsDirRebuild(sd);
-    if (!started_clean_event) {
-       eventAdd("storeDirClean", commonUfsDirCleanEvent, NULL, 15.0, 1);
-       started_clean_event = 1;
-    }
-    (void) storeDirGetBlkSize(sd->path, &sd->fs.blksize);
+    RebuildState *rb = (RebuildState *)data;
+    rb->rebuildFromDirectory();
 }
 
 void
-commonUfsDirRebuildFromDirectory(void *data)
+RebuildState::rebuildFromDirectory()
 {
-    RebuildState *rb = (RebuildState *)data;
-    SwapDir *SD = rb->sd;
     LOCAL_ARRAY(char, hdr_buf, SM_PAGE_SIZE);
     StoreEntry *e = NULL;
     StoreEntry tmpe;
     cache_key key[MD5_DIGEST_CHARS];
-    sfileno filn = 0;
-    int count;
-    int size;
     struct stat sb;
     int swap_hdr_len;
     int fd = -1;
     tlv *tlv_list;
     tlv *t;
-    assert(rb != NULL);
-    debug(47, 3) ("commonUfsDirRebuildFromDirectory: DIR #%d\n", rb->sd->index);
-    for (count = 0; count < rb->speed; count++) {
+    assert(this != NULL);
+    debug(47, 3) ("commonUfsDirRebuildFromDirectory: DIR #%d\n", sd->index);
+    for (int count = 0; count < speed; count++) {
        assert(fd == -1);
-       fd = commonUfsDirGetNextFile(rb, &filn, &size);
+       sfileno filn = 0;
+       int size;
+       fd = getNextFile(&filn, &size);
        if (fd == -2) {
            debug(47, 1) ("Done scanning %s swaplog (%d entries)\n",
-               rb->sd->path, rb->n_read);
-           store_dirs_rebuilding--;
-           commonUfsDirCloseTmpSwapLog(rb->sd);
-           storeRebuildComplete(&rb->counts);
-           cbdataFree(rb);
+               sd->path, n_read);
+           deleteSelf();
            return;
        } else if (fd < 0) {
            continue;
@@ -419,9 +116,9 @@ commonUfsDirRebuildFromDirectory(void *data)
            fd = -1;
            continue;
        }
-       if ((++rb->counts.scancount & 0xFFFF) == 0)
+       if ((++counts.scancount & 0xFFFF) == 0)
            debug(47, 3) ("  %s %7d files opened so far.\n",
-               rb->sd->path, rb->counts.scancount);
+               sd->path, counts.scancount);
        debug(47, 9) ("file_in: fd=%d %08X\n", fd, filn);
        statCounter.syscalls.disk.reads++;
        if (FD_READ_METHOD(fd, hdr_buf, SM_PAGE_SIZE) < 0) {
@@ -444,7 +141,7 @@ commonUfsDirRebuildFromDirectory(void *data)
        if (tlv_list == NULL) {
            debug(47, 1) ("commonUfsDirRebuildFromDirectory: failed to get meta data\n");
            /* XXX shouldn't this be a call to commonUfsUnlink ? */
-           commonUfsDirUnlinkFile(SD, filn);
+           sd->unlinkFile (filn);
            continue;
        }
        debug(47, 3) ("commonUfsDirRebuildFromDirectory: successful swap meta unpacking\n");
@@ -468,7 +165,7 @@ commonUfsDirRebuildFromDirectory(void *data)
        tlv_list = NULL;
        if (storeKeyNull(key)) {
            debug(47, 1) ("commonUfsDirRebuildFromDirectory: NULL key\n");
-           commonUfsDirUnlinkFile(SD, filn);
+           sd->unlinkFile(filn);
            continue;
        }
        tmpe.key = key;
@@ -480,29 +177,29 @@ commonUfsDirRebuildFromDirectory(void *data)
        } else if (tmpe.swap_file_sz != (size_t)sb.st_size) {
            debug(47, 1) ("commonUfsDirRebuildFromDirectory: SIZE MISMATCH %ld!=%ld\n",
                (long int) tmpe.swap_file_sz, (long int) sb.st_size);
-           commonUfsDirUnlinkFile(SD, filn);
+           sd->unlinkFile(filn);
            continue;
        }
        if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) {
-           commonUfsDirUnlinkFile(SD, filn);
-           rb->counts.badflags++;
+           sd->unlinkFile(filn);
+           counts.badflags++;
            continue;
        }
        e = storeGet(key);
        if (e && e->lastref >= tmpe.lastref) {
            /* key already exists, current entry is newer */
            /* keep old, ignore new */
-           rb->counts.dupcount++;
+           counts.dupcount++;
            continue;
        } else if (NULL != e) {
            /* URL already exists, this swapfile not being used */
            /* junk old, load new */
            storeRelease(e);    /* release old entry */
-           rb->counts.dupcount++;
+           counts.dupcount++;
        }
-       rb->counts.objcount++;
+       counts.objcount++;
        storeEntryDump(&tmpe, 5);
-       e = commonUfsDirAddDiskRestore(SD, key,
+       e = sd->addDiskRestore(key,
            filn,
            tmpe.swap_file_sz,
            tmpe.expires,
@@ -511,39 +208,37 @@ commonUfsDirRebuildFromDirectory(void *data)
            tmpe.lastmod,
            tmpe.refcount,      /* refcount */
            tmpe.flags,         /* flags */
-           (int) rb->flags.clean);
+           (int) flags.clean);
        storeDirSwapLog(e, SWAP_LOG_ADD);
     }
-    eventAdd("storeRebuild", commonUfsDirRebuildFromDirectory, rb, 0.0, 1);
+    eventAdd("storeRebuild", RebuildFromDirectory, this, 0.0, 1);
 }
 
 void
-commonUfsDirRebuildFromSwapLog(void *data)
+RebuildState::RebuildFromSwapLog(void *data)
 {
     RebuildState *rb = (RebuildState *)data;
-    SwapDir *SD = rb->sd;
+    rb->rebuildFromSwapLog();
+}
+
+void
+RebuildState::rebuildFromSwapLog()
+{
     StoreEntry *e = NULL;
-    storeSwapLogData s;
-    size_t ss = sizeof(storeSwapLogData);
-    int count;
-    int used;                  /* is swapfile already in use? */
-    int disk_entry_newer;      /* is the log entry newer than current entry? */
     double x;
-    assert(rb != NULL);
     /* load a number of objects per invocation */
-    for (count = 0; count < rb->speed; count++) {
-       if (fread(&s, ss, 1, rb->log) != 1) {
+    for (int count = 0; count < speed; count++) {
+        storeSwapLogData s;
+        size_t ss = sizeof(storeSwapLogData);
+       if (fread(&s, ss, 1, log) != 1) {
            debug(47, 1) ("Done reading %s swaplog (%d entries)\n",
-               rb->sd->path, rb->n_read);
-           fclose(rb->log);
-           rb->log = NULL;
-           store_dirs_rebuilding--;
-           commonUfsDirCloseTmpSwapLog(rb->sd);
-           storeRebuildComplete(&rb->counts);
-           cbdataFree(rb);
+               sd->path, n_read);
+           fclose(log);
+           log = NULL;
+           delete this;
            return;
        }
-       rb->n_read++;
+       n_read++;
        if (s.op <= SWAP_LOG_NOP)
            continue;
        if (s.op >= SWAP_LOG_MAX)
@@ -575,49 +270,51 @@ commonUfsDirRebuildFromSwapLog(void *data)
                storeExpireNow(e);
                storeReleaseRequest(e);
                if (e->swap_filen > -1) {
-                   commonUfsDirReplRemove(e);
-                   commonUfsDirMapBitReset(SD, e->swap_filen);
+                   sd->replacementRemove(e);
+                   sd->mapBitReset(e->swap_filen);
                    e->swap_filen = -1;
                    e->swap_dirn = -1;
                }
                storeRelease(e);
-               rb->counts.objcount--;
-               rb->counts.cancelcount++;
+               counts.objcount--;
+               counts.cancelcount++;
            }
            continue;
        } else {
-           x = log(++rb->counts.bad_log_op) / log(10.0);
+           x = ::log(++counts.bad_log_op) / ::log(10.0);
            if (0.0 == x - (double) (int) x)
                debug(47, 1) ("WARNING: %d invalid swap log entries found\n",
-                   rb->counts.bad_log_op);
-           rb->counts.invalid++;
+                   counts.bad_log_op);
+           counts.invalid++;
            continue;
        }
-       if ((++rb->counts.scancount & 0xFFF) == 0) {
+       if ((++counts.scancount & 0xFFF) == 0) {
            struct stat sb;
-           if (0 == fstat(fileno(rb->log), &sb))
-               storeRebuildProgress(SD->index,
-                   (int) sb.st_size / ss, rb->n_read);
+           if (0 == fstat(fileno(log), &sb))
+               storeRebuildProgress(sd->index,
+                   (int) sb.st_size / ss, n_read);
        }
-       if (!commonUfsDirValidFileno(SD, s.swap_filen, 0)) {
-           rb->counts.invalid++;
+       if (!sd->validFileno(s.swap_filen, 0)) {
+           counts.invalid++;
            continue;
        }
        if (EBIT_TEST(s.flags, KEY_PRIVATE)) {
-           rb->counts.badflags++;
+           counts.badflags++;
            continue;
        }
        e = storeGet(s.key);
-       used = commonUfsDirMapBitTest(SD, s.swap_filen);
+        int used;                      /* is swapfile already in use? */
+       used = sd->mapBitTest(s.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. */
-       disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0;
+       /* is the log entry newer than current entry? */
+       int disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0;
        if (used && !disk_entry_newer) {
            /* log entry is old, ignore it */
-           rb->counts.clashcount++;
+           counts.clashcount++;
            continue;
-       } else if (used && e && e->swap_filen == s.swap_filen && e->swap_dirn == SD->index) {
+       } else if (used && e && e->swap_filen == s.swap_filen && e->swap_dirn == sd->index) {
            /* swapfile taken, same URL, newer, update meta */
            if (e->store_status == STORE_OK) {
                e->lastref = s.timestamp;
@@ -626,7 +323,7 @@ commonUfsDirRebuildFromSwapLog(void *data)
                e->lastmod = s.lastmod;
                e->flags = s.flags;
                e->refcount += s.refcount;
-               commonUfsDirUnrefObj(SD, e);
+               sd->dereference(*e);
            } else {
                debug_trap("commonUfsDirRebuildFromSwapLog: bad condition");
                debug(47, 1) ("\tSee %s:%d\n", __FILE__, __LINE__);
@@ -639,7 +336,7 @@ commonUfsDirRebuildFromSwapLog(void *data)
             * caught this.  If the log is clean, there should never be a
             * newer entry. */
            debug(47, 1) ("WARNING: newer swaplog entry for dirno %d, fileno %08X\n",
-               SD->index, s.swap_filen);
+               sd->index, s.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
@@ -649,13 +346,13 @@ commonUfsDirRebuildFromSwapLog(void *data)
            /* 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(rb->flags.need_to_validate);
-           rb->counts.clashcount++;
+           assert(flags.need_to_validate);
+           counts.clashcount++;
            continue;
        } else if (e && !disk_entry_newer) {
            /* key already exists, current entry is newer */
            /* keep old, ignore new */
-           rb->counts.dupcount++;
+           counts.dupcount++;
            continue;
        } else if (e) {
            /* key already exists, this swapfile not being used */
@@ -663,22 +360,22 @@ commonUfsDirRebuildFromSwapLog(void *data)
            storeExpireNow(e);
            storeReleaseRequest(e);
            if (e->swap_filen > -1) {
-               commonUfsDirReplRemove(e);
+               sd->replacementRemove(e);
                /* Make sure we don't actually unlink the file */
-               commonUfsDirMapBitReset(SD, e->swap_filen);
+               sd->mapBitReset(e->swap_filen);
                e->swap_filen = -1;
                e->swap_dirn = -1;
            }
            storeRelease(e);
-           rb->counts.dupcount++;
+           counts.dupcount++;
        } else {
            /* URL doesnt exist, swapfile not in use */
            /* load new */
            (void) 0;
        }
        /* update store_swap_size */
-       rb->counts.objcount++;
-       e = commonUfsDirAddDiskRestore(SD, s.key,
+       counts.objcount++;
+       e = sd->addDiskRestore(s.key,
            s.swap_filen,
            s.swap_file_sz,
            s.expires,
@@ -687,946 +384,91 @@ commonUfsDirRebuildFromSwapLog(void *data)
            s.lastmod,
            s.refcount,
            s.flags,
-           (int) rb->flags.clean);
+           (int) flags.clean);
        storeDirSwapLog(e, SWAP_LOG_ADD);
     }
-    eventAdd("storeRebuild", commonUfsDirRebuildFromSwapLog, rb, 0.0, 1);
+    eventAdd("storeRebuild", RebuildFromSwapLog, this, 0.0, 1);
 }
 
 int
-commonUfsDirGetNextFile(RebuildState * rb, sfileno * filn_p, int *size)
+RebuildState::getNextFile(sfileno * filn_p, int *size)
 {
-    SwapDir *SD = rb->sd;
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata;
     int fd = -1;
-    int used = 0;
     int dirs_opened = 0;
     debug(47, 3) ("commonUfsDirGetNextFile: flag=%d, %d: /%02X/%02X\n",
-       rb->flags.init,
-       rb->sd->index,
-       rb->curlvl1,
-       rb->curlvl2);
-    if (rb->done)
+       flags.init,
+       sd->index,
+       curlvl1,
+       curlvl2);
+    if (done)
        return -2;
-    while (fd < 0 && rb->done == 0) {
+    while (fd < 0 && done == 0) {
        fd = -1;
-       if (0 == rb->flags.init) {      /* initialize, open first file */
-           rb->done = 0;
-           rb->curlvl1 = 0;
-           rb->curlvl2 = 0;
-           rb->in_dir = 0;
-           rb->flags.init = 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 == rb->in_dir) {  /* we need to read in a new directory */
-           snprintf(rb->fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X",
-               rb->sd->path,
-               rb->curlvl1, rb->curlvl2);
+       if (0 == in_dir) {      /* we need to read in a new directory */
+           snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X",
+               sd->path,
+               curlvl1, curlvl2);
            if (dirs_opened)
                return -1;
-           rb->td = opendir(rb->fullpath);
+           td = opendir(fullpath);
            dirs_opened++;
-           if (rb->td == NULL) {
+           if (td == NULL) {
                debug(47, 1) ("commonUfsDirGetNextFile: opendir: %s: %s\n",
-                   rb->fullpath, xstrerror());
+                   fullpath, xstrerror());
            } else {
-               rb->entry = readdir(rb->td);    /* skip . and .. */
-               rb->entry = readdir(rb->td);
-               if (rb->entry == NULL && errno == ENOENT)
+               entry = readdir(td);    /* skip . and .. */
+               entry = readdir(td);
+               if (entry == NULL && errno == ENOENT)
                    debug(47, 1) ("commonUfsDirGetNextFile: directory does not exist!.\n");
-               debug(47, 3) ("commonUfsDirGetNextFile: Directory %s\n", rb->fullpath);
+               debug(47, 3) ("commonUfsDirGetNextFile: Directory %s\n", fullpath);
            }
        }
-       if (rb->td != NULL && (rb->entry = readdir(rb->td)) != NULL) {
-           rb->in_dir++;
-           if (sscanf(rb->entry->d_name, "%x", &rb->fn) != 1) {
+       if (td != NULL && (entry = readdir(td)) != NULL) {
+           in_dir++;
+           if (sscanf(entry->d_name, "%x", &fn) != 1) {
                debug(47, 3) ("commonUfsDirGetNextFile: invalid %s\n",
-                   rb->entry->d_name);
+                   entry->d_name);
                continue;
            }
-           if (!commonUfsFilenoBelongsHere(rb->fn, rb->sd->index, rb->curlvl1, rb->curlvl2)) {
+           if (!UFSSwapDir::FilenoBelongsHere(fn, sd->index, curlvl1, curlvl2)) {
                debug(47, 3) ("commonUfsDirGetNextFile: %08X does not belong in %d/%d/%d\n",
-                   rb->fn, rb->sd->index, rb->curlvl1, rb->curlvl2);
+                   fn, sd->index, curlvl1, curlvl2);
                continue;
            }
-           used = commonUfsDirMapBitTest(SD, rb->fn);
-           if (used) {
+           if (sd->mapBitTest(fn)) {
                debug(47, 3) ("commonUfsDirGetNextFile: Locked, continuing with next.\n");
                continue;
            }
-           snprintf(rb->fullfilename, SQUID_MAXPATHLEN, "%s/%s",
-               rb->fullpath, rb->entry->d_name);
-           debug(47, 3) ("commonUfsDirGetNextFile: Opening %s\n", rb->fullfilename);
-           fd = file_open(rb->fullfilename, O_RDONLY | O_BINARY);
+           snprintf(fullfilename, SQUID_MAXPATHLEN, "%s/%s",
+               fullpath, entry->d_name);
+           debug(47, 3) ("commonUfsDirGetNextFile: Opening %s\n", fullfilename);
+           fd = file_open(fullfilename, O_RDONLY | O_BINARY);
            if (fd < 0)
-               debug(47, 1) ("commonUfsDirGetNextFile: %s: %s\n", rb->fullfilename, xstrerror());
+               debug(47, 1) ("commonUfsDirGetNextFile: %s: %s\n", fullfilename, xstrerror());
            else
                store_open_disk_fd++;
            continue;
        }
-       if (rb->td != NULL)
-           closedir(rb->td);
-       rb->td = NULL;
-       rb->in_dir = 0;
-       if (++rb->curlvl2 < ioinfo->l2)
+       if (td != NULL)
+           closedir(td);
+       td = NULL;
+       in_dir = 0;
+       if (sd->validL2(++curlvl2))
            continue;
-       rb->curlvl2 = 0;
-       if (++rb->curlvl1 < ioinfo->l1)
+       curlvl2 = 0;
+       if (sd->validL1(++curlvl1))
            continue;
-       rb->curlvl1 = 0;
-       rb->done = 1;
+       curlvl1 = 0;
+       done = 1;
     }
-    *filn_p = rb->fn;
+    *filn_p = fn;
     return fd;
 }
-
-/* Add a new object to the cache with empty memory copy and pointer to disk
- * use to rebuild store from disk. */
-StoreEntry *
-commonUfsDirAddDiskRestore(SwapDir * SD, const cache_key * key,
-    sfileno file_number,
-    size_t swap_file_sz,
-    time_t expires,
-    time_t timestamp,
-    time_t lastref,
-    time_t lastmod,
-    u_int32_t refcount,
-    u_int16_t flags,
-    int clean)
-{
-    StoreEntry *e = NULL;
-    debug(47, 5) ("commonUfsAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number);
-    /* if you call this you'd better be sure file_number is not 
-     * already in use! */
-    e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL);
-    e->store_status = STORE_OK;
-    storeSetMemStatus(e, NOT_IN_MEMORY);
-    e->swap_status = SWAPOUT_DONE;
-    e->swap_filen = file_number;
-    e->swap_dirn = SD->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 = flags;
-    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);
-    commonUfsDirMapBitSet(SD, e->swap_filen);
-    storeHashInsert(e, key);   /* do it after we clear KEY_PRIVATE */
-    commonUfsDirReplAdd(SD, e);
-    return e;
-}
-
-CBDATA_TYPE(RebuildState);
-
-void
-commonUfsDirRebuild(SwapDir * sd)
-{
-    RebuildState *rb;
-    int clean = 0;
-    int zero = 0;
-    FILE *fp;
-    EVH *func = NULL;
-    CBDATA_INIT_TYPE(RebuildState);
-    rb = cbdataAlloc(RebuildState);
-    rb->sd = sd;
-    rb->speed = opt_foreground_rebuild ? 1 << 30 : 50;
-    /*
-     * 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.
-     */
-    fp = commonUfsDirOpenTmpSwapLog(sd, &clean, &zero);
-    if (fp == NULL || zero) {
-       if (fp != NULL)
-           fclose(fp);
-       func = commonUfsDirRebuildFromDirectory;
-    } else {
-       func = commonUfsDirRebuildFromSwapLog;
-       rb->log = fp;
-       rb->flags.clean = (unsigned int) clean;
-    }
-    if (!clean)
-       rb->flags.need_to_validate = 1;
-    debug(47, 1) ("Rebuilding storage in %s (%s)\n",
-       sd->path, clean ? "CLEAN" : "DIRTY");
-    store_dirs_rebuilding++;
-    eventAdd("storeRebuild", func, rb, 0.0, 1);
-}
-
-void
-commonUfsDirCloseTmpSwapLog(SwapDir * sd)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata;
-    char *swaplog_path = xstrdup(commonUfsDirSwapLogFile(sd, NULL));
-    char *new_path = xstrdup(commonUfsDirSwapLogFile(sd, ".new"));
-    int fd;
-    file_close(ioinfo->swaplog_fd);
-#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_)
-    if (unlink(swaplog_path) < 0) {
-       debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror());
-       fatal("commonUfsDirCloseTmpSwapLog: unlink failed");
-    }
-#endif
-    if (xrename(new_path, swaplog_path) < 0) {
-       fatal("commonUfsDirCloseTmpSwapLog: rename failed");
-    }
-    fd = file_open(swaplog_path, O_WRONLY | O_CREAT | O_BINARY);
-    if (fd < 0) {
-       debug(50, 1) ("%s: %s\n", swaplog_path, xstrerror());
-       fatal("commonUfsDirCloseTmpSwapLog: Failed to open swap log.");
-    }
-    safe_free(swaplog_path);
-    safe_free(new_path);
-    ioinfo->swaplog_fd = fd;
-    debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", sd->index, fd);
-}
-
-FILE *
-commonUfsDirOpenTmpSwapLog(SwapDir * sd, int *clean_flag, int *zero_flag)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata;
-    char *swaplog_path = xstrdup(commonUfsDirSwapLogFile(sd, NULL));
-    char *clean_path = xstrdup(commonUfsDirSwapLogFile(sd, ".last-clean"));
-    char *new_path = xstrdup(commonUfsDirSwapLogFile(sd, ".new"));
-    struct stat log_sb;
-    struct stat clean_sb;
-    FILE *fp;
-    int fd;
-    if (stat(swaplog_path, &log_sb) < 0) {
-       debug(47, 1) ("Cache Dir #%d: No log file\n", sd->index);
-       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 (ioinfo->swaplog_fd >= 0)
-       file_close(ioinfo->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) {
-       debug(50, 1) ("%s: %s\n", new_path, xstrerror());
-       fatal("storeDirOpenTmpSwapLog: Failed to open swap log.");
-    }
-    ioinfo->swaplog_fd = fd;
-    /* open a read-only stream of the old log */
-    fp = fopen(swaplog_path, "rb");
-    if (fp == NULL) {
-       debug(50, 0) ("%s: %s\n", 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;
-}
-
-struct _clean_state {
-    char *cur;
-    char *newLog;
-    char *cln;
-    char *outbuf;
-    off_t outbuf_offset;
-    int fd;
-    RemovalPolicyWalker *walker;
-};
-
-#define CLEAN_BUF_SZ 16384
-
-/*
- * 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
-commonUfsDirWriteCleanStart(SwapDir * sd)
-{
-    struct _clean_state *state = (struct _clean_state *)xcalloc(1, sizeof(*state));
-#if HAVE_FCHMOD
-    struct stat sb;
-#endif
-    sd->log.clean.write = NULL;
-    sd->log.clean.state = NULL;
-    state->newLog = xstrdup(commonUfsDirSwapLogFile(sd, ".clean"));
-    state->fd = file_open(state->newLog, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
-    if (state->fd < 0) {
-       xfree(state->newLog);
-       xfree(state);
-       return -1;
-    }
-    state->cur = xstrdup(commonUfsDirSwapLogFile(sd, NULL));
-    state->cln = xstrdup(commonUfsDirSwapLogFile(sd, ".last-clean"));
-    state->outbuf = (char *)xcalloc(CLEAN_BUF_SZ, 1);
-    state->outbuf_offset = 0;
-    state->walker = sd->repl->WalkInit(sd->repl);
-    unlink(state->cln);
-    debug(47, 3) ("storeDirWriteCleanLogs: opened %s, FD %d\n",
-       state->newLog, state->fd);
-#if HAVE_FCHMOD
-    if (stat(state->cur, &sb) == 0)
-       fchmod(state->fd, sb.st_mode);
-#endif
-    sd->log.clean.write = commonUfsDirWriteCleanEntry;
-    sd->log.clean.state = state;
-    return 0;
-}
-
-/*
- * Get the next entry that is a candidate for clean log writing
- */
-const StoreEntry *
-commonUfsDirCleanLogNextEntry(SwapDir * sd)
-{
-    const StoreEntry *entry = NULL;
-    struct _clean_state *state = (struct _clean_state *)sd->log.clean.state;
-    if (state->walker)
-       entry = state->walker->Next(state->walker);
-    return entry;
-}
-
-/*
- * "write" an entry to the clean log file.
- */
-void
-commonUfsDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e)
-{
-    storeSwapLogData s;
-    static size_t ss = sizeof(storeSwapLogData);
-    struct _clean_state *state = (struct _clean_state *)sd->log.clean.state;
-    memset(&s, '\0', ss);
-    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;
-    xmemcpy(&s.key, e->key, MD5_DIGEST_CHARS);
-    xmemcpy(state->outbuf + state->outbuf_offset, &s, ss);
-    state->outbuf_offset += ss;
-    /* buffered write */
-    if (state->outbuf_offset + ss > CLEAN_BUF_SZ) {
-       if (FD_WRITE_METHOD(state->fd, state->outbuf, state->outbuf_offset) < 0) {
-           debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
-               state->newLog, xstrerror());
-           debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile not replaced.\n");
-           file_close(state->fd);
-           state->fd = -1;
-           unlink(state->newLog);
-           safe_free(state);
-           sd->log.clean.state = NULL;
-           sd->log.clean.write = NULL;
-           return;
-       }
-       state->outbuf_offset = 0;
-    }
-}
-
-void
-commonUfsDirWriteCleanDone(SwapDir * sd)
-{
-    int fd;
-    struct _clean_state *state = (struct _clean_state *)sd->log.clean.state;
-    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) {
-       debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n",
-           state->newLog, xstrerror());
-       debug(50, 0) ("storeDirWriteCleanLogs: Current swap logfile "
-           "not replaced.\n");
-       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.
-     */
-    commonUfsDirCloseSwapLog(sd);
-    /* save the fd value for a later test */
-    fd = state->fd;
-    /* rename */
-    if (state->fd >= 0) {
-#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_)
-       file_close(state->fd);
-       state->fd = -1;
-       if (unlink(state->cur) < 0)
-           debug(50, 0) ("storeDirWriteCleanLogs: unlinkd failed: %s, %s\n",
-               xstrerror(), state->cur);
-#endif
-       xrename(state->newLog, state->cur);
-    }
-    /* touch a timestamp file if we're not still validating */
-    if (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;
-    safe_free(state);
-    sd->log.clean.state = NULL;
-    sd->log.clean.write = NULL;
-}
-
-void
-storeSwapLogDataFree(void *s)
-{
-    memFree(s, MEM_SWAP_LOG_DATA);
-}
-
-void
-commonUfsDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) sd->fsdata;
-    storeSwapLogData *s = (storeSwapLogData *)memAllocate(MEM_SWAP_LOG_DATA);
-    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;
-    xmemcpy(s->key, e->key, MD5_DIGEST_CHARS);
-    file_write(ioinfo->swaplog_fd,
-       -1,
-       s,
-       sizeof(storeSwapLogData),
-       NULL,
-       NULL,
-       (FREE *) storeSwapLogDataFree);
-}
-
-void
-commonUfsDirNewfs(SwapDir * sd)
-{
-    debug(47, 3) ("Creating swap space in %s\n", sd->path);
-    commonUfsDirCreateDirectory(sd->path, 0);
-    commonUfsDirCreateSwapSubDirs(sd);
-}
-
-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
-commonUfsDirClean(int swap_index)
-{
-    DIR *dp = NULL;
-    struct dirent *de = NULL;
-    LOCAL_ARRAY(char, p1, MAXPATHLEN + 1);
-    LOCAL_ARRAY(char, p2, MAXPATHLEN + 1);
-#if USE_TRUNCATE
-    struct stat sb;
-#endif
-    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;
-    SwapDir *SD;
-    squidufsinfo_t *ioinfo;
-    N0 = n_dirs;
-    D0 = dir_index[swap_index % N0];
-    SD = &Config.cacheSwap.swapDirs[D0];
-    ioinfo = (squidufsinfo_t *) SD->fsdata;
-    N1 = ioinfo->l1;
-    D1 = (swap_index / N0) % N1;
-    N2 = ioinfo->l2;
-    D2 = ((swap_index / N0) / N1) % N2;
-    snprintf(p1, SQUID_MAXPATHLEN, "%s/%02X/%02X",
-       Config.cacheSwap.swapDirs[D0].path, D1, D2);
-    debug(36, 3) ("storeDirClean: Cleaning directory %s\n", p1);
-    dp = opendir(p1);
-    if (dp == NULL) {
-       if (errno == ENOENT) {
-           debug(36, 0) ("storeDirClean: WARNING: Creating %s\n", p1);
-#ifdef _SQUID_MSWIN_
-           if (mkdir(p1) == 0)
-#else
-           if (mkdir(p1, 0777) == 0)
-#endif
-               return 0;
-       }
-       debug(50, 0) ("storeDirClean: %s: %s\n", p1, xstrerror());
-       safeunlink(p1, 1);
-       return 0;
-    }
-    while ((de = readdir(dp)) != NULL && k < 20) {
-       if (sscanf(de->d_name, "%X", &swapfileno) != 1)
-           continue;
-       fn = swapfileno;        /* XXX should remove this cruft ! */
-       if (commonUfsDirValidFileno(SD, fn, 1))
-           if (commonUfsDirMapBitTest(SD, fn))
-               if (commonUfsFilenoBelongsHere(fn, D0, D1, D2))
-                   continue;
-#if USE_TRUNCATE
-       if (!stat(de->d_name, &sb))
-           if (sb.st_size == 0)
-               continue;
-#endif
-       files[k++] = swapfileno;
-    }
-    closedir(dp);
-    if (k == 0)
-       return 0;
-    qsort(files, k, sizeof(int), rev_int_sort);
-    if (k > 10)
-       k = 10;
-    for (n = 0; n < k; n++) {
-       debug(36, 3) ("storeDirClean: Cleaning file %08X\n", files[n]);
-       snprintf(p2, MAXPATHLEN + 1, "%s/%08X", p1, files[n]);
-#if USE_TRUNCATE
-       truncate(p2, 0);
-#else
-       safeunlink(p2, 0);
-#endif
-       statCounter.swap.files_cleaned++;
-    }
-    debug(36, 3) ("Cleaned %d unused files from %s\n", k, p1);
-    return k;
-}
-
-void
-commonUfsDirCleanEvent(void *unused)
-{
-    static int swap_index = 0;
-    int i;
-    int j = 0;
-    int n = 0;
-    /*
-     * Assert that there are AUFS cache_dirs configured, otherwise
-     * we should never be called.
-     */
-    assert(n_dirs);
-    if (NULL == dir_index) {
-       SwapDir *sd;
-       squidufsinfo_t *ioinfo;
-       /*
-        * Initialize the little array that translates AUFS cache_dir
-        * number into the Config.cacheSwap.swapDirs array index.
-        */
-       dir_index = (int *)xcalloc(n_dirs, sizeof(*dir_index));
-       for (i = 0, n = 0; i < Config.cacheSwap.n_configured; i++) {
-           sd = &Config.cacheSwap.swapDirs[i];
-           if (!commonUfsDirIs(sd))
-               continue;
-           dir_index[n++] = i;
-           ioinfo = (squidufsinfo_t *) sd->fsdata;
-           j += (ioinfo->l1 * ioinfo->l2);
-       }
-       assert(n == n_dirs);
-       /*
-        * Start the commonUfsDirClean() swap_index with a random
-        * value.  j equals the total number of AUFS level 2
-        * swap directories
-        */
-       swap_index = (int) (squid_random() % j);
-    }
-    if (0 == store_dirs_rebuilding) {
-       n = commonUfsDirClean(swap_index);
-       swap_index++;
-    }
-    eventAdd("storeDirClean", commonUfsDirCleanEvent, NULL,
-       15.0 * exp(-0.25 * n), 1);
-}
-
-int
-commonUfsDirIs(SwapDir * sd)
-{
-    if (strncmp(sd->type, "aufs", 4) == 0)
-       return 1;
-    if (strncmp(sd->type, "diskd", 5) == 0)
-       return 1;
-    if (strncmp(sd->type, "ufs", 3) == 0)
-       return 1;
-    return 0;
-}
-
-/*
- * Does swapfile number 'fn' belong in cachedir #F0,
- * level1 dir #F1, level2 dir #F2?
- */
-int
-commonUfsFilenoBelongsHere(int fn, int F0, int F1, int F2)
-{
-    int D1, D2;
-    int L1, L2;
-    int filn = fn;
-    squidufsinfo_t *ioinfo;
-    assert(F0 < Config.cacheSwap.n_configured);
-    ioinfo = (squidufsinfo_t *) Config.cacheSwap.swapDirs[F0].fsdata;
-    L1 = ioinfo->l1;
-    L2 = ioinfo->l2;
-    D1 = ((filn / L2) / L2) % L1;
-    if (F1 != D1)
-       return 0;
-    D2 = (filn / L2) % L2;
-    if (F2 != D2)
-       return 0;
-    return 1;
-}
-
-int
-commonUfsDirValidFileno(SwapDir * SD, sfileno filn, int flag)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata;
-    if (filn < 0)
-       return 0;
-    /*
-     * If flag is set it means out-of-range file number should
-     * be considered invalid.
-     */
-    if (flag)
-       if (filn > ioinfo->map->max_n_files)
-           return 0;
-    return 1;
-}
-
-void
-commonUfsDirMaintain(SwapDir * SD)
-{
-    StoreEntry *e = NULL;
-    int removed = 0;
-    int max_scan;
-    int max_remove;
-    double f;
-    RemovalPurgeWalker *walker;
-    /* We can't delete objects while rebuilding swap */
-    if (store_dirs_rebuilding) {
-       return;
-    } else {
-       f = (double) (SD->cur_size - SD->low_size) / (SD->max_size - SD->low_size);
-       f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f;
-       max_scan = (int) (f * 400.0 + 100.0);
-       max_remove = (int) (f * 70.0 + 10.0);
-       /*
-        * This is kinda cheap, but so we need this priority hack?
-        */
-    }
-    debug(47, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n",
-       f, max_scan, max_remove);
-    walker = SD->repl->PurgeInit(SD->repl, max_scan);
-    while (1) {
-       if (SD->cur_size < SD->low_size)
-           break;
-       if (removed >= max_remove)
-           break;
-       e = walker->Next(walker);
-       if (!e)
-           break;              /* no more objects */
-       removed++;
-       storeRelease(e);
-    }
-    walker->Done(walker);
-    debug(47, (removed ? 2 : 3)) ("commonUfsDirMaintain: %s removed %d/%d f=%.03f max_scan=%d\n",
-       SD->path, removed, max_remove, f, max_scan);
-}
-
-#if 0
-/*
- * commonUfsDirCheckObj
- *
- * This routine is called by storeDirSelectSwapDir to see if the given
- * object is able to be stored on this filesystem. AUFS filesystems will
- * happily store anything as long as the LRU time isn't too small.
- */
-int
-commonUfsDirCheckObj(SwapDir * SD, const StoreEntry * e)
-{
-    int loadav;
-    int ql;
-
-#if OLD_UNUSED_CODE
-    if (commonUfsDirExpiredReferenceAge(SD) < 300) {
-       debug(47, 3) ("commonUfsDirCheckObj: NO: LRU Age = %d\n",
-           commonUfsDirExpiredReferenceAge(SD));
-       /* store_check_cachable_hist.no.lru_age_too_low++; */
-       return -1;
-    }
-#endif
-    ql = aioQueueSize();
-    if (ql == 0)
-       loadav = 0;
-    loadav = ql * 1000 / MAGIC1;
-    debug(47, 9) ("commonUfsDirCheckObj: load=%d\n", loadav);
-    return loadav;
-}
-#endif
-/*
- * commonUfsDirRefObj
- *
- * This routine is called whenever an object is referenced, so we can
- * maintain replacement information within the storage fs.
- */
-void
-commonUfsDirRefObj(SwapDir * SD, StoreEntry * e)
-{
-    debug(47, 3) ("commonUfsDirRefObj: referencing %p %d/%d\n", e, e->swap_dirn,
-       e->swap_filen);
-    if (SD->repl->Referenced)
-       SD->repl->Referenced(SD->repl, e, &e->repl);
-}
-
-/*
- * commonUfsDirUnrefObj
- * This routine is called whenever the last reference to an object is
- * removed, to maintain replacement information within the storage fs.
- */
-void
-commonUfsDirUnrefObj(SwapDir * SD, StoreEntry * e)
-{
-    debug(47, 3) ("commonUfsDirUnrefObj: referencing %p %d/%d\n", e, e->swap_dirn,
-       e->swap_filen);
-    if (SD->repl->Dereferenced)
-       SD->repl->Dereferenced(SD->repl, e, &e->repl);
-}
-
-/*
- * commonUfsDirUnlinkFile
- *
- * 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
-commonUfsDirUnlinkFile(SwapDir * SD, sfileno f)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *)SD->fsdata;
-    debug(79, 3) ("commonUfsDirUnlinkFile: unlinking fileno %08X\n", f);
-    /* commonUfsDirMapBitReset(SD, f); */
-    assert(ioinfo->io.storeDirUnlinkFile);
-    ioinfo->io.storeDirUnlinkFile(commonUfsDirFullPath(SD, f, NULL));
-}
-
-
-/*
- * Add and remove the given StoreEntry from the replacement policy in
- * use.
- */
-
-void
-commonUfsDirReplAdd(SwapDir * SD, StoreEntry * e)
-{
-    debug(47, 4) ("commonUfsDirReplAdd: added node %p to dir %d\n", e,
-       SD->index);
-    SD->repl->Add(SD->repl, e, &e->repl);
-}
-
-
-void
-commonUfsDirReplRemove(StoreEntry * e)
-{
-    SwapDir *SD;
-    if (e->swap_dirn < 0)
-       return;
-    SD = INDEXSD(e->swap_dirn);
-    debug(47, 4) ("commonUfsDirReplRemove: remove node %p from dir %d\n", e,
-       SD->index);
-    SD->repl->Remove(SD->repl, e, &e->repl);
-}
-
-
-
-/* ========== LOCAL FUNCTIONS ABOVE, GLOBAL FUNCTIONS BELOW ========== */
-
-void
-commonUfsDirStats(SwapDir * SD, StoreEntry * sentry)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *)SD->fsdata;
-    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", ioinfo->l1);
-    storeAppendPrintf(sentry, "Second level subdirectories: %d\n", ioinfo->l2);
-    storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size);
-    storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size);
-    storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n",
-       100.0 * SD->cur_size / SD->max_size);
-    storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n",
-       ioinfo->map->n_files_in_map, ioinfo->map->max_n_files,
-       percent(ioinfo->map->n_files_in_map, ioinfo->map->max_n_files));
-    x = storeDirGetUFSStats(SD->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,
-           percent(totl_kb - free_kb, totl_kb));
-       storeAppendPrintf(sentry, "Filesystem Inodes in use: %d/%d (%d%%)\n",
-           totl_in - free_in,
-           totl_in,
-           percent(totl_in - free_in, totl_in));
-    }
-    storeAppendPrintf(sentry, "Flags:");
-    if (SD->flags.selected)
-       storeAppendPrintf(sentry, " SELECTED");
-    if (SD->flags.read_only)
-       storeAppendPrintf(sentry, " READ-ONLY");
-    storeAppendPrintf(sentry, "\n");
-}
-
-#if 0
-static struct cache_dir_option options[] =
-{
-#if NOT_YET_DONE
-    {"L1", commonUfsDirParseL1, commonUfsDirDumpL1},
-    {"L2", commonUfsDirParseL2, commonUfsDirDumpL2},
-#endif
-    {NULL, NULL}
-};
-
-/*
- * commonUfsDirReconfigure
- *
- * This routine is called when the given swapdir needs reconfiguring 
- */
-static void
-commonUfsDirReconfigure(SwapDir * sd, int index, char *path)
-{
-    int i;
-    int size;
-    int l1;
-    int l2;
-
-    i = GetInteger();
-    size = i << 10;            /* Mbytes to kbytes */
-    if (size <= 0)
-       fatal("commonUfsDirReconfigure: invalid size value");
-    i = GetInteger();
-    l1 = i;
-    if (l1 <= 0)
-       fatal("commonUfsDirReconfigure: invalid level 1 directories value");
-    i = GetInteger();
-    l2 = i;
-    if (l2 <= 0)
-       fatal("commonUfsDirReconfigure: invalid level 2 directories value");
-
-    /* just reconfigure it */
-    if (size == sd->max_size)
-       debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KB\n",
-           path, size);
-    else
-       debug(3, 1) ("Cache dir '%s' size changed to %d KB\n",
-           path, size);
-    sd->max_size = size;
-
-    parse_cachedir_options(sd, options, 0);
-
-    return;
-}
-
-#endif
-
-void
-commonUfsDirDump(StoreEntry * entry, SwapDir * s)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) s->fsdata;
-    storeAppendPrintf(entry, " %d %d %d",
-       s->max_size >> 10,
-       ioinfo->l1,
-       ioinfo->l2);
-}
-
-/*
- * Only "free" the filesystem specific stuff here
- */
-void
-commonUfsDirFree(SwapDir * s)
-{
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) s->fsdata;
-    if (ioinfo->swaplog_fd > -1) {
-       file_close(ioinfo->swaplog_fd);
-       ioinfo->swaplog_fd = -1;
-    }
-    filemapFreeMemory(ioinfo->map);
-    xfree(ioinfo);
-    s->fsdata = NULL;          /* Will aid debugging... */
-}
-
-
-char *
-commonUfsDirFullPath(SwapDir * SD, sfileno filn, char *fullpath)
-{
-    LOCAL_ARRAY(char, fullfilename, SQUID_MAXPATHLEN);
-    squidufsinfo_t *ioinfo = (squidufsinfo_t *) SD->fsdata;
-    int L1 = ioinfo->l1;
-    int L2 = ioinfo->l2;
-    if (!fullpath)
-       fullpath = fullfilename;
-    fullpath[0] = '\0';
-    snprintf(fullpath, SQUID_MAXPATHLEN, "%s/%02X/%02X/%08X",
-       SD->path,
-       ((filn / L2) / L2) % L1,
-       (filn / L2) % L2,
-       filn);
-    return fullpath;
-}
-
-/*
- * commonUfsCleanupDoubleCheck
- *
- * This is called by storeCleanup() if -S was given on the command line.
- */
-int
-commonUfsCleanupDoubleCheck(SwapDir * sd, StoreEntry * e)
-{
-    struct stat sb;
-    if (stat(commonUfsDirFullPath(sd, e->swap_filen, NULL), &sb) < 0) {
-       debug(47, 0) ("commonUfsCleanupDoubleCheck: MISSING SWAP FILE\n");
-       debug(47, 0) ("commonUfsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen);
-       debug(47, 0) ("commonUfsCleanupDoubleCheck: PATH %s\n",
-           commonUfsDirFullPath(sd, e->swap_filen, NULL));
-       storeEntryDump(e, 0);
-       return -1;
-    }
-    if ((off_t)e->swap_file_sz != sb.st_size) {
-       debug(47, 0) ("commonUfsCleanupDoubleCheck: SIZE MISMATCH\n");
-       debug(47, 0) ("commonUfsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen);
-       debug(47, 0) ("commonUfsCleanupDoubleCheck: PATH %s\n",
-           commonUfsDirFullPath(sd, e->swap_filen, NULL));
-       debug(47, 0) ("commonUfsCleanupDoubleCheck: ENTRY SIZE: %ld, FILE SIZE: %ld\n",
-           (long int) e->swap_file_sz, (long int) sb.st_size);
-       storeEntryDump(e, 0);
-       return -1;
-    }
-    return 0;
-}
index 838012233fb556fc9244589a07e27233484211cf..6d920ad04cabdf6ace89ee220655fbc3bc4ee5ff 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ufscommon.h,v 1.1 2002/10/12 09:45:56 robertc Exp $
+ * $Id: ufscommon.h,v 1.2 2002/12/27 10:26:34 robertc Exp $
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
  * ----------------------------------------------------------
 #define DefaultLevelTwoDirs     256
 #define STORE_META_BUFSZ 4096
 
-typedef struct _iospecific_t iospecific_t;
-struct _iospecific_t {
-    void (*storeDirUnlinkFile) (char *);
-};
+/* Common UFS routines */
+FREE storeSwapLogDataFree;
+#include "SwapDir.h"
 
-typedef struct _squidufsinfo_t squidufsinfo_t;
-struct _squidufsinfo_t {
-    int swaplog_fd;
-    int l1;
-    int l2;
+class UFSStrategy;
+
+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();
+  virtual void init();
+  virtual void newFileSystem();
+  virtual void dump(StoreEntry &) const;
+  ~UFSSwapDir();
+  virtual bool doubleCheck(StoreEntry &);
+  virtual void unlink(StoreEntry &) = 0;
+  virtual void statfs(StoreEntry &)const;
+  virtual void maintainfs();
+  virtual int canStore(StoreEntry const &)const = 0;
+  virtual void reference(StoreEntry &);
+  virtual void dereference(StoreEntry &);
+  virtual StoreIOState::Pointer createStoreIO(StoreEntry &, STFNCB *, STIOCB *, void *);
+  virtual StoreIOState::Pointer openStoreIO(StoreEntry &, STFNCB *, 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(int, char *);
+
+  void unlinkFile(sfileno f);
+  virtual void unlinkFile (char const *) = 0;
+  // 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,
+    size_t swap_file_sz,
+    time_t expires,
+    time_t timestamp,
+    time_t lastref,
+    time_t lastmod,
+    u_int32_t refcount,
+    u_int16_t flags,
+    int clean);
+  int validFileno(sfileno filn, int flag) const;
+  int mapBitAllocate();
+    void *fsdata;
+
+    bool validL2(int) const;
+    bool validL1(int) const;
+
+    void replacementAdd(StoreEntry *e);
+    void replacementRemove(StoreEntry *e);
+protected:
     fileMap *map;
     int suggest;
-    iospecific_t io;
+    int l1;
+    int l2;
+private:
+    static int NumberOfUFSDirs;
+    static int * UFSDirToGlobalDirMapping;
+    bool pathIsDirectory(const char *path)const;
+    int swaplog_fd;
+  static EVH CleanEvent;
+  void initBitmap();
+  bool verifyCacheDirs();
+  void rebuild();
+  int createDirectory(const char *path, int);
+  void createSwapSubDirs();
+  void dumpEntry(StoreEntry &) const;
+  char *logFile(char const *ext = NULL)const;
+
+};
+
+#include "RefCount.h"
+
+class IORequestor : public RefCountable{
+  public:
+    typedef RefCount<IORequestor> Pointer;
+    virtual void ioCompletedNotification() = 0;
+    virtual void closeCompleted() = 0;
+    virtual void readCompleted(const char *buf, int len, int errflag) = 0;
+    virtual void writeCompleted(int errflag, size_t len) = 0;
+};
+
+class DiskFile : public RefCountable {
+  public:
+    typedef RefCount<DiskFile> Pointer;
+    virtual void deleteSelf() const = 0;
+    virtual void open (int, mode_t, IORequestor::Pointer) = 0;
+    virtual void create (int, mode_t, IORequestor::Pointer) = 0;
+    virtual void read(char *, off_t, size_t) = 0;
+    virtual void write(char const *buf, size_t size, off_t offset, FREE *free_func) = 0;
+    virtual bool canRead() const = 0;
+    virtual bool canWrite() const {return true;}
+    /* During miogration only */
+    virtual int getFD() const {return -1;}
+    virtual bool error() const = 0;
+};
+
+/* UFS dir specific IO calls */
+class UFSStrategy
+{
+public:
+  virtual bool shedLoad() = 0;
+  virtual void deleteSelf() const = 0;
+  virtual void openFailed(){}
+  virtual int load(){return -1;}
+  virtual StoreIOState::Pointer createState(SwapDir *, StoreEntry *, STIOCB *, void *)const = 0;
+  /* UFS specific */
+  virtual DiskFile::Pointer newFile (char const *path) = 0;
+  StoreIOState::Pointer open(SwapDir *, StoreEntry *, STFNCB *,
+    STIOCB *, void *);
+  StoreIOState::Pointer create(SwapDir *, StoreEntry *, STFNCB *,
+    STIOCB *, void *);
+  /* virtual void strategyStats(StoreEntry *sentry) const = 0; */
+  /* virtual void dumpCacheDirParams(StoreEntry * e, const char *option) const = 0; */
+};
+
+/* Common ufs-store-dir logic */
+class UFSStoreState : public storeIOState, public IORequestor {
+  public:
+    virtual void deleteSelf() const = 0;
+    UFSStoreState();
+    ~UFSStoreState();
+// protected:
+    DiskFile::Pointer 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 *buf, size_t size, off_t offset, FREE * free_func);
+  protected:
+    class _queued_read {
+      public:
+       void *operator new(size_t);
+       void operator delete (void *);
+       char *buf;
+       size_t size;
+       off_t offset;
+       STRCB *callback;
+       void *callback_data;
+      private:
+       static MemPool *Pool;
+    };
+    class _queued_write {
+      public:
+       void *operator new(size_t);
+       void operator delete (void *);
+       char *buf;
+       size_t size;
+       off_t offset;
+       FREE *free_func;
+      private:
+       static MemPool *Pool;
+    };
+    link_list *pending_reads;
+    link_list *pending_writes;
+    void queueRead(char *, size_t, off_t, STRCB *, void *);
+    void queueWrite(char *, size_t, off_t, FREE *);
+    bool kickReadQueue();
+    bool kickWriteQueue();
+    char *read_buf;
+};
+
+class RebuildState : public RefCountable {
+public:
+    void *operator new(size_t);
+    void operator delete(void *);
+    void deleteSelf() const;
+    static EVH RebuildFromDirectory;
+    static EVH RebuildFromSwapLog;
+
+    ~RebuildState();
+    UFSSwapDir *sd;
+    int n_read;
+    FILE *log;
+    int speed;
+    int curlvl1;
+    int curlvl2;
+    struct {
+       unsigned int need_to_validate:1;
+       unsigned int clean:1;
+       unsigned int init:1;
+    } flags;
+    int done;
+    int in_dir;
+    int fn;
+    struct dirent *entry;
+    DIR *td;
+    char fullpath[SQUID_MAXPATHLEN];
+    char fullfilename[SQUID_MAXPATHLEN];
+    struct _store_rebuild_data counts;
+private:
+    CBDATA_CLASS(RebuildState);
+    void rebuildFromDirectory();
+    void rebuildFromSwapLog();
+    int getNextFile(sfileno *, int *size);
 };
 
-/* Common UFS routines */
-void commonUfsDirSwapLog(const SwapDir * sd, const StoreEntry * e, int op);
-FREE storeSwapLogDataFree;
-void commonUfsDirWriteCleanDone(SwapDir * sd);
-const StoreEntry *commonUfsDirCleanLogNextEntry(SwapDir * sd);
-void commonUfsDirCloseSwapLog(SwapDir * sd);
-int commonUfsDirWriteCleanStart(SwapDir * sd);
-void commonUfsDirInit(SwapDir * sd);
-void commonUfsDirUnlinkFile(SwapDir * SD, sfileno f);
-void commonUfsDirOpenSwapLog(SwapDir * sd);
-void commonUfsDirNewfs(SwapDir * sd);
-void commonUfsDirMaintain(SwapDir * SD);
-void commonUfsDirRefObj(SwapDir * SD, StoreEntry * e);
-void commonUfsDirUnrefObj(SwapDir * SD, StoreEntry * e);
-void commonUfsDirReplAdd(SwapDir * SD, StoreEntry * e);
-void commonUfsDirReplRemove(StoreEntry * e);
-void commonUfsDirStats(SwapDir * SD, StoreEntry * sentry);
-void commonUfsDirDump(StoreEntry * entry, SwapDir * s);
-void commonUfsDirFree(SwapDir * s);
-char *commonUfsDirFullPath(SwapDir * SD, sfileno filn, char *fullpath);
-int commonUfsCleanupDoubleCheck(SwapDir * sd, StoreEntry * e);
-int commonUfsDirMapBitAllocate(SwapDir * SD);
-void commonUfsDirMapBitReset(SwapDir * SD, sfileno filn);
 
 #endif /* SQUID_UFSCOMMON_H */
index 2c474cc468f24cb73c0f75886c260ffc2b3311b7..b8f62c27aa1a20177c91fa7edd34a346e88112b3 100644 (file)
@@ -1,9 +1,11 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.am,v 1.1 2002/11/21 12:35:53 robertc Exp $
+#  $Id: Makefile.am,v 1.2 2002/12/27 10:26:40 robertc Exp $
 #
 
+AUTOMAKE_OPTIONS = subdir-objects
+
 AM_CFLAGS = -Werror -Wall
 AM_CXXFLAGS = -Werror -Wall
 
@@ -19,7 +21,6 @@ check_PROGRAMS= refcount
 
 refcount_SOURCES = refcount.cc
 
-
 ## membanger won't link today. Bitrot..
 ##CC   = gcc
 ##CFLAGS       = -g -Wall -I../include -I../src