const int64_t entrySize = Ipc::Mem::PageSize(); // for now
const int64_t entryCount = Config.memMaxSize / entrySize;
// TODO: warn if we cannot cache at least one item (misconfiguration)
- if (entryCount > 0)
+ if (entryCount > 0) {
map = new MemStoreMap("cache_mem", entryCount);
+ map->cleaner = this;
+ }
}
}
extras.storedSize = copied;
return true;
}
+
+void
+MemStore::cleanReadable(const sfileno fileno)
+{
+ Ipc::Mem::PutPage(map->extras(fileno).page);
+}
+
/// Stores HTTP entities in RAM. Current implementation uses shared memory.
/// Unlike a disk store (SwapDir), operations are synchronous (and fast).
-class MemStore: public Store {
+class MemStore: public Store, public Ipc::StoreMapCleaner {
public:
MemStore();
virtual ~MemStore();
bool copyToShm(StoreEntry &e, MemStoreMap::Extras &extras);
bool copyFromShm(StoreEntry &e, const MemStoreMap::Extras &extras);
+ // Ipc::StoreMapCleaner API
+ virtual void cleanReadable(const sfileno fileno);
+
private:
MemStoreMap *map; ///< index of mem-cached entries
};
Ipc::StoreMap::StoreMap(const char *const aPath, const int limit,
size_t sharedSizeExtra):
- path(aPath), shm(aPath), shared(NULL)
+ cleaner(NULL), path(aPath), shm(aPath), shared(NULL)
{
const size_t mySharedSize = Shared::MemSize(limit);
shm.create(mySharedSize + sharedSizeExtra);
}
Ipc::StoreMap::StoreMap(const char *const aPath):
- path(aPath), shm(aPath), shared(NULL)
+ cleaner(NULL), path(aPath), shm(aPath), shared(NULL)
{
shm.open();
assert(shm.mem());
if (lock.lockExclusive()) {
assert(s.state != Slot::Writeable); // until we start breaking locks
- // free if the entry was dirty, keeping the entry locked
- if (s.waitingToBeFreed == true)
+ // free if the entry was used, keeping the entry locked
+ if (s.waitingToBeFreed == true || s.state == Slot::Readable)
freeLocked(s, true);
- if (s.state == Slot::Empty) // we may also overwrite a Readable slot
- ++shared->count;
+ assert(s.state == Slot::Empty);
+ ++shared->count;
s.state = Slot::Writeable;
fileno = idx;
//s.setKey(key); // XXX: the caller should do that
void
Ipc::StoreMap::freeLocked(Slot &s, bool keepLocked)
{
+ if (s.state == Slot::Readable && cleaner)
+ cleaner->cleanReadable(&s - shared->slots);
+
s.waitingToBeFreed = false;
s.state = Slot::Empty;
if (!keepLocked)
#include "ipc/ReadWriteLock.h"
#include "ipc/mem/Segment.h"
+#include "typedefs.h"
namespace Ipc {
State state; ///< current state
};
+class StoreMapCleaner;
+
/// map of StoreMapSlots indexed by their keys, with read/write slot locking
/// kids extend to store custom data
class StoreMap
/// adds approximate current stats to the supplied ones
void updateStats(ReadWriteLockStats &stats) const;
+ StoreMapCleaner *cleaner; ///< notified before a readable entry is freed
+
protected:
class Shared {
public:
Shared *shared; ///< pointer to shared memory
};
+/// API for adjusting external state when dirty map slot is being freed
+class StoreMapCleaner
+{
+public:
+ virtual ~StoreMapCleaner() {}
+
+ /// adjust slot-linked state before a locked Readable slot is erased
+ virtual void cleanReadable(const sfileno fileno) = 0;
+};
+
+
} // namespace Ipc
// We do not reuse struct _fileMap because we cannot control its size,