Add Blob::numNodes()

This commit is contained in:
Sebastian Messmer 2019-01-22 01:09:06 -08:00
parent 525c6618db
commit 8a5091b8a2
8 changed files with 46 additions and 1 deletions

View File

@ -52,6 +52,10 @@ void BlobOnBlocks::flush() {
_datatree->flush(); _datatree->flush();
} }
uint32_t BlobOnBlocks::numNodes() const {
return _datatree->numNodes();
}
const BlockId &BlobOnBlocks::blockId() const { const BlockId &BlobOnBlocks::blockId() const {
return _datatree->blockId(); return _datatree->blockId();
} }

View File

@ -35,6 +35,8 @@ public:
void flush() override; void flush() override;
uint32_t numNodes() const override;
cpputils::unique_ref<parallelaccessdatatreestore::DataTreeRef> releaseTree(); cpputils::unique_ref<parallelaccessdatatreestore::DataTreeRef> releaseTree();
private: private:

View File

@ -13,6 +13,7 @@
#include <cpp-utils/assert/assert.h> #include <cpp-utils/assert/assert.h>
#include "impl/LeafTraverser.h" #include "impl/LeafTraverser.h"
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <blobstore/implementations/onblocks/utils/Math.h>
using blockstore::BlockId; using blockstore::BlockId;
using blobstore::onblocks::datanodestore::DataNodeStore; using blobstore::onblocks::datanodestore::DataNodeStore;
@ -64,7 +65,16 @@ unique_ref<DataNode> DataTree::releaseRootNode() {
return std::move(_rootNode); return std::move(_rootNode);
} }
//TODO Test numLeaves(), for example also two configurations with same number of bytes but different number of leaves (last leaf has 0 bytes) uint32_t DataTree::numNodes() const {
uint32_t numNodesCurrentLevel = numLeaves();
uint32_t totalNumNodes = numNodesCurrentLevel;
for(size_t level = 0; level < _rootNode->depth(); ++level) {
numNodesCurrentLevel = blobstore::onblocks::utils::ceilDivision(numNodesCurrentLevel, static_cast<uint32_t>(_nodeStore->layout().maxChildrenPerInnerNode()));
totalNumNodes += numNodesCurrentLevel;
}
return totalNumNodes;
}
uint32_t DataTree::numLeaves() const { uint32_t DataTree::numLeaves() const {
shared_lock<shared_mutex> lock(_treeStructureMutex); shared_lock<shared_mutex> lock(_treeStructureMutex);

View File

@ -40,6 +40,7 @@ public:
void resizeNumBytes(uint64_t newNumBytes); void resizeNumBytes(uint64_t newNumBytes);
uint32_t numNodes() const;
uint32_t numLeaves() const; uint32_t numLeaves() const;
uint64_t numBytes() const; uint64_t numBytes() const;

View File

@ -54,6 +54,10 @@ public:
return _baseTree->flush(); return _baseTree->flush();
} }
uint32_t numNodes() const {
return _baseTree->numNodes();
}
private: private:
datatreestore::DataTree *_baseTree; datatreestore::DataTree *_baseTree;

View File

@ -26,6 +26,8 @@ public:
virtual void flush() = 0; virtual void flush() = 0;
virtual uint32_t numNodes() const = 0;
//TODO Test tryRead //TODO Test tryRead
}; };

View File

@ -85,6 +85,10 @@ namespace cryfs {
return _baseBlob->flush(); return _baseBlob->flush();
} }
uint32_t numNodes() const override {
return _baseBlob->numNodes();
}
cpputils::unique_ref<blobstore::Blob> releaseBaseBlob() { cpputils::unique_ref<blobstore::Blob> releaseBaseBlob() {
return std::move(_baseBlob); return std::move(_baseBlob);
} }

View File

