Caching blocks works
This commit is contained in:
parent
332f6901ef
commit
b185729113
@ -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)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
1
implementations/caching2/QueueMap.cpp
Normal file
1
implementations/caching2/QueueMap.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "QueueMap.h"
|
68
implementations/caching2/QueueMap.h
Normal file
68
implementations/caching2/QueueMap.h
Normal 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
|
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user