From b18572911379e1e6e9c3c87c94e5a5a315c0885c Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Wed, 15 Apr 2015 20:39:58 +0200 Subject: [PATCH] Caching blocks works --- implementations/caching2/Cache.cpp | 22 ++---- implementations/caching2/Cache.h | 8 ++- implementations/caching2/CacheEntry.h | 9 +++ implementations/caching2/CachedBlock.cpp | 9 ++- implementations/caching2/CachedBlock.h | 3 + .../caching2/Caching2BlockStore.cpp | 10 ++- implementations/caching2/QueueMap.cpp | 1 + implementations/caching2/QueueMap.h | 68 +++++++++++++++++++ utils/FixedSizeData.h | 3 +- 9 files changed, 110 insertions(+), 23 deletions(-) create mode 100644 implementations/caching2/QueueMap.cpp create mode 100644 implementations/caching2/QueueMap.h diff --git a/implementations/caching2/Cache.cpp b/implementations/caching2/Cache.cpp index 113b002c..e971c588 100644 --- a/implementations/caching2/Cache.cpp +++ b/implementations/caching2/Cache.cpp @@ -19,31 +19,23 @@ Cache::~Cache() { unique_ptr Cache::pop(const Key &key) { lock_guard 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) { lock_guard 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 &lhs, const pair &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(std::move(block))); } } diff --git a/implementations/caching2/Cache.h b/implementations/caching2/Cache.h index 52e10fda..1fc18f5b 100644 --- a/implementations/caching2/Cache.h +++ b/implementations/caching2/Cache.h @@ -4,12 +4,16 @@ #include "../../interface/Block.h" #include "CacheEntry.h" +#include "QueueMap.h" #include #include 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 _cachedBlocks; - - void deleteOldestEntry(); + QueueMap _cachedBlocks; }; } diff --git a/implementations/caching2/CacheEntry.h b/implementations/caching2/CacheEntry.h index 8b1a0f89..4b27b741 100644 --- a/implementations/caching2/CacheEntry.h +++ b/implementations/caching2/CacheEntry.h @@ -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; + const CacheEntry *_nextEntry; DISALLOW_COPY_AND_ASSIGN(CacheEntry); }; diff --git a/implementations/caching2/CachedBlock.cpp b/implementations/caching2/CachedBlock.cpp index fc02b5ca..b69846fb 100644 --- a/implementations/caching2/CachedBlock.cpp +++ b/implementations/caching2/CachedBlock.cpp @@ -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 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 CachedBlock::releaseBlock() { + return std::move(_baseBlock); +} + } } diff --git a/implementations/caching2/CachedBlock.h b/implementations/caching2/CachedBlock.h index 01a5a5b9..d6595132 100644 --- a/implementations/caching2/CachedBlock.h +++ b/implementations/caching2/CachedBlock.h @@ -23,6 +23,9 @@ public: size_t size() const override; + bool alreadyExistsInBaseStore(); + std::unique_ptr releaseBlock(); + private: Caching2BlockStore *_blockStore; std::unique_ptr _baseBlock; diff --git a/implementations/caching2/Caching2BlockStore.cpp b/implementations/caching2/Caching2BlockStore.cpp index 30e44816..bf3e34dc 100644 --- a/implementations/caching2/Caching2BlockStore.cpp +++ b/implementations/caching2/Caching2BlockStore.cpp @@ -3,9 +3,11 @@ #include "../../interface/Block.h" #include +#include using std::unique_ptr; using std::make_unique; +using cpputils::dynamic_pointer_move; namespace blockstore { namespace caching2 { @@ -27,11 +29,15 @@ unique_ptr Caching2BlockStore::load(const Key &key) { if (block.get() != nullptr) { return make_unique(std::move(block), this); } - return make_unique(_baseBlockStore->load(key), this); + block = _baseBlockStore->load(key); + if (block.get() == nullptr) { + return nullptr; + } + return make_unique(std::move(block), this); } void Caching2BlockStore::remove(std::unique_ptr block) { - return _baseBlockStore->remove(std::move(block)); + return _baseBlockStore->remove(std::move(dynamic_pointer_move(block)->releaseBlock())); } uint64_t Caching2BlockStore::numBlocks() const { diff --git a/implementations/caching2/QueueMap.cpp b/implementations/caching2/QueueMap.cpp new file mode 100644 index 00000000..510d8ece --- /dev/null +++ b/implementations/caching2/QueueMap.cpp @@ -0,0 +1 @@ +#include "QueueMap.h" diff --git a/implementations/caching2/QueueMap.h b/implementations/caching2/QueueMap.h new file mode 100644 index 00000000..0f490fed --- /dev/null +++ b/implementations/caching2/QueueMap.h @@ -0,0 +1,68 @@ +#pragma once +#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_CACHING2_MAP_H_ +#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_CACHING2_MAP_H_ + +#include +#include + +namespace blockstore { +namespace caching2 { + +//TODO Test +template +class QueueMap { +public: + QueueMap(): _entries(), _sentinel(Key(), nullptr, &_sentinel, &_sentinel) { + } + virtual ~QueueMap() {} + + void push(const Key &key, std::unique_ptr value) { + auto newEntry = std::make_unique(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 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 pop() { + return pop(_sentinel.next->key); + } + + uint32_t size() { + return _entries.size(); + } + +private: + struct Entry { + Entry(const Key &key_, std::unique_ptr value_, Entry *prev_, Entry *next_): key(key_), value(std::move(value_)), prev(prev_), next(next_) {} + Key key; + std::unique_ptr value; + Entry *prev; + Entry *next; + }; + + void _removeFromQueue(Entry *entry) { + entry->prev->next = entry->next; + entry->next->prev = entry->prev; + } + + //TODO Double indirection unique_ptr and Entry has unique_ptr. Necessary? + std::map> _entries; + Entry _sentinel; +}; + +} +} + +#endif diff --git a/utils/FixedSizeData.h b/utils/FixedSizeData.h index 9c62b5e4..2833c836 100644 --- a/utils/FixedSizeData.h +++ b/utils/FixedSizeData.h @@ -12,6 +12,7 @@ namespace blockstore { template 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];