From: Alex Rousskov Date: Fri, 14 Oct 2011 16:21:48 +0000 (-0600) Subject: SMP shared memory cache stats were not collected. X-Git-Tag: BumpSslServerFirst.take01~96 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=93bc1434c57ba45489e997fffb3e215592fff273;p=thirdparty%2Fsquid.git SMP shared memory cache stats were not collected. "Hot Object" stats were not reported for shared memory cache. Mean disk object size stats were aggregated inaccurately for SMP. Moved Store-related stats into a dedicated StoreStats class, encapsulating memory cache-related (mem), disk cache-related (swap), and global store (number of objects) stats. Used consistent naming scheme and a common parent class to make memory and disk stats more alike. Moved Store stats collection into corresponding Store classes rather than forcing GetInfo() in stat.cc to know how to deal with all Store stats. --- diff --git a/src/Makefile.am b/src/Makefile.am index 9505971471..14f5b0bb5e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -462,6 +462,8 @@ squid_SOURCES = \ StoreMetaVary.cc \ StoreMetaVary.h \ StoreSearch.h \ + StoreStats.cc \ + StoreStats.h \ StoreSwapLogData.cc \ StoreSwapLogData.h \ Server.cc \ @@ -1073,6 +1075,7 @@ tests_testHttpReply_SOURCES=\ tests/stub_HelperChildConfig.cc \ tests/stub_StatHist.cc \ tests/stub_store.cc \ + tests/stub_store_stats.cc \ tests/testHttpReply.cc \ tests/testHttpReply.h \ tests/testMain.cc \ @@ -1177,6 +1180,7 @@ tests_testACLMaxUserIP_SOURCES= \ tests/stub_mime.cc \ tests/stub_store.cc \ tests/stub_store_rebuild.cc \ + tests/stub_store_stats.cc \ tests/stub_store_swapout.cc \ tests/stub_tools.cc \ tests/stub_cache_manager.cc \ @@ -1251,6 +1255,7 @@ tests_testCacheManager_SOURCES = \ tests/testMain.cc \ tests/stub_main_cc.cc \ tests/stub_ipc_Forwarder.cc \ + tests/stub_store_stats.cc \ time.cc \ BodyPipe.cc \ cache_manager.cc \ @@ -1503,6 +1508,7 @@ tests_testDiskIO_SOURCES = \ tests/stub_pconn.cc \ tests/stub_Port.cc \ tests/stub_store_client.cc \ + tests/stub_store_stats.cc \ tests/stub_store_rebuild.cc \ tests/stub_tools.cc \ tests/stub_UdsOp.cc \ @@ -1693,6 +1699,7 @@ tests_testEvent_SOURCES = \ tests/testMain.cc \ tests/stub_main_cc.cc \ tests/stub_ipc_Forwarder.cc \ + tests/stub_store_stats.cc \ time.cc \ tools.cc \ tunnel.cc \ @@ -1879,6 +1886,7 @@ tests_testEventLoop_SOURCES = \ tests/testMain.cc \ tests/stub_main_cc.cc \ tests/stub_ipc_Forwarder.cc \ + tests/stub_store_stats.cc \ time.cc \ tools.cc \ tunnel.cc \ @@ -2061,6 +2069,7 @@ tests_test_http_range_SOURCES = \ tests/stub_ipc_Forwarder.cc \ tests/stub_main_cc.cc \ tests/stub_MemStore.cc \ + tests/stub_store_stats.cc \ time.cc \ tools.cc \ tunnel.cc \ @@ -2166,6 +2175,7 @@ tests_testHttpRequest_SOURCES = \ tests/stub_DiskIOModule.cc \ tests/stub_main_cc.cc \ tests/stub_ipc_Forwarder.cc \ + tests/stub_store_stats.cc \ time.cc \ BodyPipe.cc \ cache_manager.cc \ @@ -2407,6 +2417,7 @@ tests_testStore_SOURCES= \ tests/stub_mime.cc \ tests/stub_Port.cc \ tests/stub_store_client.cc \ + tests/stub_store_stats.cc \ tests/stub_store_rebuild.cc \ tests/stub_store_swapout.cc \ tests/stub_tools.cc \ @@ -2531,6 +2542,7 @@ tests_testUfs_SOURCES = \ tests/stub_UdsOp.cc \ tests/stub_internal.cc \ tests/stub_store_rebuild.cc \ + tests/stub_store_stats.cc \ fd.cc \ disk.cc \ filemap.cc \ @@ -2723,6 +2735,7 @@ tests_testRock_SOURCES = \ tests/stub_pconn.cc \ tests/stub_store_client.cc \ tests/stub_store_rebuild.cc \ + tests/stub_store_stats.cc \ tests/stub_tools.cc \ tests/stub_UdsOp.cc \ time.cc \ @@ -2781,6 +2794,7 @@ tests_testCoss_SOURCES = \ tests/stub_ipc.cc \ tests/stub_pconn.cc \ tests/stub_store_rebuild.cc \ + tests/stub_store_stats.cc \ fd.cc \ disk.cc \ filemap.cc \ @@ -2852,6 +2866,7 @@ tests_testCoss_SOURCES = \ tests/stub_MemStore.cc \ tests/stub_Port.cc \ tests/stub_store_client.cc \ + tests/stub_store_stats.cc \ tests/stub_tools.cc \ tests/stub_UdsOp.cc \ tests/testStoreSupport.cc \ @@ -2910,6 +2925,7 @@ tests_testNull_SOURCES = \ tests/stub_internal.cc \ tests/stub_CommIO.cc \ tests/stub_store_rebuild.cc \ + tests/stub_store_stats.cc \ fd.cc \ disk.cc \ filemap.cc \ @@ -2981,6 +2997,7 @@ tests_testNull_SOURCES = \ tests/stub_access_log.cc \ refresh.cc \ tests/stub_store_client.cc \ + tests/stub_store_stats.cc \ tests/stub_tools.cc \ tests/testStoreSupport.cc \ tests/testStoreSupport.h \ @@ -3150,6 +3167,7 @@ tests_testURL_SOURCES = \ tests/stub_DiskIOModule.cc \ tests/stub_main_cc.cc \ tests/stub_ipc_Forwarder.cc \ + tests/stub_store_stats.cc \ tests/testURL.cc \ tests/testURL.h \ tests/testURLScheme.cc \ diff --git a/src/MemStore.cc b/src/MemStore.cc index aece423936..02d4cabfaa 100644 --- a/src/MemStore.cc +++ b/src/MemStore.cc @@ -11,6 +11,7 @@ #include "ipc/mem/Pages.h" #include "MemObject.h" #include "MemStore.h" +#include "StoreStats.h" #include "HttpReply.h" /// shared memory segment path to use for MemStore maps @@ -51,6 +52,19 @@ MemStore::init() map->cleaner = this; } +void +MemStore::getStats(StoreInfoStats &stats) const +{ + const size_t pageSize = Ipc::Mem::PageSize(); + + stats.mem.shared = true; + stats.mem.capacity = + Ipc::Mem::PageLimit(Ipc::Mem::PageId::cachePage) * pageSize; + stats.mem.size = + Ipc::Mem::PageLevel(Ipc::Mem::PageId::cachePage) * pageSize; + stats.mem.count = currentCount(); +} + void MemStore::stat(StoreEntry &e) const { diff --git a/src/MemStore.h b/src/MemStore.h index c896c54790..17b2e0e752 100644 --- a/src/MemStore.h +++ b/src/MemStore.h @@ -37,6 +37,7 @@ public: virtual uint64_t currentSize() const; virtual uint64_t currentCount() const; virtual int64_t maxObjectSize() const; + virtual void getStats(StoreInfoStats &stats) const; virtual void stat(StoreEntry &) const; virtual StoreSearch *search(String const url, HttpRequest *); virtual void reference(StoreEntry &); diff --git a/src/Store.h b/src/Store.h index 2e0d9cb9a7..9621d1a7b8 100644 --- a/src/Store.h +++ b/src/Store.h @@ -45,6 +45,7 @@ #include "comm/forward.h" #include "Packer.h" #include "RemovalPolicy.h" +#include "StoreStats.h" #if USE_SQUID_ESI #include "esi/Element.h" @@ -61,16 +62,6 @@ class MemObject; class StoreSearch; class SwapDir; -typedef struct { - - struct { - int calls; - int select_fail; - int create_fail; - int success; - } create; -} StoreIoStats; - extern StoreIoStats store_io_stats; /// maximum number of entries per cache_dir @@ -315,6 +306,9 @@ public: /** the maximum object size that can be stored, -1 if unlimited */ virtual int64_t maxObjectSize() const = 0; + /// collect cache storage-related statistics + virtual void getStats(StoreInfoStats &stats) const = 0; + /** * Output stats to the provided store entry. \todo make these calls asynchronous diff --git a/src/StoreHashIndex.h b/src/StoreHashIndex.h index 4ec269f429..936219dc92 100644 --- a/src/StoreHashIndex.h +++ b/src/StoreHashIndex.h @@ -73,6 +73,7 @@ public: virtual int64_t maxObjectSize() const; + virtual void getStats(StoreInfoStats &stats) const; virtual void stat(StoreEntry&) const; virtual void reference(StoreEntry&); diff --git a/src/StoreStats.cc b/src/StoreStats.cc new file mode 100644 index 0000000000..ccf3290d22 --- /dev/null +++ b/src/StoreStats.cc @@ -0,0 +1,62 @@ +/* + * $Id$ + * + * DEBUG: section 20 Storage Manager Statistics + * + */ + +#include "config.h" +#include "protos.h" /* for xmemset only */ +#include "StoreStats.h" + + +/* StoreInfoStats */ + +StoreInfoStats::StoreInfoStats() +{ + xmemset(this, 0, sizeof(*this)); +} + +StoreInfoStats & +StoreInfoStats::operator +=(const StoreInfoStats &stats) +{ + swap.size += stats.swap.size; + swap.capacity += stats.swap.capacity; + swap.count += stats.swap.count; + swap.open_disk_fd += stats.swap.open_disk_fd; + + // Assume that either all workers use shared memory cache or none do. + // It is possible but difficult to report correct stats for an arbitrary + // mix, and only rather unusual deployments can benefit from mixing. + + // If workers share memory, we will get shared stats from those workers + // and non-shared stats from other processes. Ignore order and also + // ignore other processes stats because they are zero in most setups. + if (stats.mem.shared) { // workers share memory + // use the latest reported stats, they all should be about the same + mem.shared = true; + mem.size = stats.mem.size; + mem.capacity = stats.mem.capacity; + mem.count = stats.mem.count; + } else if (!mem.shared) { // do not corrupt shared stats, if any + // workers do not share so we must add everything up + mem.size += stats.mem.size; + mem.capacity += stats.mem.capacity; + mem.count += stats.mem.count; + } + + store_entry_count += stats.store_entry_count; + mem_object_count += stats.mem_object_count; + + return *this; +} + + + +/* StoreIoStats */ + +StoreIoStats::StoreIoStats() +{ + xmemset(this, 0, sizeof(*this)); +} + diff --git a/src/StoreStats.h b/src/StoreStats.h new file mode 100644 index 0000000000..e9d05d8958 --- /dev/null +++ b/src/StoreStats.h @@ -0,0 +1,60 @@ +#ifndef SQUID_STORE_STATS_H +#define SQUID_STORE_STATS_H + +/// High-level store statistics used by mgr:info action. Used inside PODs! +class StoreInfoStats { +public: + /// Info common to memory and disk parts of the storage. Used inside PODs! + class Part { + public: + double size; ///< bytes currently in use + double count; ///< number of cached objects + double capacity; ///< the size limit + + /// mean size of a cached object + double meanObjectSize() const { return count > 0 ? size/count : 0.0; } + + /// number of unused bytes + double available() const { return capacity - size; } + }; + + /// disk cache (all cache_dirs) storage stats + class Swap: public Part { + public: + double open_disk_fd; ///< number of opened disk files + }; + + /// memory cache (cache_mem) storage stats + class Mem: public Part { + public: + bool shared; ///< whether memory cache is shared among workers + }; + + + StoreInfoStats(); + StoreInfoStats &operator +=(const StoreInfoStats &stats); + + + Swap swap; ///< cache_mem stats + Mem mem; ///< all cache_dirs stats + + /* stats that could be shared by memory and disk storage */ + double store_entry_count; ///< number of StoreEntry objects in existence + double mem_object_count; ///< number of MemObject objects in existence +}; + +// TODO: this should be adjusted for use in StoreIoActionData, DiskdActionData +/// Store statistics related to low-level I/O. +class StoreIoStats { +public: + StoreIoStats(); + + struct { + int calls; + int select_fail; + int create_fail; + int success; + } create; ///< cache_dir selection and disk entry creation stats +}; + +#endif /* SQUID_STORE_STATS_H */ diff --git a/src/SwapDir.cc b/src/SwapDir.cc index 6eef047089..33b5a4dada 100644 --- a/src/SwapDir.cc +++ b/src/SwapDir.cc @@ -68,6 +68,17 @@ SwapDir::doubleCheck(StoreEntry &) void SwapDir::unlink(StoreEntry &) {} +void +SwapDir::getStats(StoreInfoStats &stats) const +{ + if (!doReportStat()) + return; + + stats.swap.size = currentSize(); + stats.swap.capacity = maxSize(); + stats.swap.count = currentCount(); +} + void SwapDir::stat(StoreEntry &output) const { diff --git a/src/SwapDir.h b/src/SwapDir.h index 723443cfad..a1c54cac20 100644 --- a/src/SwapDir.h +++ b/src/SwapDir.h @@ -75,6 +75,7 @@ public: virtual int64_t maxObjectSize() const; + virtual void getStats(StoreInfoStats &stats) const; virtual void stat(StoreEntry &) const; virtual void sync(); /* Sync the store prior to shutdown */ @@ -146,6 +147,7 @@ public: virtual int64_t maxObjectSize() const { return max_objsize; } + virtual void getStats(StoreInfoStats &stats) const; virtual void stat (StoreEntry &anEntry) const; virtual StoreSearch *search(String const url, HttpRequest *) = 0; diff --git a/src/mgr/InfoAction.cc b/src/mgr/InfoAction.cc index fa96c57e77..3e7c3412ac 100644 --- a/src/mgr/InfoAction.cc +++ b/src/mgr/InfoAction.cc @@ -58,12 +58,9 @@ Mgr::InfoActionData::operator += (const InfoActionData& stats) request_hit_mem_ratio60 += stats.request_hit_mem_ratio60; request_hit_disk_ratio5 += stats.request_hit_disk_ratio5; request_hit_disk_ratio60 += stats.request_hit_disk_ratio60; - store_swap_size += stats.store_swap_size; - store_swap_max_size += stats.store_swap_max_size; - store_mem_size += stats.store_mem_size; - store_pages_max += stats.store_pages_max; - store_mem_used += stats.store_mem_used; - objects_size += stats.objects_size; + + store += stats.store; + unlink_requests += stats.unlink_requests; http_requests5 += stats.http_requests5; http_requests60 += stats.http_requests60; @@ -124,11 +121,6 @@ Mgr::InfoActionData::operator += (const InfoActionData& stats) opening_fd += stats.opening_fd; num_fd_free += stats.num_fd_free; reserved_fd += stats.reserved_fd; - store_open_disk_fd += stats.store_open_disk_fd; - store_entries += stats.store_entries; - store_mem_entries += stats.store_mem_entries; - hot_obj_count += stats.hot_obj_count; - n_disk_objects += stats.n_disk_objects; ++count; return *this; diff --git a/src/mgr/InfoAction.h b/src/mgr/InfoAction.h index 25721e04ca..bdd9ed8baf 100644 --- a/src/mgr/InfoAction.h +++ b/src/mgr/InfoAction.h @@ -9,6 +9,7 @@ #define SQUID_MGR_INFO_ACTION_H #include "mgr/Action.h" +#include "StoreStats.h" #include @@ -48,12 +49,9 @@ public: double request_hit_mem_ratio60; double request_hit_disk_ratio5; double request_hit_disk_ratio60; - double store_swap_size; - double store_swap_max_size; - double store_mem_size; - double store_pages_max; - double store_mem_used; - double objects_size; + + StoreInfoStats store; ///< disk and memory cache statistics + double unlink_requests; double http_requests5; double http_requests60; @@ -113,11 +111,6 @@ public: double opening_fd; double num_fd_free; double reserved_fd; - double store_open_disk_fd; - double store_entries; - double store_mem_entries; - double hot_obj_count; - double n_disk_objects; unsigned int count; }; diff --git a/src/stat.cc b/src/stat.cc index b1b7b3df35..70fd04b198 100644 --- a/src/stat.cc +++ b/src/stat.cc @@ -548,16 +548,7 @@ GetInfo(Mgr::InfoActionData& stats) stats.request_hit_disk_ratio5 = statRequestHitDiskRatio(5); stats.request_hit_disk_ratio60 = statRequestHitDiskRatio(60); - stats.store_swap_size = Store::Root().currentSize() / 1024.0; - stats.store_swap_max_size = Store::Root().maxSize(); - - stats.store_mem_size = mem_node::StoreMemSize(); - stats.store_pages_max = store_pages_max; - stats.store_mem_used = mem_node::InUseCount(); - - stats.n_disk_objects = Store::Root().currentCount(); - stats.objects_size = stats.n_disk_objects > 0 ? - stats.store_swap_size / stats.n_disk_objects : 0.0; + Store::Root().getStats(stats.store); stats.unlink_requests = statCounter.unlink.requests; @@ -665,11 +656,6 @@ GetInfo(Mgr::InfoActionData& stats) stats.opening_fd = Opening_FD; stats.num_fd_free = fdNFree(); stats.reserved_fd = RESERVED_FD; - stats.store_open_disk_fd = store_open_disk_fd; - - stats.store_entries = StoreEntry::inUseCount(); - stats.store_mem_entries = MemObject::inUseCount(); - stats.hot_obj_count = hot_obj_count; } void @@ -752,22 +738,21 @@ DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry) stats.request_hit_disk_ratio60 / fct); storeAppendPrintf(sentry, "\tStorage Swap size:\t%.0f KB\n", - stats.store_swap_size); + stats.store.swap.size / 1024); storeAppendPrintf(sentry, "\tStorage Swap capacity:\t%4.1f%% used, %4.1f%% free\n", - Math::doublePercent(stats.store_swap_size, stats.store_swap_max_size), - Math::doublePercent(stats.store_swap_max_size - stats.store_swap_size, stats.store_swap_max_size)); + Math::doublePercent(stats.store.swap.size, stats.store.swap.capacity), + Math::doublePercent(stats.store.swap.available(), stats.store.swap.capacity)); storeAppendPrintf(sentry, "\tStorage Mem size:\t%.0f KB\n", - stats.store_mem_size / 1024); + stats.store.mem.size / 1024); - const double mFree = max(0.0, stats.store_pages_max-stats.store_mem_used); storeAppendPrintf(sentry, "\tStorage Mem capacity:\t%4.1f%% used, %4.1f%% free\n", - Math::doublePercent(stats.store_mem_used, stats.store_pages_max), - Math::doublePercent(mFree, stats.store_pages_max)); + Math::doublePercent(stats.store.mem.size, stats.store.mem.capacity), + Math::doublePercent(stats.store.mem.available(), stats.store.mem.capacity)); storeAppendPrintf(sentry, "\tMean Object Size:\t%0.2f KB\n", - stats.objects_size / fct); + stats.store.swap.meanObjectSize() / 1024); storeAppendPrintf(sentry, "\tRequests given to unlinkd:\t%.0f\n", stats.unlink_requests); @@ -949,17 +934,17 @@ DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry) storeAppendPrintf(sentry, "\tReserved number of file descriptors: %4.0f\n", stats.reserved_fd); storeAppendPrintf(sentry, "\tStore Disk files open: %4.0f\n", - stats.store_open_disk_fd); + stats.store.swap.open_disk_fd); storeAppendPrintf(sentry, "Internal Data Structures:\n"); storeAppendPrintf(sentry, "\t%6.0f StoreEntries\n", - stats.store_entries); + stats.store.store_entry_count); storeAppendPrintf(sentry, "\t%6.0f StoreEntries with MemObjects\n", - stats.store_mem_entries); + stats.store.mem_object_count); storeAppendPrintf(sentry, "\t%6.0f Hot Object Cache Items\n", - stats.hot_obj_count); + stats.store.mem.count); storeAppendPrintf(sentry, "\t%6.0f on-disk objects\n", - stats.n_disk_objects); + stats.store.swap.count); } void diff --git a/src/store_dir.cc b/src/store_dir.cc index 92ba9a1ddd..33feeb8e28 100644 --- a/src/store_dir.cc +++ b/src/store_dir.cc @@ -326,6 +326,26 @@ storeDirSwapLog(const StoreEntry * e, int op) dynamic_cast(INDEXSD(e->swap_dirn))->logEntry(*e, op); } +void +StoreController::getStats(StoreInfoStats &stats) const +{ + if (memStore) + memStore->getStats(stats); + else { + // move this code to a non-shared memory cache class when we have it + stats.mem.shared = false; + stats.mem.capacity = Config.memMaxSize; + stats.mem.size = mem_node::StoreMemSize(); + stats.mem.count = hot_obj_count; + } + + swapDir->getStats(stats); + + // low-level info not specific to memory or disk cache + stats.store_entry_count = StoreEntry::inUseCount(); + stats.mem_object_count = MemObject::inUseCount(); +} + void StoreController::stat(StoreEntry &output) const { @@ -965,6 +985,22 @@ StoreHashIndex::maxObjectSize() const return result; } +void +StoreHashIndex::getStats(StoreInfoStats &stats) const +{ + // accumulate per-disk cache stats + for (int i = 0; i < Config.cacheSwap.n_configured; i++) { + StoreInfoStats dirStats; + store(i)->getStats(dirStats); + stats += dirStats; + } + + // common to all disks + stats.swap.open_disk_fd = store_open_disk_fd; + + // memory cache stats are collected in StoreController::getStats(), for now +} + void StoreHashIndex::stat(StoreEntry & output) const { diff --git a/src/tests/stub_MemObject.cc b/src/tests/stub_MemObject.cc index a10d492a5b..6e4c929d04 100644 --- a/src/tests/stub_MemObject.cc +++ b/src/tests/stub_MemObject.cc @@ -199,3 +199,10 @@ MemObject::markEndOfReplyHeaders() { fatal ("MemObject.cc required."); } + +size_t +MemObject::inUseCount() +{ + fatal ("MemObject.cc required."); + return 0; +} diff --git a/src/tests/stub_MemStore.cc b/src/tests/stub_MemStore.cc index 03bef5cfd0..de357af194 100644 --- a/src/tests/stub_MemStore.cc +++ b/src/tests/stub_MemStore.cc @@ -19,6 +19,7 @@ void MemStore::maintain() STUB void MemStore::cleanReadable(const sfileno) STUB void MemStore::get(String const, STOREGETCLIENT, void *) STUB void MemStore::init() STUB +void MemStore::getStats(StoreInfoStats&) const STUB void MemStore::stat(StoreEntry &) const STUB int MemStore::callback() STUB_RETVAL(0) StoreEntry *MemStore::get(const cache_key *) STUB_RETVAL(NULL) diff --git a/src/tests/stub_store_stats.cc b/src/tests/stub_store_stats.cc new file mode 100644 index 0000000000..9a43f8441d --- /dev/null +++ b/src/tests/stub_store_stats.cc @@ -0,0 +1,19 @@ +#include "squid.h" + +#define STUB_API "StoreStats.cc" +#include "tests/STUB.h" + +#include "StoreStats.h" +#include + +StoreInfoStats::StoreInfoStats() STUB + +StoreInfoStats & +StoreInfoStats::operator +=(const StoreInfoStats &stats) STUB_RETVAL(*this) + +StoreIoStats::StoreIoStats() +{ + // we have to implement this one because tests/stub_store.cc + // has a StoreIoStats global + memset(this, 0, sizeof(*this)); +} diff --git a/src/tests/testStore.cc b/src/tests/testStore.cc index 0382776fe6..0e80a6192a 100644 --- a/src/tests/testStore.cc +++ b/src/tests/testStore.cc @@ -57,6 +57,11 @@ TestStore::maxObjectSize() const return 1; } +void +TestStore::getStats(StoreInfoStats &) const +{ +} + void TestStore::stat(StoreEntry &) const { diff --git a/src/tests/testStore.h b/src/tests/testStore.h index 9a60e75347..32c60330ae 100644 --- a/src/tests/testStore.h +++ b/src/tests/testStore.h @@ -65,6 +65,8 @@ public: virtual int64_t maxObjectSize() const; + virtual void getStats(StoreInfoStats &) const; + virtual void stat(StoreEntry &) const; /* output stats to the provided store entry */ virtual void reference(StoreEntry &) {} /* Reference this object */