Caching blocks works

This commit is contained in:
Sebastian Messmer 2015-04-15 20:39:58 +02:00
parent 332f6901ef
commit b185729113
9 changed files with 110 additions and 23 deletions

View File

@ -19,31 +19,23 @@ Cache::~Cache() {
unique_ptr<Block> Cache::pop(const Key &key) {
lock_guard<mutex> lock(_mutex);
auto found = _cachedBlocks.find(key);
if (found == _cachedBlocks.end()) {
auto found = _cachedBlocks.pop(key);
if (found.get() == nullptr) {
return nullptr;
}
auto block = found->second.releaseBlock();
_cachedBlocks.erase(found);
auto block = found->releaseBlock();
return block;
}
void Cache::push(unique_ptr<Block> block) {
lock_guard<mutex> lock(_mutex);
if (_cachedBlocks.size() > MAX_ENTRIES) {
deleteOldestEntry();
assert(_cachedBlocks.size() <= MAX_ENTRIES);
if (_cachedBlocks.size() == MAX_ENTRIES) {
_cachedBlocks.pop();
assert(_cachedBlocks.size() == MAX_ENTRIES-1);
}
Key key = block->key();
_cachedBlocks.emplace(key, std::move(block));
}
void Cache::deleteOldestEntry() {
auto oldestEntry = std::min_element(_cachedBlocks.begin(), _cachedBlocks.end(), [] (const pair<const Key, CacheEntry> &lhs, const pair<const Key, CacheEntry> &rhs) {
return lhs.second.ageSeconds() > rhs.second.ageSeconds();
});
//printf("Deleting age %f (vs %f)\n", oldestEntry->second.ageSeconds(), _cachedBlocks.begin()->second.ageSeconds());
_cachedBlocks.erase(oldestEntry);
_cachedBlocks.push(key, make_unique<CacheEntry>(std::move(block)));
}
}

View File

@ -4,12 +4,16 @@
#include "../../interface/Block.h"
#include "CacheEntry.h"
#include "QueueMap.h"
#include <memory>
#include <mutex>
namespace blockstore {
namespace caching2 {
//TODO Test
//TODO Also throw blocks out after a timeout
class Cache {
public:
static constexpr uint32_t MAX_ENTRIES = 1000;
@ -22,9 +26,7 @@ public:
private:
mutable std::mutex _mutex;
std::map<Key, CacheEntry> _cachedBlocks;
void deleteOldestEntry();
QueueMap<Key, CacheEntry> _cachedBlocks;
};
}

View File

@ -25,9 +25,18 @@ public:
return std::move(_block);
}
void setNextEntry(const CacheEntry *entry) {
_nextEntry = entry;
}
const CacheEntry *nextEntry() {
return _nextEntry;
}
private:
time_t _lastAccess;
std::unique_ptr<Block> _block;
const CacheEntry *_nextEntry;
DISALLOW_COPY_AND_ASSIGN(CacheEntry);
};

View File

@ -1,6 +1,7 @@
#include "CachedBlock.h"
#include "Caching2BlockStore.h"
using std::unique_ptr;
using std::make_unique;
namespace blockstore {
@ -13,7 +14,9 @@ CachedBlock::CachedBlock(std::unique_ptr<Block> baseBlock, Caching2BlockStore *b
}
CachedBlock::~CachedBlock() {
_blockStore->release(std::move(_baseBlock));
if (_baseBlock.get() != nullptr) {
_blockStore->release(std::move(_baseBlock));
}
}
const void *CachedBlock::data() const {
@ -32,5 +35,9 @@ size_t CachedBlock::size() const {
return _baseBlock->size();
}
unique_ptr<Block> CachedBlock::releaseBlock() {
return std::move(_baseBlock);
}
}
}

View File

@ -23,6 +23,9 @@ public:
size_t size() const override;
bool alreadyExistsInBaseStore();
std::unique_ptr<Block> releaseBlock();
private:
Caching2BlockStore *_blockStore;
std::unique_ptr<Block> _baseBlock;

View File

@ -3,9 +3,11 @@
#include "../../interface/Block.h"
#include <algorithm>
#include <messmer/cpp-utils/pointer.h>
using std::unique_ptr;
using std::make_unique;
using cpputils::dynamic_pointer_move;
namespace blockstore {
namespace caching2 {
@ -27,11 +29,15 @@ unique_ptr<Block> Caching2BlockStore::load(const Key &key) {
if (block.get() != nullptr) {
return make_unique<CachedBlock>(std::move(block), this);
}
return make_unique<CachedBlock>(_baseBlockStore->load(key), this);
block = _baseBlockStore->load(key);
if (block.get() == nullptr) {
return nullptr;
}
return make_unique<CachedBlock>(std::move(block), this);
}
void Caching2BlockStore::remove(std::unique_ptr<Block> block) {
return _baseBlockStore->remove(std::move(block));
return _baseBlockStore->remove(std::move(dynamic_pointer_move<CachedBlock>(block)->releaseBlock()));
}
uint64_t Caching2BlockStore::numBlocks() const {

View File

@ -0,0 +1 @@
#include "QueueMap.h"

View File

@ -0,0 +1,68 @@
#pragma once
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_CACHING2_MAP_H_
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_CACHING2_MAP_H_
#include <memory>
#include <map>
namespace blockstore {
namespace caching2 {
//TODO Test
template<class Key, class Value>
class QueueMap {
public:
QueueMap(): _entries(), _sentinel(Key(), nullptr, &_sentinel, &_sentinel) {
}
virtual ~QueueMap() {}
void push(const Key &key, std::unique_ptr<Value> value) {
auto newEntry = std::make_unique<Entry>(key, std::move(value), _sentinel.prev, &_sentinel);
_sentinel.prev->next = newEntry.get();
_sentinel.prev = newEntry.get();
auto insertResult = _entries.emplace(key, std::move(newEntry));
assert(insertResult.second == true);
}
std::unique_ptr<Value> pop(const Key &key) {
auto found = _entries.find(key);
if (found == _entries.end()) {
return nullptr;
}
_removeFromQueue(found->second.get());
auto value = std::move(found->second->value);
_entries.erase(found);
return value;
}
std::unique_ptr<Value> pop() {
return pop(_sentinel.next->key);
}
uint32_t size() {
return _entries.size();
}
private:
struct Entry {
Entry(const Key &key_, std::unique_ptr<Value> value_, Entry *prev_, Entry *next_): key(key_), value(std::move(value_)), prev(prev_), next(next_) {}
Key key;
std::unique_ptr<Value> value;
Entry *prev;
Entry *next;
};
void _removeFromQueue(Entry *entry) {
entry->prev->next = entry->next;
entry->next->prev = entry->prev;
}
//TODO Double indirection unique_ptr<Entry> and Entry has unique_ptr<Value>. Necessary?
std::map<Key, std::unique_ptr<Entry>> _entries;
Entry _sentinel;
};
}
}
#endif

View File

@ -12,6 +12,7 @@ namespace blockstore {
template<int SIZE>
class FixedSizeData {
public:
FixedSizeData() {}
//Non-virtual destructor because we want objects to be small
~FixedSizeData() {}
@ -29,8 +30,6 @@ public:
const unsigned char *data() const;
private:
FixedSizeData() {}
static CryptoPP::AutoSeededRandomPool &RandomPool();
unsigned char _data[BINARY_LENGTH];