Math::doublePercent(currentSize(), maxSize()));
if (map) {
- const int limit = map->entryLimit();
- storeAppendPrintf(&e, "Maximum entries: %9d\n", limit);
- if (limit > 0) {
+ const int entryLimit = map->entryLimit();
+ const int slotLimit = map->sliceLimit();
+ storeAppendPrintf(&e, "Maximum entries: %9d\n", entryLimit);
+ if (entryLimit > 0) {
storeAppendPrintf(&e, "Current entries: %" PRId64 " %.2f%%\n",
- currentCount(), (100.0 * currentCount() / limit));
+ currentCount(), (100.0 * currentCount() / entryLimit));
+ }
+ storeAppendPrintf(&e, "Maximum slots: %9d\n", slotLimit);
+ if (slotLimit > 0) {
const unsigned int slotsFree =
Ipc::Mem::PagesAvailable(Ipc::Mem::PageId::cachePage);
- if (slotsFree <= static_cast<const unsigned int>(limit)) {
- const int usedSlots = limit - static_cast<const int>(slotsFree);
+ if (slotsFree <= static_cast<const unsigned int>(slotLimit)) {
+ const int usedSlots = slotLimit - static_cast<const int>(slotsFree);
storeAppendPrintf(&e, "Used slots: %9d %.2f%%\n",
- usedSlots, (100.0 * usedSlots / limit));
+ usedSlots, (100.0 * usedSlots / slotLimit));
}
- if (limit < 100) { // XXX: otherwise too expensive to count
+ if (slotLimit < 100) { // XXX: otherwise too expensive to count
Ipc::ReadWriteLockStats stats;
map->updateStats(stats);
stats.dump(e);
}
void
-MemStore::noteFreeMapSlice(const sfileno sliceId)
+MemStore::noteFreeMapSlice(const Ipc::StoreMapSliceId sliceId)
{
Ipc::Mem::PageId &pageId = map->extras(sliceId).page;
debugs(20, 9, "slice " << sliceId << " freed " << pageId);
sfileno reserveSapForWriting(Ipc::Mem::PageId &page);
// Ipc::StoreMapCleaner API
- virtual void noteFreeMapSlice(const sfileno sliceId);
+ virtual void noteFreeMapSlice(const Ipc::StoreMapSliceId sliceId);
private:
// TODO: move freeSlots into map
}
void
-Transients::noteFreeMapSlice(const sfileno sliceId)
+Transients::noteFreeMapSlice(const Ipc::StoreMapSliceId sliceId)
{
// TODO: we should probably find the entry being deleted and abort it
}
bool abandonedAt(const sfileno index) const;
// Ipc::StoreMapCleaner API
- virtual void noteFreeMapSlice(const sfileno sliceId);
+ virtual void noteFreeMapSlice(const Ipc::StoreMapSliceId sliceId);
private:
/// shared packed info indexed by Store keys, for creating new StoreEntries
/* store entry-level information indexed by sfileno */
uint64_t size; ///< payload seen so far
uint32_t version; ///< DbCellHeader::version to distinguish same-URL chains
- uint32_t state:3; ///< current entry state (one of the State values)
- uint32_t anchored:1; ///< whether we loaded the inode slot for this entry
+ uint8_t state:3; ///< current entry state (one of the State values)
+ uint8_t anchored:1; ///< whether we loaded the inode slot for this entry
/* db slot-level information indexed by slotId, starting with firstSlot */
- uint32_t mapped:1; ///< whether this slot was added to a mapped entry
- uint32_t freed:1; ///< whether this slot was marked as free
- sfileno more:25; ///< another slot in some entry chain (unordered)
+ uint8_t mapped:1; ///< whether this slot was added to a mapped entry
+ uint8_t freed:1; ///< whether this slot was marked as free
+ Ipc::StoreMapSliceId more; ///< another slot in some entry chain (unordered)
bool used() const { return freed || mapped || more != -1; }
/// possible entry states
sd(dir),
entries(NULL),
dbSize(0),
- dbEntrySize(0),
+ dbSlotSize(0),
+ dbSlotLimit(0),
dbEntryLimit(0),
fd(-1),
dbOffset(0),
assert(sd);
memset(&counts, 0, sizeof(counts));
dbSize = sd->diskOffsetLimit(); // we do not care about the trailer waste
- dbEntrySize = sd->slotSize;
- dbEntryLimit = sd->entryLimit();
+ dbSlotSize = sd->slotSize;
+ dbEntryLimit = sd->entryLimitActual();
+ dbSlotLimit = sd->slotLimitActual();
+ assert(dbEntryLimit <= dbSlotLimit);
}
Rock::Rebuild::~Rebuild()
buf.init(SM_PAGE_SIZE, SM_PAGE_SIZE);
dbOffset = SwapDir::HeaderSize;
- loadingPos = 0;
- entries = new LoadingEntry[dbEntryLimit];
+ entries = new LoadingEntry[dbSlotLimit];
checkpoint();
}
bool
Rock::Rebuild::doneAll() const
{
- return dbOffset >= dbSize && validationPos >= dbEntryLimit &&
+ return loadingPos >= dbSlotLimit && validationPos >= dbSlotLimit &&
AsyncJob::doneAll();
}
void
Rock::Rebuild::steps()
{
- if (dbOffset < dbSize)
+ if (loadingPos < dbSlotLimit)
loadingSteps();
else
validationSteps();
const timeval loopStart = current_time;
int loaded = 0;
- while (loaded < dbEntryLimit && dbOffset < dbSize) {
+ while (loadingPos < dbSlotLimit) {
loadOneSlot();
- dbOffset += dbEntrySize;
+ dbOffset += dbSlotSize;
++loadingPos;
++loaded;
if (counts.scancount % 1000 == 0)
- storeRebuildProgress(sd->index, dbEntryLimit, counts.scancount);
+ storeRebuildProgress(sd->index, dbSlotLimit, counts.scancount);
if (opt_foreground_rebuild)
continue; // skip "few entries at a time" check below
freeSlotIfIdle(slotId, false);
return;
}
- if (!header.sane(dbEntrySize, dbEntryLimit)) {
+ if (!header.sane(dbSlotSize, dbSlotLimit)) {
debugs(47, DBG_IMPORTANT, "WARNING: cache_dir[" << sd->index << "]: " <<
"Ignoring malformed cache entry meta data at " << dbOffset);
freeSlotIfIdle(slotId, true);
const timeval loopStart = current_time;
int validated = 0;
- while (validationPos < dbEntryLimit) {
+ while (validationPos < dbSlotLimit) {
validateOneEntry();
++validationPos;
++validated;
LoadingEntry *entries; ///< store entries being loaded from disk
int64_t dbSize;
- int dbEntrySize;
- int dbEntryLimit;
+ int dbSlotSize; ///< the size of a db cell, including the cell header
+ int dbSlotLimit; ///< total number of db cells
+ int dbEntryLimit; ///< maximum number of entries that can be stored in db
int fd; // store db file descriptor
int64_t dbOffset;
#include <cstdlib>
#include <iomanip>
+#include <limits>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
}
int64_t
-Rock::SwapDir::entryLimitAllowed() const
+Rock::SwapDir::slotLimitAbsolute() const
{
- const int64_t eLimitLo = map ? map->entryLimit() : 0; // dynamic shrinking unsupported
- const int64_t eWanted = (maxSize() - HeaderSize)/slotSize;
- return min(max(eLimitLo, eWanted), entryLimitHigh());
+ // the max value is an invalid one; all values must be below the limit
+ assert(std::numeric_limits<Ipc::StoreMapSliceId>::max() ==
+ std::numeric_limits<SlotId>::max());
+ return std::numeric_limits<SlotId>::max();
+}
+
+int64_t
+Rock::SwapDir::slotLimitActual() const
+{
+ const int64_t sWanted = (maxSize() - HeaderSize)/slotSize;
+ const int64_t sLimitLo = map ? map->sliceLimit() : 0; // dynamic shrinking unsupported
+ const int64_t sLimitHi = slotLimitAbsolute();
+ return min(max(sLimitLo, sWanted), sLimitHi);
+}
+
+int64_t
+Rock::SwapDir::entryLimitActual() const
+{
+ return min(slotLimitActual(), entryLimitAbsolute());
}
// TODO: encapsulate as a tool
const int64_t slotSizeRoundingWaste = slotSize;
const int64_t maxRoundingWaste =
max(maxSizeRoundingWaste, slotSizeRoundingWaste);
- const int64_t usableDiskSize = diskOffset(entryLimitAllowed());
- const int64_t diskWasteSize = maxSize() - usableDiskSize;
- Must(diskWasteSize >= 0);
-
- // warn if maximum db size is not reachable due to sfileno limit
- if (entryLimitAllowed() == entryLimitHigh() &&
- diskWasteSize >= maxRoundingWaste) {
- debugs(47, DBG_CRITICAL, "Rock store cache_dir[" << index << "] '" << path << "':");
- debugs(47, DBG_CRITICAL, "\tmaximum number of entries: " << entryLimitAllowed());
- debugs(47, DBG_CRITICAL, "\tdb slot size: " << slotSize << " Bytes");
- debugs(47, DBG_CRITICAL, "\tmaximum db size: " << maxSize() << " Bytes");
- debugs(47, DBG_CRITICAL, "\tusable db size: " << usableDiskSize << " Bytes");
- debugs(47, DBG_CRITICAL, "\tdisk space waste: " << diskWasteSize << " Bytes");
- debugs(47, DBG_CRITICAL, "WARNING: Rock store config wastes space.");
+
+ // an entry consumes at least one slot; round up to reduce false warnings
+ const int64_t blockSize = static_cast<int64_t>(slotSize);
+ const int64_t maxObjSize = max(blockSize,
+ ((maxObjectSize()+blockSize-1)/blockSize)*blockSize);
+
+ // Does the "sfileno*max-size" limit match configured db capacity?
+ const double entriesMayOccupy = entryLimitAbsolute()*static_cast<double>(maxObjSize);
+ if (entriesMayOccupy + maxRoundingWaste < maxSize()) {
+ const int64_t diskWasteSize = maxSize() - static_cast<int64_t>(entriesMayOccupy);
+ debugs(47, DBG_CRITICAL, "WARNING: Rock cache_dir " << path << " wastes disk space due to entry limits:" <<
+ "\n\tconfigured db capacity: " << maxSize() << " bytes" <<
+ "\n\tconfigured db slot size: " << slotSize << " bytes" <<
+ "\n\tconfigured maximum entry size: " << maxObjectSize() << " bytes" <<
+ "\n\tmaximum number of cache_dir entries supported by Squid: " << entryLimitAbsolute() <<
+ "\n\tdisk space all entries may use: " << entriesMayOccupy << " bytes" <<
+ "\n\tdisk space wasted: " << diskWasteSize << " bytes");
+ }
+
+ // Does the "absolute slot count" limit match configured db capacity?
+ const double slotsMayOccupy = slotLimitAbsolute()*static_cast<double>(slotSize);
+ if (slotsMayOccupy + maxRoundingWaste < maxSize()) {
+ const int64_t diskWasteSize = maxSize() - static_cast<int64_t>(entriesMayOccupy);
+ debugs(47, DBG_CRITICAL, "WARNING: Rock cache_dir " << path << " wastes disk space due to slot limits:" <<
+ "\n\tconfigured db capacity: " << maxSize() << " bytes" <<
+ "\n\tconfigured db slot size: " << slotSize << " bytes" <<
+ "\n\tmaximum number of rock cache_dir slots supported by Squid: " << slotLimitAbsolute() <<
+ "\n\tdisk space all slots may use: " << slotsMayOccupy << " bytes" <<
+ "\n\tdisk space wasted: " << diskWasteSize << " bytes");
}
}
}
int64_t
-Rock::SwapDir::diskOffset(int filen) const
+Rock::SwapDir::diskOffset(const SlotId sid) const
{
- assert(filen >= 0);
- return HeaderSize + slotSize*filen;
+ assert(sid >= 0);
+ return HeaderSize + slotSize*sid;
}
int64_t
Rock::SwapDir::diskOffsetLimit() const
{
assert(map);
- return diskOffset(map->entryLimit());
-}
-
-int
-Rock::SwapDir::entryMaxPayloadSize() const
-{
- return slotSize - sizeof(DbCellHeader);
-}
-
-int
-Rock::SwapDir::entriesNeeded(const int64_t objSize) const
-{
- return (objSize + entryMaxPayloadSize() - 1) / entryMaxPayloadSize();
+ return diskOffset(map->sliceLimit());
}
bool
bool
Rock::SwapDir::validSlotId(const SlotId slotId) const
{
- return 0 <= slotId && slotId < entryLimitAllowed();
+ return 0 <= slotId && slotId < slotLimitActual();
}
void
-Rock::SwapDir::noteFreeMapSlice(const sfileno sliceId)
+Rock::SwapDir::noteFreeMapSlice(const Ipc::StoreMapSliceId sliceId)
{
Ipc::Mem::PageId pageId;
pageId.pool = index+1;
xstrerror());
debugs(47, 2, "Rock cache_dir[" << index << "] limits: " <<
- std::setw(12) << maxSize() << " disk bytes and " <<
- std::setw(7) << map->entryLimit() << " entries");
+ std::setw(12) << maxSize() << " disk bytes, " <<
+ std::setw(7) << map->entryLimit() << " entries, and " <<
+ std::setw(7) << map->sliceLimit() << " slots");
rebuild();
}
currentSize() / 1024.0,
Math::doublePercent(currentSize(), maxSize()));
- if (map) {
- const int limit = map->entryLimit();
- storeAppendPrintf(&e, "Maximum entries: %9d\n", limit);
- if (limit > 0) {
+ const int entryLimit = entryLimitActual();
+ const int slotLimit = slotLimitActual();
+ storeAppendPrintf(&e, "Maximum entries: %9d\n", entryLimit);
+ if (map && entryLimit > 0) {
const int entryCount = map->entryCount();
storeAppendPrintf(&e, "Current entries: %9d %.2f%%\n",
- entryCount, (100.0 * entryCount / limit));
+ entryCount, (100.0 * entryCount / entryLimit));
+ }
+ storeAppendPrintf(&e, "Maximum slots: %9d\n", slotLimit);
+ if (map && slotLimit > 0) {
const unsigned int slotsFree = !freeSlots ? 0 : freeSlots->size();
- if (slotsFree <= static_cast<const unsigned int>(limit)) {
- const int usedSlots = limit - static_cast<const int>(slotsFree);
+ if (slotsFree <= static_cast<const unsigned int>(slotLimit)) {
+ const int usedSlots = slotLimit - static_cast<const int>(slotsFree);
storeAppendPrintf(&e, "Used slots: %9d %.2f%%\n",
- usedSlots, (100.0 * usedSlots / limit));
+ usedSlots, (100.0 * usedSlots / slotLimit));
}
- if (limit < 100) { // XXX: otherwise too expensive to count
+ if (slotLimit < 100) { // XXX: otherwise too expensive to count
Ipc::ReadWriteLockStats stats;
map->updateStats(stats);
stats.dump(e);
}
- }
}
storeAppendPrintf(&e, "Pending operations: %d out of %d\n",
Must(mapOwners.empty() && freeSlotsOwners.empty());
for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (const Rock::SwapDir *const sd = dynamic_cast<Rock::SwapDir *>(INDEXSD(i))) {
- const int64_t capacity = sd->entryLimitAllowed();
+ const int64_t capacity = sd->slotLimitActual();
SwapDir::DirMap::Owner *const mapOwner =
SwapDir::DirMap::Init(sd->inodeMapPath(), capacity);
// temporary path to the shared memory stack of free slots
const char *freeSlotsPath() const;
- int64_t entryLimitHigh() const { return SwapFilenMax; } ///< Core limit
- int64_t entryLimitAllowed() const;
+ int64_t entryLimitAbsolute() const { return SwapFilenMax+1; } ///< Core limit
+ int64_t entryLimitActual() const; ///< max number of possible entries in db
+ int64_t slotLimitAbsolute() const; ///< Rock store implementation limit
+ int64_t slotLimitActual() const; ///< total number of slots in this db
/// removes a slot from a list of free slots or returns false
bool useFreeSlot(Ipc::Mem::PageId &pageId);
void writeError(StoreEntry &e);
/* StoreMapCleaner API */
- virtual void noteFreeMapSlice(const sfileno fileno);
+ virtual void noteFreeMapSlice(const Ipc::StoreMapSliceId fileno);
uint64_t slotSize; ///< all db slots are of this size
void ignoreReferences(StoreEntry &e); ///< delete from repl policy scope
int64_t diskOffsetLimit() const;
- int entryLimit() const { return map->entryLimit(); }
- int entryMaxPayloadSize() const;
- int entriesNeeded(const int64_t objSize) const;
void anchorEntry(StoreEntry &e, const sfileno filen, const Ipc::StoreMapAnchor &anchor);
bool updateCollapsedWith(StoreEntry &collapsed, const Ipc::StoreMapAnchor &anchor);
#include "tools.h"
Ipc::StoreMap::Owner *
-Ipc::StoreMap::Init(const char *const path, const int limit, const size_t extrasSize)
+Ipc::StoreMap::Init(const char *const path, const int slotLimit, const size_t extrasSize)
{
- assert(limit > 0); // we should not be created otherwise
- Owner *const owner = shm_new(Shared)(path, limit, extrasSize);
- debugs(54, 5, HERE << "new map [" << path << "] created: " << limit);
+ assert(slotLimit > 0); // we should not be created otherwise
+ Owner *const owner = shm_new(Shared)(path, slotLimit, extrasSize);
+ debugs(54, 5, HERE << "new map [" << path << "] created: " << slotLimit);
return owner;
}
Ipc::StoreMap::Owner *
-Ipc::StoreMap::Init(const char *const path, const int limit)
+Ipc::StoreMap::Init(const char *const path, const int slotLimit)
{
- return Init(path, limit, 0);
+ return Init(path, slotLimit, 0);
}
Ipc::StoreMap::StoreMap(const char *const aPath): cleaner(NULL), path(aPath),
shared(shm_old(Shared)(aPath))
{
- assert(shared->limit > 0); // we should not be created otherwise
+ assert(shared->slotLimit > 0); // we should not be created otherwise
debugs(54, 5, HERE << "attached map [" << path << "] created: " <<
- shared->limit);
+ shared->slotLimit);
}
int
Ipc::StoreMap::compareVersions(const sfileno fileno, time_t newVersion) const
{
- assert(valid(fileno));
+ assert(validEntry(fileno));
Anchor &inode = shared->slots[fileno].anchor;
// note: we do not lock, so comparison may be inacurate
void
Ipc::StoreMap::forgetWritingEntry(sfileno fileno)
{
- assert(valid(fileno));
+ assert(validEntry(fileno));
Anchor &inode = shared->slots[fileno].anchor;
assert(inode.writing());
inode.rewind();
inode.lock.unlockExclusive();
- --shared->count;
+ --shared->entryCount;
debugs(54, 8, "closed entry " << fileno << " for writing " << path);
}
assert(s.empty());
s.start = -1; // we have not allocated any slices yet
- ++shared->count;
+ ++shared->entryCount;
//s.setKey(key); // XXX: the caller should do that
debugs(54, 5, "opened entry " << fileno << " for writing " << path);
void
Ipc::StoreMap::startAppending(const sfileno fileno)
{
- assert(valid(fileno));
+ assert(validEntry(fileno));
Anchor &s = shared->slots[fileno].anchor;
assert(s.writing());
s.lock.startAppending();
void
Ipc::StoreMap::closeForWriting(const sfileno fileno, bool lockForReading)
{
- assert(valid(fileno));
+ assert(validEntry(fileno));
Anchor &s = shared->slots[fileno].anchor;
assert(s.writing());
if (lockForReading) {
Ipc::StoreMap::Slice &
Ipc::StoreMap::writeableSlice(const AnchorId anchorId, const SliceId sliceId)
{
- assert(valid(anchorId));
+ assert(validEntry(anchorId));
assert(shared->slots[anchorId].anchor.writing());
- assert(valid(sliceId));
+ assert(validSlice(sliceId));
return shared->slots[sliceId].slice;
}
const Ipc::StoreMap::Slice &
Ipc::StoreMap::readableSlice(const AnchorId anchorId, const SliceId sliceId) const
{
- assert(valid(anchorId));
+ assert(validEntry(anchorId));
assert(shared->slots[anchorId].anchor.reading());
- assert(valid(sliceId));
+ assert(validSlice(sliceId));
return shared->slots[sliceId].slice;
}
Ipc::StoreMap::Anchor &
Ipc::StoreMap::writeableEntry(const AnchorId anchorId)
{
- assert(valid(anchorId));
+ assert(validEntry(anchorId));
assert(shared->slots[anchorId].anchor.writing());
return shared->slots[anchorId].anchor;
}
const Ipc::StoreMap::Anchor &
Ipc::StoreMap::readableEntry(const AnchorId anchorId) const
{
- assert(valid(anchorId));
+ assert(validEntry(anchorId));
assert(shared->slots[anchorId].anchor.reading());
return shared->slots[anchorId].anchor;
}
Ipc::StoreMap::abortWriting(const sfileno fileno)
{
debugs(54, 5, "aborting entry " << fileno << " for writing " << path);
- assert(valid(fileno));
+ assert(validEntry(fileno));
Anchor &s = shared->slots[fileno].anchor;
assert(s.writing());
s.lock.appending = false; // locks out any new readers
const Ipc::StoreMap::Anchor *
Ipc::StoreMap::peekAtReader(const sfileno fileno) const
{
- assert(valid(fileno));
+ assert(validEntry(fileno));
const Anchor &s = shared->slots[fileno].anchor;
if (s.reading())
return &s; // immediate access by lock holder so no locking
const Ipc::StoreMap::Anchor &
Ipc::StoreMap::peekAtEntry(const sfileno fileno) const
{
- assert(valid(fileno));
+ assert(validEntry(fileno));
return shared->slots[fileno].anchor;
}
{
debugs(54, 5, "marking entry " << fileno << " to be freed in " << path);
- assert(valid(fileno));
+ assert(validEntry(fileno));
Anchor &s = shared->slots[fileno].anchor;
if (s.lock.lockExclusive())
if (!keepLocked)
inode.lock.unlockExclusive();
- --shared->count;
+ --shared->entryCount;
debugs(54, 5, "freed entry " << fileno << " in " << path);
}
Ipc::StoreMap::openForReadingAt(const sfileno fileno)
{
debugs(54, 5, "opening entry " << fileno << " for reading " << path);
- assert(valid(fileno));
+ assert(validEntry(fileno));
Anchor &s = shared->slots[fileno].anchor;
if (!s.lock.lockShared()) {
void
Ipc::StoreMap::closeForReading(const sfileno fileno)
{
- assert(valid(fileno));
+ assert(validEntry(fileno));
Anchor &s = shared->slots[fileno].anchor;
assert(s.reading());
s.lock.unlockShared();
const int searchLimit = min(10000, entryLimit());
int tries = 0;
for (; tries < searchLimit; ++tries) {
- const sfileno fileno = static_cast<sfileno>(++shared->victim % shared->limit);
- assert(valid(fileno));
+ const sfileno fileno = static_cast<sfileno>(++shared->victim % entryLimit());
+ assert(validEntry(fileno));
Anchor &s = shared->slots[fileno].anchor;
if (s.lock.lockExclusive()) {
// the caller wants a free slice; empty anchor is not enough
// "get free slice" API. This is not something we can double check
// reliably because the anchor for the imported slice may not have been
// imported yet.
- assert(valid(sliceId));
+ assert(validSlice(sliceId));
shared->slots[sliceId].slice = slice;
}
int
Ipc::StoreMap::entryLimit() const
{
- return shared->limit;
+ return min(sliceLimit(), static_cast<int>(SwapFilenMax+1));
}
int
Ipc::StoreMap::entryCount() const
{
- return shared->count;
+ return shared->entryCount;
+}
+
+int
+Ipc::StoreMap::sliceLimit() const
+{
+ return shared->slotLimit;
}
void
Ipc::StoreMap::updateStats(ReadWriteLockStats &stats) const
{
- for (int i = 0; i < shared->limit; ++i)
+ for (int i = 0; i < shared->slotLimit; ++i)
shared->slots[i].anchor.lock.updateStats(stats);
}
bool
-Ipc::StoreMap::valid(const int pos) const
+Ipc::StoreMap::validEntry(const int pos) const
{
return 0 <= pos && pos < entryLimit();
}
+bool
+Ipc::StoreMap::validSlice(const int pos) const
+{
+ return 0 <= pos && pos < sliceLimit();
+}
+
sfileno
Ipc::StoreMap::anchorIndexByKey(const cache_key *const key) const
{
const uint64_t *const k = reinterpret_cast<const uint64_t *>(key);
// TODO: use a better hash function
- return (k[0] + k[1]) % shared->limit;
+ return (k[0] + k[1]) % entryLimit();
}
Ipc::StoreMap::Anchor &
/* Ipc::StoreMap::Shared */
-Ipc::StoreMap::Shared::Shared(const int aLimit, const size_t anExtrasSize):
- limit(aLimit), extrasSize(anExtrasSize), count(0), victim(0),
- slots(aLimit)
+Ipc::StoreMap::Shared::Shared(const int aSlotLimit, const size_t anExtrasSize):
+ slotLimit(aSlotLimit), extrasSize(anExtrasSize), entryCount(0),
+ victim(0),
+ slots(aSlotLimit)
{
}
size_t
Ipc::StoreMap::Shared::sharedMemorySize() const
{
- return SharedMemorySize(limit, extrasSize);
+ return SharedMemorySize(slotLimit, extrasSize);
}
size_t
-Ipc::StoreMap::Shared::SharedMemorySize(const int limit, const size_t extrasSize)
+Ipc::StoreMap::Shared::SharedMemorySize(const int slotLimit, const size_t extrasSize)
{
- return sizeof(Shared) + limit * (sizeof(StoreMapSlot) + extrasSize);
+ return sizeof(Shared) + slotLimit * (sizeof(StoreMapSlot) + extrasSize);
}
class Shared
{
public:
- Shared(const int aLimit, const size_t anExtrasSize);
+ Shared(const int aSlotLimit, const size_t anExtrasSize);
size_t sharedMemorySize() const;
- static size_t SharedMemorySize(const int limit, const size_t anExtrasSize);
+ static size_t SharedMemorySize(const int aSlotLimit, const size_t anExtrasSize);
- const int limit; ///< maximum number of store entries
- const size_t extrasSize; ///< size of slice extra data
- Atomic::Word count; ///< current number of entries
+ const int slotLimit; ///< total number of slots
+ const size_t extrasSize; ///< size of extra data in each slot
+ Atomic::Word entryCount; ///< current number of entries
Atomic::WordT<uint32_t> victim; ///< starting point for purge search
Ipc::Mem::FlexibleArray<StoreMapSlot> slots; ///< storage
};
typedef Mem::Owner<Shared> Owner;
/// initialize shared memory
- static Owner *Init(const char *const path, const int limit);
+ static Owner *Init(const char *const path, const int slotLimit);
StoreMap(const char *const aPath);
/// copies slice to its designated position
void importSlice(const SliceId sliceId, const Slice &slice);
- bool valid(const int n) const; ///< whether n is a valid slice coordinate
+ /* SwapFilenMax limits the number of entries, but not slices or slots */
+ bool validEntry(const int n) const; ///< whether n is a valid slice coordinate
+ bool validSlice(const int n) const; ///< whether n is a valid slice coordinate
int entryCount() const; ///< number of writeable and readable entries
int entryLimit() const; ///< maximum entryCount() possible
+ int sliceLimit() const; ///< maximum number of slices possible
/// adds approximate current stats to the supplied ones
void updateStats(ReadWriteLockStats &stats) const;
StoreMapWithExtras(const char *const path);
/// write access to the extras; call openForWriting() first!
- ExtrasT &extras(const sfileno fileno);
+ ExtrasT &extras(const StoreMapSliceId sid);
/// read-only access to the extras; call openForReading() first!
- const ExtrasT &extras(const sfileno fileno) const;
+ const ExtrasT &extras(const StoreMapSliceId sid) const;
protected:
virtual ~StoreMapCleaner() {}
/// adjust slice-linked state before a locked Readable slice is erased
- virtual void noteFreeMapSlice(const sfileno sliceId) = 0;
+ virtual void noteFreeMapSlice(const StoreMapSliceId sliceId) = 0;
};
// StoreMapWithExtras implementation
StoreMap(aPath)
{
const size_t sharedSizeWithoutExtras =
- Shared::SharedMemorySize(entryLimit(), 0);
+ Shared::SharedMemorySize(sliceLimit(), 0);
sharedExtras = reinterpret_cast<Extras *>(reinterpret_cast<char *>(shared.getRaw()) + sharedSizeWithoutExtras);
}
template <class ExtrasT>
ExtrasT &
-StoreMapWithExtras<ExtrasT>::extras(const sfileno fileno)
+StoreMapWithExtras<ExtrasT>::extras(const StoreMapSliceId sid)
{
- return const_cast<ExtrasT &>(const_cast<const StoreMapWithExtras *>(this)->extras(fileno));
+ return const_cast<ExtrasT &>(const_cast<const StoreMapWithExtras *>(this)->extras(sid));
}
template <class ExtrasT>
const ExtrasT &
-StoreMapWithExtras<ExtrasT>::extras(const sfileno fileno) const
+StoreMapWithExtras<ExtrasT>::extras(const StoreMapSliceId sid) const
{
assert(sharedExtras);
- assert(valid(fileno));
- return sharedExtras[fileno];
+ assert(validSlice(sid));
+ return sharedExtras[sid];
}
} // namespace Ipc
void MemStore::disconnect(StoreEntry &e) STUB
void MemStore::reference(StoreEntry &) STUB
void MemStore::maintain() STUB
-void MemStore::noteFreeMapSlice(const sfileno) STUB
+void MemStore::noteFreeMapSlice(const Ipc::StoreMapSliceId) STUB
void MemStore::get(String const, STOREGETCLIENT, void *) STUB
void MemStore::init() STUB
void MemStore::getStats(StoreInfoStats&) const STUB