207 lines
9.8 KiB
C++
207 lines
9.8 KiB
C++
/*------------------------------------------------------------------------------*
|
|
* 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 <maximilian.berens@tu-dortmund.de> *
|
|
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
|
|
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
|
|
*------------------------------------------------------------------------------*
|
|
*/
|
|
|
|
#include <index/b_plus_tree/b_plus_tree_node.h>
|
|
#include <index/return_value.h>
|
|
#include <iostream>
|
|
#include <optional>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace beedb::index::bplustree
|
|
{
|
|
template <typename K, typename V, bool U>
|
|
BPlusTreeNode<K, V, U> *BPlusTree<K, V, U>::locate_leaf(
|
|
[[maybe_unused]] const K key, [[maybe_unused]] std::vector<BPlusTreeNode<K, V, U> *> *node_path) const
|
|
{
|
|
/**
|
|
* Assignment (2): Implement a B+-Tree
|
|
*
|
|
* The B+-Tree is used for indexing files. Using the index
|
|
* for bigger data sets will reduce the amount of scanned disk pages
|
|
* in case the query wants to filter the data.
|
|
*
|
|
* This method is used to traverse the tree and locate a leaf that may
|
|
* contain the wanted key. During the traversal for inserts, all visited nodes
|
|
* are stored in the node_path container. For lookups, the container is null.
|
|
*
|
|
* Hints for implementation:
|
|
* - "this->_root" stores the root node of the tree, where every
|
|
* lookup for a leaf is started.
|
|
* - Every inner node (also the root) has a "child(k)" method, which returns
|
|
* the next node on the way for the leaf, that may contain the key "k".
|
|
* - To check a node whether it is a leaf or inner node, use the "is_leaf()"
|
|
* method on a node, which returns true if the node is a leaf.
|
|
* - If "node_path" is not a "nullptr", push all nodes during traversal
|
|
* to that vector (also the root).
|
|
*
|
|
*
|
|
* Procedure:
|
|
* - Start the traversal at the root node.
|
|
* - Get the next node using "current_node->child(key)" while "current_node"
|
|
* is not a leaf.
|
|
* - Push every node to the "node_path", if "node_path != nullptr".
|
|
* - Return the leaf you found during traversal.
|
|
*/
|
|
|
|
Node *current_node = this->_root;
|
|
|
|
// TODO: Insert your code here.
|
|
|
|
return current_node;
|
|
}
|
|
|
|
template <typename K, typename V, bool U>
|
|
std::optional<typename ReturnValue<V, U>::type> BPlusTree<K, V, U>::get([[maybe_unused]] const K key) const
|
|
{
|
|
/**
|
|
* Assignment (2): Implement a B+-Tree
|
|
*
|
|
* This method tries to find the value for a given key.
|
|
* The tree is a very generic data structure which can hold
|
|
* one value per key or multiple values per key. The specific
|
|
* variant is given by the template parameter U which is a bool
|
|
* and stands for Unique. True means: Return one value of type V;
|
|
* false means: Return a set of values of type V.
|
|
*
|
|
* Hints for implementation:
|
|
* - You have already implemented "locate_leaf(k)" which returns the
|
|
* leaf that may contain the searched key-value pair.
|
|
* - Every leaf node provides a method "index(k)" which returns the index
|
|
* of the key "k".
|
|
* - Every leaf node provides a method "leaf_key(i)" which returns the
|
|
* key at index "i".
|
|
* - Every leaf node provides a method "value(i)" which returns the value
|
|
* at index "i". The "value(i)" method will automatically pick the correct
|
|
* return type, depending on the U-template-parameter.
|
|
*
|
|
* Procedure:
|
|
* - Locate the leaf node that may contain the wanted key.
|
|
* - Check the leaf node: Is the wanted key available?
|
|
* - If yes: return the value of the key.
|
|
* - Otherwise return an empty result, using "return std::nullopt;".
|
|
*/
|
|
|
|
// TODO: Insert your code here.
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
template <typename K, typename V, bool U>
|
|
std::optional<std::set<V>> BPlusTree<K, V, U>::get([[maybe_unused]] const K key_from,
|
|
[[maybe_unused]] const K key_to) const
|
|
{
|
|
/**
|
|
* Assignment (2): Implement a B+-Tree
|
|
*
|
|
* This method tries to find one or multiple values for a given
|
|
* range of keys.
|
|
* The tree is a very generic data structure which can hold
|
|
* one value per key or multiple values per key. The specific
|
|
* variant is given by the template parameter U which is a bool
|
|
* and stands for Unique. True means: Return one value of type V;
|
|
* false means: Return a set of values of type V.
|
|
*
|
|
* Hints for implementation:
|
|
* - You have already implemented "locate_leaf(k)" which returns the
|
|
* leaf that may contain the searched key-value pair.
|
|
* - Every node provides a method "right()" which returns a pointer
|
|
* to the right neighbour node.
|
|
* - Every node provides a method "size()" which returns the number of
|
|
* items that are stored in the node.
|
|
* - Every leaf node provides a method "index(k)" which returns the index
|
|
* of the key "k".
|
|
* - Every leaf node provides a method "leaf_key(i)" which returns the
|
|
* key at index "i".
|
|
* - Every leaf node provides a method "value(i)" which returns the value
|
|
* at index "i". The "value(i)" method will automatically pick the correct
|
|
* return type, depending on the U-template-parameter.
|
|
* - You can test whether it is a unique or non-unique tree, using
|
|
* "if constexpr(U) { code for unique... } else { boot for non-unique... }.
|
|
* - Both containers std::set (https://en.cppreference.com/w/cpp/container/set)
|
|
* and std::optional (https://en.cppreference.com/w/cpp/utility/optional) may
|
|
* be helpful on compiler errors.
|
|
*
|
|
* Procedure:
|
|
* - Locate the leaf node that may contain the wanted key.
|
|
* - Add all keys that are equal or greater than the key "key_from"
|
|
* and equal or lesser than the key "key_to" to a set of values.
|
|
* - When the last key of the node matches that predicate, also
|
|
* take a look to the right neighbour using the "right()" method
|
|
* (and also the rights right,...).
|
|
*/
|
|
|
|
std::set<V> values;
|
|
|
|
// TODO: Insert your code here.
|
|
|
|
return values;
|
|
}
|
|
|
|
template <typename K, typename V, bool U>
|
|
BPlusTreeNode<K, V, U> *BPlusTree<K, V, U>::insert_into_leaf([[maybe_unused]] BPlusTreeNode<K, V, U> *leaf_node,
|
|
[[maybe_unused]] const K key,
|
|
[[maybe_unused]] const V value)
|
|
{
|
|
/**
|
|
* Assignment (2): Implement a B+-Tree
|
|
*
|
|
* This method adds a value to a leaf node. The correct leaf node, key and
|
|
* value are all given. When inserting results in splitting the leaf,
|
|
* the pointer to the new created node is returned.
|
|
*
|
|
* Hints for implementation:
|
|
* - Every node provides a method "full()" which returns true, if there
|
|
* is no more place for a new item.
|
|
* - Every leaf node provides a method "index(k)" which returns the index
|
|
* of the key "k".
|
|
* - Every leaf node provides a method "leaf_key(i)" which returns the
|
|
* key at index "i".
|
|
* - Every leaf node provides a method "insert_value(i, v, k)" which adds
|
|
* a key-value pair (k,v) to the leaf at index i.
|
|
* - The tree has a method "this->split_leaf_node(l)" which splits the leaf
|
|
* node l and returns a pointer to the new node.
|
|
* - You can test whether it is a unique or non-unique tree, using
|
|
* "if constexpr(U) { code for unique... } else { boot for non-unique... }.
|
|
*
|
|
* Procedure:
|
|
* - Check if the leaf node already contains the key
|
|
* - If yes and the tree is non-unique: add the value to the list of values
|
|
* in the node and return a "nullptr".
|
|
* - If yey and the tree is unique: Just return a "nullptr".
|
|
* - If the key is not in the node, check for space for a new (key,value) pair.
|
|
* - If the node is not full, insert the new pair and return a "nullptr"
|
|
* - Otherwise, we have to split the node. Splitting will create a new leaf node,
|
|
* the new right neighbour of the given leaf node.
|
|
* - After splitting, we have enough space to insert the pair. Check whether the key
|
|
* should take place in the given leaf or the new leaf, created on splitting:
|
|
* When the key is lower than the first key of the new leaf, the key should be insert
|
|
* into the given leaf, otherwise in the new leaf.
|
|
* - After splitting, return the pointer to the new leaf.
|
|
*/
|
|
|
|
// TODO: Insert your code here.
|
|
|
|
return nullptr;
|
|
}
|
|
} // namespace beedb::index::bplustree
|