Minimize number of Block::write() calls when creating new nodes in a traversal. Also add test cases for it.
This commit is contained in:
parent
d626349802
commit
c428d5642a
@ -3,10 +3,12 @@
|
||||
#include <cpp-utils/assert/assert.h>
|
||||
|
||||
using blockstore::Block;
|
||||
using blockstore::BlockStore;
|
||||
using cpputils::Data;
|
||||
using cpputils::unique_ref;
|
||||
using cpputils::make_unique_ref;
|
||||
using blockstore::Key;
|
||||
using std::vector;
|
||||
|
||||
namespace blobstore {
|
||||
namespace onblocks {
|
||||
@ -23,14 +25,27 @@ DataInnerNode::DataInnerNode(DataNodeView view)
|
||||
DataInnerNode::~DataInnerNode() {
|
||||
}
|
||||
|
||||
unique_ref<DataInnerNode> DataInnerNode::InitializeNewNode(unique_ref<Block> block, const DataNode &first_child) {
|
||||
DataNodeView node(std::move(block));
|
||||
node.setFormatVersion(DataNode::FORMAT_VERSION_HEADER);
|
||||
node.setDepth(first_child.depth() + 1);
|
||||
node.setSize(1);
|
||||
auto result = make_unique_ref<DataInnerNode>(std::move(node));
|
||||
result->ChildrenBegin()->setKey(first_child.key());
|
||||
return result;
|
||||
unique_ref<DataInnerNode> DataInnerNode::InitializeNewNode(unique_ref<Block> block, const DataNodeLayout &layout, uint8_t depth, const vector<Key> &children) {
|
||||
ASSERT(children.size() >= 1, "An inner node must have at least one child");
|
||||
Data data = _serializeChildren(children);
|
||||
|
||||
return make_unique_ref<DataInnerNode>(DataNodeView::initialize(std::move(block), layout, DataNode::FORMAT_VERSION_HEADER, depth, children.size(), std::move(data)));
|
||||
}
|
||||
|
||||
unique_ref<DataInnerNode> DataInnerNode::CreateNewNode(BlockStore *blockStore, const DataNodeLayout &layout, uint8_t depth, const vector<Key> &children) {
|
||||
ASSERT(children.size() >= 1, "An inner node must have at least one child");
|
||||
Data data = _serializeChildren(children);
|
||||
|
||||
return make_unique_ref<DataInnerNode>(DataNodeView::create(blockStore, layout, DataNode::FORMAT_VERSION_HEADER, depth, children.size(), std::move(data)));
|
||||
}
|
||||
|
||||
Data DataInnerNode::_serializeChildren(const vector<Key> &children) {
|
||||
Data data(sizeof(ChildEntry) * children.size());
|
||||
uint32_t i = 0;
|
||||
for (const Key &child : children) {
|
||||
reinterpret_cast<ChildEntry*>(data.data())[i++].setKey(child);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
uint32_t DataInnerNode::numChildren() const {
|
||||
|
@ -11,7 +11,8 @@ namespace datanodestore {
|
||||
|
||||
class DataInnerNode final: public DataNode {
|
||||
public:
|
||||
static cpputils::unique_ref<DataInnerNode> InitializeNewNode(cpputils::unique_ref<blockstore::Block> block, const DataNode &first_child_key);
|
||||
static cpputils::unique_ref<DataInnerNode> InitializeNewNode(cpputils::unique_ref<blockstore::Block> block, const DataNodeLayout &layout, uint8_t depth, const std::vector<blockstore::Key> &children);
|
||||
static cpputils::unique_ref<DataInnerNode> CreateNewNode(blockstore::BlockStore *blockStore, const DataNodeLayout &layout, uint8_t depth, const std::vector<blockstore::Key> &children);
|
||||
|
||||
DataInnerNode(DataNodeView block);
|
||||
~DataInnerNode();
|
||||
@ -39,6 +40,8 @@ private:
|
||||
const ChildEntry *ChildrenBegin() const;
|
||||
const ChildEntry *ChildrenEnd() const;
|
||||
|
||||
static cpputils::Data _serializeChildren(const std::vector<blockstore::Key> &children);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DataInnerNode);
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
using blockstore::Block;
|
||||
using cpputils::Data;
|
||||
using blockstore::Key;
|
||||
using blockstore::BlockStore;
|
||||
using cpputils::unique_ref;
|
||||
using cpputils::make_unique_ref;
|
||||
|
||||
@ -24,13 +25,10 @@ DataLeafNode::DataLeafNode(DataNodeView view)
|
||||
DataLeafNode::~DataLeafNode() {
|
||||
}
|
||||
|
||||
unique_ref<DataLeafNode> DataLeafNode::InitializeNewNode(unique_ref<Block> block) {
|
||||
DataNodeView node(std::move(block));
|
||||
node.setFormatVersion(DataNode::FORMAT_VERSION_HEADER);
|
||||
node.setDepth(0);
|
||||
node.setSize(0);
|
||||
//fillDataWithZeroes(); not needed, because a newly created block will be zeroed out. DataLeafNodeTest.SpaceIsZeroFilledWhenGrowing ensures this.
|
||||
return make_unique_ref<DataLeafNode>(std::move(node));
|
||||
unique_ref<DataLeafNode> DataLeafNode::CreateNewNode(BlockStore *blockStore, const DataNodeLayout &layout, Data data) {
|
||||
ASSERT(data.size() <= layout.maxBytesPerLeaf(), "Data passed in is too large for one leaf.");
|
||||
uint32_t size = data.size();
|
||||
return make_unique_ref<DataLeafNode>(DataNodeView::create(blockStore, layout, DataNode::FORMAT_VERSION_HEADER, 0, size, std::move(data)));
|
||||
}
|
||||
|
||||
void DataLeafNode::read(void *target, uint64_t offset, uint64_t size) const {
|
||||
|
@ -11,7 +11,8 @@ class DataInnerNode;
|
||||
|
||||
class DataLeafNode final: public DataNode {
|
||||
public:
|
||||
static cpputils::unique_ref<DataLeafNode> InitializeNewNode(cpputils::unique_ref<blockstore::Block> block);
|
||||
//static cpputils::unique_ref<DataLeafNode> InitializeNewNode(cpputils::unique_ref<blockstore::Block> block);
|
||||
static cpputils::unique_ref<DataLeafNode> CreateNewNode(blockstore::BlockStore *blockStore, const DataNodeLayout &layout, cpputils::Data data);
|
||||
|
||||
DataLeafNode(DataNodeView block);
|
||||
~DataLeafNode();
|
||||
|
@ -39,11 +39,11 @@ uint8_t DataNode::depth() const {
|
||||
return _node.Depth();
|
||||
}
|
||||
|
||||
unique_ref<DataInnerNode> DataNode::convertToNewInnerNode(unique_ref<DataNode> node, const DataNode &first_child) {
|
||||
unique_ref<DataInnerNode> DataNode::convertToNewInnerNode(unique_ref<DataNode> node, const DataNodeLayout &layout, const DataNode &first_child) {
|
||||
auto block = node->_node.releaseBlock();
|
||||
blockstore::utils::fillWithZeroes(block.get());
|
||||
|
||||
return DataInnerNode::InitializeNewNode(std::move(block), first_child);
|
||||
return DataInnerNode::InitializeNewNode(std::move(block), layout, first_child.depth()+1, {first_child.key()});
|
||||
}
|
||||
|
||||
void DataNode::flush() const {
|
||||
|
@ -19,7 +19,7 @@ public:
|
||||
|
||||
uint8_t depth() const;
|
||||
|
||||
static cpputils::unique_ref<DataInnerNode> convertToNewInnerNode(cpputils::unique_ref<DataNode> node, const DataNode &first_child);
|
||||
static cpputils::unique_ref<DataInnerNode> convertToNewInnerNode(cpputils::unique_ref<DataNode> node, const DataNodeLayout &layout, const DataNode &first_child);
|
||||
|
||||
void flush() const;
|
||||
|
||||
|
@ -16,6 +16,7 @@ using cpputils::dynamic_pointer_move;
|
||||
using std::runtime_error;
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
using std::vector;
|
||||
|
||||
namespace blobstore {
|
||||
namespace onblocks {
|
||||
@ -41,17 +42,13 @@ unique_ref<DataNode> DataNodeStore::load(unique_ref<Block> block) {
|
||||
}
|
||||
}
|
||||
|
||||
unique_ref<DataInnerNode> DataNodeStore::createNewInnerNode(const DataNode &first_child) {
|
||||
ASSERT(first_child.node().layout().blocksizeBytes() == _layout.blocksizeBytes(), "Source node has wrong layout. Is it from the same DataNodeStore?");
|
||||
//TODO Initialize block and then create it in the blockstore - this is more efficient than creating it and then writing to it
|
||||
auto block = _blockstore->create(Data(_layout.blocksizeBytes()).FillWithZeroes());
|
||||
return DataInnerNode::InitializeNewNode(std::move(block), first_child);
|
||||
unique_ref<DataInnerNode> DataNodeStore::createNewInnerNode(uint8_t depth, const vector<Key> &children) {
|
||||
ASSERT(children.size() >= 1, "Inner node must have at least one child");
|
||||
return DataInnerNode::CreateNewNode(_blockstore.get(), _layout, depth, children);
|
||||
}
|
||||
|
||||
unique_ref<DataLeafNode> DataNodeStore::createNewLeafNode() {
|
||||
//TODO Initialize block and then create it in the blockstore - this is more efficient than creating it and then writing to it
|
||||
auto block = _blockstore->create(Data(_layout.blocksizeBytes()).FillWithZeroes());
|
||||
return DataLeafNode::InitializeNewNode(std::move(block));
|
||||
unique_ref<DataLeafNode> DataNodeStore::createNewLeafNode(Data data) {
|
||||
return DataLeafNode::CreateNewNode(_blockstore.get(), _layout, std::move(data));
|
||||
}
|
||||
|
||||
optional<unique_ref<DataNode>> DataNodeStore::load(const Key &key) {
|
||||
|
@ -30,8 +30,8 @@ public:
|
||||
|
||||
boost::optional<cpputils::unique_ref<DataNode>> load(const blockstore::Key &key);
|
||||
|
||||
cpputils::unique_ref<DataLeafNode> createNewLeafNode();
|
||||
cpputils::unique_ref<DataInnerNode> createNewInnerNode(const DataNode &first_child);
|
||||
cpputils::unique_ref<DataLeafNode> createNewLeafNode(cpputils::Data data);
|
||||
cpputils::unique_ref<DataInnerNode> createNewInnerNode(uint8_t depth, const std::vector<blockstore::Key> &children);
|
||||
|
||||
cpputils::unique_ref<DataNode> createNewNodeAsCopyFrom(const DataNode &source);
|
||||
|
||||
|
@ -65,6 +65,22 @@ public:
|
||||
}
|
||||
~DataNodeView() {}
|
||||
|
||||
static DataNodeView create(blockstore::BlockStore *blockStore, const DataNodeLayout &layout, uint16_t formatVersion, uint8_t depth, uint32_t size, cpputils::Data data) {
|
||||
ASSERT(data.size() <= layout.datasizeBytes(), "Data is too large for node");
|
||||
cpputils::Data serialized = _serialize(layout, formatVersion, depth, size, std::move(data));
|
||||
ASSERT(serialized.size() == layout.blocksizeBytes(), "Wrong block size");
|
||||
auto block = blockStore->create(std::move(serialized));
|
||||
return DataNodeView(std::move(block));
|
||||
}
|
||||
|
||||
static DataNodeView initialize(cpputils::unique_ref<blockstore::Block> block, const DataNodeLayout &layout, uint16_t formatVersion, uint8_t depth, uint32_t size, cpputils::Data data) {
|
||||
ASSERT(data.size() <= DataNodeLayout(block->size()).datasizeBytes(), "Data is too large for node");
|
||||
cpputils::Data serialized = _serialize(layout, formatVersion, depth, size, std::move(data));
|
||||
ASSERT(serialized.size() == block->size(), "Block has wrong size");
|
||||
block->write(serialized.data(), 0, serialized.size());
|
||||
return DataNodeView(std::move(block));
|
||||
}
|
||||
|
||||
DataNodeView(DataNodeView &&rhs) = default;
|
||||
|
||||
uint16_t FormatVersion() const {
|
||||
@ -136,6 +152,16 @@ private:
|
||||
return (Type*)(((const int8_t*)_block->data())+offset);
|
||||
}
|
||||
|
||||
static cpputils::Data _serialize(const DataNodeLayout &layout, uint16_t formatVersion, uint8_t depth, uint32_t size, cpputils::Data data) {
|
||||
cpputils::Data result(layout.blocksizeBytes());
|
||||
*((uint16_t*)result.dataOffset(layout.FORMAT_VERSION_OFFSET_BYTES)) = formatVersion;
|
||||
*((uint8_t*)result.dataOffset(layout.DEPTH_OFFSET_BYTES)) = depth;
|
||||
*((uint32_t*)result.dataOffset(layout.SIZE_OFFSET_BYTES)) = size;
|
||||
std::memcpy(result.dataOffset(layout.HEADERSIZE_BYTES), data.data(), data.size());
|
||||
std::memset(result.dataOffset(layout.HEADERSIZE_BYTES+data.size()), 0, layout.datasizeBytes()-data.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
cpputils::unique_ref<blockstore::Block> _block;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DataNodeView);
|
||||
|
@ -176,7 +176,7 @@ void DataTree::resizeNumBytes(uint64_t newNumBytes) {
|
||||
|
||||
_traverseLeaves(newNumLeaves - 1, newNumLeaves, onExistingLeaf, onCreateLeaf, onBacktrackFromSubtree);
|
||||
_numLeavesCache = newNumLeaves;
|
||||
ASSERT(newNumBytes == _numStoredBytes(), "We resized to the wrong number of bytes ("+std::to_string(numStoredBytes())+" instead of "+std::to_string(newNumBytes)+")");
|
||||
ASSERT(newNumBytes == _numStoredBytes(), "We resized to the wrong number of bytes ("+std::to_string(_numStoredBytes())+" instead of "+std::to_string(newNumBytes)+")");
|
||||
}
|
||||
|
||||
uint64_t DataTree::maxBytesPerLeaf() const {
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
using cpputils::unique_ref;
|
||||
using cpputils::make_unique_ref;
|
||||
using cpputils::Data;
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
|
||||
@ -30,7 +31,7 @@ optional<unique_ref<DataTree>> DataTreeStore::load(const blockstore::Key &key) {
|
||||
}
|
||||
|
||||
unique_ref<DataTree> DataTreeStore::createNewTree() {
|
||||
auto newleaf = _nodeStore->createNewLeafNode();
|
||||
auto newleaf = _nodeStore->createNewLeafNode(Data(0));
|
||||
return make_unique_ref<DataTree>(_nodeStore.get(), std::move(newleaf));
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace blobstore {
|
||||
|
||||
unique_ref<DataInnerNode> LeafTraverser::_increaseTreeDepth(unique_ref<DataNode> root) {
|
||||
auto copyOfOldRoot = _nodeStore->createNewNodeAsCopyFrom(*root);
|
||||
return DataNode::convertToNewInnerNode(std::move(root), *copyOfOldRoot);
|
||||
return DataNode::convertToNewInnerNode(std::move(root), _nodeStore->layout(), *copyOfOldRoot);
|
||||
}
|
||||
|
||||
void LeafTraverser::_traverseExistingSubtree(DataNode *root, uint32_t beginIndex, uint32_t endIndex, uint32_t leafOffset, bool isLeftBorderOfTraversal, bool growLastLeaf, function<void (uint32_t index, DataLeafNode* leaf)> onExistingLeaf, function<Data (uint32_t index)> onCreateLeaf, function<void (DataInnerNode *node)> onBacktrackFromSubtree) {
|
||||
@ -68,7 +68,7 @@ namespace blobstore {
|
||||
DataLeafNode *leaf = dynamic_cast<DataLeafNode*>(root);
|
||||
if (leaf != nullptr) {
|
||||
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 (growLastLeaf) {
|
||||
if (growLastLeaf && leaf->numBytes() != _nodeStore->layout().maxBytesPerLeaf()) {
|
||||
leaf->resize(_nodeStore->layout().maxBytesPerLeaf());
|
||||
}
|
||||
if (beginIndex == 0 && endIndex == 1) {
|
||||
@ -141,12 +141,7 @@ namespace blobstore {
|
||||
if (0 == depth) {
|
||||
ASSERT(beginIndex <= 1 && endIndex == 1, "With depth 0, we can only traverse one or zero leaves (i.e. traverse one leaf or traverse a gap leaf).");
|
||||
auto leafCreator = (beginIndex == 0) ? onCreateLeaf : _createMaxSizeLeaf();
|
||||
auto data = leafCreator(leafOffset);
|
||||
// TODO Performance: Directly create leaf node with data.
|
||||
auto node = _nodeStore->createNewLeafNode();
|
||||
node->resize(data.size());
|
||||
node->write(data.data(), 0, data.size());
|
||||
return node;
|
||||
return _nodeStore->createNewLeafNode(leafCreator(leafOffset));
|
||||
}
|
||||
|
||||
uint8_t minNeededDepth = utils::ceilLog(_nodeStore->layout().maxChildrenPerInnerNode(), (uint64_t)endIndex);
|
||||
@ -155,7 +150,7 @@ namespace blobstore {
|
||||
uint32_t beginChild = beginIndex/leavesPerChild;
|
||||
uint32_t endChild = utils::ceilDivision(endIndex, leavesPerChild);
|
||||
|
||||
vector<unique_ref<DataNode>> children;
|
||||
vector<blockstore::Key> children;
|
||||
children.reserve(endChild);
|
||||
// TODO Remove redundancy of following two for loops by using min/max for calculating the parameters of the recursive call.
|
||||
// Create gap children (i.e. children before the traversal but after the current size)
|
||||
@ -164,7 +159,8 @@ namespace blobstore {
|
||||
auto child = _createNewSubtree(leavesPerChild, leavesPerChild, leafOffset + childOffset, depth - 1,
|
||||
[] (uint32_t /*index*/)->Data {ASSERT(false, "We're only creating gap leaves here, not traversing any.");},
|
||||
[] (DataInnerNode* /*node*/) {});
|
||||
children.push_back(std::move(child));
|
||||
ASSERT(child->depth() == depth-1, "Created child node has wrong depth");
|
||||
children.push_back(child->key());
|
||||
}
|
||||
// Create new children that are traversed
|
||||
for(uint32_t childIndex = beginChild; childIndex < endChild; ++childIndex) {
|
||||
@ -172,15 +168,13 @@ namespace blobstore {
|
||||
uint32_t localBeginIndex = utils::maxZeroSubtraction(beginIndex, childOffset);
|
||||
uint32_t localEndIndex = std::min(leavesPerChild, endIndex - childOffset);
|
||||
auto child = _createNewSubtree(localBeginIndex, localEndIndex, leafOffset + childOffset, depth - 1, onCreateLeaf, onBacktrackFromSubtree);
|
||||
children.push_back(std::move(child));
|
||||
ASSERT(child->depth() == depth-1, "Created child node has wrong depth");
|
||||
children.push_back(child->key());
|
||||
}
|
||||
|
||||
ASSERT(children.size() > 0, "No children created");
|
||||
//TODO Performance: Directly create inner node with all children
|
||||
auto newNode = _nodeStore->createNewInnerNode(*children[0]);
|
||||
for (auto childIter = children.begin()+1; childIter != children.end(); ++childIter) {
|
||||
newNode->addChild(**childIter);
|
||||
}
|
||||
auto newNode = _nodeStore->createNewInnerNode(depth, children);
|
||||
|
||||
// This is only a backtrack, if we actually created a leaf here.
|
||||
if (endIndex > beginIndex) {
|
||||
onBacktrackFromSubtree(newNode.get());
|
||||
|
@ -81,22 +81,31 @@ namespace blockstore {
|
||||
return _createdBlocks;
|
||||
}
|
||||
|
||||
const std::vector<Key> loadedBlocks() const {
|
||||
const std::vector<Key> &loadedBlocks() const {
|
||||
return _loadedBlocks;
|
||||
}
|
||||
|
||||
const std::vector<Key> removedBlocks() const {
|
||||
const std::vector<Key> &removedBlocks() const {
|
||||
return _removedBlocks;
|
||||
}
|
||||
|
||||
const std::vector<Key> resizedBlocks() const {
|
||||
const std::vector<Key> &resizedBlocks() const {
|
||||
return _resizedBlocks;
|
||||
}
|
||||
|
||||
const std::vector<Key> writtenBlocks() const {
|
||||
const std::vector<Key> &writtenBlocks() const {
|
||||
return _writtenBlocks;
|
||||
}
|
||||
|
||||
std::vector<Key> distinctWrittenBlocks() const {
|
||||
std::vector<Key> result(_writtenBlocks);
|
||||
std::sort(result.begin(), result.end(), [](const Key &lhs, const Key &rhs) {
|
||||
return std::memcmp(lhs.data(), rhs.data(), lhs.BINARY_LENGTH) < 0;
|
||||
});
|
||||
result.erase(std::unique(result.begin(), result.end() ), result.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
void _increaseNumCreatedBlocks() {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
|
@ -24,6 +24,7 @@ using namespace blobstore::onblocks::datanodestore;
|
||||
|
||||
using cpputils::unique_ref;
|
||||
using cpputils::make_unique_ref;
|
||||
using std::vector;
|
||||
|
||||
class DataInnerNodeTest: public Test {
|
||||
public:
|
||||
@ -34,8 +35,8 @@ public:
|
||||
blockStore(_blockStore.get()),
|
||||
nodeStore(make_unique_ref<DataNodeStore>(std::move(_blockStore), BLOCKSIZE_BYTES)),
|
||||
ZEROES(nodeStore->layout().maxBytesPerLeaf()),
|
||||
leaf(nodeStore->createNewLeafNode()),
|
||||
node(nodeStore->createNewInnerNode(*leaf)) {
|
||||
leaf(nodeStore->createNewLeafNode(Data(0))),
|
||||
node(nodeStore->createNewInnerNode(1, {leaf->key()})) {
|
||||
|
||||
ZEROES.FillWithZeroes();
|
||||
}
|
||||
@ -46,12 +47,12 @@ public:
|
||||
}
|
||||
|
||||
Key CreateNewInnerNodeReturnKey(const DataNode &firstChild) {
|
||||
return nodeStore->createNewInnerNode(firstChild)->key();
|
||||
return nodeStore->createNewInnerNode(firstChild.depth()+1, {firstChild.key()})->key();
|
||||
}
|
||||
|
||||
unique_ref<DataInnerNode> CreateNewInnerNode() {
|
||||
auto new_leaf = nodeStore->createNewLeafNode();
|
||||
return nodeStore->createNewInnerNode(*new_leaf);
|
||||
auto new_leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
return nodeStore->createNewInnerNode(1, {new_leaf->key()});
|
||||
}
|
||||
|
||||
unique_ref<DataInnerNode> CreateAndLoadNewInnerNode(const DataNode &firstChild) {
|
||||
@ -59,23 +60,21 @@ public:
|
||||
return LoadInnerNode(key);
|
||||
}
|
||||
|
||||
unique_ref<DataInnerNode> CreateNewInnerNode(const DataNode &firstChild, const DataNode &secondChild) {
|
||||
auto node = nodeStore->createNewInnerNode(firstChild);
|
||||
node->addChild(secondChild);
|
||||
return node;
|
||||
unique_ref<DataInnerNode> CreateNewInnerNode(uint8_t depth, const vector<blockstore::Key> &children) {
|
||||
return nodeStore->createNewInnerNode(depth, children);
|
||||
}
|
||||
|
||||
Key CreateNewInnerNodeReturnKey(const DataNode &firstChild, const DataNode &secondChild) {
|
||||
return CreateNewInnerNode(firstChild, secondChild)->key();
|
||||
Key CreateNewInnerNodeReturnKey(uint8_t depth, const vector<blockstore::Key> &children) {
|
||||
return CreateNewInnerNode(depth, children)->key();
|
||||
}
|
||||
|
||||
unique_ref<DataInnerNode> CreateAndLoadNewInnerNode(const DataNode &firstChild, const DataNode &secondChild) {
|
||||
auto key = CreateNewInnerNodeReturnKey(firstChild, secondChild);
|
||||
unique_ref<DataInnerNode> CreateAndLoadNewInnerNode(uint8_t depth, const vector<blockstore::Key> &children) {
|
||||
auto key = CreateNewInnerNodeReturnKey(depth, children);
|
||||
return LoadInnerNode(key);
|
||||
}
|
||||
|
||||
Key AddALeafTo(DataInnerNode *node) {
|
||||
auto leaf2 = nodeStore->createNewLeafNode();
|
||||
auto leaf2 = nodeStore->createNewLeafNode(Data(0));
|
||||
node->addChild(*leaf2);
|
||||
return leaf2->key();
|
||||
}
|
||||
@ -84,8 +83,8 @@ public:
|
||||
auto node = CreateNewInnerNode();
|
||||
AddALeafTo(node.get());
|
||||
AddALeafTo(node.get());
|
||||
auto child = nodeStore->createNewLeafNode();
|
||||
unique_ref<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(node), *child);
|
||||
auto child = nodeStore->createNewLeafNode(Data(0));
|
||||
unique_ref<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(node), nodeStore->layout(), *child);
|
||||
return converted->key();
|
||||
}
|
||||
|
||||
@ -95,7 +94,7 @@ public:
|
||||
}
|
||||
|
||||
Key InitializeInnerNodeAddLeafReturnKey() {
|
||||
auto node = DataInnerNode::InitializeNewNode(blockStore->create(Data(BLOCKSIZE_BYTES)), *leaf);
|
||||
auto node = DataInnerNode::CreateNewNode(blockStore, nodeStore->layout(), 1, {leaf->key()});
|
||||
AddALeafTo(node.get());
|
||||
return node->key();
|
||||
}
|
||||
@ -114,32 +113,23 @@ private:
|
||||
|
||||
constexpr uint32_t DataInnerNodeTest::BLOCKSIZE_BYTES;
|
||||
|
||||
TEST_F(DataInnerNodeTest, CorrectKeyReturnedAfterInitialization) {
|
||||
auto block = blockStore->create(Data(BLOCKSIZE_BYTES));
|
||||
Key key = block->key();
|
||||
auto node = DataInnerNode::InitializeNewNode(std::move(block), *leaf);
|
||||
EXPECT_EQ(key, node->key());
|
||||
}
|
||||
|
||||
TEST_F(DataInnerNodeTest, CorrectKeyReturnedAfterLoading) {
|
||||
auto block = blockStore->create(Data(BLOCKSIZE_BYTES));
|
||||
Key key = block->key();
|
||||
DataInnerNode::InitializeNewNode(std::move(block), *leaf);
|
||||
Key key = DataInnerNode::CreateNewNode(blockStore, nodeStore->layout(), 1, {leaf->key()})->key();
|
||||
|
||||
auto loaded = nodeStore->load(key).value();
|
||||
EXPECT_EQ(key, loaded->key());
|
||||
}
|
||||
|
||||
TEST_F(DataInnerNodeTest, InitializesCorrectly) {
|
||||
auto node = DataInnerNode::InitializeNewNode(blockStore->create(Data(BLOCKSIZE_BYTES)), *leaf);
|
||||
auto node = DataInnerNode::CreateNewNode(blockStore, nodeStore->layout(), 1, {leaf->key()});
|
||||
|
||||
EXPECT_EQ(1u, node->numChildren());
|
||||
EXPECT_EQ(leaf->key(), node->getChild(0)->key());
|
||||
}
|
||||
|
||||
TEST_F(DataInnerNodeTest, ReinitializesCorrectly) {
|
||||
auto key = InitializeInnerNodeAddLeafReturnKey();
|
||||
auto node = DataInnerNode::InitializeNewNode(blockStore->load(key).value(), *leaf);
|
||||
auto key = DataLeafNode::CreateNewNode(blockStore, nodeStore->layout(), Data(0))->key();
|
||||
auto node = DataInnerNode::InitializeNewNode(blockStore->load(key).value(), nodeStore->layout(), 1, {leaf->key()});
|
||||
|
||||
EXPECT_EQ(1u, node->numChildren());
|
||||
EXPECT_EQ(leaf->key(), node->getChild(0)->key());
|
||||
@ -161,8 +151,8 @@ TEST_F(DataInnerNodeTest, AddingASecondLeaf) {
|
||||
}
|
||||
|
||||
TEST_F(DataInnerNodeTest, AddingASecondLeafAndReload) {
|
||||
auto leaf2 = nodeStore->createNewLeafNode();
|
||||
auto loaded = CreateAndLoadNewInnerNode(*leaf, *leaf2);
|
||||
auto leaf2 = nodeStore->createNewLeafNode(Data(0));
|
||||
auto loaded = CreateAndLoadNewInnerNode(1, {leaf->key(), leaf2->key()});
|
||||
|
||||
EXPECT_EQ(2u, loaded->numChildren());
|
||||
EXPECT_EQ(leaf->key(), loaded->getChild(0)->key());
|
||||
@ -171,7 +161,7 @@ TEST_F(DataInnerNodeTest, AddingASecondLeafAndReload) {
|
||||
|
||||
TEST_F(DataInnerNodeTest, BuildingAThreeLevelTree) {
|
||||
auto node2 = CreateNewInnerNode();
|
||||
auto parent = CreateNewInnerNode(*node, *node2);
|
||||
auto parent = CreateNewInnerNode(node->depth()+1, {node->key(), node2->key()});
|
||||
|
||||
EXPECT_EQ(2u, parent->numChildren());
|
||||
EXPECT_EQ(node->key(), parent->getChild(0)->key());
|
||||
@ -180,7 +170,7 @@ TEST_F(DataInnerNodeTest, BuildingAThreeLevelTree) {
|
||||
|
||||
TEST_F(DataInnerNodeTest, BuildingAThreeLevelTreeAndReload) {
|
||||
auto node2 = CreateNewInnerNode();
|
||||
auto parent = CreateAndLoadNewInnerNode(*node, *node2);
|
||||
auto parent = CreateAndLoadNewInnerNode(node->depth()+1, {node->key(), node2->key()});
|
||||
|
||||
EXPECT_EQ(2u, parent->numChildren());
|
||||
EXPECT_EQ(node->key(), parent->getChild(0)->key());
|
||||
@ -188,9 +178,9 @@ TEST_F(DataInnerNodeTest, BuildingAThreeLevelTreeAndReload) {
|
||||
}
|
||||
|
||||
TEST_F(DataInnerNodeTest, ConvertToInternalNode) {
|
||||
auto child = nodeStore->createNewLeafNode();
|
||||
auto child = nodeStore->createNewLeafNode(Data(0));
|
||||
Key node_key = node->key();
|
||||
unique_ref<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(node), *child);
|
||||
unique_ref<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(node), nodeStore->layout(), *child);
|
||||
|
||||
EXPECT_EQ(1u, converted->numChildren());
|
||||
EXPECT_EQ(child->key(), converted->getChild(0)->key());
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
nodeStore(make_unique_ref<DataNodeStore>(std::move(_blockStore), BLOCKSIZE_BYTES)),
|
||||
ZEROES(nodeStore->layout().maxBytesPerLeaf()),
|
||||
randomData(nodeStore->layout().maxBytesPerLeaf()),
|
||||
leaf(nodeStore->createNewLeafNode()) {
|
||||
leaf(nodeStore->createNewLeafNode(Data(0))) {
|
||||
|
||||
ZEROES.FillWithZeroes();
|
||||
|
||||
@ -61,7 +61,7 @@ public:
|
||||
}
|
||||
|
||||
Key WriteDataToNewLeafBlockAndReturnKey() {
|
||||
auto newleaf = nodeStore->createNewLeafNode();
|
||||
auto newleaf = nodeStore->createNewLeafNode(Data(0));
|
||||
newleaf->resize(randomData.size());
|
||||
newleaf->write(randomData.data(), 0, randomData.size());
|
||||
return newleaf->key();
|
||||
@ -88,10 +88,10 @@ public:
|
||||
}
|
||||
|
||||
Key CreateLeafWithDataConvertItToInnerNodeAndReturnKey() {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
FillLeafBlockWithData(leaf.get());
|
||||
auto child = nodeStore->createNewLeafNode();
|
||||
unique_ref<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(leaf), *child);
|
||||
auto child = nodeStore->createNewLeafNode(Data(0));
|
||||
unique_ref<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(leaf), LAYOUT, *child);
|
||||
return converted->key();
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ public:
|
||||
}
|
||||
|
||||
Key InitializeLeafGrowAndReturnKey() {
|
||||
auto leaf = DataLeafNode::InitializeNewNode(blockStore->create(Data(BLOCKSIZE_BYTES)));
|
||||
auto leaf = DataLeafNode::CreateNewNode(blockStore, LAYOUT, Data(LAYOUT.maxBytesPerLeaf()));
|
||||
leaf->resize(5);
|
||||
return leaf->key();
|
||||
}
|
||||
@ -120,31 +120,16 @@ private:
|
||||
constexpr uint32_t DataLeafNodeTest::BLOCKSIZE_BYTES;
|
||||
constexpr DataNodeLayout DataLeafNodeTest::LAYOUT;
|
||||
|
||||
TEST_F(DataLeafNodeTest, CorrectKeyReturnedAfterInitialization) {
|
||||
auto block = blockStore->create(Data(BLOCKSIZE_BYTES));
|
||||
Key key = block->key();
|
||||
auto node = DataLeafNode::InitializeNewNode(std::move(block));
|
||||
EXPECT_EQ(key, node->key());
|
||||
}
|
||||
|
||||
TEST_F(DataLeafNodeTest, CorrectKeyReturnedAfterLoading) {
|
||||
auto block = blockStore->create(Data(BLOCKSIZE_BYTES));
|
||||
Key key = block->key();
|
||||
DataLeafNode::InitializeNewNode(std::move(block));
|
||||
Key key = DataLeafNode::CreateNewNode(blockStore, LAYOUT, Data(LAYOUT.maxBytesPerLeaf()))->key();
|
||||
|
||||
auto loaded = nodeStore->load(key).value();
|
||||
EXPECT_EQ(key, loaded->key());
|
||||
}
|
||||
|
||||
TEST_F(DataLeafNodeTest, InitializesCorrectly) {
|
||||
auto leaf = DataLeafNode::InitializeNewNode(blockStore->create(Data(BLOCKSIZE_BYTES)));
|
||||
EXPECT_EQ(0u, leaf->numBytes());
|
||||
}
|
||||
|
||||
TEST_F(DataLeafNodeTest, ReinitializesCorrectly) {
|
||||
auto key = InitializeLeafGrowAndReturnKey();
|
||||
auto leaf = DataLeafNode::InitializeNewNode(blockStore->load(key).value());
|
||||
EXPECT_EQ(0u, leaf->numBytes());
|
||||
auto leaf = DataLeafNode::CreateNewNode(blockStore, LAYOUT, Data(5));
|
||||
EXPECT_EQ(5u, leaf->numBytes());
|
||||
}
|
||||
|
||||
TEST_F(DataLeafNodeTest, ReadWrittenDataAfterReloadingBlock) {
|
||||
@ -161,7 +146,7 @@ TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero) {
|
||||
}
|
||||
|
||||
TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero_AfterLoading) {
|
||||
Key key = nodeStore->createNewLeafNode()->key();
|
||||
Key key = nodeStore->createNewLeafNode(Data(0))->key();
|
||||
auto leaf = LoadLeafNode(key);
|
||||
|
||||
EXPECT_EQ(0u, leaf->numBytes());
|
||||
@ -170,7 +155,7 @@ TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero_AfterLoading) {
|
||||
class DataLeafNodeSizeTest: public DataLeafNodeTest, public WithParamInterface<unsigned int> {
|
||||
public:
|
||||
Key CreateLeafResizeItAndReturnKey() {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
leaf->resize(GetParam());
|
||||
return leaf->key();
|
||||
}
|
||||
@ -232,9 +217,9 @@ TEST_F(DataLeafNodeTest, ShrinkingDoesntDestroyValidDataRegion) {
|
||||
}
|
||||
|
||||
TEST_F(DataLeafNodeTest, ConvertToInternalNode) {
|
||||
auto child = nodeStore->createNewLeafNode();
|
||||
auto child = nodeStore->createNewLeafNode(Data(0));
|
||||
Key leaf_key = leaf->key();
|
||||
unique_ref<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(leaf), *child);
|
||||
unique_ref<DataInnerNode> converted = DataNode::convertToNewInnerNode(std::move(leaf), LAYOUT, *child);
|
||||
|
||||
EXPECT_EQ(1u, converted->numChildren());
|
||||
EXPECT_EQ(child->key(), converted->getChild(0)->key());
|
||||
@ -290,7 +275,7 @@ public:
|
||||
}
|
||||
|
||||
Key CreateLeafWriteToItAndReturnKey(const Data &to_write) {
|
||||
auto newleaf = nodeStore->createNewLeafNode();
|
||||
auto newleaf = nodeStore->createNewLeafNode(Data(0));
|
||||
|
||||
newleaf->resize(GetParam().leafsize);
|
||||
newleaf->write(to_write.data(), GetParam().offset, GetParam().count);
|
||||
|
@ -37,19 +37,19 @@ constexpr uint32_t DataNodeStoreTest::BLOCKSIZE_BYTES;
|
||||
#define EXPECT_IS_PTR_TYPE(Type, ptr) EXPECT_NE(nullptr, dynamic_cast<Type*>(ptr)) << "Given pointer cannot be cast to the given type"
|
||||
|
||||
TEST_F(DataNodeStoreTest, CreateLeafNodeCreatesLeafNode) {
|
||||
auto node = nodeStore->createNewLeafNode();
|
||||
auto node = nodeStore->createNewLeafNode(Data(0));
|
||||
EXPECT_IS_PTR_TYPE(DataLeafNode, node.get());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, CreateInnerNodeCreatesInnerNode) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
|
||||
auto node = nodeStore->createNewInnerNode(*leaf);
|
||||
auto node = nodeStore->createNewInnerNode(1, {leaf->key()});
|
||||
EXPECT_IS_PTR_TYPE(DataInnerNode, node.get());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, LeafNodeIsRecognizedAfterStoreAndLoad) {
|
||||
Key key = nodeStore->createNewLeafNode()->key();
|
||||
Key key = nodeStore->createNewLeafNode(Data(0))->key();
|
||||
|
||||
auto loaded_node = nodeStore->load(key).value();
|
||||
|
||||
@ -57,8 +57,8 @@ TEST_F(DataNodeStoreTest, LeafNodeIsRecognizedAfterStoreAndLoad) {
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, InnerNodeWithDepth1IsRecognizedAfterStoreAndLoad) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
Key key = nodeStore->createNewInnerNode(*leaf)->key();
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
Key key = nodeStore->createNewInnerNode(1, {leaf->key()})->key();
|
||||
|
||||
auto loaded_node = nodeStore->load(key).value();
|
||||
|
||||
@ -66,9 +66,9 @@ TEST_F(DataNodeStoreTest, InnerNodeWithDepth1IsRecognizedAfterStoreAndLoad) {
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, InnerNodeWithDepth2IsRecognizedAfterStoreAndLoad) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto inner = nodeStore->createNewInnerNode(*leaf);
|
||||
Key key = nodeStore->createNewInnerNode(*inner)->key();
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
auto inner = nodeStore->createNewInnerNode(1, {leaf->key()});
|
||||
Key key = nodeStore->createNewInnerNode(2, {inner->key()})->key();
|
||||
|
||||
auto loaded_node = nodeStore->load(key).value();
|
||||
|
||||
@ -89,19 +89,19 @@ TEST_F(DataNodeStoreTest, DataNodeCrashesOnLoadIfDepthIsTooHigh) {
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, CreatedInnerNodeIsInitialized) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto node = nodeStore->createNewInnerNode(*leaf);
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
auto node = nodeStore->createNewInnerNode(1, {leaf->key()});
|
||||
EXPECT_EQ(1u, node->numChildren());
|
||||
EXPECT_EQ(leaf->key(), node->getChild(0)->key());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, CreatedLeafNodeIsInitialized) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
EXPECT_EQ(0u, leaf->numBytes());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, NodeIsNotLoadableAfterDeleting) {
|
||||
auto nodekey = nodeStore->createNewLeafNode()->key();
|
||||
auto nodekey = nodeStore->createNewLeafNode(Data(0))->key();
|
||||
auto node = nodeStore->load(nodekey);
|
||||
EXPECT_NE(none, node);
|
||||
nodeStore->remove(std::move(*node));
|
||||
@ -113,38 +113,38 @@ TEST_F(DataNodeStoreTest, NumNodesIsCorrectOnEmptyNodestore) {
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterAddingOneLeafNode) {
|
||||
nodeStore->createNewLeafNode();
|
||||
nodeStore->createNewLeafNode(Data(0));
|
||||
EXPECT_EQ(1u, nodeStore->numNodes());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterRemovingTheLastNode) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
nodeStore->remove(std::move(leaf));
|
||||
EXPECT_EQ(0u, nodeStore->numNodes());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterAddingTwoNodes) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto node = nodeStore->createNewInnerNode(*leaf);
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
auto node = nodeStore->createNewInnerNode(1, {leaf->key()});
|
||||
EXPECT_EQ(2u, nodeStore->numNodes());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterRemovingANode) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto node = nodeStore->createNewInnerNode(*leaf);
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
auto node = nodeStore->createNewInnerNode(1, {leaf->key()});
|
||||
nodeStore->remove(std::move(node));
|
||||
EXPECT_EQ(1u, nodeStore->numNodes());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, PhysicalBlockSize_Leaf) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
auto block = blockStore->load(leaf->key()).value();
|
||||
EXPECT_EQ(BLOCKSIZE_BYTES, block->size());
|
||||
}
|
||||
|
||||
TEST_F(DataNodeStoreTest, PhysicalBlockSize_Inner) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto node = nodeStore->createNewInnerNode(*leaf);
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
auto node = nodeStore->createNewInnerNode(1, {leaf->key()});
|
||||
auto block = blockStore->load(node->key()).value();
|
||||
EXPECT_EQ(BLOCKSIZE_BYTES, block->size());
|
||||
}
|
@ -30,6 +30,9 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByTree)
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // First loading is from loading the tree, second one from removing it (i.e. loading the root)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByKey) {
|
||||
@ -40,6 +43,9 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByKey)
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByTree) {
|
||||
@ -51,6 +57,9 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByTre
|
||||
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode + maxChildrenPerInnerNode*maxChildrenPerInnerNode, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByKey) {
|
||||
@ -61,6 +70,9 @@ TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByKey
|
||||
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode + maxChildrenPerInnerNode*maxChildrenPerInnerNode, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All) {
|
||||
@ -72,6 +84,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All) {
|
||||
|
||||
EXPECT_EQ(maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads all leaves (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some) {
|
||||
@ -83,6 +98,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some) {
|
||||
|
||||
EXPECT_EQ(2u, blockStore->loadedBlocks().size()); // Loads both leaves (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All) {
|
||||
@ -94,6 +112,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All) {
|
||||
|
||||
EXPECT_EQ(maxChildrenPerInnerNode + maxChildrenPerInnerNode * maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads inner nodes and all leaves once (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner) {
|
||||
@ -105,6 +126,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner) {
|
||||
|
||||
EXPECT_EQ(3u, blockStore->loadedBlocks().size()); // Loads inner node and both leaves (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner) {
|
||||
@ -116,6 +140,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner) {
|
||||
|
||||
EXPECT_EQ(2u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads inner node and both leaves (not the root, because it is already loaded in the tree)
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner) {
|
||||
@ -127,6 +154,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner) {
|
||||
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads inner node and leaves (not the root, because it is already loaded in the tree)f
|
||||
EXPECT_EQ(0u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size());
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingInside) {
|
||||
@ -138,6 +168,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingInside) {
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old child (for growing it)
|
||||
EXPECT_EQ(2u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add children to inner node
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_TwoLevel) {
|
||||
@ -149,6 +182,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_TwoL
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it
|
||||
EXPECT_EQ(3u, blockStore->createdBlocks());
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add child to inner node
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_ThreeLevel) {
|
||||
@ -160,6 +196,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_Thre
|
||||
|
||||
EXPECT_EQ(2u, blockStore->loadedBlocks().size()); // Loads last old leaf (and its inner node) for growing it
|
||||
EXPECT_EQ(3u, blockStore->createdBlocks()); // inner node and two leaves
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add children to existing inner node
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingAtBeginOfChild) {
|
||||
@ -171,6 +210,9 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingAtBeginOfChi
|
||||
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Inner node and its leaves
|
||||
EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->createdBlocks()); // Creates an inner node and its leaves
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add children to existing inner node
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDepth) {
|
||||
@ -182,6 +224,23 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDe
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it
|
||||
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // Add children to existing inner node
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDepth_ResizeLastLeaf) {
|
||||
auto key = CreateInner({CreateLeaf(), CreateLeafWithSize(5)})->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), 4, maxChildrenPerInnerNode+2);
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it
|
||||
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // Resize last leaf and add children to existing inner node
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDepth) {
|
||||
@ -193,4 +252,21 @@ TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDe
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it
|
||||
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // Add children to existing inner node
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
||||
TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDepth_ResizeLastLeaf) {
|
||||
auto key = CreateInner({CreateLeaf(), CreateLeafWithSize(5)})->key();
|
||||
auto tree = treeStore.load(key).value();
|
||||
blockStore->resetCounters();
|
||||
|
||||
Traverse(tree.get(), maxChildrenPerInnerNode, maxChildrenPerInnerNode+2);
|
||||
|
||||
EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it
|
||||
EXPECT_EQ(2 + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves
|
||||
EXPECT_EQ(0u, blockStore->removedBlocks().size());
|
||||
EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // Resize last leaf and add children to existing inner node
|
||||
EXPECT_EQ(0u, blockStore->resizedBlocks().size());
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ using blobstore::onblocks::datanodestore::DataNode;
|
||||
using blobstore::onblocks::datanodestore::DataInnerNode;
|
||||
using blockstore::testfake::FakeBlockStore;
|
||||
using blockstore::Key;
|
||||
using cpputils::Data;
|
||||
using namespace blobstore::onblocks::datatreestore::algorithms;
|
||||
|
||||
class GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest: public DataTreeTest {
|
||||
@ -55,7 +56,7 @@ public:
|
||||
};
|
||||
|
||||
TEST_F(GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest, Leaf) {
|
||||
auto leaf = nodeStore->createNewLeafNode();
|
||||
auto leaf = nodeStore->createNewLeafNode(Data(0));
|
||||
auto result = GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(nodeStore, leaf.get());
|
||||
EXPECT_EQ(nullptr, result.get());
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ using std::initializer_list;
|
||||
using std::vector;
|
||||
using boost::none;
|
||||
using cpputils::dynamic_pointer_move;
|
||||
using cpputils::Data;
|
||||
|
||||
constexpr uint32_t DataTreeTest::BLOCKSIZE_BYTES;
|
||||
|
||||
@ -29,7 +30,7 @@ DataTreeTest::DataTreeTest()
|
||||
}
|
||||
|
||||
unique_ref<DataLeafNode> DataTreeTest::CreateLeaf() {
|
||||
return nodeStore->createNewLeafNode();
|
||||
return nodeStore->createNewLeafNode(Data(nodeStore->layout().maxBytesPerLeaf()));
|
||||
}
|
||||
|
||||
unique_ref<DataInnerNode> DataTreeTest::CreateInner(initializer_list<unique_ref<DataNode>> children) {
|
||||
@ -44,10 +45,13 @@ unique_ref<DataInnerNode> DataTreeTest::CreateInner(initializer_list<const DataN
|
||||
|
||||
unique_ref<DataInnerNode> DataTreeTest::CreateInner(vector<const DataNode*> children) {
|
||||
ASSERT(children.size() >= 1, "An inner node must have at least one child");
|
||||
auto node = nodeStore->createNewInnerNode(**children.begin());
|
||||
for(auto child = children.begin()+1; child != children.end(); ++child) {
|
||||
node->addChild(**child);
|
||||
vector<Key> childrenKeys;
|
||||
childrenKeys.reserve(children.size());
|
||||
for (const DataNode *child : children) {
|
||||
ASSERT(child->depth() == (*children.begin())->depth(), "Children with different depth");
|
||||
childrenKeys.push_back(child->key());
|
||||
}
|
||||
auto node = nodeStore->createNewInnerNode((*children.begin())->depth()+1, childrenKeys);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user