From bf4a4af83d01a2fcf885a49f94c84080f8f4f3c5 Mon Sep 17 00:00:00 2001 From: happyZYM Date: Sun, 28 Apr 2024 13:28:41 +0000 Subject: [PATCH] basically write and test insert --- bpt/include/bpt/bpt.hpp | 190 ++++++++++++++++++-------- bpt/include/bpt/config.h | 1 + bpt/src/bpt.cpp | 3 +- bpt/src/buffer_pool_manager.cpp | 4 + test/bpt_basic_test.cpp | 233 +++++++++++++++++++++++++++++++- 5 files changed, 376 insertions(+), 55 deletions(-) diff --git a/bpt/include/bpt/bpt.hpp b/bpt/include/bpt/bpt.hpp index 0de72f4..41918d9 100644 --- a/bpt/include/bpt/bpt.hpp +++ b/bpt/include/bpt/bpt.hpp @@ -64,6 +64,139 @@ class BPlusTreeIndexer { res.is_end = false; return res; } + void InsertFixUpLookPartA(PositionSignType &pos, BasicPageGuard &parent_page_guard, BasicPageGuard &new_page_guard, + BasicPageGuard &page_guard, default_numeric_index_t new_page_id) { + pos.path[pos.path.size() - 2].second++; + // now check we are able to "insert" (new_page_guard.template + // As()->data.p_data[new_page_guard.template As()->data.key_count - 1].first, new_page_id) + // at pos + if (parent_page_guard.template As()->data.key_count < _ActualDataType::kMaxKeyCount) { + // Has enough space, reach end, just insert it + // first, manually move the last pointer + parent_page_guard.template AsMut()->data.p_data[pos.path[pos.path.size() - 2].second - 1].first = + page_guard.template As()->data.p_data[page_guard.template As()->data.key_count - 1].first; + if (parent_page_guard.template As()->data.key_count == _ActualDataType::kMaxKeyCount - 1) { + parent_page_guard.template AsMut()->data.p_n = + parent_page_guard.template As() + ->data.p_data[parent_page_guard.template As()->data.key_count] + .second; + } else { + parent_page_guard.template AsMut() + ->data.p_data[parent_page_guard.template As()->data.key_count + 1] + .second = parent_page_guard.template As() + ->data.p_data[parent_page_guard.template As()->data.key_count] + .second; + } + // Then, use memmove to move the key_point pairs + fprintf(stderr, "parent_page_guard.template As()->data.key_count = %d\n", + (int)parent_page_guard.template As()->data.key_count); + if (pos.path[pos.path.size() - 2].second < parent_page_guard.template As()->data.key_count) { + memmove(parent_page_guard.template AsMut()->data.p_data + pos.path[pos.path.size() - 2].second + 1, + parent_page_guard.template As()->data.p_data + pos.path[pos.path.size() - 2].second, + (parent_page_guard.template As()->data.key_count - pos.path[pos.path.size() - 2].second) * + sizeof(key_index_pair_t)); + } + // Then Set the key_point pair + if (pos.path[pos.path.size() - 2].second < _ActualDataType::kMaxKeyCount) { + parent_page_guard.template AsMut()->data.p_data[pos.path[pos.path.size() - 2].second] = + std::make_pair(new_page_guard.template As() + ->data.p_data[new_page_guard.template As()->data.key_count - 1] + .first, + new_page_id); + } else { + // just set p_n + parent_page_guard.template AsMut()->data.p_n = new_page_id; + } + parent_page_guard.template AsMut()->data.key_count++; + return; + } + // TODO: process and prepare for next round + assert((pos.path.size() == 2) == + ((parent_page_guard.template As()->data.page_status & PageStatusType::ROOT) != 0)); + /** + * Step 1: split current page + * Step 2: Check if current page is root. If current page is root, create a new root, update and exit + * Step 3: Otherwise, update parent page, and continue the loop + */ + key_index_pair_t new_entry_backup = + std::make_pair(new_page_guard.template As() + ->data.p_data[new_page_guard.template As()->data.key_count - 1] + .first, + new_page_id); + KeyType key_to_update_backup = + page_guard.template As()->data.p_data[page_guard.template As()->data.key_count - 1].first; + InsertFixUpLookPartB(pos, parent_page_guard, new_entry_backup, key_to_update_backup); + } + void InsertFixUpLookPartB(PositionSignType &pos, BasicPageGuard &page_guard, const key_index_pair_t &new_entry_backup, + const KeyType &key_to_update_backup) { + default_numeric_index_t new_page_id; + auto new_page_guard = std::move(bpm->NewPageGuarded(&new_page_id)); + new_page_guard.template AsMut()->data.page_status = PageStatusType::INTERNAL; + // Now begin spliting. It is expected that the new page has _ActualDataType::kMinNumberOfKeysForLeaf keys + if (pos.path[pos.path.size() - 2].second - 1 == _ActualDataType::kMaxKeyCount) { + // In this case, first, move the last _ActualDataType::kMinNumberOfKeysForLeaf-1 keys to the new page + memmove(new_page_guard.template AsMut()->data.p_data, + page_guard.template As()->data.p_data + _ActualDataType::kMaxKeyCount - + (_ActualDataType::kMinNumberOfKeysForLeaf - 1), + (_ActualDataType::kMinNumberOfKeysForLeaf - 1) * sizeof(key_index_pair_t)); + new_page_guard.template AsMut()->data.p_data[_ActualDataType::kMinNumberOfKeysForLeaf - 1].second = + page_guard.template As()->data.p_n; + new_page_guard.template AsMut()->data.p_data[_ActualDataType::kMinNumberOfKeysForLeaf - 1].first = + key_to_update_backup; + new_page_guard.template AsMut()->data.p_data[_ActualDataType::kMinNumberOfKeysForLeaf].second = + new_entry_backup.second; + new_page_guard.template AsMut()->data.key_count = _ActualDataType::kMinNumberOfKeysForLeaf; + page_guard.template AsMut()->data.key_count -= _ActualDataType::kMinNumberOfKeysForLeaf - 1; + } else { + page_guard.template AsMut()->data.p_data[pos.path[pos.path.size() - 2].second - 1].first = + key_to_update_backup; + // now, we need to "insert" the new_entry_backup to position pos.path[pos.path.size() - 2].second + new_page_guard.template AsMut()->data.p_data[_ActualDataType::kMinNumberOfKeysForLeaf].second = + page_guard.template As()->data.p_n; + default_numeric_index_t it_dest = _ActualDataType::kMinNumberOfKeysForLeaf - 1; + default_numeric_index_t it_src = _ActualDataType::kMaxKeyCount - 1; + bool has_processed = false; + for (; it_dest != kInvalidNumericIndex; --it_dest) { + if (!has_processed && pos.path[pos.path.size() - 2].second == it_src + 1) { + new_page_guard.template AsMut()->data.p_data[it_dest] = new_entry_backup; + has_processed = true; + continue; + } + new_page_guard.template AsMut()->data.p_data[it_dest] = + page_guard.template As()->data.p_data[it_src]; + --it_src; + } + if (pos.path[pos.path.size() - 2].second <= + _ActualDataType::kMaxKeyCount - _ActualDataType::kMinNumberOfKeysForLeaf) { + memmove(page_guard.template AsMut()->data.p_data + pos.path[pos.path.size() - 2].second + 1, + page_guard.template As()->data.p_data + pos.path[pos.path.size() - 2].second, + ((_ActualDataType::kMaxKeyCount - _ActualDataType::kMinNumberOfKeysForLeaf) - + pos.path[pos.path.size() - 2].second) * + sizeof(key_index_pair_t)); + page_guard.template AsMut()->data.p_data[pos.path[pos.path.size() - 2].second] = new_entry_backup; + } + new_page_guard.template AsMut()->data.key_count = _ActualDataType::kMinNumberOfKeysForLeaf; + page_guard.template AsMut()->data.key_count -= _ActualDataType::kMinNumberOfKeysForLeaf - 1; + } + fprintf(stderr, "Evicting page %d\n", (int)pos.path.back().first.PageId()); + fprintf(stderr, "page id of page_guard = %d\n", (int)page_guard.PageId()); + pos.path.pop_back(); + fprintf(stderr, "the page id of the res page in pos %d\n", (int)pos.path.back().first.PageId()); + if (pos.path.size() == 1) { + // we have split the root page, update and quit + page_guard.template AsMut()->data.page_status &= ~PageStatusType::ROOT; + BasicPageGuard new_root_page_guard = bpm->NewPageGuarded(&root_page_id); + new_root_page_guard.AsMut()->data.page_status = PageStatusType::ROOT; + new_root_page_guard.AsMut()->data.key_count = 1; + new_root_page_guard.AsMut()->data.p_data[0] = std::make_pair( + page_guard.template As()->data.p_data[page_guard.template As()->data.key_count - 1].first, + page_guard.PageId()); + new_root_page_guard.AsMut()->data.p_data[1] = std::make_pair(KeyType(), new_page_id); + return; + } + auto &parent_page_guard = pos.path[pos.path.size() - 2].first; + InsertFixUpLookPartA(pos, parent_page_guard, new_page_guard, page_guard, new_page_id); + } void InsertEntryAt(PositionSignType &pos, const KeyType &key, b_plus_tree_value_index_t value, bool is_fixing_up_recursive = false) { fprintf(stderr, "_ActualDataType::kMaxKeyCount = %d\n", (int)_ActualDataType::kMaxKeyCount); @@ -103,8 +236,9 @@ class BPlusTreeIndexer { new_page_guard.AsMut()->data.page_status = 0; // PageStatusType::INTERNAL; new_page_guard.AsMut()->data.key_count = _ActualDataType::kMinNumberOfKeysForLeaf; page_guard.template AsMut()->data.key_count -= _ActualDataType::kMinNumberOfKeysForLeaf; - new_page_guard.AsMut()->data.p_n = page_guard.template As()->data.p_n; - page_guard.template AsMut()->data.p_n = new_page_id; + if (!is_fixing_up_recursive) + new_page_guard.AsMut()->data.p_n = page_guard.template As()->data.p_n; + if (!is_fixing_up_recursive) page_guard.template AsMut()->data.p_n = new_page_id; if (pos.path.back().second <= _ActualDataType::kMaxKeyCount - _ActualDataType::kMinNumberOfKeysForLeaf) { // the new key is in the first half memmove(new_page_guard.template AsMut()->data.p_data, @@ -160,57 +294,7 @@ class BPlusTreeIndexer { is_in_right_skew_path = true; } if (is_in_right_skew_path) { - do { - parent_page_guard.template AsMut()->data.p_data[pos.path[pos.path.size() - 2].second].first = - page_guard.template As() - ->data.p_data[page_guard.template As()->data.key_count - 1] - .first; - pos.path[pos.path.size() - 2].second++; - // now check we are able to "insert" (new_page_guard.template - // As()->data.p_data[new_page_guard.template As()->data.key_count - 1].first, new_page_id) - // at pos - if (parent_page_guard.template As()->data.key_count < _ActualDataType::kMaxKeyCount) { - // Has enough space, reach end, just insert it - // first, manually move the last pointer - if (parent_page_guard.template As()->data.key_count == _ActualDataType::kMaxKeyCount - 1) { - parent_page_guard.template AsMut()->data.p_n = - parent_page_guard.template As() - ->data.p_data[parent_page_guard.template As()->data.key_count] - .second; - } else { - parent_page_guard.template AsMut() - ->data.p_data[parent_page_guard.template As()->data.key_count + 1] - .second = parent_page_guard.template As() - ->data.p_data[parent_page_guard.template As()->data.key_count] - .second; - } - // Then, use memmove to move the key_point pairs - fprintf(stderr, "parent_page_guard.template As()->data.key_count = %d\n", - (int)parent_page_guard.template As()->data.key_count); - if (pos.path[pos.path.size() - 2].second < parent_page_guard.template As()->data.key_count) { - memmove( - parent_page_guard.template AsMut()->data.p_data + pos.path[pos.path.size() - 2].second + 1, - parent_page_guard.template As()->data.p_data + pos.path[pos.path.size() - 2].second, - (parent_page_guard.template As()->data.key_count - pos.path[pos.path.size() - 2].second) * - sizeof(key_index_pair_t)); - } - // Then Set the key_point pair - if (pos.path[pos.path.size() - 2].second < _ActualDataType::kMaxKeyCount) { - parent_page_guard.template AsMut()->data.p_data[pos.path[pos.path.size() - 2].second] = - std::make_pair(new_page_guard.template As() - ->data.p_data[new_page_guard.template As()->data.key_count - 1] - .first, - new_page_id); - } else { - // just set p_n - parent_page_guard.template AsMut()->data.p_n = new_page_id; - } - parent_page_guard.template AsMut()->data.key_count++; - break; - } - // TODO: process and prepare for next round - throw std::runtime_error("Not implemented yet: InsertEntryAt"); - } while (true); + InsertFixUpLookPartA(pos, parent_page_guard, new_page_guard, page_guard, new_page_id); if (!is_fixing_up_recursive) ++siz; return; } diff --git a/bpt/include/bpt/config.h b/bpt/include/bpt/config.h index 3ecb9e6..ae18ae8 100644 --- a/bpt/include/bpt/config.h +++ b/bpt/include/bpt/config.h @@ -7,6 +7,7 @@ typedef uint32_t default_numeric_index_t; typedef default_numeric_index_t page_id_t; typedef default_numeric_index_t frame_id_t; typedef default_numeric_index_t b_plus_tree_value_index_t; +extern const default_numeric_index_t kInvalidNumericIndex; extern const b_plus_tree_value_index_t kInvalidValueIndex; typedef uint8_t page_status_t; typedef uint16_t in_page_key_count_t; diff --git a/bpt/src/bpt.cpp b/bpt/src/bpt.cpp index 9ae68c5..7770328 100644 --- a/bpt/src/bpt.cpp +++ b/bpt/src/bpt.cpp @@ -1,3 +1,4 @@ #include "bpt/bpt.hpp" #include "bpt/config.h" -const b_plus_tree_value_index_t kInvalidValueIndex = -1; \ No newline at end of file +const b_plus_tree_value_index_t kInvalidValueIndex = -1; +const default_numeric_index_t kInvalidNumericIndex = -1; \ No newline at end of file diff --git a/bpt/src/buffer_pool_manager.cpp b/bpt/src/buffer_pool_manager.cpp index b4c6c3c..164c494 100644 --- a/bpt/src/buffer_pool_manager.cpp +++ b/bpt/src/buffer_pool_manager.cpp @@ -251,11 +251,13 @@ auto BufferPoolManager::DeletePage(page_id_t page_id) -> bool { auto BufferPoolManager::FetchPageBasic(page_id_t page_id) -> BasicPageGuard { Page *page = FetchPage(page_id); + if (page == nullptr) throw std::runtime_error("Buffer Pool is full!"); return {this, page}; } auto BufferPoolManager::FetchPageRead(page_id_t page_id) -> ReadPageGuard { Page *page = FetchPage(page_id); + if (page == nullptr) throw std::runtime_error("Buffer Pool is full!"); if (page != nullptr) { page->RLatch(); } @@ -264,6 +266,7 @@ auto BufferPoolManager::FetchPageRead(page_id_t page_id) -> ReadPageGuard { auto BufferPoolManager::FetchPageWrite(page_id_t page_id) -> WritePageGuard { Page *page = FetchPage(page_id); + if (page == nullptr) throw std::runtime_error("Buffer Pool is full!"); if (page != nullptr) { page->WLatch(); } @@ -272,5 +275,6 @@ auto BufferPoolManager::FetchPageWrite(page_id_t page_id) -> WritePageGuard { auto BufferPoolManager::NewPageGuarded(page_id_t *page_id) -> BasicPageGuard { Page *page = NewPage(page_id); + if (page == nullptr) throw std::runtime_error("Buffer Pool is full!"); return {this, page}; } \ No newline at end of file diff --git a/test/bpt_basic_test.cpp b/test/bpt_basic_test.cpp index ecf0e2f..d9ec89a 100644 --- a/test/bpt_basic_test.cpp +++ b/test/bpt_basic_test.cpp @@ -352,7 +352,7 @@ TEST(HarderTest, Split_in_Put_Harder_3) { sizeof(std::pair)); const std::string db_file_name = "/tmp/bpt8.db"; std::vector keys; - const int ops = 20; + const int ops = 1000; remove(db_file_name.c_str()); DiskManager *dm = new DiskManager(db_file_name.c_str()); BufferPoolManager *bpm = new BufferPoolManager(20, 3, dm); @@ -364,6 +364,237 @@ TEST(HarderTest, Split_in_Put_Harder_3) { } // sort(keys.begin(), keys.end()); std::shuffle(keys.begin(), keys.end(), rnd); + for (int i = 1; i <= ops; i++) fprintf(stderr, "key[%d]=%s\n", i - 1, keys[i - 1].data); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + bpt.Put(keys[i - 1], i + 3); + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; + dm = new DiskManager(db_file_name.c_str()); + bpm = new BufferPoolManager(20, 3, dm); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; +} + +TEST(HarderTest, Split_in_Put_Harder_4) { + const unsigned int RndSeed = testing::GTEST_FLAG(random_seed); + std::mt19937 rnd(RndSeed); + const int str_len = 800; + typedef bpt_basic_test::FixLengthString KeyType; + fprintf(stderr, "sizeof(std::pair)=%lu\n", + sizeof(std::pair)); + const std::string db_file_name = "/tmp/bpt9.db"; + std::vector keys; + const int ops = 1000; + remove(db_file_name.c_str()); + DiskManager *dm = new DiskManager(db_file_name.c_str()); + BufferPoolManager *bpm = new BufferPoolManager(20, 3, dm); + for (int i = 1; i <= ops; i++) { + KeyType key; + for (size_t j = 0; j < str_len; j++) key.data[j] = 'a' + rnd() % 26; + key.data[str_len - 1] = '\0'; + keys.push_back(key); + } + sort(keys.begin(), keys.end()); + // std::shuffle(keys.begin(), keys.end(), rnd); + for (int i = 1; i <= ops; i++) fprintf(stderr, "key[%d]=%s\n", i - 1, keys[i - 1].data); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + bpt.Put(keys[i - 1], i + 3); + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; + dm = new DiskManager(db_file_name.c_str()); + bpm = new BufferPoolManager(20, 3, dm); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; +} + +TEST(HarderTest, Split_in_Put_Harder_5) { + const unsigned int RndSeed = testing::GTEST_FLAG(random_seed); + std::mt19937 rnd(RndSeed); + const int str_len = 800; + typedef bpt_basic_test::FixLengthString KeyType; + fprintf(stderr, "sizeof(std::pair)=%lu\n", + sizeof(std::pair)); + const std::string db_file_name = "/tmp/bpt10.db"; + std::vector keys; + const int ops = 15 + rnd() % 20; + remove(db_file_name.c_str()); + DiskManager *dm = new DiskManager(db_file_name.c_str()); + BufferPoolManager *bpm = new BufferPoolManager(20, 3, dm); + for (int i = 1; i <= ops; i++) { + KeyType key; + for (size_t j = 0; j < str_len; j++) key.data[j] = 'a' + rnd() % 26; + key.data[str_len - 1] = '\0'; + keys.push_back(key); + } + // sort(keys.begin(), keys.end()); + std::shuffle(keys.begin(), keys.end(), rnd); + for (int i = 1; i <= ops; i++) fprintf(stderr, "key[%d]=%s\n", i - 1, keys[i - 1].data); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + bpt.Put(keys[i - 1], i + 3); + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; + dm = new DiskManager(db_file_name.c_str()); + bpm = new BufferPoolManager(20, 3, dm); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; +} + +TEST(HarderTest, Split_in_Put_Harder_6) { + const unsigned int RndSeed = testing::GTEST_FLAG(random_seed); + std::mt19937 rnd(RndSeed); + const int str_len = 1000; + typedef bpt_basic_test::FixLengthString KeyType; + fprintf(stderr, "sizeof(std::pair)=%lu\n", + sizeof(std::pair)); + const std::string db_file_name = "/tmp/bpt11.db"; + std::vector keys; + const int ops = 15 + rnd() % 20; + remove(db_file_name.c_str()); + DiskManager *dm = new DiskManager(db_file_name.c_str()); + BufferPoolManager *bpm = new BufferPoolManager(20, 3, dm); + for (int i = 1; i <= ops; i++) { + KeyType key; + for (size_t j = 0; j < str_len; j++) key.data[j] = 'a' + rnd() % 26; + key.data[str_len - 1] = '\0'; + keys.push_back(key); + } + // sort(keys.begin(), keys.end()); + std::shuffle(keys.begin(), keys.end(), rnd); + for (int i = 1; i <= ops; i++) fprintf(stderr, "key[%d]=%s\n", i - 1, keys[i - 1].data); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + bpt.Put(keys[i - 1], i + 3); + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; + dm = new DiskManager(db_file_name.c_str()); + bpm = new BufferPoolManager(20, 3, dm); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; +} + +TEST(HarderTest, Split_in_Put_Harder_7) { + const unsigned int RndSeed = testing::GTEST_FLAG(random_seed); + std::mt19937 rnd(RndSeed); + const int str_len = 2000; + typedef bpt_basic_test::FixLengthString KeyType; + fprintf(stderr, "sizeof(std::pair)=%lu\n", + sizeof(std::pair)); + const std::string db_file_name = "/tmp/bpt12.db"; + std::vector keys; + const int ops = 15 + rnd() % 20; + remove(db_file_name.c_str()); + DiskManager *dm = new DiskManager(db_file_name.c_str()); + BufferPoolManager *bpm = new BufferPoolManager(20, 3, dm); + for (int i = 1; i <= ops; i++) { + KeyType key; + for (size_t j = 0; j < str_len; j++) key.data[j] = 'a' + rnd() % 26; + key.data[str_len - 1] = '\0'; + keys.push_back(key); + } + // sort(keys.begin(), keys.end()); + std::shuffle(keys.begin(), keys.end(), rnd); + for (int i = 1; i <= ops; i++) fprintf(stderr, "key[%d]=%s\n", i - 1, keys[i - 1].data); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + bpt.Put(keys[i - 1], i + 3); + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; + dm = new DiskManager(db_file_name.c_str()); + bpm = new BufferPoolManager(20, 3, dm); + { + BPlusTreeIndexer> bpt(bpm); + for (int i = 1; i <= ops; i++) { + ASSERT_EQ(bpt.Get(keys[i - 1]), i + 3); + } + } + delete bpm; + delete dm; +} + +TEST(HarderTest, Split_in_Put_Harder_8) { + const unsigned int RndSeed = testing::GTEST_FLAG(random_seed); + std::mt19937 rnd(RndSeed); + const int str_len = 1300; + typedef bpt_basic_test::FixLengthString KeyType; + fprintf(stderr, "sizeof(std::pair)=%lu\n", + sizeof(std::pair)); + const std::string db_file_name = "/tmp/bpt13.db"; + std::vector keys; + const int ops = 15 + rnd() % 20; + remove(db_file_name.c_str()); + DiskManager *dm = new DiskManager(db_file_name.c_str()); + BufferPoolManager *bpm = new BufferPoolManager(20, 3, dm); + for (int i = 1; i <= ops; i++) { + KeyType key; + for (size_t j = 0; j < str_len; j++) key.data[j] = 'a' + rnd() % 26; + key.data[str_len - 1] = '\0'; + keys.push_back(key); + } + // sort(keys.begin(), keys.end()); + std::shuffle(keys.begin(), keys.end(), rnd); + for (int i = 1; i <= ops; i++) fprintf(stderr, "key[%d]=%s\n", i - 1, keys[i - 1].data); { BPlusTreeIndexer> bpt(bpm); for (int i = 1; i <= ops; i++) {