diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ba563b77..87e7bc3c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -291,16 +291,17 @@ add_custom_target(submit-p1 ) set(P2_FILES - "src/include/storage/page/page_guard.h" - "src/storage/page/page_guard.cpp" - "src/include/storage/page/extendible_htable_bucket_page.h" - "src/storage/page/extendible_htable_bucket_page.cpp" - "src/include/storage/page/extendible_htable_directory_page.h" - "src/storage/page/extendible_htable_directory_page.cpp" - "src/include/storage/page/extendible_htable_header_page.h" - "src/storage/page/extendible_htable_header_page.cpp" - "src/include/container/disk/hash/disk_extendible_hash_table.h" - "src/container/disk/hash/disk_extendible_hash_table.cpp" + "src/include/storage/page/b_plus_tree_page.h" + "src/storage/page/b_plus_tree_page.cpp" + "src/include/storage/page/b_plus_tree_internal_page.h" + "src/storage/page/b_plus_tree_internal_page.cpp" + "src/include/storage/page/b_plus_tree_leaf_page.h" + "src/storage/page/b_plus_tree_leaf_page.cpp" + "src/include/storage/index/index_iterator.h" + "src/storage/index/index_iterator.cpp" + "src/include/storage/index/b_plus_tree.h" + "src/include/storage/index/b_plus_tree_debug.h" + "src/storage/index/b_plus_tree.cpp" ${P1_FILES} ) add_custom_target(check-clang-tidy-p2 diff --git a/src/container/disk/hash/disk_extendible_hash_table_utils.cpp b/src/container/disk/hash/disk_extendible_hash_table_utils.cpp index 340a39c1d..7a55662b1 100644 --- a/src/container/disk/hash/disk_extendible_hash_table_utils.cpp +++ b/src/container/disk/hash/disk_extendible_hash_table_utils.cpp @@ -6,7 +6,7 @@ // // Identification: src/container/disk/hash/disk_extendible_hash_table_utils.cpp // -// Copyright (c) 2015-2023, Carnegie Mellon University Database Group +// Copyright (c) 2015-2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// diff --git a/src/include/storage/index/b_plus_tree.h b/src/include/storage/index/b_plus_tree.h index a2aa961d7..c05df7f88 100644 --- a/src/include/storage/index/b_plus_tree.h +++ b/src/include/storage/index/b_plus_tree.h @@ -22,7 +22,6 @@ #include "common/config.h" #include "common/macros.h" -#include "concurrency/transaction.h" #include "storage/index/index_iterator.h" #include "storage/page/b_plus_tree_header_page.h" #include "storage/page/b_plus_tree_internal_page.h" @@ -67,20 +66,20 @@ class BPlusTree { public: explicit BPlusTree(std::string name, page_id_t header_page_id, BufferPoolManager *buffer_pool_manager, - const KeyComparator &comparator, int leaf_max_size = LEAF_PAGE_SIZE, - int internal_max_size = INTERNAL_PAGE_SIZE); + const KeyComparator &comparator, int leaf_max_size = LEAF_PAGE_SLOT_CNT, + int internal_max_size = INTERNAL_PAGE_SLOT_CNT); // Returns true if this B+ tree has no keys and values. auto IsEmpty() const -> bool; // Insert a key-value pair into this B+ tree. - auto Insert(const KeyType &key, const ValueType &value, Transaction *txn = nullptr) -> bool; + auto Insert(const KeyType &key, const ValueType &value) -> bool; // Remove a key and its value from this B+ tree. - void Remove(const KeyType &key, Transaction *txn); + void Remove(const KeyType &key); // Return the value associated with a given key - auto GetValue(const KeyType &key, std::vector *result, Transaction *txn = nullptr) -> bool; + auto GetValue(const KeyType &key, std::vector *result) -> bool; // Return the page id of the root node auto GetRootPageId() -> page_id_t; @@ -112,10 +111,10 @@ class BPlusTree { auto DrawBPlusTree() -> std::string; // read data from file and insert one by one - void InsertFromFile(const std::filesystem::path &file_name, Transaction *txn = nullptr); + void InsertFromFile(const std::filesystem::path &file_name); // read data from file and remove one by one - void RemoveFromFile(const std::filesystem::path &file_name, Transaction *txn = nullptr); + void RemoveFromFile(const std::filesystem::path &file_name); /** * @brief Read batch operations from input file, below is a sample file format @@ -126,7 +125,7 @@ class BPlusTree { * (3) (7) * (1,2) (3,4) (5,6) (7,10,30) // The output tree example */ - void BatchOpsFromFile(const std::filesystem::path &file_name, Transaction *txn = nullptr); + void BatchOpsFromFile(const std::filesystem::path &file_name); private: /* Debug Routines for FREE!! */ diff --git a/src/include/storage/index/b_plus_tree_debug.h b/src/include/storage/index/b_plus_tree_debug.h new file mode 100644 index 000000000..790030fa2 --- /dev/null +++ b/src/include/storage/index/b_plus_tree_debug.h @@ -0,0 +1,278 @@ +//===----------------------------------------------------------------------===// +// +// BusTub +// +// b_plus_tree_debug.h +// +// Identification: bustub/src/include/storage/index/b_plus_tree_debug.h +// +// Copyright (c) 2024, Carnegie Mellon University Database Group +// +//===----------------------------------------------------------------------===// + +#include +#include + +#include "common/exception.h" +#include "common/logger.h" +#include "common/rid.h" +#include "storage/index/b_plus_tree.h" +#include "storage/page/b_plus_tree_page.h" + +namespace bustub { + +/* + * All the methods in this file are used for test and debug only. + * You don't need to modify them. + */ + +/***************************************************************************** + * UTILITIES AND DEBUG + *****************************************************************************/ + +/* + * This method is used for test only + * Read data from file and insert one by one + */ +INDEX_TEMPLATE_ARGUMENTS +void BPLUSTREE_TYPE::InsertFromFile(const std::filesystem::path &file_name) { + int64_t key; + std::ifstream input(file_name); + while (input) { + input >> key; + + KeyType index_key; + index_key.SetFromInteger(key); + RID rid(key); + Insert(index_key, rid); + } +} +/* + * This method is used for test only + * Read data from file and remove one by one + */ +INDEX_TEMPLATE_ARGUMENTS +void BPLUSTREE_TYPE::RemoveFromFile(const std::filesystem::path &file_name) { + int64_t key; + std::ifstream input(file_name); + while (input) { + input >> key; + KeyType index_key; + index_key.SetFromInteger(key); + Remove(index_key); + } +} + +INDEX_TEMPLATE_ARGUMENTS +void BPLUSTREE_TYPE::Print(BufferPoolManager *bpm) { + auto root_page_id = GetRootPageId(); + if (root_page_id != INVALID_PAGE_ID) { + auto guard = bpm->ReadPage(root_page_id); + PrintTree(guard.GetPageId(), guard.template As()); + } +} + +INDEX_TEMPLATE_ARGUMENTS +void BPLUSTREE_TYPE::PrintTree(page_id_t page_id, const BPlusTreePage *page) { + if (page->IsLeafPage()) { + auto *leaf = reinterpret_cast(page); + std::cout << "Leaf Page: " << page_id << "\tNext: " << leaf->GetNextPageId() << std::endl; + + // Print the contents of the leaf page. + std::cout << "Contents: "; + for (int i = 0; i < leaf->GetSize(); i++) { + std::cout << leaf->KeyAt(i); + if ((i + 1) < leaf->GetSize()) { + std::cout << ", "; + } + } + std::cout << std::endl; + std::cout << std::endl; + + } else { + auto *internal = reinterpret_cast(page); + std::cout << "Internal Page: " << page_id << std::endl; + + // Print the contents of the internal page. + std::cout << "Contents: "; + for (int i = 0; i < internal->GetSize(); i++) { + if (i == 0) { + std::cout << internal->ValueAt(i); + } else { + std::cout << internal->KeyAt(i) << ": " << internal->ValueAt(i); + } + if ((i + 1) < internal->GetSize()) { + std::cout << ", "; + } + } + std::cout << std::endl; + std::cout << std::endl; + for (int i = 0; i < internal->GetSize(); i++) { + auto guard = bpm_->ReadPage(internal->ValueAt(i)); + PrintTree(guard.GetPageId(), guard.template As()); + } + } +} + +INDEX_TEMPLATE_ARGUMENTS +void BPLUSTREE_TYPE::Draw(BufferPoolManager *bpm, const std::filesystem::path &outf) { + if (IsEmpty()) { + LOG_WARN("Drawing an empty tree"); + return; + } + + std::ofstream out(outf); + out << "digraph G {" << std::endl; + auto root_page_id = GetRootPageId(); + auto guard = bpm->ReadPage(root_page_id); + ToGraph(guard.GetPageId(), guard.template As(), out); + out << "}" << std::endl; + out.close(); +} + +INDEX_TEMPLATE_ARGUMENTS +void BPLUSTREE_TYPE::ToGraph(page_id_t page_id, const BPlusTreePage *page, std::ofstream &out) { + std::string leaf_prefix("LEAF_"); + std::string internal_prefix("INT_"); + if (page->IsLeafPage()) { + auto *leaf = reinterpret_cast(page); + // Print node name + out << leaf_prefix << page_id; + // Print node properties + out << "[shape=plain color=green "; + // Print data of the node + out << "label=<\n"; + // Print data + out << "\n"; + out << "\n"; + out << ""; + for (int i = 0; i < leaf->GetSize(); i++) { + out << "\n"; + } + out << ""; + // Print table end + out << "
GetSize() << "\">P=" << page_id << "
GetSize() << "\">" + << "max_size=" << leaf->GetMaxSize() << ",min_size=" << leaf->GetMinSize() << ",size=" << leaf->GetSize() + << "
" << leaf->KeyAt(i) << "
>];\n"; + // Print Leaf node link if there is a next page + if (leaf->GetNextPageId() != INVALID_PAGE_ID) { + out << leaf_prefix << page_id << " -> " << leaf_prefix << leaf->GetNextPageId() << ";\n"; + out << "{rank=same " << leaf_prefix << page_id << " " << leaf_prefix << leaf->GetNextPageId() << "};\n"; + } + } else { + auto *inner = reinterpret_cast(page); + // Print node name + out << internal_prefix << page_id; + // Print node properties + out << "[shape=plain color=pink "; // why not? + // Print data of the node + out << "label=<\n"; + // Print data + out << "\n"; + out << "\n"; + out << ""; + for (int i = 0; i < inner->GetSize(); i++) { + out << "\n"; + } + out << ""; + // Print table end + out << "
GetSize() << "\">P=" << page_id << "
GetSize() << "\">" + << "max_size=" << inner->GetMaxSize() << ",min_size=" << inner->GetMinSize() << ",size=" << inner->GetSize() + << "
ValueAt(i) << "\">"; + if (i > 0) { + out << inner->KeyAt(i); + } else { + out << " "; + } + out << "
>];\n"; + // Print leaves + for (int i = 0; i < inner->GetSize(); i++) { + auto child_guard = bpm_->ReadPage(inner->ValueAt(i)); + auto child_page = child_guard.template As(); + ToGraph(child_guard.GetPageId(), child_page, out); + if (i > 0) { + auto sibling_guard = bpm_->ReadPage(inner->ValueAt(i - 1)); + auto sibling_page = sibling_guard.template As(); + if (!sibling_page->IsLeafPage() && !child_page->IsLeafPage()) { + out << "{rank=same " << internal_prefix << sibling_guard.GetPageId() << " " << internal_prefix + << child_guard.GetPageId() << "};\n"; + } + } + out << internal_prefix << page_id << ":p" << child_guard.GetPageId() << " -> "; + if (child_page->IsLeafPage()) { + out << leaf_prefix << child_guard.GetPageId() << ";\n"; + } else { + out << internal_prefix << child_guard.GetPageId() << ";\n"; + } + } + } +} + +INDEX_TEMPLATE_ARGUMENTS +auto BPLUSTREE_TYPE::DrawBPlusTree() -> std::string { + if (IsEmpty()) { + return "()"; + } + + PrintableBPlusTree p_root = ToPrintableBPlusTree(GetRootPageId()); + std::ostringstream out_buf; + p_root.Print(out_buf); + + return out_buf.str(); +} + +/* + * This method is used for test only + * Read data from file and insert/remove one by one + */ +INDEX_TEMPLATE_ARGUMENTS +void BPLUSTREE_TYPE::BatchOpsFromFile(const std::filesystem::path &file_name) { + int64_t key; + char instruction; + std::ifstream input(file_name); + while (input) { + input >> instruction >> key; + RID rid(key); + KeyType index_key; + index_key.SetFromInteger(key); + switch (instruction) { + case 'i': + Insert(index_key, rid); + break; + case 'd': + Remove(index_key); + break; + default: + break; + } + } +} + +INDEX_TEMPLATE_ARGUMENTS +auto BPLUSTREE_TYPE::ToPrintableBPlusTree(page_id_t root_id) -> PrintableBPlusTree { + auto root_page_guard = bpm_->ReadPage(root_id); + auto root_page = root_page_guard.template As(); + PrintableBPlusTree proot; + + if (root_page->IsLeafPage()) { + auto leaf_page = root_page_guard.template As(); + proot.keys_ = leaf_page->ToString(); + proot.size_ = proot.keys_.size() + 4; // 4 more spaces for indent + + return proot; + } + + // draw internal page + auto internal_page = root_page_guard.template As(); + proot.keys_ = internal_page->ToString(); + proot.size_ = 0; + for (int i = 0; i < internal_page->GetSize(); i++) { + page_id_t child_id = internal_page->ValueAt(i); + PrintableBPlusTree child_node = ToPrintableBPlusTree(child_id); + proot.size_ += child_node.size_; + proot.children_.push_back(child_node); + } + + return proot; +} +} // namespace bustub diff --git a/src/include/storage/index/index_iterator.h b/src/include/storage/index/index_iterator.h index 7618823e1..df0884aef 100644 --- a/src/include/storage/index/index_iterator.h +++ b/src/include/storage/index/index_iterator.h @@ -13,6 +13,7 @@ * For range scan of b+ tree */ #pragma once +#include #include "storage/page/b_plus_tree_leaf_page.h" namespace bustub { @@ -28,7 +29,7 @@ class IndexIterator { auto IsEnd() -> bool; - auto operator*() -> const MappingType &; + auto operator*() -> std::pair; auto operator++() -> IndexIterator &; diff --git a/src/include/storage/page/b_plus_tree_internal_page.h b/src/include/storage/page/b_plus_tree_internal_page.h index 29639b98b..b5bf4ce11 100644 --- a/src/include/storage/page/b_plus_tree_internal_page.h +++ b/src/include/storage/page/b_plus_tree_internal_page.h @@ -5,7 +5,7 @@ // // Identification: src/include/page/b_plus_tree_internal_page.h // -// Copyright (c) 2018, Carnegie Mellon University Database Group +// Copyright (c) 2018-2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// #pragma once @@ -19,20 +19,27 @@ namespace bustub { #define B_PLUS_TREE_INTERNAL_PAGE_TYPE BPlusTreeInternalPage #define INTERNAL_PAGE_HEADER_SIZE 12 -#define INTERNAL_PAGE_SIZE ((BUSTUB_PAGE_SIZE - INTERNAL_PAGE_HEADER_SIZE) / (sizeof(MappingType))) +#define INTERNAL_PAGE_SLOT_CNT \ + ((BUSTUB_PAGE_SIZE - INTERNAL_PAGE_HEADER_SIZE) / ((int)(sizeof(KeyType) + sizeof(ValueType)))) // NOLINT /** * Store `n` indexed keys and `n + 1` child pointers (page_id) within internal page. * Pointer PAGE_ID(i) points to a subtree in which all keys K satisfy: * K(i) <= K < K(i+1). * NOTE: Since the number of keys does not equal to number of child pointers, - * the first key always remains invalid. That is to say, any search / lookup + * the first key in key_array_ always remains invalid. That is to say, any search / lookup * should ignore the first key. * * Internal page format (keys are stored in increasing order): - * ---------------------------------------------------------------------------------- - * | HEADER | KEY(1) + PAGE_ID(1) | KEY(2) + PAGE_ID(2) | ... | KEY(n) + PAGE_ID(n) | - * ---------------------------------------------------------------------------------- + * --------- + * | HEADER | + * --------- + * ------------------------------------------ + * | KEY(1)(INVALID) | KEY(2) | ... | KEY(n) | + * ------------------------------------------ + * --------------------------------------------- + * | PAGE_ID(1) | PAGE_ID(2) | ... | PAGE_ID(n) | + * --------------------------------------------- */ INDEX_TEMPLATE_ARGUMENTS class BPlusTreeInternalPage : public BPlusTreePage { @@ -46,7 +53,7 @@ class BPlusTreeInternalPage : public BPlusTreePage { * the creation of a new page to make a valid `BPlusTreeInternalPage` * @param max_size Maximal size of the page */ - void Init(int max_size = INTERNAL_PAGE_SIZE); + void Init(int max_size = INTERNAL_PAGE_SLOT_CNT); /** * @param index The index of the key to get. Index must be non-zero. @@ -99,8 +106,10 @@ class BPlusTreeInternalPage : public BPlusTreePage { } private: - // Flexible array member for page data. - MappingType array_[0]; + // Array members for page data. + KeyType key_array_[INTERNAL_PAGE_SLOT_CNT]; + ValueType page_id_array_[INTERNAL_PAGE_SLOT_CNT]; + // (Fall 2024) Feel free to add more fields and helper functions below if needed }; } // namespace bustub diff --git a/src/include/storage/page/b_plus_tree_leaf_page.h b/src/include/storage/page/b_plus_tree_leaf_page.h index d952647ac..d3ee83b8f 100644 --- a/src/include/storage/page/b_plus_tree_leaf_page.h +++ b/src/include/storage/page/b_plus_tree_leaf_page.h @@ -5,7 +5,7 @@ // // Identification: src/include/page/b_plus_tree_leaf_page.h // -// Copyright (c) 2018, Carnegie Mellon University Database Group +// Copyright (c) 2018-2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// #pragma once @@ -20,7 +20,7 @@ namespace bustub { #define B_PLUS_TREE_LEAF_PAGE_TYPE BPlusTreeLeafPage #define LEAF_PAGE_HEADER_SIZE 16 -#define LEAF_PAGE_SIZE ((BUSTUB_PAGE_SIZE - LEAF_PAGE_HEADER_SIZE) / sizeof(MappingType)) +#define LEAF_PAGE_SLOT_CNT ((BUSTUB_PAGE_SIZE - LEAF_PAGE_HEADER_SIZE) / (sizeof(KeyType) + sizeof(ValueType))) /** * Store indexed key and record id (record id = page id combined with slot id, @@ -28,14 +28,23 @@ namespace bustub { * page. Only support unique key. * * Leaf page format (keys are stored in order): - * ----------------------------------------------------------------------- - * | HEADER | KEY(1) + RID(1) | KEY(2) + RID(2) | ... | KEY(n) + RID(n) | - * ----------------------------------------------------------------------- + * --------- + * | HEADER | + * --------- + * --------------------------------- + * | KEY(1) | KEY(2) | ... | KEY(n) | + * --------------------------------- + * --------------------------------- + * | RID(1) | RID(2) | ... | RID(n) | + * --------------------------------- * - * Header format (size in byte, 16 bytes in total): - * ----------------------------------------------------------------------- - * | PageType (4) | CurrentSize (4) | MaxSize (4) | NextPageId (4) | ... | - * ----------------------------------------------------------------------- + * Header format (size in byte, 16 bytes in total): + * ----------------------------------------------- + * | PageType (4) | CurrentSize (4) | MaxSize (4) | + * ----------------------------------------------- + * ----------------- + * | NextPageId (4) | + * ----------------- */ INDEX_TEMPLATE_ARGUMENTS class BPlusTreeLeafPage : public BPlusTreePage { @@ -49,7 +58,7 @@ class BPlusTreeLeafPage : public BPlusTreePage { * method to set default values * @param max_size Max size of the leaf node */ - void Init(int max_size = LEAF_PAGE_SIZE); + void Init(int max_size = LEAF_PAGE_SLOT_CNT); // Helper methods auto GetNextPageId() const -> page_id_t; @@ -83,8 +92,10 @@ class BPlusTreeLeafPage : public BPlusTreePage { private: page_id_t next_page_id_; - // Flexible array member for page data. - MappingType array_[0]; + // Array members for page data. + KeyType key_array_[LEAF_PAGE_SLOT_CNT]; + ValueType rid_array_[LEAF_PAGE_SLOT_CNT]; + // (Fall 2024) Feel free to add more fields and helper functions below if needed }; } // namespace bustub diff --git a/src/include/storage/page/b_plus_tree_page.h b/src/include/storage/page/b_plus_tree_page.h index 884e2e6cc..a8588dbb8 100644 --- a/src/include/storage/page/b_plus_tree_page.h +++ b/src/include/storage/page/b_plus_tree_page.h @@ -50,7 +50,7 @@ class BPlusTreePage { auto GetSize() const -> int; void SetSize(int size); - void IncreaseSize(int amount); + void ChangeSizeBy(int amount); auto GetMaxSize() const -> int; void SetMaxSize(int max_size); @@ -59,7 +59,9 @@ class BPlusTreePage { private: // Member variables, attributes that both internal and leaf page share IndexPageType page_type_ __attribute__((__unused__)); + // Number of key & value pairs in a page int size_ __attribute__((__unused__)); + // Max number of key & value pairs in a page int max_size_ __attribute__((__unused__)); }; diff --git a/src/storage/index/b_plus_tree.cpp b/src/storage/index/b_plus_tree.cpp index 5da9cea98..f52603e06 100644 --- a/src/storage/index/b_plus_tree.cpp +++ b/src/storage/index/b_plus_tree.cpp @@ -1,10 +1,5 @@ -#include -#include - -#include "common/exception.h" -#include "common/logger.h" -#include "common/rid.h" #include "storage/index/b_plus_tree.h" +#include "storage/index/b_plus_tree_debug.h" namespace bustub { @@ -37,7 +32,7 @@ auto BPLUSTREE_TYPE::IsEmpty() const -> bool { return true; } * @return : true means key exists */ INDEX_TEMPLATE_ARGUMENTS -auto BPLUSTREE_TYPE::GetValue(const KeyType &key, std::vector *result, Transaction *txn) -> bool { +auto BPLUSTREE_TYPE::GetValue(const KeyType &key, std::vector *result) -> bool { // Declaration of context instance. Context ctx; (void)ctx; @@ -55,7 +50,7 @@ auto BPLUSTREE_TYPE::GetValue(const KeyType &key, std::vector *result * keys return false, otherwise return true. */ INDEX_TEMPLATE_ARGUMENTS -auto BPLUSTREE_TYPE::Insert(const KeyType &key, const ValueType &value, Transaction *txn) -> bool { +auto BPLUSTREE_TYPE::Insert(const KeyType &key, const ValueType &value) -> bool { // Declaration of context instance. Context ctx; (void)ctx; @@ -73,7 +68,7 @@ auto BPLUSTREE_TYPE::Insert(const KeyType &key, const ValueType &value, Transact * necessary. */ INDEX_TEMPLATE_ARGUMENTS -void BPLUSTREE_TYPE::Remove(const KeyType &key, Transaction *txn) { +void BPLUSTREE_TYPE::Remove(const KeyType &key) { // Declaration of context instance. Context ctx; (void)ctx; @@ -112,255 +107,6 @@ auto BPLUSTREE_TYPE::End() -> INDEXITERATOR_TYPE { return INDEXITERATOR_TYPE(); INDEX_TEMPLATE_ARGUMENTS auto BPLUSTREE_TYPE::GetRootPageId() -> page_id_t { return 0; } -/***************************************************************************** - * UTILITIES AND DEBUG - *****************************************************************************/ - -/* - * This method is used for test only - * Read data from file and insert one by one - */ -INDEX_TEMPLATE_ARGUMENTS -void BPLUSTREE_TYPE::InsertFromFile(const std::filesystem::path &file_name, Transaction *txn) { - int64_t key; - std::ifstream input(file_name); - while (input >> key) { - KeyType index_key; - index_key.SetFromInteger(key); - RID rid(key); - Insert(index_key, rid, txn); - } -} -/* - * This method is used for test only - * Read data from file and remove one by one - */ -INDEX_TEMPLATE_ARGUMENTS -void BPLUSTREE_TYPE::RemoveFromFile(const std::filesystem::path &file_name, Transaction *txn) { - int64_t key; - std::ifstream input(file_name); - while (input >> key) { - KeyType index_key; - index_key.SetFromInteger(key); - Remove(index_key, txn); - } -} - -/* - * This method is used for test only - * Read data from file and insert/remove one by one - */ -INDEX_TEMPLATE_ARGUMENTS -void BPLUSTREE_TYPE::BatchOpsFromFile(const std::filesystem::path &file_name, Transaction *txn) { - int64_t key; - char instruction; - std::ifstream input(file_name); - while (input) { - input >> instruction >> key; - RID rid(key); - KeyType index_key; - index_key.SetFromInteger(key); - switch (instruction) { - case 'i': - Insert(index_key, rid, txn); - break; - case 'd': - Remove(index_key, txn); - break; - default: - break; - } - } -} - -INDEX_TEMPLATE_ARGUMENTS -void BPLUSTREE_TYPE::Print(BufferPoolManager *bpm) { - auto root_page_id = GetRootPageId(); - if (root_page_id != INVALID_PAGE_ID) { - auto guard = bpm->ReadPage(root_page_id); - PrintTree(guard.GetPageId(), guard.template As()); - } -} - -INDEX_TEMPLATE_ARGUMENTS -void BPLUSTREE_TYPE::PrintTree(page_id_t page_id, const BPlusTreePage *page) { - if (page->IsLeafPage()) { - auto *leaf = reinterpret_cast(page); - std::cout << "Leaf Page: " << page_id << "\tNext: " << leaf->GetNextPageId() << std::endl; - - // Print the contents of the leaf page. - std::cout << "Contents: "; - for (int i = 0; i < leaf->GetSize(); i++) { - std::cout << leaf->KeyAt(i); - if ((i + 1) < leaf->GetSize()) { - std::cout << ", "; - } - } - std::cout << std::endl; - std::cout << std::endl; - - } else { - auto *internal = reinterpret_cast(page); - std::cout << "Internal Page: " << page_id << std::endl; - - // Print the contents of the internal page. - std::cout << "Contents: "; - for (int i = 0; i < internal->GetSize(); i++) { - std::cout << internal->KeyAt(i) << ": " << internal->ValueAt(i); - if ((i + 1) < internal->GetSize()) { - std::cout << ", "; - } - } - std::cout << std::endl; - std::cout << std::endl; - for (int i = 0; i < internal->GetSize(); i++) { - auto guard = bpm_->ReadPage(internal->ValueAt(i)); - PrintTree(guard.GetPageId(), guard.template As()); - } - } -} - -/** - * This method is used for debug only, You don't need to modify - */ -INDEX_TEMPLATE_ARGUMENTS -void BPLUSTREE_TYPE::Draw(BufferPoolManager *bpm, const std::filesystem::path &outf) { - if (IsEmpty()) { - LOG_WARN("Drawing an empty tree"); - return; - } - - std::ofstream out(outf); - out << "digraph G {" << std::endl; - auto root_page_id = GetRootPageId(); - auto guard = bpm->ReadPage(root_page_id); - ToGraph(guard.GetPageId(), guard.template As(), out); - out << "}" << std::endl; - out.close(); -} - -/** - * This method is used for debug only, You don't need to modify - */ -INDEX_TEMPLATE_ARGUMENTS -void BPLUSTREE_TYPE::ToGraph(page_id_t page_id, const BPlusTreePage *page, std::ofstream &out) { - std::string leaf_prefix("LEAF_"); - std::string internal_prefix("INT_"); - if (page->IsLeafPage()) { - auto *leaf = reinterpret_cast(page); - // Print node name - out << leaf_prefix << page_id; - // Print node properties - out << "[shape=plain color=green "; - // Print data of the node - out << "label=<\n"; - // Print data - out << "\n"; - out << "\n"; - out << ""; - for (int i = 0; i < leaf->GetSize(); i++) { - out << "\n"; - } - out << ""; - // Print table end - out << "
GetSize() << "\">P=" << page_id << "
GetSize() << "\">" - << "max_size=" << leaf->GetMaxSize() << ",min_size=" << leaf->GetMinSize() << ",size=" << leaf->GetSize() - << "
" << leaf->KeyAt(i) << "
>];\n"; - // Print Leaf node link if there is a next page - if (leaf->GetNextPageId() != INVALID_PAGE_ID) { - out << leaf_prefix << page_id << " -> " << leaf_prefix << leaf->GetNextPageId() << ";\n"; - out << "{rank=same " << leaf_prefix << page_id << " " << leaf_prefix << leaf->GetNextPageId() << "};\n"; - } - } else { - auto *inner = reinterpret_cast(page); - // Print node name - out << internal_prefix << page_id; - // Print node properties - out << "[shape=plain color=pink "; // why not? - // Print data of the node - out << "label=<\n"; - // Print data - out << "\n"; - out << "\n"; - out << ""; - for (int i = 0; i < inner->GetSize(); i++) { - out << "\n"; - } - out << ""; - // Print table end - out << "
GetSize() << "\">P=" << page_id << "
GetSize() << "\">" - << "max_size=" << inner->GetMaxSize() << ",min_size=" << inner->GetMinSize() << ",size=" << inner->GetSize() - << "
ValueAt(i) << "\">"; - if (i > 0) { - out << inner->KeyAt(i); - } else { - out << " "; - } - out << "
>];\n"; - // Print leaves - for (int i = 0; i < inner->GetSize(); i++) { - auto child_guard = bpm_->ReadPage(inner->ValueAt(i)); - auto child_page = child_guard.template As(); - ToGraph(child_guard.GetPageId(), child_page, out); - if (i > 0) { - auto sibling_guard = bpm_->ReadPage(inner->ValueAt(i - 1)); - auto sibling_page = sibling_guard.template As(); - if (!sibling_page->IsLeafPage() && !child_page->IsLeafPage()) { - out << "{rank=same " << internal_prefix << sibling_guard.GetPageId() << " " << internal_prefix - << child_guard.GetPageId() << "};\n"; - } - } - out << internal_prefix << page_id << ":p" << child_guard.GetPageId() << " -> "; - if (child_page->IsLeafPage()) { - out << leaf_prefix << child_guard.GetPageId() << ";\n"; - } else { - out << internal_prefix << child_guard.GetPageId() << ";\n"; - } - } - } -} - -INDEX_TEMPLATE_ARGUMENTS -auto BPLUSTREE_TYPE::DrawBPlusTree() -> std::string { - if (IsEmpty()) { - return "()"; - } - - PrintableBPlusTree p_root = ToPrintableBPlusTree(GetRootPageId()); - std::ostringstream out_buf; - p_root.Print(out_buf); - - return out_buf.str(); -} - -INDEX_TEMPLATE_ARGUMENTS -auto BPLUSTREE_TYPE::ToPrintableBPlusTree(page_id_t root_id) -> PrintableBPlusTree { - auto root_page_guard = bpm_->ReadPage(root_id); - auto root_page = root_page_guard.template As(); - PrintableBPlusTree proot; - - if (root_page->IsLeafPage()) { - auto leaf_page = root_page_guard.template As(); - proot.keys_ = leaf_page->ToString(); - proot.size_ = proot.keys_.size() + 4; // 4 more spaces for indent - - return proot; - } - - // draw internal page - auto internal_page = root_page_guard.template As(); - proot.keys_ = internal_page->ToString(); - proot.size_ = 0; - for (int i = 0; i < internal_page->GetSize(); i++) { - page_id_t child_id = internal_page->ValueAt(i); - PrintableBPlusTree child_node = ToPrintableBPlusTree(child_id); - proot.size_ += child_node.size_; - proot.children_.push_back(child_node); - } - - return proot; -} - template class BPlusTree, RID, GenericComparator<4>>; template class BPlusTree, RID, GenericComparator<8>>; diff --git a/src/storage/index/b_plus_tree_index.cpp b/src/storage/index/b_plus_tree_index.cpp index 5b613729d..4e22c124f 100644 --- a/src/storage/index/b_plus_tree_index.cpp +++ b/src/storage/index/b_plus_tree_index.cpp @@ -5,7 +5,7 @@ // // Identification: src/index/b_plus_tree_index.cpp // -// Copyright (c) 2018, Carnegie Mellon University Database Group +// Copyright (c) 2018-2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// @@ -29,7 +29,7 @@ auto BPLUSTREE_INDEX_TYPE::InsertEntry(const Tuple &key, RID rid, Transaction *t KeyType index_key; index_key.SetFromKey(key); - return container_->Insert(index_key, rid, transaction); + return container_->Insert(index_key, rid); } INDEX_TEMPLATE_ARGUMENTS @@ -38,7 +38,7 @@ void BPLUSTREE_INDEX_TYPE::DeleteEntry(const Tuple &key, RID rid, Transaction *t KeyType index_key; index_key.SetFromKey(key); - container_->Remove(index_key, transaction); + container_->Remove(index_key); } INDEX_TEMPLATE_ARGUMENTS @@ -47,7 +47,7 @@ void BPLUSTREE_INDEX_TYPE::ScanKey(const Tuple &key, std::vector *result, T KeyType index_key; index_key.SetFromKey(key); - container_->GetValue(index_key, result, transaction); + container_->GetValue(index_key, result); } INDEX_TEMPLATE_ARGUMENTS diff --git a/src/storage/index/index_iterator.cpp b/src/storage/index/index_iterator.cpp index 3c2ee3ae6..b9ac2b71c 100644 --- a/src/storage/index/index_iterator.cpp +++ b/src/storage/index/index_iterator.cpp @@ -21,7 +21,9 @@ INDEX_TEMPLATE_ARGUMENTS auto INDEXITERATOR_TYPE::IsEnd() -> bool { throw std::runtime_error("unimplemented"); } INDEX_TEMPLATE_ARGUMENTS -auto INDEXITERATOR_TYPE::operator*() -> const MappingType & { throw std::runtime_error("unimplemented"); } +auto INDEXITERATOR_TYPE::operator*() -> std::pair { + throw std::runtime_error("unimplemented"); +} INDEX_TEMPLATE_ARGUMENTS auto INDEXITERATOR_TYPE::operator++() -> INDEXITERATOR_TYPE & { throw std::runtime_error("unimplemented"); } diff --git a/src/storage/page/b_plus_tree_internal_page.cpp b/src/storage/page/b_plus_tree_internal_page.cpp index e0ab2b33c..9be3b0b40 100644 --- a/src/storage/page/b_plus_tree_internal_page.cpp +++ b/src/storage/page/b_plus_tree_internal_page.cpp @@ -5,7 +5,7 @@ // // Identification: src/page/b_plus_tree_internal_page.cpp // -// Copyright (c) 2018, Carnegie Mellon University Database Group +// Copyright (c) 2018-2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// @@ -26,21 +26,17 @@ namespace bustub { INDEX_TEMPLATE_ARGUMENTS void B_PLUS_TREE_INTERNAL_PAGE_TYPE::Init(int max_size) {} /* - * Helper method to get/set the key associated with input "index"(a.k.a + * Helper method to get/set the key associated with input "index" (a.k.a * array offset) */ INDEX_TEMPLATE_ARGUMENTS -auto B_PLUS_TREE_INTERNAL_PAGE_TYPE::KeyAt(int index) const -> KeyType { - // replace with your own code - KeyType key{}; - return key; -} +auto B_PLUS_TREE_INTERNAL_PAGE_TYPE::KeyAt(int index) const -> KeyType { return {}; } INDEX_TEMPLATE_ARGUMENTS void B_PLUS_TREE_INTERNAL_PAGE_TYPE::SetKeyAt(int index, const KeyType &key) {} /* - * Helper method to get the value associated with input "index"(a.k.a array + * Helper method to get the value associated with input "index" (a.k.a array * offset) */ INDEX_TEMPLATE_ARGUMENTS diff --git a/src/storage/page/b_plus_tree_leaf_page.cpp b/src/storage/page/b_plus_tree_leaf_page.cpp index 3b325d721..763eddb42 100644 --- a/src/storage/page/b_plus_tree_leaf_page.cpp +++ b/src/storage/page/b_plus_tree_leaf_page.cpp @@ -5,7 +5,7 @@ // // Identification: src/page/b_plus_tree_leaf_page.cpp // -// Copyright (c) 2018, Carnegie Mellon University Database Group +// Copyright (c) 2018-2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// @@ -38,15 +38,11 @@ INDEX_TEMPLATE_ARGUMENTS void B_PLUS_TREE_LEAF_PAGE_TYPE::SetNextPageId(page_id_t next_page_id) {} /* - * Helper method to find and return the key associated with input "index"(a.k.a + * Helper method to find and return the key associated with input "index" (a.k.a * array offset) */ INDEX_TEMPLATE_ARGUMENTS -auto B_PLUS_TREE_LEAF_PAGE_TYPE::KeyAt(int index) const -> KeyType { - // replace with your own code - KeyType key{}; - return key; -} +auto B_PLUS_TREE_LEAF_PAGE_TYPE::KeyAt(int index) const -> KeyType { return {}; } template class BPlusTreeLeafPage, RID, GenericComparator<4>>; template class BPlusTreeLeafPage, RID, GenericComparator<8>>; diff --git a/src/storage/page/b_plus_tree_page.cpp b/src/storage/page/b_plus_tree_page.cpp index 0339069ad..ea26571fb 100644 --- a/src/storage/page/b_plus_tree_page.cpp +++ b/src/storage/page/b_plus_tree_page.cpp @@ -26,7 +26,7 @@ void BPlusTreePage::SetPageType(IndexPageType page_type) {} */ auto BPlusTreePage::GetSize() const -> int { return 0; } void BPlusTreePage::SetSize(int size) {} -void BPlusTreePage::IncreaseSize(int amount) {} +void BPlusTreePage::ChangeSizeBy(int amount) {} /* * Helper methods to get/set max size (capacity) of the page @@ -37,6 +37,7 @@ void BPlusTreePage::SetMaxSize(int size) {} /* * Helper method to get min page size * Generally, min page size == max page size / 2 + * But whether you will take ceil() or floor() depends on your implementation */ auto BPlusTreePage::GetMinSize() const -> int { return 0; } diff --git a/test/include/storage/b_plus_tree_utils.h b/test/include/storage/b_plus_tree_utils.h new file mode 100644 index 000000000..25506135c --- /dev/null +++ b/test/include/storage/b_plus_tree_utils.h @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// BusTub +// +// b_plus_tree_utils.h +// +// Identification: test/include/storage/b_plus_tree_utils.h +// +// Copyright (c) 2015-2024, Carnegie Mellon University Database Group +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include + +#include "buffer/buffer_pool_manager.h" +#include "storage/index/b_plus_tree.h" + +namespace bustub { + +template +bool TreeValuesMatch(BPlusTree &tree, std::vector &inserted, + std::vector &deleted) { + std::vector rids; + KeyType index_key; + for (auto &key : inserted) { + rids.clear(); + index_key.SetFromInteger(key); + tree.GetValue(index_key, &rids); + if (rids.size() != 1) { + return false; + } + } + for (auto &key : deleted) { + rids.clear(); + index_key.SetFromInteger(key); + tree.GetValue(index_key, &rids); + if (!rids.empty()) { + return false; + } + } + return true; +} + +} // namespace bustub diff --git a/test/storage/b_plus_tree_concurrent_test.cpp b/test/storage/b_plus_tree_concurrent_test.cpp index 9aff57211..94dc19ff6 100644 --- a/test/storage/b_plus_tree_concurrent_test.cpp +++ b/test/storage/b_plus_tree_concurrent_test.cpp @@ -6,13 +6,15 @@ // // Identification: test/storage/b_plus_tree_concurrent_test.cpp // -// Copyright (c) 2015-2021, Carnegie Mellon University Database Group +// Copyright (c) 2015-2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// #include // NOLINT #include +#include #include +#include // NOLINT #include // NOLINT #include "buffer/buffer_pool_manager.h" @@ -46,15 +48,13 @@ void InsertHelper(BPlusTree, RID, GenericComparator<8>> *tree, con __attribute__((unused)) uint64_t thread_itr = 0) { GenericKey<8> index_key; RID rid; - // create transaction - auto *transaction = new Transaction(0); + for (auto key : keys) { int64_t value = key & 0xFFFFFFFF; rid.Set(static_cast(key >> 32), value); index_key.SetFromInteger(key); - tree->Insert(index_key, rid, transaction); + tree->Insert(index_key, rid); } - delete transaction; } // helper function to seperate insert @@ -62,30 +62,26 @@ void InsertHelperSplit(BPlusTree, RID, GenericComparator<8>> *tree int total_threads, __attribute__((unused)) uint64_t thread_itr) { GenericKey<8> index_key; RID rid; - // create transaction - auto *transaction = new Transaction(0); + for (auto key : keys) { if (static_cast(key) % total_threads == thread_itr) { int64_t value = key & 0xFFFFFFFF; rid.Set(static_cast(key >> 32), value); index_key.SetFromInteger(key); - tree->Insert(index_key, rid, transaction); + tree->Insert(index_key, rid); } } - delete transaction; } // helper function to delete void DeleteHelper(BPlusTree, RID, GenericComparator<8>> *tree, const std::vector &remove_keys, __attribute__((unused)) uint64_t thread_itr = 0) { GenericKey<8> index_key; - // create transaction - auto *transaction = new Transaction(0); + for (auto key : remove_keys) { index_key.SetFromInteger(key); - tree->Remove(index_key, transaction); + tree->Remove(index_key); } - delete transaction; } // helper function to seperate delete @@ -93,20 +89,17 @@ void DeleteHelperSplit(BPlusTree, RID, GenericComparator<8>> *tree const std::vector &remove_keys, int total_threads, __attribute__((unused)) uint64_t thread_itr) { GenericKey<8> index_key; - // create transaction - auto *transaction = new Transaction(0); + for (auto key : remove_keys) { if (static_cast(key) % total_threads == thread_itr) { index_key.SetFromInteger(key); - tree->Remove(index_key, transaction); + tree->Remove(index_key); } } - delete transaction; } void LookupHelper(BPlusTree, RID, GenericComparator<8>> *tree, const std::vector &keys, - uint64_t tid, __attribute__((unused)) uint64_t thread_itr = 0) { - auto *transaction = new Transaction(static_cast(tid)); + __attribute__((unused)) uint64_t thread_itr = 0) { GenericKey<8> index_key; RID rid; for (auto key : keys) { @@ -114,279 +107,363 @@ void LookupHelper(BPlusTree, RID, GenericComparator<8>> *tree, con rid.Set(static_cast(key >> 32), value); index_key.SetFromInteger(key); std::vector result; - bool res = tree->GetValue(index_key, &result, transaction); + bool res = tree->GetValue(index_key, &result); ASSERT_EQ(res, true); ASSERT_EQ(result.size(), 1); ASSERT_EQ(result[0], rid); } - delete transaction; } -TEST(BPlusTreeConcurrentTest, DISABLED_InsertTest1) { - // create KeyComparator and index schema - auto key_schema = ParseCreateStatement("a bigint"); - GenericComparator<8> comparator(key_schema.get()); - - auto disk_manager = std::make_unique(); - auto *bpm = new BufferPoolManager(50, disk_manager.get()); - // allocate header_page - page_id_t page_id = bpm->NewPage(); - // create b+ tree - BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); - // keys to Insert - std::vector keys; - int64_t scale_factor = 100; - for (int64_t key = 1; key < scale_factor; key++) { - keys.push_back(key); - } - LaunchParallelTest(2, InsertHelper, &tree, keys); +const size_t NUM_ITERS = 50; +const size_t MIXTEST_NUM_ITERS = 20; +static const size_t BPM_SIZE = 50; - std::vector rids; - GenericKey<8> index_key; - for (auto key : keys) { - rids.clear(); - index_key.SetFromInteger(key); - tree.GetValue(index_key, &rids); - EXPECT_EQ(rids.size(), 1); +void InsertTest1Call() { + for (size_t iter = 0; iter < NUM_ITERS; iter++) { + // create KeyComparator and index schema + auto key_schema = ParseCreateStatement("a bigint"); + GenericComparator<8> comparator(key_schema.get()); - int64_t value = key & 0xFFFFFFFF; - EXPECT_EQ(rids[0].GetSlotNum(), value); - } + auto *disk_manager = new DiskManagerUnlimitedMemory(); + auto *bpm = new BufferPoolManager(BPM_SIZE, disk_manager); - int64_t start_key = 1; - int64_t current_key = start_key; - index_key.SetFromInteger(start_key); - for (auto iterator = tree.Begin(index_key); iterator != tree.End(); ++iterator) { - auto location = (*iterator).second; - EXPECT_EQ(location.GetPageId(), 0); - EXPECT_EQ(location.GetSlotNum(), current_key); - current_key = current_key + 1; - } + // create and fetch header_page + page_id_t page_id = bpm->NewPage(); - EXPECT_EQ(current_key, keys.size() + 1); + // create b+ tree + BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, 3, 5); - delete bpm; -} + // keys to Insert + std::vector keys; + int64_t scale_factor = 100; + for (int64_t key = 1; key < scale_factor; key++) { + keys.push_back(key); + } + LaunchParallelTest(2, InsertHelper, &tree, keys); -TEST(BPlusTreeConcurrentTest, DISABLED_InsertTest2) { - // create KeyComparator and index schema - auto key_schema = ParseCreateStatement("a bigint"); - GenericComparator<8> comparator(key_schema.get()); - auto disk_manager = std::make_unique(); - auto *bpm = new BufferPoolManager(50, disk_manager.get()); - // allocate header_page - page_id_t page_id = bpm->NewPage(); - // create b+ tree - BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); - // keys to Insert - std::vector keys; - int64_t scale_factor = 100; - for (int64_t key = 1; key < scale_factor; key++) { - keys.push_back(key); - } - LaunchParallelTest(2, InsertHelperSplit, &tree, keys, 2); + std::vector rids; + GenericKey<8> index_key; + for (auto key : keys) { + rids.clear(); + index_key.SetFromInteger(key); + tree.GetValue(index_key, &rids); + ASSERT_EQ(rids.size(), 1); - std::vector rids; - GenericKey<8> index_key; - for (auto key : keys) { - rids.clear(); - index_key.SetFromInteger(key); - tree.GetValue(index_key, &rids); - EXPECT_EQ(rids.size(), 1); + int64_t value = key & 0xFFFFFFFF; + ASSERT_EQ(rids[0].GetSlotNum(), value); + } - int64_t value = key & 0xFFFFFFFF; - EXPECT_EQ(rids[0].GetSlotNum(), value); - } + int64_t start_key = 1; + int64_t current_key = start_key; - int64_t start_key = 1; - int64_t current_key = start_key; - index_key.SetFromInteger(start_key); - for (auto iterator = tree.Begin(index_key); iterator != tree.End(); ++iterator) { - auto location = (*iterator).second; - EXPECT_EQ(location.GetPageId(), 0); - EXPECT_EQ(location.GetSlotNum(), current_key); - current_key = current_key + 1; - } + for (auto iter = tree.Begin(); iter != tree.End(); ++iter) { + const auto &pair = *iter; + auto location = pair.second; + ASSERT_EQ(location.GetPageId(), 0); + ASSERT_EQ(location.GetSlotNum(), current_key); + current_key = current_key + 1; + } - EXPECT_EQ(current_key, keys.size() + 1); + ASSERT_EQ(current_key, keys.size() + 1); - delete bpm; + delete disk_manager; + delete bpm; + remove("test.db"); + remove("test.log"); + } } -TEST(BPlusTreeConcurrentTest, DISABLED_DeleteTest1) { - // create KeyComparator and index schema - auto key_schema = ParseCreateStatement("a bigint"); - GenericComparator<8> comparator(key_schema.get()); +void InsertTest2Call() { + for (size_t iter = 0; iter < NUM_ITERS; iter++) { + // create KeyComparator and index schema + auto key_schema = ParseCreateStatement("a bigint"); + GenericComparator<8> comparator(key_schema.get()); - auto disk_manager = std::make_unique(); - auto *bpm = new BufferPoolManager(50, disk_manager.get()); + auto *disk_manager = new DiskManagerUnlimitedMemory(); + auto *bpm = new BufferPoolManager(BPM_SIZE, disk_manager); - GenericKey<8> index_key; - // allocate header_page - page_id_t page_id = bpm->NewPage(); - // create b+ tree - BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); - // sequential insert - std::vector keys = {1, 2, 3, 4, 5}; - InsertHelper(&tree, keys); - - std::vector remove_keys = {1, 5, 3, 4}; - LaunchParallelTest(2, DeleteHelper, &tree, remove_keys); - - int64_t start_key = 2; - int64_t current_key = start_key; - int64_t size = 0; - index_key.SetFromInteger(start_key); - for (auto iterator = tree.Begin(index_key); iterator != tree.End(); ++iterator) { - auto location = (*iterator).second; - EXPECT_EQ(location.GetPageId(), 0); - EXPECT_EQ(location.GetSlotNum(), current_key); - current_key = current_key + 1; - size = size + 1; - } + // create and fetch header_page + page_id_t page_id = bpm->NewPage(); - EXPECT_EQ(size, 1); + // create b+ tree + BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, 3, 5); - delete bpm; -} + // keys to Insert + std::vector keys; + int64_t scale_factor = 1000; + for (int64_t key = 1; key < scale_factor; key++) { + keys.push_back(key); + } + LaunchParallelTest(2, InsertHelperSplit, &tree, keys, 2); -TEST(BPlusTreeConcurrentTest, DISABLED_DeleteTest2) { - // create KeyComparator and index schema - auto key_schema = ParseCreateStatement("a bigint"); - GenericComparator<8> comparator(key_schema.get()); + std::vector rids; + GenericKey<8> index_key; + for (auto key : keys) { + rids.clear(); + index_key.SetFromInteger(key); + tree.GetValue(index_key, &rids); + ASSERT_EQ(rids.size(), 1); - auto disk_manager = std::make_unique(); - auto *bpm = new BufferPoolManager(50, disk_manager.get()); - GenericKey<8> index_key; - // allocate header_page - page_id_t page_id = bpm->NewPage(); - // create b+ tree - BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); - - // sequential insert - std::vector keys = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - InsertHelper(&tree, keys); - - std::vector remove_keys = {1, 4, 3, 2, 5, 6}; - LaunchParallelTest(2, DeleteHelperSplit, &tree, remove_keys, 2); - - int64_t start_key = 7; - int64_t current_key = start_key; - int64_t size = 0; - index_key.SetFromInteger(start_key); - for (auto iterator = tree.Begin(index_key); iterator != tree.End(); ++iterator) { - auto location = (*iterator).second; - EXPECT_EQ(location.GetPageId(), 0); - EXPECT_EQ(location.GetSlotNum(), current_key); - current_key = current_key + 1; - size = size + 1; - } + int64_t value = key & 0xFFFFFFFF; + ASSERT_EQ(rids[0].GetSlotNum(), value); + } - EXPECT_EQ(size, 4); + int64_t start_key = 1; + int64_t current_key = start_key; - delete bpm; + for (auto iter = tree.Begin(); iter != tree.End(); ++iter) { + const auto &pair = *iter; + auto location = pair.second; + ASSERT_EQ(location.GetPageId(), 0); + ASSERT_EQ(location.GetSlotNum(), current_key); + current_key = current_key + 1; + } + + ASSERT_EQ(current_key, keys.size() + 1); + + delete disk_manager; + delete bpm; + remove("test.db"); + remove("test.log"); + } } -TEST(BPlusTreeConcurrentTest, DISABLED_MixTest1) { - // create KeyComparator and index schema - auto key_schema = ParseCreateStatement("a bigint"); - GenericComparator<8> comparator(key_schema.get()); +void DeleteTest1Call() { + for (size_t iter = 0; iter < NUM_ITERS; iter++) { + // create KeyComparator and index schema + auto key_schema = ParseCreateStatement("a bigint"); + GenericComparator<8> comparator(key_schema.get()); - auto disk_manager = std::make_unique(); - auto *bpm = new BufferPoolManager(50, disk_manager.get()); + auto *disk_manager = new DiskManagerUnlimitedMemory(); + auto *bpm = new BufferPoolManager(BPM_SIZE, disk_manager); - // allocate header_page - page_id_t page_id = bpm->NewPage(); - // create b+ tree - BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); - GenericKey<8> index_key; - // first, populate index - std::vector keys = {1, 2, 3, 4, 5}; - InsertHelper(&tree, keys); - - // concurrent insert - keys.clear(); - for (int i = 6; i <= 10; i++) { - keys.push_back(i); - } - LaunchParallelTest(1, InsertHelper, &tree, keys); - // concurrent delete - std::vector remove_keys = {1, 4, 3, 5, 6}; - LaunchParallelTest(1, DeleteHelper, &tree, remove_keys); - - int64_t start_key = 2; - int64_t size = 0; - index_key.SetFromInteger(start_key); - for (auto iterator = tree.Begin(index_key); iterator != tree.End(); ++iterator) { - size = size + 1; - } + // create and fetch header_page + page_id_t page_id = bpm->NewPage(); - EXPECT_EQ(size, 5); + // create b+ tree + BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, 3, 5); - delete bpm; -} + // sequential insert + std::vector keys = {1, 2, 3, 4, 5}; + InsertHelper(&tree, keys); + + std::vector remove_keys = {1, 5, 3, 4}; + LaunchParallelTest(2, DeleteHelper, &tree, remove_keys); -TEST(BPlusTreeConcurrentTest, DISABLED_MixTest2) { - // create KeyComparator and index schema - auto key_schema = ParseCreateStatement("a bigint"); - GenericComparator<8> comparator(key_schema.get()); - - auto disk_manager = std::make_unique(); - auto *bpm = new BufferPoolManager(50, disk_manager.get()); - - // allocate header_page - page_id_t page_id = bpm->NewPage(); - - // create b+ tree - BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); - - // Add perserved_keys - std::vector perserved_keys; - std::vector dynamic_keys; - int64_t total_keys = 50; - int64_t sieve = 5; - for (int64_t i = 1; i <= total_keys; i++) { - if (i % sieve == 0) { - perserved_keys.push_back(i); - } else { - dynamic_keys.push_back(i); + int64_t start_key = 2; + int64_t current_key = start_key; + int64_t size = 0; + + for (auto iter = tree.Begin(); iter != tree.End(); ++iter) { + const auto &pair = *iter; + auto location = pair.second; + ASSERT_EQ(location.GetPageId(), 0); + ASSERT_EQ(location.GetSlotNum(), current_key); + current_key = current_key + 1; + size = size + 1; } + + ASSERT_EQ(size, 1); + + delete disk_manager; + delete bpm; + remove("test.db"); + remove("test.log"); } - InsertHelper(&tree, perserved_keys, 1); - // Check there are 1000 keys in there - size_t size; - - auto insert_task = [&](int tid) { InsertHelper(&tree, dynamic_keys, tid); }; - auto delete_task = [&](int tid) { DeleteHelper(&tree, dynamic_keys, tid); }; - auto lookup_task = [&](int tid) { LookupHelper(&tree, perserved_keys, tid); }; - - std::vector threads; - std::vector> tasks; - tasks.emplace_back(insert_task); - tasks.emplace_back(delete_task); - tasks.emplace_back(lookup_task); - - size_t num_threads = 6; - for (size_t i = 0; i < num_threads; i++) { - threads.emplace_back(std::thread{tasks[i % tasks.size()], i}); - } - for (size_t i = 0; i < num_threads; i++) { - threads[i].join(); +} + +void DeleteTest2Call() { + for (size_t iter = 0; iter < NUM_ITERS; iter++) { + // create KeyComparator and index schema + auto key_schema = ParseCreateStatement("a bigint"); + GenericComparator<8> comparator(key_schema.get()); + + auto *disk_manager = new DiskManagerUnlimitedMemory(); + auto *bpm = new BufferPoolManager(BPM_SIZE, disk_manager); + + // create and fetch header_page + page_id_t page_id = bpm->NewPage(); + + // create b+ tree + BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, 3, 5); + + // sequential insert + std::vector keys = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + InsertHelper(&tree, keys); + + std::vector remove_keys = {1, 4, 3, 2, 5, 6}; + LaunchParallelTest(2, DeleteHelperSplit, &tree, remove_keys, 2); + + int64_t start_key = 7; + int64_t current_key = start_key; + int64_t size = 0; + + for (auto iter = tree.Begin(); iter != tree.End(); ++iter) { + const auto &pair = *iter; + auto location = pair.second; + ASSERT_EQ(location.GetPageId(), 0); + ASSERT_EQ(location.GetSlotNum(), current_key); + current_key = current_key + 1; + size = size + 1; + } + + ASSERT_EQ(size, 4); + + delete disk_manager; + delete bpm; + remove("test.db"); + remove("test.log"); } +} - // Check all reserved keys exist - size = 0; +void MixTest1Call() { + for (size_t iter = 0; iter < MIXTEST_NUM_ITERS; iter++) { + // create KeyComparator and index schema + auto key_schema = ParseCreateStatement("a bigint"); + GenericComparator<8> comparator(key_schema.get()); + + auto *disk_manager = new DiskManagerUnlimitedMemory(); + auto *bpm = new BufferPoolManager(BPM_SIZE, disk_manager); + + // create and fetch header_page + page_id_t page_id = bpm->NewPage(); + + // create b+ tree + BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, 3, 5); + + // first, populate index + std::vector for_insert; + std::vector for_delete; + int64_t sieve = 2; // divide evenly + int64_t total_keys = 1000; + for (int64_t i = 1; i <= total_keys; i++) { + if (i % sieve == 0) { + for_insert.push_back(i); + } else { + for_delete.push_back(i); + } + } + // Insert all the keys to delete + InsertHelper(&tree, for_delete); + + auto insert_task = [&](int tid) { InsertHelper(&tree, for_insert); }; + auto delete_task = [&](int tid) { DeleteHelper(&tree, for_delete); }; + std::vector> tasks; + tasks.emplace_back(insert_task); + tasks.emplace_back(delete_task); + std::vector threads; + size_t num_threads = 10; + for (size_t i = 0; i < num_threads; i++) { + threads.emplace_back(tasks[i % tasks.size()], i); + } + for (size_t i = 0; i < num_threads; i++) { + threads[i].join(); + } - for (auto iter = tree.Begin(); iter != tree.End(); ++iter) { - const auto &pair = *iter; - if ((pair.first).ToString() % sieve == 0) { + int64_t size = 0; + + for (auto iter = tree.Begin(); iter != tree.End(); ++iter) { + const auto &pair = *iter; + ASSERT_EQ((pair.first).ToString(), for_insert[size]); size++; } + + ASSERT_EQ(size, for_insert.size()); + + delete disk_manager; + delete bpm; + remove("test.db"); + remove("test.log"); } +} - ASSERT_EQ(size, perserved_keys.size()); +void MixTest2Call() { + for (size_t iter = 0; iter < MIXTEST_NUM_ITERS; iter++) { + // create KeyComparator and index schema + auto key_schema = ParseCreateStatement("a bigint"); + GenericComparator<8> comparator(key_schema.get()); + + auto *disk_manager = new DiskManagerUnlimitedMemory(); + auto *bpm = new BufferPoolManager(BPM_SIZE, disk_manager); + + // create and fetch header_page + page_id_t page_id = bpm->NewPage(); + + // create b+ tree + BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); + + // Add perserved_keys + std::vector perserved_keys; + std::vector dynamic_keys; + int64_t total_keys = 1000; + int64_t sieve = 5; + for (int64_t i = 1; i <= total_keys; i++) { + if (i % sieve == 0) { + perserved_keys.push_back(i); + } else { + dynamic_keys.push_back(i); + } + } + InsertHelper(&tree, perserved_keys); - delete bpm; + size_t size; + + auto insert_task = [&](int tid) { InsertHelper(&tree, dynamic_keys); }; + auto delete_task = [&](int tid) { DeleteHelper(&tree, dynamic_keys); }; + auto lookup_task = [&](int tid) { LookupHelper(&tree, perserved_keys); }; + + std::vector threads; + std::vector> tasks; + tasks.emplace_back(insert_task); + tasks.emplace_back(delete_task); + tasks.emplace_back(lookup_task); + + size_t num_threads = 6; + for (size_t i = 0; i < num_threads; i++) { + threads.emplace_back(tasks[i % tasks.size()], i); + } + for (size_t i = 0; i < num_threads; i++) { + threads[i].join(); + } + + // Check all reserved keys exist + size = 0; + + for (auto iter = tree.Begin(); iter != tree.End(); ++iter) { + const auto &pair = *iter; + if ((pair.first).ToString() % sieve == 0) { + size++; + } + } + + ASSERT_EQ(size, perserved_keys.size()); + + delete disk_manager; + delete bpm; + } } +TEST(BPlusTreeConcurrentTest, DISABLED_InsertTest1) { // NOLINT + InsertTest1Call(); +} + +TEST(BPlusTreeConcurrentTest, DISABLED_InsertTest2) { // NOLINT + InsertTest2Call(); +} + +TEST(BPlusTreeConcurrentTest, DISABLED_DeleteTest1) { // NOLINT + DeleteTest1Call(); +} + +TEST(BPlusTreeConcurrentTest, DISABLED_DeleteTest2) { // NOLINT + DeleteTest2Call(); +} + +TEST(BPlusTreeConcurrentTest, DISABLED_MixTest1) { // NOLINT + MixTest1Call(); +} + +TEST(BPlusTreeConcurrentTest, DISABLED_MixTest2) { // NOLINT + MixTest2Call(); +} } // namespace bustub diff --git a/test/storage/b_plus_tree_contention_test.cpp b/test/storage/b_plus_tree_contention_test.cpp index be78f4cbb..e07837a1c 100644 --- a/test/storage/b_plus_tree_contention_test.cpp +++ b/test/storage/b_plus_tree_contention_test.cpp @@ -43,7 +43,6 @@ bool BPlusTreeLockBenchmarkCall(size_t num_threads, int leaf_node_size, bool wit auto func = [&tree, &mtx, i, keys_per_thread, with_global_mutex]() { GenericKey<8> index_key; RID rid; - auto *transaction = new Transaction(static_cast(i + 1)); const auto end_key = keys_stride * i + keys_per_thread; for (auto key = i * keys_stride; key < end_key; key++) { int64_t value = key & 0xFFFFFFFF; @@ -52,12 +51,11 @@ bool BPlusTreeLockBenchmarkCall(size_t num_threads, int leaf_node_size, bool wit if (with_global_mutex) { mtx.lock(); } - tree.Insert(index_key, rid, transaction); + tree.Insert(index_key, rid); if (with_global_mutex) { mtx.unlock(); } } - delete transaction; }; auto t = std::thread(std::move(func)); threads.emplace_back(std::move(t)); diff --git a/test/storage/b_plus_tree_delete_test.cpp b/test/storage/b_plus_tree_delete_test.cpp index 99a4e40b7..80bd118e9 100644 --- a/test/storage/b_plus_tree_delete_test.cpp +++ b/test/storage/b_plus_tree_delete_test.cpp @@ -6,7 +6,7 @@ // // Identification: test/storage/b_plus_tree_delete_test.cpp // -// Copyright (c) 2015-2021, Carnegie Mellon University Database Group +// Copyright (c) 2015-2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// @@ -15,6 +15,7 @@ #include "buffer/buffer_pool_manager.h" #include "gtest/gtest.h" +#include "storage/b_plus_tree_utils.h" #include "storage/disk/disk_manager_memory.h" #include "storage/index/b_plus_tree.h" #include "test_util.h" // NOLINT @@ -23,7 +24,7 @@ namespace bustub { using bustub::DiskManagerUnlimitedMemory; -TEST(BPlusTreeTests, DISABLED_DeleteTest1) { +TEST(BPlusTreeTests, DISABLED_DeleteTest) { // create KeyComparator and index schema auto key_schema = ParseCreateStatement("a bigint"); GenericComparator<8> comparator(key_schema.get()); @@ -36,15 +37,13 @@ TEST(BPlusTreeTests, DISABLED_DeleteTest1) { BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); GenericKey<8> index_key; RID rid; - // create transaction - auto *transaction = new Transaction(0); std::vector keys = {1, 2, 3, 4, 5}; for (auto key : keys) { int64_t value = key & 0xFFFFFFFF; rid.Set(static_cast(key >> 32), value); index_key.SetFromInteger(key); - tree.Insert(index_key, rid, transaction); + tree.Insert(index_key, rid); } std::vector rids; @@ -58,10 +57,10 @@ TEST(BPlusTreeTests, DISABLED_DeleteTest1) { EXPECT_EQ(rids[0].GetSlotNum(), value); } - std::vector remove_keys = {1, 5}; + std::vector remove_keys = {1, 5, 3, 4}; for (auto key : remove_keys) { index_key.SetFromInteger(key); - tree.Remove(index_key, transaction); + tree.Remove(index_key); } int64_t size = 0; @@ -78,78 +77,68 @@ TEST(BPlusTreeTests, DISABLED_DeleteTest1) { EXPECT_EQ(rids.size(), 1); EXPECT_EQ(rids[0].GetPageId(), 0); EXPECT_EQ(rids[0].GetSlotNum(), key); - size = size + 1; + ++size; } } - - EXPECT_EQ(size, 3); - - delete transaction; + EXPECT_EQ(size, 1); delete bpm; } -TEST(BPlusTreeTests, DISABLED_DeleteTest2) { +TEST(BPlusTreeTests, DISABLED_SequentialEdgeMixTest) { // NOLINT // create KeyComparator and index schema auto key_schema = ParseCreateStatement("a bigint"); GenericComparator<8> comparator(key_schema.get()); auto disk_manager = std::make_unique(); auto *bpm = new BufferPoolManager(50, disk_manager.get()); - // allocate header_page - page_id_t page_id = bpm->NewPage(); - // create b+ tree - BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); - GenericKey<8> index_key; - RID rid; - // create transaction - auto *transaction = new Transaction(0); - std::vector keys = {1, 2, 3, 4, 5}; - for (auto key : keys) { - int64_t value = key & 0xFFFFFFFF; - rid.Set(static_cast(key >> 32), value); - index_key.SetFromInteger(key); - tree.Insert(index_key, rid, transaction); - } - - std::vector rids; - for (auto key : keys) { - rids.clear(); - index_key.SetFromInteger(key); - tree.GetValue(index_key, &rids); - EXPECT_EQ(rids.size(), 1); - - int64_t value = key & 0xFFFFFFFF; - EXPECT_EQ(rids[0].GetSlotNum(), value); - } - - std::vector remove_keys = {1, 5, 3, 4}; - for (auto key : remove_keys) { - index_key.SetFromInteger(key); - tree.Remove(index_key, transaction); - } - - int64_t size = 0; - bool is_present; - - for (auto key : keys) { - rids.clear(); - index_key.SetFromInteger(key); - is_present = tree.GetValue(index_key, &rids); + for (int leaf_max_size = 2; leaf_max_size <= 5; leaf_max_size++) { + // create and fetch header_page + page_id_t page_id = bpm->NewPage(); + + // create b+ tree + BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, leaf_max_size, 3); + GenericKey<8> index_key; + RID rid; + + std::vector keys = {1, 5, 15, 20, 25, 2, -1, -2, 6, 14, 4}; + std::vector inserted = {}; + std::vector deleted = {}; + for (auto key : keys) { + int64_t value = key & 0xFFFFFFFF; + rid.Set(static_cast(key >> 32), value); + index_key.SetFromInteger(key); + tree.Insert(index_key, rid); + inserted.push_back(key); + auto res = TreeValuesMatch, RID, GenericComparator<8>>(tree, inserted, deleted); + ASSERT_TRUE(res); + } - if (!is_present) { - EXPECT_NE(std::find(remove_keys.begin(), remove_keys.end(), key), remove_keys.end()); - } else { - EXPECT_EQ(rids.size(), 1); - EXPECT_EQ(rids[0].GetPageId(), 0); - EXPECT_EQ(rids[0].GetSlotNum(), key); - size = size + 1; + index_key.SetFromInteger(1); + tree.Remove(index_key); + deleted.push_back(1); + inserted.erase(std::find(inserted.begin(), inserted.end(), 1)); + auto res = TreeValuesMatch, RID, GenericComparator<8>>(tree, inserted, deleted); + ASSERT_TRUE(res); + + index_key.SetFromInteger(3); + rid.Set(3, 3); + tree.Insert(index_key, rid); + inserted.push_back(3); + res = TreeValuesMatch, RID, GenericComparator<8>>(tree, inserted, deleted); + ASSERT_TRUE(res); + + keys = {4, 14, 6, 2, 15, -2, -1, 3, 5, 25, 20}; + for (auto key : keys) { + index_key.SetFromInteger(key); + tree.Remove(index_key); + deleted.push_back(key); + inserted.erase(std::find(inserted.begin(), inserted.end(), key)); + res = TreeValuesMatch, RID, GenericComparator<8>>(tree, inserted, deleted); + ASSERT_TRUE(res); } } - EXPECT_EQ(size, 1); - - delete transaction; delete bpm; } } // namespace bustub diff --git a/test/storage/b_plus_tree_insert_test.cpp b/test/storage/b_plus_tree_insert_test.cpp index 3267df7aa..1c7fb817d 100644 --- a/test/storage/b_plus_tree_insert_test.cpp +++ b/test/storage/b_plus_tree_insert_test.cpp @@ -6,7 +6,7 @@ // // Identification: test/storage/b_plus_tree_insert_test.cpp // -// Copyright (c) 2015-2021, Carnegie Mellon University Database Group +// Copyright (c) 2015-2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// @@ -36,14 +36,12 @@ TEST(BPlusTreeTests, DISABLED_InsertTest1) { BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, 2, 3); GenericKey<8> index_key; RID rid; - // create transaction - auto *transaction = new Transaction(0); int64_t key = 42; int64_t value = key & 0xFFFFFFFF; rid.Set(static_cast(key), value); index_key.SetFromInteger(key); - tree.Insert(index_key, rid, transaction); + tree.Insert(index_key, rid); auto root_page_id = tree.GetRootPageId(); auto root_page_guard = bpm->ReadPage(root_page_id); @@ -55,7 +53,6 @@ TEST(BPlusTreeTests, DISABLED_InsertTest1) { ASSERT_EQ(root_as_leaf->GetSize(), 1); ASSERT_EQ(comparator(root_as_leaf->KeyAt(0), index_key), 0); - delete transaction; delete bpm; } @@ -72,30 +69,17 @@ TEST(BPlusTreeTests, DISABLED_InsertTest2) { BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, 2, 3); GenericKey<8> index_key; RID rid; - // create transaction - auto *transaction = new Transaction(0); std::vector keys = {1, 2, 3, 4, 5}; for (auto key : keys) { int64_t value = key & 0xFFFFFFFF; rid.Set(static_cast(key >> 32), value); index_key.SetFromInteger(key); - tree.Insert(index_key, rid, transaction); + tree.Insert(index_key, rid); } - std::vector rids; - for (auto key : keys) { - rids.clear(); - index_key.SetFromInteger(key); - tree.GetValue(index_key, &rids); - EXPECT_EQ(rids.size(), 1); - - int64_t value = key & 0xFFFFFFFF; - EXPECT_EQ(rids[0].GetSlotNum(), value); - } - - int64_t size = 0; bool is_present; + std::vector rids; for (auto key : keys) { rids.clear(); @@ -105,13 +89,9 @@ TEST(BPlusTreeTests, DISABLED_InsertTest2) { EXPECT_EQ(is_present, true); EXPECT_EQ(rids.size(), 1); EXPECT_EQ(rids[0].GetPageId(), 0); - EXPECT_EQ(rids[0].GetSlotNum(), key); - size = size + 1; + int64_t value = key & 0xFFFFFFFF; + EXPECT_EQ(rids[0].GetSlotNum(), value); } - - EXPECT_EQ(size, keys.size()); - - delete transaction; delete bpm; } @@ -128,15 +108,13 @@ TEST(BPlusTreeTests, DISABLED_InsertTest3) { BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator); GenericKey<8> index_key; RID rid; - // create transaction - auto *transaction = new Transaction(0); std::vector keys = {5, 4, 3, 2, 1}; for (auto key : keys) { int64_t value = key & 0xFFFFFFFF; rid.Set(static_cast(key >> 32), value); index_key.SetFromInteger(key); - tree.Insert(index_key, rid, transaction); + tree.Insert(index_key, rid); } std::vector rids; @@ -157,7 +135,7 @@ TEST(BPlusTreeTests, DISABLED_InsertTest3) { auto location = (*iterator).second; EXPECT_EQ(location.GetPageId(), 0); EXPECT_EQ(location.GetSlotNum(), current_key); - current_key = current_key + 1; + ++current_key; } EXPECT_EQ(current_key, keys.size() + 1); @@ -169,10 +147,8 @@ TEST(BPlusTreeTests, DISABLED_InsertTest3) { auto location = (*iterator).second; EXPECT_EQ(location.GetPageId(), 0); EXPECT_EQ(location.GetSlotNum(), current_key); - current_key = current_key + 1; + ++current_key; } - - delete transaction; delete bpm; } } // namespace bustub diff --git a/test/storage/b_plus_tree_sequential_scale_test.cpp b/test/storage/b_plus_tree_sequential_scale_test.cpp index ed093c496..b0069e5ea 100644 --- a/test/storage/b_plus_tree_sequential_scale_test.cpp +++ b/test/storage/b_plus_tree_sequential_scale_test.cpp @@ -6,7 +6,7 @@ // // Identification: test/storage/b_plus_tree_sequential_scale_test.cpp // -// Copyright (c) 2023, Carnegie Mellon University Database Group +// Copyright (c) 2024, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// @@ -25,7 +25,7 @@ namespace bustub { using bustub::DiskManagerUnlimitedMemory; /** - * This test should be passing with your Checkpoint 1 submission. + * (Fall 2024) You should pass this test after finishing insertion and point search. */ TEST(BPlusTreeTests, DISABLED_ScaleTest) { // NOLINT // create KeyComparator and index schema @@ -42,14 +42,10 @@ TEST(BPlusTreeTests, DISABLED_ScaleTest) { // NOLINT BPlusTree, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, 2, 3); GenericKey<8> index_key; RID rid; - // create transaction - auto *transaction = new Transaction(0); int64_t scale = 5000; - std::vector keys; - for (int64_t key = 1; key < scale; key++) { - keys.push_back(key); - } + std::vector keys(scale); + std::iota(keys.begin(), keys.end(), 1); // randomized the insertion order auto rng = std::default_random_engine{}; @@ -58,7 +54,7 @@ TEST(BPlusTreeTests, DISABLED_ScaleTest) { // NOLINT int64_t value = key & 0xFFFFFFFF; rid.Set(static_cast(key >> 32), value); index_key.SetFromInteger(key); - tree.Insert(index_key, rid, transaction); + tree.Insert(index_key, rid); } std::vector rids; for (auto key : keys) { @@ -70,8 +66,6 @@ TEST(BPlusTreeTests, DISABLED_ScaleTest) { // NOLINT int64_t value = key & 0xFFFFFFFF; ASSERT_EQ(rids[0].GetSlotNum(), value); } - - delete transaction; delete bpm; } } // namespace bustub diff --git a/tools/b_plus_tree_printer/b_plus_tree_printer.cpp b/tools/b_plus_tree_printer/b_plus_tree_printer.cpp index 5e8c041fe..3ed2f584d 100644 --- a/tools/b_plus_tree_printer/b_plus_tree_printer.cpp +++ b/tools/b_plus_tree_printer/b_plus_tree_printer.cpp @@ -27,7 +27,6 @@ using bustub::GenericKey; using bustub::page_id_t; using bustub::ParseCreateStatement; using bustub::RID; -using bustub::Transaction; auto UsageMessage() -> std::string { std::string message = @@ -80,8 +79,7 @@ auto main(int argc, char **argv) -> int { // create b+ tree BPlusTree, RID, GenericComparator<8>> tree("foo_pk", root_pid, bpm, comparator, leaf_max_size, internal_max_size); - // create transaction - auto *transaction = new Transaction(0); + while (!quit) { std::cout << "> "; std::cin >> instruction; @@ -91,26 +89,26 @@ auto main(int argc, char **argv) -> int { switch (instruction) { case 'c': std::cin >> filename; - tree.RemoveFromFile(filename, transaction); + tree.RemoveFromFile(filename); break; case 'x': std::cin >> filename; - tree.BatchOpsFromFile(filename, transaction); + tree.BatchOpsFromFile(filename); break; case 'd': std::cin >> key; index_key.SetFromInteger(key); - tree.Remove(index_key, transaction); + tree.Remove(index_key); break; case 'i': std::cin >> key; rid.Set(static_cast(key >> 32), static_cast(key & 0xFFFFFFFF)); index_key.SetFromInteger(key); - tree.Insert(index_key, rid, transaction); + tree.Insert(index_key, rid); break; case 'f': std::cin >> filename; - tree.InsertFromFile(filename, transaction); + tree.InsertFromFile(filename); break; case 'q': quit = true; @@ -136,7 +134,7 @@ auto main(int argc, char **argv) -> int { BUSTUB_ASSERT(bpm->DeletePage(root_pid), "Unable to delete root page for some reason"); delete bpm; - delete transaction; + delete disk_manager; remove("test.bustub"); remove("test.log"); diff --git a/tools/btree_bench/btree_bench.cpp b/tools/btree_bench/btree_bench.cpp index 1335343e8..a417b530e 100644 --- a/tools/btree_bench/btree_bench.cpp +++ b/tools/btree_bench/btree_bench.cpp @@ -35,7 +35,9 @@ auto ClockMs() -> uint64_t { static const size_t BUSTUB_READ_THREAD = 4; static const size_t BUSTUB_WRITE_THREAD = 2; static const size_t LRU_K_SIZE = 4; -static const size_t BUSTUB_BPM_SIZE = 256; +// We should keep the BPM size large enough to hold all pages in memory, to minimize the dependency on P1. +// There will be roughly 500 leaf pages and tens of internal pages. Thus, 1024 should be enough. +static const size_t BUSTUB_BPM_SIZE = 1024; static const size_t TOTAL_KEYS = 100000; static const size_t KEY_MODIFY_RANGE = 2048; @@ -153,7 +155,7 @@ auto main(int argc, char **argv) -> int { uint32_t value = key; rid.Set(value, value); index_key.SetFromInteger(key); - index.Insert(index_key, rid, nullptr); + index.Insert(index_key, rid); } fmt::print(stderr, "[info] benchmark start\n"); @@ -164,7 +166,7 @@ auto main(int argc, char **argv) -> int { std::vector threads; for (size_t thread_id = 0; thread_id < BUSTUB_READ_THREAD; thread_id++) { - threads.emplace_back(std::thread([thread_id, &index, duration_ms, &total_metrics] { + threads.emplace_back([thread_id, &index, duration_ms, &total_metrics] { BTreeMetrics metrics(fmt::format("read {:>2}", thread_id), duration_ms); metrics.Begin(); @@ -206,11 +208,11 @@ auto main(int argc, char **argv) -> int { } total_metrics.ReportRead(metrics.cnt_); - })); + }); } for (size_t thread_id = 0; thread_id < BUSTUB_WRITE_THREAD; thread_id++) { - threads.emplace_back(std::thread([thread_id, &index, duration_ms, &total_metrics] { + threads.emplace_back([thread_id, &index, duration_ms, &total_metrics] { BTreeMetrics metrics(fmt::format("write {:>2}", thread_id), duration_ms); metrics.Begin(); @@ -234,9 +236,9 @@ auto main(int argc, char **argv) -> int { rid.Set(value, value); index_key.SetFromInteger(key); if (do_insert) { - index.Insert(index_key, rid, nullptr); + index.Insert(index_key, rid); } else { - index.Remove(index_key, nullptr); + index.Remove(index_key); } metrics.Tick(); metrics.Report(); @@ -244,7 +246,7 @@ auto main(int argc, char **argv) -> int { uint32_t value = key; rid.Set(value, dis(gen)); index_key.SetFromInteger(key); - index.Insert(index_key, rid, nullptr); + index.Insert(index_key, rid); metrics.Tick(); metrics.Report(); } @@ -253,7 +255,7 @@ auto main(int argc, char **argv) -> int { } total_metrics.ReportWrite(metrics.cnt_); - })); + }); } for (auto &thread : threads) {