/*------------------------------------------------------------------------------* * Architecture & Implementation of DBMS * *------------------------------------------------------------------------------* * Copyright 2022 Databases and Information Systems Group TU Dortmund * * Visit us at * * http://dbis.cs.tu-dortmund.de/cms/en/home/ * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * * OTHER DEALINGS IN THE SOFTWARE. * * * * Authors: * * Maximilian Berens * * Roland Kühn * * Jan Mühlig * *------------------------------------------------------------------------------* */ #pragma once #include #include #include #include #include #include namespace beedb::index::bplustree { using size_type = std::size_t; template class BPlusTreeNode; template struct BPlusTreeNodeHeader { size_type size = 0; bool is_leaf; BPlusTreeNode *right = nullptr; explicit BPlusTreeNodeHeader(const bool is_leaf_) : is_leaf(is_leaf_) { } }; template struct BPlusTreeLeafNode { static constexpr size_type max_items = (Config::b_plus_tree_page_size - sizeof(BPlusTreeNodeHeader)) / (sizeof(K) + sizeof(typename ReturnValue::type)); std::array keys; std::array::type, BPlusTreeLeafNode::max_items> values; }; template struct BPlusTreeInnerNode { static constexpr size_type max_keys = (Config::b_plus_tree_page_size - sizeof(BPlusTreeNodeHeader) - sizeof(BPlusTreeNode *)) / (sizeof(K) + sizeof(BPlusTreeInnerNode *)); static constexpr size_type max_separators = max_keys + 1; std::array keys; std::array *, BPlusTreeInnerNode::max_separators> separators; }; template class BPlusTreeNode { public: explicit BPlusTreeNode(const bool is_leaf) : _header(is_leaf) { } ~BPlusTreeNode(); [[nodiscard]] bool is_leaf() const { return _header.is_leaf; } [[nodiscard]] bool is_inner() const { return is_leaf() == false; } [[nodiscard]] size_type size() const { return _header.size; } void size(const size_type size) { _header.size = size; } [[nodiscard]] BPlusTreeNode *right() { return _header.right; } [[nodiscard]] bool has_right() const { return _header.right != nullptr; } void right(BPlusTreeNode *right) { _header.right = right; } [[nodiscard]] typename ReturnValue::type &value(const size_type index) { return _leaf_node.values[index]; } [[nodiscard]] BPlusTreeNode *separator(const size_type index) { return _inner_node.separators[index]; } void separator(const size_type index, BPlusTreeNode *separator) { _inner_node.separators[index] = separator; } [[nodiscard]] K leaf_key(const size_type index) { return _leaf_node.keys[index]; } [[nodiscard]] K inner_key(const size_type index) { return _inner_node.keys[index]; } [[nodiscard]] bool is_full() const { const size_type max_size = is_leaf() ? BPlusTreeLeafNode::max_items : BPlusTreeInnerNode::max_keys; return size() >= max_size; } size_type index(const K key); BPlusTreeNode *child(const K key); void insert_separator(const size_type index, BPlusTreeNode *separator, const K key); void insert_value(const size_type index, const V value, const K key); void copy(BPlusTreeNode *other, const size_type from_index, const size_type count); std::pair size_include_children(); std::pair count_children(); private: BPlusTreeNodeHeader _header; union { BPlusTreeInnerNode _inner_node; BPlusTreeLeafNode _leaf_node; }; }; template BPlusTreeNode::~BPlusTreeNode() { if (is_leaf() == false) { for (size_type i = 0; i < size(); i++) { delete _inner_node.separators[i]; } } } template size_type BPlusTreeNode::index(const K key) { auto keys = is_leaf() ? _leaf_node.keys.begin() : _inner_node.keys.begin(); auto iterator = std::lower_bound(keys, keys + size(), key); return std::distance(keys, iterator); } template BPlusTreeNode *BPlusTreeNode::child(const K key) { std::int32_t low = 0, high = size() - 1; while (low <= high) { const std::int32_t mid = (low + high) / 2; if (_inner_node.keys[mid] <= key) { low = mid + 1; } else { high = mid - 1; } } return _inner_node.separators[high + 1]; } template void BPlusTreeNode::insert_separator(const size_type index, BPlusTreeNode *separator, const K key) { if (index < size()) { const size_type offset = size() - index; std::memmove(&_inner_node.keys[index + 1], &_inner_node.keys[index], offset * sizeof(K)); std::memmove(&_inner_node.separators[index + 2], &_inner_node.separators[index + 1], offset * sizeof(BPlusTreeNode *)); } _inner_node.keys[index] = key; _inner_node.separators[index + 1] = separator; _header.size++; } template void BPlusTreeNode::insert_value(const size_type index, const V value, const K key) { if (index < size()) { const size_type offset = size() - index; std::memmove(&_leaf_node.keys[index + 1], &_leaf_node.keys[index], offset * sizeof(K)); std::memmove(static_cast(&_leaf_node.values[index + 1]), &_leaf_node.values[index], offset * sizeof(typename ReturnValue::type)); } _leaf_node.keys[index] = key; if constexpr (U) { _leaf_node.values[index] = value; } else { new (&_leaf_node.values[index]) typename ReturnValue::type(); _leaf_node.values[index].insert(value); } _header.size++; } template void BPlusTreeNode::copy(BPlusTreeNode *other, const size_type from_index, const size_type count) { if (is_leaf()) { std::memcpy(&other->_leaf_node.keys[0], &_leaf_node.keys[from_index], count * sizeof(K)); std::memcpy(static_cast(&other->_leaf_node.values[0]), &_leaf_node.values[from_index], count * sizeof(typename ReturnValue::type)); } else { std::memcpy(&other->_inner_node.keys[0], &_inner_node.keys[from_index], count * sizeof(K)); std::memcpy(&other->_inner_node.separators[1], &_inner_node.separators[from_index + 1], count * sizeof(BPlusTreeNode *)); } } template std::pair BPlusTreeNode::size_include_children() { if (is_leaf()) { return {0u, size()}; } std::size_t leaf_sizes = 0, inner_sizes = 0; for (auto i = 0u; i <= size(); i++) { BPlusTreeNode *child = _inner_node.separators[i]; const auto child_size = child->size_include_children(); inner_sizes += child_size.first; leaf_sizes += child_size.second; } return {inner_sizes, leaf_sizes}; } template std::pair BPlusTreeNode::count_children() { if (is_leaf()) { return {0u, 0u}; } if (_inner_node.separators[0]->is_leaf()) { return {0u, size() + 1u}; } std::size_t leaf_children = 0, inner_children = 0; for (auto i = 0u; i <= size(); i++) { BPlusTreeNode *child = _inner_node.separators[i]; const auto child_size = child->count_children(); inner_children += child_size.first; leaf_children += child_size.second; } return {inner_children + size(), leaf_children}; } } // namespace beedb::index::bplustree