@ -21,50 +21,68 @@ INSTANTIATE_TEST_CASE_P(EmptyLastLeaf, DataTreeTest_NumStoredBytes_P, Values(0u)
INSTANTIATE_TEST_CASE_P(HalfFullLastLeaf, DataTreeTest_NumStoredBytes_P, Values(5u, 10u)); INSTANTIATE_TEST_CASE_P(HalfFullLastLeaf, DataTreeTest_NumStoredBytes_P, Values(5u, 10u));
INSTANTIATE_TEST_CASE_P(FullLastLeaf, DataTreeTest_NumStoredBytes_P, Values(static_cast<uint32_t>(DataNodeLayout(DataTreeTest_NumStoredBytes::BLOCKSIZE_BYTES).maxBytesPerLeaf()))); INSTANTIATE_TEST_CASE_P(FullLastLeaf, DataTreeTest_NumStoredBytes_P, Values(static_cast<uint32_t>(DataNodeLayout(DataTreeTest_NumStoredBytes::BLOCKSIZE_BYTES).maxBytesPerLeaf())));
//TODO Test numLeaves() and numNodes() also two configurations with same number of bytes but different number of leaves (last leaf has 0 bytes)
TEST_P(DataTreeTest_NumStoredBytes_P, SingleLeaf) { TEST_P(DataTreeTest_NumStoredBytes_P, SingleLeaf) {
BlockId blockId = CreateLeafWithSize(GetParam())->blockId(); BlockId blockId = CreateLeafWithSize(GetParam())->blockId();
auto tree = treeStore.load(blockId).value(); auto tree = treeStore.load(blockId).value();
EXPECT_EQ(GetParam(), tree->numBytes()); EXPECT_EQ(GetParam(), tree->numBytes());
EXPECT_EQ(1, tree->numLeaves());
EXPECT_EQ(1, tree->numNodes());
} }
TEST_P(DataTreeTest_NumStoredBytes_P, TwoLeafTree) { TEST_P(DataTreeTest_NumStoredBytes_P, TwoLeafTree) {
BlockId blockId = CreateTwoLeafWithSecondLeafSize(GetParam())->blockId(); BlockId blockId = CreateTwoLeafWithSecondLeafSize(GetParam())->blockId();
auto tree = treeStore.load(blockId).value(); auto tree = treeStore.load(blockId).value();
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes()); EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes());
EXPECT_EQ(2, tree->numLeaves());
EXPECT_EQ(3, tree->numNodes());
} }
TEST_P(DataTreeTest_NumStoredBytes_P, FullTwolevelTree) { TEST_P(DataTreeTest_NumStoredBytes_P, FullTwolevelTree) {
BlockId blockId = CreateFullTwoLevelWithLastLeafSize(GetParam())->blockId(); BlockId blockId = CreateFullTwoLevelWithLastLeafSize(GetParam())->blockId();
auto tree = treeStore.load(blockId).value(); auto tree = treeStore.load(blockId).value();
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*(nodeStore->layout().maxChildrenPerInnerNode()-1) + GetParam(), tree->numBytes()); EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*(nodeStore->layout().maxChildrenPerInnerNode()-1) + GetParam(), tree->numBytes());
EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves());
EXPECT_EQ(1 + nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes());
} }
TEST_P(DataTreeTest_NumStoredBytes_P, ThreeLevelTreeWithOneChild) { TEST_P(DataTreeTest_NumStoredBytes_P, ThreeLevelTreeWithOneChild) {
BlockId blockId = CreateThreeLevelWithOneChildAndLastLeafSize(GetParam())->blockId(); BlockId blockId = CreateThreeLevelWithOneChildAndLastLeafSize(GetParam())->blockId();
auto tree = treeStore.load(blockId).value(); auto tree = treeStore.load(blockId).value();
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes()); EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes());
EXPECT_EQ(2, tree->numLeaves());
EXPECT_EQ(4, tree->numNodes());
} }
TEST_P(DataTreeTest_NumStoredBytes_P, ThreeLevelTreeWithTwoChildren) { TEST_P(DataTreeTest_NumStoredBytes_P, ThreeLevelTreeWithTwoChildren) {
BlockId blockId = CreateThreeLevelWithTwoChildrenAndLastLeafSize(GetParam())->blockId(); BlockId blockId = CreateThreeLevelWithTwoChildrenAndLastLeafSize(GetParam())->blockId();
auto tree = treeStore.load(blockId).value(); auto tree = treeStore.load(blockId).value();
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes()); EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes());
EXPECT_EQ(2 + nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves());
EXPECT_EQ(5 + nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes());
} }
TEST_P(DataTreeTest_NumStoredBytes_P, ThreeLevelTreeWithThreeChildren) { TEST_P(DataTreeTest_NumStoredBytes_P, ThreeLevelTreeWithThreeChildren) {
BlockId blockId = CreateThreeLevelWithThreeChildrenAndLastLeafSize(GetParam())->blockId(); BlockId blockId = CreateThreeLevelWithThreeChildrenAndLastLeafSize(GetParam())->blockId();
auto tree = treeStore.load(blockId).value(); auto tree = treeStore.load(blockId).value();
EXPECT_EQ(2*nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes()); EXPECT_EQ(2*nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes());
EXPECT_EQ(2 + 2*nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves());
EXPECT_EQ(6 + 2*nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes());
} }
TEST_P(DataTreeTest_NumStoredBytes_P, FullThreeLevelTree) { TEST_P(DataTreeTest_NumStoredBytes_P, FullThreeLevelTree) {
BlockId blockId = CreateFullThreeLevelWithLastLeafSize(GetParam())->blockId(); BlockId blockId = CreateFullThreeLevelWithLastLeafSize(GetParam())->blockId();
auto tree = treeStore.load(blockId).value(); auto tree = treeStore.load(blockId).value();
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode()*(nodeStore->layout().maxChildrenPerInnerNode()-1) + nodeStore->layout().maxBytesPerLeaf()*(nodeStore->layout().maxChildrenPerInnerNode()-1) + GetParam(), tree->numBytes()); EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode()*(nodeStore->layout().maxChildrenPerInnerNode()-1) + nodeStore->layout().maxBytesPerLeaf()*(nodeStore->layout().maxChildrenPerInnerNode()-1) + GetParam(), tree->numBytes());
EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves());
EXPECT_EQ(1 + nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes());
} }
TEST_P(DataTreeTest_NumStoredBytes_P, FourLevelMinDataTree) { TEST_P(DataTreeTest_NumStoredBytes_P, FourLevelMinDataTree) {
BlockId blockId = CreateFourLevelMinDataWithLastLeafSize(GetParam())->blockId(); BlockId blockId = CreateFourLevelMinDataWithLastLeafSize(GetParam())->blockId();
auto tree = treeStore.load(blockId).value(); auto tree = treeStore.load(blockId).value();
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + GetParam(), tree->numBytes()); EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + GetParam(), tree->numBytes());
EXPECT_EQ(1 + nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves());
EXPECT_EQ(5 + nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes());
} }