#include "SquidString.h"
#include "ssl/ProxyCerts.h"
#include "Store.h"
-#include "store/Disk.h"
#include "store/Disks.h"
-#include "StoreFileSystem.h"
#include "tools.h"
#include "util.h"
#include "wordlist.h"
memConfigure();
/* Sanity checks */
- Config.cacheSwap.n_strands = 0; // no diskers by default
- if (Config.cacheSwap.swapDirs == NULL) {
- /* Memory-only cache probably in effect. */
- /* turn off the cache rebuild delays... */
- StoreController::store_dirs_rebuilding = 0;
- } else if (InDaemonMode()) { // no diskers in non-daemon mode
- for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
- const RefCount<SwapDir> sd = Config.cacheSwap.swapDirs[i];
- if (sd->needsDiskStrand())
- sd->disker = Config.workers + (++Config.cacheSwap.n_strands);
- }
- }
-
if (Debug::rotateNumber < 0) {
Debug::rotateNumber = Config.Log.rotateNumber;
}
static void
dump_cachedir(StoreEntry * entry, const char *name, const Store::DiskConfig &swap)
{
- SwapDir *s;
- int i;
- assert (entry);
-
- for (i = 0; i < swap.n_configured; ++i) {
- s = dynamic_cast<SwapDir *>(swap.swapDirs[i].getRaw());
- if (!s) continue;
- storeAppendPrintf(entry, "%s %s %s", name, s->type(), s->path);
- s->dump(*entry);
- storeAppendPrintf(entry, "\n");
- }
+ Store::Disks::Dump(swap, *entry, name);
}
static int
(*access)->add(rule, action);
}
-/* TODO: just return the object, the # is irrelevant */
-static int
-find_fstype(char *type)
-{
- for (size_t i = 0; i < StoreFileSystem::FileSystems().size(); ++i)
- if (strcasecmp(type, StoreFileSystem::FileSystems().at(i)->type()) == 0)
- return (int)i;
-
- return (-1);
-}
-
static void
parse_cachedir(Store::DiskConfig *swap)
{
- char *type_str = ConfigParser::NextToken();
- if (!type_str) {
- self_destruct();
- return;
- }
-
- char *path_str = ConfigParser::NextToken();
- if (!path_str) {
- self_destruct();
- return;
- }
-
- int fs = find_fstype(type_str);
- if (fs < 0) {
- debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: This proxy does not support the '" << type_str << "' cache type. Ignoring.");
- return;
- }
-
- /* reconfigure existing dir */
-
- RefCount<SwapDir> sd;
- for (int i = 0; i < swap->n_configured; ++i) {
- assert (swap->swapDirs[i].getRaw());
-
- if ((strcasecmp(path_str, dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw())->path)) == 0) {
- /* this is specific to on-fs Stores. The right
- * way to handle this is probably to have a mapping
- * from paths to stores, and have on-fs stores
- * register with that, and lookip in that in their
- * own setup logic. RBC 20041225. TODO.
- */
-
- sd = dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw());
-
- if (strcmp(sd->type(), StoreFileSystem::FileSystems().at(fs)->type()) != 0) {
- debugs(3, DBG_CRITICAL, "ERROR: Can't change type of existing cache_dir " <<
- sd->type() << " " << sd->path << " to " << type_str << ". Restart required");
- return;
- }
-
- sd->reconfigure();
- return;
- }
- }
-
- /* new cache_dir */
- if (swap->n_configured > 63) {
- /* 7 bits, signed */
- debugs(3, DBG_CRITICAL, "WARNING: There is a fixed maximum of 63 cache_dir entries Squid can handle.");
- debugs(3, DBG_CRITICAL, "WARNING: '" << path_str << "' is one to many.");
- self_destruct();
- return;
- }
-
- allocate_new_swapdir(swap);
-
- swap->swapDirs[swap->n_configured] = StoreFileSystem::FileSystems().at(fs)->createSwapDir();
-
- sd = dynamic_cast<SwapDir *>(swap->swapDirs[swap->n_configured].getRaw());
-
- /* parse the FS parameters and options */
- sd->parse(swap->n_configured, path_str);
-
- ++swap->n_configured;
+ assert(swap);
+ Store::Disks::Parse(*swap);
}
static const char *
/* DEBUG: section 47 Store Directory Routines */
#include "squid.h"
+#include "cache_cf.h"
+#include "ConfigParser.h"
#include "Debug.h"
#include "globals.h"
#include "profiler/Profiler.h"
+#include "sbuf/Stream.h"
#include "SquidConfig.h"
#include "Store.h"
#include "store/Disk.h"
#include "store/Disks.h"
+#include "StoreFileSystem.h"
#include "store_rebuild.h"
#include "swap_log_op.h"
+#include "tools.h"
#include "util.h" // for tvSubDsec() which should be in SquidTime.h
+typedef SwapDir *STDIRSELECT(const StoreEntry *e);
+
static STDIRSELECT storeDirSelectSwapDirRoundRobin;
static STDIRSELECT storeDirSelectSwapDirLeastLoad;
/**
* This function pointer is set according to 'store_dir_select_algorithm'
* in squid.conf.
*/
-STDIRSELECT *storeDirSelectSwapDir = storeDirSelectSwapDirLeastLoad;
+static STDIRSELECT *storeDirSelectSwapDir = storeDirSelectSwapDirLeastLoad;
/// The entry size to use for Disk::canStore() size limit checks.
/// This is an optimization to avoid similar calculations in every cache_dir.
return minSize;
}
+/// TODO: Remove when cache_dir-iterating functions are converted to Disks methods
+static SwapDir &
+SwapDirByIndex(const int i)
+{
+ assert(i >= 0);
+ assert(i < Config.cacheSwap.n_allocated);
+ const auto sd = INDEXSD(i);
+ assert(sd);
+ return *sd;
+}
+
/**
* 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
* overloaded.
*/
-static int
+static SwapDir *
storeDirSelectSwapDirRoundRobin(const StoreEntry * e)
{
const int64_t objsize = objectSizeForDirSelection(*e);
for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
const int dirn = (firstCandidate + i) % Config.cacheSwap.n_configured;
- const SwapDir *sd = dynamic_cast<SwapDir*>(INDEXSD(dirn));
+ auto &dir = SwapDirByIndex(dirn);
int load = 0;
- if (!sd->canStore(*e, objsize, load))
+ if (!dir.canStore(*e, objsize, load))
continue;
if (load < 0 || load > 1000) {
continue;
}
- return dirn;
+ return &dir;
}
- return -1;
+ return nullptr;
}
/**
* ALL swapdirs, regardless of state. Again, this is a hack while
* we sort out the real usefulness of this algorithm.
*/
-static int
+static SwapDir *
storeDirSelectSwapDirLeastLoad(const StoreEntry * e)
{
int64_t most_free = 0;
int64_t best_objsize = -1;
int least_load = INT_MAX;
int load;
- int dirn = -1;
+ SwapDir *selectedDir = nullptr;
int i;
- RefCount<SwapDir> SD;
const int64_t objsize = objectSizeForDirSelection(*e);
for (i = 0; i < Config.cacheSwap.n_configured; ++i) {
- SD = dynamic_cast<SwapDir *>(INDEXSD(i));
- SD->flags.selected = false;
+ auto &sd = SwapDirByIndex(i);
+ sd.flags.selected = false;
- if (!SD->canStore(*e, objsize, load))
+ if (!sd.canStore(*e, objsize, load))
continue;
if (load < 0 || load > 1000)
if (load > least_load)
continue;
- const int64_t cur_free = SD->maxSize() - SD->currentSize();
+ const int64_t cur_free = sd.maxSize() - sd.currentSize();
/* If the load is equal, then look in more details */
if (load == least_load) {
if (best_objsize != -1) {
// cache_dir with the smallest max-size gets the known-size object
// cache_dir with the largest max-size gets the unknown-size object
- if ((objsize != -1 && SD->maxObjectSize() > best_objsize) ||
- (objsize == -1 && SD->maxObjectSize() < best_objsize))
+ if ((objsize != -1 && sd.maxObjectSize() > best_objsize) ||
+ (objsize == -1 && sd.maxObjectSize() < best_objsize))
continue;
}
}
least_load = load;
- best_objsize = SD->maxObjectSize();
+ best_objsize = sd.maxObjectSize();
most_free = cur_free;
- dirn = i;
+ selectedDir = &sd;
}
- if (dirn >= 0)
- dynamic_cast<SwapDir *>(INDEXSD(dirn))->flags.selected = true;
+ if (selectedDir)
+ selectedDir->flags.selected = true;
- return dirn;
+ return selectedDir;
}
Store::Disks::Disks():
SwapDir *
Store::Disks::store(int const x) const
{
- return INDEXSD(x);
+ return &SwapDirByIndex(x);
}
SwapDir &
Store::Disks::Dir(const int i)
{
- SwapDir *sd = INDEXSD(i);
- assert(sd);
- return *sd;
+ return SwapDirByIndex(i);
}
int
static int idx = 0;
for (int n = 0; n < cacheDirs; ++n) {
idx = (idx + 1) % cacheDirs;
- SwapDir *sd = dynamic_cast<SwapDir*>(INDEXSD(idx));
- if (!sd->active())
+ auto &sd = Dir(idx);
+ if (!sd.active())
continue;
- if (StoreEntry *e = sd->get(key)) {
+ if (auto e = sd.get(key)) {
debugs(20, 7, "cache_dir " << idx << " has: " << *e);
return e;
}
}
void
-Store::Disks::updateLimits()
+Store::Disks::configure()
{
+ if (!Config.cacheSwap.swapDirs)
+ Controller::store_dirs_rebuilding = 0; // nothing to index
+
largestMinimumObjectSize = -1;
largestMaximumObjectSize = -1;
secondLargestMaximumObjectSize = -1;
+ Config.cacheSwap.n_strands = 0;
+
for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
- const auto &disk = Dir(i);
+ auto &disk = Dir(i);
+ if (disk.needsDiskStrand()) {
+ assert(InDaemonMode());
+ // XXX: Do not pretend to support disk.disker changes during reconfiguration
+ disk.disker = Config.workers + (++Config.cacheSwap.n_strands);
+ }
+
if (!disk.active())
continue;
}
}
+void
+Store::Disks::Parse(DiskConfig &swap)
+{
+ const auto typeStr = ConfigParser::NextToken();
+ if (!typeStr)
+ throw TextException("missing cache_dir parameter: storage type", Here());
+
+ const auto pathStr = ConfigParser::NextToken();
+ if (!pathStr)
+ throw TextException("missing cache_dir parameter: directory name", Here());
+
+ const auto fs = StoreFileSystem::FindByType(typeStr);
+ if (!fs) {
+ debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: This proxy does not support the '" << typeStr << "' cache type. Ignoring.");
+ return;
+ }
+
+ const auto fsType = fs->type();
+
+ // check for the existing cache_dir
+ // XXX: This code mistreats duplicated cache_dir entries (that should be fatal).
+ for (int i = 0; i < swap.n_configured; ++i) {
+ auto &disk = Dir(i);
+ if ((strcasecmp(pathStr, disk.path)) == 0) {
+ /* this is specific to on-fs Stores. The right
+ * way to handle this is probably to have a mapping
+ * from paths to stores, and have on-fs stores
+ * register with that, and lookip in that in their
+ * own setup logic. RBC 20041225. TODO.
+ */
+
+ if (strcmp(disk.type(), fsType) == 0)
+ disk.reconfigure();
+ else
+ debugs(3, DBG_CRITICAL, "ERROR: Can't change type of existing cache_dir " <<
+ disk.type() << " " << disk.path << " to " << fsType << ". Restart required");
+
+ return;
+ }
+ }
+
+ const int cacheDirCountLimit = 64; // StoreEntry::swap_dirn is a signed 7-bit integer
+ if (swap.n_configured >= cacheDirCountLimit)
+ throw TextException(ToSBuf("Squid cannot handle more than ", cacheDirCountLimit, " cache_dir directives"), Here());
+
+ // create a new cache_dir
+ allocate_new_swapdir(swap);
+ swap.swapDirs[swap.n_configured] = fs->createSwapDir();
+ auto &disk = Dir(swap.n_configured);
+ disk.parse(swap.n_configured, pathStr);
+ ++swap.n_configured;
+}
+
+void
+Store::Disks::Dump(const DiskConfig &swap, StoreEntry &entry, const char *name)
+{
+ for (int i = 0; i < swap.n_configured; ++i) {
+ const auto &disk = Dir(i);
+ storeAppendPrintf(&entry, "%s %s %s", name, disk.type(), disk.path);
+ disk.dump(entry);
+ storeAppendPrintf(&entry, "\n");
+ }
+}
+
int64_t
Store::Disks::accumulateMore(const StoreEntry &entry) const
{
Store::Disks::updateAnchored(StoreEntry &entry)
{
return entry.hasDisk() &&
- Dir(entry.swap_dirn).updateAnchored(entry);
+ entry.disk().updateAnchored(entry);
}
bool
return false;
}
+SwapDir *
+Store::Disks::SelectSwapDir(const StoreEntry *e)
+{
+ return storeDirSelectSwapDir(e);
+}
+
bool
Store::Disks::hasReadableEntry(const StoreEntry &e) const
{
storeDirOpenSwapLogs()
{
for (int dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn)
- INDEXSD(dirn)->openLog();
+ SwapDirByIndex(dirn).openLog();
}
void
storeDirCloseSwapLogs()
{
for (int dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn)
- INDEXSD(dirn)->closeLog();
+ SwapDirByIndex(dirn).closeLog();
}
/**
struct timeval start;
double dt;
- RefCount<SwapDir> sd;
int dirn;
int notdone = 1;
start = current_time;
for (dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn) {
- sd = dynamic_cast<SwapDir *>(INDEXSD(dirn));
+ auto &sd = SwapDirByIndex(dirn);
- if (sd->writeCleanStart() < 0) {
- debugs(20, DBG_IMPORTANT, "log.clean.start() failed for dir #" << sd->index);
+ if (sd.writeCleanStart() < 0) {
+ debugs(20, DBG_IMPORTANT, "log.clean.start() failed for dir #" << sd.index);
continue;
}
}
notdone = 0;
for (dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn) {
- sd = dynamic_cast<SwapDir *>(INDEXSD(dirn));
+ auto &sd = SwapDirByIndex(dirn);
- if (NULL == sd->cleanLog)
+ if (!sd.cleanLog)
continue;
- e = sd->cleanLog->nextEntry();
+ e = sd.cleanLog->nextEntry();
if (!e)
continue;
notdone = 1;
- if (!sd->canLog(*e))
+ if (!sd.canLog(*e))
continue;
- sd->cleanLog->write(*e);
+ sd.cleanLog->write(*e);
if ((++n & 0xFFFF) == 0) {
getCurrentTime();
/* Flush */
for (dirn = 0; dirn < Config.cacheSwap.n_configured; ++dirn)
- dynamic_cast<SwapDir *>(INDEXSD(dirn))->writeCleanDone();
+ SwapDirByIndex(dirn).writeCleanDone();
if (reopen)
storeDirOpenSwapLogs();
/* Globals that should be converted to static Store::Disks methods */
void
-allocate_new_swapdir(Store::DiskConfig *swap)
+allocate_new_swapdir(Store::DiskConfig &swap)
{
- if (!swap->swapDirs) {
- swap->n_allocated = 4;
- swap->swapDirs = new SwapDir::Pointer[swap->n_allocated];
+ if (!swap.swapDirs) {
+ swap.n_allocated = 4;
+ swap.swapDirs = new SwapDir::Pointer[swap.n_allocated];
}
- if (swap->n_allocated == swap->n_configured) {
- swap->n_allocated <<= 1;
- const auto tmp = new SwapDir::Pointer[swap->n_allocated];
- for (int i = 0; i < swap->n_configured; ++i) {
- tmp[i] = swap->swapDirs[i];
+ if (swap.n_allocated == swap.n_configured) {
+ swap.n_allocated <<= 1;
+ const auto tmp = new SwapDir::Pointer[swap.n_allocated];
+ for (int i = 0; i < swap.n_configured; ++i) {
+ tmp[i] = swap.swapDirs[i];
}
- delete[] swap->swapDirs;
- swap->swapDirs = tmp;
+ delete[] swap.swapDirs;
+ swap.swapDirs = tmp;
}
}
e->swap_dirn << " " <<
std::hex << std::uppercase << std::setfill('0') << std::setw(8) << e->swap_filen);
- dynamic_cast<SwapDir *>(INDEXSD(e->swap_dirn))->logEntry(*e, op);
+ e->disk().logEntry(*e, op);
}