2015-01-23 04:39:36 +01:00
|
|
|
#include "DataTree.h"
|
|
|
|
|
2015-02-17 00:40:34 +01:00
|
|
|
#include "../datanodestore/DataNodeStore.h"
|
|
|
|
#include "../datanodestore/DataInnerNode.h"
|
|
|
|
#include "../datanodestore/DataLeafNode.h"
|
2015-02-26 20:19:12 +01:00
|
|
|
#include "../utils/Math.h"
|
2015-01-23 04:39:36 +01:00
|
|
|
|
2015-02-21 01:58:23 +01:00
|
|
|
#include "impl/algorithms.h"
|
2015-01-26 00:38:06 +01:00
|
|
|
|
2015-06-21 17:43:45 +02:00
|
|
|
#include "messmer/cpp-utils/pointer/cast.h"
|
|
|
|
#include "messmer/cpp-utils/pointer/optional_ownership_ptr.h"
|
2015-02-25 01:31:16 +01:00
|
|
|
#include <cmath>
|
2015-07-22 13:42:44 +02:00
|
|
|
#include <messmer/cpp-utils/assert/assert.h>
|
2015-01-23 04:39:36 +01:00
|
|
|
|
|
|
|
using blockstore::Key;
|
|
|
|
using blobstore::onblocks::datanodestore::DataNodeStore;
|
|
|
|
using blobstore::onblocks::datanodestore::DataNode;
|
|
|
|
using blobstore::onblocks::datanodestore::DataInnerNode;
|
|
|
|
using blobstore::onblocks::datanodestore::DataLeafNode;
|
2015-02-26 20:19:12 +01:00
|
|
|
using blobstore::onblocks::datanodestore::DataNodeLayout;
|
2015-01-23 04:39:36 +01:00
|
|
|
|
2015-01-23 18:32:26 +01:00
|
|
|
using std::dynamic_pointer_cast;
|
|
|
|
using std::function;
|
2015-04-09 16:10:57 +02:00
|
|
|
using boost::shared_mutex;
|
|
|
|
using boost::shared_lock;
|
|
|
|
using boost::unique_lock;
|
2015-06-26 15:59:18 +02:00
|
|
|
using boost::none;
|
2015-04-10 21:52:30 +02:00
|
|
|
using std::vector;
|
2015-01-23 04:39:36 +01:00
|
|
|
|
2015-02-17 00:40:34 +01:00
|
|
|
using cpputils::dynamic_pointer_move;
|
|
|
|
using cpputils::optional_ownership_ptr;
|
2015-02-26 17:33:47 +01:00
|
|
|
using cpputils::WithOwnership;
|
|
|
|
using cpputils::WithoutOwnership;
|
2015-06-26 15:59:18 +02:00
|
|
|
using cpputils::unique_ref;
|
2015-01-23 04:39:36 +01:00
|
|
|
|
|
|
|
namespace blobstore {
|
|
|
|
namespace onblocks {
|
|
|
|
namespace datatreestore {
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
DataTree::DataTree(DataNodeStore *nodeStore, unique_ref<DataNode> rootNode)
|
2015-04-09 16:10:57 +02:00
|
|
|
: _mutex(), _nodeStore(nodeStore), _rootNode(std::move(rootNode)) {
|
2015-01-23 04:39:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DataTree::~DataTree() {
|
|
|
|
}
|
|
|
|
|
2015-02-21 01:58:23 +01:00
|
|
|
void DataTree::removeLastDataLeaf() {
|
2015-02-22 19:30:42 +01:00
|
|
|
auto deletePosOrNull = algorithms::GetLowestRightBorderNodeWithMoreThanOneChildOrNull(_nodeStore, _rootNode.get());
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(deletePosOrNull.get() != nullptr, "Tree has only one leaf, can't shrink it.");
|
2015-02-22 19:30:42 +01:00
|
|
|
|
|
|
|
deleteLastChildSubtree(deletePosOrNull.get());
|
|
|
|
|
|
|
|
ifRootHasOnlyOneChildReplaceRootWithItsChild();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DataTree::ifRootHasOnlyOneChildReplaceRootWithItsChild() {
|
2015-02-21 01:58:23 +01:00
|
|
|
DataInnerNode *rootNode = dynamic_cast<DataInnerNode*>(_rootNode.get());
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(rootNode != nullptr, "RootNode is not an inner node");
|
2015-02-22 19:30:42 +01:00
|
|
|
if (rootNode->numChildren() == 1) {
|
|
|
|
auto child = _nodeStore->load(rootNode->getChild(0)->key());
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(child != none, "Couldn't load first child of root node");
|
2015-06-26 15:59:18 +02:00
|
|
|
_rootNode = _nodeStore->overwriteNodeWith(std::move(_rootNode), **child);
|
|
|
|
_nodeStore->remove(std::move(*child));
|
2015-02-22 19:30:42 +01:00
|
|
|
}
|
|
|
|
}
|
2015-02-21 01:58:23 +01:00
|
|
|
|
2015-02-22 19:30:42 +01:00
|
|
|
void DataTree::deleteLastChildSubtree(DataInnerNode *node) {
|
2015-02-24 23:11:20 +01:00
|
|
|
auto lastChild = _nodeStore->load(node->LastChild()->key());
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(lastChild != none, "Couldn't load last child");
|
2015-06-26 15:59:18 +02:00
|
|
|
_nodeStore->removeSubtree(std::move(*lastChild));
|
2015-02-22 19:30:42 +01:00
|
|
|
node->removeLastChild();
|
|
|
|
}
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
unique_ref<DataLeafNode> DataTree::addDataLeaf() {
|
2015-02-21 01:58:23 +01:00
|
|
|
auto insertPosOrNull = algorithms::GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(_nodeStore, _rootNode.get());
|
2015-01-23 04:39:36 +01:00
|
|
|
if (insertPosOrNull) {
|
2015-01-23 18:32:26 +01:00
|
|
|
return addDataLeafAt(insertPosOrNull.get());
|
2015-01-23 04:39:36 +01:00
|
|
|
} else {
|
2015-01-23 18:32:26 +01:00
|
|
|
return addDataLeafToFullTree();
|
2015-01-23 04:39:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
unique_ref<DataLeafNode> DataTree::addDataLeafAt(DataInnerNode *insertPos) {
|
2015-01-23 04:39:36 +01:00
|
|
|
auto new_leaf = _nodeStore->createNewLeafNode();
|
2015-01-23 18:32:26 +01:00
|
|
|
auto chain = createChainOfInnerNodes(insertPos->depth()-1, new_leaf.get());
|
|
|
|
insertPos->addChild(*chain);
|
2015-01-23 04:39:36 +01:00
|
|
|
return new_leaf;
|
|
|
|
}
|
|
|
|
|
2015-04-10 21:52:30 +02:00
|
|
|
optional_ownership_ptr<DataNode> DataTree::createChainOfInnerNodes(unsigned int num, DataNode *child) {
|
2015-06-26 15:59:18 +02:00
|
|
|
//TODO This function is implemented twice, once with optional_ownership_ptr, once with unique_ref. Redundancy!
|
2015-04-10 21:52:30 +02:00
|
|
|
optional_ownership_ptr<DataNode> chain = cpputils::WithoutOwnership<DataNode>(child);
|
2015-01-23 18:32:26 +01:00
|
|
|
for(unsigned int i=0; i<num; ++i) {
|
|
|
|
auto newnode = _nodeStore->createNewInnerNode(*chain);
|
2015-07-21 15:24:49 +02:00
|
|
|
chain = cpputils::WithOwnership<DataNode>(std::move(newnode));
|
2015-01-23 04:39:36 +01:00
|
|
|
}
|
|
|
|
return chain;
|
|
|
|
}
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
unique_ref<DataNode> DataTree::createChainOfInnerNodes(unsigned int num, unique_ref<DataNode> child) {
|
|
|
|
unique_ref<DataNode> chain = std::move(child);
|
2015-04-10 21:52:30 +02:00
|
|
|
for(unsigned int i=0; i<num; ++i) {
|
|
|
|
chain = _nodeStore->createNewInnerNode(*chain);
|
|
|
|
}
|
|
|
|
return chain;
|
|
|
|
}
|
|
|
|
|
|
|
|
DataInnerNode* DataTree::increaseTreeDepth(unsigned int levels) {
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(levels >= 1, "Parameter out of bounds: tried to increase tree depth by zero.");
|
2015-01-24 01:59:42 +01:00
|
|
|
auto copyOfOldRoot = _nodeStore->createNewNodeAsCopyFrom(*_rootNode);
|
2015-04-10 21:52:30 +02:00
|
|
|
auto chain = createChainOfInnerNodes(levels-1, copyOfOldRoot.get());
|
|
|
|
auto newRootNode = DataNode::convertToNewInnerNode(std::move(_rootNode), *chain);
|
|
|
|
DataInnerNode *result = newRootNode.get();
|
2015-01-24 00:54:27 +01:00
|
|
|
_rootNode = std::move(newRootNode);
|
2015-04-10 21:52:30 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
unique_ref<DataLeafNode> DataTree::addDataLeafToFullTree() {
|
2015-04-10 21:52:30 +02:00
|
|
|
DataInnerNode *rootNode = increaseTreeDepth(1);
|
|
|
|
auto newLeaf = addDataLeafAt(rootNode);
|
2015-01-24 00:54:27 +01:00
|
|
|
return newLeaf;
|
2015-01-23 04:39:36 +01:00
|
|
|
}
|
|
|
|
|
2015-01-27 00:54:25 +01:00
|
|
|
const Key &DataTree::key() const {
|
|
|
|
return _rootNode->key();
|
|
|
|
}
|
2015-01-23 04:39:36 +01:00
|
|
|
|
2015-01-28 01:02:32 +01:00
|
|
|
void DataTree::flush() const {
|
|
|
|
_rootNode->flush();
|
|
|
|
}
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
unique_ref<DataNode> DataTree::releaseRootNode() {
|
2015-02-24 22:44:10 +01:00
|
|
|
return std::move(_rootNode);
|
|
|
|
}
|
|
|
|
|
2015-04-10 22:57:29 +02:00
|
|
|
//TODO Test numLeaves(), for example also two configurations with same number of bytes but different number of leaves (last leaf has 0 bytes)
|
2015-04-10 21:52:30 +02:00
|
|
|
uint32_t DataTree::numLeaves() const {
|
2015-09-30 10:02:06 +02:00
|
|
|
shared_lock<shared_mutex> lock(_mutex);
|
2015-04-10 22:57:29 +02:00
|
|
|
return _numLeaves(*_rootNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t DataTree::_numLeaves(const DataNode &node) const {
|
|
|
|
const DataLeafNode *leaf = dynamic_cast<const DataLeafNode*>(&node);
|
|
|
|
if (leaf != nullptr) {
|
|
|
|
return 1;
|
2015-04-10 21:52:30 +02:00
|
|
|
}
|
2015-04-10 22:57:29 +02:00
|
|
|
|
|
|
|
const DataInnerNode &inner = dynamic_cast<const DataInnerNode&>(node);
|
|
|
|
uint64_t numLeavesInLeftChildren = (inner.numChildren()-1) * leavesPerFullChild(inner);
|
|
|
|
auto lastChild = _nodeStore->load(inner.LastChild()->key());
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(lastChild != none, "Couldn't load last child");
|
2015-06-26 15:59:18 +02:00
|
|
|
uint64_t numLeavesInRightChild = _numLeaves(**lastChild);
|
2015-04-10 22:57:29 +02:00
|
|
|
|
|
|
|
return numLeavesInLeftChildren + numLeavesInRightChild;
|
2015-03-04 03:17:59 +01:00
|
|
|
}
|
|
|
|
|
2015-04-10 21:52:30 +02:00
|
|
|
void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function<void (DataLeafNode*, uint32_t)> func) {
|
|
|
|
unique_lock<shared_mutex> lock(_mutex); //TODO Only lock when resizing
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(beginIndex <= endIndex, "Invalid parameters");
|
2015-04-10 21:52:30 +02:00
|
|
|
|
|
|
|
uint8_t neededTreeDepth = utils::ceilLog(_nodeStore->layout().maxChildrenPerInnerNode(), endIndex);
|
2015-09-30 10:02:06 +02:00
|
|
|
uint32_t numLeaves = this->_numLeaves(*_rootNode);
|
2015-04-10 21:52:30 +02:00
|
|
|
if (_rootNode->depth() < neededTreeDepth) {
|
|
|
|
//TODO Test cases that actually increase it here by 0 level / 1 level / more than 1 level
|
|
|
|
increaseTreeDepth(neededTreeDepth - _rootNode->depth());
|
|
|
|
}
|
2015-04-10 22:57:29 +02:00
|
|
|
|
|
|
|
if (numLeaves <= beginIndex) {
|
2015-04-10 21:52:30 +02:00
|
|
|
//TODO Test cases with numLeaves < / >= beginIndex
|
2015-04-10 22:57:29 +02:00
|
|
|
// There is a gap between the current size and the begin of the traversal
|
|
|
|
return _traverseLeaves(_rootNode.get(), 0, numLeaves-1, endIndex, [beginIndex, numLeaves, &func, this](DataLeafNode* node, uint32_t index) {
|
2015-04-10 21:52:30 +02:00
|
|
|
if (index >= beginIndex) {
|
|
|
|
func(node, index);
|
2015-04-10 22:57:29 +02:00
|
|
|
} else if (index == numLeaves - 1) {
|
|
|
|
// It is the old last leaf - resize it to maximum
|
|
|
|
node->resize(_nodeStore->layout().maxBytesPerLeaf());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else if (numLeaves < endIndex) {
|
|
|
|
// We are starting traversal in the valid region, but traverse until after it (we grow new leaves)
|
|
|
|
return _traverseLeaves(_rootNode.get(), 0, beginIndex, endIndex, [numLeaves, &func, this] (DataLeafNode *node, uint32_t index) {
|
|
|
|
if (index == numLeaves - 1) {
|
|
|
|
// It is the old last leaf - resize it to maximum
|
|
|
|
node->resize(_nodeStore->layout().maxBytesPerLeaf());
|
2015-04-10 21:52:30 +02:00
|
|
|
}
|
2015-04-10 22:57:29 +02:00
|
|
|
func(node, index);
|
2015-04-10 21:52:30 +02:00
|
|
|
});
|
|
|
|
} else {
|
2015-09-30 10:02:06 +02:00
|
|
|
//We are traversing entirely inside the valid region
|
2015-04-10 22:57:29 +02:00
|
|
|
_traverseLeaves(_rootNode.get(), 0, beginIndex, endIndex, func);
|
2015-04-10 21:52:30 +02:00
|
|
|
}
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
|
|
|
|
2015-04-10 21:52:30 +02:00
|
|
|
void DataTree::_traverseLeaves(DataNode *root, uint32_t leafOffset, uint32_t beginIndex, uint32_t endIndex, function<void (DataLeafNode*, uint32_t)> func) {
|
|
|
|
DataLeafNode *leaf = dynamic_cast<DataLeafNode*>(root);
|
2015-02-25 01:31:16 +01:00
|
|
|
if (leaf != nullptr) {
|
2015-07-22 13:42:44 +02:00
|
|
|
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.");
|
2015-02-25 01:31:16 +01:00
|
|
|
if (beginIndex == 0 && endIndex == 1) {
|
|
|
|
func(leaf, leafOffset);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-10 21:52:30 +02:00
|
|
|
DataInnerNode *inner = dynamic_cast<DataInnerNode*>(root);
|
2015-02-25 23:08:16 +01:00
|
|
|
uint32_t leavesPerChild = leavesPerFullChild(*inner);
|
2015-02-25 01:31:16 +01:00
|
|
|
uint32_t beginChild = beginIndex/leavesPerChild;
|
2015-02-26 20:19:12 +01:00
|
|
|
uint32_t endChild = utils::ceilDivision(endIndex, leavesPerChild);
|
2015-06-26 15:59:18 +02:00
|
|
|
vector<unique_ref<DataNode>> children = getOrCreateChildren(inner, beginChild, endChild);
|
2015-02-25 01:31:16 +01:00
|
|
|
|
|
|
|
for (uint32_t childIndex = beginChild; childIndex < endChild; ++childIndex) {
|
|
|
|
uint32_t childOffset = childIndex * leavesPerChild;
|
2015-02-26 20:19:12 +01:00
|
|
|
uint32_t localBeginIndex = utils::maxZeroSubtraction(beginIndex, childOffset);
|
2015-02-25 01:31:16 +01:00
|
|
|
uint32_t localEndIndex = std::min(leavesPerChild, endIndex - childOffset);
|
2015-04-10 21:52:30 +02:00
|
|
|
auto child = std::move(children[childIndex-beginChild]);
|
|
|
|
_traverseLeaves(child.get(), leafOffset + childOffset, localBeginIndex, localEndIndex, func);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
vector<unique_ref<DataNode>> DataTree::getOrCreateChildren(DataInnerNode *node, uint32_t begin, uint32_t end) {
|
|
|
|
vector<unique_ref<DataNode>> children;
|
2015-04-10 21:52:30 +02:00
|
|
|
children.reserve(end-begin);
|
|
|
|
for (uint32_t childIndex = begin; childIndex < std::min(node->numChildren(), end); ++childIndex) {
|
2015-06-26 15:59:18 +02:00
|
|
|
auto child = _nodeStore->load(node->getChild(childIndex)->key());
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(child != none, "Couldn't load child node");
|
2015-06-26 15:59:18 +02:00
|
|
|
children.emplace_back(std::move(*child));
|
2015-04-10 21:52:30 +02:00
|
|
|
}
|
|
|
|
for (uint32_t childIndex = node->numChildren(); childIndex < end; ++childIndex) {
|
2015-09-30 10:02:06 +02:00
|
|
|
//TODO This creates each child with one chain to one leaf only, and then on the next lower level it
|
|
|
|
// has to create the children for the child. Would be faster to directly create full trees if necessary.
|
2015-04-10 21:52:30 +02:00
|
|
|
children.emplace_back(addChildTo(node));
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(children.size() == end-begin, "Number of children in the result is wrong");
|
2015-04-10 21:52:30 +02:00
|
|
|
return children;
|
|
|
|
}
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
unique_ref<DataNode> DataTree::addChildTo(DataInnerNode *node) {
|
2015-04-10 21:52:30 +02:00
|
|
|
auto new_leaf = _nodeStore->createNewLeafNode();
|
|
|
|
new_leaf->resize(_nodeStore->layout().maxBytesPerLeaf());
|
|
|
|
auto chain = createChainOfInnerNodes(node->depth()-1, std::move(new_leaf));
|
|
|
|
node->addChild(*chain);
|
|
|
|
return std::move(chain);
|
2015-02-25 01:31:16 +01:00
|
|
|
}
|
2015-01-23 04:39:36 +01:00
|
|
|
|
2015-02-25 23:08:16 +01:00
|
|
|
uint32_t DataTree::leavesPerFullChild(const DataInnerNode &root) const {
|
2015-02-26 20:19:12 +01:00
|
|
|
return utils::intPow(_nodeStore->layout().maxChildrenPerInnerNode(), root.depth()-1);
|
2015-02-25 23:08:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t DataTree::numStoredBytes() const {
|
2015-04-09 16:30:36 +02:00
|
|
|
shared_lock<shared_mutex> lock(_mutex);
|
|
|
|
return _numStoredBytes();
|
2015-02-25 23:08:16 +01:00
|
|
|
}
|
|
|
|
|
2015-04-09 16:30:36 +02:00
|
|
|
uint64_t DataTree::_numStoredBytes() const {
|
|
|
|
return _numStoredBytes(*_rootNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t DataTree::_numStoredBytes(const DataNode &root) const {
|
2015-02-25 23:08:16 +01:00
|
|
|
const DataLeafNode *leaf = dynamic_cast<const DataLeafNode*>(&root);
|
|
|
|
if (leaf != nullptr) {
|
|
|
|
return leaf->numBytes();
|
|
|
|
}
|
|
|
|
|
|
|
|
const DataInnerNode &inner = dynamic_cast<const DataInnerNode&>(root);
|
2015-02-26 17:04:02 +01:00
|
|
|
uint64_t numBytesInLeftChildren = (inner.numChildren()-1) * leavesPerFullChild(inner) * _nodeStore->layout().maxBytesPerLeaf();
|
2015-02-25 23:08:16 +01:00
|
|
|
auto lastChild = _nodeStore->load(inner.LastChild()->key());
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(lastChild != none, "Couldn't load last child");
|
2015-06-26 15:59:18 +02:00
|
|
|
uint64_t numBytesInRightChild = _numStoredBytes(**lastChild);
|
2015-02-25 23:08:16 +01:00
|
|
|
|
|
|
|
return numBytesInLeftChildren + numBytesInRightChild;
|
|
|
|
}
|
|
|
|
|
2015-02-26 17:33:47 +01:00
|
|
|
void DataTree::resizeNumBytes(uint64_t newNumBytes) {
|
2015-04-09 16:30:36 +02:00
|
|
|
boost::upgrade_lock<shared_mutex> lock(_mutex);
|
|
|
|
{
|
|
|
|
boost::upgrade_to_unique_lock<shared_mutex> exclusiveLock(lock);
|
|
|
|
//TODO Faster implementation possible (no addDataLeaf()/removeLastDataLeaf() in a loop, but directly resizing)
|
|
|
|
LastLeaf(_rootNode.get())->resize(_nodeStore->layout().maxBytesPerLeaf());
|
|
|
|
uint64_t currentNumBytes = _numStoredBytes();
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(currentNumBytes % _nodeStore->layout().maxBytesPerLeaf() == 0, "The last leaf is not a max data leaf, although we just resized it to be one.");
|
2015-04-09 16:30:36 +02:00
|
|
|
uint32_t currentNumLeaves = currentNumBytes / _nodeStore->layout().maxBytesPerLeaf();
|
|
|
|
uint32_t newNumLeaves = std::max(1u, utils::ceilDivision(newNumBytes, _nodeStore->layout().maxBytesPerLeaf()));
|
|
|
|
|
|
|
|
for(uint32_t i = currentNumLeaves; i < newNumLeaves; ++i) {
|
|
|
|
addDataLeaf()->resize(_nodeStore->layout().maxBytesPerLeaf());
|
|
|
|
}
|
|
|
|
for(uint32_t i = currentNumLeaves; i > newNumLeaves; --i) {
|
|
|
|
removeLastDataLeaf();
|
|
|
|
}
|
|
|
|
uint32_t newLastLeafSize = newNumBytes - (newNumLeaves-1)*_nodeStore->layout().maxBytesPerLeaf();
|
|
|
|
LastLeaf(_rootNode.get())->resize(newLastLeafSize);
|
2015-02-26 17:33:47 +01:00
|
|
|
}
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(newNumBytes == numStoredBytes(), "We resized to the wrong number of bytes");
|
2015-02-26 17:33:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
optional_ownership_ptr<DataLeafNode> DataTree::LastLeaf(DataNode *root) {
|
|
|
|
DataLeafNode *leaf = dynamic_cast<DataLeafNode*>(root);
|
|
|
|
if (leaf != nullptr) {
|
|
|
|
return WithoutOwnership(leaf);
|
|
|
|
}
|
|
|
|
|
|
|
|
DataInnerNode *inner = dynamic_cast<DataInnerNode*>(root);
|
2015-06-26 15:59:18 +02:00
|
|
|
auto lastChild = _nodeStore->load(inner->LastChild()->key());
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(lastChild != none, "Couldn't load last child");
|
2015-07-21 15:24:49 +02:00
|
|
|
return WithOwnership(LastLeaf(std::move(*lastChild)));
|
2015-02-26 17:33:47 +01:00
|
|
|
}
|
|
|
|
|
2015-06-26 15:59:18 +02:00
|
|
|
unique_ref<DataLeafNode> DataTree::LastLeaf(unique_ref<DataNode> root) {
|
2015-02-26 17:33:47 +01:00
|
|
|
auto leaf = dynamic_pointer_move<DataLeafNode>(root);
|
2015-06-26 15:59:18 +02:00
|
|
|
if (leaf != none) {
|
|
|
|
return std::move(*leaf);
|
2015-02-26 17:33:47 +01:00
|
|
|
}
|
|
|
|
auto inner = dynamic_pointer_move<DataInnerNode>(root);
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(inner != none, "Root node is neither a leaf nor an inner node");
|
2015-06-26 15:59:18 +02:00
|
|
|
auto child = _nodeStore->load((*inner)->LastChild()->key());
|
2015-07-22 13:42:44 +02:00
|
|
|
ASSERT(child != none, "Couldn't load last child");
|
2015-06-26 15:59:18 +02:00
|
|
|
return LastLeaf(std::move(*child));
|
2015-02-26 17:33:47 +01:00
|
|
|
}
|
|
|
|
|
2015-02-26 20:19:12 +01:00
|
|
|
uint32_t DataTree::maxBytesPerLeaf() const {
|
|
|
|
return _nodeStore->layout().maxBytesPerLeaf();
|
|
|
|
}
|
|
|
|
|
2015-01-23 04:39:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|