From: robertc <> Date: Fri, 27 Dec 2002 17:26:32 +0000 (+0000) Subject: apply unify io patch to simplify IO code for diskd/aufs/ufs X-Git-Tag: SQUID_3_0_PRE1~486 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d3b3ab859857da0851f9c7de916b6df261ba43ae;p=thirdparty%2Fsquid.git apply unify io patch to simplify IO code for diskd/aufs/ufs --- diff --git a/configure.in b/configure.in index 146835df69..35e42a1b48 100644 --- a/configure.in +++ b/configure.in @@ -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) diff --git a/src/Makefile.am b/src/Makefile.am index 7dc50d5b35..3a56044fdd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/Store.h b/src/Store.h index 249942cc43..e338dd4abc 100644 --- a/src/Store.h +++ b/src/Store.h @@ -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 *); diff --git a/src/StoreClient.h b/src/StoreClient.h index e6be253a19..06067f0c16 100644 --- a/src/StoreClient.h +++ b/src/StoreClient.h @@ -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 index 0000000000..e335091634 --- /dev/null +++ b/src/StoreIOState.cc @@ -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 index 0000000000..f0800726ac --- /dev/null +++ b/src/StoreIOState.h @@ -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 Pointer; +}; + +#endif /* SQUID_STOREIOSTATE_H */ diff --git a/src/SwapDir.cc b/src/SwapDir.cc new file mode 100644 index 0000000000..136fa51ab8 --- /dev/null +++ b/src/SwapDir.cc @@ -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 index 0000000000..2d7d03ac77 --- /dev/null +++ b/src/SwapDir.h @@ -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 */ diff --git a/src/authenticate.cc b/src/authenticate.cc index 4225b932e4..a0fe402c28 100644 --- a/src/authenticate.cc +++ b/src/authenticate.cc @@ -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 (memPoolAlloc(pool)); + return memPoolAlloc(pool); } AuthUser::AuthUser (const char *scheme) : diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 3d063d5689..6e27c4f841 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -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(xcalloc(swap->n_allocated, sizeof(SwapDir))); + swap->swapDirs = static_cast(xcalloc(swap->n_allocated, sizeof(SwapDir *))); } if (swap->n_allocated == swap->n_configured) { - SwapDir *tmp; + SwapDir **tmp; swap->n_allocated <<= 1; - tmp = static_cast(xcalloc(swap->n_allocated, sizeof(SwapDir))); - xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir)); + tmp = static_cast(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; diff --git a/src/client_side_reply.cc b/src/client_side_reply.cc index 39ff5b288a..6b0c3dd32f 100644 --- a/src/client_side_reply.cc +++ b/src/client_side_reply.cc @@ -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 */ diff --git a/src/fs/aufs/async_io.cc b/src/fs/aufs/async_io.cc index fe8d3854b8..3f4fdf8ad1 100644 --- a/src/fs/aufs/async_io.cc +++ b/src/fs/aufs/async_io.cc @@ -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 @@ -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"); } diff --git a/src/fs/aufs/store_asyncufs.h b/src/fs/aufs/store_asyncufs.h index f8c6134922..167f5218e3 100644 --- a/src/fs/aufs/store_asyncufs.h +++ b/src/fs/aufs/store_asyncufs.h @@ -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 diff --git a/src/fs/aufs/store_dir_aufs.cc b/src/fs/aufs/store_dir_aufs.cc index e0b89e6c9d..45cf1efa8e 100644 --- a/src/fs/aufs/store_dir_aufs.cc +++ b/src/fs/aufs/store_dir_aufs.cc @@ -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 @@ -38,17 +38,12 @@ #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(); diff --git a/src/fs/aufs/store_io_aufs.cc b/src/fs/aufs/store_io_aufs.cc index 7ceebdebd1..f908d2f873 100644 --- a/src/fs/aufs/store_io_aufs.cc +++ b/src/fs/aufs/store_io_aufs.cc @@ -7,322 +7,310 @@ #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(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(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(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 (((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 (((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(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(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(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(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"); } diff --git a/src/fs/coss/store_coss.h b/src/fs/coss/store_coss.h index 0dd4f41e5c..630f46ef89 100644 --- a/src/fs/coss/store_coss.h +++ b/src/fs/coss/store_coss.h @@ -1,6 +1,8 @@ #ifndef __COSS_H__ #define __COSS_H__ +#include "SwapDir.h" + #ifndef COSS_MEMBUF_SZ #define COSS_MEMBUF_SZ 1048576 #endif @@ -19,12 +21,12 @@ #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 diff --git a/src/fs/coss/store_dir_coss.cc b/src/fs/coss/store_dir_coss.cc index 98e3559e2a..09b255c081 100644 --- a/src/fs/coss/store_dir_coss.cc +++ b/src/fs/coss/store_dir_coss.cc @@ -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 @@ -39,18 +39,18 @@ #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; } diff --git a/src/fs/coss/store_io_coss.cc b/src/fs/coss/store_io_coss.cc index 92399b05c1..f1b4c01838 100644 --- a/src/fs/coss/store_io_coss.cc +++ b/src/fs/coss/store_io_coss.cc @@ -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 @@ -38,24 +38,44 @@ #include #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(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(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(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(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); } diff --git a/src/fs/diskd/diskd.cc b/src/fs/diskd/diskd.cc index c83b96cb07..f001979054 100644 --- a/src/fs/diskd/diskd.cc +++ b/src/fs/diskd/diskd.cc @@ -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: diff --git a/src/fs/diskd/store_dir_diskd.cc b/src/fs/diskd/store_dir_diskd.cc index e0486b7bea..72f26dfbd6 100644 --- a/src/fs/diskd/store_dir_diskd.cc +++ b/src/fs/diskd/store_dir_diskd.cc @@ -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 @@ -44,65 +44,44 @@ #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(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(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(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(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(((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(((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(((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(((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"); diff --git a/src/fs/diskd/store_diskd.h b/src/fs/diskd/store_diskd.h index 8833fabc05..a1a9f4ed7a 100644 --- a/src/fs/diskd/store_diskd.h +++ b/src/fs/diskd/store_diskd.h @@ -16,53 +16,95 @@ * 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 diff --git a/src/fs/diskd/store_io_diskd.cc b/src/fs/diskd/store_io_diskd.cc index d97d0384f9..35e6114cdf 100644 --- a/src/fs/diskd/store_io_diskd.cc +++ b/src/fs/diskd/store_io_diskd.cc @@ -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 @@ -42,257 +42,503 @@ #include #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(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(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(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; } + + diff --git a/src/fs/null/store_null.cc b/src/fs/null/store_null.cc index 15e68a8ebe..2708215b37 100644 --- a/src/fs/null/store_null.cc +++ b/src/fs/null/store_null.cc @@ -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 @@ -39,21 +39,28 @@ #include #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; } diff --git a/src/fs/ufs/store_dir_ufs.cc b/src/fs/ufs/store_dir_ufs.cc index 74dd6c28d9..af94ce5006 100644 --- a/src/fs/ufs/store_dir_ufs.cc +++ b/src/fs/ufs/store_dir_ufs.cc @@ -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 @@ -39,12 +39,11 @@ #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(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(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(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(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(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; +} diff --git a/src/fs/ufs/store_io_ufs.cc b/src/fs/ufs/store_io_ufs.cc index c13ff03911..e53320a3a2 100644 --- a/src/fs/ufs/store_io_ufs.cc +++ b/src/fs/ufs/store_io_ufs.cc @@ -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 @@ -38,228 +38,533 @@ #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(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(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(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(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 (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 (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; } diff --git a/src/fs/ufs/store_ufs.h b/src/fs/ufs/store_ufs.h index 8568c00218..210809a16c 100644 --- a/src/fs/ufs/store_ufs.h +++ b/src/fs/ufs/store_ufs.h @@ -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 diff --git a/src/protos.h b/src/protos.h index 280c3b5033..b0e6f11921 100644 --- a/src/protos.h +++ b/src/protos.h @@ -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 diff --git a/src/squid.h b/src/squid.h index a0c6b399e5..8a8095e5ed 100644 --- a/src/squid.h +++ b/src/squid.h @@ -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) diff --git a/src/stat.cc b/src/stat.cc index 8280135483..975113bb60 100644 --- a/src/stat.cc +++ b/src/stat.cc @@ -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); } diff --git a/src/store.cc b/src/store.cc index 3ba1d0bd59..05c7ce772e 100644 --- a/src/store.cc +++ b/src/store.cc @@ -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 diff --git a/src/store_client.cc b/src/store_client.cc index 170bad8c37..53f0405482 100644 --- a/src/store_client.cc +++ b/src/store_client.cc @@ -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; diff --git a/src/store_dir.cc b/src/store_dir.cc index ce405865e0..be2baf223a 100644 --- a/src/store_dir.cc +++ b/src/store_dir.cc @@ -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++; diff --git a/src/store_io.cc b/src/store_io.cc index 1b7da2b6ef..c57d281c9c 100644 --- a/src/store_io.cc +++ b/src/store_io.cc @@ -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); } /* diff --git a/src/store_rebuild.cc b/src/store_rebuild.cc index 6c955934a5..ad6a6564bc 100644 --- a/src/store_rebuild.cc +++ b/src/store_rebuild.cc @@ -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); } diff --git a/src/store_swapin.cc b/src/store_swapin.cc index eda42b4436..6fb75a76d8 100644 --- a/src/store_swapin.cc +++ b/src/store_swapin.cc @@ -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; diff --git a/src/store_swapout.cc b/src/store_swapout.cc index 470ee442ac..57de1ac072 100644 --- a/src/store_swapout.cc +++ b/src/store_swapout.cc @@ -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; diff --git a/src/structs.h b/src/structs.h index cbbeea60fe..1f47584df9 100644 --- a/src/structs.h +++ b/src/structs.h @@ -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 */ diff --git a/src/typedefs.h b/src/typedefs.h index 20cfced746..c68b5e7403 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -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); diff --git a/src/ufscommon.cc b/src/ufscommon.cc index 8c7b6d0330..f64c5af1f0 100644 --- a/src/ufscommon.cc +++ b/src/ufscommon.cc @@ -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 @@ -34,377 +34,74 @@ #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(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; -} diff --git a/src/ufscommon.h b/src/ufscommon.h index 838012233f..6d920ad04c 100644 --- a/src/ufscommon.h +++ b/src/ufscommon.h @@ -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/ * ---------------------------------------------------------- @@ -39,43 +39,220 @@ #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 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 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 */ diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am index 2c474cc468..b8f62c27aa 100644 --- a/test-suite/Makefile.am +++ b/test-suite/Makefile.am @@ -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