From: hno <> Date: Fri, 9 Jun 2000 00:05:30 +0000 (+0000) Subject: Modular policy implementation. See programmers guide for API details. X-Git-Tag: SQUID_3_0_PRE1~1933 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6a566b9c9fa4d40f154a60497e332bc9067b4fc8;p=thirdparty%2Fsquid.git Modular policy implementation. See programmers guide for API details. This also includes Adrians improved store I/O callback handler model. --- diff --git a/configure.in b/configure.in index 7f2aaa91fb..f8b0fad3c3 100644 --- a/configure.in +++ b/configure.in @@ -3,13 +3,13 @@ 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.192 2000/05/31 08:57:08 hno Exp $ +dnl $Id: configure.in,v 1.193 2000/06/08 18:05:30 hno Exp $ dnl dnl dnl AC_INIT(src/main.c) AC_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.192 $)dnl +AC_REVISION($Revision: 1.193 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AC_CONFIG_AUX_DIR(cfgaux) @@ -322,6 +322,49 @@ AC_SUBST(STORE_MODULES) STORE_OBJS="fs/`echo $STORE_MODULES|sed -e's% %.a fs/%g'`.a" AC_SUBST(STORE_OBJS) +dnl --enable-heap-replacement compability option +AC_ARG_ENABLE(heap-replacement, +[ --enable-heap-replacement + Backwards compability option. Please use the + new --enable-removal-policies directive instead.], +[ if test "$enableval" = "yes" ; then + echo "--enable-heap-replacement is obsolete. please use the new" + echo "--enable-removal-policies directive instead" + sleep 5 + REPL_POLICIES="heap" + fi +]) + +AC_ARG_ENABLE(removal_policies, +[ --enable-removal-policies=\"list of policies\" + Build support for the list of removal policies. + The default is only to build the "lru" module. + See src/repl for a list of available modules, or + Programmers Guide section 9.9 for details on how + to build your custom policy], +[ case $enableval in + yes) + for module in $srcdir/src/repl/*; do + if test -f $module/Makefile.in; then + REPL_POLICIES="$REPL_POLICIES `basename $module`" + fi + done + ;; + no) + ;; + *) REPL_POLICIES="`echo $enableval| sed -e 's/,/ /g;s/ */ /g'`" + ;; + esac +], +[ if test -z "$REPL_POLICIES"; then + REPL_POLICIES="lru" + fi +]) +echo "Store modules built: $REPL_POLICIES" +AC_SUBST(REPL_POLICIES) +REPL_OBJS="repl/`echo $REPL_POLICIES|sed -e's% %.a repl/%g'`.a" +AC_SUBST(REPL_OBJS) + OPT_PINGER_EXE='' AC_ARG_ENABLE(icmp, [ --enable-icmp Enable ICMP pinging], @@ -609,18 +652,6 @@ AC_ARG_ENABLE(underscores, fi ]) -dnl Enable HEAP_REPLACEMENT -AC_ARG_ENABLE(heap-replacement, -[ --enable-heap-replacement - This option allows you to use various cache - replacement algorithms, instead of the standard - LRU algorithm.], -[ if test "$enableval" = "yes" ; then - echo "Enabling HEAP_REPLACEMENT" - AC_DEFINE(HEAP_REPLACEMENT, 1) - fi -]) - dnl Select auth modules to build AUTH_MODULES= AC_ARG_ENABLE(auth-modules, @@ -1618,6 +1649,9 @@ AC_OUTPUT(\ ./src/fs/ufs/Makefile \ ./src/fs/aufs/Makefile \ ./src/fs/coss/Makefile \ + ./src/repl/Makefile \ + ./src/repl/lru/Makefile \ + ./src/repl/heap/Makefile \ ./src/fs/diskd/Makefile \ ./contrib/Makefile \ $SNMP_MAKEFILE \ diff --git a/doc/Programming-Guide/prog-guide.sgml b/doc/Programming-Guide/prog-guide.sgml index fd90426900..092bc4fdc7 100644 --- a/doc/Programming-Guide/prog-guide.sgml +++ b/doc/Programming-Guide/prog-guide.sgml @@ -2,7 +2,7 @@
Squid Programmers Guide Duane Wessels, Squid Developers -$Id: prog-guide.sgml,v 1.27 2000/05/03 17:15:40 adrian Exp $ +$Id: prog-guide.sgml,v 1.28 2000/06/08 18:05:33 hno Exp $ Squid is a WWW Cache application developed by the National Laboratory @@ -1492,16 +1492,16 @@ Squid consists of the following major components This feature may not be required by some storage systems and can be implemented as a null-function (no-op). - int - STLOGCLEANOPEN(SwapDir *); + STLOGCLEANSTART(SwapDir *);

- The + + StoreEntry * + STLOGCLEANNEXTENTRY(SwapDir *); + + +

+ Gets the next entry that is a candidate for the clean log. + +

+ Returns NULL when there is no more objects to log + void - STLOGCLEANWRITE(const StoreEntry *, SwapDir *); + STLOGCLEANWRITE(SwapDir *, const StoreEntry *);

The - A NULL + void + STLOGCLEANDONE(SwapDir *); + +

+ Indicates the end of the clean-writing process and signals + the storage system to close the clean log, and rename or + move them to become the official state-holding log ready + to be opened. Replacement policy implementation @@ -1545,10 +1566,7 @@ replacement policy. Cyclic filesystems such as COSS require this tight coupling between the storage layer and the replacement policy. -Future removal policy - -

- (replaces the above Replace policy) +Removal policy API

The removal policy is responsible for determining in which order @@ -1625,10 +1643,26 @@ coupling between the storage layer and the replacement policy.

- Tells the policy that a StoreEntry has been referenced. + Tells the policy that a StoreEntry is going to be referenced. Called + whenever a entry gets locked.

- datap is a pointer to where policy specific data is stored + node is a pointer to where policy specific data is stored + for the store entry, currently the size of one (void *) pointer. + +policy.Dereferenced() + +

+ + policy->Dereferenced(RemovalPolicy *policy, const StoreEntry *, RemovalPolicyNode *node) + + +

+ Tells the policy that a StoreEntry has been referenced. Called when + an access to the entry has finished. + +

+ node is a pointer to where policy specific data is stored for the store entry, currently the size of one (void *) pointer. policy.WalkInit() @@ -1822,6 +1856,32 @@ coupling between the storage layer and the replacement policy. Prior to returning the created instance must be registered as callback-data by calling cbdataAdd(). +Design notes/bugs + +

+ The RemovalPolicyNode design is incomplete/insufficient. The intention + was to abstract the location of the index pointers from the policy + implementation to allow the policy to work on both on-disk and memory + caches, but unfortunately the purge method for HEAP based policies + needs to update this, and it is also preferable if the purge method + in general knows how to clear the information. I think the agreement + was that the current design of thightly coupling the two together + on one StoreEntry is not the best design possible. + +

+ It is debated if the design in having the policy index control the + clean index writes is the correct approach. Perhaps not. Perhaps a + more appropriate design is probably to do the store indexing + completely outside the policy implementation (i.e. using the hash + index), and only ask the policy to dump it's state somehow. + +

+ The Referenced/Dereferenced() calls is today mapped to lock/unlock + which is an approximation of when they are intended to be called. + However, the real intention is to have Referenced() called whenever + an object is referenced, and Dereferenced() only called when the + object has actually been used for anything good. + Forwarding Selection diff --git a/doc/debug-sections.txt b/doc/debug-sections.txt index 15bf1ad1a5..1b35dbc6bc 100644 --- a/doc/debug-sections.txt +++ b/doc/debug-sections.txt @@ -85,3 +85,4 @@ section 77 Delay Pools section 78 HTTP Connection Header section 79 HTTP Meter Header section 80 WCCP +section 81 Store Removal/Replacement policy diff --git a/src/Makefile.in b/src/Makefile.in index 2d209d5cef..6dcd6c7b03 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.in,v 1.188 2000/05/31 08:57:08 hno Exp $ +# $Id: Makefile.in,v 1.189 2000/06/08 18:05:34 hno Exp $ # # Uncomment and customize the following to suit your needs: # @@ -18,7 +18,7 @@ localstatedir = @localstatedir@ srcdir = @srcdir@ VPATH = @srcdir@ -SUBDIRS = fs +SUBDIRS = fs repl # Gotta love the DOS legacy # @@ -67,6 +67,8 @@ XTRA_LIBS = @XTRA_LIBS@ XTRA_OBJS = @XTRA_OBJS@ STORE_OBJS = @STORE_OBJS@ STORE_MODULES = @STORE_MODULES@ +REPL_OBJS = @REPL_OBJS@ +REPL_POLICIES = @REPL_POLICIES@ MV = @MV@ RM = @RM@ SHELL = /bin/sh @@ -149,6 +151,7 @@ OBJS = \ pump.o \ redirect.o \ refresh.o \ + repl_modules.o \ send-announce.o \ @SNMP_OBJS@ \ ssl.o \ @@ -168,7 +171,6 @@ OBJS = \ store_swapin.o \ store_swapmeta.o \ store_swapout.o \ - store_heap_replacement.o \ string_arrays.o \ tools.o \ @UNLINKD_OBJS@ \ @@ -194,14 +196,14 @@ LEAKFINDER_OBJS = \ DEFAULTS = \ -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -all: squid.conf store_modules $(PROGS) $(UTILS) $(SUID_UTILS) $(CGIPROGS) +all: squid.conf store_modules repl_modules $(PROGS) $(UTILS) $(SUID_UTILS) $(CGIPROGS) $(OBJS): $(top_srcdir)/include/version.h ../include/autoconf.h $(SNMP_OBJS): ../snmplib/libsnmp.a $(top_srcdir)/include/cache_snmp.h -$(SQUID_EXE): $(OBJS) $(STORE_OBJS) - $(CC) -o $@ $(LDFLAGS) $(OBJS) $(STORE_OBJS) $(SQUID_LIBS) +$(SQUID_EXE): $(OBJS) $(STORE_OBJS) $(REPL_OBJS) + $(CC) -o $@ $(LDFLAGS) $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(SQUID_LIBS) globals.o: globals.c Makefile $(CC) -c globals.c $(CFLAGS) -I$(srcdir) $(DEFAULTS) @@ -267,7 +269,7 @@ cf.data: cf.data.pre Makefile < $(srcdir)/cf.data.pre >$@ store_modules.c: store_modules.sh Makefile - @sh $(srcdir)/store_modules.sh $(STORE_MODULES) >store_modules.c + sh $(srcdir)/store_modules.sh $(STORE_MODULES) >store_modules.c store_modules.o: store_modules.c $(CC) -c store_modules.c $(CFLAGS) -I$(srcdir) @@ -277,6 +279,17 @@ $(STORE_OBJS): fs/stamp store_modules fs/stamp: @sh -c "cd fs && $(MAKE) all" +repl_modules.c: repl_modules.sh Makefile + sh $(srcdir)/repl_modules.sh $(REPL_POLICIES) >repl_modules.c + +repl_modules.o: repl_modules.c + $(CC) -c repl_modules.c $(CFLAGS) -I$(srcdir) + +$(REPL_OBJS): repl/stamp + +repl_modules repl/stamp: + @sh -c "cd repl && $(MAKE) all" + install-mkdirs: -@if test ! -d $(prefix); then \ echo "mkdir $(prefix)"; \ diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 83106cb840..90016c1db5 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -1,6 +1,6 @@ /* - * $Id: cache_cf.cc,v 1.349 2000/05/31 07:01:41 hno Exp $ + * $Id: cache_cf.cc,v 1.350 2000/06/08 18:05:34 hno Exp $ * * DEBUG: section 3 Configuration File Parsing * AUTHOR: Harvest Derived @@ -348,14 +348,6 @@ configDoConfigure(void) debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n"); Config.retry.maxtries = 1; } -#if HEAP_REPLACEMENT - /* The non-LRU policies do not use referenceAge */ -#else - if (Config.referenceAge < 300) { - debug(3, 0) ("WARNING: resetting 'reference_age' to 1 week\n"); - Config.referenceAge = 86400 * 7; - } -#endif requirePathnameExists("MIME Config Table", Config.mimeTablePathname); #if USE_DNSSERVERS requirePathnameExists("cache_dns_program", Config.Program.dnsserver); @@ -1732,6 +1724,40 @@ dump_uri_whitespace(StoreEntry * entry, const char *name, int var) storeAppendPrintf(entry, "%s %s\n", name, s); } +static void +free_removalpolicy(RemovalPolicySettings **settings) +{ + if (!*settings) + return; + free_string(&(*settings)->type); + free_wordlist(&(*settings)->args); + xfree(*settings); + *settings = NULL; +} + +static void +parse_removalpolicy(RemovalPolicySettings **settings) +{ + if (*settings) + free_removalpolicy(settings); + *settings = xcalloc(1, sizeof(**settings)); + parse_string(&(*settings)->type); + parse_wordlist(&(*settings)->args); +} + +static void +dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings *settings) +{ + wordlist *args; + storeAppendPrintf(entry, "%s %s", name, settings->type); + args = settings->args; + while (args) { + storeAppendPrintf(entry, " %s", args->key); + args = args->next; + } +} + + #include "cf_parser.c" peer_t @@ -1833,3 +1859,5 @@ requirePathnameExists(const char *name, const char *path) if (stat(path, &sb) < 0) fatalf("%s: %s", path, xstrerror()); } + + diff --git a/src/cf.data.pre b/src/cf.data.pre index b80383eced..3488e763ec 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -1,6 +1,6 @@ # -# $Id: cf.data.pre,v 1.187 2000/05/31 07:01:42 hno Exp $ +# $Id: cf.data.pre,v 1.188 2000/06/08 18:05:35 hno Exp $ # # # SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -590,6 +590,58 @@ DOC_START Maximum number of FQDN cache entries. DOC_END +NAME: cache_replacement_policy +TYPE: removalpolicy +LOC: Config.replPolicy +DEFAULT: lru +DOC_START + The cache replacement policy parameter determines which + objects are evicted (replaced) when disk space is needed. + + lru : Squid's original list based LRU policy + heap GDSF : Greedy-Dual Size Frequency + heap LFUDA: Least Frequently Used with Dynamic Aging + heap LRU : LRU policy implemented using a heap + + Applies to any cache_dir lines listed below this. + + The LRU policies keeps recently referenced objects. + + The heap GDSF policy optimizes object hit rate by keeping smaller + popular objects in cache so it has a better chance of getting a + hit. It achieves a lower byte hit rate than LFUDA though since + it evicts larger (possibly popular) objects. + + The heap LFUDA policy keeps popular objects in cache regardless of + their size and thus optimizes byte hit rate at the expense of + hit rate since one large, popular object will prevent many + smaller, slightly less popular objects from being cached. + + Both policies utilize a dynamic aging mechanism that prevents + cache pollution that can otherwise occur with frequency-based + replacement policies. + + NOTE: if using the LFUDA replacement policy you should increase + the value of maximum_object_size above its default of 4096 KB to + to maximize the potential byte hit rate improvement of LFUDA. + + For more information about the GDSF and LFUDA cache replacement + policies see http://www.hpl.hp.com/techreports/1999/HPL-1999-69.html + and http://fog.hpl.external.hp.com/techreports/98/HPL-98-173.html. +DOC_END + +NAME: memory_replacement_policy +TYPE: removalpolicy +LOC: Config.memPolicy +DEFAULT: lru +DOC_START + The memory replacement policy parameter determines which + objects are purged from memory when memory space is needed. + + See cache_replacement_policy for details. +DOC_END + + COMMENT_START LOGFILE PATHNAMES AND CACHE DIRECTORIES ----------------------------------------------------------------------------- @@ -1227,49 +1279,6 @@ DOC_START used. DOC_END - -NAME: replacement_policy -TYPE: string -LOC: Config.replPolicy -DEFAULT: LFUDA -IFDEF: HEAP_REPLACEMENT -DOC_START - The cache replacement policy parameter determines which - objects are evicted (replaced) when disk space is needed. - Squid used to have only a single replacement policy, LRU. - But when built with -DHEAP_REPLACEMENT you can choose - between two new, enhanced policies: - - GDSF: Greedy-Dual Size Frequency - LFUDA: Least Frequently Used with Dynamic Aging - - Both of these policies are frequency based rather than recency - based, and perform better than LRU. - - The GDSF policy optimizes object hit rate by keeping smaller - popular objects in cache so it has a better chance of getting a - hit. It achieves a lower byte hit rate than LFUDA though since - it evicts larger (possibly popular) objects. - - The LFUDA policy keeps popular objects in cache regardless of - their size and thus optimizes byte hit rate at the expense of - hit rate since one large, popular object will prevent many - smaller, slightly less popular objects from being cached. - - Both policies utilize a dynamic aging mechanism that prevents - cache pollution that can otherwise occur with frequency-based - replacement policies. - - NOTE: if using the LFUDA replacement policy you should increase - the value of maximum_object_size above its default of 4096 KB to - to maximize the potential byte hit rate improvement of LFUDA. - - For more information about these cache replacement policies see - http://www.hpl.hp.com/techreports/1999/HPL-1999-69.html and - http://fog.hpl.external.hp.com/techreports/98/HPL-98-173.html. -DOC_END - - NAME: reference_age TYPE: time_t LOC: Config.referenceAge diff --git a/src/fs/aufs/async_io.cc b/src/fs/aufs/async_io.cc index 263976eac6..036f238e54 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.3 2000/05/29 21:06:28 hno Exp $ + * $Id: async_io.cc,v 1.4 2000/06/08 18:05:37 hno Exp $ * * DEBUG: section 32 Asynchronous Disk I/O * AUTHOR: Pete Bentley @@ -335,7 +335,8 @@ aioUnlink(const char *pathname, AIOCB * callback, void *callback_data) cbdataLock(callback_data); if (aio_unlink(path, &ctrlp->result) < 0) { int ret = unlink(path); - (callback) (ctrlp->fd, callback_data, ret, errno); + if (callback) + (callback) (ctrlp->fd, callback_data, ret, errno); cbdataUnlock(callback_data); memPoolFree(aio_ctrl_pool, ctrlp); xfree(path); @@ -347,7 +348,7 @@ aioUnlink(const char *pathname, AIOCB * callback, void *callback_data) } /* aioUnlink */ -void +int aioCheckCallbacks(SwapDir * SD) { aio_result_t *resultp; @@ -355,7 +356,8 @@ aioCheckCallbacks(SwapDir * SD) aio_ctrl_t *prev; AIOCB *done_handler; void *their_data; - + int retval = 0; + assert(initialised); aio_counts.check_callback++; for (;;) { @@ -376,6 +378,7 @@ aioCheckCallbacks(SwapDir * SD) ctrlp->done_handler = NULL; ctrlp->done_handler_data = NULL; if (cbdataValid(their_data)) + retval = 1; /* Return that we've actually done some work */ done_handler(ctrlp->fd, their_data, ctrlp->result.aio_return, ctrlp->result.aio_errno); cbdataUnlock(their_data); @@ -384,6 +387,7 @@ aioCheckCallbacks(SwapDir * SD) aioFDWasClosed(ctrlp->fd); memPoolFree(aio_ctrl_pool, ctrlp); } + return retval; } void diff --git a/src/fs/aufs/store_asyncufs.h b/src/fs/aufs/store_asyncufs.h index 0757e96505..2385ba5af7 100644 --- a/src/fs/aufs/store_asyncufs.h +++ b/src/fs/aufs/store_asyncufs.h @@ -47,7 +47,7 @@ void aioWrite(int, int offset, char *, int size, AIOCB *, void *, FREE *); void aioRead(int, int offset, char *, int size, AIOCB *, void *); void aioStat(char *, struct stat *, AIOCB *, void *); void aioUnlink(const char *, AIOCB *, void *); -void aioCheckCallbacks(SwapDir *); +int aioCheckCallbacks(SwapDir *); void aioSync(SwapDir *); int aioQueueSize(void); diff --git a/src/fs/aufs/store_dir_aufs.cc b/src/fs/aufs/store_dir_aufs.cc index ec98323330..dd96090c9d 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.3 2000/05/29 21:06:28 hno Exp $ + * $Id: store_dir_aufs.cc,v 1.4 2000/06/08 18:05:37 hno Exp $ * * DEBUG: section 47 Store Directory Routines * AUTHOR: Duane Wessels @@ -99,9 +99,10 @@ static FILE *storeAufsDirOpenTmpSwapLog(SwapDir *, int *, int *); static STLOGOPEN storeAufsDirOpenSwapLog; static STINIT storeAufsDirInit; static STFREE storeAufsDirFree; -static STLOGCLEANOPEN storeAufsDirWriteCleanOpen; -static void storeAufsDirWriteCleanClose(SwapDir * sd); +static STLOGCLEANSTART storeAufsDirWriteCleanStart; +static STLOGCLEANNEXTENTRY storeAufsDirCleanLogNextEntry; static STLOGCLEANWRITE storeAufsDirWriteCleanEntry; +static STLOGCLEANDONE storeAufsDirWriteCleanDone; static STLOGCLOSE storeAufsDirCloseSwapLog; static STLOGWRITE storeAufsDirSwapLog; static STNEWFS storeAufsDirNewfs; @@ -119,10 +120,6 @@ static int storeAufsCleanupDoubleCheck(SwapDir *, StoreEntry *); static void storeAufsDirStats(SwapDir *, StoreEntry *); static void storeAufsDirInitBitmap(SwapDir *); static int storeAufsDirValidFileno(SwapDir *, sfileno, int); -static int storeAufsDirCheckExpired(SwapDir *, StoreEntry *); -#if !HEAP_REPLACEMENT -static time_t storeAufsDirExpiredReferenceAge(SwapDir *); -#endif /* * These functions were ripped straight out of the heart of store_dir.c. @@ -351,9 +348,9 @@ storeAufsDirInit(SwapDir * sd) { 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."; + "\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."; storeAufsDirInitBitmap(sd); if (storeAufsDirVerifyCacheDirs(sd) < 0) fatal(errmsg); @@ -612,10 +609,7 @@ storeAufsDirRebuildFromSwapLog(void *data) e->lastmod = s.lastmod; e->flags = s.flags; e->refcount += s.refcount; -#if HEAP_REPLACEMENT - storeHeapPositionUpdate(e, SD); storeAufsDirUnrefObj(SD, e); -#endif } else { debug_trap("storeAufsDirRebuildFromSwapLog: bad condition"); debug(20, 1) ("\tSee %s:%d\n", __FILE__, __LINE__); @@ -795,9 +789,6 @@ storeAufsDirAddDiskRestore(SwapDir * SD, const cache_key * key, e->swap_dirn = SD->index; e->swap_file_sz = swap_file_sz; e->lock_count = 0; -#if !HEAP_REPLACEMENT - e->refcount = 0; -#endif e->lastref = lastref; e->timestamp = timestamp; e->expires = expires; @@ -934,6 +925,7 @@ struct _clean_state { char *outbuf; off_t outbuf_offset; int fd; + RemovalPolicyWalker *walker; }; #define CLEAN_BUF_SZ 16384 @@ -943,7 +935,7 @@ struct _clean_state { * we succeed, and assign the 'func' and 'data' return pointers. */ static int -storeAufsDirWriteCleanOpen(SwapDir * sd) +storeAufsDirWriteCleanStart(SwapDir * sd) { struct _clean_state *state = xcalloc(1, sizeof(*state)); struct stat sb; @@ -954,6 +946,7 @@ storeAufsDirWriteCleanOpen(SwapDir * sd) state->cln = xstrdup(storeAufsDirSwapLogFile(sd, ".last-clean")); state->outbuf = xcalloc(CLEAN_BUF_SZ, 1); state->outbuf_offset = 0; + state->walker = sd->repl->WalkInit(sd->repl); unlink(state->new); unlink(state->cln); state->fd = file_open(state->new, O_WRONLY | O_CREAT | O_TRUNC); @@ -970,19 +963,28 @@ storeAufsDirWriteCleanOpen(SwapDir * sd) return 0; } +/* + * Get the next entry that is a candidate for clean log writing + */ +const StoreEntry * +storeAufsDirCleanLogNextEntry(SwapDir * sd) +{ + const StoreEntry *entry = NULL; + struct _clean_state *state = sd->log.clean.state; + if (state->walker) + entry = state->walker->Next(state->walker); + return entry; +} + /* * "write" an entry to the clean log file. */ static void -storeAufsDirWriteCleanEntry(const StoreEntry * e, SwapDir * sd) +storeAufsDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e) { storeSwapLogData s; static size_t ss = sizeof(storeSwapLogData); struct _clean_state *state = sd->log.clean.state; - if (NULL == e) { - storeAufsDirWriteCleanClose(sd); - return; - } memset(&s, '\0', ss); s.op = (char) SWAP_LOG_ADD; s.swap_filen = e->swap_filen; @@ -1014,11 +1016,12 @@ storeAufsDirWriteCleanEntry(const StoreEntry * e, SwapDir * sd) } static void -storeAufsDirWriteCleanClose(SwapDir * sd) +storeAufsDirWriteCleanDone(SwapDir * sd) { struct _clean_state *state = sd->log.clean.state; if (state->fd < 0) return; + state->walker->Done(state->walker); if (write(state->fd, state->outbuf, state->outbuf_offset) < 0) { debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", state->new, xstrerror()); @@ -1276,30 +1279,18 @@ void storeAufsDirMaintain(SwapDir * SD) { StoreEntry *e = NULL; - int scanned = 0; - int locked = 0; - int expired = 0; + int removed = 0; int max_scan; int max_remove; double f; - static time_t last_warn_time = 0; -#if !HEAP_REPLACEMENT - dlink_node *m; - dlink_node *prev = NULL; -#else - heap_key age; - heap_key min_age = 0.0; - link_list *locked_entries = NULL; -#if HEAP_REPLACEMENT_DEBUG - if (!verify_heap_property(SD->repl.heap.heap)) { - debug(20, 1) ("Heap property violated!\n"); - } -#endif -#endif + RemovalPurgeWalker *walker; /* We can't delete objects while rebuilding swap */ if (store_dirs_rebuilding) { return; } else { + /* XXX FixMe: This should use the cache_dir hig/low values, not the + * global ones + */ f = (double) (store_swap_size - store_swap_low) / (store_swap_high - store_swap_low); f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f; max_scan = (int) (f * 400.0 + 100.0); @@ -1307,120 +1298,26 @@ storeAufsDirMaintain(SwapDir * SD) /* * This is kinda cheap, but so we need this priority hack? */ -#if 0 - eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0 - f, 1); -#endif } - debug(20, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n", f, max_scan, max_remove); -#if HEAP_REPLACEMENT - while (heap_nodes(SD->repl.heap.heap) > 0) { - if (store_swap_size < store_swap_low) - break; - if (expired >= max_remove) - break; - if (scanned >= max_scan) - break; - age = heap_peepminkey(SD->repl.heap.heap); - e = heap_extractmin(SD->repl.heap.heap); - e->repl.node = NULL; /* no longer in the heap */ - scanned++; - if (storeEntryLocked(e)) { - /* - * Entry is in use ... put it in a linked list to ignore it. - */ - if (!EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - /* - * If this was a "SPECIAL" do not add it back into the heap. - * It will always be "SPECIAL" and therefore never removed. - */ - debug(20, 4) ("storeAufsDirMaintain: locked url %s\n", - (e->mem_obj && e->mem_obj->url) ? e->mem_obj->url : storeKeyText(e-> - key)); - linklistPush(&locked_entries, e); - } - locked++; - continue; - } else if (storeAufsDirCheckExpired(SD, e)) { - /* - * Note: This will not check the reference age ifdef - * HEAP_REPLACEMENT, but it does some other useful - * checks... - */ - expired++; - debug(20, 3) ("Released store object age %f size %d refs %d key %s\n", - age, e->swap_file_sz, e->refcount, storeKeyText(e->key)); - min_age = age; - storeRelease(e); - } else { - /* - * Did not expire the object so we need to add it back - * into the heap! - */ - debug(20, 5) ("storeMaintainSwapSpace: non-expired %s\n", - storeKeyText(e->key)); - linklistPush(&locked_entries, e); - continue; - } + debug(20, 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) { + /* XXX FixMe: This should use the cache_dir hig/low values, not the + * global ones + */ if (store_swap_size < store_swap_low) break; - else if (expired >= max_remove) - break; - else if (scanned >= max_scan) + if (removed >= max_remove) break; + e = walker->Next(walker); + if (!e) + break; /* no more objects */ + removed++; + storeRelease(e); } - /* - * Bump the heap age factor. - */ - if (min_age > 0.0) - SD->repl.heap.heap->age = min_age; - /* - * Reinsert all bumped locked entries back into heap... - */ - while ((e = linklistShift(&locked_entries))) - e->repl.node = heap_insert(SD->repl.heap.heap, e); -#else - for (m = SD->repl.lru.list.tail; m; m = prev) { - prev = m->prev; - e = m->data; - scanned++; - if (storeEntryLocked(e)) { - /* - * If there is a locked entry at the tail of the LRU list, - * move it to the beginning to get it out of the way. - * Theoretically, we might have all locked objects at the - * tail, and then we'll never remove anything here and the - * LRU age will go to zero. - */ - if (memInUse(MEM_STOREENTRY) > max_scan) { - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); - } - locked++; - - } else if (storeAufsDirCheckExpired(SD, e)) { - expired++; - storeRelease(e); - } - if (expired >= max_remove) - break; - if (scanned >= max_scan) - break; - } -#endif - debug(20, (expired ? 2 : 3)) ("storeMaintainSwapSpace: scanned %d/%d removed %d/%d locked %d f=%.03f\n", - scanned, max_scan, expired, max_remove, locked, f); - debug(20, 3) ("storeMaintainSwapSpace stats:\n"); - debug(20, 3) (" %6d objects\n", memInUse(MEM_STOREENTRY)); - debug(20, 3) (" %6d were scanned\n", scanned); - debug(20, 3) (" %6d were locked\n", locked); - debug(20, 3) (" %6d were expired\n", expired); - if (store_swap_size < Config.Swap.maxSize) - return; - if (squid_curtime - last_warn_time < 10) - return; - debug(20, 0) ("WARNING: Disk space over limit: %d KB > %d KB\n", - store_swap_size, Config.Swap.maxSize); - last_warn_time = squid_curtime; + debug(20, (removed ? 2 : 3)) ("storeUfsDirMaintain: %s removed %d/%d f=%.03f max_scan=%d\n", + SD->path, removed, max_remove, f, max_scan); } /* @@ -1436,7 +1333,7 @@ storeAufsDirCheckObj(SwapDir * SD, const StoreEntry * e) int loadav; int ql; -#if !HEAP_REPLACEMENT +#if OLD_UNUSED_CODE if (storeAufsDirExpiredReferenceAge(SD) < 300) { debug(20, 3) ("storeAufsDirCheckObj: NO: LRU Age = %d\n", storeAufsDirExpiredReferenceAge(SD)); @@ -1465,16 +1362,8 @@ storeAufsDirRefObj(SwapDir * SD, StoreEntry * e) { debug(1, 3) ("storeAufsDirRefObj: referencing %p %d/%d\n", e, e->swap_dirn, e->swap_filen); -#if HEAP_REPLACEMENT - /* Nothing to do here */ -#else - /* Reference the object */ - if (!EBIT_TEST(e->flags, RELEASE_REQUEST) && - !EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); - } -#endif + if (SD->repl->Referenced) + SD->repl->Referenced(SD->repl, e, &e->repl); } /* @@ -1487,10 +1376,8 @@ storeAufsDirUnrefObj(SwapDir * SD, StoreEntry * e) { debug(1, 3) ("storeAufsDirUnrefObj: referencing %p %d/%d\n", e, e->swap_dirn, e->swap_filen); -#if HEAP_REPLACEMENT - if (e->repl.node) - heap_update(SD->repl.heap.heap, e->repl.node, e); -#endif + if (SD->repl->Dereferenced) + SD->repl->Dereferenced(SD->repl, e, &e->repl); } /* @@ -1504,80 +1391,10 @@ void storeAufsDirUnlinkFile(SwapDir * SD, sfileno f) { debug(79, 3) ("storeAufsDirUnlinkFile: unlinking fileno %08X\n", f); - storeAufsDirMapBitReset(SD, f); + /* storeAufsDirMapBitReset(SD, f); */ aioUnlink(storeAufsDirFullPath(SD, f, NULL), NULL, NULL); } -#if !HEAP_REPLACEMENT -/* - * storeAufsDirExpiredReferenceAge - * - * The LRU age is scaled exponentially between 1 minute and - * Config.referenceAge , when store_swap_low < store_swap_size < - * store_swap_high. This keeps store_swap_size within the low and high - * water marks. If the cache is very busy then store_swap_size stays - * closer to the low water mark, if it is not busy, then it will stay - * near the high water mark. The LRU age value can be examined on the - * cachemgr 'info' page. - */ -static time_t -storeAufsDirExpiredReferenceAge(SwapDir * SD) -{ - double x; - double z; - time_t age; - long store_high, store_low; - - store_high = (long) (((float) SD->max_size * - (float) Config.Swap.highWaterMark) / (float) 100); - store_low = (long) (((float) SD->max_size * - (float) Config.Swap.lowWaterMark) / (float) 100); - debug(20, 20) ("RA: Dir %s, hi=%d, lo=%d, cur=%d\n", SD->path, store_high, store_low, SD->cur_size); - - x = (double) (store_high - SD->cur_size) / - (store_high - store_low); - x = x < 0.0 ? 0.0 : x > 1.0 ? 1.0 : x; - z = pow((double) (Config.referenceAge / 60), x); - age = (time_t) (z * 60.0); - if (age < 60) - age = 60; - else if (age > Config.referenceAge) - age = Config.referenceAge; - return age; -} -#endif - -/* - * storeAufsDirCheckExpired - * - * Check whether the given object is expired or not - * It breaks layering a little by calling the upper layers to find - * out whether the object is locked or not, but we can't help this - * right now. - */ -static int -storeAufsDirCheckExpired(SwapDir * SD, StoreEntry * e) -{ - if (storeEntryLocked(e)) - return 0; - if (EBIT_TEST(e->flags, RELEASE_REQUEST)) - return 1; - if (EBIT_TEST(e->flags, ENTRY_NEGCACHED) && squid_curtime >= e->expires) - return 1; - -#if HEAP_REPLACEMENT - /* - * with HEAP_REPLACEMENT we are not using the LRU reference age, the heap - * controls the replacement of objects. - */ - return 1; -#else - if (squid_curtime - e->lastref > storeAufsDirExpiredReferenceAge(SD)) - return 1; - return 0; -#endif -} - /* * Add and remove the given StoreEntry from the replacement policy in * use. @@ -1588,17 +1405,7 @@ storeAufsDirReplAdd(SwapDir * SD, StoreEntry * e) { debug(20, 4) ("storeAufsDirReplAdd: added node %p to dir %d\n", e, SD->index); -#if HEAP_REPLACEMENT - if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - (void) 0; - } else { - e->repl.node = heap_insert(SD->repl.heap.heap, e); - debug(20, 4) ("storeAufsDirReplAdd: inserted node 0x%x\n", e->repl.node); - } -#else - /* Shouldn't we not throw special objects into the lru ? */ - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); -#endif + SD->repl->Add(SD->repl, e, &e->repl); } @@ -1608,17 +1415,7 @@ storeAufsDirReplRemove(StoreEntry * e) SwapDir *SD = INDEXSD(e->swap_dirn); debug(20, 4) ("storeAufsDirReplRemove: remove node %p from dir %d\n", e, SD->index); -#if HEAP_REPLACEMENT - /* And now, release the object from the replacement policy */ - if (e->repl.node) { - debug(20, 4) ("storeAufsDirReplRemove: deleting node 0x%x\n", - e->repl.node); - heap_delete(SD->repl.heap.heap, e->repl.node); - e->repl.node = NULL; - } -#else - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); -#endif + SD->repl->Remove(SD->repl, e, &e->repl); } @@ -1662,15 +1459,15 @@ storeAufsDirStats(SwapDir * SD, StoreEntry * sentry) if (SD->flags.read_only) storeAppendPrintf(sentry, " READ-ONLY"); storeAppendPrintf(sentry, "\n"); +#if OLD_UNUSED_CODE #if !HEAP_REPLACEMENT storeAppendPrintf(sentry, "LRU Expiration Age: %6.2f days\n", (double) storeAufsDirExpiredReferenceAge(SD) / 86400.0); #else -#if 0 storeAppendPrintf(sentry, "Storage Replacement Threshold:\t%f\n", heap_peepminkey(sd.repl.heap.heap)); #endif -#endif +#endif /* OLD_UNUSED_CODE */ } /* @@ -1746,7 +1543,6 @@ storeAufsDirFree(SwapDir * s) filemapFreeMemory(aioinfo->map); xfree(aioinfo); s->fsdata = NULL; /* Will aid debugging... */ - } char * @@ -1865,41 +1661,12 @@ storeAufsDirParse(SwapDir * sd, int index, char *path) sd->log.open = storeAufsDirOpenSwapLog; sd->log.close = storeAufsDirCloseSwapLog; sd->log.write = storeAufsDirSwapLog; - sd->log.clean.open = storeAufsDirWriteCleanOpen; + sd->log.clean.start = storeAufsDirWriteCleanStart; + sd->log.clean.nextentry = storeAufsDirCleanLogNextEntry; + sd->log.clean.done = storeAufsDirWriteCleanDone; /* Initialise replacement policy stuff */ -#if HEAP_REPLACEMENT - /* - * Create new heaps with cache replacement policies attached to them. - * The cache replacement policy is specified as either GDSF or LFUDA in - * the squid.conf configuration file. Note that the replacement policy - * applies only to the disk replacement algorithm. Memory replacement - * always uses GDSF since we want to maximize object hit rate. - */ - if (Config.replPolicy) { - if (tolower(Config.replPolicy[0]) == 'g') { - debug(20, 1) ("Using GDSF disk replacement policy\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_GDSF); - } else if (tolower(Config.replPolicy[0]) == 'l') { - if (tolower(Config.replPolicy[1]) == 'f') { - debug(20, 1) ("Using LFUDA disk replacement policy\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_LFUDA); - } else if (tolower(Config.replPolicy[1]) == 'r') { - debug(20, 1) ("Using LRU heap disk replacement policy\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_LRU); - } - } else { - debug(20, 1) ("Unrecognized replacement_policy; using GDSF\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_GDSF); - } - } else { - debug(20, 1) ("Using default disk replacement policy (GDSF)\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_GDSF); - } -#else - sd->repl.lru.list.head = NULL; - sd->repl.lru.list.tail = NULL; -#endif + sd->repl = createRemovalPolicy(Config.replPolicy); } /* diff --git a/src/fs/aufs/store_io_aufs.cc b/src/fs/aufs/store_io_aufs.cc index 38e7a10ee8..3d7e6147b0 100644 --- a/src/fs/aufs/store_io_aufs.cc +++ b/src/fs/aufs/store_io_aufs.cc @@ -204,6 +204,7 @@ storeAufsUnlink(SwapDir * SD, StoreEntry * e) { debug(78, 3) ("storeAufsUnlink: dirno %d, fileno %08X\n", SD->index, e->swap_filen); storeAufsDirReplRemove(e); + storeAufsDirMapBitReset(SD, e->swap_filen); storeAufsDirUnlinkFile(SD, e->swap_filen); } diff --git a/src/fs/coss/store_coss.h b/src/fs/coss/store_coss.h index 1b9fa4b3ae..9699fd89e0 100644 --- a/src/fs/coss/store_coss.h +++ b/src/fs/coss/store_coss.h @@ -31,6 +31,16 @@ struct _cossinfo { int fd; int swaplog_fd; int numcollisions; + dlink_list index; + int count; + 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 *. + */ + dlink_node node; }; @@ -50,12 +60,13 @@ struct _cossstate { 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 @@ -66,17 +77,11 @@ 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 storeCossFree(StoreEntry * e); -extern void storeCossMaintainSwapSpace(SwapDir * SD); -extern void storeCossDirStats(SwapDir *, StoreEntry *); -extern void storeCossDirDump(StoreEntry * entry, const char *name, SwapDir * s); -extern void storeCossDirFree(SwapDir *); -extern SwapDir *storeCossDirPick(void); - -void storeFsSetup_ufs(storefs_entry_t *); - - +extern void storeCossAdd(SwapDir *, StoreEntry *); +extern void storeCossRemove(SwapDir *, StoreEntry *); +extern void storeCossStartMembuf(SwapDir *SD); #endif diff --git a/src/fs/coss/store_dir_coss.cc b/src/fs/coss/store_dir_coss.cc index 60e444f42b..5b85c96631 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.2 2000/05/12 00:29:19 wessels Exp $ + * $Id: store_dir_coss.cc,v 1.3 2000/06/08 18:05:38 hno Exp $ * * DEBUG: section 81 Store COSS Directory Routines * AUTHOR: Eric Stern @@ -39,13 +39,12 @@ #define STORE_META_BUFSZ 4096 -extern void storeCossFlushMemBufs(SwapDir * SD); - int n_coss_dirs = 0; /* static int last_coss_pick_index = -1; */ int coss_initialised = 0; MemPool *coss_membuf_pool = NULL; MemPool *coss_state_pool = NULL; +MemPool *coss_index_pool = NULL; typedef struct _RebuildState RebuildState; struct _RebuildState { @@ -87,16 +86,18 @@ static void storeCossDirCloseTmpSwapLog(SwapDir * sd); static FILE *storeCossDirOpenTmpSwapLog(SwapDir *, int *, int *); static STLOGOPEN storeCossDirOpenSwapLog; static STINIT storeCossDirInit; -static STLOGCLEANOPEN storeCossDirWriteCleanOpen; -static void storeCossDirWriteCleanClose(SwapDir * sd); +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 void storeCossDirShutdown(SwapDir * sd); -static void storeCossDirParse(SwapDir *, int, char *); -static void storeCossDirReconfigure(SwapDir *, int, char *); +static STFREE storeCossDirShutdown; +static STFSPARSE storeCossDirParse; +static STFSRECONFIGURE storeCossDirReconfigure; +static STDUMP storeCossDirDump; static char * storeCossDirSwapLogFile(SwapDir * sd, const char *ext) @@ -165,10 +166,45 @@ storeCossDirInit(SwapDir * sd) n_coss_dirs++; } +void +storeCossRemove(SwapDir *sd, StoreEntry *e) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + CossIndexNode *coss_node = e->repl.data; + e->repl.data = NULL; + dlinkDelete(&coss_node->node, &cs->index); + memPoolFree(coss_index_pool, coss_node); + cs->count -= 1; +} + +void +storeCossAdd(SwapDir *sd, StoreEntry *e) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + CossIndexNode *coss_node = memPoolAlloc(coss_index_pool); + assert(!e->repl.data); + e->repl.data = coss_node; + dlinkAdd(e, &coss_node->node, &cs->index); + cs->count += 1; +} + +static void +storeCossRebuildComplete(void *data) +{ + RebuildState *rb = data; + SwapDir *sd = rb->sd; + storeCossStartMembuf(sd); + store_dirs_rebuilding--; + storeCossDirCloseTmpSwapLog(rb->sd); + storeRebuildComplete(&rb->counts); + cbdataFree(rb); +} + static void storeCossRebuildFromSwapLog(void *data) { RebuildState *rb = data; + SwapDir *sd = rb->sd; StoreEntry *e = NULL; storeSwapLogData s; size_t ss = sizeof(storeSwapLogData); @@ -182,10 +218,7 @@ storeCossRebuildFromSwapLog(void *data) rb->sd->path, rb->n_read); fclose(rb->log); rb->log = NULL; - store_dirs_rebuilding--; - storeCossDirCloseTmpSwapLog(rb->sd); - storeRebuildComplete(&rb->counts); - cbdataFree(rb); + storeCossRebuildComplete(rb); return; } rb->n_read++; @@ -215,7 +248,7 @@ storeCossRebuildFromSwapLog(void *data) } storeRelease(e); /* Fake an unlink here, this is a bad hack :( */ - dlinkDelete(&e->repl.lru, &rb->sd->repl.lru.list); + storeCossRemove(sd, e); rb->counts.objcount--; rb->counts.cancelcount++; } @@ -285,9 +318,6 @@ storeCossAddDiskRestore(SwapDir * SD, const cache_key * key, e->swap_filen = file_number; e->swap_file_sz = swap_file_sz; e->lock_count = 0; -#if !HEAP_REPLACEMENT - e->refcount = 0; -#endif e->lastref = lastref; e->timestamp = timestamp; e->expires = expires; @@ -300,7 +330,7 @@ storeCossAddDiskRestore(SwapDir * SD, const cache_key * key, e->ping_status = PING_NONE; EBIT_CLR(e->flags, ENTRY_VALIDATED); storeHashInsert(e, key); /* do it after we clear KEY_PRIVATE */ - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); + storeCossAdd(SD, e); e->swap_filen = storeCossAllocate(SD, e, COSS_ALLOC_NOTIFY); return e; } @@ -313,8 +343,11 @@ storeCossDirRebuild(SwapDir * sd) int zero = 0; FILE *fp; EVH *func = NULL; + cbdataAdd(rb, cbdataXfree, 0); rb->sd = sd; rb->speed = opt_foreground_rebuild ? 1 << 30 : 50; + func = storeCossRebuildFromSwapLog; + rb->flags.clean = (unsigned int) clean; /* * If the swap.state file exists in the cache_dir, then * we'll use storeCossRebuildFromSwapLog(). @@ -322,6 +355,8 @@ storeCossDirRebuild(SwapDir * sd) fp = storeCossDirOpenTmpSwapLog(sd, &clean, &zero); debug(20, 1) ("Rebuilding COSS storage in %s (%s)\n", sd->path, clean ? "CLEAN" : "DIRTY"); + rb->log = fp; + store_dirs_rebuilding++; if (!clean || fp == NULL) { /* COSS cannot yet rebuild from a dirty state. If the log * is dirty then the COSS contents is thrown away. @@ -330,24 +365,15 @@ storeCossDirRebuild(SwapDir * sd) */ if (fp != NULL) fclose(fp); - storeCossDirCloseTmpSwapLog(rb->sd); /* * XXX Make sure we don't trigger an assertion if this is the first * storedir, since if we are, this call will cause storeRebuildComplete * to prematurely complete the rebuild process, and then some other * storedir will try to rebuild and eventually die. */ - store_dirs_rebuilding++; - storeRebuildComplete(&rb->counts); - store_dirs_rebuilding--; - xfree(rb); + eventAdd("storeCossRebuildComplete", storeCossRebuildComplete, rb, 0.0, 0); return; } - func = storeCossRebuildFromSwapLog; - rb->log = fp; - rb->flags.clean = (unsigned int) clean; - store_dirs_rebuilding++; - cbdataAdd(rb, cbdataXfree, 0); eventAdd("storeCossRebuild", func, rb, 0.0, 1); } @@ -435,6 +461,7 @@ struct _clean_state { char *outbuf; off_t outbuf_offset; int fd; + dlink_node *current; }; #define CLEAN_BUF_SZ 16384 @@ -444,8 +471,9 @@ struct _clean_state { * we succeed, and assign the 'func' and 'data' return pointers. */ static int -storeCossDirWriteCleanOpen(SwapDir * sd) +storeCossDirWriteCleanStart(SwapDir * sd) { + CossInfo *cs = (CossInfo *) sd->fsdata; struct _clean_state *state = xcalloc(1, sizeof(*state)); struct stat sb; sd->log.clean.write = NULL; @@ -460,6 +488,7 @@ storeCossDirWriteCleanOpen(SwapDir * sd) state->fd = file_open(state->new, O_WRONLY | O_CREAT | O_TRUNC); if (state->fd < 0) return -1; + state->current = cs->index.tail; debug(20, 3) ("storeCOssDirWriteCleanLogs: opened %s, FD %d\n", state->new, state->fd); #if HAVE_FCHMOD @@ -468,22 +497,33 @@ storeCossDirWriteCleanOpen(SwapDir * sd) #endif sd->log.clean.write = storeCossDirWriteCleanEntry; sd->log.clean.state = state; + return 0; } +static const StoreEntry * +storeCossDirCleanLogNextEntry(SwapDir * sd) +{ + struct _clean_state *state = sd->log.clean.state; + const StoreEntry *entry; + if (!state) + return NULL; + if (!state->current) + return NULL; + entry = (const StoreEntry *)state->current->data; + state->current = state->current->prev; + return entry; +} + /* * "write" an entry to the clean log file. */ static void -storeCossDirWriteCleanEntry(const StoreEntry * e, SwapDir * sd) +storeCossDirWriteCleanEntry(SwapDir *sd, const StoreEntry * e) { storeSwapLogData s; static size_t ss = sizeof(storeSwapLogData); struct _clean_state *state = sd->log.clean.state; - if (NULL == e) { - storeCossDirWriteCleanClose(sd); - return; - } memset(&s, '\0', ss); s.op = (char) SWAP_LOG_ADD; s.swap_filen = e->swap_filen; @@ -515,7 +555,7 @@ storeCossDirWriteCleanEntry(const StoreEntry * e, SwapDir * sd) } static void -storeCossDirWriteCleanClose(SwapDir * sd) +storeCossDirWriteCleanDone(SwapDir * sd) { struct _clean_state *state = sd->log.clean.state; if (state->fd < 0) @@ -600,13 +640,9 @@ static void storeCossDirShutdown(SwapDir * SD) { CossInfo *cs = (CossInfo *) SD->fsdata; - CossMemBuf *t; - /* we need to do this synchronously! */ - for (t = cs->membufs; t; t = t->next) { - lseek(cs->fd, t->diskstart, SEEK_SET); - write(cs->fd, t->buffer, COSS_MEMBUF_SZ); - } + storeCossSync(SD); + file_close(cs->fd); cs->fd = -1; @@ -705,7 +741,7 @@ storeCossDirParse(SwapDir * sd, int index, char *path) sd->refobj = NULL; /* LRU is done in storeCossRead */ sd->unrefobj = NULL; sd->callback = NULL; - sd->sync = NULL; /* should we make it call the coss sync? */ + sd->sync = storeCossSync; sd->obj.create = storeCossCreate; sd->obj.open = storeCossOpen; @@ -717,25 +753,19 @@ storeCossDirParse(SwapDir * sd, int index, char *path) sd->log.open = storeCossDirOpenSwapLog; sd->log.close = storeCossDirCloseSwapLog; sd->log.write = storeCossDirSwapLog; - sd->log.clean.open = storeCossDirWriteCleanOpen; + 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 = memPoolAlloc(coss_membuf_pool); - cs->membufs->diskstart = 0; - cs->membufs->diskend = COSS_MEMBUF_SZ; - cs->membufs->lockcount = 0; - cs->membufs->flags.full = 0; - cs->membufs->flags.writing = 0; - cs->membufs->next = NULL; - cs->membufs->SD = sd; + cs->membufs = NULL; /* set when the rebuild completes */ cs->current_membuf = cs->membufs; - - sd->repl.lru.list.head = NULL; - sd->repl.lru.list.tail = NULL; + cs->index.head = NULL; + cs->index.tail = NULL; } @@ -778,7 +808,7 @@ storeCossDirDump(StoreEntry * entry, const char *name, SwapDir * s) s->max_size >> 20); } -#if 0 +#if OLD_UNUSED_CODE SwapDir * storeCossDirPick(void) { @@ -840,5 +870,6 @@ storeFsSetup_coss(storefs_entry_t * storefs) storefs->donefunc = storeCossDirDone; coss_membuf_pool = memPoolCreate("COSS Membuf data", sizeof(CossMemBuf)); coss_state_pool = memPoolCreate("COSS IO State data", sizeof(CossState)); + 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 d361a269a5..64b5ad888b 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.3 2000/05/16 07:09:36 wessels Exp $ + * $Id: store_io_coss.cc,v 1.4 2000/06/08 18:05:38 hno Exp $ * * DEBUG: section 81 Storage Manager COSS Interface * AUTHOR: Eric Stern @@ -74,7 +74,7 @@ storeCossAllocate(SwapDir * SD, const StoreEntry * e, int which) else checkf = -1; - retofs = e->swap_filen; /* Just for defaults */ + retofs = e->swap_filen; /* Just for defaults, or while rebuilding */ if (e->swap_file_sz > 0) allocsize = e->swap_file_sz; @@ -107,7 +107,7 @@ storeCossAllocate(SwapDir * SD, const StoreEntry * e, int which) } } if (coll == 0) { - cs->current_offset += allocsize; + cs->current_offset = retofs + allocsize; return retofs; } else { return -1; @@ -118,7 +118,7 @@ void storeCossUnlink(SwapDir * SD, StoreEntry * e) { debug(81, 3) ("storeCossUnlink: offset %d\n", e->swap_filen); - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); + storeCossRemove(SD, e); } @@ -148,15 +148,14 @@ storeCossCreate(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, STIOCB * c sio->callback_data = callback_data; cbdataLock(callback_data); sio->e = (StoreEntry *) e; - sio->st_size = -1; /* we won't know this until we read the metadata */ cstate->flags.writing = 0; cstate->flags.reading = 0; cstate->readbuffer = NULL; cstate->reqdiskoffset = -1; - /* Now add it into the LRU */ - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); + /* Now add it into the index list */ + storeCossAdd(SD, e); storeCossMemBufLock(SD, sio); return sio; @@ -231,10 +230,10 @@ storeCossOpen(SwapDir * SD, StoreEntry * e, STFNCB * file_callback, storeCossMemBufLock(SD, sio); /* - * Do the LRU magic to keep the disk and memory LRUs identical + * Do the index magic to keep the disk and memory LRUs identical */ - dlinkDelete(&sio->e->repl.lru, &SD->repl.lru.list); - dlinkAdd(sio->e, &sio->e->repl.lru, &SD->repl.lru.list); + storeCossRemove(SD, e); + storeCossAdd(SD, e); /* * Since we've reallocated a spot for this object, we need to @@ -410,6 +409,22 @@ storeCossMemBufUnlock(SwapDir * SD, storeIOState * e) } } +void +storeCossSync(SwapDir * SD) +{ + CossInfo *cs = (CossInfo *) SD->fsdata; + CossMemBuf *t; + int end; + if (!cs->membufs) + return; + for (t=cs->membufs; t; t = t->next) { + if (t->flags.writing) + sleep(5); + lseek(cs->fd, t->diskstart, SEEK_SET); + end = (t == cs->current_membuf) ? cs->current_offset : t->diskend; + write(cs->fd, t->buffer, end - t->diskstart); + } +} static void storeCossWriteMemBuf(SwapDir * SD, CossMemBuf * t) @@ -418,9 +433,9 @@ storeCossWriteMemBuf(SwapDir * SD, CossMemBuf * t) debug(81, 3) ("storeCossWriteMemBuf: offset %d, len %d\n", t->diskstart, t->diskend - t->diskstart); cbdataAdd(t, storeCossMembufFree, 0); + t->flags.writing = 1; file_write(cs->fd, t->diskstart, &t->buffer, t->diskend - t->diskstart, storeCossWriteMemBufDone, t, NULL); - t->flags.writing = 1; } @@ -472,15 +487,16 @@ storeCossCreateMemBuf(SwapDir * SD, size_t start, newmb->flags.writing = 0; newmb->lockcount = 0; newmb->SD = SD; + /* XXX This should be reversed, with the new buffer last in the chain */ newmb->next = cs->membufs; cs->membufs = newmb; for (t = cs->membufs; t; t = t->next) debug(81, 3) ("storeCossCreateMemBuf: membuflist %d lockcount %d\n", t->diskstart, t->lockcount); /* - * XXX more evil LRU specific code. This needs to be replaced. + * Kill objects from the tail to make space for a new chunk */ - for (m = SD->repl.lru.list.tail; m; m = prev) { + for (m = cs->index.tail; m; m = prev) { prev = m->prev; e = m->data; if (curfn == e->swap_filen) @@ -497,6 +513,18 @@ storeCossCreateMemBuf(SwapDir * SD, size_t start, return newmb; } +/* + * Creates the initial membuf after rebuild + */ +void +storeCossStartMembuf(SwapDir *sd) +{ + CossInfo *cs = (CossInfo *) sd->fsdata; + CossMemBuf *newmb = storeCossCreateMemBuf(sd, cs->current_offset, -1, NULL); + assert(!cs->current_membuf); + cs->current_membuf = newmb; +} + /* * We can't pass memFree() as a free function here, because we need to free * the fsstate variable .. diff --git a/src/fs/diskd/store_dir_diskd.cc b/src/fs/diskd/store_dir_diskd.cc index 6e737d7a9b..1b62da48ab 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.10 2000/05/29 03:10:39 wessels Exp $ + * $Id: store_dir_diskd.cc,v 1.11 2000/06/08 18:05:38 hno Exp $ * * DEBUG: section 47 Store Directory Routines * AUTHOR: Duane Wessels @@ -109,9 +109,10 @@ static FILE *storeDiskdDirOpenTmpSwapLog(SwapDir *, int *, int *); static STLOGOPEN storeDiskdDirOpenSwapLog; static STINIT storeDiskdDirInit; static STFREE storeDiskdDirFree; -static STLOGCLEANOPEN storeDiskdDirWriteCleanOpen; -static void storeDiskdDirWriteCleanClose(SwapDir * sd); +static STLOGCLEANSTART storeDiskdDirWriteCleanStart; +static STLOGCLEANNEXTENTRY storeDiskdDirCleanLogNextEntry; static STLOGCLEANWRITE storeDiskdDirWriteCleanEntry; +static STLOGCLEANDONE storeDiskdDirWriteCleanDone; static STLOGCLOSE storeDiskdDirCloseSwapLog; static STLOGWRITE storeDiskdDirSwapLog; static STNEWFS storeDiskdDirNewfs; @@ -129,10 +130,6 @@ static int storeDiskdCleanupDoubleCheck(SwapDir *, StoreEntry *); static void storeDiskdDirStats(SwapDir *, StoreEntry *); static void storeDiskdDirInitBitmap(SwapDir *); static int storeDiskdDirValidFileno(SwapDir *, sfileno, int); -static int storeDiskdDirCheckExpired(SwapDir *, StoreEntry *); -#if !HEAP_REPLACEMENT -static time_t storeDiskdDirExpiredReferenceAge(SwapDir *); -#endif static void storeDiskdStats(StoreEntry * sentry); static void storeDiskdDirSync(SwapDir *); @@ -475,31 +472,31 @@ storeDiskdDirSync(SwapDir * SD) * until the queue is below magic2. Otherwise, we simply return when we * don't get a message. */ -void +int storeDiskdDirCallback(SwapDir * SD) { diomsg M; int x; diskdinfo_t *diskdinfo = SD->fsdata; + int retval = 0; - if (diskdinfo->away >= diskdinfo->magic2) + if (diskdinfo->away >= diskdinfo->magic2) { diskd_stats.block_queue_len++; + retval = 1; /* We might not have anything to do, but our queue + * is full.. */ + } if (diskd_stats.sent_count - diskd_stats.recv_count > diskd_stats.max_away) { diskd_stats.max_away = diskd_stats.sent_count - diskd_stats.recv_count; diskd_stats.max_shmuse = diskd_stats.shmbuf_count; } - /* if we are above magic2, we do not break under any reason */ while (1) { memset(&M, '\0', sizeof(M)); x = msgrcv(diskdinfo->rmsgid, &M, msg_snd_rcv_sz, 0, IPC_NOWAIT); - if (x < 0) { - if (diskdinfo->away >= diskdinfo->magic2) - continue; - else + if (x < 0) break; - } else if (x != msg_snd_rcv_sz) { + else if (x != msg_snd_rcv_sz) { debug(81, 1) ("storeDiskdDirCallback: msgget returns %d\n", x); break; @@ -507,9 +504,11 @@ storeDiskdDirCallback(SwapDir * SD) diskd_stats.recv_count++; diskdinfo->away--; storeDiskdHandle(&M); + retval = 1; /* Return that we've actually done some work */ if (M.shm_offset > -1) storeDiskdShmPut(SD, M.shm_offset); } + return retval; } @@ -761,10 +760,7 @@ storeDiskdDirRebuildFromSwapLog(void *data) e->lastmod = s.lastmod; e->flags = s.flags; e->refcount += s.refcount; -#if HEAP_REPLACEMENT - storeHeapPositionUpdate(e, SD); storeDiskdDirUnrefObj(SD, e); -#endif } else { debug_trap("storeDiskdDirRebuildFromSwapLog: bad condition"); debug(20, 1) ("\tSee %s:%d\n", __FILE__, __LINE__); @@ -944,9 +940,6 @@ storeDiskdDirAddDiskRestore(SwapDir * SD, const cache_key * key, e->swap_dirn = SD->index; e->swap_file_sz = swap_file_sz; e->lock_count = 0; -#if !HEAP_REPLACEMENT - e->refcount = 0; -#endif e->lastref = lastref; e->timestamp = timestamp; e->expires = expires; @@ -1083,6 +1076,7 @@ struct _clean_state { char *outbuf; off_t outbuf_offset; int fd; + RemovalPolicyWalker *walker; }; #define CLEAN_BUF_SZ 16384 @@ -1092,7 +1086,7 @@ struct _clean_state { * we succeed, and assign the 'func' and 'data' return pointers. */ static int -storeDiskdDirWriteCleanOpen(SwapDir * sd) +storeDiskdDirWriteCleanStart(SwapDir * sd) { struct _clean_state *state = xcalloc(1, sizeof(*state)); struct stat sb; @@ -1103,6 +1097,7 @@ storeDiskdDirWriteCleanOpen(SwapDir * sd) state->cln = xstrdup(storeDiskdDirSwapLogFile(sd, ".last-clean")); state->outbuf = xcalloc(CLEAN_BUF_SZ, 1); state->outbuf_offset = 0; + state->walker = sd->repl->WalkInit(sd->repl); unlink(state->new); unlink(state->cln); state->fd = file_open(state->new, O_WRONLY | O_CREAT | O_TRUNC); @@ -1119,19 +1114,28 @@ storeDiskdDirWriteCleanOpen(SwapDir * sd) return 0; } +/* + * Get the next entry that is a candidate for clean log writing + */ +const StoreEntry * +storeDiskdDirCleanLogNextEntry(SwapDir * sd) +{ + const StoreEntry *entry = NULL; + struct _clean_state *state = sd->log.clean.state; + if (state->walker) + entry = state->walker->Next(state->walker); + return entry; +} + /* * "write" an entry to the clean log file. */ static void -storeDiskdDirWriteCleanEntry(const StoreEntry * e, SwapDir * sd) +storeDiskdDirWriteCleanEntry(SwapDir *sd, const StoreEntry * e) { storeSwapLogData s; static size_t ss = sizeof(storeSwapLogData); struct _clean_state *state = sd->log.clean.state; - if (NULL == e) { - storeDiskdDirWriteCleanClose(sd); - return; - } memset(&s, '\0', ss); s.op = (char) SWAP_LOG_ADD; s.swap_filen = e->swap_filen; @@ -1163,11 +1167,12 @@ storeDiskdDirWriteCleanEntry(const StoreEntry * e, SwapDir * sd) } static void -storeDiskdDirWriteCleanClose(SwapDir * sd) +storeDiskdDirWriteCleanDone(SwapDir * sd) { struct _clean_state *state = sd->log.clean.state; if (state->fd < 0) return; + state->walker->Done(state->walker); if (write(state->fd, state->outbuf, state->outbuf_offset) < 0) { debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", state->new, xstrerror()); @@ -1425,30 +1430,18 @@ void storeDiskdDirMaintain(SwapDir * SD) { StoreEntry *e = NULL; - int scanned = 0; - int locked = 0; - int expired = 0; + int removed = 0; int max_scan; int max_remove; double f; - static time_t last_warn_time = 0; -#if !HEAP_REPLACEMENT - dlink_node *m; - dlink_node *prev = NULL; -#else - heap_key age; - heap_key min_age = 0.0; - link_list *locked_entries = NULL; -#if HEAP_REPLACEMENT_DEBUG - if (!verify_heap_property(SD->repl.heap.heap)) { - debug(20, 1) ("Heap property violated!\n"); - } -#endif -#endif + RemovalPurgeWalker *walker; /* We can't delete objects while rebuilding swap */ if (store_dirs_rebuilding) { return; } else { + /* XXX FixMe: This should use the cache_dir hig/low values, not the + * global ones + */ f = (double) (store_swap_size - store_swap_low) / (store_swap_high - store_swap_low); f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f; max_scan = (int) (f * 400.0 + 100.0); @@ -1456,120 +1449,26 @@ storeDiskdDirMaintain(SwapDir * SD) /* * This is kinda cheap, but so we need this priority hack? */ -#if 0 - eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0 - f, 1); -#endif } debug(20, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n", f, max_scan, max_remove); -#if HEAP_REPLACEMENT - while (heap_nodes(SD->repl.heap.heap) > 0) { - if (store_swap_size < store_swap_low) - break; - if (expired >= max_remove) - break; - if (scanned >= max_scan) - break; - age = heap_peepminkey(SD->repl.heap.heap); - e = heap_extractmin(SD->repl.heap.heap); - e->repl.node = NULL; /* no longer in the heap */ - scanned++; - if (storeEntryLocked(e)) { - /* - * Entry is in use ... put it in a linked list to ignore it. - */ - if (!EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - /* - * If this was a "SPECIAL" do not add it back into the heap. - * It will always be "SPECIAL" and therefore never removed. - */ - debug(20, 4) ("storeDiskdDirMaintain: locked url %s\n", - (e->mem_obj && e->mem_obj->url) ? e->mem_obj->url : storeKeyText(e-> - key)); - linklistPush(&locked_entries, e); - } - locked++; - continue; - } else if (storeDiskdDirCheckExpired(SD, e)) { - /* - * Note: This will not check the reference age ifdef - * HEAP_REPLACEMENT, but it does some other useful - * checks... - */ - expired++; - debug(20, 3) ("Released store object age %f size %d refs %d key %s\n", - age, e->swap_file_sz, e->refcount, storeKeyText(e->key)); - min_age = age; - storeRelease(e); - } else { - /* - * Did not expire the object so we need to add it back - * into the heap! - */ - debug(20, 5) ("storeMaintainSwapSpace: non-expired %s\n", - storeKeyText(e->key)); - linklistPush(&locked_entries, e); - continue; - } + walker = SD->repl->PurgeInit(SD->repl, max_scan); + while (1) { + /* XXX FixMe: This should use the cache_dir hig/low values, not the + * global ones + */ if (store_swap_size < store_swap_low) break; - else if (expired >= max_remove) - break; - else if (scanned >= max_scan) + if (removed >= max_remove) break; + e = walker->Next(walker); + if (!e) + break; /* no more objects */ + removed++; + storeRelease(e); } - /* - * Bump the heap age factor. - */ - if (min_age > 0.0) - SD->repl.heap.heap->age = min_age; - /* - * Reinsert all bumped locked entries back into heap... - */ - while ((e = linklistShift(&locked_entries))) - e->repl.node = heap_insert(SD->repl.heap.heap, e); -#else - for (m = SD->repl.lru.list.tail; m; m = prev) { - prev = m->prev; - e = m->data; - scanned++; - if (storeEntryLocked(e)) { - /* - * If there is a locked entry at the tail of the LRU list, - * move it to the beginning to get it out of the way. - * Theoretically, we might have all locked objects at the - * tail, and then we'll never remove anything here and the - * LRU age will go to zero. - */ - if (memInUse(MEM_STOREENTRY) > max_scan) { - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); - } - locked++; - - } else if (storeDiskdDirCheckExpired(SD, e)) { - expired++; - storeRelease(e); - } - if (expired >= max_remove) - break; - if (scanned >= max_scan) - break; - } -#endif - debug(20, (expired ? 2 : 3)) ("storeMaintainSwapSpace: scanned %d/%d removed %d/%d locked %d f=%.03f\n", - scanned, max_scan, expired, max_remove, locked, f); - debug(20, 3) ("storeMaintainSwapSpace stats:\n"); - debug(20, 3) (" %6d objects\n", memInUse(MEM_STOREENTRY)); - debug(20, 3) (" %6d were scanned\n", scanned); - debug(20, 3) (" %6d were locked\n", locked); - debug(20, 3) (" %6d were expired\n", expired); - if (store_swap_size < Config.Swap.maxSize) - return; - if (squid_curtime - last_warn_time < 10) - return; - debug(20, 0) ("WARNING: Disk space over limit: %d KB > %d KB\n", - store_swap_size, Config.Swap.maxSize); - last_warn_time = squid_curtime; + walker->Done(walker); + debug(20, (removed ? 2 : 3)) ("storeDiskdDirMaintain: %s removed %d/%d f=%.03f max_scan=%d\n", + SD->path, removed, max_remove, f, max_scan); } /* @@ -1585,7 +1484,7 @@ storeDiskdDirCheckObj(SwapDir * SD, const StoreEntry * e) int loadav; diskdinfo_t *diskdinfo = SD->fsdata; -#if !HEAP_REPLACEMENT +#if OLD_UNUSED_CODE if (storeDiskdDirExpiredReferenceAge(SD) < 300) { debug(20, 3) ("storeDiskdDirCheckObj: NO: LRU Age = %d\n", storeDiskdDirExpiredReferenceAge(SD)); @@ -1617,16 +1516,8 @@ storeDiskdDirRefObj(SwapDir * SD, StoreEntry * e) { debug(1, 3) ("storeDiskdDirRefObj: referencing %p %d/%d\n", e, e->swap_dirn, e->swap_filen); -#if HEAP_REPLACEMENT - /* Nothing to do here */ -#else - /* Reference the object */ - if (!EBIT_TEST(e->flags, RELEASE_REQUEST) && - !EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); - } -#endif + if (SD->repl->Referenced) + SD->repl->Referenced(SD->repl, e, &e->repl); } /* @@ -1639,10 +1530,8 @@ storeDiskdDirUnrefObj(SwapDir * SD, StoreEntry * e) { debug(1, 3) ("storeDiskdDirUnrefObj: referencing %p %d/%d\n", e, e->swap_dirn, e->swap_filen); -#if HEAP_REPLACEMENT - if (e->repl.node) - heap_update(SD->repl.heap.heap, e->repl.node, e); -#endif + if (SD->repl->Dereferenced) + SD->repl->Dereferenced(SD->repl, e, &e->repl); } /* @@ -1656,80 +1545,10 @@ void storeDiskdDirUnlinkFile(SwapDir * SD, sfileno f) { debug(79, 3) ("storeDiskdDirUnlinkFile: unlinking fileno %08X\n", f); - storeDiskdDirMapBitReset(SD, f); + /* storeDiskdDirMapBitReset(SD, f); */ unlinkdUnlink(storeDiskdDirFullPath(SD, f, NULL)); } -#if !HEAP_REPLACEMENT -/* - * storeDiskdDirExpiredReferenceAge - * - * The LRU age is scaled exponentially between 1 minute and - * Config.referenceAge , when store_swap_low < store_swap_size < - * store_swap_high. This keeps store_swap_size within the low and high - * water marks. If the cache is very busy then store_swap_size stays - * closer to the low water mark, if it is not busy, then it will stay - * near the high water mark. The LRU age value can be examined on the - * cachemgr 'info' page. - */ -static time_t -storeDiskdDirExpiredReferenceAge(SwapDir * SD) -{ - double x; - double z; - time_t age; - long store_high, store_low; - - store_high = (long) (((float) SD->max_size * - (float) Config.Swap.highWaterMark) / (float) 100); - store_low = (long) (((float) SD->max_size * - (float) Config.Swap.lowWaterMark) / (float) 100); - debug(20, 20) ("RA: Dir %s, hi=%d, lo=%d, cur=%d\n", SD->path, store_high, store_low, SD->cur_size); - - x = (double) (store_high - SD->cur_size) / - (store_high - store_low); - x = x < 0.0 ? 0.0 : x > 1.0 ? 1.0 : x; - z = pow((double) (Config.referenceAge / 60), x); - age = (time_t) (z * 60.0); - if (age < 60) - age = 60; - else if (age > Config.referenceAge) - age = Config.referenceAge; - return age; -} -#endif - -/* - * storeDiskdDirCheckExpired - * - * Check whether the given object is expired or not - * It breaks layering a little by calling the upper layers to find - * out whether the object is locked or not, but we can't help this - * right now. - */ -static int -storeDiskdDirCheckExpired(SwapDir * SD, StoreEntry * e) -{ - if (storeEntryLocked(e)) - return 0; - if (EBIT_TEST(e->flags, RELEASE_REQUEST)) - return 1; - if (EBIT_TEST(e->flags, ENTRY_NEGCACHED) && squid_curtime >= e->expires) - return 1; - -#if HEAP_REPLACEMENT - /* - * with HEAP_REPLACEMENT we are not using the LRU reference age, the heap - * controls the replacement of objects. - */ - return 1; -#else - if (squid_curtime - e->lastref > storeDiskdDirExpiredReferenceAge(SD)) - return 1; - return 0; -#endif -} - /* * Add and remove the given StoreEntry from the replacement policy in * use. @@ -1740,17 +1559,7 @@ storeDiskdDirReplAdd(SwapDir * SD, StoreEntry * e) { debug(20, 4) ("storeDiskdDirReplAdd: added node %p to dir %d\n", e, SD->index); -#if HEAP_REPLACEMENT - if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - (void) 0; - } else { - e->repl.node = heap_insert(SD->repl.heap.heap, e); - debug(20, 4) ("storeDiskdDirReplAdd: inserted node 0x%x\n", e->repl.node); - } -#else - /* Shouldn't we not throw special objects into the lru ? */ - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); -#endif + SD->repl->Add(SD->repl, e, &e->repl); } @@ -1760,17 +1569,7 @@ storeDiskdDirReplRemove(StoreEntry * e) SwapDir *SD = INDEXSD(e->swap_dirn); debug(20, 4) ("storeDiskdDirReplRemove: remove node %p from dir %d\n", e, SD->index); -#if HEAP_REPLACEMENT - /* And now, release the object from the replacement policy */ - if (e->repl.node) { - debug(20, 4) ("storeDiskdDirReplRemove: deleting node 0x%x\n", - e->repl.node); - heap_delete(SD->repl.heap.heap, e->repl.node); - e->repl.node = NULL; - } -#else - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); -#endif + SD->repl->Remove(SD->repl, e, &e->repl); } @@ -1846,15 +1645,15 @@ storeDiskdDirStats(SwapDir * SD, StoreEntry * sentry) if (SD->flags.read_only) storeAppendPrintf(sentry, " READ-ONLY"); storeAppendPrintf(sentry, "\n"); +#if OLD_UNUSED_CODE #if !HEAP_REPLACEMENT storeAppendPrintf(sentry, "LRU Expiration Age: %6.2f days\n", (double) storeDiskdDirExpiredReferenceAge(SD) / 86400.0); #else -#if 0 storeAppendPrintf(sentry, "Storage Replacement Threshold:\t%f\n", heap_peepminkey(sd.repl.heap.heap)); #endif -#endif +#endif /* OLD_UNUSED_CODE */ storeAppendPrintf(sentry, "Pending operations: %d\n", diskdinfo->away); } @@ -2072,41 +1871,12 @@ storeDiskdDirParse(SwapDir * sd, int index, char *path) sd->log.open = storeDiskdDirOpenSwapLog; sd->log.close = storeDiskdDirCloseSwapLog; sd->log.write = storeDiskdDirSwapLog; - sd->log.clean.open = storeDiskdDirWriteCleanOpen; + sd->log.clean.start = storeDiskdDirWriteCleanStart; + sd->log.clean.nextentry = storeDiskdDirCleanLogNextEntry; + sd->log.clean.done = storeDiskdDirWriteCleanDone; /* Initialise replacement policy stuff */ -#if HEAP_REPLACEMENT - /* - * Create new heaps with cache replacement policies attached to them. - * The cache replacement policy is specified as either GDSF or LFUDA in - * the squid.conf configuration file. Note that the replacement policy - * applies only to the disk replacement algorithm. Memory replacement - * always uses GDSF since we want to maximize object hit rate. - */ - if (Config.replPolicy) { - if (tolower(Config.replPolicy[0]) == 'g') { - debug(20, 1) ("Using GDSF disk replacement policy\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_GDSF); - } else if (tolower(Config.replPolicy[0]) == 'l') { - if (tolower(Config.replPolicy[1]) == 'f') { - debug(20, 1) ("Using LFUDA disk replacement policy\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_LFUDA); - } else if (tolower(Config.replPolicy[1]) == 'r') { - debug(20, 1) ("Using LRU heap disk replacement policy\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_LRU); - } - } else { - debug(20, 1) ("Unrecognized replacement_policy; using GDSF\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_GDSF); - } - } else { - debug(20, 1) ("Using default disk replacement policy (GDSF)\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_GDSF); - } -#else - sd->repl.lru.list.head = NULL; - sd->repl.lru.list.tail = NULL; -#endif + sd->repl = createRemovalPolicy(Config.replPolicy); } /* diff --git a/src/fs/diskd/store_diskd.h b/src/fs/diskd/store_diskd.h index 0ee2d89149..4c410d09a0 100644 --- a/src/fs/diskd/store_diskd.h +++ b/src/fs/diskd/store_diskd.h @@ -93,7 +93,7 @@ extern void storeDiskdDirReplRemove(StoreEntry *); extern void storeDiskdShmPut(SwapDir *, int); extern void *storeDiskdShmGet(SwapDir *, int *); extern void storeDiskdHandle(diomsg * M); -extern void storeDiskdDirCallback(SwapDir *); +extern int storeDiskdDirCallback(SwapDir *); /* diff --git a/src/fs/ufs/store_dir_ufs.cc b/src/fs/ufs/store_dir_ufs.cc index 659528f5e7..df51ca615e 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.4 2000/05/29 03:10:42 wessels Exp $ + * $Id: store_dir_ufs.cc,v 1.5 2000/06/08 18:05:39 hno Exp $ * * DEBUG: section 47 Store Directory Routines * AUTHOR: Duane Wessels @@ -99,9 +99,10 @@ static FILE *storeUfsDirOpenTmpSwapLog(SwapDir *, int *, int *); static STLOGOPEN storeUfsDirOpenSwapLog; static STINIT storeUfsDirInit; static STFREE storeUfsDirFree; -static STLOGCLEANOPEN storeUfsDirWriteCleanOpen; -static void storeUfsDirWriteCleanClose(SwapDir * sd); +static STLOGCLEANSTART storeUfsDirWriteCleanStart; +static STLOGCLEANNEXTENTRY storeUfsDirCleanLogNextEntry; static STLOGCLEANWRITE storeUfsDirWriteCleanEntry; +static STLOGCLEANDONE storeUfsDirWriteCleanDone; static STLOGCLOSE storeUfsDirCloseSwapLog; static STLOGWRITE storeUfsDirSwapLog; static STNEWFS storeUfsDirNewfs; @@ -119,10 +120,6 @@ static int storeUfsCleanupDoubleCheck(SwapDir *, StoreEntry *); static void storeUfsDirStats(SwapDir *, StoreEntry *); static void storeUfsDirInitBitmap(SwapDir *); static int storeUfsDirValidFileno(SwapDir *, sfileno, int); -static int storeUfsDirCheckExpired(SwapDir *, StoreEntry *); -#if !HEAP_REPLACEMENT -static time_t storeUfsDirExpiredReferenceAge(SwapDir *); -#endif /* * These functions were ripped straight out of the heart of store_dir.c. @@ -351,9 +348,9 @@ storeUfsDirInit(SwapDir * sd) { 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."; + "\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."; storeUfsDirInitBitmap(sd); if (storeUfsDirVerifyCacheDirs(sd) < 0) fatal(errmsg); @@ -612,10 +609,7 @@ storeUfsDirRebuildFromSwapLog(void *data) e->lastmod = s.lastmod; e->flags = s.flags; e->refcount += s.refcount; -#if HEAP_REPLACEMENT - storeHeapPositionUpdate(e, SD); storeUfsDirUnrefObj(SD, e); -#endif } else { debug_trap("storeUfsDirRebuildFromSwapLog: bad condition"); debug(20, 1) ("\tSee %s:%d\n", __FILE__, __LINE__); @@ -693,8 +687,7 @@ storeUfsDirGetNextFile(RebuildState * rb, int *sfileno, int *size) debug(20, 3) ("storeUfsDirGetNextFile: flag=%d, %d: /%02X/%02X\n", rb->flags.init, rb->sd->index, - rb->curlvl1, - rb->curlvl2); + rb->curlvl1, rb->curlvl2); if (rb->done) return -2; while (fd < 0 && rb->done == 0) { @@ -710,7 +703,8 @@ storeUfsDirGetNextFile(RebuildState * rb, int *sfileno, int *size) 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); + rb->curlvl1, + rb->curlvl2); if (rb->flags.init && rb->td != NULL) closedir(rb->td); rb->td = NULL; @@ -795,9 +789,6 @@ storeUfsDirAddDiskRestore(SwapDir * SD, const cache_key * key, e->swap_dirn = SD->index; e->swap_file_sz = swap_file_sz; e->lock_count = 0; -#if !HEAP_REPLACEMENT - e->refcount = 0; -#endif e->lastref = lastref; e->timestamp = timestamp; e->expires = expires; @@ -934,6 +925,7 @@ struct _clean_state { char *outbuf; off_t outbuf_offset; int fd; + RemovalPolicyWalker *walker; }; #define CLEAN_BUF_SZ 16384 @@ -943,7 +935,7 @@ struct _clean_state { * we succeed, and assign the 'func' and 'data' return pointers. */ static int -storeUfsDirWriteCleanOpen(SwapDir * sd) +storeUfsDirWriteCleanStart(SwapDir * sd) { struct _clean_state *state = xcalloc(1, sizeof(*state)); struct stat sb; @@ -954,6 +946,7 @@ storeUfsDirWriteCleanOpen(SwapDir * sd) state->cln = xstrdup(storeUfsDirSwapLogFile(sd, ".last-clean")); state->outbuf = xcalloc(CLEAN_BUF_SZ, 1); state->outbuf_offset = 0; + state->walker = sd->repl->WalkInit(sd->repl); unlink(state->new); unlink(state->cln); state->fd = file_open(state->new, O_WRONLY | O_CREAT | O_TRUNC); @@ -970,19 +963,28 @@ storeUfsDirWriteCleanOpen(SwapDir * sd) return 0; } +/* + * Get the next entry that is a candidate for clean log writing + */ +const StoreEntry * +storeUfsDirCleanLogNextEntry(SwapDir * sd) +{ + const StoreEntry *entry = NULL; + struct _clean_state *state = sd->log.clean.state; + if (state->walker) + entry = state->walker->Next(state->walker); + return entry; +} + /* * "write" an entry to the clean log file. */ static void -storeUfsDirWriteCleanEntry(const StoreEntry * e, SwapDir * sd) +storeUfsDirWriteCleanEntry(SwapDir * sd, const StoreEntry * e) { storeSwapLogData s; static size_t ss = sizeof(storeSwapLogData); struct _clean_state *state = sd->log.clean.state; - if (NULL == e) { - storeUfsDirWriteCleanClose(sd); - return; - } memset(&s, '\0', ss); s.op = (char) SWAP_LOG_ADD; s.swap_filen = e->swap_filen; @@ -1014,11 +1016,12 @@ storeUfsDirWriteCleanEntry(const StoreEntry * e, SwapDir * sd) } static void -storeUfsDirWriteCleanClose(SwapDir * sd) +storeUfsDirWriteCleanDone(SwapDir * sd) { struct _clean_state *state = sd->log.clean.state; if (state->fd < 0) return; + state->walker->Done(state->walker); if (write(state->fd, state->outbuf, state->outbuf_offset) < 0) { debug(50, 0) ("storeDirWriteCleanLogs: %s: write: %s\n", state->new, xstrerror()); @@ -1276,30 +1279,18 @@ void storeUfsDirMaintain(SwapDir * SD) { StoreEntry *e = NULL; - int scanned = 0; - int locked = 0; - int expired = 0; + int removed = 0; int max_scan; int max_remove; double f; - static time_t last_warn_time = 0; -#if !HEAP_REPLACEMENT - dlink_node *m; - dlink_node *prev = NULL; -#else - heap_key age; - heap_key min_age = 0.0; - link_list *locked_entries = NULL; -#if HEAP_REPLACEMENT_DEBUG - if (!verify_heap_property(SD->repl.heap.heap)) { - debug(20, 1) ("Heap property violated!\n"); - } -#endif -#endif + RemovalPurgeWalker *walker; /* We can't delete objects while rebuilding swap */ if (store_dirs_rebuilding) { return; } else { + /* XXX FixMe: This should use the cache_dir hig/low values, not the + * global ones + */ f = (double) (store_swap_size - store_swap_low) / (store_swap_high - store_swap_low); f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f; max_scan = (int) (f * 400.0 + 100.0); @@ -1307,120 +1298,26 @@ storeUfsDirMaintain(SwapDir * SD) /* * This is kinda cheap, but so we need this priority hack? */ -#if 0 - eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0 - f, 1); -#endif } debug(20, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n", f, max_scan, max_remove); -#if HEAP_REPLACEMENT - while (heap_nodes(SD->repl.heap.heap) > 0) { - if (store_swap_size < store_swap_low) - break; - if (expired >= max_remove) - break; - if (scanned >= max_scan) - break; - age = heap_peepminkey(SD->repl.heap.heap); - e = heap_extractmin(SD->repl.heap.heap); - e->repl.node = NULL; /* no longer in the heap */ - scanned++; - if (storeEntryLocked(e)) { - /* - * Entry is in use ... put it in a linked list to ignore it. - */ - if (!EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - /* - * If this was a "SPECIAL" do not add it back into the heap. - * It will always be "SPECIAL" and therefore never removed. - */ - debug(20, 4) ("storeUfsDirMaintain: locked url %s\n", - (e->mem_obj && e->mem_obj->url) ? e->mem_obj->url : storeKeyText(e-> - key)); - linklistPush(&locked_entries, e); - } - locked++; - continue; - } else if (storeUfsDirCheckExpired(SD, e)) { - /* - * Note: This will not check the reference age ifdef - * HEAP_REPLACEMENT, but it does some other useful - * checks... - */ - expired++; - debug(20, 3) ("Released store object age %f size %d refs %d key %s\n", - age, e->swap_file_sz, e->refcount, storeKeyText(e->key)); - min_age = age; - storeRelease(e); - } else { - /* - * Did not expire the object so we need to add it back - * into the heap! - */ - debug(20, 5) ("storeMaintainSwapSpace: non-expired %s\n", - storeKeyText(e->key)); - linklistPush(&locked_entries, e); - continue; - } + walker = SD->repl->PurgeInit(SD->repl, max_scan); + while (1) { + /* XXX FixMe: This should use the cache_dir hig/low values, not the + * global ones + */ if (store_swap_size < store_swap_low) break; - else if (expired >= max_remove) - break; - else if (scanned >= max_scan) + if (removed >= max_remove) break; + e = walker->Next(walker); + if (!e) + break; /* no more objects */ + removed++; + storeRelease(e); } - /* - * Bump the heap age factor. - */ - if (min_age > 0.0) - SD->repl.heap.heap->age = min_age; - /* - * Reinsert all bumped locked entries back into heap... - */ - while ((e = linklistShift(&locked_entries))) - e->repl.node = heap_insert(SD->repl.heap.heap, e); -#else - for (m = SD->repl.lru.list.tail; m; m = prev) { - prev = m->prev; - e = m->data; - scanned++; - if (storeEntryLocked(e)) { - /* - * If there is a locked entry at the tail of the LRU list, - * move it to the beginning to get it out of the way. - * Theoretically, we might have all locked objects at the - * tail, and then we'll never remove anything here and the - * LRU age will go to zero. - */ - if (memInUse(MEM_STOREENTRY) > max_scan) { - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); - } - locked++; - - } else if (storeUfsDirCheckExpired(SD, e)) { - expired++; - storeRelease(e); - } - if (expired >= max_remove) - break; - if (scanned >= max_scan) - break; - } -#endif - debug(20, (expired ? 2 : 3)) ("storeMaintainSwapSpace: scanned %d/%d removed %d/%d locked %d f=%.03f\n", - scanned, max_scan, expired, max_remove, locked, f); - debug(20, 3) ("storeMaintainSwapSpace stats:\n"); - debug(20, 3) (" %6d objects\n", memInUse(MEM_STOREENTRY)); - debug(20, 3) (" %6d were scanned\n", scanned); - debug(20, 3) (" %6d were locked\n", locked); - debug(20, 3) (" %6d were expired\n", expired); - if (store_swap_size < Config.Swap.maxSize) - return; - if (squid_curtime - last_warn_time < 10) - return; - debug(20, 0) ("WARNING: Disk space over limit: %d KB > %d KB\n", - store_swap_size, Config.Swap.maxSize); - last_warn_time = squid_curtime; + walker->Done(walker); + debug(20, (removed ? 2 : 3)) ("storeUfsDirMaintain: %s removed %d/%d f=%.03f max_scan=%d\n", + SD->path, removed, max_remove, f, max_scan); } /* @@ -1433,7 +1330,7 @@ storeUfsDirMaintain(SwapDir * SD) int storeUfsDirCheckObj(SwapDir * SD, const StoreEntry * e) { -#if !HEAP_REPLACEMENT +#if OLD_UNUSED_CODE if (storeUfsDirExpiredReferenceAge(SD) < 300) { debug(20, 3) ("storeUfsDirCheckObj: NO: LRU Age = %d\n", storeUfsDirExpiredReferenceAge(SD)); @@ -1456,16 +1353,8 @@ storeUfsDirRefObj(SwapDir * SD, StoreEntry * e) { debug(1, 3) ("storeUfsDirRefObj: referencing %p %d/%d\n", e, e->swap_dirn, e->swap_filen); -#if HEAP_REPLACEMENT - /* Nothing to do here */ -#else - /* Reference the object */ - if (!EBIT_TEST(e->flags, RELEASE_REQUEST) && - !EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); - } -#endif + if (SD->repl->Referenced) + SD->repl->Referenced(SD->repl, e, &e->repl); } /* @@ -1478,10 +1367,8 @@ storeUfsDirUnrefObj(SwapDir * SD, StoreEntry * e) { debug(1, 3) ("storeUfsDirUnrefObj: referencing %p %d/%d\n", e, e->swap_dirn, e->swap_filen); -#if HEAP_REPLACEMENT - if (e->repl.node) - heap_update(SD->repl.heap.heap, e->repl.node, e); -#endif + if (SD->repl->Dereferenced) + SD->repl->Dereferenced(SD->repl, e, &e->repl); } /* @@ -1495,80 +1382,10 @@ void storeUfsDirUnlinkFile(SwapDir * SD, sfileno f) { debug(79, 3) ("storeUfsDirUnlinkFile: unlinking fileno %08X\n", f); - storeUfsDirMapBitReset(SD, f); + /* storeUfsDirMapBitReset(SD, f); */ unlinkdUnlink(storeUfsDirFullPath(SD, f, NULL)); } -#if !HEAP_REPLACEMENT -/* - * storeUfsDirExpiredReferenceAge - * - * The LRU age is scaled exponentially between 1 minute and - * Config.referenceAge , when store_swap_low < store_swap_size < - * store_swap_high. This keeps store_swap_size within the low and high - * water marks. If the cache is very busy then store_swap_size stays - * closer to the low water mark, if it is not busy, then it will stay - * near the high water mark. The LRU age value can be examined on the - * cachemgr 'info' page. - */ -static time_t -storeUfsDirExpiredReferenceAge(SwapDir * SD) -{ - double x; - double z; - time_t age; - long store_high, store_low; - - store_high = (long) (((float) SD->max_size * - (float) Config.Swap.highWaterMark) / (float) 100); - store_low = (long) (((float) SD->max_size * - (float) Config.Swap.lowWaterMark) / (float) 100); - debug(20, 20) ("RA: Dir %s, hi=%d, lo=%d, cur=%d\n", SD->path, store_high, store_low, SD->cur_size); - - x = (double) (store_high - SD->cur_size) / - (store_high - store_low); - x = x < 0.0 ? 0.0 : x > 1.0 ? 1.0 : x; - z = pow((double) (Config.referenceAge / 60), x); - age = (time_t) (z * 60.0); - if (age < 60) - age = 60; - else if (age > Config.referenceAge) - age = Config.referenceAge; - return age; -} -#endif - -/* - * storeUfsDirCheckExpired - * - * Check whether the given object is expired or not - * It breaks layering a little by calling the upper layers to find - * out whether the object is locked or not, but we can't help this - * right now. - */ -static int -storeUfsDirCheckExpired(SwapDir * SD, StoreEntry * e) -{ - if (storeEntryLocked(e)) - return 0; - if (EBIT_TEST(e->flags, RELEASE_REQUEST)) - return 1; - if (EBIT_TEST(e->flags, ENTRY_NEGCACHED) && squid_curtime >= e->expires) - return 1; - -#if HEAP_REPLACEMENT - /* - * with HEAP_REPLACEMENT we are not using the LRU reference age, the heap - * controls the replacement of objects. - */ - return 1; -#else - if (squid_curtime - e->lastref > storeUfsDirExpiredReferenceAge(SD)) - return 1; - return 0; -#endif -} - /* * Add and remove the given StoreEntry from the replacement policy in * use. @@ -1579,17 +1396,7 @@ storeUfsDirReplAdd(SwapDir * SD, StoreEntry * e) { debug(20, 4) ("storeUfsDirReplAdd: added node %p to dir %d\n", e, SD->index); -#if HEAP_REPLACEMENT - if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - (void) 0; - } else { - e->repl.node = heap_insert(SD->repl.heap.heap, e); - debug(20, 4) ("storeUfsDirReplAdd: inserted node 0x%x\n", e->repl.node); - } -#else - /* Shouldn't we not throw special objects into the lru ? */ - dlinkAdd(e, &e->repl.lru, &SD->repl.lru.list); -#endif + SD->repl->Add(SD->repl, e, &e->repl); } @@ -1599,17 +1406,7 @@ storeUfsDirReplRemove(StoreEntry * e) SwapDir *SD = INDEXSD(e->swap_dirn); debug(20, 4) ("storeUfsDirReplRemove: remove node %p from dir %d\n", e, SD->index); -#if HEAP_REPLACEMENT - /* And now, release the object from the replacement policy */ - if (e->repl.node) { - debug(20, 4) ("storeUfsDirReplRemove: deleting node 0x%x\n", - e->repl.node); - heap_delete(SD->repl.heap.heap, e->repl.node); - e->repl.node = NULL; - } -#else - dlinkDelete(&e->repl.lru, &SD->repl.lru.list); -#endif + SD->repl->Remove(SD->repl, e, &e->repl); } @@ -1653,15 +1450,15 @@ storeUfsDirStats(SwapDir * SD, StoreEntry * sentry) if (SD->flags.read_only) storeAppendPrintf(sentry, " READ-ONLY"); storeAppendPrintf(sentry, "\n"); +#if OLD_UNUSED_CODE #if !HEAP_REPLACEMENT storeAppendPrintf(sentry, "LRU Expiration Age: %6.2f days\n", (double) storeUfsDirExpiredReferenceAge(SD) / 86400.0); #else -#if 0 storeAppendPrintf(sentry, "Storage Replacement Threshold:\t%f\n", heap_peepminkey(sd.repl.heap.heap)); #endif -#endif +#endif /* OLD_UNUSED_CODE */ } /* @@ -1856,41 +1653,12 @@ storeUfsDirParse(SwapDir * sd, int index, char *path) sd->log.open = storeUfsDirOpenSwapLog; sd->log.close = storeUfsDirCloseSwapLog; sd->log.write = storeUfsDirSwapLog; - sd->log.clean.open = storeUfsDirWriteCleanOpen; + sd->log.clean.start = storeUfsDirWriteCleanStart; + sd->log.clean.nextentry = storeUfsDirCleanLogNextEntry; + sd->log.clean.done = storeUfsDirWriteCleanDone; /* Initialise replacement policy stuff */ -#if HEAP_REPLACEMENT - /* - * Create new heaps with cache replacement policies attached to them. - * The cache replacement policy is specified as either GDSF or LFUDA in - * the squid.conf configuration file. Note that the replacement policy - * applies only to the disk replacement algorithm. Memory replacement - * always uses GDSF since we want to maximize object hit rate. - */ - if (Config.replPolicy) { - if (tolower(Config.replPolicy[0]) == 'g') { - debug(20, 1) ("Using GDSF disk replacement policy\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_GDSF); - } else if (tolower(Config.replPolicy[0]) == 'l') { - if (tolower(Config.replPolicy[1]) == 'f') { - debug(20, 1) ("Using LFUDA disk replacement policy\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_LFUDA); - } else if (tolower(Config.replPolicy[1]) == 'r') { - debug(20, 1) ("Using LRU heap disk replacement policy\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_LRU); - } - } else { - debug(20, 1) ("Unrecognized replacement_policy; using GDSF\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_GDSF); - } - } else { - debug(20, 1) ("Using default disk replacement policy (GDSF)\n"); - sd->repl.heap.heap = new_heap(10000, HeapKeyGen_StoreEntry_GDSF); - } -#else - sd->repl.lru.list.head = NULL; - sd->repl.lru.list.tail = NULL; -#endif + sd->repl = createRemovalPolicy(Config.replPolicy); } /* diff --git a/src/globals.h b/src/globals.h index da90d7c047..884c91ff80 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1,6 +1,6 @@ /* - * $Id: globals.h,v 1.91 2000/05/31 04:26:32 wessels Exp $ + * $Id: globals.h,v 1.92 2000/06/08 18:05:35 hno Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -125,10 +125,6 @@ extern double request_failure_ratio; /* 0.0 */ extern double current_dtime; extern int store_hash_buckets; /* 0 */ extern hash_table *store_table; /* NULL */ -#if HEAP_REPLACEMENT -extern heap *inmem_heap; -#else -#endif extern dlink_list ClientActiveRequests; extern const String StringNull; /* { 0, 0, NULL } */ extern const MemBuf MemBufNull; /* MemBufNULL */ @@ -154,3 +150,4 @@ extern int store_swap_low; /* 0 */ extern int store_swap_high; /* 0 */ extern int store_pages_max; /* 0 */ extern ssize_t store_maxobjsize; /* -1 */ +extern RemovalPolicy *mem_policy; diff --git a/src/protos.h b/src/protos.h index e7e213aca3..4e4fdb3652 100644 --- a/src/protos.h +++ b/src/protos.h @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.369 2000/05/31 07:01:42 hno Exp $ + * $Id: protos.h,v 1.370 2000/06/08 18:05:35 hno Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -849,13 +849,6 @@ extern void storeFsInit(void); extern void storeFsDone(void); extern void storeFsAdd(char *, STSETUP *); -/* store_heap_replacement.c */ -#ifdef HEAP_REPLACEMENT -extern heap_key HeapKeyGen_StoreEntry_LFUDA(void *, double); -extern heap_key HeapKeyGen_StoreEntry_GDSF(void *, double); -extern heap_key HeapKeyGen_StoreEntry_LRU(void *, double); -#endif - /* store_modules.c */ extern void storeFsSetup(void); @@ -1185,6 +1178,10 @@ extern void logfilePrintf(Logfile * lf, const char *fmt,...); extern void logfilePrintf(va_alist); #endif +/* Removal Policies */ +RemovalPolicy * +createRemovalPolicy(RemovalPolicySettings *settings); + /* * prototypes for system functions missing from system includes */ diff --git a/src/repl/Makefile.in b/src/repl/Makefile.in new file mode 100644 index 0000000000..c4589edc85 --- /dev/null +++ b/src/repl/Makefile.in @@ -0,0 +1,35 @@ +# Makefile for storage modules in the Squid Object Cache server +# +# $Id: Makefile.in,v 1.1 2000/06/08 18:05:39 hno Exp $ +# + +SUBDIRS = @REPL_POLICIES@ + +all: + @test -z "$(SUBDIRS)" || for dir in $(SUBDIRS); do \ + sh -c "cd $$dir && $(MAKE) all" || exit 1; \ + done; \ + if [ ! -f stamp ]; then \ + touch stamp; \ + fi + +clean: + -rm -f *.a stamp + -for dir in *; do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) $@" || exit 1;\ + fi; \ + done + +distclean: + -rm -f *.a Makefile + -for dir in *; do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) distclean"; \ + fi; \ + done + +.DEFAULT: + @test -z "$(SUBDIRS)" || for dir in $(SUBDIRS); do \ + sh -c "cd $$dir && $(MAKE) $@" || exit 1; \ + done diff --git a/src/repl/heap/Makefile.in b/src/repl/heap/Makefile.in new file mode 100644 index 0000000000..a2e56b6958 --- /dev/null +++ b/src/repl/heap/Makefile.in @@ -0,0 +1,55 @@ +# +# Makefile for the UFS storage driver for the Squid Object Cache server +# +# $Id: Makefile.in,v 1.1 2000/06/08 18:05:40 hno Exp $ +# + +REPL = heap + +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +MAKEDEPEND = @MAKEDEPEND@ +AR_R = @AR_R@ +RANLIB = @RANLIB@ +AC_CFLAGS = @CFLAGS@ +SHELL = /bin/sh + +INCLUDE = -I../../../include -I$(top_srcdir)/include -I$(top_srcdir)/src/ +CFLAGS = $(AC_CFLAGS) $(INCLUDE) $(DEFINES) + +OUT = ../$(REPL).a + +OBJS = \ + store_repl_$(REPL).o \ + store_heap_replacement.o + +all: $(OUT) + +$(OUT): $(OBJS) + @rm -f ../stamp + $(AR_R) $(OUT) $(OBJS) + $(RANLIB) $(OUT) + +$(OBJS): $(top_srcdir)/include/version.h ../../../include/autoconf.h + +.c.o: + @rm -f ../stamp + $(CC) $(CFLAGS) -c $< + +clean: + -rm -rf *.o *pure_* core ../$(FS).a + +distclean: clean + -rm -f Makefile + -rm -f Makefile.bak + -rm -f tags + +install: + +tags: + ctags *.[ch] $(top_srcdir)/src/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[ch] + +depend: + $(MAKEDEPEND) $(INCLUDE) -fMakefile *.c diff --git a/src/repl/heap/store_heap_replacement.cc b/src/repl/heap/store_heap_replacement.cc new file mode 100644 index 0000000000..e04d459e81 --- /dev/null +++ b/src/repl/heap/store_heap_replacement.cc @@ -0,0 +1,138 @@ + +/* + * $Id: store_heap_replacement.cc,v 1.1 2000/06/08 18:05:40 hno Exp $ + * + * DEBUG: section 20 Storage Manager Heap-based replacement + * AUTHOR: John Dilley + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * the Regents of the University of California. Please see the + * COPYRIGHT file for full details. Squid incorporates software + * developed and/or copyrighted by other sources. Please 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. + * + */ + +/* + * The code in this file is Copyrighted (C) 1999 by Hewlett Packard. + * + * + * For a description of these cache replacement policies see -- + * http://www.hpl.hp.com/techreports/1999/HPL-1999-69.html + */ + +#include "squid.h" +#include "heap.h" + +/* + * Key generation function to implement the LFU-DA policy (Least + * Frequently Used with Dynamic Aging). Similar to classical LFU + * but with aging to handle turnover of the popular document set. + * Maximizes byte hit rate by keeping more currently popular objects + * in cache regardless of size. Achieves lower hit rate than GDS + * because there are more large objects in cache (so less room for + * smaller popular objects). + * + * This version implements a tie-breaker based upon recency + * (e->lastref): for objects that have the same reference count + * the most recent object wins (gets a higher key value). + * + * Note: this does not properly handle when the aging factor + * gets so huge that the added value is outside of the + * precision of double. However, Squid has to stay up + * for quite a extended period of time (number of requests) + * for this to become a problem. (estimation is 10^8 cache + * turnarounds) + */ +heap_key HeapKeyGen_StoreEntry_LFUDA(void *entry, double age) +{ + StoreEntry *e = entry; + heap_key key; + double tie; + if (e->lastref <= 0) + tie = 0.0; + else if (squid_curtime <= e->lastref) + tie = 0.0; + else + tie = 1.0 - exp((double) (e->lastref - squid_curtime) / 86400.0); + key = age + (double) e->refcount - tie; + debug(81, 3) ("HeapKeyGen_StoreEntry_LFUDA: %s refcnt=%ld lastref=%ld age=%f tie=%f -> %f\n", + storeKeyText(e->key), e->refcount, e->lastref, age, tie, key); + if (e->mem_obj && e->mem_obj->url) + debug(81, 3) ("HeapKeyGen_StoreEntry_LFUDA: url=%s\n", + e->mem_obj->url); + return (double)key; +} + + +/* + * Key generation function to implement the GDS-Frequency policy. + * Similar to Greedy Dual-Size Hits policy, but adds aging of + * documents to prevent pollution. Maximizes object hit rate by + * keeping more small, popular objects in cache. Achieves lower + * byte hit rate than LFUDA because there are fewer large objects + * in cache. + * + * This version implements a tie-breaker based upon recency + * (e->lastref): for objects that have the same reference count + * the most recent object wins (gets a higher key value). + * + * Note: this does not properly handle when the aging factor + * gets so huge that the added value is outside of the + * precision of double. However, Squid has to stay up + * for quite a extended period of time (number of requests) + * for this to become a problem. (estimation is 10^8 cache + * turnarounds) + */ +heap_key HeapKeyGen_StoreEntry_GDSF(void *entry, double age) +{ + StoreEntry *e = entry; + heap_key key; + double size = e->swap_file_sz ? (double) e->swap_file_sz : 1.0; + double tie = (e->lastref > 1) ? (1.0 / e->lastref) : 1.0; + key = age + ((double) e->refcount / size) - tie; + debug(81, 3) ("HeapKeyGen_StoreEntry_GDSF: %s size=%f refcnt=%ld lastref=%ld age=%f tie=%f -> %f\n", + storeKeyText(e->key), size, e->refcount, e->lastref, age, tie, key); + if (e->mem_obj && e->mem_obj->url) + debug(81, 3) ("HeapKeyGen_StoreEntry_GDSF: url=%s\n", + e->mem_obj->url); + return key; +} + +/* + * Key generation function to implement the LRU policy. Normally + * one would not do this with a heap -- use the linked list instead. + * For testing and performance characterization it was useful. + * Don't use it unless you are trying to compare performance among + * heap-based replacement policies... + */ +heap_key HeapKeyGen_StoreEntry_LRU(void *entry, double age) +{ + StoreEntry *e = entry; + debug(81, 3) ("HeapKeyGen_StoreEntry_LRU: %s age=%f lastref=%f\n", + storeKeyText(e->key), age, (double)e->lastref); + if (e->mem_obj && e->mem_obj->url) + debug(81, 3) ("HeapKeyGen_StoreEntry_LRU: url=%s\n", + e->mem_obj->url); + return (heap_key) e->lastref; +} diff --git a/src/repl/heap/store_heap_replacement.h b/src/repl/heap/store_heap_replacement.h new file mode 100644 index 0000000000..f8084aa85b --- /dev/null +++ b/src/repl/heap/store_heap_replacement.h @@ -0,0 +1,3 @@ +extern heap_key HeapKeyGen_StoreEntry_LFUDA(void *entry, double age); +extern heap_key HeapKeyGen_StoreEntry_GDSF(void *entry, double age); +extern heap_key HeapKeyGen_StoreEntry_LRU(void *entry, double age); diff --git a/src/repl/heap/store_repl_heap.cc b/src/repl/heap/store_repl_heap.cc new file mode 100644 index 0000000000..5da654ee09 --- /dev/null +++ b/src/repl/heap/store_repl_heap.cc @@ -0,0 +1,310 @@ + +/* + * $Id: store_repl_heap.cc,v 1.1 2000/06/08 18:05:40 hno Exp $ + * + * DEBUG: section ? HEAP based removal policies + * AUTHOR: Henrik Nordstrom + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * Duane Wessels and the University of California San Diego. Please + * see the COPYRIGHT file for full details. Squid incorporates + * software developed and/or copyrighted by other sources. Please 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 "heap.h" +#include "store_heap_replacement.h" + +REMOVALPOLICYCREATE createRemovalPolicy_heap; + +static int nr_heap_policies = 0; + +typedef struct _HeapPolicyData HeapPolicyData; +struct _HeapPolicyData { + RemovalPolicy *policy; + heap *heap; + heap_key_func *keyfunc; + int count; + int nwalkers; + enum heap_entry_type + { TYPE_UNKNOWN = 0, TYPE_STORE_ENTRY, TYPE_STORE_MEM } + type; +}; + +/* Hack to avoid having to remember the RemovalPolicyNode location. + * Needed by the purge walker. + */ +static enum heap_entry_type +heap_guessType(StoreEntry * entry, RemovalPolicyNode * node) +{ + if (node == &entry->repl) + return TYPE_STORE_ENTRY; + if (entry->mem_obj && node == &entry->mem_obj->repl) + return TYPE_STORE_MEM; + fatal("Heap Replacement: Unknown StoreEntry node type"); + return TYPE_UNKNOWN; +} +#define SET_POLICY_NODE(entry,value) \ + switch(heap->type) { \ + case TYPE_STORE_ENTRY: entry->repl.data = value; break ; \ + case TYPE_STORE_MEM: entry->mem_obj->repl.data = value ; break ; \ + default: break; \ + } + +static void +heap_add(RemovalPolicy * policy, StoreEntry * entry, RemovalPolicyNode * node) +{ + HeapPolicyData *heap = policy->_data; + assert(!node->data); + if (EBIT_TEST(entry->flags, ENTRY_SPECIAL)) + return; /* We won't manage these.. they messes things up */ + node->data = heap_insert(heap->heap, entry); + heap->count += 1; + if (!heap->type) + heap->type = heap_guessType(entry, node); + /* Add a little more variance to the aging factor */ + heap->heap->age += heap->heap->age / 100000000; +} + +static void +heap_remove(RemovalPolicy * policy, StoreEntry * entry, + RemovalPolicyNode * node) +{ + HeapPolicyData *heap = policy->_data; + heap_node *hnode = node->data; + if (!hnode) + return; + heap_delete(heap->heap, hnode); + node->data = NULL; + heap->count -= 1; +} + +static void +heap_referenced(RemovalPolicy * policy, const StoreEntry * entry, + RemovalPolicyNode * node) +{ + HeapPolicyData *heap = policy->_data; + heap_node *hnode = node->data; + if (!hnode) + return; + heap_update(heap->heap, hnode, (StoreEntry *) entry); +} + +/** RemovalPolicyWalker **/ + +typedef struct _HeapWalkData HeapWalkData; +struct _HeapWalkData +{ + int current; +}; + +const StoreEntry * +heap_walkNext(RemovalPolicyWalker * walker) +{ + HeapWalkData *heap_walk = walker->_data; + RemovalPolicy *policy = walker->_policy; + HeapPolicyData *heap = policy->_data; + StoreEntry *entry; + if (heap_walk->current >= heap_nodes(heap->heap)) + return NULL; /* done */ + entry = (StoreEntry *) heap_peep(heap->heap, heap_walk->current++); + return entry; +} + +static void +heap_walkDone(RemovalPolicyWalker * walker) +{ + RemovalPolicy *policy = walker->_policy; + HeapPolicyData *heap = policy->_data; + assert(strcmp(policy->_type, "heap") == 0); + assert(heap->nwalkers > 0); + heap->nwalkers -= 1; + safe_free(walker->_data); + cbdataFree(walker); +} + +static RemovalPolicyWalker * +heap_walkInit(RemovalPolicy * policy) +{ + HeapPolicyData *heap = policy->_data; + RemovalPolicyWalker *walker; + HeapWalkData *heap_walk; + heap->nwalkers += 1; + walker = xcalloc(1, sizeof(*walker)); + heap_walk = xcalloc(1, sizeof(*heap_walk)); + heap_walk->current = 0; + walker->_policy = policy; + walker->_data = heap_walk; + walker->Next = heap_walkNext; + walker->Done = heap_walkDone; + cbdataAdd(walker, cbdataXfree, 0); + return walker; +} + +/** RemovalPurgeWalker **/ + +typedef struct _HeapPurgeData HeapPurgeData; +struct _HeapPurgeData +{ + link_list *locked_entries; + heap_key min_age; +}; + +static StoreEntry * +heap_purgeNext(RemovalPurgeWalker * walker) +{ + HeapPurgeData *heap_walker = walker->_data; + RemovalPolicy *policy = walker->_policy; + HeapPolicyData *heap = policy->_data; + StoreEntry *entry; + heap_key age; + try_again: + if (!heap_nodes(heap->heap) > 0) + return NULL; /* done */ + age = heap_peepminkey(heap->heap); + entry = heap_extractmin(heap->heap); + if (storeEntryLocked(entry)) { + linklistPush(&heap_walker->locked_entries, entry); + goto try_again; + } + heap_walker->min_age = age; + SET_POLICY_NODE(entry, NULL); + return entry; +} + +static void +heap_purgeDone(RemovalPurgeWalker * walker) +{ + HeapPurgeData *heap_walker = walker->_data; + RemovalPolicy *policy = walker->_policy; + HeapPolicyData *heap = policy->_data; + StoreEntry *entry; + assert(strcmp(policy->_type, "heap") == 0); + assert(heap->nwalkers > 0); + heap->nwalkers -= 1; + if (heap_walker->min_age > 0) { + heap->heap->age = heap_walker->min_age; + debug (81, 3) ("heap_purgeDone: Heap age set to %f\n", + (double) heap->heap->age); + } + /* + * Reinsert the locked entries + */ + while ((entry = linklistShift(&heap_walker->locked_entries))) { + heap_node *node = heap_insert(heap->heap, entry); + SET_POLICY_NODE(entry, node); + } + safe_free(walker->_data); + cbdataFree(walker); +} + +static RemovalPurgeWalker * +heap_purgeInit(RemovalPolicy * policy, int max_scan) +{ + HeapPolicyData *heap = policy->_data; + RemovalPurgeWalker *walker; + HeapPurgeData *heap_walk; + heap->nwalkers += 1; + walker = xcalloc(1, sizeof(*walker)); + heap_walk = xcalloc(1, sizeof(*heap_walk)); + heap_walk->min_age = 0.0; + heap_walk->locked_entries = NULL; + walker->_policy = policy; + walker->_data = heap_walk; + walker->max_scan = max_scan; + walker->Next = heap_purgeNext; + walker->Done = heap_purgeDone; + cbdataAdd(walker, cbdataXfree, 0); +#if HEAP_REPLACEMENT_DEBUG + if (!verify_heap_property(heap->heap)) { + debug(81, 1) ("Heap property violated!\n"); + } +#endif + return walker; +} + +static void +heap_free(RemovalPolicy * policy) +{ + HeapPolicyData *heap = policy->_data; + /* Make some verification of the policy state */ + assert(strcmp(policy->_type, "heap") == 0); + assert(heap->nwalkers); + assert(heap->count); + /* Ok, time to destroy this policy */ + safe_free(policy->_data); + memset(policy, 0, sizeof(*policy)); + cbdataFree(policy); +} + +RemovalPolicy * +createRemovalPolicy_heap(wordlist * args) +{ + RemovalPolicy *policy; + HeapPolicyData *heap_data; + char *keytype; + /* Allocate the needed structures */ + policy = xcalloc(1, sizeof(*policy)); + heap_data = xcalloc(1, sizeof(*heap_data)); + /* cbdata register the policy */ + cbdataAdd(policy, cbdataXfree, 0); + /* Initialize the policy data */ + heap_data->policy = policy; + if (args) { + keytype = args->key; + args = args->next; + } else { + debug(81, 1) ("createRemovalPolicy_heap: No key type specified. Using LRU\n"); + keytype = "LRU"; + } + if (!strcmp(keytype, "GDSF")) + heap_data->keyfunc = HeapKeyGen_StoreEntry_GDSF; + else if (!strcmp(keytype, "LFUDA")) + heap_data->keyfunc = HeapKeyGen_StoreEntry_LFUDA; + else if (!strcmp(keytype, "LRU")) + heap_data->keyfunc = HeapKeyGen_StoreEntry_LRU; + else { + debug(81, 0) ("createRemovalPolicy_heap: Unknown key type \"%s\". Using LRU\n", + keytype); + heap_data->keyfunc = HeapKeyGen_StoreEntry_LRU; + } + /* No additional arguments expected */ + assert(!args); + heap_data->heap = new_heap(1000, heap_data->keyfunc); + heap_data->heap->age = 1.0; + /* Populate the policy structure */ + policy->_type = "heap"; + policy->_data = heap_data; + policy->Free = heap_free; + policy->Add = heap_add; + policy->Remove = heap_remove; + policy->Referenced = NULL; + policy->Dereferenced = heap_referenced; + policy->WalkInit = heap_walkInit; + policy->PurgeInit = heap_purgeInit; + /* Increase policy usage count */ + nr_heap_policies += 0; + return policy; +} diff --git a/src/repl/lru/Makefile.in b/src/repl/lru/Makefile.in new file mode 100644 index 0000000000..a89ebea876 --- /dev/null +++ b/src/repl/lru/Makefile.in @@ -0,0 +1,54 @@ +# +# Makefile for the UFS storage driver for the Squid Object Cache server +# +# $Id: Makefile.in,v 1.1 2000/06/08 18:05:40 hno Exp $ +# + +REPL = lru + +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +MAKEDEPEND = @MAKEDEPEND@ +AR_R = @AR_R@ +RANLIB = @RANLIB@ +AC_CFLAGS = @CFLAGS@ +SHELL = /bin/sh + +INCLUDE = -I../../../include -I$(top_srcdir)/include -I$(top_srcdir)/src/ +CFLAGS = $(AC_CFLAGS) $(INCLUDE) $(DEFINES) + +OUT = ../$(REPL).a + +OBJS = \ + store_repl_$(REPL).o + +all: $(OUT) + +$(OUT): $(OBJS) + @rm -f ../stamp + $(AR_R) $(OUT) $(OBJS) + $(RANLIB) $(OUT) + +$(OBJS): $(top_srcdir)/include/version.h ../../../include/autoconf.h + +.c.o: + @rm -f ../stamp + $(CC) $(CFLAGS) -c $< + +install: + +clean: + -rm -rf *.o *pure_* core ../$(FS).a + +distclean: clean + -rm -f Makefile + -rm -f Makefile.bak + -rm -f tags + +tags: + ctags *.[ch] $(top_srcdir)/src/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[ch] + +depend: + $(MAKEDEPEND) $(INCLUDE) -fMakefile *.c diff --git a/src/repl/lru/store_repl_lru.cc b/src/repl/lru/store_repl_lru.cc new file mode 100644 index 0000000000..2a6e82c1ac --- /dev/null +++ b/src/repl/lru/store_repl_lru.cc @@ -0,0 +1,358 @@ + +/* + * $Id: store_repl_lru.cc,v 1.1 2000/06/08 18:05:40 hno Exp $ + * + * DEBUG: section ? LRU Removal policy + * AUTHOR: Henrik Nordstrom + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * Duane Wessels and the University of California San Diego. Please + * see the COPYRIGHT file for full details. Squid incorporates + * software developed and/or copyrighted by other sources. Please 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" + +REMOVALPOLICYCREATE createRemovalPolicy_lru; + +typedef struct _LruPolicyData LruPolicyData; +struct _LruPolicyData { + RemovalPolicy *policy; + dlink_list list; + int count; + int nwalkers; + enum heap_entry_type + { TYPE_UNKNOWN = 0, TYPE_STORE_ENTRY, TYPE_STORE_MEM } + type; +}; + +/* Hack to avoid having to remember the RemovalPolicyNode location. + * Needed by the purge walker to clear the policy information + */ +static enum heap_entry_type +repl_guessType(StoreEntry * entry, RemovalPolicyNode * node) +{ + if (node == &entry->repl) + return TYPE_STORE_ENTRY; + if (entry->mem_obj && node == &entry->mem_obj->repl) + return TYPE_STORE_MEM; + fatal("Heap Replacement: Unknown StoreEntry node type"); + return TYPE_UNKNOWN; +} +#define SET_POLICY_NODE(entry,value) \ + switch(lru->type) { \ + case TYPE_STORE_ENTRY: entry->repl.data = value; break ; \ + case TYPE_STORE_MEM: entry->mem_obj->repl.data = value ; break ; \ + default: break; \ + } + +typedef struct _LruNode LruNode; +struct _LruNode +{ + /* Note: the dlink_node MUST be the first member of the LruNode + * structure. This member is later pointer typecasted to LruNode *. + */ + dlink_node node; +}; + +static MemPool *lru_node_pool = NULL; +static int nr_lru_policies = 0; + +static void +lru_add(RemovalPolicy * policy, StoreEntry * entry, RemovalPolicyNode * node) +{ + LruPolicyData *lru = policy->_data; + LruNode *lru_node; + assert(!node->data); + node->data = lru_node = memPoolAlloc(lru_node_pool); + dlinkAddTail(entry, &lru_node->node, &lru->list); + lru->count += 1; + if (!lru->type) + lru->type = repl_guessType(entry, node); +} + +static void +lru_remove(RemovalPolicy * policy, StoreEntry * entry, RemovalPolicyNode * node) +{ + LruPolicyData *lru = policy->_data; + LruNode *lru_node = node->data; + if (!lru_node) + return; + assert(lru_node->node.data == entry); + node->data = NULL; + dlinkDelete(&lru_node->node, &lru->list); + memPoolFree(lru_node_pool, lru_node); + lru->count -= 1; +} + +static void +lru_referenced(RemovalPolicy * policy, const StoreEntry * entry, + RemovalPolicyNode * node) +{ + LruPolicyData *lru = policy->_data; + LruNode *lru_node = node->data; + if (!lru_node) + return; + dlinkDelete(&lru_node->node, &lru->list); + dlinkAddTail((void *) entry, &lru_node->node, &lru->list); +} + +/** RemovalPolicyWalker **/ + +typedef struct _LruWalkData LruWalkData; +struct _LruWalkData +{ + LruNode *current; +}; + +const StoreEntry * +lru_walkNext(RemovalPolicyWalker * walker) +{ + LruWalkData *lru_walk = walker->_data; + LruNode *lru_node = lru_walk->current; + if (!lru_node) + return NULL; + lru_walk->current = (LruNode *) lru_node->node.next; + return (StoreEntry *) lru_node->node.data; +} + +static void +lru_walkDone(RemovalPolicyWalker * walker) +{ + RemovalPolicy *policy = walker->_policy; + LruPolicyData *lru = policy->_data; + assert(strcmp(policy->_type, "lru") == 0); + assert(lru->nwalkers > 0); + lru->nwalkers -= 1; + safe_free(walker->_data); + cbdataFree(walker); +} + +static RemovalPolicyWalker * +lru_walkInit(RemovalPolicy * policy) +{ + LruPolicyData *lru = policy->_data; + RemovalPolicyWalker *walker; + LruWalkData *lru_walk; + lru->nwalkers += 1; + walker = xcalloc(1, sizeof(*walker)); + lru_walk = xcalloc(1, sizeof(*lru_walk)); + walker->_policy = policy; + walker->_data = lru_walk; + walker->Next = lru_walkNext; + walker->Done = lru_walkDone; + lru_walk->current = (LruNode *) lru->list.head; + cbdataAdd(walker, cbdataXfree, 0); + return walker; +} + +/** RemovalPurgeWalker **/ + +typedef struct _LruPurgeData LruPurgeData; +struct _LruPurgeData +{ + LruNode *current; + LruNode *start; +}; + +static StoreEntry * +lru_purgeNext(RemovalPurgeWalker * walker) +{ + LruPurgeData *lru_walker = walker->_data; + RemovalPolicy *policy = walker->_policy; + LruPolicyData *lru = policy->_data; + LruNode *lru_node; + StoreEntry *entry; + try_again: + lru_node = lru_walker->current; + if (!lru_node || walker->scanned >= walker->max_scan) + return NULL; + walker->scanned += 1; + lru_walker->current = (LruNode *) lru_node->node.next; + if (lru_walker->current == lru_walker->start) { + /* Last node found */ + lru_walker->current = NULL; + } + entry = (StoreEntry *) lru_node->node.data; + dlinkDelete(&lru_node->node, &lru->list); + if (storeEntryLocked(entry)) { + /* Shit, it is locked. we can't return this one */ + walker->locked++; + dlinkAddTail(entry, &lru_node->node, &lru->list); + goto try_again; + } + memPoolFree(lru_node_pool, lru_node); + lru->count -= 1; + SET_POLICY_NODE(entry, NULL); + return entry; +} + +static void +lru_purgeDone(RemovalPurgeWalker * walker) +{ + RemovalPolicy *policy = walker->_policy; + LruPolicyData *lru = policy->_data; + assert(strcmp(policy->_type, "lru") == 0); + assert(lru->nwalkers > 0); + lru->nwalkers -= 1; + safe_free(walker->_data); + cbdataFree(walker); +} + +static RemovalPurgeWalker * +lru_purgeInit(RemovalPolicy * policy, int max_scan) +{ + LruPolicyData *lru = policy->_data; + RemovalPurgeWalker *walker; + LruPurgeData *lru_walk; + lru->nwalkers += 1; + walker = xcalloc(1, sizeof(*walker)); + lru_walk = xcalloc(1, sizeof(*lru_walk)); + walker->_policy = policy; + walker->_data = lru_walk; + walker->max_scan = max_scan; + walker->Next = lru_purgeNext; + walker->Done = lru_purgeDone; + lru_walk->start = lru_walk->current = (LruNode *) lru->list.head; + cbdataAdd(walker, cbdataXfree, 0); + return walker; +} + +static void +lru_free(RemovalPolicy * policy) +{ + LruPolicyData *lru = policy->_data; + /* Make some verification of the policy state */ + assert(strcmp(policy->_type, "lru") == 0); + assert(lru->nwalkers); + assert(lru->count); + /* Ok, time to destroy this policy */ + safe_free(policy->_data); + memset(policy, 0, sizeof(*policy)); + cbdataFree(policy); +} + +RemovalPolicy * +createRemovalPolicy_lru(wordlist *args) +{ + RemovalPolicy *policy; + LruPolicyData *lru_data; + /* no arguments expected or understood */ + assert(!args); + /* Initialize */ + if (!lru_node_pool) + lru_node_pool = memPoolCreate("LRU policy node", sizeof(LruNode)); + /* Allocate the needed structures */ + policy = xcalloc(1, sizeof(*policy)); + lru_data = xcalloc(1, sizeof(*lru_data)); + /* cbdata register the policy */ + cbdataAdd(policy, cbdataXfree, 0); + /* Initialize the URL data */ + lru_data->policy = policy; + /* Populate the policy structure */ + policy->_type = "lru"; + policy->_data = lru_data; + policy->Free = lru_free; + policy->Add = lru_add; + policy->Remove = lru_remove; + policy->Referenced = lru_referenced; + policy->Dereferenced = lru_referenced; + policy->WalkInit = lru_walkInit; + policy->PurgeInit = lru_purgeInit; + /* Increase policy usage count */ + nr_lru_policies += 0; + return policy; +} + + +#if OLD_UNUSED_CODE +/* + * storeUfsDirCheckExpired + * + * Check whether the given object is expired or not + * It breaks layering a little by calling the upper layers to find + * out whether the object is locked or not, but we can't help this + * right now. + */ +static int +storeUfsDirCheckExpired(SwapDir * SD, StoreEntry * e) +{ + if (storeEntryLocked(e)) + return 0; + if (EBIT_TEST(e->flags, RELEASE_REQUEST)) + return 1; + if (EBIT_TEST(e->flags, ENTRY_NEGCACHED) && squid_curtime >= e->expires) + return 1; + +#if HEAP_REPLACEMENT + /* + * with HEAP_REPLACEMENT we are not using the LRU reference age, the heap + * controls the replacement of objects. + */ + return 1; +#else + if (squid_curtime - e->lastref > storeUfsDirExpiredReferenceAge(SD)) + return 1; + return 0; +#endif +} + +/* + * storeUfsDirExpiredReferenceAge + * + * The LRU age is scaled exponentially between 1 minute and + * Config.referenceAge , when store_swap_low < store_swap_size < + * store_swap_high. This keeps store_swap_size within the low and high + * water marks. If the cache is very busy then store_swap_size stays + * closer to the low water mark, if it is not busy, then it will stay + * near the high water mark. The LRU age value can be examined on the + * cachemgr 'info' page. + */ +static time_t +storeUfsDirExpiredReferenceAge(SwapDir * SD) +{ + double x; + double z; + time_t age; + long store_high, store_low; + + store_high = (long) (((float) SD->max_size * + (float) Config.Swap.highWaterMark) / (float) 100); + store_low = (long) (((float) SD->max_size * + (float) Config.Swap.lowWaterMark) / (float) 100); + debug(81, 4) ("storeUfsDirExpiredReferenceAge: Dir %s, hi=%d, lo=%d, cur=%d\n", SD->path, store_high, + store_low, SD->cur_size); + + x = (double) (store_high - SD->cur_size) / (store_high - store_low); + x = x < 0.0 ? 0.0 : x > 1.0 ? 1.0 : x; + z = pow((double) (Config.referenceAge / 60), x); + age = (time_t) (z * 60.0); + if (age < 60) + age = 60; + else if (age > Config.referenceAge) + age = Config.referenceAge; + return age; +} +#endif /* OLD_UNUSED_CODE */ diff --git a/src/squid.h b/src/squid.h index ee3c6fc752..d237dcc890 100644 --- a/src/squid.h +++ b/src/squid.h @@ -1,6 +1,6 @@ /* - * $Id: squid.h,v 1.201 2000/05/03 17:15:42 adrian Exp $ + * $Id: squid.h,v 1.202 2000/06/08 18:05:35 hno Exp $ * * AUTHOR: Duane Wessels * @@ -359,9 +359,6 @@ struct rusage { #include "hash.h" #include "rfc1035.h" -#if HEAP_REPLACEMENT -#include "heap.h" -#endif #include "defines.h" #include "enums.h" diff --git a/src/store.cc b/src/store.cc index 472bf2c49c..6e1856b3e4 100644 --- a/src/store.cc +++ b/src/store.cc @@ -1,6 +1,6 @@ /* - * $Id: store.cc,v 1.524 2000/05/28 17:00:13 wessels Exp $ + * $Id: store.cc,v 1.525 2000/06/08 18:05:36 hno Exp $ * * DEBUG: section 20 Storage Manager * AUTHOR: Harvest Derived @@ -81,6 +81,8 @@ static MemObject *new_MemObject(const char *, const char *); static void destroy_MemObject(StoreEntry *); static FREE destroy_StoreEntry; static void storePurgeMem(StoreEntry *); +static void storeEntryReferenced(StoreEntry *); +static void storeEntryDereferenced(StoreEntry *); static int getKeyCounter(void); static int storeKeepInMemory(const StoreEntry *); static OBJH storeCheckCachableStats; @@ -89,14 +91,6 @@ static EVH storeLateRelease; /* * local variables */ -#if HEAP_REPLACEMENT -/* - * The heap equivalent of inmem_list, inmem_heap, is in globals.c so other - * modules can access it when updating object metadata (e.g., refcount) - */ -#else -static dlink_list inmem_list; -#endif static Stack LateReleaseStack; #if URL_CHECKSUM_DEBUG @@ -223,23 +217,50 @@ storePurgeMem(StoreEntry * e) storeRelease(e); } -void -storeLockObject(StoreEntry * e) +static void +storeEntryReferenced(StoreEntry *e) { SwapDir *SD; - if (e->swap_dirn > -1) + /* Notify the fs that we're referencing this object again */ + if (e->swap_dirn > -1) { SD = INDEXSD(e->swap_dirn); - else - SD = NULL; + if (SD->refobj) + SD->refobj(SD, e); + } + /* Notify the memory cache that we're referencing this object again */ + if(e->mem_obj) { + if (mem_policy->Referenced) + mem_policy->Referenced(mem_policy, e, &e->mem_obj->repl); + } +} +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); + } + /* Notify the memory cache that we're not referencing this object any more */ + if(e->mem_obj) { + if (mem_policy->Dereferenced) + mem_policy->Dereferenced(mem_policy, e, &e->mem_obj->repl); + } +} + +void +storeLockObject(StoreEntry * e) +{ e->lock_count++; debug(20, 3) ("storeLockObject: key '%s' count=%d\n", storeKeyText(e->key), (int) e->lock_count); e->lastref = squid_curtime; - /* Notify the fs that we're referencing this object again */ - if (SD != NULL && SD->refobj != NULL) - SD->refobj(SD, e); + storeEntryReferenced(e); } void @@ -263,7 +284,6 @@ storeReleaseRequest(StoreEntry * e) int storeUnlockObject(StoreEntry * e) { - SwapDir *SD; e->lock_count--; debug(20, 3) ("storeUnlockObject: key '%s' count=%d\n", storeKeyText(e->key), e->lock_count); @@ -272,30 +292,16 @@ storeUnlockObject(StoreEntry * e) if (e->store_status == STORE_PENDING) EBIT_SET(e->flags, RELEASE_REQUEST); assert(storePendingNClients(e) == 0); - /* Notify the fs that we're not referencing this object any more */ - if (e->swap_filen > -1) - SD = INDEXSD(e->swap_dirn); - else - SD = NULL; - if (SD != NULL && SD->unrefobj != NULL) - SD->unrefobj(SD, e); -#if HEAP_REPLACEMENT - storeHeapPositionUpdate(e, SD); -#else -#if 0 - /* Note: From 2.4. Not sure how this relates to the unrefobj() call above */ - storeDirLRUDelete(e); - storeDirLRUAdd(e); -#endif -#endif if (EBIT_TEST(e->flags, RELEASE_REQUEST)) storeRelease(e); else if (storeKeepInMemory(e)) { + storeEntryDereferenced(e); storeSetMemStatus(e, IN_MEMORY); requestUnlink(e->mem_obj->request); e->mem_obj->request = NULL; } else { storePurgeMem(e); + storeEntryDereferenced(e); if (EBIT_TEST(e->flags, KEY_PRIVATE)) debug(20, 1) ("WARNING: %s:%d: found KEY_PRIVATE\n", __FILE__, __LINE__); } @@ -368,7 +374,7 @@ storeSetPublicKey(StoreEntry * e) * If RELEASE_REQUEST is set, then ENTRY_CACHABLE should not * be set, and storeSetPublicKey() should not be called. */ -#if HEAP_REPLACEMENT +#if MORE_DEBUG_OUTPUT if (EBIT_TEST(e->flags, RELEASE_REQUEST)) debug(20, 1) ("assertion failed: RELEASE key %s, url %s\n", e->key, mem->url); @@ -698,16 +704,7 @@ storeGetMemSpace(int size) int released = 0; static time_t last_check = 0; int pages_needed; - int locked = 0; -#if !HEAP_REPLACEMENT - dlink_node *head; - dlink_node *m; - dlink_node *prev = NULL; -#else - heap_key age; - heap_key min_age = 0.0; - link_list *locked_entries = NULL; -#endif + RemovalPurgeWalker *walker; if (squid_curtime == last_check) return; last_check = squid_curtime; @@ -715,57 +712,15 @@ storeGetMemSpace(int size) if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_max) return; debug(20, 2) ("storeGetMemSpace: Starting, need %d pages\n", pages_needed); -#if HEAP_REPLACEMENT - while (heap_nodes(inmem_heap) > 0) { - age = heap_peepminkey(inmem_heap); - e = heap_extractmin(inmem_heap); - e->mem_obj->node = NULL; /* no longer in the heap */ - if (storeEntryLocked(e)) { - locked++; - debug(20, 5) ("storeGetMemSpace: locked key %s\n", - storeKeyText(e->key)); - linklistPush(&locked_entries, e); - continue; - } - released++; - debug(20, 3) ("Released memory object with key %f size %d refs %d url %s\n", - age, e->swap_file_sz, e->refcount, e->mem_obj->url); - min_age = age; + /* XXX what to set as max_scan here? */ + walker = mem_policy->PurgeInit(mem_policy, 100000); + while((e = walker->Next(walker))) { storePurgeMem(e); - if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_max) - break; - } - /* - * Increase the heap age factor. - */ - if (min_age > 0) - inmem_heap->age = min_age; - /* - * Reinsert all bumped locked entries back into heap... - */ - while ((e = linklistShift(&locked_entries))) - e->mem_obj->node = heap_insert(inmem_heap, e); -#else - head = inmem_list.head; - for (m = inmem_list.tail; m; m = prev) { - if (m == head) - break; - prev = m->prev; - e = m->data; - if (storeEntryLocked(e)) { - locked++; - dlinkDelete(m, &inmem_list); - dlinkAdd(e, m, &inmem_list); - continue; - } released++; - storePurgeMem(e); if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_max) break; } -#endif - debug(20, 3) ("storeGetMemSpace: released %d/%d locked %d\n", - released, hot_obj_count, locked); + walker->Done(walker); debug(20, 3) ("storeGetMemSpace stats:\n"); debug(20, 3) (" %6d HOT objects\n", hot_obj_count); debug(20, 3) (" %6d were released\n", released); @@ -787,15 +742,25 @@ storeMaintainSwapSpace(void *datanotused) { int i; SwapDir *SD; + static time_t last_warn_time = 0; /* walk each fs */ for (i = 0; i < Config.cacheSwap.n_configured; i++) { /* call the maintain function .. */ - SD = INDEXSD(i); - if (SD->maintainfs != NULL) + SD = INDEXSD(i); + /* 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); } - + if (store_swap_size > Config.Swap.maxSize) { + if (squid_curtime - last_warn_time > 10) { + debug(20, 0) ("WARNING: Disk space over limit: %d KB > %d KB\n", + store_swap_size, Config.Swap.maxSize); + last_warn_time = squid_curtime; + } + } /* Reregister a maintain event .. */ eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0, 1); } @@ -960,11 +925,9 @@ storeInit(void) storeInitHashValues(); store_table = hash_create(storeKeyHashCmp, store_hash_buckets, storeKeyHashHash); + mem_policy = createRemovalPolicy(Config.memPolicy); storeDigestInit(); storeLogOpen(); -#if HEAP_REPLACEMENT - inmem_heap = new_heap(1000, HeapKeyGen_StoreEntry_GDSF); -#endif stackInit(&LateReleaseStack); eventAdd("storeLateRelease", storeLateRelease, NULL, 1.0, 1); storeDirInit(); @@ -1148,35 +1111,24 @@ storeSetMemStatus(StoreEntry * e, int new_status) assert(mem != NULL); if (new_status == IN_MEMORY) { assert(mem->inmem_lo == 0); -#if HEAP_REPLACEMENT - if (mem->node == NULL) { - if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) { - debug(20, 4) ("storeSetMemStatus: not inserting special %s\n", - mem->url); - } else { - mem->node = heap_insert(inmem_heap, e); - debug(20, 4) ("storeSetMemStatus: inserted mem node %p\n", - mem->node); - } + if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) { + debug(20, 4) ("storeSetMemStatus: not inserting special %s into policy\n", + mem->url); + } else { + mem_policy->Add(mem_policy, e, &mem->repl); + debug(20, 4) ("storeSetMemStatus: inserted mem node %s\n", + mem->url); } -#else - dlinkAdd(e, &mem->lru, &inmem_list); -#endif hot_obj_count++; } else { -#if HEAP_REPLACEMENT - /* - * It's being removed from the memory heap; is it already gone? - */ - if (mem->node) { - heap_delete(inmem_heap, mem->node); - debug(20, 4) ("storeSetMemStatus: deleted mem node %p\n", - mem->node); - mem->node = NULL; + if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) { + debug(20, 4) ("storeSetMemStatus: special entry %s\n", + mem->url); + } else { + mem_policy->Remove(mem_policy, e, &mem->repl); + debug(20, 4) ("storeSetMemStatus: removed mem node %s\n", + mem->url); } -#else - dlinkDelete(&mem->lru, &inmem_list); -#endif hot_obj_count--; } e->mem_status = new_status; @@ -1255,18 +1207,6 @@ storeEntryReset(StoreEntry * e) e->expires = e->lastmod = e->timestamp = -1; } -#if HEAP_REPLACEMENT -/* - * This routine only handles memory updates these days - */ -void -storeHeapPositionUpdate(StoreEntry * e, SwapDir * SD) -{ - if (e->mem_obj && e->mem_obj->node) - heap_update(inmem_heap, e->mem_obj->node, e); -} -#endif - /* * storeFsInit * diff --git a/src/store_digest.cc b/src/store_digest.cc index bab541c723..e90ab0ee30 100644 --- a/src/store_digest.cc +++ b/src/store_digest.cc @@ -1,6 +1,6 @@ /* - * $Id: store_digest.cc,v 1.41 2000/06/06 19:34:31 hno Exp $ + * $Id: store_digest.cc,v 1.42 2000/06/08 18:05:36 hno Exp $ * * DEBUG: section 71 Store Digest Manager * AUTHOR: Alex Rousskov @@ -231,11 +231,9 @@ storeDigestAddable(const StoreEntry * e) * idea: skip objects that are going to be purged before the next * update. */ -#if 0 /* This code isn't applicable anymore, we can't fix it atm either :( */ -#if !HEAP_REPLACEMENT +#if OLD_UNUSED_CODE /* This code isn't applicable anymore, we can't fix it atm either :( */ if ((squid_curtime + Config.digest.rebuild_period) - e->lastref > storeExpiredReferenceAge()) return 0; -#endif #endif return 1; } diff --git a/src/store_dir.cc b/src/store_dir.cc index 976e74f11a..8081119794 100644 --- a/src/store_dir.cc +++ b/src/store_dir.cc @@ -1,6 +1,6 @@ /* - * $Id: store_dir.cc,v 1.110 2000/05/28 22:15:42 wessels Exp $ + * $Id: store_dir.cc,v 1.111 2000/06/08 18:05:36 hno Exp $ * * DEBUG: section 47 Store Directory Routines * AUTHOR: Duane Wessels @@ -36,8 +36,6 @@ #include "squid.h" static int storeDirValidSwapDirSize(int, ssize_t); -static void storeDirLRUWalkInitHead(SwapDir * sd); -static void *storeDirLRUWalkNext(SwapDir * sd); void storeDirInit(void) @@ -365,15 +363,14 @@ storeDirCloseSwapLogs(void) int storeDirWriteCleanLogs(int reopen) { - StoreEntry *e = NULL; + const StoreEntry *e = NULL; int n = 0; struct timeval start; double dt; SwapDir *sd; + RemovalPolicyWalker **walkers; int dirn; -#if HEAP_REPLACEMENT - int node; -#endif + int notdone = 1; if (store_dirs_rebuilding) { debug(20, 1) ("Not currently OK to rewrite swap log.\n"); debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.\n"); @@ -382,28 +379,24 @@ storeDirWriteCleanLogs(int reopen) debug(20, 1) ("storeDirWriteCleanLogs: Starting...\n"); getCurrentTime(); start = current_time; + walkers = xcalloc(Config.cacheSwap.n_configured, sizeof *walkers); for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { sd = &Config.cacheSwap.swapDirs[dirn]; - if (sd->log.clean.open(sd) < 0) { - debug(20, 1) ("log.clean.open() failed for dir #%d\n", sd->index); + if (sd->log.clean.start(sd) < 0) { + debug(20, 1) ("log.clean.start() failed for dir #%d\n", sd->index); continue; } - if (NULL == sd->log.clean.write) - continue; -#if HEAP_REPLACEMENT - if (NULL == sd->repl.heap.heap) - continue; -#endif -#if HEAP_REPLACEMENT - for (node = 0; node < heap_nodes(sd->repl.heap.heap); node++) -#else - storeDirLRUWalkInitHead(sd); - while ((e = storeDirLRUWalkNext(sd)) != NULL) -#endif - { -#if HEAP_REPLACEMENT - e = (StoreEntry *) heap_peep(sd->repl.heap.heap, node); -#endif + } + while(notdone) { + notdone = 0; + for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { + sd = &Config.cacheSwap.swapDirs[dirn]; + if (NULL == sd->log.clean.write) + continue; + e = sd->log.clean.nextentry(sd); + if (!e) + continue; + notdone = 1; if (e->swap_filen < 0) continue; if (e->swap_status != SWAPOUT_DONE) @@ -416,14 +409,17 @@ storeDirWriteCleanLogs(int reopen) continue; if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) continue; - sd->log.clean.write(e, sd); + sd->log.clean.write(sd, e); if ((++n & 0xFFFF) == 0) { getCurrentTime(); debug(20, 1) (" %7d entries written so far.\n", n); } } - /* Flush */ - sd->log.clean.write(NULL, sd); + } + /* Flush */ + for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { + sd = &Config.cacheSwap.swapDirs[dirn]; + sd->log.clean.done(sd); } if (reopen) storeDirOpenSwapLogs(); @@ -458,51 +454,20 @@ storeDirSync(void) void storeDirCallback(void) { - int i; + int i, j; SwapDir *SD; - - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - SD = &Config.cacheSwap.swapDirs[i]; - if (SD->callback != NULL) - SD->callback(SD); - } -} - -#if 0 /* from Squid-2.4.DEVEL3 */ -void -storeDirLRUDelete(StoreEntry * e) -{ - SwapDir *sd; - if (e->swap_filen < 0) - return; - sd = &Config.cacheSwap.swapDirs[e->swap_dirn]; - dlinkDelete(&e->lru, &sd->repl.lru.list); -} - -void -storeDirLRUAdd(StoreEntry * e) -{ - SwapDir *sd; - if (e->swap_file_number < 0) - return; - sd = &Config.cacheSwap.swapDirs[e->swap_dirn]; - dlinkAdd(e, &e->lru, &sd->repl.lru.list); -} -#endif /* from Squid-2.4.DEVEL3 */ - -static void -storeDirLRUWalkInitHead(SwapDir * sd) -{ - sd->repl.lru.walker = sd->repl.lru.list.head; + static int ndir = 0; + do { + j = 0; + 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); + } + } while (j > 0); + ndir++; } -static void * -storeDirLRUWalkNext(SwapDir * sd) -{ - void *p; - if (NULL == sd->repl.lru.walker) - return NULL; - p = sd->repl.lru.walker->data; - sd->repl.lru.walker = sd->repl.lru.walker->next; - return p; -} diff --git a/src/store_log.cc b/src/store_log.cc index 8bccb847d6..afb059305f 100644 --- a/src/store_log.cc +++ b/src/store_log.cc @@ -1,6 +1,6 @@ /* - * $Id: store_log.cc,v 1.15 2000/05/29 23:30:46 hno Exp $ + * $Id: store_log.cc,v 1.16 2000/06/08 18:05:36 hno Exp $ * * DEBUG: section 20 Storage Manager Logging Functions * AUTHOR: Duane Wessels @@ -66,12 +66,13 @@ storeLog(int tag, const StoreEntry * e) * Because if we print it before the swap file number, it'll break * the existing log format. */ - logfilePrintf(storelog, "%9d.%03d %-7s %02d %08X %4d %9d %9d %9d %s %d/%d %s %s\n", + logfilePrintf(storelog, "%9d.%03d %-7s %02d %08X %s %4d %9d %9d %9d %s %d/%d %s %s\n", (int) current_time.tv_sec, (int) current_time.tv_usec / 1000, storeLogTags[tag], e->swap_dirn, e->swap_filen, + storeKeyText(e->key), reply->sline.status, (int) reply->date, (int) reply->last_modified, @@ -83,7 +84,7 @@ storeLog(int tag, const StoreEntry * e) mem->log_url); } else { /* no mem object. Most RELEASE cases */ - logfilePrintf(storelog, "%9d.%03d %-7s %02d %08X ? ? ? ? ?/? ?/? ? %s\n", + logfilePrintf(storelog, "%9d.%03d %-7s %02d %08X %s ? ? ? ? ?/? ?/? ? ?\n", (int) current_time.tv_sec, (int) current_time.tv_usec / 1000, storeLogTags[tag], diff --git a/src/structs.h b/src/structs.h index 0963c9952d..8ae03d8710 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.338 2000/05/31 07:01:42 hno Exp $ + * $Id: structs.h,v 1.339 2000/06/08 18:05:36 hno Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -210,6 +210,11 @@ struct _delayConfig { #endif +struct _RemovalPolicySettings { + char *type; + wordlist *args; +}; + struct _SquidConfig { struct { size_t maxSize; @@ -227,14 +232,8 @@ struct _SquidConfig { int pct; size_t max; } quickAbort; -#if HEAP_REPLACEMENT - char *replPolicy; -#else - /* - * Note: the non-LRU policies do not use referenceAge, but we cannot - * remove it until we find out how to implement #else for cf_parser.c - */ -#endif + RemovalPolicySettings *replPolicy; + RemovalPolicySettings *memPolicy; time_t referenceAge; time_t negativeTtl; time_t negativeDnsTtl; @@ -1272,6 +1271,39 @@ struct _store_client { }; +/* Removal policies */ + +struct _RemovalPolicyNode { + void *data; +}; + +struct _RemovalPolicy { + char *_type; + void *_data; + void (*Free)(RemovalPolicy *policy); + void (*Add)(RemovalPolicy *policy, StoreEntry *entry, RemovalPolicyNode *node); + void (*Remove)(RemovalPolicy *policy, StoreEntry *entry, RemovalPolicyNode *node); + void (*Referenced)(RemovalPolicy *policy, const StoreEntry *entry, RemovalPolicyNode *node); + void (*Dereferenced)(RemovalPolicy *policy, const StoreEntry *entry, RemovalPolicyNode *node); + RemovalPolicyWalker *(*WalkInit)(RemovalPolicy *policy); + RemovalPurgeWalker *(*PurgeInit)(RemovalPolicy *policy, int max_scan); +}; + +struct _RemovalPolicyWalker { + RemovalPolicy *_policy; + void *_data; + const StoreEntry *(*Next)(RemovalPolicyWalker *walker); + void (*Done)(RemovalPolicyWalker *walker); +}; + +struct _RemovalPurgeWalker { + RemovalPolicy *_policy; + void *_data; + int scanned, max_scan, locked; + StoreEntry *(*Next)(RemovalPurgeWalker *walker); + void (*Done)(RemovalPurgeWalker *walker); +}; + /* This structure can be freed while object is purged out from memory */ struct _MemObject { method_t method; @@ -1297,14 +1329,7 @@ struct _MemObject { void *data; } abort; char *log_url; -#if HEAP_REPLACEMENT - /* - * A MemObject knows where it is in the in-memory heap. - */ - heap_node *node; -#else - dlink_node lru; -#endif + RemovalPolicyNode repl; int id; ssize_t object_sz; size_t swap_hdr_sz; @@ -1327,12 +1352,7 @@ struct _StoreEntry { u_short flags; sdirno swap_dirn; sfileno swap_filen; - union { -#ifdef HEAP_REPLACEMENT - heap_node *node; -#endif - dlink_node lru; - } repl; + RemovalPolicyNode repl; u_short lock_count; /* Assume < 65536! */ mem_status_t mem_status:3; ping_status_t ping_status:3; @@ -1349,17 +1369,7 @@ struct _SwapDir { int index; /* This entry's index into the swapDirs array */ int suggest; ssize_t max_objsize; - union { -#ifdef HEAP_REPLACEMENT - struct { - heap *heap; - } heap; -#endif - struct { - dlink_list list; - dlink_node *walker; - } lru; - } repl; + RemovalPolicy *repl; int removals; int scanned; struct { @@ -1392,8 +1402,10 @@ struct _SwapDir { STLOGCLOSE *close; STLOGWRITE *write; struct { - STLOGCLEANOPEN *open; + STLOGCLEANSTART *start; + STLOGCLEANNEXTENTRY *nextentry; STLOGCLEANWRITE *write; + STLOGCLEANDONE *done; void *state; } clean; } log; @@ -1897,3 +1909,4 @@ struct _Logfile { size_t bufsz; off_t offset; }; + diff --git a/src/typedefs.h b/src/typedefs.h index 0cc45bcba4..e0684479af 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.103 2000/05/12 00:29:09 wessels Exp $ + * $Id: typedefs.h,v 1.104 2000/06/08 18:05:37 hno Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -171,6 +171,11 @@ typedef struct _link_list link_list; typedef struct _storefs_entry storefs_entry_t; typedef struct _diskd_queue diskd_queue; typedef struct _Logfile Logfile; +typedef struct _RemovalPolicy RemovalPolicy; +typedef struct _RemovalPolicyWalker RemovalPolicyWalker; +typedef struct _RemovalPurgeWalker RemovalPurgeWalker; +typedef struct _RemovalPolicyNode RemovalPolicyNode; +typedef struct _RemovalPolicySettings RemovalPolicySettings; #if SQUID_SNMP typedef variable_list *(oid_ParseFn) (variable_list *, snint *); @@ -238,7 +243,7 @@ typedef void STREFOBJ(SwapDir *, StoreEntry *); typedef void STUNREFOBJ(SwapDir *, StoreEntry *); typedef void STSETUP(storefs_entry_t *); typedef void STDONE(void); -typedef void STCALLBACK(SwapDir *); +typedef int STCALLBACK(SwapDir *); typedef void STSYNC(SwapDir *); typedef storeIOState *STOBJCREATE(SwapDir *, StoreEntry *, STFNCB *, STIOCB *, void *); @@ -251,8 +256,10 @@ typedef void STOBJUNLINK(SwapDir *, StoreEntry *); typedef void STLOGOPEN(SwapDir *); typedef void STLOGCLOSE(SwapDir *); typedef void STLOGWRITE(const SwapDir *, const StoreEntry *, int); -typedef int STLOGCLEANOPEN(SwapDir *); -typedef void STLOGCLEANWRITE(const StoreEntry *, SwapDir *); +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) */ @@ -301,4 +308,5 @@ typedef unsigned int delay_id; typedef struct _htcpReplyData htcpReplyData; #endif +typedef RemovalPolicy *REMOVALPOLICYCREATE(wordlist *args); #endif /* _TYPEDEFS_H_ */