#include "CachedBlock.h" #include "NewBlock.h" #include "CachingBlockStore.h" #include "../../interface/Block.h" #include #include #include using cpputils::dynamic_pointer_move; using cpputils::Data; using boost::optional; using cpputils::unique_ref; using cpputils::make_unique_ref; using boost::none; namespace blockstore { namespace caching { CachingBlockStore::CachingBlockStore(cpputils::unique_ref baseBlockStore) :_baseBlockStore(std::move(baseBlockStore)), _cache(), _numNewBlocks(0) { } Key CachingBlockStore::createKey() { return _baseBlockStore->createKey(); } optional> CachingBlockStore::tryCreate(const Key &key, Data data) { ASSERT(_cache.pop(key) == none, "Key already exists in cache"); //TODO Shouldn't we return boost::none if the key already exists? //TODO Key can also already exist but not be in the cache right now. ++_numNewBlocks; return unique_ref(make_unique_ref(make_unique_ref(key, std::move(data), this), this)); } optional> CachingBlockStore::load(const Key &key) { optional> optBlock = _cache.pop(key); //TODO an optional<> class with .getOrElse() would make this code simpler. boost::optional<>::value_or_eval didn't seem to work with unique_ptr members. if (optBlock != none) { return optional>(make_unique_ref(std::move(*optBlock), this)); } else { auto block = _baseBlockStore->load(key); if (block == none) { return none; } else { return optional>(make_unique_ref(std::move(*block), this)); } } } void CachingBlockStore::remove(cpputils::unique_ref block) { auto cached_block = dynamic_pointer_move(block); ASSERT(cached_block != none, "Passed block is not a CachedBlock"); auto baseBlock = (*cached_block)->releaseBlock(); auto baseNewBlock = dynamic_pointer_move(baseBlock); if (baseNewBlock != none) { if(!(*baseNewBlock)->alreadyExistsInBaseStore()) { --_numNewBlocks; } (*baseNewBlock)->remove(); } else { _baseBlockStore->remove(std::move(baseBlock)); } } uint64_t CachingBlockStore::numBlocks() const { return _baseBlockStore->numBlocks() + _numNewBlocks; } void CachingBlockStore::release(unique_ref block) { Key key = block->key(); _cache.push(key, std::move(block)); } optional> CachingBlockStore::tryCreateInBaseStore(const Key &key, Data data) { auto block = _baseBlockStore->tryCreate(key, std::move(data)); if (block != none) { --_numNewBlocks; } return block; } void CachingBlockStore::removeFromBaseStore(cpputils::unique_ref block) { _baseBlockStore->remove(std::move(block)); } void CachingBlockStore::flush() { _cache.flush(); } } }