From ca9f3fe2e6e19b35fc4e822df0606a0a374a2d4b Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Mon, 5 Oct 2015 03:45:00 +0200 Subject: [PATCH] Introduce Blob::readAll() and introduce a size cache so the blob size doesn't have to be queried so often --- implementations/onblocks/BlobOnBlocks.cpp | 35 ++++++++++++++++++----- implementations/onblocks/BlobOnBlocks.h | 4 +++ interface/Blob.h | 2 ++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/implementations/onblocks/BlobOnBlocks.cpp b/implementations/onblocks/BlobOnBlocks.cpp index cc57dd3d..7d643cb9 100644 --- a/implementations/onblocks/BlobOnBlocks.cpp +++ b/implementations/onblocks/BlobOnBlocks.cpp @@ -8,6 +8,7 @@ using std::function; using cpputils::unique_ref; +using cpputils::Data; using blobstore::onblocks::datanodestore::DataLeafNode; using blobstore::onblocks::datanodestore::DataNodeLayout; using blockstore::Key; @@ -18,18 +19,22 @@ namespace onblocks { using parallelaccessdatatreestore::DataTreeRef; BlobOnBlocks::BlobOnBlocks(unique_ref datatree) -: _datatree(std::move(datatree)) { +: _datatree(std::move(datatree)), _sizeCache(boost::none) { } BlobOnBlocks::~BlobOnBlocks() { } uint64_t BlobOnBlocks::size() const { - return _datatree->numStoredBytes(); + if (_sizeCache == boost::none) { + _sizeCache = _datatree->numStoredBytes(); + } + return *_sizeCache; } void BlobOnBlocks::resize(uint64_t numBytes) { _datatree->resizeNumBytes(numBytes); + _sizeCache = numBytes; } void BlobOnBlocks::traverseLeaves(uint64_t beginByte, uint64_t sizeBytes, function func) const { @@ -47,10 +52,22 @@ void BlobOnBlocks::traverseLeaves(uint64_t beginByte, uint64_t sizeBytes, functi } func(indexOfFirstLeafByte, leaf, dataBegin, dataEnd-dataBegin); }); + if (writingOutside) { + //ASSERT(_datatree->numStoredBytes() == endByte, "Writing didn't grow by the correct number of bytes"); + _sizeCache = endByte; + } +} + +Data BlobOnBlocks::readAll() const { + //TODO Querying size is inefficient. Is this possible without numStoredBytes()? + uint64_t count = size(); + Data result(count); + _read(result.data(), 0, count); + return result; } void BlobOnBlocks::read(void *target, uint64_t offset, uint64_t count) const { - ASSERT(offset <= _datatree->numStoredBytes() && offset + count <= size(), "BlobOnBlocks::read() read outside blob. Use BlobOnBlocks::tryRead() if this should be allowed."); + ASSERT(offset <= size() && offset + count <= size(), "BlobOnBlocks::read() read outside blob. Use BlobOnBlocks::tryRead() if this should be allowed."); uint64_t read = tryRead(target, offset, count); ASSERT(read == count, "BlobOnBlocks::read() couldn't read all requested bytes. Use BlobOnBlocks::tryRead() if this should be allowed."); } @@ -58,13 +75,17 @@ void BlobOnBlocks::read(void *target, uint64_t offset, uint64_t count) const { uint64_t BlobOnBlocks::tryRead(void *target, uint64_t offset, uint64_t count) const { //TODO Quite inefficient to call size() here, because that has to traverse the tree uint64_t realCount = std::max(UINT64_C(0), std::min(count, size()-offset)); - traverseLeaves(offset, realCount, [target, offset] (uint64_t indexOfFirstLeafByte, const DataLeafNode *leaf, uint32_t leafDataOffset, uint32_t leafDataSize) { - //TODO Simplify formula, make it easier to understand - leaf->read((uint8_t*)target + indexOfFirstLeafByte - offset + leafDataOffset, leafDataOffset, leafDataSize); - }); + _read(target, offset, realCount); return realCount; } +void BlobOnBlocks::_read(void *target, uint64_t offset, uint64_t count) const { + traverseLeaves(offset, count, [target, offset] (uint64_t indexOfFirstLeafByte, const DataLeafNode *leaf, uint32_t leafDataOffset, uint32_t leafDataSize) { + //TODO Simplify formula, make it easier to understand + leaf->read((uint8_t*)target + indexOfFirstLeafByte - offset + leafDataOffset, leafDataOffset, leafDataSize); + }); +} + void BlobOnBlocks::write(const void *source, uint64_t offset, uint64_t count) { traverseLeaves(offset, count, [source, offset] (uint64_t indexOfFirstLeafByte, DataLeafNode *leaf, uint32_t leafDataOffset, uint32_t leafDataSize) { //TODO Simplify formula, make it easier to understand diff --git a/implementations/onblocks/BlobOnBlocks.h b/implementations/onblocks/BlobOnBlocks.h index db609dab..0d3b9622 100644 --- a/implementations/onblocks/BlobOnBlocks.h +++ b/implementations/onblocks/BlobOnBlocks.h @@ -5,6 +5,7 @@ #include "../../interface/Blob.h" #include +#include namespace blobstore { namespace onblocks { @@ -25,6 +26,7 @@ public: uint64_t size() const override; void resize(uint64_t numBytes) override; + cpputils::Data readAll() const override; void read(void *target, uint64_t offset, uint64_t size) const override; uint64_t tryRead(void *target, uint64_t offset, uint64_t size) const override; void write(const void *source, uint64_t offset, uint64_t size) override; @@ -35,9 +37,11 @@ public: private: + void _read(void *target, uint64_t offset, uint64_t count) const; void traverseLeaves(uint64_t offsetBytes, uint64_t sizeBytes, std::function) const; cpputils::unique_ref _datatree; + mutable boost::optional _sizeCache; }; } diff --git a/interface/Blob.h b/interface/Blob.h index 4f832e4d..1b75fcb1 100644 --- a/interface/Blob.h +++ b/interface/Blob.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace blobstore { @@ -18,6 +19,7 @@ public: virtual uint64_t size() const = 0; virtual void resize(uint64_t numBytes) = 0; + virtual cpputils::Data readAll() const = 0; virtual void read(void *target, uint64_t offset, uint64_t size) const = 0; virtual uint64_t tryRead(void *target, uint64_t offset, uint64_t size) const = 0; virtual void write(const void *source, uint64_t offset, uint64_t size) = 0;