*
*/
-#include "squid-old.h"
-#include "Store.h"
+#include "squid.h"
+#include "globals.h"
+#include "mem_node.h"
#include "MemObject.h"
#include "MemStore.h"
-#include "mem_node.h"
+#include "profiler/Profiler.h"
+#include "protos.h"
#include "SquidMath.h"
#include "SquidTime.h"
+#include "Store.h"
+#include "StoreHashIndex.h"
#include "SwapDir.h"
#include "swap_log_op.h"
#if HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
-
-#include "StoreHashIndex.h"
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
static STDIRSELECT storeDirSelectSwapDirRoundRobin;
static STDIRSELECT storeDirSelectSwapDirLeastLoad;
if (0 == strcasecmp(Config.store_dir_select_algorithm, "round-robin")) {
storeDirSelectSwapDir = storeDirSelectSwapDirRoundRobin;
- debugs(47, 1, "Using Round Robin store dir selection");
+ debugs(47, DBG_IMPORTANT, "Using Round Robin store dir selection");
} else {
storeDirSelectSwapDir = storeDirSelectSwapDirLeastLoad;
- debugs(47, 1, "Using Least Load store dir selection");
+ debugs(47, DBG_IMPORTANT, "Using Least Load store dir selection");
}
}
return min_objsize <= objsize && max_objsize > objsize;
}
-
/*
* This new selection scheme simply does round-robin on all SwapDirs.
* A SwapDir is skipped if it is over the max_size (100%) limit, or
if (objsize != -1)
objsize += e->mem_obj->swap_hdr_sz;
- for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (++dirn >= Config.cacheSwap.n_configured)
dirn = 0;
if (objsize != -1)
objsize += e->mem_obj->swap_hdr_sz;
- for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (i = 0; i < Config.cacheSwap.n_configured; ++i) {
SD = dynamic_cast<SwapDir *>(INDEXSD(i));
SD->flags.selected = 0;
storeAppendPrintf(&output, "Store Directory Statistics:\n");
storeAppendPrintf(&output, "Store Entries : %lu\n",
(unsigned long int)StoreEntry::inUseCount());
- storeAppendPrintf(&output, "Maximum Swap Size : %"PRIu64" KB\n",
+ storeAppendPrintf(&output, "Maximum Swap Size : %" PRIu64 " KB\n",
maxSize() >> 10);
storeAppendPrintf(&output, "Current Store Swap Size: %.2f KB\n",
currentSize() / 1024.0);
max_size = currentSize();
- debugs(20, 1, "WARNING: Shrinking cache_dir #" << index << " to " << currentSize() / 1024.0 << " KB");
+ debugs(20, DBG_IMPORTANT, "WARNING: Shrinking cache_dir #" << index << " to " << currentSize() / 1024.0 << " KB");
}
void
int notdone = 1;
if (StoreController::store_dirs_rebuilding) {
- debugs(20, 1, "Not currently OK to rewrite swap log.");
- debugs(20, 1, "storeDirWriteCleanLogs: Operation aborted.");
+ debugs(20, DBG_IMPORTANT, "Not currently OK to rewrite swap log.");
+ debugs(20, DBG_IMPORTANT, "storeDirWriteCleanLogs: Operation aborted.");
return 0;
}
- debugs(20, 1, "storeDirWriteCleanLogs: Starting...");
+ debugs(20, DBG_IMPORTANT, "storeDirWriteCleanLogs: Starting...");
getCurrentTime();
start = current_time;
- for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
+ for (dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn) {
sd = dynamic_cast<SwapDir *>(INDEXSD(dirn));
if (sd->writeCleanStart() < 0) {
- debugs(20, 1, "log.clean.start() failed for dir #" << sd->index);
+ debugs(20, DBG_IMPORTANT, "log.clean.start() failed for dir #" << sd->index);
continue;
}
}
while (notdone) {
notdone = 0;
- for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) {
+ for (dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn) {
sd = dynamic_cast<SwapDir *>(INDEXSD(dirn));
if (NULL == sd->cleanLog)
if ((++n & 0xFFFF) == 0) {
getCurrentTime();
- debugs(20, 1, " " << std::setw(7) << n <<
+ debugs(20, DBG_IMPORTANT, " " << std::setw(7) << n <<
" entries written so far.");
}
}
}
/* Flush */
- for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++)
+ for (dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn)
dynamic_cast<SwapDir *>(INDEXSD(dirn))->writeCleanDone();
if (reopen)
dt = tvSubDsec(start, current_time);
- debugs(20, 1, " Finished. Wrote " << n << " entries.");
- debugs(20, 1, " Took "<< std::setw(3)<< std::setprecision(2) << dt <<
+ debugs(20, DBG_IMPORTANT, " Finished. Wrote " << n << " entries.");
+ debugs(20, DBG_IMPORTANT, " Took "<< std::setw(3)<< std::setprecision(2) << dt <<
" seconds ("<< std::setw(6) << ((double) n / (dt > 0.0 ? dt : 1.0)) << " entries/sec).");
-
return n;
}
struct statvfs sfs;
if (statvfs(path, &sfs)) {
- debugs(50, 1, "" << path << ": " << xstrerror());
+ debugs(50, DBG_IMPORTANT, "" << path << ": " << xstrerror());
*blksize = 2048;
return 1;
}
struct statfs sfs;
if (statfs(path, &sfs)) {
- debugs(50, 1, "" << path << ": " << xstrerror());
+ debugs(50, DBG_IMPORTANT, "" << path << ": " << xstrerror());
*blksize = 2048;
return 1;
}
struct statvfs sfs;
if (statvfs(path, &sfs)) {
- debugs(50, 1, "" << path << ": " << xstrerror());
+ debugs(50, DBG_IMPORTANT, "" << path << ": " << xstrerror());
return 1;
}
struct statfs sfs;
if (statfs(path, &sfs)) {
- debugs(50, 1, "" << path << ": " << xstrerror());
+ debugs(50, DBG_IMPORTANT, "" << path << ": " << xstrerror());
return 1;
}
if (reconfiguring)
return;
- for (i = 0; i < swap->n_configured; i++) {
+ for (i = 0; i < swap->n_configured; ++i) {
/* TODO XXX this lets the swapdir free resources asynchronously
* swap->swapDirs[i]->deactivate();
* but there may be such a means already.
void
StoreController::reference(StoreEntry &e)
{
+ // special entries do not belong to any specific Store, but are IN_MEMORY
+ if (EBIT_TEST(e.flags, ENTRY_SPECIAL))
+ return;
+
/* Notify the fs that we're referencing this object again */
if (e.swap_dirn > -1)
{
bool keepInStoreTable = true; // keep if there are no objections
+ // special entries do not belong to any specific Store, but are IN_MEMORY
+ if (EBIT_TEST(e.flags, ENTRY_SPECIAL))
+ return keepInStoreTable;
+
/* Notify the fs that we're not referencing this object any more */
if (e.swap_filen > -1)
fatal("not implemented");
}
+// move this into [non-shared] memory cache class when we have one
+/// whether e should be kept in local RAM for possible future caching
+bool
+StoreController::keepForLocalMemoryCache(const StoreEntry &e) const
+{
+ if (!e.memoryCachable())
+ return false;
+
+ // does the current and expected size obey memory caching limits?
+ assert(e.mem_obj);
+ const int64_t loadedSize = e.mem_obj->endOffset();
+ const int64_t expectedSize = e.mem_obj->expectedReplySize(); // may be < 0
+ const int64_t ramSize = max(loadedSize, expectedSize);
+ const int64_t ramLimit = min(
+ static_cast<int64_t>(Config.memMaxSize),
+ static_cast<int64_t>(Config.Store.maxInMemObjSize));
+ return ramSize <= ramLimit;
+}
+
+void
+StoreController::maybeTrimMemory(StoreEntry &e, const bool preserveSwappable)
+{
+ bool keepInLocalMemory = false;
+ if (memStore)
+ keepInLocalMemory = memStore->keepInLocalMemory(e);
+ else
+ keepInLocalMemory = keepForLocalMemoryCache(e);
+
+ debugs(20, 7, HERE << "keepInLocalMemory: " << keepInLocalMemory);
+
+ if (!keepInLocalMemory)
+ e.trimMemory(preserveSwappable);
+}
+
void
StoreController::handleIdleEntry(StoreEntry &e)
{
bool keepInLocalMemory = false;
- if (memStore) {
+
+ if (EBIT_TEST(e.flags, ENTRY_SPECIAL)) {
+ // Icons (and cache digests?) should stay in store_table until we
+ // have a dedicated storage for them (that would not purge them).
+ // They are not managed [well] by any specific Store handled below.
+ keepInLocalMemory = true;
+ } else if (memStore) {
memStore->considerKeeping(e);
// leave keepInLocalMemory false; memStore maintains its own cache
} else {
- keepInLocalMemory = e.memoryCachable() && // entry is in good shape and
+ keepInLocalMemory = keepForLocalMemoryCache(e) && // in good shape and
// the local memory cache is not overflowing
(mem_node::InUseCount() <= store_pages_max);
}
return;
}
+ debugs(20, 5, HERE << "keepInLocalMemory: " << keepInLocalMemory);
+
// TODO: move this into [non-shared] memory cache class when we have one
if (keepInLocalMemory) {
e.setMemStatus(IN_MEMORY);
do {
j = 0;
- for (int i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (ndir >= Config.cacheSwap.n_configured)
ndir = ndir % Config.cacheSwap.n_configured;
}
} while (j > 0);
- ndir++;
+ ++ndir;
return result;
}
void
StoreHashIndex::create()
{
- for (int i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (dir(i).active())
store(i)->create();
}
/* this is very bogus, its specific to the any Store maintaining an
* in-core index, not global */
size_t buckets = (Store::Root().maxSize() + Config.memMaxSize) / Config.Store.avgObjectSize;
- debugs(20, 1, "Swap maxSize " << (Store::Root().maxSize() >> 10) <<
+ debugs(20, DBG_IMPORTANT, "Swap maxSize " << (Store::Root().maxSize() >> 10) <<
" + " << ( Config.memMaxSize >> 10) << " KB, estimated " << buckets << " objects");
buckets /= Config.Store.objectsPerBucket;
- debugs(20, 1, "Target number of buckets: " << buckets);
+ debugs(20, DBG_IMPORTANT, "Target number of buckets: " << buckets);
/* ideally the full scan period should be configurable, for the
* moment it remains at approximately 24 hours. */
store_hash_buckets = storeKeyHashBuckets(buckets);
- debugs(20, 1, "Using " << store_hash_buckets << " Store buckets");
- debugs(20, 1, "Max Mem size: " << ( Config.memMaxSize >> 10) << " KB" <<
+ debugs(20, DBG_IMPORTANT, "Using " << store_hash_buckets << " Store buckets");
+ debugs(20, DBG_IMPORTANT, "Max Mem size: " << ( Config.memMaxSize >> 10) << " KB" <<
(Config.memShared ? " [shared]" : ""));
- debugs(20, 1, "Max Swap size: " << (Store::Root().maxSize() >> 10) << " KB");
+ debugs(20, DBG_IMPORTANT, "Max Swap size: " << (Store::Root().maxSize() >> 10) << " KB");
store_table = hash_create(storeKeyHashCmp,
store_hash_buckets, storeKeyHashHash);
- for (int i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
/* this starts a search of the store dirs, loading their
* index. under the new Store api this should be
* driven by the StoreHashIndex, not by each store.
{
uint64_t result = 0;
- for (int i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (dir(i).doReportStat())
result += store(i)->maxSize();
}
{
uint64_t result = 0;
- for (int i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (dir(i).doReportStat())
result += store(i)->minSize();
}
{
uint64_t result = 0;
- for (int i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (dir(i).doReportStat())
result += store(i)->currentSize();
}
{
uint64_t result = 0;
- for (int i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (dir(i).doReportStat())
result += store(i)->currentCount();
}
{
int64_t result = -1;
- for (int i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (dir(i).active() && store(i)->maxObjectSize() > result)
result = store(i)->maxObjectSize();
}
StoreHashIndex::getStats(StoreInfoStats &stats) const
{
// accumulate per-disk cache stats
- for (int i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
StoreInfoStats dirStats;
store(i)->getStats(dirStats);
stats += dirStats;
/* Now go through each store, calling its stat routine */
- for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (i = 0; i < Config.cacheSwap.n_configured; ++i) {
storeAppendPrintf(&output, "\n");
store(i)->stat(output);
}
int i;
/* walk each fs */
- for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+ for (i = 0; i < Config.cacheSwap.n_configured; ++i) {
/* XXX FixMe: This should be done "in parallell" on the different
* cache_dirs, not one at a time.
*/
entries.push_back(e);
}
- bucket++;
+ ++bucket;
debugs(47,3, "got entries: " << entries.size());
}