Special case treatment for traversals until exactly the last leaf has to load the last leaf to grow it. Before this commit, we just always loaded the last traversed leaf and checked its size. Now we only do so if it's the right border leaf. This saves us loading some leaves.

This commit is contained in:
Sebastian Messmer 2016-07-17 10:16:09 +02:00
parent b339261924
commit bbdd8a548b
9 changed files with 84 additions and 82 deletions

View File

@ -49,15 +49,16 @@ void BlobOnBlocks::_traverseLeaves(uint64_t beginByte, uint64_t sizeBytes, funct
uint32_t firstLeaf = beginByte / maxBytesPerLeaf; uint32_t firstLeaf = beginByte / maxBytesPerLeaf;
uint32_t endLeaf = utils::ceilDivision(endByte, maxBytesPerLeaf); uint32_t endLeaf = utils::ceilDivision(endByte, maxBytesPerLeaf);
bool blobIsGrowingFromThisTraversal = false; bool blobIsGrowingFromThisTraversal = false;
auto _onExistingLeaf = [&onExistingLeaf, beginByte, endByte, endLeaf, maxBytesPerLeaf, &blobIsGrowingFromThisTraversal] (uint32_t leafIndex, LeafHandle leafHandle) { auto _onExistingLeaf = [&onExistingLeaf, beginByte, endByte, endLeaf, maxBytesPerLeaf, &blobIsGrowingFromThisTraversal] (uint32_t leafIndex, bool isRightBorderLeaf, LeafHandle leafHandle) {
uint64_t indexOfFirstLeafByte = leafIndex * maxBytesPerLeaf; uint64_t indexOfFirstLeafByte = leafIndex * maxBytesPerLeaf;
ASSERT(endByte > indexOfFirstLeafByte, "Traversal went too far right"); ASSERT(endByte > indexOfFirstLeafByte, "Traversal went too far right");
uint32_t dataBegin = utils::maxZeroSubtraction(beginByte, indexOfFirstLeafByte); uint32_t dataBegin = utils::maxZeroSubtraction(beginByte, indexOfFirstLeafByte);
uint32_t dataEnd = std::min(maxBytesPerLeaf, endByte - indexOfFirstLeafByte); uint32_t dataEnd = std::min(maxBytesPerLeaf, endByte - indexOfFirstLeafByte);
if (leafIndex == endLeaf-1) { // If we are traversing exactly until the last leaf, then the last leaf wasn't resized by the traversal and might have a wrong size. We have to fix it.
if (isRightBorderLeaf) {
ASSERT(leafIndex == endLeaf-1, "If we traversed further right, this wouldn't be the right border leaf.");
auto leaf = leafHandle.node(); auto leaf = leafHandle.node();
if (leaf->numBytes() < dataEnd) { if (leaf->numBytes() < dataEnd) {
// If we are traversing an area that didn't exist before (i.e. in the area of the last leaf that wasn't used before), then the last leaf might have a wrong size. We have to fix it.
leaf->resize(dataEnd); leaf->resize(dataEnd);
blobIsGrowingFromThisTraversal = true; blobIsGrowingFromThisTraversal = true;
} }
@ -127,12 +128,12 @@ void BlobOnBlocks::_read(void *target, uint64_t offset, uint64_t count) const {
void BlobOnBlocks::write(const void *source, uint64_t offset, uint64_t count) { void BlobOnBlocks::write(const void *source, uint64_t offset, uint64_t count) {
auto onExistingLeaf = [source, offset, count] (uint64_t indexOfFirstLeafByte, LeafHandle leaf, uint32_t leafDataOffset, uint32_t leafDataSize) { auto onExistingLeaf = [source, offset, count] (uint64_t indexOfFirstLeafByte, LeafHandle leaf, uint32_t leafDataOffset, uint32_t leafDataSize) {
ASSERT(indexOfFirstLeafByte+leafDataOffset>=offset && indexOfFirstLeafByte-offset+leafDataOffset <= count && indexOfFirstLeafByte-offset+leafDataOffset+leafDataSize <= count, "Reading from source out of bounds"); ASSERT(indexOfFirstLeafByte+leafDataOffset>=offset && indexOfFirstLeafByte-offset+leafDataOffset <= count && indexOfFirstLeafByte-offset+leafDataOffset+leafDataSize <= count, "Reading from source out of bounds");
//TODO Simplify formula, make it easier to understand
if (leafDataOffset == 0 && leafDataSize == leaf.nodeStore()->layout().maxBytesPerLeaf()) { if (leafDataOffset == 0 && leafDataSize == leaf.nodeStore()->layout().maxBytesPerLeaf()) {
Data leafData(leafDataSize); Data leafData(leafDataSize);
std::memcpy(leafData.data(), (uint8_t*)source + indexOfFirstLeafByte - offset, leafDataSize); std::memcpy(leafData.data(), (uint8_t*)source + indexOfFirstLeafByte - offset, leafDataSize);
leaf.nodeStore()->overwriteLeaf(leaf.key(), std::move(leafData)); leaf.nodeStore()->overwriteLeaf(leaf.key(), std::move(leafData));
} else { } else {
//TODO Simplify formula, make it easier to understand
leaf.node()->write((uint8_t *) source + indexOfFirstLeafByte - offset + leafDataOffset, leafDataOffset, leaf.node()->write((uint8_t *) source + indexOfFirstLeafByte - offset + leafDataOffset, leafDataOffset,
leafDataSize); leafDataSize);
} }

View File

@ -96,7 +96,7 @@ uint32_t DataTree::_computeNumLeaves(const DataNode &node) const {
return numLeavesInLeftChildren + numLeavesInRightChild; return numLeavesInLeftChildren + numLeavesInRightChild;
} }
void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf) { void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf) {
//TODO Can we allow multiple runs of traverseLeaves() in parallel? Also in parallel with resizeNumBytes()? //TODO Can we allow multiple runs of traverseLeaves() in parallel? Also in parallel with resizeNumBytes()?
std::unique_lock<shared_mutex> lock(_mutex); std::unique_lock<shared_mutex> lock(_mutex);
ASSERT(beginIndex <= endIndex, "Invalid parameters"); ASSERT(beginIndex <= endIndex, "Invalid parameters");
@ -111,7 +111,7 @@ void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function<v
} }
void DataTree::_traverseLeaves(uint32_t beginIndex, uint32_t endIndex, void DataTree::_traverseLeaves(uint32_t beginIndex, uint32_t endIndex,
function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
function<Data (uint32_t index)> onCreateLeaf, function<Data (uint32_t index)> onCreateLeaf,
function<void (DataInnerNode *node)> onBacktrackFromSubtree) { function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
_rootNode = LeafTraverser(_nodeStore).traverseAndReturnRoot(std::move(_rootNode), beginIndex, endIndex, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); _rootNode = LeafTraverser(_nodeStore).traverseAndReturnRoot(std::move(_rootNode), beginIndex, endIndex, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree);
@ -151,7 +151,7 @@ void DataTree::resizeNumBytes(uint64_t newNumBytes) {
uint32_t newNumLeaves = std::max(UINT64_C(1), utils::ceilDivision(newNumBytes, _nodeStore->layout().maxBytesPerLeaf())); uint32_t newNumLeaves = std::max(UINT64_C(1), utils::ceilDivision(newNumBytes, _nodeStore->layout().maxBytesPerLeaf()));
uint32_t newLastLeafSize = newNumBytes - (newNumLeaves-1) * _nodeStore->layout().maxBytesPerLeaf(); uint32_t newLastLeafSize = newNumBytes - (newNumLeaves-1) * _nodeStore->layout().maxBytesPerLeaf();
uint32_t maxChildrenPerInnerNode = _nodeStore->layout().maxChildrenPerInnerNode(); uint32_t maxChildrenPerInnerNode = _nodeStore->layout().maxChildrenPerInnerNode();
auto onExistingLeaf = [newLastLeafSize] (uint32_t /*index*/, LeafHandle leafHandle) { auto onExistingLeaf = [newLastLeafSize] (uint32_t /*index*/, bool /*isRightBorderLeaf*/, LeafHandle leafHandle) {
auto leaf = leafHandle.node(); auto leaf = leafHandle.node();
// This is only called, if the new last leaf was already existing // This is only called, if the new last leaf was already existing
if (leaf->numBytes() != newLastLeafSize) { if (leaf->numBytes() != newLastLeafSize) {

View File

@ -31,7 +31,7 @@ public:
//Returning uint64_t, because calculations handling this probably need to be done in 64bit to support >4GB blobs. //Returning uint64_t, because calculations handling this probably need to be done in 64bit to support >4GB blobs.
uint64_t maxBytesPerLeaf() const; uint64_t maxBytesPerLeaf() const;
void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf); void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf);
void resizeNumBytes(uint64_t newNumBytes); void resizeNumBytes(uint64_t newNumBytes);
uint32_t numLeaves() const; uint32_t numLeaves() const;
@ -56,7 +56,7 @@ private:
//TODO Use underscore for private methods //TODO Use underscore for private methods
void _traverseLeaves(uint32_t beginIndex, uint32_t endIndex, void _traverseLeaves(uint32_t beginIndex, uint32_t endIndex,
std::function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree); std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree);
uint32_t leavesPerFullChild(const datanodestore::DataInnerNode &root) const; uint32_t leavesPerFullChild(const datanodestore::DataInnerNode &root) const;

View File

@ -24,11 +24,11 @@ namespace blobstore {
: _nodeStore(nodeStore) { : _nodeStore(nodeStore) {
} }
unique_ref<DataNode> LeafTraverser::traverseAndReturnRoot(unique_ref<DataNode> root, uint32_t beginIndex, uint32_t endIndex, function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) { unique_ref<DataNode> LeafTraverser::traverseAndReturnRoot(unique_ref<DataNode> root, uint32_t beginIndex, uint32_t endIndex, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
return _traverseAndReturnRoot(std::move(root), beginIndex, endIndex, true, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); return _traverseAndReturnRoot(std::move(root), beginIndex, endIndex, true, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree);
} }
unique_ref<DataNode> LeafTraverser::_traverseAndReturnRoot(unique_ref<DataNode> root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal, function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) { unique_ref<DataNode> LeafTraverser::_traverseAndReturnRoot(unique_ref<DataNode> root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
ASSERT(beginIndex <= endIndex, "Invalid parameters"); ASSERT(beginIndex <= endIndex, "Invalid parameters");
//TODO Test cases with numLeaves < / >= beginIndex, ideally test all configurations: //TODO Test cases with numLeaves < / >= beginIndex, ideally test all configurations:
@ -47,13 +47,13 @@ namespace blobstore {
leaf->resize(_nodeStore->layout().maxBytesPerLeaf()); leaf->resize(_nodeStore->layout().maxBytesPerLeaf());
} }
if (beginIndex == 0 && endIndex == 1) { if (beginIndex == 0 && endIndex == 1) {
onExistingLeaf(0, LeafHandle(_nodeStore, leaf)); onExistingLeaf(0, true, LeafHandle(_nodeStore, leaf));
} }
} else { } else {
DataInnerNode *inner = dynamic_cast<DataInnerNode*>(root.get()); DataInnerNode *inner = dynamic_cast<DataInnerNode*>(root.get());
ASSERT(inner != nullptr, "Depth != 0 has to be leaf node"); ASSERT(inner != nullptr, "Depth != 0 has to be leaf node");
_traverseExistingSubtree(inner, std::min(beginIndex, maxLeavesForDepth), _traverseExistingSubtree(inner, std::min(beginIndex, maxLeavesForDepth),
std::min(endIndex, maxLeavesForDepth), 0, isLeftBorderOfTraversal, std::min(endIndex, maxLeavesForDepth), 0, isLeftBorderOfTraversal, true,
increaseTreeDepth, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); increaseTreeDepth, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree);
} }
@ -77,7 +77,7 @@ namespace blobstore {
return DataNode::convertToNewInnerNode(std::move(root), _nodeStore->layout(), *copyOfOldRoot); return DataNode::convertToNewInnerNode(std::move(root), _nodeStore->layout(), *copyOfOldRoot);
} }
void LeafTraverser::_traverseExistingSubtree(const blockstore::Key &key, uint8_t depth, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) { void LeafTraverser::_traverseExistingSubtree(const blockstore::Key &key, uint8_t depth, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
if (depth == 0) { if (depth == 0) {
ASSERT(beginIndex <= 1 && endIndex <= 1, ASSERT(beginIndex <= 1 && endIndex <= 1,
"If root node is a leaf, the (sub)tree has only one leaf - access indices must be 0 or 1."); "If root node is a leaf, the (sub)tree has only one leaf - access indices must be 0 or 1.");
@ -88,7 +88,7 @@ namespace blobstore {
} }
} }
if (beginIndex == 0 && endIndex == 1) { if (beginIndex == 0 && endIndex == 1) {
onExistingLeaf(leafOffset, std::move(leafHandle)); onExistingLeaf(leafOffset, isRightBorderNode, std::move(leafHandle));
} }
} else { } else {
auto node = _nodeStore->load(key); auto node = _nodeStore->load(key);
@ -100,11 +100,11 @@ namespace blobstore {
ASSERT(inner != none, "Has to be either leaf or inner node"); ASSERT(inner != none, "Has to be either leaf or inner node");
ASSERT((*inner)->depth() == depth, "Wrong depth given"); ASSERT((*inner)->depth() == depth, "Wrong depth given");
_traverseExistingSubtree(inner->get(), beginIndex, endIndex, leafOffset, isLeftBorderOfTraversal, _traverseExistingSubtree(inner->get(), beginIndex, endIndex, leafOffset, isLeftBorderOfTraversal,
growLastLeaf, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); isRightBorderNode, growLastLeaf, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree);
} }
} }
void LeafTraverser::_traverseExistingSubtree(DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) { void LeafTraverser::_traverseExistingSubtree(DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf, function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
ASSERT(beginIndex <= endIndex, "Invalid parameters"); ASSERT(beginIndex <= endIndex, "Invalid parameters");
//TODO Call callbacks for different leaves in parallel. //TODO Call callbacks for different leaves in parallel.
@ -123,8 +123,8 @@ namespace blobstore {
ASSERT(numChildren > 0, "Node doesn't have children."); ASSERT(numChildren > 0, "Node doesn't have children.");
auto childKey = root->getChild(numChildren-1)->key(); auto childKey = root->getChild(numChildren-1)->key();
uint32_t childOffset = (numChildren-1) * leavesPerChild; uint32_t childOffset = (numChildren-1) * leavesPerChild;
_traverseExistingSubtree(childKey, root->depth()-1, leavesPerChild, leavesPerChild, childOffset, true, true, _traverseExistingSubtree(childKey, root->depth()-1, leavesPerChild, leavesPerChild, childOffset, true, false, true,
[] (uint32_t /*index*/, LeafHandle /*leaf*/) {ASSERT(false, "We don't actually traverse any leaves.");}, [] (uint32_t /*index*/, bool /*isRightBorderNode*/, LeafHandle /*leaf*/) {ASSERT(false, "We don't actually traverse any leaves.");},
[] (uint32_t /*index*/) -> Data {ASSERT(false, "We don't actually traverse any leaves.");}, [] (uint32_t /*index*/) -> Data {ASSERT(false, "We don't actually traverse any leaves.");},
[] (DataInnerNode* /*node*/) {ASSERT(false, "We don't actually traverse any leaves.");}); [] (DataInnerNode* /*node*/) {ASSERT(false, "We don't actually traverse any leaves.");});
} }
@ -136,10 +136,11 @@ namespace blobstore {
uint32_t localBeginIndex = utils::maxZeroSubtraction(beginIndex, childOffset); uint32_t localBeginIndex = utils::maxZeroSubtraction(beginIndex, childOffset);
uint32_t localEndIndex = std::min(leavesPerChild, endIndex - childOffset); uint32_t localEndIndex = std::min(leavesPerChild, endIndex - childOffset);
bool isFirstChild = (childIndex == beginChild); bool isFirstChild = (childIndex == beginChild);
bool isLastChild = (childIndex == numChildren - 1); bool isLastExistingChild = (childIndex == numChildren - 1);
bool isLastChild = isLastExistingChild && (numChildren == endChild);
ASSERT(localEndIndex <= leavesPerChild, "We don't want the child to add a tree level because it doesn't have enough space for the traversal."); ASSERT(localEndIndex <= leavesPerChild, "We don't want the child to add a tree level because it doesn't have enough space for the traversal.");
_traverseExistingSubtree(childKey, root->depth()-1, localBeginIndex, localEndIndex, leafOffset + childOffset, isLeftBorderOfTraversal && isFirstChild, _traverseExistingSubtree(childKey, root->depth()-1, localBeginIndex, localEndIndex, leafOffset + childOffset, isLeftBorderOfTraversal && isFirstChild,
shouldGrowLastExistingLeaf && isLastChild, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree); isRightBorderNode && isLastChild, shouldGrowLastExistingLeaf && isLastExistingChild, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree);
} }
// Traverse new children (including gap children, i.e. children that are created but not traversed because they're to the right of the current size, but to the left of the traversal region) // Traverse new children (including gap children, i.e. children that are created but not traversed because they're to the right of the current size, but to the left of the traversal region)

View File

@ -29,7 +29,7 @@ namespace blobstore {
cpputils::unique_ref<datanodestore::DataNode> traverseAndReturnRoot( cpputils::unique_ref<datanodestore::DataNode> traverseAndReturnRoot(
cpputils::unique_ref<datanodestore::DataNode> root, uint32_t beginIndex, uint32_t endIndex, cpputils::unique_ref<datanodestore::DataNode> root, uint32_t beginIndex, uint32_t endIndex,
std::function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree); std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree);
@ -38,15 +38,15 @@ namespace blobstore {
cpputils::unique_ref<datanodestore::DataNode> _traverseAndReturnRoot( cpputils::unique_ref<datanodestore::DataNode> _traverseAndReturnRoot(
cpputils::unique_ref<datanodestore::DataNode> root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal, cpputils::unique_ref<datanodestore::DataNode> root, uint32_t beginIndex, uint32_t endIndex, bool isLeftBorderOfTraversal,
std::function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree); std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree);
void _traverseExistingSubtree(datanodestore::DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, void _traverseExistingSubtree(datanodestore::DataInnerNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf,
std::function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree); std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree);
void _traverseExistingSubtree(const blockstore::Key &key, uint8_t depth, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, void _traverseExistingSubtree(const blockstore::Key &key, uint8_t depth, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool isRightBorderNode, bool growLastLeaf,
std::function<void (uint32_t index, LeafHandle leaf)> onExistingLeaf, std::function<void (uint32_t index, bool isRightBorderLeaf, LeafHandle leaf)> onExistingLeaf,
std::function<cpputils::Data (uint32_t index)> onCreateLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf,
std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree); std::function<void (datanodestore::DataInnerNode *node)> onBacktrackFromSubtree);
cpputils::unique_ref<datanodestore::DataInnerNode> _increaseTreeDepth(cpputils::unique_ref<datanodestore::DataNode> root); cpputils::unique_ref<datanodestore::DataInnerNode> _increaseTreeDepth(cpputils::unique_ref<datanodestore::DataNode> root);

View File

@ -22,7 +22,7 @@ public:
return _baseTree->maxBytesPerLeaf(); return _baseTree->maxBytesPerLeaf();
} }
void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function<void (uint32_t index, datatreestore::LeafHandle leaf)> onExistingLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf) { void traverseLeaves(uint32_t beginIndex, uint32_t endIndex, std::function<void (uint32_t index, bool isRightBorderLeaf, datatreestore::LeafHandle leaf)> onExistingLeaf, std::function<cpputils::Data (uint32_t index)> onCreateLeaf) {
return _baseTree->traverseLeaves(beginIndex, endIndex, onExistingLeaf, onCreateLeaf); return _baseTree->traverseLeaves(beginIndex, endIndex, onExistingLeaf, onCreateLeaf);
} }

View File

@ -16,7 +16,7 @@ using cpputils::make_unique_ref;
class DataTreeTest_Performance: public DataTreeTest { class DataTreeTest_Performance: public DataTreeTest {
public: public:
void Traverse(DataTree *tree, uint64_t beginIndex, uint64_t endIndex) { void Traverse(DataTree *tree, uint64_t beginIndex, uint64_t endIndex) {
tree->traverseLeaves(beginIndex, endIndex, [] (uint32_t /*index*/, LeafHandle /*leaf*/) {}, [this] (uint32_t /*index*/) -> Data {return Data(maxChildrenPerInnerNode).FillWithZeroes();}); tree->traverseLeaves(beginIndex, endIndex, [] (uint32_t /*index*/, bool /*isRightBorderNode*/, LeafHandle /*leaf*/) {}, [this] (uint32_t /*index*/) -> Data {return Data(maxChildrenPerInnerNode).FillWithZeroes();});
} }
uint64_t maxChildrenPerInnerNode = nodeStore->layout().maxChildrenPerInnerNode(); uint64_t maxChildrenPerInnerNode = nodeStore->layout().maxChildrenPerInnerNode();

View File

@ -111,7 +111,7 @@ public:
void GrowTree(DataTree *tree) { void GrowTree(DataTree *tree) {
uint64_t maxBytesPerLeaf = tree->maxBytesPerLeaf(); uint64_t maxBytesPerLeaf = tree->maxBytesPerLeaf();
tree->traverseLeaves(traversalBeginIndex, newNumberOfLeaves, [] (uint32_t, LeafHandle){}, [maxBytesPerLeaf] (uint32_t) -> Data { return Data(maxBytesPerLeaf).FillWithZeroes();}); tree->traverseLeaves(traversalBeginIndex, newNumberOfLeaves, [] (uint32_t, bool, LeafHandle){}, [maxBytesPerLeaf] (uint32_t) -> Data { return Data(maxBytesPerLeaf).FillWithZeroes();});
tree->flush(); tree->flush();
} }

View File

@ -16,7 +16,7 @@ using std::shared_ptr;
class TraversorMock { class TraversorMock {
public: public:
MOCK_METHOD2(calledExistingLeaf, void(DataLeafNode*, uint32_t)); MOCK_METHOD3(calledExistingLeaf, void(DataLeafNode*, bool, uint32_t));
MOCK_METHOD1(calledCreateLeaf, shared_ptr<Data>(uint32_t)); MOCK_METHOD1(calledCreateLeaf, shared_ptr<Data>(uint32_t));
}; };
@ -46,26 +46,26 @@ public:
}); });
} }
void EXPECT_TRAVERSE_LEAF(const Key &key, uint32_t leafIndex) { void EXPECT_TRAVERSE_LEAF(const Key &key, bool isRightBorderLeaf, uint32_t leafIndex) {
EXPECT_CALL(traversor, calledExistingLeaf(KeyEq(key), leafIndex)).Times(1); EXPECT_CALL(traversor, calledExistingLeaf(KeyEq(key), isRightBorderLeaf, leafIndex)).Times(1);
} }
void EXPECT_TRAVERSE_ALL_CHILDREN_OF(const DataInnerNode &node, uint32_t firstLeafIndex) { void EXPECT_TRAVERSE_ALL_CHILDREN_OF(const DataInnerNode &node, bool isRightBorderNode, uint32_t firstLeafIndex) {
for (unsigned int i = 0; i < node.numChildren(); ++i) { for (unsigned int i = 0; i < node.numChildren(); ++i) {
EXPECT_TRAVERSE_LEAF(node.getChild(i)->key(), firstLeafIndex+i); EXPECT_TRAVERSE_LEAF(node.getChild(i)->key(), isRightBorderNode && i == node.numChildren()-1, firstLeafIndex+i);
} }
} }
void EXPECT_DONT_TRAVERSE_ANY_LEAVES() { void EXPECT_DONT_TRAVERSE_ANY_LEAVES() {
EXPECT_CALL(traversor, calledExistingLeaf(_, _)).Times(0); EXPECT_CALL(traversor, calledExistingLeaf(_, _, _)).Times(0);
EXPECT_CALL(traversor, calledCreateLeaf(_)).Times(0); EXPECT_CALL(traversor, calledCreateLeaf(_)).Times(0);
} }
void TraverseLeaves(DataNode *root, uint32_t beginIndex, uint32_t endIndex) { void TraverseLeaves(DataNode *root, uint32_t beginIndex, uint32_t endIndex) {
root->flush(); root->flush();
auto tree = treeStore.load(root->key()).value(); auto tree = treeStore.load(root->key()).value();
tree->traverseLeaves(beginIndex, endIndex, [this] (uint32_t nodeIndex, LeafHandle leaf) { tree->traverseLeaves(beginIndex, endIndex, [this] (uint32_t nodeIndex, bool isRightBorderNode,LeafHandle leaf) {
traversor.calledExistingLeaf(leaf.node(), nodeIndex); traversor.calledExistingLeaf(leaf.node(), isRightBorderNode, nodeIndex);
}, [this] (uint32_t nodeIndex) -> Data { }, [this] (uint32_t nodeIndex) -> Data {
return traversor.calledCreateLeaf(nodeIndex)->copy(); return traversor.calledCreateLeaf(nodeIndex)->copy();
}); });
@ -76,7 +76,7 @@ public:
TEST_F(DataTreeTest_TraverseLeaves, TraverseSingleLeafTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseSingleLeafTree) {
auto root = CreateLeaf(); auto root = CreateLeaf();
EXPECT_TRAVERSE_LEAF(root->key(), 0); EXPECT_TRAVERSE_LEAF(root->key(), true, 0);
TraverseLeaves(root.get(), 0, 1); TraverseLeaves(root.get(), 0, 1);
} }
@ -97,21 +97,21 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseNothingInSingleLeafTree2) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfFullTwolevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfFullTwolevelTree) {
auto root = CreateFullTwoLevel(); auto root = CreateFullTwoLevel();
EXPECT_TRAVERSE_LEAF(root->getChild(0)->key(), 0); EXPECT_TRAVERSE_LEAF(root->getChild(0)->key(), false, 0);
TraverseLeaves(root.get(), 0, 1); TraverseLeaves(root.get(), 0, 1);
} }
TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfFullTwolevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfFullTwolevelTree) {
auto root = CreateFullTwoLevel(); auto root = CreateFullTwoLevel();
EXPECT_TRAVERSE_LEAF(root->getChild(5)->key(), 5); EXPECT_TRAVERSE_LEAF(root->getChild(5)->key(), false, 5);
TraverseLeaves(root.get(), 5, 6); TraverseLeaves(root.get(), 5, 6);
} }
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfFullTwolevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfFullTwolevelTree) {
auto root = CreateFullTwoLevel(); auto root = CreateFullTwoLevel();
EXPECT_TRAVERSE_LEAF(root->getChild(nodeStore->layout().maxChildrenPerInnerNode()-1)->key(), nodeStore->layout().maxChildrenPerInnerNode()-1); EXPECT_TRAVERSE_LEAF(root->getChild(nodeStore->layout().maxChildrenPerInnerNode()-1)->key(), true, nodeStore->layout().maxChildrenPerInnerNode()-1);
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode()-1, nodeStore->layout().maxChildrenPerInnerNode()); TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode()-1, nodeStore->layout().maxChildrenPerInnerNode());
} }
@ -132,43 +132,43 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseNothingInFullTwolevelTree2) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreeLevelMinDataTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreeLevelMinDataTree) {
auto root = CreateThreeLevelMinData(); auto root = CreateThreeLevelMinData();
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(0)->key(), 0); EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(0)->key(), false, 0);
TraverseLeaves(root.get(), 0, 1); TraverseLeaves(root.get(), 0, 1);
} }
TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfThreeLevelMinDataTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfThreeLevelMinDataTree) {
auto root = CreateThreeLevelMinData(); auto root = CreateThreeLevelMinData();
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(5)->key(), 5); EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(5)->key(), false, 5);
TraverseLeaves(root.get(), 5, 6); TraverseLeaves(root.get(), 5, 6);
} }
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreeLevelMinDataTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreeLevelMinDataTree) {
auto root = CreateThreeLevelMinData(); auto root = CreateThreeLevelMinData();
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), true, nodeStore->layout().maxChildrenPerInnerNode());
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode(), nodeStore->layout().maxChildrenPerInnerNode()+1); TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode(), nodeStore->layout().maxChildrenPerInnerNode()+1);
} }
TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfFullTwolevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfFullTwolevelTree) {
auto root = CreateFullTwoLevel(); auto root = CreateFullTwoLevel();
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*root, 0); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*root, true, 0);
TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode()); TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode());
} }
TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfThreelevelMinDataTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfThreelevelMinDataTree) {
auto root = CreateThreeLevelMinData(); auto root = CreateThreeLevelMinData();
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), 0); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), false, 0);
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), true, nodeStore->layout().maxChildrenPerInnerNode());
TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode()+1); TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode()+1);
} }
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstChildOfThreelevelMinDataTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstChildOfThreelevelMinDataTree) {
auto root = CreateThreeLevelMinData(); auto root = CreateThreeLevelMinData();
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), 0); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(0)->key()), false, 0);
TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode()); TraverseLeaves(root.get(), 0, nodeStore->layout().maxChildrenPerInnerNode());
} }
@ -176,7 +176,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstChildOfThreelevelMinDataTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfFullTwolevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfFullTwolevelTree) {
auto root = CreateFullTwoLevel(); auto root = CreateFullTwoLevel();
for (unsigned int i = 0; i < 5; ++i) { for (unsigned int i = 0; i < 5; ++i) {
EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), i); EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), false, i);
} }
TraverseLeaves(root.get(), 0, 5); TraverseLeaves(root.get(), 0, 5);
@ -185,7 +185,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfFullTwolevelTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseInnerPartOfFullTwolevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseInnerPartOfFullTwolevelTree) {
auto root = CreateFullTwoLevel(); auto root = CreateFullTwoLevel();
for (unsigned int i = 5; i < 10; ++i) { for (unsigned int i = 5; i < 10; ++i) {
EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), i); EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), false, i);
} }
TraverseLeaves(root.get(), 5, 10); TraverseLeaves(root.get(), 5, 10);
@ -194,7 +194,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseInnerPartOfFullTwolevelTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfFullTwolevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfFullTwolevelTree) {
auto root = CreateFullTwoLevel(); auto root = CreateFullTwoLevel();
for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), i); EXPECT_TRAVERSE_LEAF(root->getChild(i)->key(), i==nodeStore->layout().maxChildrenPerInnerNode()-1, i);
} }
TraverseLeaves(root.get(), 5, nodeStore->layout().maxChildrenPerInnerNode()); TraverseLeaves(root.get(), 5, nodeStore->layout().maxChildrenPerInnerNode());
@ -204,7 +204,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfThreelevelMinDataTree) {
auto root = CreateThreeLevelMinData(); auto root = CreateThreeLevelMinData();
auto node = LoadInnerNode(root->getChild(0)->key()); auto node = LoadInnerNode(root->getChild(0)->key());
for (unsigned int i = 0; i < 5; ++i) { for (unsigned int i = 0; i < 5; ++i) {
EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), i); EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), false, i);
} }
TraverseLeaves(root.get(), 0, 5); TraverseLeaves(root.get(), 0, 5);
@ -214,7 +214,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseInnerPartOfThreelevelMinDataTree) {
auto root = CreateThreeLevelMinData(); auto root = CreateThreeLevelMinData();
auto node = LoadInnerNode(root->getChild(0)->key()); auto node = LoadInnerNode(root->getChild(0)->key());
for (unsigned int i = 5; i < 10; ++i) { for (unsigned int i = 5; i < 10; ++i) {
EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), i); EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), false, i);
} }
TraverseLeaves(root.get(), 5, 10); TraverseLeaves(root.get(), 5, 10);
@ -224,16 +224,16 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfThreelevelMinDataTree) {
auto root = CreateThreeLevelMinData(); auto root = CreateThreeLevelMinData();
auto node = LoadInnerNode(root->getChild(0)->key()); auto node = LoadInnerNode(root->getChild(0)->key());
for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), i); EXPECT_TRAVERSE_LEAF(node->getChild(i)->key(), false, i);
} }
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(1)->key())->getChild(0)->key(), true, nodeStore->layout().maxChildrenPerInnerNode());
TraverseLeaves(root.get(), 5, nodeStore->layout().maxChildrenPerInnerNode()+1); TraverseLeaves(root.get(), 5, nodeStore->layout().maxChildrenPerInnerNode()+1);
} }
TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreelevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreelevelTree) {
auto root = CreateThreeLevel(); auto root = CreateThreeLevel();
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(0)->key(), 0); EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(0)->key())->getChild(0)->key(), false, 0);
TraverseLeaves(root.get(), 0, 1); TraverseLeaves(root.get(), 0, 1);
} }
@ -241,7 +241,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstLeafOfThreelevelTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreelevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreelevelTree) {
auto root = CreateThreeLevel(); auto root = CreateThreeLevel();
uint32_t numLeaves = nodeStore->layout().maxChildrenPerInnerNode() * 5 + 3; uint32_t numLeaves = nodeStore->layout().maxChildrenPerInnerNode() * 5 + 3;
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->LastChild()->key())->LastChild()->key(), numLeaves-1); EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->LastChild()->key())->LastChild()->key(), true, numLeaves-1);
TraverseLeaves(root.get(), numLeaves-1, numLeaves); TraverseLeaves(root.get(), numLeaves-1, numLeaves);
} }
@ -249,7 +249,7 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseLastLeafOfThreelevelTree) {
TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfThreelevelTree) { TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddleLeafOfThreelevelTree) {
auto root = CreateThreeLevel(); auto root = CreateThreeLevel();
uint32_t wantedLeafIndex = nodeStore->layout().maxChildrenPerInnerNode() * 2 + 5; uint32_t wantedLeafIndex = nodeStore->layout().maxChildrenPerInnerNode() * 2 + 5;
EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(2)->key())->getChild(5)->key(), wantedLeafIndex); EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->getChild(2)->key())->getChild(5)->key(), false, wantedLeafIndex);
TraverseLeaves(root.get(), wantedLeafIndex, wantedLeafIndex+1); TraverseLeaves(root.get(), wantedLeafIndex, wantedLeafIndex+1);
} }
@ -258,12 +258,12 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseFirstPartOfThreelevelTree) {
auto root = CreateThreeLevel(); auto root = CreateThreeLevel();
//Traverse all leaves in the first two children of the root //Traverse all leaves in the first two children of the root
for(unsigned int i = 0; i < 2; ++i) { for(unsigned int i = 0; i < 2; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
} }
//Traverse some of the leaves in the third child of the root //Traverse some of the leaves in the third child of the root
auto child = LoadInnerNode(root->getChild(2)->key()); auto child = LoadInnerNode(root->getChild(2)->key());
for(unsigned int i = 0; i < 5; ++i) { for(unsigned int i = 0; i < 5; ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 2 * nodeStore->layout().maxChildrenPerInnerNode() + i); EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, 2 * nodeStore->layout().maxChildrenPerInnerNode() + i);
} }
TraverseLeaves(root.get(), 0, 2 * nodeStore->layout().maxChildrenPerInnerNode() + 5); TraverseLeaves(root.get(), 0, 2 * nodeStore->layout().maxChildrenPerInnerNode() + 5);
@ -274,16 +274,16 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddlePartOfThreelevelTree_OnlyFullC
//Traverse some of the leaves in the second child of the root //Traverse some of the leaves in the second child of the root
auto child = LoadInnerNode(root->getChild(1)->key()); auto child = LoadInnerNode(root->getChild(1)->key());
for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode() + i); EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, nodeStore->layout().maxChildrenPerInnerNode() + i);
} }
//Traverse all leaves in the third and fourth child of the root //Traverse all leaves in the third and fourth child of the root
for(unsigned int i = 2; i < 4; ++i) { for(unsigned int i = 2; i < 4; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()),false, i * nodeStore->layout().maxChildrenPerInnerNode());
} }
//Traverse some of the leaves in the fifth child of the root //Traverse some of the leaves in the fifth child of the root
child = LoadInnerNode(root->getChild(4)->key()); child = LoadInnerNode(root->getChild(4)->key());
for(unsigned int i = 0; i < 5; ++i) { for(unsigned int i = 0; i < 5; ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 4 * nodeStore->layout().maxChildrenPerInnerNode() + i); EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, 4 * nodeStore->layout().maxChildrenPerInnerNode() + i);
} }
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 4 * nodeStore->layout().maxChildrenPerInnerNode() + 5); TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 4 * nodeStore->layout().maxChildrenPerInnerNode() + 5);
@ -294,16 +294,16 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddlePartOfThreelevelTree_AlsoLastN
//Traverse some of the leaves in the second child of the root //Traverse some of the leaves in the second child of the root
auto child = LoadInnerNode(root->getChild(1)->key()); auto child = LoadInnerNode(root->getChild(1)->key());
for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode() + i); EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, nodeStore->layout().maxChildrenPerInnerNode() + i);
} }
//Traverse all leaves in the third, fourth and fifth child of the root //Traverse all leaves in the third, fourth and fifth child of the root
for(unsigned int i = 2; i < 5; ++i) { for(unsigned int i = 2; i < 5; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
} }
//Traverse some of the leaves in the sixth child of the root //Traverse some of the leaves in the sixth child of the root
child = LoadInnerNode(root->getChild(5)->key()); child = LoadInnerNode(root->getChild(5)->key());
for(unsigned int i = 0; i < 2; ++i) { for(unsigned int i = 0; i < 2; ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i);
} }
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + 2); TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + 2);
@ -314,16 +314,16 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseLastPartOfThreelevelTree) {
//Traverse some of the leaves in the second child of the root //Traverse some of the leaves in the second child of the root
auto child = LoadInnerNode(root->getChild(1)->key()); auto child = LoadInnerNode(root->getChild(1)->key());
for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode() + i); EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), false, nodeStore->layout().maxChildrenPerInnerNode() + i);
} }
//Traverse all leaves in the third, fourth and fifth child of the root //Traverse all leaves in the third, fourth and fifth child of the root
for(unsigned int i = 2; i < 5; ++i) { for(unsigned int i = 2; i < 5; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
} }
//Traverse all of the leaves in the sixth child of the root //Traverse all of the leaves in the sixth child of the root
child = LoadInnerNode(root->getChild(5)->key()); child = LoadInnerNode(root->getChild(5)->key());
for(unsigned int i = 0; i < child->numChildren(); ++i) { for(unsigned int i = 0; i < child->numChildren(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), i == child->numChildren()-1, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i);
} }
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren()); TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren());
@ -333,12 +333,12 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfThreelevelTree) {
auto root = CreateThreeLevel(); auto root = CreateThreeLevel();
//Traverse all leaves in the third, fourth and fifth child of the root //Traverse all leaves in the third, fourth and fifth child of the root
for(unsigned int i = 0; i < 5; ++i) { for(unsigned int i = 0; i < 5; ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
} }
//Traverse all of the leaves in the sixth child of the root //Traverse all of the leaves in the sixth child of the root
auto child = LoadInnerNode(root->getChild(5)->key()); auto child = LoadInnerNode(root->getChild(5)->key());
for(unsigned int i = 0; i < child->numChildren(); ++i) { for(unsigned int i = 0; i < child->numChildren(); ++i) {
EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); EXPECT_TRAVERSE_LEAF(child->getChild(i)->key(), i==child->numChildren()-1, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i);
} }
TraverseLeaves(root.get(), 0, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren()); TraverseLeaves(root.get(), 0, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren());
@ -349,17 +349,17 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseAllLeavesOfFourLevelTree) {
//Traverse all leaves of the full threelevel tree in the first child //Traverse all leaves of the full threelevel tree in the first child
auto firstChild = LoadInnerNode(root->getChild(0)->key()); auto firstChild = LoadInnerNode(root->getChild(0)->key());
for(unsigned int i = 0; i < firstChild->numChildren(); ++i) { for(unsigned int i = 0; i < firstChild->numChildren(); ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
} }
//Traverse all leaves of the full threelevel tree in the second child //Traverse all leaves of the full threelevel tree in the second child
auto secondChild = LoadInnerNode(root->getChild(1)->key()); auto secondChild = LoadInnerNode(root->getChild(1)->key());
for(unsigned int i = 0; i < secondChild->numChildren(); ++i) { for(unsigned int i = 0; i < secondChild->numChildren(); ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), false, (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode());
} }
//Traverse all leaves of the non-full threelevel tree in the third child //Traverse all leaves of the non-full threelevel tree in the third child
auto thirdChild = LoadInnerNode(root->getChild(2)->key()); auto thirdChild = LoadInnerNode(root->getChild(2)->key());
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(thirdChild->getChild(0)->key()), 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(thirdChild->getChild(0)->key()), false, 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode());
EXPECT_TRAVERSE_LEAF(LoadInnerNode(thirdChild->getChild(1)->key())->getChild(0)->key(), 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_LEAF(LoadInnerNode(thirdChild->getChild(1)->key())->getChild(0)->key(), true, 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode());
TraverseLeaves(root.get(), 0, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() + 1); TraverseLeaves(root.get(), 0, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() + 1);
} }
@ -370,21 +370,21 @@ TEST_F(DataTreeTest_TraverseLeaves, TraverseMiddlePartOfFourLevelTree) {
auto firstChild = LoadInnerNode(root->getChild(0)->key()); auto firstChild = LoadInnerNode(root->getChild(0)->key());
auto secondChildOfFirstChild = LoadInnerNode(firstChild->getChild(1)->key()); auto secondChildOfFirstChild = LoadInnerNode(firstChild->getChild(1)->key());
for(unsigned int i = 5; i < secondChildOfFirstChild->numChildren(); ++i) { for(unsigned int i = 5; i < secondChildOfFirstChild->numChildren(); ++i) {
EXPECT_TRAVERSE_LEAF(secondChildOfFirstChild->getChild(i)->key(), nodeStore->layout().maxChildrenPerInnerNode()+i); EXPECT_TRAVERSE_LEAF(secondChildOfFirstChild->getChild(i)->key(), false, nodeStore->layout().maxChildrenPerInnerNode()+i);
} }
for(unsigned int i = 2; i < firstChild->numChildren(); ++i) { for(unsigned int i = 2; i < firstChild->numChildren(); ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), i * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->getChild(i)->key()), false, i * nodeStore->layout().maxChildrenPerInnerNode());
} }
//Traverse all leaves of the full threelevel tree in the second child //Traverse all leaves of the full threelevel tree in the second child
auto secondChild = LoadInnerNode(root->getChild(1)->key()); auto secondChild = LoadInnerNode(root->getChild(1)->key());
for(unsigned int i = 0; i < secondChild->numChildren(); ++i) { for(unsigned int i = 0; i < secondChild->numChildren(); ++i) {
EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode()); EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->getChild(i)->key()), false, (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode());
} }
//Traverse some leaves of the non-full threelevel tree in the third child //Traverse some leaves of the non-full threelevel tree in the third child
auto thirdChild = LoadInnerNode(root->getChild(2)->key()); auto thirdChild = LoadInnerNode(root->getChild(2)->key());
auto firstChildOfThirdChild = LoadInnerNode(thirdChild->getChild(0)->key()); auto firstChildOfThirdChild = LoadInnerNode(thirdChild->getChild(0)->key());
for(unsigned int i = 0; i < firstChildOfThirdChild->numChildren()-1; ++i) { for(unsigned int i = 0; i < firstChildOfThirdChild->numChildren()-1; ++i) {
EXPECT_TRAVERSE_LEAF(firstChildOfThirdChild->getChild(i)->key(), 2 * nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode()+i); EXPECT_TRAVERSE_LEAF(firstChildOfThirdChild->getChild(i)->key(), false, 2 * nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode()+i);
} }
TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode()+5, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() -1); TraverseLeaves(root.get(), nodeStore->layout().maxChildrenPerInnerNode()+5, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() -1);
@ -394,7 +394,7 @@ TEST_F(DataTreeTest_TraverseLeaves, LastLeafIsAlreadyResizedInCallback) {
auto root = CreateLeaf(); auto root = CreateLeaf();
root->flush(); root->flush();
auto tree = treeStore.load(root->key()).value(); auto tree = treeStore.load(root->key()).value();
tree->traverseLeaves(0, 2, [this] (uint32_t leafIndex, LeafHandle leaf) { tree->traverseLeaves(0, 2, [this] (uint32_t leafIndex, bool /*isRightBorderNode*/, LeafHandle leaf) {
if (leafIndex == 0) { if (leafIndex == 0) {
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes()); EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes());
} else { } else {
@ -409,7 +409,7 @@ TEST_F(DataTreeTest_TraverseLeaves, LastLeafIsAlreadyResizedInCallback_TwoLevel)
auto root = CreateFullTwoLevelWithLastLeafSize(5); auto root = CreateFullTwoLevelWithLastLeafSize(5);
root->flush(); root->flush();
auto tree = treeStore.load(root->key()).value(); auto tree = treeStore.load(root->key()).value();
tree->traverseLeaves(0, nodeStore->layout().maxChildrenPerInnerNode()+1, [this] (uint32_t /*leafIndex*/, LeafHandle leaf) { tree->traverseLeaves(0, nodeStore->layout().maxChildrenPerInnerNode()+1, [this] (uint32_t /*leafIndex*/, bool /*isRightBorderNode*/, LeafHandle leaf) {
EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes()); EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes());
}, [this] (uint32_t /*nodeIndex*/) -> Data { }, [this] (uint32_t /*nodeIndex*/) -> Data {
return Data(1); return Data(1);