From 0a6b83b067e5ce0051afb5baa18b45cb60605bfd Mon Sep 17 00:00:00 2001 From: JaySon Date: Sat, 1 Oct 2022 03:37:45 +0800 Subject: [PATCH 01/40] tests: Remove embed test funcs from PageEntriesEdit (#6074) ref pingcap/tiflash#4562 --- dbms/src/Storages/Page/V3/PageEntriesEdit.h | 43 +-- .../Page/V3/tests/gtest_page_directory.cpp | 328 +++++++++--------- .../Page/V3/tests/gtest_wal_store.cpp | 75 ++-- 3 files changed, 204 insertions(+), 242 deletions(-) diff --git a/dbms/src/Storages/Page/V3/PageEntriesEdit.h b/dbms/src/Storages/Page/V3/PageEntriesEdit.h index b75b16da4a4..6b33990629b 100644 --- a/dbms/src/Storages/Page/V3/PageEntriesEdit.h +++ b/dbms/src/Storages/Page/V3/PageEntriesEdit.h @@ -222,7 +222,8 @@ class PageEntriesEdit Int64 being_ref_count; EditRecord() - : page_id(0) + : type(EditRecordType::DEL) + , page_id(0) , ori_page_id(0) , version(0, 0) , being_ref_count(1) @@ -250,46 +251,6 @@ class PageEntriesEdit EditRecords & getMutRecords() { return records; } const EditRecords & getRecords() const { return records; } -#ifndef NDEBUG - // Just for tests, refactor them out later - void put(PageId page_id, const PageEntryV3 & entry) - { - put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry); - } - void putExternal(PageId page_id) - { - putExternal(buildV3Id(TEST_NAMESPACE_ID, page_id)); - } - void upsertPage(PageId page_id, const PageVersion & ver, const PageEntryV3 & entry) - { - upsertPage(buildV3Id(TEST_NAMESPACE_ID, page_id), ver, entry); - } - void del(PageId page_id) - { - del(buildV3Id(TEST_NAMESPACE_ID, page_id)); - } - void ref(PageId ref_id, PageId page_id) - { - ref(buildV3Id(TEST_NAMESPACE_ID, ref_id), buildV3Id(TEST_NAMESPACE_ID, page_id)); - } - void varRef(PageId ref_id, const PageVersion & ver, PageId ori_page_id) - { - varRef(buildV3Id(TEST_NAMESPACE_ID, ref_id), ver, buildV3Id(TEST_NAMESPACE_ID, ori_page_id)); - } - void varExternal(PageId page_id, const PageVersion & create_ver, Int64 being_ref_count) - { - varExternal(buildV3Id(TEST_NAMESPACE_ID, page_id), create_ver, being_ref_count); - } - void varEntry(PageId page_id, const PageVersion & ver, const PageEntryV3 & entry, Int64 being_ref_count) - { - varEntry(buildV3Id(TEST_NAMESPACE_ID, page_id), ver, entry, being_ref_count); - } - void varDel(PageId page_id, const PageVersion & delete_ver) - { - varDel(buildV3Id(TEST_NAMESPACE_ID, page_id), delete_ver); - } -#endif - private: EditRecords records; diff --git a/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp b/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp index 5fce5797c8d..0ffedc95d9b 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp @@ -123,7 +123,7 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); dir->apply(std::move(edit)); } @@ -133,7 +133,7 @@ try PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(2, entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } @@ -150,8 +150,8 @@ try PageEntryV3 entry2_v2{.file_id = 2 + 102, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.del(2); - edit.put(2, entry2_v2); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2_v2); dir->apply(std::move(edit)); } auto snap3 = dir->createSnapshot(); @@ -171,7 +171,7 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(page_id, entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry1); dir->apply(std::move(edit)); } @@ -181,7 +181,7 @@ try PageEntryV3 entry2{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x1234, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(page_id, entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry2); dir->apply(std::move(edit)); } @@ -199,9 +199,9 @@ try PageEntryV3 entry3{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x12345, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(page_id, entry1); - edit.put(page_id, entry2); - edit.put(page_id, entry3); + edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry3); // Should not be dead-lock dir->apply(std::move(edit)); @@ -221,8 +221,8 @@ try PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry1); - edit.put(2, entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } @@ -234,9 +234,9 @@ try PageEntryV3 entry4{.file_id = 4, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.del(2); - edit.put(3, entry3); - edit.put(4, entry4); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry3); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 4), entry4); dir->apply(std::move(edit)); } @@ -266,14 +266,14 @@ try PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry1); - edit.put(2, entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 PageEntriesEdit edit; - edit.ref(3, 2); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } auto snap1 = dir->createSnapshot(); @@ -284,14 +284,14 @@ try PageEntryV3 entry_updated{.file_id = 999, .size = 16, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x123}; { PageEntriesEdit edit; - edit.put(3, entry_updated); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry_updated); ASSERT_ANY_THROW(dir->apply(std::move(edit))); } PageEntryV3 entry_updated2{.file_id = 777, .size = 16, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x123}; { PageEntriesEdit edit; - edit.put(2, entry_updated2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_updated2); ASSERT_ANY_THROW(dir->apply(std::move(edit))); } } @@ -304,14 +304,14 @@ try PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry1); - edit.put(2, entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 PageEntriesEdit edit; - edit.ref(3, 2); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } auto snap1 = dir->createSnapshot(); @@ -321,7 +321,7 @@ try // Delete 3, 2 won't get deleted. { PageEntriesEdit edit; - edit.del(3); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 3)); dir->apply(std::move(edit)); } auto snap2 = dir->createSnapshot(); @@ -333,7 +333,7 @@ try // Delete 2, 3 won't get deleted. { PageEntriesEdit edit; - edit.del(2); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } auto snap3 = dir->createSnapshot(); @@ -354,14 +354,14 @@ try PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry1); - edit.put(2, entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 PageEntriesEdit edit; - edit.ref(3, 2); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } auto snap1 = dir->createSnapshot(); @@ -371,7 +371,7 @@ try // Ref 4 -> 3 { PageEntriesEdit edit; - edit.ref(4, 3); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); dir->apply(std::move(edit)); } auto snap2 = dir->createSnapshot(); @@ -392,14 +392,14 @@ try PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry1); - edit.put(2, entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 PageEntriesEdit edit; - edit.ref(3, 2); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } auto snap1 = dir->createSnapshot(); @@ -409,7 +409,7 @@ try { // Ref 3 -> 2 again, should be idempotent PageEntriesEdit edit; - edit.ref(3, 2); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } auto snap2 = dir->createSnapshot(); @@ -420,8 +420,8 @@ try { PageEntriesEdit edit; - edit.del(3); - edit.del(2); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 3)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } auto snap3 = dir->createSnapshot(); @@ -436,7 +436,7 @@ try // Adding ref after deleted. // It will invalid snap1 and snap2 PageEntriesEdit edit; - edit.ref(3, 1); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } auto snap4 = dir->createSnapshot(); @@ -459,14 +459,14 @@ try PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry1); - edit.put(2, entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 PageEntriesEdit edit; - edit.ref(3, 2); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } auto snap1 = dir->createSnapshot(); @@ -476,7 +476,7 @@ try { // Ref 4 -> 3, collapse to 4 -> 2 PageEntriesEdit edit; - edit.ref(4, 3); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); dir->apply(std::move(edit)); } auto snap2 = dir->createSnapshot(); @@ -495,10 +495,10 @@ TEST_F(PageDirectoryTest, RefWontDeadLock) { // 1. batch.putExternal(0, 0); PageEntryV3 entry1; - edit.put(0, entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 0), entry1); // 2. batch.putRefPage(1, 0); - edit.ref(1, 0); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 1), buildV3Id(TEST_NAMESPACE_ID, 0)); } dir->apply(std::move(edit)); @@ -506,10 +506,10 @@ TEST_F(PageDirectoryTest, RefWontDeadLock) PageEntriesEdit edit2; { // 1. batch.putRefPage(2, 1); // ref 2 -> 1 -> 0 - edit2.ref(2, 1); + edit2.ref(buildV3Id(TEST_NAMESPACE_ID, 2), buildV3Id(TEST_NAMESPACE_ID, 1)); // 2. batch.delPage(1); // free ref 1 -> 0 - edit2.del(1); + edit2.del(buildV3Id(TEST_NAMESPACE_ID, 1)); } dir->apply(std::move(edit2)); @@ -521,7 +521,7 @@ TEST_F(PageDirectoryTest, IdempotentNewExtPageAfterAllCleaned) // is idempotent { PageEntriesEdit edit; - edit.putExternal(10); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); auto alive_ids = dir->getAliveExternalIds(TEST_NAMESPACE_ID); EXPECT_EQ(alive_ids.size(), 1); @@ -530,7 +530,7 @@ TEST_F(PageDirectoryTest, IdempotentNewExtPageAfterAllCleaned) { PageEntriesEdit edit; - edit.putExternal(10); // should be idempotent + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); // should be idempotent dir->apply(std::move(edit)); auto alive_ids = dir->getAliveExternalIds(TEST_NAMESPACE_ID); EXPECT_EQ(alive_ids.size(), 1); @@ -539,7 +539,7 @@ TEST_F(PageDirectoryTest, IdempotentNewExtPageAfterAllCleaned) { PageEntriesEdit edit; - edit.del(10); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); dir->gcInMemEntries(); // clean in memory auto alive_ids = dir->getAliveExternalIds(TEST_NAMESPACE_ID); @@ -550,7 +550,7 @@ TEST_F(PageDirectoryTest, IdempotentNewExtPageAfterAllCleaned) { // Add again after deleted PageEntriesEdit edit; - edit.putExternal(10); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); auto alive_ids = dir->getAliveExternalIds(TEST_NAMESPACE_ID); EXPECT_EQ(alive_ids.size(), 1); @@ -566,16 +566,16 @@ try PageEntryV3 entry3{.file_id = 3, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry1); - edit.put(2, entry2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } // Applying ref to not exist entry is not allowed { // Ref 4-> 999 PageEntriesEdit edit; - edit.put(3, entry3); - edit.ref(4, 999); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry3); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 999)); ASSERT_ANY_THROW(dir->apply(std::move(edit))); } } @@ -587,22 +587,22 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(2, 1); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 2), buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.del(1); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(3, 1); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 1)); ASSERT_ANY_THROW({ dir->apply(std::move(edit)); }); } } @@ -613,22 +613,22 @@ try { { PageEntriesEdit edit; - edit.putExternal(1); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(2, 1); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 2), buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.del(1); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(3, 1); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 1)); ASSERT_ANY_THROW({ dir->apply(std::move(edit)); }); } } @@ -641,40 +641,40 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(951, entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 951), entry1); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(954, 951); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 954), buildV3Id(TEST_NAMESPACE_ID, 951)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.del(951); - edit.del(951); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 951)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 951)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(972, 954); - edit.ref(985, 954); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 972), buildV3Id(TEST_NAMESPACE_ID, 954)); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 985), buildV3Id(TEST_NAMESPACE_ID, 954)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.del(954); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 954)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(998, 985); - edit.ref(1011, 985); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 998), buildV3Id(TEST_NAMESPACE_ID, 985)); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 1011), buildV3Id(TEST_NAMESPACE_ID, 985)); dir->apply(std::move(edit)); } @@ -690,7 +690,7 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(id, entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, id), entry1); dir->apply(std::move(edit)); } @@ -753,9 +753,9 @@ try // create ref and del in the same write batch PageEntriesEdit edit; for (const auto & x : new_ref_page_ids) - edit.ref(x.first, x.second); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, x.first), buildV3Id(TEST_NAMESPACE_ID, x.second)); for (const auto x : delete_ref_page_ids) - edit.del(x); + edit.del(buildV3Id(TEST_NAMESPACE_ID, x)); dir->apply(std::move(edit)); } else @@ -764,13 +764,13 @@ try { PageEntriesEdit edit; for (const auto & x : new_ref_page_ids) - edit.ref(x.first, x.second); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, x.first), buildV3Id(TEST_NAMESPACE_ID, x.second)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; for (const auto x : delete_ref_page_ids) - edit.del(x); + edit.del(buildV3Id(TEST_NAMESPACE_ID, x)); dir->apply(std::move(edit)); } } @@ -797,7 +797,7 @@ try PageId id = 50; { PageEntriesEdit edit; - edit.putExternal(id); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, id)); dir->apply(std::move(edit)); } @@ -855,9 +855,9 @@ try { PageEntriesEdit edit; for (const auto & x : new_ref_page_ids) - edit.ref(x.first, x.second); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, x.first), buildV3Id(TEST_NAMESPACE_ID, x.second)); for (const auto x : delete_ref_page_ids) - edit.del(x); + edit.del(buildV3Id(TEST_NAMESPACE_ID, x)); dir->apply(std::move(edit)); } else @@ -865,13 +865,13 @@ try { PageEntriesEdit edit; for (const auto & x : new_ref_page_ids) - edit.ref(x.first, x.second); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, x.first), buildV3Id(TEST_NAMESPACE_ID, x.second)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; for (const auto x : delete_ref_page_ids) - edit.del(x); + edit.del(buildV3Id(TEST_NAMESPACE_ID, x)); dir->apply(std::move(edit)); } } @@ -903,8 +903,8 @@ try { { PageEntriesEdit edit; - edit.put(9, PageEntryV3{}); - edit.putExternal(10); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 9), PageEntryV3{}); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } auto s0 = dir->createSnapshot(); @@ -916,12 +916,12 @@ try { PageEntriesEdit edit; - edit.ref(11, 10); - edit.ref(12, 10); - edit.del(10); - edit.ref(13, 9); - edit.ref(14, 9); - edit.del(9); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 12), buildV3Id(TEST_NAMESPACE_ID, 10)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 13), buildV3Id(TEST_NAMESPACE_ID, 9)); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 14), buildV3Id(TEST_NAMESPACE_ID, 9)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 9)); dir->apply(std::move(edit)); } auto s1 = dir->createSnapshot(); @@ -934,8 +934,8 @@ try { PageEntriesEdit edit; - edit.del(11); - edit.del(14); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 14)); dir->apply(std::move(edit)); } auto s2 = dir->createSnapshot(); @@ -948,8 +948,8 @@ try { PageEntriesEdit edit; - edit.del(12); - edit.del(13); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 12)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 13)); dir->apply(std::move(edit)); } auto s3 = dir->createSnapshot(); @@ -1611,7 +1611,7 @@ class PageDirectoryGCTest : public PageDirectoryTest PageEntryV3 entry_v##VERSION{.file_id = (BLOB_FILE_ID), .size = (VERSION), .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; \ { \ PageEntriesEdit edit; \ - edit.put((PAGE_ID), entry_v##VERSION); \ + edit.put(buildV3Id(TEST_NAMESPACE_ID, (PAGE_ID)), entry_v##VERSION); \ dir->apply(std::move(edit)); \ } // Insert an entry into mvcc directory @@ -1620,11 +1620,11 @@ class PageDirectoryGCTest : public PageDirectoryTest #define INSERT_ENTRY_ACQ_SNAP(PAGE_ID, VERSION) \ INSERT_ENTRY(PAGE_ID, VERSION) \ auto snapshot##VERSION = dir->createSnapshot(); -#define INSERT_DELETE(PAGE_ID) \ - { \ - PageEntriesEdit edit; \ - edit.del((PAGE_ID)); \ - dir->apply(std::move(edit)); \ +#define INSERT_DELETE(PAGE_ID) \ + { \ + PageEntriesEdit edit; \ + edit.del(buildV3Id(TEST_NAMESPACE_ID, (PAGE_ID))); \ + dir->apply(std::move(edit)); \ } TEST_F(PageDirectoryGCTest, ManyEditsAndDumpSnapshot) @@ -1905,8 +1905,8 @@ try PageEntryV3 entry_v8{.file_id = 1, .size = 8, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.del(page_id); - edit.put(another_page_id, entry_v8); + edit.del(buildV3Id(TEST_NAMESPACE_ID, page_id)); + edit.put(buildV3Id(TEST_NAMESPACE_ID, another_page_id), entry_v8); dir->apply(std::move(edit)); } auto snapshot8 = dir->createSnapshot(); @@ -2095,13 +2095,13 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(10, entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 10), entry1); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(11, 10); - edit.del(10); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } // entry1 should not be removed @@ -2113,7 +2113,7 @@ try // del 11->entry1 { PageEntriesEdit edit; - edit.del(11); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); dir->apply(std::move(edit)); } // entry1 get removed @@ -2132,18 +2132,18 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(10, entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 10), entry1); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(11, 10); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(12, 10); - edit.del(10); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 12), buildV3Id(TEST_NAMESPACE_ID, 10)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } // entry1 should not be removed @@ -2155,8 +2155,8 @@ try // del 11->entry1 { PageEntriesEdit edit; - edit.del(11); - edit.del(12); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 12)); dir->apply(std::move(edit)); } // entry1 get removed @@ -2175,18 +2175,18 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(10, entry1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 10), entry1); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(11, 10); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(12, 10); - edit.del(10); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 12), buildV3Id(TEST_NAMESPACE_ID, 10)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } // entry1 should not be removed @@ -2219,14 +2219,14 @@ try // del 11->entry2 { PageEntriesEdit edit; - edit.del(11); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); dir->apply(std::move(edit)); EXPECT_EQ(dir->gcInMemEntries().size(), 0); } // del 12->entry2 { PageEntriesEdit edit; - edit.del(12); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 12)); dir->apply(std::move(edit)); // entry2 get removed auto outdated_entries = dir->gcInMemEntries(); @@ -2242,13 +2242,13 @@ try // 10->ext, 11->10=>11->ext; del 10->ext { PageEntriesEdit edit; - edit.putExternal(10); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(11, 10); - edit.del(10); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } // entry1 should not be removed @@ -2263,7 +2263,7 @@ try // del 11->ext { PageEntriesEdit edit; - edit.del(11); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); dir->apply(std::move(edit)); } // entry1 get removed @@ -2282,33 +2282,33 @@ try { { PageEntriesEdit edit; // ingest - edit.putExternal(352); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 352)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(353, 352); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 353), buildV3Id(TEST_NAMESPACE_ID, 352)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; // ingest done - edit.del(352); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 352)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; // split - edit.ref(357, 353); - edit.ref(359, 353); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 357), buildV3Id(TEST_NAMESPACE_ID, 353)); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 359), buildV3Id(TEST_NAMESPACE_ID, 353)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; // split done - edit.del(353); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 353)); dir->apply(std::move(edit)); } { PageEntriesEdit edit; // one of segment delta-merge - edit.del(359); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 359)); dir->apply(std::move(edit)); } @@ -2366,15 +2366,15 @@ try PageEntryV3 entry_2_v2{.file_id = 2, .size = 2, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry_1_v1); - edit.put(1, entry_1_v2); - edit.put(2, entry_2_v1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_1_v1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_1_v2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_2_v1); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.put(2, entry_2_v2); - edit.del(3); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_2_v2); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 3)); dir->apply(std::move(edit)); } // dump 0 @@ -2395,13 +2395,13 @@ try PageEntryV3 entry_60{.file_id = 1, .size = 90, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.del(2); - edit.del(1); - edit.putExternal(10); - edit.putExternal(20); - edit.putExternal(30); - edit.put(50, entry_50); - edit.put(60, entry_60); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 1)); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 20)); + edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 30)); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 50), entry_50); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 60), entry_60); dir->apply(std::move(edit)); } auto s1 = dir->createSnapshot(); @@ -2425,21 +2425,21 @@ try { PageEntriesEdit edit; - edit.ref(11, 10); - edit.del(10); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); - edit.ref(21, 20); - edit.ref(22, 20); - edit.del(20); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 21), buildV3Id(TEST_NAMESPACE_ID, 20)); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 22), buildV3Id(TEST_NAMESPACE_ID, 20)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 20)); - edit.del(30); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 30)); - edit.ref(51, 50); - edit.ref(52, 51); - edit.del(50); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 51), buildV3Id(TEST_NAMESPACE_ID, 50)); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 52), buildV3Id(TEST_NAMESPACE_ID, 51)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 50)); - edit.ref(61, 60); - edit.del(61); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 61), buildV3Id(TEST_NAMESPACE_ID, 60)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 61)); dir->apply(std::move(edit)); } auto s2 = dir->createSnapshot(); @@ -2475,11 +2475,11 @@ try { // only 51->50 left PageEntriesEdit edit; - edit.del(11); - edit.del(21); - edit.del(22); - edit.del(52); - edit.del(60); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 21)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 22)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 52)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 60)); dir->apply(std::move(edit)); } auto s3 = dir->createSnapshot(); @@ -2511,7 +2511,7 @@ try { // only 51->50 left PageEntriesEdit edit; - edit.del(51); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 51)); dir->apply(std::move(edit)); } auto s4 = dir->createSnapshot(); @@ -2559,15 +2559,15 @@ try PageEntryV3 entry_5_v2{.file_id = file_id2, .size = 255, .padded_size = 0, .tag = 0, .offset = 0x400, .checksum = 0x4567}; { PageEntriesEdit edit; - edit.put(1, entry_1_v1); - edit.put(5, entry_5_v1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_1_v1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_5_v1); dir->apply(std::move(edit)); } { PageEntriesEdit edit; - edit.ref(2, 1); - edit.del(1); - edit.put(5, entry_5_v2); // replaced for page 5 entry + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 2), buildV3Id(TEST_NAMESPACE_ID, 1)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 1)); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_5_v2); // replaced for page 5 entry dir->apply(std::move(edit)); } @@ -2627,11 +2627,11 @@ try { PageEntriesEdit edit; - edit.put(50, entry_50_1); - edit.put(50, entry_50_2); - edit.ref(51, 50); - edit.del(50); - edit.del(51); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 50), entry_50_1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 50), entry_50_2); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 51), buildV3Id(TEST_NAMESPACE_ID, 50)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 50)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 51)); auto restored_dir = restore_from_edit(edit); auto page_ids = restored_dir->getAllPageIds(); ASSERT_EQ(page_ids.size(), 0); diff --git a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp index b4e6c2d9204..8b6680c6030 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -38,8 +39,8 @@ TEST(WALSeriTest, AllPuts) PageEntryV3 entry_p2{.file_id = 1, .size = 2, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageVersion ver20(/*seq=*/20); PageEntriesEdit edit; - edit.put(1, entry_p1); - edit.put(2, entry_p2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_p1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_p2); for (auto & rec : edit.getMutRecords()) rec.version = ver20; @@ -60,12 +61,12 @@ try PageEntryV3 entry_p5{.file_id = 1, .size = 5, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageVersion ver21(/*seq=*/21); PageEntriesEdit edit; - edit.put(3, entry_p3); - edit.ref(4, 3); - edit.put(5, entry_p5); - edit.del(2); - edit.del(1); - edit.del(987); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry_p3); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_p5); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 1)); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 987)); for (auto & rec : edit.getMutRecords()) rec.version = ver21; @@ -110,9 +111,9 @@ TEST(WALSeriTest, Upserts) PageVersion ver20_1(/*seq=*/20, /*epoch*/ 1); PageVersion ver21_1(/*seq=*/21, /*epoch*/ 1); PageEntriesEdit edit; - edit.upsertPage(1, ver20_1, entry_p1_2); - edit.upsertPage(3, ver21_1, entry_p3_2); - edit.upsertPage(5, ver21_1, entry_p5_2); + edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 1), ver20_1, entry_p1_2); + edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 3), ver21_1, entry_p3_2); + edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 5), ver21_1, entry_p5_2); auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); ASSERT_EQ(deseri_edit.size(), 3); @@ -140,9 +141,9 @@ TEST(WALSeriTest, RefExternalAndEntry) PageVersion ver3_0(/*seq=*/3, /*epoch*/ 0); { PageEntriesEdit edit; - edit.varExternal(1, ver1_0, 2); - edit.varDel(1, ver2_0); - edit.varRef(2, ver3_0, 1); + edit.varExternal(buildV3Id(TEST_NAMESPACE_ID, 1), ver1_0, 2); + edit.varDel(buildV3Id(TEST_NAMESPACE_ID, 1), ver2_0); + edit.varRef(buildV3Id(TEST_NAMESPACE_ID, 2), ver3_0, buildV3Id(TEST_NAMESPACE_ID, 1)); auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); ASSERT_EQ(deseri_edit.size(), 3); @@ -165,9 +166,9 @@ TEST(WALSeriTest, RefExternalAndEntry) { PageEntriesEdit edit; PageEntryV3 entry_p1_2{.file_id = 2, .size = 1, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; - edit.varEntry(1, ver1_0, entry_p1_2, 2); - edit.varDel(1, ver2_0); - edit.varRef(2, ver3_0, 1); + edit.varEntry(buildV3Id(TEST_NAMESPACE_ID, 1), ver1_0, entry_p1_2, 2); + edit.varDel(buildV3Id(TEST_NAMESPACE_ID, 1), ver2_0); + edit.varRef(buildV3Id(TEST_NAMESPACE_ID, 2), ver3_0, buildV3Id(TEST_NAMESPACE_ID, 1)); auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); ASSERT_EQ(deseri_edit.size(), 3); @@ -410,8 +411,8 @@ try PageVersion ver20(/*seq=*/20); { PageEntriesEdit edit; - edit.put(1, entry_p1); - edit.put(2, entry_p2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_p1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_p2); size_each_edit.emplace_back(edit.size()); wal->apply(edit, ver20); } @@ -440,10 +441,10 @@ try PageVersion ver21(/*seq=*/21); { PageEntriesEdit edit; - edit.put(3, entry_p3); - edit.ref(4, 3); - edit.put(5, entry_p5); - edit.del(2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry_p3); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_p5); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); size_each_edit.emplace_back(edit.size()); wal->apply(edit, ver21); } @@ -475,9 +476,9 @@ try PageVersion ver21_1(/*seq=*/21, /*epoch*/ 1); { PageEntriesEdit edit; - edit.upsertPage(1, ver20_1, entry_p1_2); - edit.upsertPage(3, ver21_1, entry_p3_2); - edit.upsertPage(5, ver21_1, entry_p5_2); + edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 1), ver20_1, entry_p1_2); + edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 3), ver21_1, entry_p3_2); + edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 5), ver21_1, entry_p5_2); size_each_edit.emplace_back(edit.size()); wal->apply(edit); } @@ -519,8 +520,8 @@ try PageVersion ver20(/*seq=*/20); { PageEntriesEdit edit; - edit.put(1, entry_p1); - edit.put(2, entry_p2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_p1); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_p2); size_each_edit.emplace_back(edit.size()); wal->apply(edit, ver20); } @@ -531,10 +532,10 @@ try PageVersion ver21(/*seq=*/21); { PageEntriesEdit edit; - edit.put(3, entry_p3); - edit.ref(4, 3); - edit.put(5, entry_p5); - edit.del(2); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry_p3); + edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); + edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_p5); + edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); size_each_edit.emplace_back(edit.size()); wal->apply(edit, ver21); } @@ -547,9 +548,9 @@ try PageVersion ver21_1(/*seq=*/21, /*epoch*/ 1); { PageEntriesEdit edit; - edit.upsertPage(1, ver20_1, entry_p1_2); - edit.upsertPage(3, ver21_1, entry_p3_2); - edit.upsertPage(5, ver21_1, entry_p5_2); + edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 1), ver20_1, entry_p1_2); + edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 3), ver21_1, entry_p3_2); + edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 5), ver21_1, entry_p5_2); size_each_edit.emplace_back(edit.size()); wal->apply(edit); } @@ -622,7 +623,7 @@ try { page_id += 1; entry.size = page_id; - edit.put(page_id, entry); + edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry); } wal->apply(edit, ver); @@ -665,7 +666,7 @@ try // just fill in some random entry for (size_t i = 0; i < 70; ++i) { - snap_edit.varEntry(d_10000(rd), PageVersion(345, 22), entry, 1); + snap_edit.varEntry(buildV3Id(TEST_NAMESPACE_ID, d_10000(rd)), PageVersion(345, 22), entry, 1); } std::tie(wal, reader) = WALStore::create(getCurrentTestName(), enc_provider, delegator, config); bool done = wal->saveSnapshot(std::move(file_snap), std::move(snap_edit)); From c484a4e33ffe4d1c29f2b620a9c7aed5014fe0c2 Mon Sep 17 00:00:00 2001 From: JaySon Date: Tue, 4 Oct 2022 12:41:46 +0800 Subject: [PATCH 02/40] PageStorage: Make deserialize out of WALReader (#6070) ref pingcap/tiflash#6071 --- .../src/Storages/Page/ExternalPageCallbacks.h | 38 ++++++++++++++++++ dbms/src/Storages/Page/PageStorage.h | 15 +------ dbms/src/Storages/Page/V3/PageDirectory.cpp | 36 ++++++++--------- dbms/src/Storages/Page/V3/PageDirectory.h | 14 ++++--- .../Storages/Page/V3/PageDirectoryFactory.cpp | 6 ++- dbms/src/Storages/Page/V3/WAL/WALReader.cpp | 8 ++-- dbms/src/Storages/Page/V3/WAL/WALReader.h | 2 +- .../Page/V3/tests/gtest_wal_store.cpp | 40 +++++++++++-------- 8 files changed, 97 insertions(+), 62 deletions(-) create mode 100644 dbms/src/Storages/Page/ExternalPageCallbacks.h diff --git a/dbms/src/Storages/Page/ExternalPageCallbacks.h b/dbms/src/Storages/Page/ExternalPageCallbacks.h new file mode 100644 index 00000000000..09fcc94d090 --- /dev/null +++ b/dbms/src/Storages/Page/ExternalPageCallbacks.h @@ -0,0 +1,38 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include + +namespace DB +{ + +struct ExternalPageCallbacks +{ + // `scanner` for scanning available external page ids on disks. + // `remover` will be called with living normal page ids after gc run a round, user should remove those + // external pages(files) in `pending_external_pages` but not in `valid_normal_pages` + using PathAndIdsVec = std::vector>>; + using ExternalPagesScanner = std::function; + using ExternalPagesRemover + = std::function & valid_normal_pages)>; + ExternalPagesScanner scanner = nullptr; + ExternalPagesRemover remover = nullptr; + NamespaceId ns_id = MAX_NAMESPACE_ID; +}; + +} // namespace DB diff --git a/dbms/src/Storages/Page/PageStorage.h b/dbms/src/Storages/Page/PageStorage.h index 7468c4fde44..4f89772db8f 100644 --- a/dbms/src/Storages/Page/PageStorage.h +++ b/dbms/src/Storages/Page/PageStorage.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -66,20 +67,6 @@ enum class PageStorageRunMode : UInt8 MIX_MODE = 3, }; -struct ExternalPageCallbacks -{ - // `scanner` for scanning available external page ids on disks. - // `remover` will be called with living normal page ids after gc run a round, user should remove those - // external pages(files) in `pending_external_pages` but not in `valid_normal_pages` - using PathAndIdsVec = std::vector>>; - using ExternalPagesScanner = std::function; - using ExternalPagesRemover - = std::function & valid_normal_pages)>; - ExternalPagesScanner scanner = nullptr; - ExternalPagesRemover remover = nullptr; - NamespaceId ns_id = MAX_NAMESPACE_ID; -}; - /** * A storage system stored pages. Pages are serialized objects referenced by PageID. Store Page with the same PageID * will cover the old ones. diff --git a/dbms/src/Storages/Page/V3/PageDirectory.cpp b/dbms/src/Storages/Page/V3/PageDirectory.cpp index 5dbda3b1927..9cb7230cec9 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectory.cpp @@ -293,7 +293,7 @@ std::shared_ptr VersionedPageEntries::fromRestored(const PageE } } -std::tuple +std::tuple VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV3 * entry) { auto page_lock = acquireLock(); @@ -306,7 +306,7 @@ VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV if (!ignore_delete && iter->second.isDelete()) { // the page is not visible - return {RESOLVE_FAIL, buildV3Id(0, 0), PageVersion(0)}; + return {ResolveResult::FAIL, buildV3Id(0, 0), PageVersion(0)}; } // If `ignore_delete` is true, we need the page entry even if it is logical deleted. @@ -323,7 +323,7 @@ VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV // copy and return the entry if (entry != nullptr) *entry = iter->second.entry; - return {RESOLVE_TO_NORMAL, buildV3Id(0, 0), PageVersion(0)}; + return {ResolveResult::TO_NORMAL, buildV3Id(0, 0), PageVersion(0)}; } // else fallthrough to FAIL } // else fallthrough to FAIL @@ -335,7 +335,7 @@ VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV bool ok = ignore_delete || (!is_deleted || seq < delete_ver.sequence); if (create_ver.sequence <= seq && ok) { - return {RESOLVE_TO_NORMAL, buildV3Id(0, 0), PageVersion(0)}; + return {ResolveResult::TO_NORMAL, buildV3Id(0, 0), PageVersion(0)}; } } else if (type == EditRecordType::VAR_REF) @@ -343,7 +343,7 @@ VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV // Return the origin page id if this ref is visible by `seq`. if (create_ver.sequence <= seq && (!is_deleted || seq < delete_ver.sequence)) { - return {RESOLVE_TO_REF, ori_page_id, create_ver}; + return {ResolveResult::TO_REF, ori_page_id, create_ver}; } } else @@ -351,7 +351,7 @@ VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV LOG_FMT_WARNING(&Poco::Logger::get("VersionedPageEntries"), "Can't resolve the EditRecordType {}", type); } - return {RESOLVE_FAIL, buildV3Id(0, 0), PageVersion(0)}; + return {ResolveResult::FAIL, buildV3Id(0, 0), PageVersion(0)}; } std::optional VersionedPageEntries::getEntry(UInt64 seq) const @@ -852,12 +852,12 @@ PageIDAndEntryV3 PageDirectory::get(PageIdV3Internal page_id, const PageDirector auto [resolve_state, next_id_to_resolve, next_ver_to_resolve] = iter->second->resolveToPageId(ver_to_resolve.sequence, /*ignore_delete=*/id_to_resolve != page_id, &entry_got); switch (resolve_state) { - case VersionedPageEntries::RESOLVE_TO_NORMAL: + case ResolveResult::TO_NORMAL: return PageIDAndEntryV3(page_id, entry_got); - case VersionedPageEntries::RESOLVE_FAIL: + case ResolveResult::FAIL: ok = false; break; - case VersionedPageEntries::RESOLVE_TO_REF: + case ResolveResult::TO_REF: if (id_to_resolve == next_id_to_resolve) { ok = false; @@ -912,12 +912,12 @@ std::pair PageDirectory::get(const PageIdV3Internal auto [resolve_state, next_id_to_resolve, next_ver_to_resolve] = iter->second->resolveToPageId(ver_to_resolve.sequence, /*ignore_delete=*/id_to_resolve != page_id, &entry_got); switch (resolve_state) { - case VersionedPageEntries::RESOLVE_TO_NORMAL: + case ResolveResult::TO_NORMAL: return true; - case VersionedPageEntries::RESOLVE_FAIL: + case ResolveResult::FAIL: ok = false; break; - case VersionedPageEntries::RESOLVE_TO_REF: + case ResolveResult::TO_REF: if (id_to_resolve == next_id_to_resolve) { ok = false; @@ -981,13 +981,13 @@ PageIdV3Internal PageDirectory::getNormalPageId(PageIdV3Internal page_id, const auto [resolve_state, next_id_to_resolve, next_ver_to_resolve] = iter->second->resolveToPageId(ver_to_resolve.sequence, /*ignore_delete=*/id_to_resolve != page_id, nullptr); switch (resolve_state) { - case VersionedPageEntries::RESOLVE_TO_NORMAL: + case ResolveResult::TO_NORMAL: return id_to_resolve; - case VersionedPageEntries::RESOLVE_FAIL: + case ResolveResult::FAIL: // resolve failed keep_resolve = false; break; - case VersionedPageEntries::RESOLVE_TO_REF: + case ResolveResult::TO_REF: if (id_to_resolve == next_id_to_resolve) { // dead-loop, so break the `while(keep_resolve)` @@ -1086,11 +1086,11 @@ void PageDirectory::applyRefEditRecord( nullptr); switch (resolve_state) { - case VersionedPageEntries::RESOLVE_FAIL: + case ResolveResult::FAIL: return {false, id_to_resolve, ver_to_resolve}; - case VersionedPageEntries::RESOLVE_TO_NORMAL: + case ResolveResult::TO_NORMAL: return {true, id_to_resolve, ver_to_resolve}; - case VersionedPageEntries::RESOLVE_TO_REF: + case ResolveResult::TO_REF: if (id_to_resolve == next_id_to_resolve) { return {false, next_id_to_resolve, next_ver_to_resolve}; diff --git a/dbms/src/Storages/Page/V3/PageDirectory.h b/dbms/src/Storages/Page/V3/PageDirectory.h index 065d5a86f34..947d95926b8 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.h +++ b/dbms/src/Storages/Page/V3/PageDirectory.h @@ -134,6 +134,14 @@ struct EntryOrDelete class VersionedPageEntries; using VersionedPageEntriesPtr = std::shared_ptr; using PageLock = std::lock_guard; + +enum class ResolveResult +{ + FAIL, + TO_REF, + TO_NORMAL, +}; + class VersionedPageEntries { public: @@ -161,12 +169,6 @@ class VersionedPageEntries std::shared_ptr fromRestored(const PageEntriesEdit::EditRecord & rec); - enum ResolveResult - { - RESOLVE_FAIL, - RESOLVE_TO_REF, - RESOLVE_TO_NORMAL, - }; std::tuple resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV3 * entry); diff --git a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp index 8bb75af72cb..9f607c9509d 100644 --- a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -196,8 +197,8 @@ void PageDirectoryFactory::loadFromDisk(const PageDirectoryPtr & dir, WALStoreRe { while (reader->remained()) { - auto [ok, edit] = reader->next(); - if (!ok) + auto record = reader->next(); + if (!record) { // TODO: Handle error, some error could be ignored. // If the file happened to some error, @@ -208,6 +209,7 @@ void PageDirectoryFactory::loadFromDisk(const PageDirectoryPtr & dir, WALStoreRe } // apply the edit read + auto edit = ser::deserializeFrom(record.value()); loadEdit(dir, edit); } } diff --git a/dbms/src/Storages/Page/V3/WAL/WALReader.cpp b/dbms/src/Storages/Page/V3/WAL/WALReader.cpp index 6b67126d9ad..fd8c21caed6 100644 --- a/dbms/src/Storages/Page/V3/WAL/WALReader.cpp +++ b/dbms/src/Storages/Page/V3/WAL/WALReader.cpp @@ -81,7 +81,7 @@ LogFilenameSet WALStoreReader::listAllFiles( std::tuple, LogFilenameSet> WALStoreReader::findCheckpoint(LogFilenameSet && all_files) { - LogFilenameSet::const_iterator latest_checkpoint_iter = all_files.cend(); + auto latest_checkpoint_iter = all_files.cend(); for (auto iter = all_files.cbegin(); iter != all_files.cend(); ++iter) { if (iter->level_num > 0) @@ -170,7 +170,7 @@ bool WALStoreReader::remained() const return false; } -std::tuple WALStoreReader::next() +std::optional WALStoreReader::next() { bool ok = false; String record; @@ -179,14 +179,14 @@ std::tuple WALStoreReader::next() std::tie(ok, record) = reader->readRecord(); if (ok) { - return {true, ser::deserializeFrom(record)}; + return record; } // Roll to read the next file if (bool next_file = openNextFile(); !next_file) { // No more file to be read. - return {false, PageEntriesEdit{}}; + return std::nullopt; } } while (true); } diff --git a/dbms/src/Storages/Page/V3/WAL/WALReader.h b/dbms/src/Storages/Page/V3/WAL/WALReader.h index e61a53da5de..4c4885d7df9 100644 --- a/dbms/src/Storages/Page/V3/WAL/WALReader.h +++ b/dbms/src/Storages/Page/V3/WAL/WALReader.h @@ -71,7 +71,7 @@ class WALStoreReader bool remained() const; - std::tuple next(); + std::optional next(); void throwIfError() const { diff --git a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp index 8b6680c6030..782d08fe6d9 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp @@ -370,9 +370,8 @@ TEST_P(WALStoreTest, Empty) ASSERT_NE(wal, nullptr); while (reader->remained()) { - auto [ok, edit] = reader->next(); - (void)edit; - if (!ok) + auto record = reader->next(); + if (!record) { reader->throwIfError(); // else it just run to the end of file. @@ -425,10 +424,11 @@ try size_t num_applied_edit = 0; while (reader->remained()) { - const auto & [ok, edit] = reader->next(); - if (!ok) + const auto record = reader->next(); + if (!record) break; // Details of each edit is verified in `WALSeriTest` + auto edit = ser::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()); num_applied_edit += 1; } @@ -457,10 +457,11 @@ try size_t num_applied_edit = 0; while (reader->remained()) { - const auto & [ok, edit] = reader->next(); - if (!ok) + const auto record = reader->next(); + if (!record) break; // Details of each edit is verified in `WALSeriTest` + auto edit = ser::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()); num_applied_edit += 1; } @@ -491,10 +492,11 @@ try auto reader = WALStoreReader::create(getCurrentTestName(), provider, delegator); while (reader->remained()) { - const auto & [ok, edit] = reader->next(); - if (!ok) + const auto record = reader->next(); + if (!record) break; // Details of each edit is verified in `WALSeriTest` + auto edit = ser::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()); num_applied_edit += 1; } @@ -562,10 +564,11 @@ try auto reader = WALStoreReader::create(getCurrentTestName(), provider, delegator); while (reader->remained()) { - const auto & [ok, edit] = reader->next(); - if (!ok) + const auto record = reader->next(); + if (!record) break; // Details of each edit is verified in `WALSeriTest` + auto edit = ser::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()) << fmt::format("edit size not match at idx={}", num_applied_edit); num_applied_edit += 1; } @@ -577,14 +580,15 @@ try std::tie(wal, reader) = WALStore::create(getCurrentTestName(), provider, delegator, config); while (reader->remained()) { - auto [ok, edit] = reader->next(); - if (!ok) + auto record = reader->next(); + if (!record) { reader->throwIfError(); // else it just run to the end of file. break; } // Details of each edit is verified in `WALSeriTest` + auto edit = ser::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()) << fmt::format("edit size not match at idx={}", num_applied_edit); num_applied_edit += 1; } @@ -638,13 +642,14 @@ try std::tie(wal, reader) = WALStore::create(getCurrentTestName(), enc_provider, delegator, config); while (reader->remained()) { - auto [ok, edit] = reader->next(); - if (!ok) + auto record = reader->next(); + if (!record) { reader->throwIfError(); // else it just run to the end of file. break; } + auto edit = ser::deserializeFrom(record.value()); num_pages_read += edit.size(); EXPECT_EQ(size_each_edit[num_edits_read], edit.size()) << fmt::format("at idx={}", num_edits_read); num_edits_read += 1; @@ -680,13 +685,14 @@ try std::tie(wal, reader) = WALStore::create(getCurrentTestName(), enc_provider, delegator, config); while (reader->remained()) { - auto [ok, edit] = reader->next(); - if (!ok) + auto record = reader->next(); + if (!record) { reader->throwIfError(); // else it just run to the end of file. break; } + auto edit = ser::deserializeFrom(record.value()); num_pages_read += edit.size(); num_edits_read += 1; } From 3e2addf887cda80b0f2a02c98cd01966ad6861ab Mon Sep 17 00:00:00 2001 From: JaySon Date: Wed, 12 Oct 2022 15:23:51 +0800 Subject: [PATCH 03/40] Fix that empty namespace won't be clean (#6108) close pingcap/tiflash#6109 --- .../V3/PageDirectory/ExternalIdsByNamespace.cpp | 2 +- .../V3/PageDirectory/ExternalIdsByNamespace.h | 10 ++++++++++ .../Page/V3/tests/gtest_page_directory.cpp | 15 ++++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.cpp b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.cpp index 217b8896f7e..34934297d30 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.cpp @@ -64,7 +64,7 @@ std::set ExternalIdsByNamespace::getAliveIds(NamespaceId ns_id) const // No valid external pages in this `ns_id` if (valid_external_ids.empty()) { - valid_external_ids.erase(ns_id); + ids_by_ns.erase(ns_id); } return valid_external_ids; } diff --git a/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h index 51c118e9172..01cae5ebe20 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h +++ b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h @@ -47,6 +47,16 @@ class ExternalIdsByNamespace // cleanup all external id ptrs. void unregisterNamespace(NamespaceId ns_id); + // Check whether `ns_id` exist. Expose for testing. + // Note that the result is meaningless unless `getAliveIds` + // or `unregisterNamespace` is called to cleanup invalid + // external ids. + bool existNamespace(NamespaceId ns_id) const + { + std::lock_guard map_guard(mu); + return ids_by_ns.count(ns_id) > 0; + } + DISALLOW_COPY_AND_MOVE(ExternalIdsByNamespace); private: diff --git a/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp b/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp index 0ffedc95d9b..1db4a893cfb 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp @@ -47,11 +47,19 @@ namespace DB { namespace PS::V3::tests { -TEST(ExternalIdsByNamespace, Simple) +TEST(ExternalIdsByNamespaceTest, Simple) { NamespaceId ns_id = 100; ExternalIdsByNamespace external_ids_by_ns; + { + ASSERT_FALSE(external_ids_by_ns.existNamespace(ns_id)); + std::shared_ptr holder0 = std::make_shared(buildV3Id(ns_id, 10)); + holder0.reset(); + // though holder0 is released, but the ns_id still exist + // until we call getAliveIds. So not check the ns_id here. + } + std::atomic who(0); std::shared_ptr holder = std::make_shared(buildV3Id(ns_id, 50)); @@ -71,16 +79,21 @@ TEST(ExternalIdsByNamespace, Simple) th_insert.wait(); { + // holder keep "50" alive auto ids = external_ids_by_ns.getAliveIds(ns_id); LOG_DEBUG(&Poco::Logger::root(), "{} end first, size={}", who.load(), ids.size()); ASSERT_EQ(ids.size(), 1); ASSERT_EQ(*ids.begin(), 50); + ASSERT_TRUE(external_ids_by_ns.existNamespace(ns_id)); } { + // unregister all ids under the namespace + // "50" is erased though the holder is not released. external_ids_by_ns.unregisterNamespace(ns_id); auto ids = external_ids_by_ns.getAliveIds(ns_id); ASSERT_EQ(ids.size(), 0); + ASSERT_FALSE(external_ids_by_ns.existNamespace(ns_id)); } } From 65eca8cb7ce6b324963e64252e57846fe08a24b4 Mon Sep 17 00:00:00 2001 From: JaySon Date: Tue, 20 Sep 2022 12:15:01 +0800 Subject: [PATCH 04/40] PageStorage: Refactor some file structure (#5828) ref pingcap/tiflash#4562 --- dbms/CMakeLists.txt | 1 + dbms/src/Storages/Page/V3/Blob/BlobConfig.h | 45 + .../Storages/Page/V3/{ => Blob}/BlobFile.cpp | 2 +- .../Storages/Page/V3/{ => Blob}/BlobFile.h | 0 dbms/src/Storages/Page/V3/Blob/BlobStat.cpp | 368 ++++++++ dbms/src/Storages/Page/V3/Blob/BlobStat.h | 201 +++++ dbms/src/Storages/Page/V3/BlobStore.cpp | 344 +------- dbms/src/Storages/Page/V3/BlobStore.h | 204 +---- dbms/src/Storages/Page/V3/PageDirectory.cpp | 17 +- dbms/src/Storages/Page/V3/PageDirectory.h | 49 +- .../Storages/Page/V3/PageDirectoryFactory.cpp | 4 +- .../Storages/Page/V3/PageDirectoryFactory.h | 7 +- dbms/src/Storages/Page/V3/PageEntry.h | 2 +- dbms/src/Storages/Page/V3/PageStorageImpl.cpp | 16 +- dbms/src/Storages/Page/V3/PageStorageImpl.h | 8 +- dbms/src/Storages/Page/V3/WAL/WALConfig.h | 50 ++ dbms/src/Storages/Page/V3/WALStore.cpp | 72 +- dbms/src/Storages/Page/V3/WALStore.h | 44 +- .../Storages/Page/V3/tests/entries_helper.h | 10 +- .../Page/V3/tests/gtest_blob_stat.cpp | 281 ++++++ .../Page/V3/tests/gtest_blob_store.cpp | 280 +----- .../Page/V3/tests/gtest_page_directory.cpp | 797 ++---------------- .../Page/V3/tests/gtest_versioned_entries.cpp | 683 +++++++++++++++ .../Page/V3/tests/gtest_wal_store.cpp | 30 +- .../Page/tools/PageCtl/PageStorageCtlV3.cpp | 22 +- 25 files changed, 1863 insertions(+), 1674 deletions(-) create mode 100644 dbms/src/Storages/Page/V3/Blob/BlobConfig.h rename dbms/src/Storages/Page/V3/{ => Blob}/BlobFile.cpp (99%) rename dbms/src/Storages/Page/V3/{ => Blob}/BlobFile.h (100%) create mode 100644 dbms/src/Storages/Page/V3/Blob/BlobStat.cpp create mode 100644 dbms/src/Storages/Page/V3/Blob/BlobStat.h create mode 100644 dbms/src/Storages/Page/V3/WAL/WALConfig.h create mode 100644 dbms/src/Storages/Page/V3/tests/gtest_blob_stat.cpp create mode 100644 dbms/src/Storages/Page/V3/tests/gtest_versioned_entries.cpp diff --git a/dbms/CMakeLists.txt b/dbms/CMakeLists.txt index 1b3a54eb50b..c5813f9735a 100644 --- a/dbms/CMakeLists.txt +++ b/dbms/CMakeLists.txt @@ -99,6 +99,7 @@ add_headers_and_sources(dbms src/Storages/Page/V3/LogFile) add_headers_and_sources(dbms src/Storages/Page/V3/WAL) add_headers_and_sources(dbms src/Storages/Page/V3/spacemap) add_headers_and_sources(dbms src/Storages/Page/V3/PageDirectory) +add_headers_and_sources(dbms src/Storages/Page/V3/Blob) add_headers_and_sources(dbms src/Storages/Page/) add_headers_and_sources(dbms src/TiDB) add_headers_and_sources(dbms src/Client) diff --git a/dbms/src/Storages/Page/V3/Blob/BlobConfig.h b/dbms/src/Storages/Page/V3/Blob/BlobConfig.h new file mode 100644 index 00000000000..6323af708ef --- /dev/null +++ b/dbms/src/Storages/Page/V3/Blob/BlobConfig.h @@ -0,0 +1,45 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +namespace DB::PS::V3 +{ +struct BlobConfig +{ + SettingUInt64 file_limit_size = BLOBFILE_LIMIT_SIZE; + SettingUInt64 spacemap_type = SpaceMap::SpaceMapType::SMAP64_STD_MAP; + SettingUInt64 cached_fd_size = BLOBSTORE_CACHED_FD_SIZE; + SettingUInt64 block_alignment_bytes = 0; + SettingDouble heavy_gc_valid_rate = 0.2; + + String toString() + { + return fmt::format("BlobStore Config Info: " + "[file_limit_size={}],[spacemap_type={}]," + "[cached_fd_size={}],[block_alignment_bytes={}]," + "[heavy_gc_valid_rate={}]", + file_limit_size, + spacemap_type, + cached_fd_size, + block_alignment_bytes, + heavy_gc_valid_rate); + } +}; +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/BlobFile.cpp b/dbms/src/Storages/Page/V3/Blob/BlobFile.cpp similarity index 99% rename from dbms/src/Storages/Page/V3/BlobFile.cpp rename to dbms/src/Storages/Page/V3/Blob/BlobFile.cpp index b018150c605..45e7c04f0e1 100644 --- a/dbms/src/Storages/Page/V3/BlobFile.cpp +++ b/dbms/src/Storages/Page/V3/Blob/BlobFile.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include namespace DB { diff --git a/dbms/src/Storages/Page/V3/BlobFile.h b/dbms/src/Storages/Page/V3/Blob/BlobFile.h similarity index 100% rename from dbms/src/Storages/Page/V3/BlobFile.h rename to dbms/src/Storages/Page/V3/Blob/BlobFile.h diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp new file mode 100644 index 00000000000..e494b8108d4 --- /dev/null +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp @@ -0,0 +1,368 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include + +namespace ProfileEvents +{ +extern const Event PSMWritePages; +extern const Event PSMReadPages; +extern const Event PSV3MBlobExpansion; +extern const Event PSV3MBlobReused; +} // namespace ProfileEvents + +namespace DB::PS::V3 +{ + +/********************** + * BlobStats methods * + *********************/ + +BlobStats::BlobStats(LoggerPtr log_, PSDiskDelegatorPtr delegator_, BlobConfig & config_) + : log(std::move(log_)) + , delegator(delegator_) + , config(config_) +{ +} + +void BlobStats::restoreByEntry(const PageEntryV3 & entry) +{ + auto stat = blobIdToStat(entry.file_id); + stat->restoreSpaceMap(entry.offset, entry.getTotalSize()); +} + +std::pair BlobStats::getBlobIdFromName(String blob_name) +{ + String err_msg; + if (!startsWith(blob_name, BlobFile::BLOB_PREFIX_NAME)) + { + return {INVALID_BLOBFILE_ID, err_msg}; + } + + Strings ss; + boost::split(ss, blob_name, boost::is_any_of("_")); + + if (ss.size() != 2) + { + return {INVALID_BLOBFILE_ID, err_msg}; + } + + try + { + const auto & blob_id = std::stoull(ss[1]); + return {blob_id, err_msg}; + } + catch (std::invalid_argument & e) + { + err_msg = e.what(); + } + catch (std::out_of_range & e) + { + err_msg = e.what(); + } + return {INVALID_BLOBFILE_ID, err_msg}; +} + +void BlobStats::restore() +{ + BlobFileId max_restored_file_id = 0; + + for (auto & [path, stats] : stats_map) + { + (void)path; + for (const auto & stat : stats) + { + stat->recalculateSpaceMap(); + max_restored_file_id = std::max(stat->id, max_restored_file_id); + } + } + + // restore `roll_id` + roll_id = max_restored_file_id + 1; +} + +std::lock_guard BlobStats::lock() const +{ + return std::lock_guard(lock_stats); +} + +BlobStats::BlobStatPtr BlobStats::createStat(BlobFileId blob_file_id, UInt64 max_caps, const std::lock_guard & guard) +{ + // New blob file id won't bigger than roll_id + if (blob_file_id > roll_id) + { + throw Exception(fmt::format("BlobStats won't create [blob_id={}], which is bigger than [roll_id={}]", + blob_file_id, + roll_id), + ErrorCodes::LOGICAL_ERROR); + } + + for (auto & [path, stats] : stats_map) + { + (void)path; + for (const auto & stat : stats) + { + if (stat->id == blob_file_id) + { + throw Exception(fmt::format("BlobStats can not create [blob_id={}] which is exist", + blob_file_id), + ErrorCodes::LOGICAL_ERROR); + } + } + } + + // Create a stat without checking the file_id exist or not + auto stat = createStatNotChecking(blob_file_id, max_caps, guard); + + // Roll to the next new blob id + if (blob_file_id == roll_id) + { + roll_id++; + } + + return stat; +} + +BlobStats::BlobStatPtr BlobStats::createStatNotChecking(BlobFileId blob_file_id, UInt64 max_caps, const std::lock_guard &) +{ + LOG_FMT_INFO(log, "Created a new BlobStat [blob_id={}] [capacity={}]", blob_file_id, max_caps); + // Only BlobFile which total capacity is smaller or equal to config.file_limit_size can be reused for another write + auto stat_type = max_caps <= config.file_limit_size ? BlobStats::BlobStatType::NORMAL : BlobStats::BlobStatType::READ_ONLY; + BlobStatPtr stat = std::make_shared( + blob_file_id, + static_cast(config.spacemap_type.get()), + max_caps, + stat_type); + + PageFileIdAndLevel id_lvl{blob_file_id, 0}; + auto path = delegator->choosePath(id_lvl); + /// This function may be called when restoring an old BlobFile at restart or creating a new BlobFile. + /// If restoring an old BlobFile, the BlobFile path maybe already added to delegator, but an another call to `addPageFileUsedSize` should do no harm. + /// If creating a new BlobFile, we need to register the BlobFile's path to delegator, so it's necessary to call `addPageFileUsedSize` here. + delegator->addPageFileUsedSize({blob_file_id, 0}, 0, path, true); + stats_map[path].emplace_back(stat); + return stat; +} + +void BlobStats::eraseStat(const BlobStatPtr && stat, const std::lock_guard &) +{ + PageFileIdAndLevel id_lvl{stat->id, 0}; + stats_map[delegator->getPageFilePath(id_lvl)].remove(stat); +} + +void BlobStats::eraseStat(BlobFileId blob_file_id, const std::lock_guard & lock) +{ + BlobStatPtr stat = nullptr; + + for (auto & [path, stats] : stats_map) + { + (void)path; + for (const auto & stat_in_map : stats) + { + if (stat_in_map->id == blob_file_id) + { + stat = stat_in_map; + break; + } + } + } + + if (stat == nullptr) + { + LOG_FMT_ERROR(log, "BlobStat not exist [blob_id={}]", blob_file_id); + return; + } + + LOG_FMT_DEBUG(log, "Erase BlobStat from maps [blob_id={}]", blob_file_id); + + eraseStat(std::move(stat), lock); +} + +std::pair BlobStats::chooseStat(size_t buf_size, const std::lock_guard &) +{ + BlobStatPtr stat_ptr = nullptr; + double smallest_valid_rate = 2; + + // No stats exist + if (stats_map.empty()) + { + return std::make_pair(nullptr, roll_id); + } + + // If the stats_map size changes, or stats_map_path_index is out of range, + // then make stats_map_path_index fit to current size. + stats_map_path_index %= stats_map.size(); + + auto stats_iter = stats_map.begin(); + std::advance(stats_iter, stats_map_path_index); + + size_t path_iter_idx = 0; + for (path_iter_idx = 0; path_iter_idx < stats_map.size(); ++path_iter_idx) + { + // Try to find a suitable stat under current path (path=`stats_iter->first`) + for (const auto & stat : stats_iter->second) + { + auto lock = stat->lock(); // TODO: will it bring performance regression? + if (stat->isNormal() + && stat->sm_max_caps >= buf_size + && stat->sm_valid_rate < smallest_valid_rate) + { + smallest_valid_rate = stat->sm_valid_rate; + stat_ptr = stat; + } + } + + // Already find the available stat under current path. + if (stat_ptr != nullptr) + { + break; + } + + // Try to find stat in the next path. + stats_iter++; + if (stats_iter == stats_map.end()) + { + stats_iter = stats_map.begin(); + } + } + + // advance the `stats_map_path_idx` without size checking + stats_map_path_index += path_iter_idx + 1; + + // Can not find a suitable stat under all paths + if (stat_ptr == nullptr) + { + return std::make_pair(nullptr, roll_id); + } + + return std::make_pair(stat_ptr, INVALID_BLOBFILE_ID); +} + +BlobStats::BlobStatPtr BlobStats::blobIdToStat(BlobFileId file_id, bool ignore_not_exist) +{ + auto guard = lock(); + for (const auto & [path, stats] : stats_map) + { + (void)path; + for (const auto & stat : stats) + { + if (stat->id == file_id) + { + return stat; + } + } + } + + if (!ignore_not_exist) + { + throw Exception(fmt::format("Can't find BlobStat with [blob_id={}]", + file_id), + ErrorCodes::LOGICAL_ERROR); + } + + return nullptr; +} + +/********************* + * BlobStat methods * + ********************/ + +BlobFileOffset BlobStats::BlobStat::getPosFromStat(size_t buf_size, const std::lock_guard &) +{ + BlobFileOffset offset = 0; + UInt64 max_cap = 0; + bool expansion = true; + + std::tie(offset, max_cap, expansion) = smap->searchInsertOffset(buf_size); + ProfileEvents::increment(expansion ? ProfileEvents::PSV3MBlobExpansion : ProfileEvents::PSV3MBlobReused); + + /** + * Whatever `searchInsertOffset` success or failed, + * Max capability still need update. + */ + sm_max_caps = max_cap; + if (offset != INVALID_BLOBFILE_OFFSET) + { + if (offset + buf_size > sm_total_size) + { + // This file must be expanded + auto expand_size = buf_size - (sm_total_size - offset); + sm_total_size += expand_size; + sm_valid_size += buf_size; + } + else + { + /** + * The `offset` reuses the original address. + * Current blob file is not expanded. + * Only update valid size. + */ + sm_valid_size += buf_size; + } + + sm_valid_rate = sm_valid_size * 1.0 / sm_total_size; + } + return offset; +} + +size_t BlobStats::BlobStat::removePosFromStat(BlobFileOffset offset, size_t buf_size, const std::lock_guard &) +{ + if (!smap->markFree(offset, buf_size)) + { + smap->logDebugString(); + throw Exception(fmt::format("Remove position from BlobStat failed, invalid position [offset={}] [buf_size={}] [blob_id={}]", + offset, + buf_size, + id), + ErrorCodes::LOGICAL_ERROR); + } + + sm_valid_size -= buf_size; + sm_valid_rate = sm_valid_size * 1.0 / sm_total_size; + return sm_valid_size; +} + +void BlobStats::BlobStat::restoreSpaceMap(BlobFileOffset offset, size_t buf_size) +{ + if (!smap->markUsed(offset, buf_size)) + { + smap->logDebugString(); + throw Exception(fmt::format("Restore position from BlobStat failed, the space/subspace is already being used [offset={}] [buf_size={}] [blob_id={}]", + offset, + buf_size, + id), + ErrorCodes::LOGICAL_ERROR); + } +} + +void BlobStats::BlobStat::recalculateSpaceMap() +{ + const auto & [total_size, valid_size] = smap->getSizes(); + sm_total_size = total_size; + sm_valid_size = valid_size; + sm_valid_rate = total_size == 0 ? 0.0 : valid_size * 1.0 / total_size; + recalculateCapacity(); +} + +void BlobStats::BlobStat::recalculateCapacity() +{ + sm_max_caps = smap->updateAccurateMaxCapacity(); +} + +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.h b/dbms/src/Storages/Page/V3/Blob/BlobStat.h new file mode 100644 index 00000000000..531eb2441f9 --- /dev/null +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.h @@ -0,0 +1,201 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DB::PS::V3 +{ + +class BlobStats +{ +public: + enum BlobStatType + { + NORMAL = 1, + + // Read Only. + // Only after heavy GC, BlobFile will change to READ_ONLY type. + // After GC remove, empty files will be removed. + READ_ONLY = 2 + }; + + static String blobTypeToString(BlobStatType type) + { + switch (type) + { + case BlobStatType::NORMAL: + return "normal"; + case BlobStatType::READ_ONLY: + return "read only"; + } + return "Invalid"; + } + + struct BlobStat + { + const BlobFileId id; + std::atomic type; + + std::mutex sm_lock; + const SpaceMapPtr smap; + + // The max capacity hint of all available slots in SpaceMap + // A hint means that it is not an absolutely accurate value after inserting data, + // but is useful for quickly choosing BlobFile. + // Should call `recalculateCapacity` to get an accurate value after removing data. + UInt64 sm_max_caps = 0; + // The current file size of the BlobFile + UInt64 sm_total_size = 0; + // The sum of the size of all valid data in the BlobFile + UInt64 sm_valid_size = 0; + // sm_valid_size / sm_total_size + double sm_valid_rate = 0.0; + + public: + BlobStat(BlobFileId id_, SpaceMap::SpaceMapType sm_type, UInt64 sm_max_caps_, BlobStatType type_) + : id(id_) + , type(type_) + , smap(SpaceMap::createSpaceMap(sm_type, 0, sm_max_caps_)) + , sm_max_caps(sm_max_caps_) + {} + + [[nodiscard]] std::lock_guard lock() + { + return std::lock_guard(sm_lock); + } + + bool isNormal() const + { + return type.load() == BlobStatType::NORMAL; + } + + bool isReadOnly() const + { + return type.load() == BlobStatType::READ_ONLY; + } + + void changeToReadOnly() + { + type.store(BlobStatType::READ_ONLY); + } + + BlobFileOffset getPosFromStat(size_t buf_size, const std::lock_guard &); + + /** + * The return value is the valid data size remained in the BlobFile after the remove + */ + size_t removePosFromStat(BlobFileOffset offset, size_t buf_size, const std::lock_guard &); + + /** + * This method is only used when blobstore restore + * Restore space map won't change the `sm_total_size`/`sm_valid_size`/`sm_valid_rate` + */ + void restoreSpaceMap(BlobFileOffset offset, size_t buf_size); + + /** + * After we restore the space map. + * We still need to recalculate a `sm_total_size`/`sm_valid_size`/`sm_valid_rate`. + */ + void recalculateSpaceMap(); + + /** + * The `sm_max_cap` is not accurate after GC removes out-of-date data, or after restoring from disk. + * Caller should call this function to update the `sm_max_cap` so that we can reuse the space in this BlobStat. + */ + void recalculateCapacity(); + }; + + using BlobStatPtr = std::shared_ptr; + +public: + BlobStats(LoggerPtr log_, PSDiskDelegatorPtr delegator_, BlobConfig & config); + + // Don't require a lock from BlobStats When you already hold a BlobStat lock + // + // Safe options: + // 1. Hold a BlobStats lock, then Hold a/many BlobStat lock(s). + // 2. Without hold a BlobStats lock, But hold a/many BlobStat lock(s). + // 3. Hold a BlobStats lock, without hold a/many BlobStat lock(s). + // + // Not safe options: + // 1. then Hold a/many BlobStat lock(s), then a BlobStats lock. + // + [[nodiscard]] std::lock_guard lock() const; + + BlobStatPtr createStatNotChecking(BlobFileId blob_file_id, UInt64 max_caps, const std::lock_guard &); + + BlobStatPtr createStat(BlobFileId blob_file_id, UInt64 max_caps, const std::lock_guard & guard); + + void eraseStat(const BlobStatPtr && stat, const std::lock_guard &); + + void eraseStat(BlobFileId blob_file_id, const std::lock_guard &); + + /** + * Choose a available `BlobStat` from `BlobStats`. + * + * If we can't find any usable span to fit `buf_size` in the existed stats. + * Then it will return null `BlobStat` with a available `BlobFileId`. + * eq. {nullptr,`BlobFileId`}. + * The `BlobFileId` can use to create a new `BlobFile`. + * + * If we do find a usable span to fit `buf_size`. + * Then it will return a available `BlobStatPtr` with a `INVALID_BLOBFILE_ID`. + * eq. {`BlobStatPtr`,INVALID_BLOBFILE_ID}. + * The `INVALID_BLOBFILE_ID` means that you don't need create a new `BlobFile`. + * + */ + std::pair chooseStat(size_t buf_size, const std::lock_guard &); + + BlobStatPtr blobIdToStat(BlobFileId file_id, bool ignore_not_exist = false); + + using StatsMap = std::map>; + StatsMap getStats() const + { + auto guard = lock(); + return stats_map; + } + + static std::pair getBlobIdFromName(String blob_name); + +#ifndef DBMS_PUBLIC_GTEST +private: +#endif + void restoreByEntry(const PageEntryV3 & entry); + void restore(); + friend class PageDirectoryFactory; + +#ifndef DBMS_PUBLIC_GTEST +private: +#endif + LoggerPtr log; + PSDiskDelegatorPtr delegator; + BlobConfig & config; + + mutable std::mutex lock_stats; + BlobFileId roll_id = 1; + // Index for selecting next path for creating new blobfile + UInt32 stats_map_path_index = 0; + std::map> stats_map; +}; + +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/BlobStore.cpp b/dbms/src/Storages/Page/V3/BlobStore.cpp index 493a61a22a4..f565e3dd930 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.cpp +++ b/dbms/src/Storages/Page/V3/BlobStore.cpp @@ -29,8 +29,6 @@ #include #include -#include -#include #include #include #include @@ -60,15 +58,14 @@ namespace PS::V3 { static constexpr bool BLOBSTORE_CHECKSUM_ON_READ = true; -using BlobStat = BlobStore::BlobStats::BlobStat; -using BlobStatPtr = BlobStore::BlobStats::BlobStatPtr; +using BlobStatPtr = BlobStats::BlobStatPtr; using ChecksumClass = Digest::CRC64; /********************** * BlobStore methods * *********************/ -BlobStore::BlobStore(String storage_name, const FileProviderPtr & file_provider_, PSDiskDelegatorPtr delegator_, const BlobStore::Config & config_) +BlobStore::BlobStore(String storage_name, const FileProviderPtr & file_provider_, PSDiskDelegatorPtr delegator_, const BlobConfig & config_) : delegator(std::move(delegator_)) , file_provider(file_provider_) , config(config_) @@ -112,7 +109,7 @@ void BlobStore::registerPaths() } } -void BlobStore::reloadConfig(const BlobStore::Config & rhs) +void BlobStore::reloadConfig(const BlobConfig & rhs) { // Currently, we don't add any config for `file_limit_size`, so it won't reload at run time. // And if we support it in the future(although it seems there is no need to do that), @@ -1219,340 +1216,5 @@ BlobFilePtr BlobStore::getBlobFile(BlobFileId blob_id) .first; } -/********************** - * BlobStats methods * - *********************/ - -BlobStore::BlobStats::BlobStats(LoggerPtr log_, PSDiskDelegatorPtr delegator_, BlobStore::Config & config_) - : log(std::move(log_)) - , delegator(delegator_) - , config(config_) -{ -} - -void BlobStore::BlobStats::restoreByEntry(const PageEntryV3 & entry) -{ - auto stat = blobIdToStat(entry.file_id); - stat->restoreSpaceMap(entry.offset, entry.getTotalSize()); -} - -std::pair BlobStore::BlobStats::getBlobIdFromName(String blob_name) -{ - String err_msg; - if (!startsWith(blob_name, BlobFile::BLOB_PREFIX_NAME)) - { - return {INVALID_BLOBFILE_ID, err_msg}; - } - - Strings ss; - boost::split(ss, blob_name, boost::is_any_of("_")); - - if (ss.size() != 2) - { - return {INVALID_BLOBFILE_ID, err_msg}; - } - - try - { - const auto & blob_id = std::stoull(ss[1]); - return {blob_id, err_msg}; - } - catch (std::invalid_argument & e) - { - err_msg = e.what(); - } - catch (std::out_of_range & e) - { - err_msg = e.what(); - } - return {INVALID_BLOBFILE_ID, err_msg}; -} - -void BlobStore::BlobStats::restore() -{ - BlobFileId max_restored_file_id = 0; - - for (auto & [path, stats] : stats_map) - { - (void)path; - for (const auto & stat : stats) - { - stat->recalculateSpaceMap(); - max_restored_file_id = std::max(stat->id, max_restored_file_id); - } - } - - // restore `roll_id` - roll_id = max_restored_file_id + 1; -} - -std::lock_guard BlobStore::BlobStats::lock() const -{ - return std::lock_guard(lock_stats); -} - -BlobStatPtr BlobStore::BlobStats::createStat(BlobFileId blob_file_id, UInt64 max_caps, const std::lock_guard & guard) -{ - // New blob file id won't bigger than roll_id - if (blob_file_id > roll_id) - { - throw Exception(fmt::format("BlobStats won't create [blob_id={}], which is bigger than [roll_id={}]", - blob_file_id, - roll_id), - ErrorCodes::LOGICAL_ERROR); - } - - for (auto & [path, stats] : stats_map) - { - (void)path; - for (const auto & stat : stats) - { - if (stat->id == blob_file_id) - { - throw Exception(fmt::format("BlobStats can not create [blob_id={}] which is exist", - blob_file_id), - ErrorCodes::LOGICAL_ERROR); - } - } - } - - // Create a stat without checking the file_id exist or not - auto stat = createStatNotChecking(blob_file_id, max_caps, guard); - - // Roll to the next new blob id - if (blob_file_id == roll_id) - { - roll_id++; - } - - return stat; -} - -BlobStatPtr BlobStore::BlobStats::createStatNotChecking(BlobFileId blob_file_id, UInt64 max_caps, const std::lock_guard &) -{ - LOG_FMT_INFO(log, "Created a new BlobStat [blob_id={}] [capacity={}]", blob_file_id, max_caps); - // Only BlobFile which total capacity is smaller or equal to config.file_limit_size can be reused for another write - auto stat_type = max_caps <= config.file_limit_size ? BlobStats::BlobStatType::NORMAL : BlobStats::BlobStatType::READ_ONLY; - BlobStatPtr stat = std::make_shared( - blob_file_id, - static_cast(config.spacemap_type.get()), - max_caps, - stat_type); - - PageFileIdAndLevel id_lvl{blob_file_id, 0}; - auto path = delegator->choosePath(id_lvl); - /// This function may be called when restoring an old BlobFile at restart or creating a new BlobFile. - /// If restoring an old BlobFile, the BlobFile path maybe already added to delegator, but an another call to `addPageFileUsedSize` should do no harm. - /// If creating a new BlobFile, we need to register the BlobFile's path to delegator, so it's necessary to call `addPageFileUsedSize` here. - delegator->addPageFileUsedSize({blob_file_id, 0}, 0, path, true); - stats_map[path].emplace_back(stat); - return stat; -} - -void BlobStore::BlobStats::eraseStat(const BlobStatPtr && stat, const std::lock_guard &) -{ - PageFileIdAndLevel id_lvl{stat->id, 0}; - stats_map[delegator->getPageFilePath(id_lvl)].remove(stat); -} - -void BlobStore::BlobStats::eraseStat(BlobFileId blob_file_id, const std::lock_guard & lock) -{ - BlobStatPtr stat = nullptr; - - for (auto & [path, stats] : stats_map) - { - (void)path; - for (const auto & stat_in_map : stats) - { - if (stat_in_map->id == blob_file_id) - { - stat = stat_in_map; - break; - } - } - } - - if (stat == nullptr) - { - LOG_FMT_ERROR(log, "BlobStat not exist [blob_id={}]", blob_file_id); - return; - } - - LOG_FMT_DEBUG(log, "Erase BlobStat from maps [blob_id={}]", blob_file_id); - - eraseStat(std::move(stat), lock); -} - -std::pair BlobStore::BlobStats::chooseStat(size_t buf_size, const std::lock_guard &) -{ - BlobStatPtr stat_ptr = nullptr; - double smallest_valid_rate = 2; - - // No stats exist - if (stats_map.empty()) - { - return std::make_pair(nullptr, roll_id); - } - - // If the stats_map size changes, or stats_map_path_index is out of range, - // then make stats_map_path_index fit to current size. - stats_map_path_index %= stats_map.size(); - - auto stats_iter = stats_map.begin(); - std::advance(stats_iter, stats_map_path_index); - - size_t path_iter_idx = 0; - for (path_iter_idx = 0; path_iter_idx < stats_map.size(); ++path_iter_idx) - { - // Try to find a suitable stat under current path (path=`stats_iter->first`) - for (const auto & stat : stats_iter->second) - { - auto lock = stat->lock(); // TODO: will it bring performance regression? - if (stat->isNormal() - && stat->sm_max_caps >= buf_size - && stat->sm_valid_rate < smallest_valid_rate) - { - smallest_valid_rate = stat->sm_valid_rate; - stat_ptr = stat; - } - } - - // Already find the available stat under current path. - if (stat_ptr != nullptr) - { - break; - } - - // Try to find stat in the next path. - stats_iter++; - if (stats_iter == stats_map.end()) - { - stats_iter = stats_map.begin(); - } - } - - // advance the `stats_map_path_idx` without size checking - stats_map_path_index += path_iter_idx + 1; - - // Can not find a suitable stat under all paths - if (stat_ptr == nullptr) - { - return std::make_pair(nullptr, roll_id); - } - - return std::make_pair(stat_ptr, INVALID_BLOBFILE_ID); -} - -BlobStatPtr BlobStore::BlobStats::blobIdToStat(BlobFileId file_id, bool ignore_not_exist) -{ - auto guard = lock(); - for (const auto & [path, stats] : stats_map) - { - (void)path; - for (const auto & stat : stats) - { - if (stat->id == file_id) - { - return stat; - } - } - } - - if (!ignore_not_exist) - { - throw Exception(fmt::format("Can't find BlobStat with [blob_id={}]", - file_id), - ErrorCodes::LOGICAL_ERROR); - } - - return nullptr; -} - -/********************* - * BlobStat methods * - ********************/ - -BlobFileOffset BlobStore::BlobStats::BlobStat::getPosFromStat(size_t buf_size, const std::lock_guard &) -{ - BlobFileOffset offset = 0; - UInt64 max_cap = 0; - bool expansion = true; - - std::tie(offset, max_cap, expansion) = smap->searchInsertOffset(buf_size); - ProfileEvents::increment(expansion ? ProfileEvents::PSV3MBlobExpansion : ProfileEvents::PSV3MBlobReused); - - /** - * Whatever `searchInsertOffset` success or failed, - * Max capability still need update. - */ - sm_max_caps = max_cap; - if (offset != INVALID_BLOBFILE_OFFSET) - { - if (offset + buf_size > sm_total_size) - { - // This file must be expanded - auto expand_size = buf_size - (sm_total_size - offset); - sm_total_size += expand_size; - sm_valid_size += buf_size; - } - else - { - /** - * The `offset` reuses the original address. - * Current blob file is not expanded. - * Only update valid size. - */ - sm_valid_size += buf_size; - } - - sm_valid_rate = sm_valid_size * 1.0 / sm_total_size; - } - return offset; -} - -size_t BlobStore::BlobStats::BlobStat::removePosFromStat(BlobFileOffset offset, size_t buf_size, const std::lock_guard &) -{ - if (!smap->markFree(offset, buf_size)) - { - smap->logDebugString(); - throw Exception(fmt::format("Remove position from BlobStat failed, invalid position [offset={}] [buf_size={}] [blob_id={}]", - offset, - buf_size, - id), - ErrorCodes::LOGICAL_ERROR); - } - - sm_valid_size -= buf_size; - sm_valid_rate = sm_valid_size * 1.0 / sm_total_size; - return sm_valid_size; -} - -void BlobStore::BlobStats::BlobStat::restoreSpaceMap(BlobFileOffset offset, size_t buf_size) -{ - if (!smap->markUsed(offset, buf_size)) - { - smap->logDebugString(); - throw Exception(fmt::format("Restore position from BlobStat failed, the space/subspace is already being used [offset={}] [buf_size={}] [blob_id={}]", - offset, - buf_size, - id), - ErrorCodes::LOGICAL_ERROR); - } -} - -void BlobStore::BlobStats::BlobStat::recalculateSpaceMap() -{ - const auto & [total_size, valid_size] = smap->getSizes(); - sm_total_size = total_size; - sm_valid_size = valid_size; - sm_valid_rate = total_size == 0 ? 0.0 : valid_size * 1.0 / total_size; - recalculateCapacity(); -} - -void BlobStore::BlobStats::BlobStat::recalculateCapacity() -{ - sm_max_caps = smap->updateAccurateMaxCapacity(); -} - } // namespace PS::V3 } // namespace DB diff --git a/dbms/src/Storages/Page/V3/BlobStore.h b/dbms/src/Storages/Page/V3/BlobStore.h index aa273ef823c..af1ac994a3d 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.h +++ b/dbms/src/Storages/Page/V3/BlobStore.h @@ -18,7 +18,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include @@ -40,205 +42,11 @@ using PageIdAndVersionedEntries = std::vector { public: - struct Config - { - SettingUInt64 file_limit_size = BLOBFILE_LIMIT_SIZE; - SettingUInt64 spacemap_type = SpaceMap::SpaceMapType::SMAP64_STD_MAP; - SettingUInt64 cached_fd_size = BLOBSTORE_CACHED_FD_SIZE; - SettingUInt64 block_alignment_bytes = 0; - SettingDouble heavy_gc_valid_rate = 0.2; - - String toString() - { - return fmt::format("BlobStore Config Info: " - "[file_limit_size={}],[spacemap_type={}]," - "[cached_fd_size={}],[block_alignment_bytes={}]," - "[heavy_gc_valid_rate={}]", - file_limit_size, - spacemap_type, - cached_fd_size, - block_alignment_bytes, - heavy_gc_valid_rate); - } - }; - - class BlobStats - { - public: - enum BlobStatType - { - NORMAL = 1, - - // Read Only. - // Only after heavy GC, BlobFile will change to READ_ONLY type. - // After GC remove, empty files will be removed. - READ_ONLY = 2 - }; - - static String blobTypeToString(BlobStatType type) - { - switch (type) - { - case BlobStatType::NORMAL: - return "normal"; - case BlobStatType::READ_ONLY: - return "read only"; - } - return "Invalid"; - } - - struct BlobStat - { - const BlobFileId id; - std::atomic type; - - std::mutex sm_lock; - const SpaceMapPtr smap; - - // The max capacity hint of all available slots in SpaceMap - // A hint means that it is not an absolutely accurate value after inserting data, - // but is useful for quickly choosing BlobFile. - // Should call `recalculateCapacity` to get an accurate value after removing data. - UInt64 sm_max_caps = 0; - // The current file size of the BlobFile - UInt64 sm_total_size = 0; - // The sum of the size of all valid data in the BlobFile - UInt64 sm_valid_size = 0; - // sm_valid_size / sm_total_size - double sm_valid_rate = 0.0; - - public: - BlobStat(BlobFileId id_, SpaceMap::SpaceMapType sm_type, UInt64 sm_max_caps_, BlobStatType type_) - : id(id_) - , type(type_) - , smap(SpaceMap::createSpaceMap(sm_type, 0, sm_max_caps_)) - , sm_max_caps(sm_max_caps_) - {} - - [[nodiscard]] std::lock_guard lock() - { - return std::lock_guard(sm_lock); - } - - bool isNormal() const - { - return type.load() == BlobStatType::NORMAL; - } - - bool isReadOnly() const - { - return type.load() == BlobStatType::READ_ONLY; - } - - void changeToReadOnly() - { - type.store(BlobStatType::READ_ONLY); - } - - BlobFileOffset getPosFromStat(size_t buf_size, const std::lock_guard &); - - /** - * The return value is the valid data size remained in the BlobFile after the remove - */ - size_t removePosFromStat(BlobFileOffset offset, size_t buf_size, const std::lock_guard &); - - /** - * This method is only used when blobstore restore - * Restore space map won't change the `sm_total_size`/`sm_valid_size`/`sm_valid_rate` - */ - void restoreSpaceMap(BlobFileOffset offset, size_t buf_size); - - /** - * After we restore the space map. - * We still need to recalculate a `sm_total_size`/`sm_valid_size`/`sm_valid_rate`. - */ - void recalculateSpaceMap(); - - /** - * The `sm_max_cap` is not accurate after GC removes out-of-date data, or after restoring from disk. - * Caller should call this function to update the `sm_max_cap` so that we can reuse the space in this BlobStat. - */ - void recalculateCapacity(); - }; - - using BlobStatPtr = std::shared_ptr; - - public: - BlobStats(LoggerPtr log_, PSDiskDelegatorPtr delegator_, BlobStore::Config & config); - - // Don't require a lock from BlobStats When you already hold a BlobStat lock - // - // Safe options: - // 1. Hold a BlobStats lock, then Hold a/many BlobStat lock(s). - // 2. Without hold a BlobStats lock, But hold a/many BlobStat lock(s). - // 3. Hold a BlobStats lock, without hold a/many BlobStat lock(s). - // - // Not safe options: - // 1. then Hold a/many BlobStat lock(s), then a BlobStats lock. - // - [[nodiscard]] std::lock_guard lock() const; - - BlobStatPtr createStatNotChecking(BlobFileId blob_file_id, UInt64 max_caps, const std::lock_guard &); - - BlobStatPtr createStat(BlobFileId blob_file_id, UInt64 max_caps, const std::lock_guard & guard); - - void eraseStat(const BlobStatPtr && stat, const std::lock_guard &); - - void eraseStat(BlobFileId blob_file_id, const std::lock_guard &); - - /** - * Choose a available `BlobStat` from `BlobStats`. - * - * If we can't find any usable span to fit `buf_size` in the existed stats. - * Then it will return null `BlobStat` with a available `BlobFileId`. - * eq. {nullptr,`BlobFileId`}. - * The `BlobFileId` can use to create a new `BlobFile`. - * - * If we do find a usable span to fit `buf_size`. - * Then it will return a available `BlobStatPtr` with a `INVALID_BLOBFILE_ID`. - * eq. {`BlobStatPtr`,INVALID_BLOBFILE_ID}. - * The `INVALID_BLOBFILE_ID` means that you don't need create a new `BlobFile`. - * - */ - std::pair chooseStat(size_t buf_size, const std::lock_guard &); - - BlobStatPtr blobIdToStat(BlobFileId file_id, bool ignore_not_exist = false); - - using StatsMap = std::map>; - StatsMap getStats() const - { - auto guard = lock(); - return stats_map; - } - - static std::pair getBlobIdFromName(String blob_name); - -#ifndef DBMS_PUBLIC_GTEST - private: -#endif - void restoreByEntry(const PageEntryV3 & entry); - void restore(); - friend class PageDirectoryFactory; - -#ifndef DBMS_PUBLIC_GTEST - private: -#endif - LoggerPtr log; - PSDiskDelegatorPtr delegator; - BlobStore::Config & config; - - mutable std::mutex lock_stats; - BlobFileId roll_id = 1; - // Index for selecting next path for creating new blobfile - UInt32 stats_map_path_index = 0; - std::map> stats_map; - }; - - BlobStore(String storage_name, const FileProviderPtr & file_provider_, PSDiskDelegatorPtr delegator_, const BlobStore::Config & config); + BlobStore(String storage_name, const FileProviderPtr & file_provider_, PSDiskDelegatorPtr delegator_, const BlobConfig & config); void registerPaths(); - void reloadConfig(const BlobStore::Config & rhs); + void reloadConfig(const BlobConfig & rhs); FileUsageStatistics getFileUsageStatistics() const; @@ -309,7 +117,7 @@ class BlobStore : private Allocator PSDiskDelegatorPtr delegator; FileProviderPtr file_provider; - Config config; + BlobConfig config; LoggerPtr log; diff --git a/dbms/src/Storages/Page/V3/PageDirectory.cpp b/dbms/src/Storages/Page/V3/PageDirectory.cpp index 9cb7230cec9..e95016e8eca 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectory.cpp @@ -791,7 +791,7 @@ SnapshotsStatistics PageDirectory::getSnapshotsStat() const return stat; } -PageIDAndEntryV3 PageDirectory::get(PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const +PageIDAndEntryV3 PageDirectory::getByIDImpl(PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const { PageEntryV3 entry_got; @@ -882,7 +882,7 @@ PageIDAndEntryV3 PageDirectory::get(PageIdV3Internal page_id, const PageDirector } } -std::pair PageDirectory::get(const PageIdV3Internals & page_ids, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const +std::pair PageDirectory::getByIDsImpl(const PageIdV3Internals & page_ids, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const { PageEntryV3 entry_got; PageIds page_not_found = {}; @@ -955,8 +955,9 @@ std::pair PageDirectory::get(const PageIdV3Internal return std::make_pair(id_entries, page_not_found); } -PageIdV3Internal PageDirectory::getNormalPageId(PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const +PageIdV3Internal PageDirectory::getNormalPageId(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap_, bool throw_on_not_exist) const { + auto snap = toConcreteSnapshot(snap_); PageIdV3Internal id_to_resolve = page_id; PageVersion ver_to_resolve(snap->sequence, 0); bool keep_resolve = true; @@ -1144,7 +1145,11 @@ void PageDirectory::apply(PageEntriesEdit && edit, const WriteLimiterPtr & write PageVersion new_version(last_sequence + 1, 0); // stage 1, persisted the changes to WAL with version [seq=last_seq + 1, epoch=0] - wal->apply(edit, new_version, write_limiter); + for (auto & r : edit.getMutRecords()) + { + r.version = new_version; + } + wal->apply(ser::serializeTo(edit), write_limiter); // stage 2, create entry version list for page_id. for (const auto & r : edit.getRecords()) @@ -1211,7 +1216,7 @@ void PageDirectory::gcApply(PageEntriesEdit && migrated_edit, const WriteLimiter } // Apply migrate edit into WAL with the increased epoch version - wal->apply(migrated_edit, write_limiter); + wal->apply(ser::serializeTo(migrated_edit), write_limiter); // Apply migrate edit to the mvcc map for (const auto & record : migrated_edit.getRecords()) @@ -1313,7 +1318,7 @@ bool PageDirectory::tryDumpSnapshot(const ReadLimiterPtr & read_limiter, const W /* for_dump_snapshot */ true); // The records persisted in `files_snap` is older than or equal to all records in `edit` auto edit_from_disk = collapsed_dir->dumpSnapshotToEdit(); - done_any_io = wal->saveSnapshot(std::move(files_snap), std::move(edit_from_disk), write_limiter); + done_any_io = wal->saveSnapshot(std::move(files_snap), ser::serializeTo(edit_from_disk), edit_from_disk.size(), write_limiter); } return done_any_io; } diff --git a/dbms/src/Storages/Page/V3/PageDirectory.h b/dbms/src/Storages/Page/V3/PageDirectory.h index 947d95926b8..669b6feb24e 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.h +++ b/dbms/src/Storages/Page/V3/PageDirectory.h @@ -285,51 +285,25 @@ class PageDirectory SnapshotsStatistics getSnapshotsStat() const; - PageIDAndEntryV3 get(PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist = true) const; - PageIDAndEntryV3 get(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap) const + PageIDAndEntryV3 getByID(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap) const { - return get(page_id, toConcreteSnapshot(snap), /*throw_on_not_exist=*/true); + return getByIDImpl(page_id, toConcreteSnapshot(snap), /*throw_on_not_exist=*/true); } - PageIDAndEntryV3 getOrNull(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap) const + PageIDAndEntryV3 getByIDOrNull(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap) const { - return get(page_id, toConcreteSnapshot(snap), /*throw_on_not_exist=*/false); + return getByIDImpl(page_id, toConcreteSnapshot(snap), /*throw_on_not_exist=*/false); } - std::pair get(const PageIdV3Internals & page_ids, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist = true) const; - PageIDAndEntriesV3 get(const PageIdV3Internals & page_ids, const DB::PageStorageSnapshotPtr & snap) const + PageIDAndEntriesV3 getByIDs(const PageIdV3Internals & page_ids, const DB::PageStorageSnapshotPtr & snap) const { - return std::get<0>(get(page_ids, toConcreteSnapshot(snap), /*throw_on_not_exist=*/true)); + return std::get<0>(getByIDsImpl(page_ids, toConcreteSnapshot(snap), /*throw_on_not_exist=*/true)); } - std::pair getOrNull(PageIdV3Internals page_ids, const DB::PageStorageSnapshotPtr & snap) const + std::pair getByIDsOrNull(PageIdV3Internals page_ids, const DB::PageStorageSnapshotPtr & snap) const { - return get(page_ids, toConcreteSnapshot(snap), /*throw_on_not_exist=*/false); + return getByIDsImpl(page_ids, toConcreteSnapshot(snap), /*throw_on_not_exist=*/false); } - PageIdV3Internal getNormalPageId(PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const; - PageIdV3Internal getNormalPageId(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap, bool throw_on_not_exist) const - { - return getNormalPageId(page_id, toConcreteSnapshot(snap), throw_on_not_exist); - } - -#ifndef NDEBUG - // Just for tests, refactor them out later - PageIDAndEntryV3 get(PageId page_id, const PageDirectorySnapshotPtr & snap) const - { - return get(buildV3Id(TEST_NAMESPACE_ID, page_id), snap); - } - PageIDAndEntryV3 get(PageId page_id, const DB::PageStorageSnapshotPtr & snap) const - { - return get(buildV3Id(TEST_NAMESPACE_ID, page_id), toConcreteSnapshot(snap)); - } - PageIdV3Internal getNormalPageId(PageId page_id, const PageDirectorySnapshotPtr & snap) const - { - return getNormalPageId(buildV3Id(TEST_NAMESPACE_ID, page_id), snap, /*throw_on_not_exist*/ true); - } - PageIdV3Internal getNormalPageId(PageId page_id, const DB::PageStorageSnapshotPtr & snap) const - { - return getNormalPageId(buildV3Id(TEST_NAMESPACE_ID, page_id), toConcreteSnapshot(snap), /*throw_on_not_exist*/ true); - } -#endif + PageIdV3Internal getNormalPageId(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap_, bool throw_on_not_exist) const; PageId getMaxId() const; @@ -381,6 +355,11 @@ class PageDirectory friend class PageDirectoryFactory; friend class PageStorageControlV3; +private: + PageIDAndEntryV3 getByIDImpl(PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const; + std::pair + getByIDsImpl(const PageIdV3Internals & page_ids, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const; + private: // Only `std::map` is allow for `MVCCMap`. Cause `std::map::insert` ensure that // "No iterators or references are invalidated" diff --git a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp index 9f607c9509d..d3d99c93891 100644 --- a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp @@ -29,7 +29,7 @@ extern const int PS_DIR_APPLY_INVALID_STATUS; } // namespace ErrorCodes namespace PS::V3 { -PageDirectoryPtr PageDirectoryFactory::create(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, WALStore::Config config) +PageDirectoryPtr PageDirectoryFactory::create(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, WALConfig config) { auto [wal, reader] = WALStore::create(storage_name, file_provider, delegator, config); return createFromReader(storage_name, reader, std::move(wal)); @@ -77,7 +77,7 @@ PageDirectoryPtr PageDirectoryFactory::createFromReader(String storage_name, WAL PageDirectoryPtr PageDirectoryFactory::createFromEdit(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, const PageEntriesEdit & edit) { - auto [wal, reader] = WALStore::create(storage_name, file_provider, delegator, WALStore::Config()); + auto [wal, reader] = WALStore::create(storage_name, file_provider, delegator, WALConfig()); (void)reader; PageDirectoryPtr dir = std::make_unique(std::move(storage_name), std::move(wal)); loadEdit(dir, edit); diff --git a/dbms/src/Storages/Page/V3/PageDirectoryFactory.h b/dbms/src/Storages/Page/V3/PageDirectoryFactory.h index 97a9d0da8d6..20512893013 100644 --- a/dbms/src/Storages/Page/V3/PageDirectoryFactory.h +++ b/dbms/src/Storages/Page/V3/PageDirectoryFactory.h @@ -15,6 +15,7 @@ #pragma once #include +#include #include #include #include @@ -46,7 +47,7 @@ class PageDirectoryFactory return *this; } - PageDirectoryPtr create(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, WALStore::Config config); + PageDirectoryPtr create(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, WALConfig config); PageDirectoryPtr createFromReader(String storage_name, WALStoreReaderPtr reader, WALStorePtr wal, bool for_dump_snapshot = false); @@ -54,7 +55,7 @@ class PageDirectoryFactory PageDirectoryPtr createFromEdit(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, const PageEntriesEdit & edit); // just for test - PageDirectoryFactory & setBlobStats(BlobStore::BlobStats & blob_stats_) + PageDirectoryFactory & setBlobStats(BlobStats & blob_stats_) { blob_stats = &blob_stats_; return *this; @@ -67,7 +68,7 @@ class PageDirectoryFactory const PageDirectoryPtr & dir, const PageEntriesEdit::EditRecord & r); - BlobStore::BlobStats * blob_stats = nullptr; + BlobStats * blob_stats = nullptr; }; } // namespace PS::V3 diff --git a/dbms/src/Storages/Page/V3/PageEntry.h b/dbms/src/Storages/Page/V3/PageEntry.h index 56411f87faf..c26f7399bdd 100644 --- a/dbms/src/Storages/Page/V3/PageEntry.h +++ b/dbms/src/Storages/Page/V3/PageEntry.h @@ -37,7 +37,7 @@ struct PageEntryV3 BlobFileOffset offset = 0; // The offset of page data in file UInt64 checksum = 0; // The checksum of whole page data - // The offset to the begining of specify field. + // The offset to the beginning of specify field. PageFieldOffsetChecksums field_offsets{}; public: diff --git a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp index 67611dc980b..eb60ffa5112 100644 --- a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp +++ b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp @@ -131,7 +131,7 @@ DB::PageEntry PageStorageImpl::getEntryImpl(NamespaceId ns_id, PageId page_id, S try { - const auto & [id, entry] = page_directory->getOrNull(buildV3Id(ns_id, page_id), snapshot); + const auto & [id, entry] = page_directory->getByIDOrNull(buildV3Id(ns_id, page_id), snapshot); (void)id; // TODO : after `PageEntry` in page.h been moved to v2. // Then we don't copy from V3 to V2 format @@ -159,7 +159,7 @@ DB::Page PageStorageImpl::readImpl(NamespaceId ns_id, PageId page_id, const Read snapshot = this->getSnapshot(""); } - auto page_entry = throw_on_not_exist ? page_directory->get(buildV3Id(ns_id, page_id), snapshot) : page_directory->getOrNull(buildV3Id(ns_id, page_id), snapshot); + auto page_entry = throw_on_not_exist ? page_directory->getByID(buildV3Id(ns_id, page_id), snapshot) : page_directory->getByIDOrNull(buildV3Id(ns_id, page_id), snapshot); return blob_store.read(page_entry, read_limiter); } @@ -178,12 +178,12 @@ PageMap PageStorageImpl::readImpl(NamespaceId ns_id, const PageIds & page_ids, c if (throw_on_not_exist) { - auto page_entries = page_directory->get(page_id_v3s, snapshot); + auto page_entries = page_directory->getByIDs(page_id_v3s, snapshot); return blob_store.read(page_entries, read_limiter); } else { - auto [page_entries, page_ids_not_found] = page_directory->getOrNull(page_id_v3s, snapshot); + auto [page_entries, page_ids_not_found] = page_directory->getByIDsOrNull(page_id_v3s, snapshot); PageMap page_map = blob_store.read(page_entries, read_limiter); for (const auto & page_id_not_found : page_ids_not_found) @@ -209,13 +209,13 @@ PageIds PageStorageImpl::readImpl(NamespaceId ns_id, const PageIds & page_ids, c if (throw_on_not_exist) { - auto page_entries = page_directory->get(page_id_v3s, snapshot); + auto page_entries = page_directory->getByIDs(page_id_v3s, snapshot); blob_store.read(page_entries, handler, read_limiter); return {}; } else { - auto [page_entries, page_ids_not_found] = page_directory->getOrNull(page_id_v3s, snapshot); + auto [page_entries, page_ids_not_found] = page_directory->getByIDsOrNull(page_id_v3s, snapshot); blob_store.read(page_entries, handler, read_limiter); return page_ids_not_found; } @@ -232,7 +232,7 @@ PageMap PageStorageImpl::readImpl(NamespaceId ns_id, const std::vectorget(buildV3Id(ns_id, page_id), snapshot) : page_directory->getOrNull(buildV3Id(ns_id, page_id), snapshot); + const auto & [id, entry] = throw_on_not_exist ? page_directory->getByID(buildV3Id(ns_id, page_id), snapshot) : page_directory->getByIDOrNull(buildV3Id(ns_id, page_id), snapshot); if (entry.isValid()) { @@ -271,7 +271,7 @@ void PageStorageImpl::traverseImpl(const std::functiongetAllPageIds(); for (const auto & valid_page : page_ids) { - const auto & page_id_and_entry = page_directory->get(valid_page, snapshot); + const auto & page_id_and_entry = page_directory->getByID(valid_page, snapshot); acceptor(blob_store.read(page_id_and_entry)); } } diff --git a/dbms/src/Storages/Page/V3/PageStorageImpl.h b/dbms/src/Storages/Page/V3/PageStorageImpl.h index 321c9742f66..eabaff90504 100644 --- a/dbms/src/Storages/Page/V3/PageStorageImpl.h +++ b/dbms/src/Storages/Page/V3/PageStorageImpl.h @@ -38,9 +38,9 @@ class PageStorageImpl : public DB::PageStorage ~PageStorageImpl() override; - static BlobStore::Config parseBlobConfig(const Config & config) + static BlobConfig parseBlobConfig(const Config & config) { - BlobStore::Config blob_config; + BlobConfig blob_config; blob_config.file_limit_size = config.blob_file_limit_size; blob_config.cached_fd_size = config.blob_cached_fd_size; @@ -51,9 +51,9 @@ class PageStorageImpl : public DB::PageStorage return blob_config; } - static WALStore::Config parseWALConfig(const Config & config) + static WALConfig parseWALConfig(const Config & config) { - WALStore::Config wal_config; + WALConfig wal_config; wal_config.roll_size = config.wal_roll_size; wal_config.max_persisted_log_files = config.wal_max_persisted_log_files; diff --git a/dbms/src/Storages/Page/V3/WAL/WALConfig.h b/dbms/src/Storages/Page/V3/WAL/WALConfig.h new file mode 100644 index 00000000000..642f08f97e3 --- /dev/null +++ b/dbms/src/Storages/Page/V3/WAL/WALConfig.h @@ -0,0 +1,50 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +namespace DB::PS::V3 +{ +struct WALConfig +{ + SettingUInt64 roll_size = PAGE_META_ROLL_SIZE; + SettingUInt64 max_persisted_log_files = MAX_PERSISTED_LOG_FILES; + +private: + SettingUInt64 wal_recover_mode = 0; + +public: + void setRecoverMode(UInt64 recover_mode) + { + RUNTIME_CHECK_MSG(recover_mode == static_cast(WALRecoveryMode::TolerateCorruptedTailRecords) + || recover_mode == static_cast(WALRecoveryMode::AbsoluteConsistency) + || recover_mode == static_cast(WALRecoveryMode::PointInTimeRecovery) + || recover_mode == static_cast(WALRecoveryMode::SkipAnyCorruptedRecords), + "Unknow recover mode [num={}]", + recover_mode); + wal_recover_mode = recover_mode; + } + + WALRecoveryMode getRecoverMode() + { + return static_cast(wal_recover_mode.get()); + } +}; + +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/WALStore.cpp b/dbms/src/Storages/Page/V3/WALStore.cpp index 8afc52c6dca..3d006f1931b 100644 --- a/dbms/src/Storages/Page/V3/WALStore.cpp +++ b/dbms/src/Storages/Page/V3/WALStore.cpp @@ -42,7 +42,7 @@ std::pair WALStore::create( String storage_name, FileProviderPtr & provider, PSDiskDelegatorPtr & delegator, - WALStore::Config config) + WALConfig config) { auto reader = WALStoreReader::create(storage_name, provider, @@ -65,7 +65,7 @@ WALStore::WALStore( const PSDiskDelegatorPtr & delegator_, const FileProviderPtr & provider_, Format::LogNumberType last_log_num_, - WALStore::Config config_) + WALConfig config_) : storage_name(std::move(storage_name_)) , delegator(delegator_) , provider(provider_) @@ -76,19 +76,9 @@ WALStore::WALStore( { } -void WALStore::apply(PageEntriesEdit & edit, const PageVersion & version, const WriteLimiterPtr & write_limiter) +void WALStore::apply(String && serialized_edit, const WriteLimiterPtr & write_limiter) { - for (auto & r : edit.getMutRecords()) - { - r.version = version; - } - apply(edit, write_limiter); -} - -void WALStore::apply(const PageEntriesEdit & edit, const WriteLimiterPtr & write_limiter) -{ - const String serialized = ser::serializeTo(edit); - ReadBufferFromString payload(serialized); + ReadBufferFromString payload(serialized_edit); { std::lock_guard lock(log_file_mutex); @@ -102,7 +92,7 @@ void WALStore::apply(const PageEntriesEdit & edit, const WriteLimiterPtr & write log_file.swap(new_log_file); } - log_file->addRecord(payload, serialized.size(), write_limiter); + log_file->addRecord(payload, serialized_edit.size(), write_limiter); } } @@ -152,7 +142,7 @@ std::tuple, LogFilename> WALStore::createLogWriter( WALStore::FilesSnapshot WALStore::getFilesSnapshot() const { - const auto [ok, current_writting_log_num] = [this]() -> std::tuple { + const auto [ok, current_writing_log_num] = [this]() -> std::tuple { std::lock_guard lock(log_file_mutex); if (!log_file) { @@ -164,7 +154,7 @@ WALStore::FilesSnapshot WALStore::getFilesSnapshot() const if (!ok) { return WALStore::FilesSnapshot{ - .current_writting_log_num = 0, + .current_writing_log_num = 0, .persisted_log_files = {}, }; } @@ -173,20 +163,24 @@ WALStore::FilesSnapshot WALStore::getFilesSnapshot() const LogFilenameSet persisted_log_files = WALStoreReader::listAllFiles(delegator, logger); for (auto iter = persisted_log_files.begin(); iter != persisted_log_files.end(); /*empty*/) { - if (iter->log_num >= current_writting_log_num) + if (iter->log_num >= current_writing_log_num) iter = persisted_log_files.erase(iter); else ++iter; } return WALStore::FilesSnapshot{ - .current_writting_log_num = current_writting_log_num, + .current_writing_log_num = current_writing_log_num, .persisted_log_files = std::move(persisted_log_files), }; } // In order to make `restore` in a reasonable time, we need to compact // log files. -bool WALStore::saveSnapshot(FilesSnapshot && files_snap, PageEntriesEdit && directory_snap, const WriteLimiterPtr & write_limiter) +bool WALStore::saveSnapshot( + FilesSnapshot && files_snap, + String && serialized_snap, + size_t num_records, + const WriteLimiterPtr & write_limiter) { if (files_snap.persisted_log_files.empty()) return false; @@ -198,10 +192,9 @@ bool WALStore::saveSnapshot(FilesSnapshot && files_snap, PageEntriesEdit && dire // Create a temporary file for saving directory snapshot auto [compact_log, log_filename] = createLogWriter({log_num, 1}, /*manual_flush*/ true); - const String serialized = ser::serializeTo(directory_snap); - ReadBufferFromString payload(serialized); + ReadBufferFromString payload(serialized_snap); - compact_log->addRecord(payload, serialized.size(), write_limiter, /*background*/ true); + compact_log->addRecord(payload, serialized_snap.size(), write_limiter, /*background*/ true); compact_log->flush(write_limiter, /*background*/ true); compact_log.reset(); // close fd explicitly before renaming file. @@ -226,22 +219,23 @@ bool WALStore::saveSnapshot(FilesSnapshot && files_snap, PageEntriesEdit && dire provider->deleteRegularFile(log_fullname, EncryptionPath(log_fullname, "")); } - FmtBuffer fmt_buf; - fmt_buf.append("Dumped directory snapshot to log file done. [files_snapshot="); - - fmt_buf.joinStr( - files_snap.persisted_log_files.begin(), - files_snap.persisted_log_files.end(), - [](const auto & arg, FmtBuffer & fb) { - fb.fmtAppend("{}", arg.filename(arg.stage)); - }, - ", "); - fmt_buf.fmtAppend("] [num of records={}] [file={}] [size={}].", - directory_snap.size(), - normal_fullname, - serialized.size()); - - LOG_INFO(logger, fmt_buf.toString()); + auto get_logging_str = [&]() { + FmtBuffer fmt_buf; + fmt_buf.append("Dumped directory snapshot to log file done. [files_snapshot="); + fmt_buf.joinStr( + files_snap.persisted_log_files.begin(), + files_snap.persisted_log_files.end(), + [](const auto & arg, FmtBuffer & fb) { + fb.fmtAppend("{}", arg.filename(arg.stage)); + }, + ", "); + fmt_buf.fmtAppend("] [num_records={}] [file={}] [size={}].", + num_records, + normal_fullname, + serialized_snap.size()); + return fmt_buf.toString(); + }; + LOG_INFO(logger, get_logging_str()); return true; } diff --git a/dbms/src/Storages/Page/V3/WALStore.h b/dbms/src/Storages/Page/V3/WALStore.h index f1ea00d3562..91f02c67771 100644 --- a/dbms/src/Storages/Page/V3/WALStore.h +++ b/dbms/src/Storages/Page/V3/WALStore.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -36,7 +36,6 @@ using PSDiskDelegatorPtr = std::shared_ptr; namespace PS::V3 { - class WALStore; using WALStorePtr = std::unique_ptr; @@ -46,33 +45,6 @@ using WALStoreReaderPtr = std::shared_ptr; class WALStore { public: - struct Config - { - SettingUInt64 roll_size = PAGE_META_ROLL_SIZE; - SettingUInt64 max_persisted_log_files = MAX_PERSISTED_LOG_FILES; - - private: - SettingUInt64 wal_recover_mode = 0; - - public: - void setRecoverMode(UInt64 recover_mode) - { - if (unlikely(recover_mode != static_cast(WALRecoveryMode::TolerateCorruptedTailRecords) - && recover_mode != static_cast(WALRecoveryMode::AbsoluteConsistency) - && recover_mode != static_cast(WALRecoveryMode::PointInTimeRecovery) - && recover_mode != static_cast(WALRecoveryMode::SkipAnyCorruptedRecords))) - { - throw Exception("Unknow recover mode [num={}]", recover_mode); - } - wal_recover_mode = recover_mode; - } - - WALRecoveryMode getRecoverMode() - { - return static_cast(wal_recover_mode.get()); - } - }; - constexpr static const char * wal_folder_prefix = "/wal"; static std::pair @@ -80,16 +52,15 @@ class WALStore String storage_name_, FileProviderPtr & provider, PSDiskDelegatorPtr & delegator, - WALStore::Config config); + WALConfig config); WALStoreReaderPtr createReaderForFiles(const String & identifier, const LogFilenameSet & log_filenames, const ReadLimiterPtr & read_limiter); - void apply(PageEntriesEdit & edit, const PageVersion & version, const WriteLimiterPtr & write_limiter = nullptr); - void apply(const PageEntriesEdit & edit, const WriteLimiterPtr & write_limiter = nullptr); + void apply(String && serialized_edit, const WriteLimiterPtr & write_limiter = nullptr); struct FilesSnapshot { - Format::LogNumberType current_writting_log_num; + Format::LogNumberType current_writing_log_num; // The log files to generate snapshot from. Sorted by . // If the WAL log file is not inited, it is an empty set. LogFilenameSet persisted_log_files; @@ -107,7 +78,8 @@ class WALStore bool saveSnapshot( FilesSnapshot && files_snap, - PageEntriesEdit && directory_snap, + String && serialized_snap, + size_t num_records, const WriteLimiterPtr & write_limiter = nullptr); const String & name() { return storage_name; } @@ -118,7 +90,7 @@ class WALStore const PSDiskDelegatorPtr & delegator_, const FileProviderPtr & provider_, Format::LogNumberType last_log_num_, - WALStore::Config config); + WALConfig config); std::tuple, LogFilename> createLogWriter( @@ -137,7 +109,7 @@ class WALStore LoggerPtr logger; - WALStore::Config config; + WALConfig config; }; } // namespace PS::V3 diff --git a/dbms/src/Storages/Page/V3/tests/entries_helper.h b/dbms/src/Storages/Page/V3/tests/entries_helper.h index 19e42755dae..a651bfc5e04 100644 --- a/dbms/src/Storages/Page/V3/tests/entries_helper.h +++ b/dbms/src/Storages/Page/V3/tests/entries_helper.h @@ -109,7 +109,7 @@ inline ::testing::AssertionResult getEntryCompare( String error; try { - auto id_entry = dir->get(page_id, snap); + auto id_entry = dir->getByID(page_id, snap); return check_id_entry({page_id, expected_entry}, id_entry); } catch (DB::Exception & ex) @@ -186,8 +186,7 @@ inline ::testing::AssertionResult getEntriesCompare( String error; try { - auto [id_entries, page_ids_not_found] = dir->get(page_ids, snap); - (void)page_ids_not_found; + auto id_entries = dir->getByIDs(page_ids, snap); return check_id_entries(expected_entries, id_entries); } catch (DB::Exception & ex) @@ -222,7 +221,7 @@ inline ::testing::AssertionResult getEntryNotExist( String error; try { - auto id_entry = dir->getOrNull(page_id, snap); + auto id_entry = dir->getByIDOrNull(page_id, snap); if (!id_entry.second.isValid()) return ::testing::AssertionSuccess(); error = fmt::format( @@ -262,8 +261,7 @@ inline ::testing::AssertionResult getEntriesNotExist( String error; try { - auto [id_entries, page_ids_not_found] = dir->get(page_ids, snap); - (void)page_ids_not_found; + auto id_entries = dir->getByIDs(page_ids, snap); error = fmt::format( "Expect entry [id={}] from {} with snap{} not exist, but got {}", page_ids_expr, diff --git a/dbms/src/Storages/Page/V3/tests/gtest_blob_stat.cpp b/dbms/src/Storages/Page/V3/tests/gtest_blob_stat.cpp new file mode 100644 index 00000000000..22448bf923f --- /dev/null +++ b/dbms/src/Storages/Page/V3/tests/gtest_blob_stat.cpp @@ -0,0 +1,281 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +namespace DB::PS::V3::tests +{ + + +class BlobStoreStatsTest : public DB::base::TiFlashStorageTestBasic +{ +public: + static constexpr size_t path_num = 3; + +public: + BlobStoreStatsTest() + : logger(Logger::get("BlobStoreStatsTest")) + { + auto path = getTemporaryPath(); + DB::tests::TiFlashTestEnv::tryRemovePath(path); + createIfNotExist(path); + Strings paths; + for (size_t i = 0; i < path_num; i++) + { + paths.emplace_back(fmt::format("{}/{}", path, i)); + } + delegator = std::make_shared(paths); + } + +protected: + BlobConfig config; + LoggerPtr logger; + PSDiskDelegatorPtr delegator; +}; + +static size_t getTotalStatsNum(const BlobStats::StatsMap & stats_map) +{ + size_t total_stats_num = 0; + for (const auto & iter : stats_map) + { + total_stats_num += iter.second.size(); + } + return total_stats_num; +} + +TEST_F(BlobStoreStatsTest, RestoreEmpty) +{ + BlobStats stats(logger, delegator, config); + + stats.restore(); + + auto stats_copy = stats.getStats(); + ASSERT_TRUE(stats_copy.empty()); + + EXPECT_EQ(stats.roll_id, 1); + EXPECT_NO_THROW(stats.createStat(stats.roll_id, config.file_limit_size, stats.lock())); +} + +TEST_F(BlobStoreStatsTest, Restore) +try +{ + BlobStats stats(logger, delegator, config); + + BlobFileId file_id1 = 10; + BlobFileId file_id2 = 12; + + { + const auto & lock = stats.lock(); + stats.createStatNotChecking(file_id1, config.file_limit_size, lock); + stats.createStatNotChecking(file_id2, config.file_limit_size, lock); + } + + { + stats.restoreByEntry(PageEntryV3{ + .file_id = file_id1, + .size = 128, + .padded_size = 0, + .tag = 0, + .offset = 1024, + .checksum = 0x4567, + }); + stats.restoreByEntry(PageEntryV3{ + .file_id = file_id1, + .size = 512, + .padded_size = 0, + .tag = 0, + .offset = 2048, + .checksum = 0x4567, + }); + stats.restoreByEntry(PageEntryV3{ + .file_id = file_id2, + .size = 512, + .padded_size = 0, + .tag = 0, + .offset = 2048, + .checksum = 0x4567, + }); + stats.restore(); + } + + auto stats_copy = stats.getStats(); + + ASSERT_EQ(stats_copy.size(), std::min(getTotalStatsNum(stats_copy), path_num)); + ASSERT_EQ(getTotalStatsNum(stats_copy), 2); + EXPECT_EQ(stats.roll_id, 13); + + auto stat1 = stats.blobIdToStat(file_id1); + EXPECT_EQ(stat1->sm_total_size, 2048 + 512); + EXPECT_EQ(stat1->sm_valid_size, 128 + 512); + auto stat2 = stats.blobIdToStat(file_id2); + EXPECT_EQ(stat2->sm_total_size, 2048 + 512); + EXPECT_EQ(stat2->sm_valid_size, 512); + + // This will throw exception since we try to create + // a new file bigger than restored `roll_id` + EXPECT_ANY_THROW({ stats.createStat(14, config.file_limit_size, stats.lock()); }); + + EXPECT_ANY_THROW({ stats.createStat(file_id1, config.file_limit_size, stats.lock()); }); + EXPECT_ANY_THROW({ stats.createStat(file_id2, config.file_limit_size, stats.lock()); }); + EXPECT_ANY_THROW({ stats.createStat(stats.roll_id + 1, config.file_limit_size, stats.lock()); }); +} +CATCH + +TEST_F(BlobStoreStatsTest, testStats) +{ + BlobStats stats(logger, delegator, config); + + auto stat = stats.createStat(0, config.file_limit_size, stats.lock()); + + ASSERT_TRUE(stat); + ASSERT_TRUE(stat->smap); + stats.createStat(1, config.file_limit_size, stats.lock()); + stats.createStat(2, config.file_limit_size, stats.lock()); + + auto stats_copy = stats.getStats(); + + ASSERT_EQ(stats_copy.size(), std::min(getTotalStatsNum(stats_copy), path_num)); + ASSERT_EQ(getTotalStatsNum(stats_copy), 3); + ASSERT_EQ(stats.roll_id, 3); + + stats.eraseStat(0, stats.lock()); + stats.eraseStat(1, stats.lock()); + ASSERT_EQ(getTotalStatsNum(stats.getStats()), 1); + ASSERT_EQ(stats.roll_id, 3); +} + + +TEST_F(BlobStoreStatsTest, testStat) +{ + BlobFileId blob_file_id = 0; + BlobStats::BlobStatPtr stat; + + BlobStats stats(logger, delegator, config); + + std::tie(stat, blob_file_id) = stats.chooseStat(10, stats.lock()); + ASSERT_EQ(blob_file_id, 1); + ASSERT_FALSE(stat); + + // still 0 + std::tie(stat, blob_file_id) = stats.chooseStat(10, stats.lock()); + ASSERT_EQ(blob_file_id, 1); + ASSERT_FALSE(stat); + + stats.createStat(0, config.file_limit_size, stats.lock()); + std::tie(stat, blob_file_id) = stats.chooseStat(10, stats.lock()); + ASSERT_EQ(blob_file_id, INVALID_BLOBFILE_ID); + ASSERT_TRUE(stat); + + auto offset = stat->getPosFromStat(10, stats.lock()); + ASSERT_EQ(offset, 0); + + offset = stat->getPosFromStat(100, stats.lock()); + ASSERT_EQ(offset, 10); + + offset = stat->getPosFromStat(20, stats.lock()); + ASSERT_EQ(offset, 110); + + ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20); + ASSERT_EQ(stat->sm_valid_size, 10 + 100 + 20); + ASSERT_EQ(stat->sm_valid_rate, 1); + + stat->removePosFromStat(10, 100, stats.lock()); + ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20); + ASSERT_EQ(stat->sm_valid_size, 10 + 20); + ASSERT_LE(stat->sm_valid_rate, 1); + + offset = stat->getPosFromStat(110, stats.lock()); + ASSERT_EQ(offset, 130); + ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20 + 110); + ASSERT_EQ(stat->sm_valid_size, 10 + 20 + 110); + ASSERT_LE(stat->sm_valid_rate, 1); + + offset = stat->getPosFromStat(90, stats.lock()); + ASSERT_EQ(offset, 10); + ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20 + 110); + ASSERT_EQ(stat->sm_valid_size, 10 + 20 + 110 + 90); + ASSERT_LE(stat->sm_valid_rate, 1); + + // Unmark the last range + stat->removePosFromStat(130, 110, stats.lock()); + ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20 + 110); + ASSERT_EQ(stat->sm_valid_size, 10 + 20 + 90); + ASSERT_LE(stat->sm_valid_rate, 1); + + /** + * now used space looks like: + * [0,10) [10,100) [110,130) + * And total size still is 10 + 100 + 20 + 110 + * Then after we add a range which size is 120 + * Total size should plus 10, rather than 120. + * And the postion return should be last range freed. + */ + offset = stat->getPosFromStat(120, stats.lock()); + ASSERT_EQ(offset, 130); + ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20 + 110 + 10); + ASSERT_EQ(stat->sm_valid_size, 10 + 20 + 90 + 120); + ASSERT_LE(stat->sm_valid_rate, 1); +} + +TEST_F(BlobStoreStatsTest, testFullStats) +{ + BlobFileId blob_file_id = 0; + BlobStats::BlobStatPtr stat; + BlobFileOffset offset = 0; + + BlobStats stats(logger, delegator, config); + + stat = stats.createStat(1, config.file_limit_size, stats.lock()); + offset = stat->getPosFromStat(BLOBFILE_LIMIT_SIZE - 1, stats.lock()); + ASSERT_EQ(offset, 0); + + // Can't get pos from a full stat + offset = stat->getPosFromStat(100, stats.lock()); + ASSERT_EQ(offset, INVALID_BLOBFILE_OFFSET); + + // Stat internal property should not changed + ASSERT_EQ(stat->sm_total_size, BLOBFILE_LIMIT_SIZE - 1); + ASSERT_EQ(stat->sm_valid_size, BLOBFILE_LIMIT_SIZE - 1); + ASSERT_LE(stat->sm_valid_rate, 1); + + // Won't choose full one + std::tie(stat, blob_file_id) = stats.chooseStat(100, stats.lock()); + ASSERT_EQ(blob_file_id, 2); + ASSERT_FALSE(stat); + + // A new stat can use + stat = stats.createStat(blob_file_id, config.file_limit_size, stats.lock()); + offset = stat->getPosFromStat(100, stats.lock()); + ASSERT_EQ(offset, 0); + + // Remove the stat which id is 0 , now remain the stat which id is 1 + stats.eraseStat(1, stats.lock()); + + // Then full the stat which id 2 + offset = stat->getPosFromStat(BLOBFILE_LIMIT_SIZE - 100, stats.lock()); + ASSERT_EQ(offset, 100); + + // Then choose stat , it should return the stat id 3 + // Stat which id is 2 is full. + std::tie(stat, blob_file_id) = stats.chooseStat(100, stats.lock()); + ASSERT_EQ(blob_file_id, 3); + ASSERT_FALSE(stat); +} +} // namespace DB::PS::V3::tests diff --git a/dbms/src/Storages/Page/V3/tests/gtest_blob_store.cpp b/dbms/src/Storages/Page/V3/tests/gtest_blob_store.cpp index 19d183dfe6c..255a598c834 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_blob_store.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_blob_store.cpp @@ -30,263 +30,9 @@ namespace DB::PS::V3::tests { -using BlobStat = BlobStore::BlobStats::BlobStat; -using BlobStats = BlobStore::BlobStats; constexpr size_t path_num = 3; -class BlobStoreStatsTest : public DB::base::TiFlashStorageTestBasic -{ -public: - BlobStoreStatsTest() - : logger(Logger::get("BlobStoreStatsTest")) - { - auto path = getTemporaryPath(); - DB::tests::TiFlashTestEnv::tryRemovePath(path); - createIfNotExist(path); - Strings paths; - for (size_t i = 0; i < path_num; i++) - { - paths.emplace_back(fmt::format("{}/{}", path, i)); - } - delegator = std::make_shared(paths); - } - -protected: - BlobStore::Config config; - LoggerPtr logger; - PSDiskDelegatorPtr delegator; -}; - -static size_t getTotalStatsNum(const BlobStore::BlobStats::StatsMap & stats_map) -{ - size_t total_stats_num = 0; - for (auto iter = stats_map.begin(); iter != stats_map.end(); iter++) - { - total_stats_num += iter->second.size(); - } - return total_stats_num; -} - -TEST_F(BlobStoreStatsTest, RestoreEmpty) -{ - BlobStats stats(logger, delegator, config); - - stats.restore(); - - auto stats_copy = stats.getStats(); - ASSERT_TRUE(stats_copy.empty()); - - EXPECT_EQ(stats.roll_id, 1); - EXPECT_NO_THROW(stats.createStat(stats.roll_id, config.file_limit_size, stats.lock())); -} - -TEST_F(BlobStoreStatsTest, Restore) -try -{ - BlobStats stats(logger, delegator, config); - - BlobFileId file_id1 = 10; - BlobFileId file_id2 = 12; - - { - const auto & lock = stats.lock(); - stats.createStatNotChecking(file_id1, config.file_limit_size, lock); - stats.createStatNotChecking(file_id2, config.file_limit_size, lock); - } - - { - stats.restoreByEntry(PageEntryV3{ - .file_id = file_id1, - .size = 128, - .padded_size = 0, - .tag = 0, - .offset = 1024, - .checksum = 0x4567, - }); - stats.restoreByEntry(PageEntryV3{ - .file_id = file_id1, - .size = 512, - .padded_size = 0, - .tag = 0, - .offset = 2048, - .checksum = 0x4567, - }); - stats.restoreByEntry(PageEntryV3{ - .file_id = file_id2, - .size = 512, - .padded_size = 0, - .tag = 0, - .offset = 2048, - .checksum = 0x4567, - }); - stats.restore(); - } - - auto stats_copy = stats.getStats(); - - ASSERT_EQ(stats_copy.size(), std::min(getTotalStatsNum(stats_copy), path_num)); - ASSERT_EQ(getTotalStatsNum(stats_copy), 2); - EXPECT_EQ(stats.roll_id, 13); - - auto stat1 = stats.blobIdToStat(file_id1); - EXPECT_EQ(stat1->sm_total_size, 2048 + 512); - EXPECT_EQ(stat1->sm_valid_size, 128 + 512); - auto stat2 = stats.blobIdToStat(file_id2); - EXPECT_EQ(stat2->sm_total_size, 2048 + 512); - EXPECT_EQ(stat2->sm_valid_size, 512); - - // This will throw exception since we try to create - // a new file bigger than restored `roll_id` - EXPECT_ANY_THROW({ stats.createStat(14, config.file_limit_size, stats.lock()); }); - - EXPECT_ANY_THROW({ stats.createStat(file_id1, config.file_limit_size, stats.lock()); }); - EXPECT_ANY_THROW({ stats.createStat(file_id2, config.file_limit_size, stats.lock()); }); - EXPECT_ANY_THROW({ stats.createStat(stats.roll_id + 1, config.file_limit_size, stats.lock()); }); -} -CATCH - -TEST_F(BlobStoreStatsTest, testStats) -{ - BlobStats stats(logger, delegator, config); - - auto stat = stats.createStat(0, config.file_limit_size, stats.lock()); - - ASSERT_TRUE(stat); - ASSERT_TRUE(stat->smap); - stats.createStat(1, config.file_limit_size, stats.lock()); - stats.createStat(2, config.file_limit_size, stats.lock()); - - auto stats_copy = stats.getStats(); - - ASSERT_EQ(stats_copy.size(), std::min(getTotalStatsNum(stats_copy), path_num)); - ASSERT_EQ(getTotalStatsNum(stats_copy), 3); - ASSERT_EQ(stats.roll_id, 3); - - stats.eraseStat(0, stats.lock()); - stats.eraseStat(1, stats.lock()); - ASSERT_EQ(getTotalStatsNum(stats.getStats()), 1); - ASSERT_EQ(stats.roll_id, 3); -} - - -TEST_F(BlobStoreStatsTest, testStat) -{ - BlobFileId blob_file_id = 0; - BlobStore::BlobStats::BlobStatPtr stat; - - BlobStats stats(logger, delegator, config); - - std::tie(stat, blob_file_id) = stats.chooseStat(10, stats.lock()); - ASSERT_EQ(blob_file_id, 1); - ASSERT_FALSE(stat); - - // still 0 - std::tie(stat, blob_file_id) = stats.chooseStat(10, stats.lock()); - ASSERT_EQ(blob_file_id, 1); - ASSERT_FALSE(stat); - - stats.createStat(0, config.file_limit_size, stats.lock()); - std::tie(stat, blob_file_id) = stats.chooseStat(10, stats.lock()); - ASSERT_EQ(blob_file_id, INVALID_BLOBFILE_ID); - ASSERT_TRUE(stat); - - auto offset = stat->getPosFromStat(10, stats.lock()); - ASSERT_EQ(offset, 0); - - offset = stat->getPosFromStat(100, stats.lock()); - ASSERT_EQ(offset, 10); - - offset = stat->getPosFromStat(20, stats.lock()); - ASSERT_EQ(offset, 110); - - ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20); - ASSERT_EQ(stat->sm_valid_size, 10 + 100 + 20); - ASSERT_EQ(stat->sm_valid_rate, 1); - - stat->removePosFromStat(10, 100, stats.lock()); - ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20); - ASSERT_EQ(stat->sm_valid_size, 10 + 20); - ASSERT_LE(stat->sm_valid_rate, 1); - - offset = stat->getPosFromStat(110, stats.lock()); - ASSERT_EQ(offset, 130); - ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20 + 110); - ASSERT_EQ(stat->sm_valid_size, 10 + 20 + 110); - ASSERT_LE(stat->sm_valid_rate, 1); - - offset = stat->getPosFromStat(90, stats.lock()); - ASSERT_EQ(offset, 10); - ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20 + 110); - ASSERT_EQ(stat->sm_valid_size, 10 + 20 + 110 + 90); - ASSERT_LE(stat->sm_valid_rate, 1); - - // Unmark the last range - stat->removePosFromStat(130, 110, stats.lock()); - ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20 + 110); - ASSERT_EQ(stat->sm_valid_size, 10 + 20 + 90); - ASSERT_LE(stat->sm_valid_rate, 1); - - /** - * now used space looks like: - * [0,10) [10,100) [110,130) - * And total size still is 10 + 100 + 20 + 110 - * Then after we add a range which size is 120 - * Total size should plus 10, rather than 120. - * And the postion return should be last range freed. - */ - offset = stat->getPosFromStat(120, stats.lock()); - ASSERT_EQ(offset, 130); - ASSERT_EQ(stat->sm_total_size, 10 + 100 + 20 + 110 + 10); - ASSERT_EQ(stat->sm_valid_size, 10 + 20 + 90 + 120); - ASSERT_LE(stat->sm_valid_rate, 1); -} - -TEST_F(BlobStoreStatsTest, testFullStats) -{ - BlobFileId blob_file_id = 0; - BlobStore::BlobStats::BlobStatPtr stat; - BlobFileOffset offset = 0; - - BlobStats stats(logger, delegator, config); - - stat = stats.createStat(1, config.file_limit_size, stats.lock()); - offset = stat->getPosFromStat(BLOBFILE_LIMIT_SIZE - 1, stats.lock()); - ASSERT_EQ(offset, 0); - - // Can't get pos from a full stat - offset = stat->getPosFromStat(100, stats.lock()); - ASSERT_EQ(offset, INVALID_BLOBFILE_OFFSET); - - // Stat internal property should not changed - ASSERT_EQ(stat->sm_total_size, BLOBFILE_LIMIT_SIZE - 1); - ASSERT_EQ(stat->sm_valid_size, BLOBFILE_LIMIT_SIZE - 1); - ASSERT_LE(stat->sm_valid_rate, 1); - - // Won't choose full one - std::tie(stat, blob_file_id) = stats.chooseStat(100, stats.lock()); - ASSERT_EQ(blob_file_id, 2); - ASSERT_FALSE(stat); - - // A new stat can use - stat = stats.createStat(blob_file_id, config.file_limit_size, stats.lock()); - offset = stat->getPosFromStat(100, stats.lock()); - ASSERT_EQ(offset, 0); - - // Remove the stat which id is 0 , now remain the stat which id is 1 - stats.eraseStat(1, stats.lock()); - - // Then full the stat which id 2 - offset = stat->getPosFromStat(BLOBFILE_LIMIT_SIZE - 100, stats.lock()); - ASSERT_EQ(offset, 100); - - // Then choose stat , it should return the stat id 3 - // Stat which id is 2 is full. - std::tie(stat, blob_file_id) = stats.chooseStat(100, stats.lock()); - ASSERT_EQ(blob_file_id, 3); - ASSERT_FALSE(stat); -} - class BlobStoreTest : public DB::base::TiFlashStorageTestBasic { public: @@ -307,8 +53,18 @@ class BlobStoreTest : public DB::base::TiFlashStorageTestBasic config.cached_fd_size = 0; } + static size_t getTotalStatsNum(const BlobStats::StatsMap & stats_map) + { + size_t total_stats_num = 0; + for (const auto & iter : stats_map) + { + total_stats_num += iter.second.size(); + } + return total_stats_num; + } + protected: - BlobStore::Config config; + BlobConfig config; PSDiskDelegatorPtr delegator; }; @@ -1287,7 +1043,7 @@ try size_t buff_nums = 20; size_t buff_size = 20; - BlobStore::Config config_with_small_file_limit_size; + BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 100; auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); char c_buff[buff_size * buff_nums]; @@ -1338,7 +1094,7 @@ try size_t buff_nums = 20; size_t buff_size = 20; - BlobStore::Config config_with_small_file_limit_size; + BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 100; auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); char c_buff[buff_size * buff_nums]; @@ -1383,7 +1139,7 @@ try PageId fixed_page_id = 50; PageId page_id = fixed_page_id; - BlobStore::Config config_with_small_file_limit_size; + BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 400; auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); @@ -1549,7 +1305,7 @@ try PageId fixed_page_id = 50; PageId page_id = fixed_page_id; - BlobStore::Config config_with_small_file_limit_size; + BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 400; auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); @@ -1581,7 +1337,7 @@ try PageId fixed_page_id = 50; PageId page_id = fixed_page_id; - BlobStore::Config config_with_small_file_limit_size; + BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 400; PageEntryV3 entry_from_write; @@ -1620,7 +1376,7 @@ try const auto file_provider = DB::tests::TiFlashTestEnv::getContext().getFileProvider(); PageId page_id = 50; - BlobStore::Config config_with_small_file_limit_size; + BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 800; PageEntryV3 entry_from_write1; @@ -1692,7 +1448,7 @@ try PageId page_id2 = 51; PageId page_id3 = 52; - BlobStore::Config config_with_small_file_limit_size; + BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 800; PageEntryV3 entry_from_write1; diff --git a/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp b/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp index 1db4a893cfb..8a7140cc938 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp @@ -118,7 +118,17 @@ class PageDirectoryTest : public DB::base::TiFlashStorageTestBasic FileProviderPtr provider = ctx.getFileProvider(); PSDiskDelegatorPtr delegator = std::make_shared(path); PageDirectoryFactory factory; - return factory.create("PageDirectoryTest", provider, delegator, WALStore::Config()); + return factory.create("PageDirectoryTest", provider, delegator, WALConfig()); + } + +protected: + static PageId getNormalPageIdU64(const PageDirectoryPtr & d, PageId page_id, const PageDirectorySnapshotPtr & snap) + { + return d->getNormalPageId(buildV3Id(TEST_NAMESPACE_ID, page_id), snap, true).low; + } + static PageEntryV3 getEntry(const PageDirectoryPtr & d, PageId page_id, const PageDirectorySnapshotPtr & snap) + { + return d->getByID(buildV3Id(TEST_NAMESPACE_ID, page_id), snap).second; } protected: @@ -922,10 +932,10 @@ try } auto s0 = dir->createSnapshot(); // calling getNormalPageId on non-external-page will return itself - EXPECT_EQ(9, dir->getNormalPageId(9, s0).low); - EXPECT_EQ(10, dir->getNormalPageId(10, s0).low); - EXPECT_ANY_THROW(dir->getNormalPageId(11, s0)); // not exist at all - EXPECT_ANY_THROW(dir->getNormalPageId(12, s0)); // not exist at all + EXPECT_EQ(9, getNormalPageIdU64(dir, 9, s0)); + EXPECT_EQ(10, getNormalPageIdU64(dir, 10, s0)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 11, s0)); // not exist at all + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 12, s0)); // not exist at all { PageEntriesEdit edit; @@ -938,12 +948,12 @@ try dir->apply(std::move(edit)); } auto s1 = dir->createSnapshot(); - EXPECT_ANY_THROW(dir->getNormalPageId(10, s1)); - EXPECT_EQ(10, dir->getNormalPageId(11, s1).low); - EXPECT_EQ(10, dir->getNormalPageId(12, s1).low); - EXPECT_ANY_THROW(dir->getNormalPageId(9, s1)); - EXPECT_EQ(9, dir->getNormalPageId(13, s1).low); - EXPECT_EQ(9, dir->getNormalPageId(14, s1).low); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 10, s1)); + EXPECT_EQ(10, getNormalPageIdU64(dir, 11, s1)); + EXPECT_EQ(10, getNormalPageIdU64(dir, 12, s1)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 9, s1)); + EXPECT_EQ(9, getNormalPageIdU64(dir, 13, s1)); + EXPECT_EQ(9, getNormalPageIdU64(dir, 14, s1)); { PageEntriesEdit edit; @@ -952,12 +962,12 @@ try dir->apply(std::move(edit)); } auto s2 = dir->createSnapshot(); - EXPECT_ANY_THROW(dir->getNormalPageId(10, s2)); - EXPECT_ANY_THROW(dir->getNormalPageId(11, s2)); - EXPECT_EQ(10, dir->getNormalPageId(12, s2).low); - EXPECT_ANY_THROW(dir->getNormalPageId(9, s2)); - EXPECT_EQ(9, dir->getNormalPageId(13, s2).low); - EXPECT_ANY_THROW(dir->getNormalPageId(14, s2)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 10, s2)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 11, s2)); + EXPECT_EQ(10, getNormalPageIdU64(dir, 12, s2)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 9, s2)); + EXPECT_EQ(9, getNormalPageIdU64(dir, 13, s2)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 14, s2)); { PageEntriesEdit edit; @@ -966,656 +976,15 @@ try dir->apply(std::move(edit)); } auto s3 = dir->createSnapshot(); - EXPECT_ANY_THROW(dir->getNormalPageId(10, s3)); - EXPECT_ANY_THROW(dir->getNormalPageId(11, s3)); - EXPECT_ANY_THROW(dir->getNormalPageId(12, s3)); - EXPECT_ANY_THROW(dir->getNormalPageId(9, s3)); - EXPECT_ANY_THROW(dir->getNormalPageId(13, s3)); - EXPECT_ANY_THROW(dir->getNormalPageId(14, s3)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 10, s3)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 11, s3)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 12, s3)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 9, s3)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 13, s3)); + EXPECT_ANY_THROW(getNormalPageIdU64(dir, 14, s3)); } CATCH -#define INSERT_BLOBID_ENTRY(BLOBID, VERSION) \ - PageEntryV3 entry_v##VERSION{.file_id = (BLOBID), .size = (VERSION), .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; \ - entries.createNewEntry(PageVersion(VERSION), entry_v##VERSION); -#define INSERT_ENTRY(VERSION) INSERT_BLOBID_ENTRY(1, VERSION) -#define INSERT_GC_ENTRY(VERSION, EPOCH) \ - PageEntryV3 entry_gc_v##VERSION##_##EPOCH{.file_id = 2, .size = 100 * (VERSION) + (EPOCH), .padded_size = 0, .tag = 0, .offset = 0x234, .checksum = 0x5678}; \ - entries.createNewEntry(PageVersion((VERSION), (EPOCH)), entry_gc_v##VERSION##_##EPOCH); - -class VersionedEntriesTest : public ::testing::Test -{ -public: - using DerefCounter = std::map>; - std::tuple runClean(UInt64 seq) - { - DerefCounter deref_counter; - PageEntriesV3 removed_entries; - bool all_removed = entries.cleanOutdatedEntries(seq, &deref_counter, &removed_entries, entries.acquireLock()); - return {all_removed, removed_entries, deref_counter}; - } - - std::tuple runDeref(UInt64 seq, PageVersion ver, Int64 decrease_num) - { - PageEntriesV3 removed_entries; - bool all_removed = entries.derefAndClean(seq, buildV3Id(TEST_NAMESPACE_ID, page_id), ver, decrease_num, &removed_entries); - return {all_removed, removed_entries}; - } - -protected: - const PageId page_id = 100; - VersionedPageEntries entries; -}; - -TEST_F(VersionedEntriesTest, InsertGet) -{ - INSERT_ENTRY(2); - INSERT_ENTRY(5); - INSERT_ENTRY(10); - - // Insert some entries with version - ASSERT_FALSE(entries.getEntry(1).has_value()); - ASSERT_SAME_ENTRY(*entries.getEntry(2), entry_v2); - ASSERT_SAME_ENTRY(*entries.getEntry(3), entry_v2); - ASSERT_SAME_ENTRY(*entries.getEntry(4), entry_v2); - for (UInt64 seq = 5; seq < 10; ++seq) - { - ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_v5); - } - for (UInt64 seq = 10; seq < 20; ++seq) - { - ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_v10); - } - - // Insert some entries with version && gc epoch - INSERT_GC_ENTRY(2, 1); - INSERT_GC_ENTRY(5, 1); - INSERT_GC_ENTRY(5, 2); - ASSERT_FALSE(entries.getEntry(1).has_value()); - ASSERT_SAME_ENTRY(*entries.getEntry(2), entry_gc_v2_1); - ASSERT_SAME_ENTRY(*entries.getEntry(3), entry_gc_v2_1); - ASSERT_SAME_ENTRY(*entries.getEntry(4), entry_gc_v2_1); - for (UInt64 seq = 5; seq < 10; ++seq) - { - ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_gc_v5_2); - } - for (UInt64 seq = 10; seq < 20; ++seq) - { - ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_v10); - } - - // Insert delete. Can not get entry with seq >= delete_version. - // But it won't affect reading with old seq. - entries.createDelete(PageVersion(15)); - ASSERT_FALSE(entries.getEntry(1).has_value()); - ASSERT_SAME_ENTRY(*entries.getEntry(2), entry_gc_v2_1); - ASSERT_SAME_ENTRY(*entries.getEntry(3), entry_gc_v2_1); - ASSERT_SAME_ENTRY(*entries.getEntry(4), entry_gc_v2_1); - for (UInt64 seq = 5; seq < 10; ++seq) - { - ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_gc_v5_2); - } - for (UInt64 seq = 10; seq < 15; ++seq) - { - ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_v10); - } - for (UInt64 seq = 15; seq < 20; ++seq) - { - ASSERT_FALSE(entries.getEntry(seq).has_value()); - } -} - -TEST_F(VersionedEntriesTest, InsertWithLowerVersion) -{ - INSERT_ENTRY(5); - ASSERT_SAME_ENTRY(*entries.getEntry(5), entry_v5); - ASSERT_FALSE(entries.getEntry(2).has_value()); - INSERT_ENTRY(2); - ASSERT_SAME_ENTRY(*entries.getEntry(2), entry_v2); -} - -TEST_F(VersionedEntriesTest, EntryIsVisible) -try -{ - // init state - ASSERT_FALSE(entries.isVisible(0)); - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_FALSE(entries.isVisible(2)); - ASSERT_FALSE(entries.isVisible(10000)); - - // insert some entries - INSERT_ENTRY(2); - INSERT_ENTRY(3); - INSERT_ENTRY(5); - - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_TRUE(entries.isVisible(2)); - ASSERT_TRUE(entries.isVisible(3)); - ASSERT_TRUE(entries.isVisible(4)); - ASSERT_TRUE(entries.isVisible(5)); - ASSERT_TRUE(entries.isVisible(6)); - - // insert delete - entries.createDelete(PageVersion(6)); - - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_TRUE(entries.isVisible(2)); - ASSERT_TRUE(entries.isVisible(3)); - ASSERT_TRUE(entries.isVisible(4)); - ASSERT_TRUE(entries.isVisible(5)); - ASSERT_FALSE(entries.isVisible(6)); - ASSERT_FALSE(entries.isVisible(10000)); - - // insert entry after delete - INSERT_ENTRY(7); - - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_TRUE(entries.isVisible(2)); - ASSERT_TRUE(entries.isVisible(3)); - ASSERT_TRUE(entries.isVisible(4)); - ASSERT_TRUE(entries.isVisible(5)); - ASSERT_FALSE(entries.isVisible(6)); - ASSERT_TRUE(entries.isVisible(7)); - ASSERT_TRUE(entries.isVisible(10000)); -} -CATCH - -TEST_F(VersionedEntriesTest, ExternalPageIsVisible) -try -{ - // init state - ASSERT_FALSE(entries.isVisible(0)); - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_FALSE(entries.isVisible(2)); - ASSERT_FALSE(entries.isVisible(10000)); - - // insert some entries - entries.createNewExternal(PageVersion(2)); - - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_TRUE(entries.isVisible(2)); - ASSERT_TRUE(entries.isVisible(10000)); - - // insert delete - entries.createDelete(PageVersion(6)); - - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_TRUE(entries.isVisible(2)); - ASSERT_TRUE(entries.isVisible(3)); - ASSERT_TRUE(entries.isVisible(4)); - ASSERT_TRUE(entries.isVisible(5)); - ASSERT_FALSE(entries.isVisible(6)); - ASSERT_FALSE(entries.isVisible(10000)); - - // insert entry after delete - entries.createNewExternal(PageVersion(7)); - - // after re-create external page, the visible for 1~5 has changed - ASSERT_FALSE(entries.isVisible(6)); - ASSERT_TRUE(entries.isVisible(7)); - ASSERT_TRUE(entries.isVisible(10000)); -} -CATCH - -TEST_F(VersionedEntriesTest, RefPageIsVisible) -try -{ - // init state - ASSERT_FALSE(entries.isVisible(0)); - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_FALSE(entries.isVisible(2)); - ASSERT_FALSE(entries.isVisible(10000)); - - // insert some entries - entries.createNewRef(PageVersion(2), buildV3Id(TEST_NAMESPACE_ID, 2)); - - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_TRUE(entries.isVisible(2)); - ASSERT_TRUE(entries.isVisible(10000)); - - // insert delete - entries.createDelete(PageVersion(6)); - - ASSERT_FALSE(entries.isVisible(1)); - ASSERT_TRUE(entries.isVisible(2)); - ASSERT_TRUE(entries.isVisible(3)); - ASSERT_TRUE(entries.isVisible(4)); - ASSERT_TRUE(entries.isVisible(5)); - ASSERT_FALSE(entries.isVisible(6)); - ASSERT_FALSE(entries.isVisible(10000)); - - // insert entry after delete - entries.createNewRef(PageVersion(7), buildV3Id(TEST_NAMESPACE_ID, 2)); - - // after re-create ref page, the visible for 1~5 has changed - ASSERT_FALSE(entries.isVisible(6)); - ASSERT_TRUE(entries.isVisible(7)); - ASSERT_TRUE(entries.isVisible(10000)); -} -CATCH - -TEST_F(VersionedEntriesTest, CleanOutdateVersions) -try -{ - // Test running gc on a single page, it should clean all - // outdated versions. - INSERT_ENTRY(2); - INSERT_GC_ENTRY(2, 1); - INSERT_ENTRY(5); - INSERT_GC_ENTRY(5, 1); - INSERT_GC_ENTRY(5, 2); - INSERT_ENTRY(10); - INSERT_ENTRY(11); - entries.createDelete(PageVersion(15)); - - // noting to be removed - auto [all_removed, removed_entries, deref_counter] = runClean(1); - ASSERT_FALSE(all_removed); - ASSERT_EQ(removed_entries.size(), 0); - ASSERT_EQ(deref_counter.size(), 0); - - // <2,0> get removed. - std::tie(all_removed, removed_entries, deref_counter) = runClean(2); - ASSERT_FALSE(all_removed); - ASSERT_EQ(removed_entries.size(), 1); - auto iter = removed_entries.begin(); - ASSERT_SAME_ENTRY(entry_v2, *iter); - ASSERT_SAME_ENTRY(entry_gc_v2_1, *entries.getEntry(2)); - ASSERT_EQ(deref_counter.size(), 0); - - // nothing get removed. - std::tie(all_removed, removed_entries, deref_counter) = runClean(4); - ASSERT_FALSE(all_removed); - ASSERT_EQ(removed_entries.size(), 0); - ASSERT_SAME_ENTRY(entry_gc_v2_1, *entries.getEntry(4)); - ASSERT_EQ(deref_counter.size(), 0); - - // <2,1>, <5,0>, <5,1>, <5,2>, <10,0> get removed. - std::tie(all_removed, removed_entries, deref_counter) = runClean(11); - ASSERT_FALSE(all_removed); - ASSERT_EQ(removed_entries.size(), 5); - iter = removed_entries.begin(); - ASSERT_SAME_ENTRY(entry_v10, *iter); - iter++; - ASSERT_SAME_ENTRY(entry_gc_v5_2, *iter); - iter++; - ASSERT_SAME_ENTRY(entry_gc_v5_1, *iter); - iter++; - ASSERT_SAME_ENTRY(entry_v5, *iter); - iter++; - ASSERT_SAME_ENTRY(entry_gc_v2_1, *iter); - ASSERT_SAME_ENTRY(entry_v11, *entries.getEntry(11)); - ASSERT_EQ(deref_counter.size(), 0); - - // <11,0> get removed, all cleared. - std::tie(all_removed, removed_entries, deref_counter) = runClean(20); - ASSERT_TRUE(all_removed); // should remove this chain - ASSERT_EQ(removed_entries.size(), 1); - ASSERT_FALSE(entries.getEntry(20)); - ASSERT_EQ(deref_counter.size(), 0); -} -CATCH - -TEST_F(VersionedEntriesTest, DeleteMultiTime) -try -{ - entries.createDelete(PageVersion(1)); - INSERT_ENTRY(2); - INSERT_GC_ENTRY(2, 1); - entries.createDelete(PageVersion(15)); - entries.createDelete(PageVersion(17)); - entries.createDelete(PageVersion(16)); - - bool all_removed; - std::map> deref_counter; - PageEntriesV3 removed_entries; - - // <2,0> get removed. - std::tie(all_removed, removed_entries, deref_counter) = runClean(2); - ASSERT_FALSE(all_removed); - ASSERT_EQ(removed_entries.size(), 1); - auto iter = removed_entries.begin(); - ASSERT_SAME_ENTRY(entry_v2, *iter); - ASSERT_SAME_ENTRY(entry_gc_v2_1, *entries.getEntry(2)); - ASSERT_EQ(deref_counter.size(), 0); - - // clear all - std::tie(all_removed, removed_entries, deref_counter) = runClean(20); - ASSERT_EQ(removed_entries.size(), 1); - ASSERT_TRUE(all_removed); // should remove this chain - ASSERT_FALSE(entries.getEntry(20)); - ASSERT_EQ(deref_counter.size(), 0); -} -CATCH - -TEST_F(VersionedEntriesTest, DontCleanWhenBeingRef) -try -{ - bool all_removed; - std::map> deref_counter; - PageEntriesV3 removed_entries; - - INSERT_ENTRY(2); - entries.incrRefCount(PageVersion(2)); - entries.incrRefCount(PageVersion(2)); - entries.createDelete(PageVersion(5)); - - // <2, 0> is not available after seq=5, but not get removed - ASSERT_SAME_ENTRY(entry_v2, *entries.getEntry(4)); - ASSERT_FALSE(entries.getEntry(5)); - - // <2, 0> is not removed since it's being ref - std::tie(all_removed, removed_entries, deref_counter) = runClean(5); - ASSERT_FALSE(all_removed); - ASSERT_EQ(removed_entries.size(), 0); - ASSERT_FALSE(entries.getEntry(5)); - ASSERT_EQ(deref_counter.size(), 0); - - // decrease 1 ref counting - std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 1); - ASSERT_EQ(removed_entries.size(), 0); - ASSERT_FALSE(all_removed); // should not remove this chain - ASSERT_FALSE(entries.getEntry(5)); - - // clear all - std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 1); - ASSERT_EQ(removed_entries.size(), 1); - ASSERT_SAME_ENTRY(removed_entries[0], entry_v2); - ASSERT_TRUE(all_removed); // should remove this chain - ASSERT_FALSE(entries.getEntry(5)); -} -CATCH - -TEST_F(VersionedEntriesTest, DontCleanWhenBeingRef2) -try -{ - bool all_removed; - std::map> deref_counter; - PageEntriesV3 removed_entries; - - INSERT_ENTRY(2); - entries.incrRefCount(PageVersion(2)); - entries.incrRefCount(PageVersion(2)); - entries.createDelete(PageVersion(5)); - - // <2, 0> is not available after seq=5, but not get removed - ASSERT_SAME_ENTRY(entry_v2, *entries.getEntry(4)); - ASSERT_FALSE(entries.getEntry(5)); - - // <2, 0> is not removed since it's being ref - std::tie(all_removed, removed_entries, deref_counter) = runClean(5); - ASSERT_FALSE(all_removed); - ASSERT_EQ(removed_entries.size(), 0); - ASSERT_FALSE(entries.getEntry(5)); - ASSERT_EQ(deref_counter.size(), 0); - - // clear all - std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 2); - ASSERT_EQ(removed_entries.size(), 1); - ASSERT_SAME_ENTRY(removed_entries[0], entry_v2); - ASSERT_TRUE(all_removed); // should remove this chain - ASSERT_FALSE(entries.getEntry(5)); -} -CATCH - -TEST_F(VersionedEntriesTest, CleanDuplicatedWhenBeingRefAndAppliedUpsert) -try -{ - bool all_removed; - std::map> deref_counter; - PageEntriesV3 removed_entries; - - INSERT_ENTRY(2); - entries.incrRefCount(PageVersion(2)); - entries.incrRefCount(PageVersion(2)); - INSERT_GC_ENTRY(2, 1); - INSERT_GC_ENTRY(2, 2); - - // <2, 2> - ASSERT_SAME_ENTRY(entry_gc_v2_2, *entries.getEntry(4)); - - // <2, 2> is not removed since it's being ref, but <2,0> <2,1> is removed since they are replaced by newer version - std::tie(all_removed, removed_entries, deref_counter) = runClean(5); - ASSERT_FALSE(all_removed); - ASSERT_EQ(removed_entries.size(), 2); - ASSERT_SAME_ENTRY(removed_entries[0], entry_gc_v2_1); - ASSERT_SAME_ENTRY(removed_entries[1], entry_v2); - ASSERT_SAME_ENTRY(entry_gc_v2_2, *entries.getEntry(4)); - ASSERT_EQ(deref_counter.size(), 0); - - // clear all - std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 2); - ASSERT_EQ(removed_entries.size(), 0); - ASSERT_FALSE(all_removed); // should not remove this chain - ASSERT_SAME_ENTRY(entry_gc_v2_2, *entries.getEntry(4)); -} -CATCH - -TEST_F(VersionedEntriesTest, CleanDuplicatedWhenBeingRefAndAppliedUpsert2) -try -{ - bool all_removed; - std::map> deref_counter; - PageEntriesV3 removed_entries; - - INSERT_ENTRY(2); - entries.incrRefCount(PageVersion(2)); - entries.incrRefCount(PageVersion(2)); - INSERT_GC_ENTRY(2, 1); - INSERT_GC_ENTRY(2, 2); - entries.createDelete(PageVersion(5)); - - // <2, 2> is not available after seq=5, but not get removed - ASSERT_SAME_ENTRY(entry_gc_v2_2, *entries.getEntry(4)); - ASSERT_FALSE(entries.getEntry(5)); - - // <2, 2> is not removed since it's being ref, but <2,0> <2,1> is removed since they are replaced by newer version - std::tie(all_removed, removed_entries, deref_counter) = runClean(5); - ASSERT_FALSE(all_removed); - ASSERT_EQ(removed_entries.size(), 2); - ASSERT_SAME_ENTRY(removed_entries[0], entry_gc_v2_1); - ASSERT_SAME_ENTRY(removed_entries[1], entry_v2); - ASSERT_FALSE(entries.getEntry(5)); - ASSERT_EQ(deref_counter.size(), 0); - - // clear all - std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 2); - ASSERT_EQ(removed_entries.size(), 1); - ASSERT_SAME_ENTRY(removed_entries[0], entry_gc_v2_2); - ASSERT_TRUE(all_removed); // should remove this chain - ASSERT_FALSE(entries.getEntry(5)); -} -CATCH - -TEST_F(VersionedEntriesTest, ReadAfterGcApplied) -try -{ - bool all_removed; - std::map> deref_counter; - PageEntriesV3 removed_entries; - - INSERT_ENTRY(2); - INSERT_ENTRY(3); - INSERT_ENTRY(5); - - // Read with snapshot seq=2 - ASSERT_SAME_ENTRY(entry_v2, *entries.getEntry(2)); - - // Mock that gc applied and insert <2, 1> - INSERT_GC_ENTRY(2, 1); - - // Now we should read the entry <2, 1> with seq=2 - ASSERT_SAME_ENTRY(entry_gc_v2_1, *entries.getEntry(2)); - - // <2,0> get removed - std::tie(all_removed, removed_entries, deref_counter) = runClean(2); - ASSERT_EQ(removed_entries.size(), 1); -} -CATCH - -TEST_F(VersionedEntriesTest, getEntriesByBlobId) -{ - INSERT_BLOBID_ENTRY(1, 1); - INSERT_BLOBID_ENTRY(1, 2); - INSERT_BLOBID_ENTRY(2, 3); - INSERT_BLOBID_ENTRY(2, 4); - INSERT_BLOBID_ENTRY(1, 5); - INSERT_BLOBID_ENTRY(3, 6); - INSERT_BLOBID_ENTRY(3, 8); - INSERT_BLOBID_ENTRY(1, 11); - - PageId page_id = 100; - auto check_for_blob_id_1 = [&](const PageIdAndVersionedEntries & entries) { - auto it = entries.begin(); - - ASSERT_EQ(std::get<0>(*it).low, page_id); - ASSERT_EQ(std::get<1>(*it).sequence, 1); - ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v1); - - it++; - ASSERT_EQ(std::get<0>(*it).low, page_id); - ASSERT_EQ(std::get<1>(*it).sequence, 2); - ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v2); - - it++; - ASSERT_EQ(std::get<0>(*it).low, page_id); - ASSERT_EQ(std::get<1>(*it).sequence, 5); - ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v5); - - it++; - ASSERT_EQ(std::get<0>(*it).low, page_id); - ASSERT_EQ(std::get<1>(*it).sequence, 11); - ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v11); - }; - auto check_for_blob_id_2 = [&](const PageIdAndVersionedEntries & entries) { - auto it = entries.begin(); - - ASSERT_EQ(std::get<0>(*it).low, page_id); - ASSERT_EQ(std::get<1>(*it).sequence, 3); - ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v3); - - it++; - ASSERT_EQ(std::get<0>(*it).low, page_id); - ASSERT_EQ(std::get<1>(*it).sequence, 4); - ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v4); - }; - auto check_for_blob_id_3 = [&](const PageIdAndVersionedEntries & entries) { - auto it = entries.begin(); - - ASSERT_EQ(std::get<0>(*it).low, page_id); - ASSERT_EQ(std::get<1>(*it).sequence, 6); - ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v6); - - it++; - ASSERT_EQ(std::get<0>(*it).low, page_id); - ASSERT_EQ(std::get<1>(*it).sequence, 8); - ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v8); - }; - - { - std::map blob_entries; - PageSize total_size = entries.getEntriesByBlobIds({/*empty*/}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); - - ASSERT_EQ(blob_entries.size(), 0); - ASSERT_EQ(total_size, 0); - } - - { - std::map blob_entries; - const BlobFileId blob_id = 1; - PageSize total_size = entries.getEntriesByBlobIds({blob_id}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); - - ASSERT_EQ(blob_entries.size(), 1); - ASSERT_EQ(blob_entries[blob_id].size(), 4); - ASSERT_EQ(total_size, 1 + 2 + 5 + 11); - check_for_blob_id_1(blob_entries[blob_id]); - } - - { - std::map blob_entries; - const BlobFileId blob_id = 2; - PageSize total_size = entries.getEntriesByBlobIds({blob_id}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); - - ASSERT_EQ(blob_entries.size(), 1); - ASSERT_EQ(blob_entries[blob_id].size(), 2); - ASSERT_EQ(total_size, 3 + 4); - check_for_blob_id_2(blob_entries[blob_id]); - } - - { - std::map blob_entries; - const BlobFileId blob_id = 3; - PageSize total_size = entries.getEntriesByBlobIds({blob_id}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); - - ASSERT_EQ(blob_entries.size(), 1); - ASSERT_EQ(blob_entries[blob_id].size(), 2); - ASSERT_EQ(total_size, 6 + 8); - check_for_blob_id_3(blob_entries[blob_id]); - } - - // {1, 2} - { - std::map blob_entries; - PageSize total_size = entries.getEntriesByBlobIds({1, 2}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); - - ASSERT_EQ(blob_entries.size(), 2); - ASSERT_EQ(blob_entries[1].size(), 4); - ASSERT_EQ(blob_entries[2].size(), 2); - ASSERT_EQ(total_size, (1 + 2 + 5 + 11) + (3 + 4)); - check_for_blob_id_1(blob_entries[1]); - check_for_blob_id_2(blob_entries[2]); - } - - // {2, 3} - { - std::map blob_entries; - PageSize total_size = entries.getEntriesByBlobIds({3, 2}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); - - ASSERT_EQ(blob_entries.size(), 2); - ASSERT_EQ(blob_entries[2].size(), 2); - ASSERT_EQ(blob_entries[3].size(), 2); - ASSERT_EQ(total_size, (6 + 8) + (3 + 4)); - check_for_blob_id_2(blob_entries[2]); - check_for_blob_id_3(blob_entries[3]); - } - - // {1, 2, 3} - { - std::map blob_entries; - PageSize total_size = entries.getEntriesByBlobIds({1, 3, 2}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); - - ASSERT_EQ(blob_entries.size(), 3); - ASSERT_EQ(blob_entries[1].size(), 4); - ASSERT_EQ(blob_entries[2].size(), 2); - ASSERT_EQ(blob_entries[3].size(), 2); - ASSERT_EQ(total_size, (1 + 2 + 5 + 11) + (6 + 8) + (3 + 4)); - check_for_blob_id_1(blob_entries[1]); - check_for_blob_id_2(blob_entries[2]); - check_for_blob_id_3(blob_entries[3]); - } - - // {1, 2, 3, 100}; blob_id 100 is not exist in actual - { - std::map blob_entries; - PageSize total_size = entries.getEntriesByBlobIds({1, 3, 2, 4}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); - - ASSERT_EQ(blob_entries.size(), 3); // 100 not exist - ASSERT_EQ(blob_entries.find(100), blob_entries.end()); - ASSERT_EQ(blob_entries[1].size(), 4); - ASSERT_EQ(blob_entries[2].size(), 2); - ASSERT_EQ(blob_entries[3].size(), 2); - ASSERT_EQ(total_size, (1 + 2 + 5 + 11) + (6 + 8) + (3 + 4)); - check_for_blob_id_1(blob_entries[1]); - check_for_blob_id_2(blob_entries[2]); - check_for_blob_id_3(blob_entries[3]); - } -} - -#undef INSERT_BLOBID_ENTRY -#undef INSERT_ENTRY -#undef INSERT_GC_ENTRY -// end of testing `VersionedEntriesTest` - class PageDirectoryGCTest : public PageDirectoryTest { }; @@ -1666,7 +1035,7 @@ TEST_F(PageDirectoryGCTest, ManyEditsAndDumpSnapshot) dir = restoreFromDisk(); { auto snap = dir->createSnapshot(); - ASSERT_SAME_ENTRY(dir->get(page_id0, snap).second, last_entry_for_0); + ASSERT_SAME_ENTRY(getEntry(dir, page_id0, snap), last_entry_for_0); EXPECT_ENTRY_NOT_EXIST(dir, page_id1, snap); } @@ -1687,9 +1056,9 @@ TEST_F(PageDirectoryGCTest, ManyEditsAndDumpSnapshot) dir = restoreFromDisk(); { auto snap = dir->createSnapshot(); - ASSERT_SAME_ENTRY(dir->get(page_id0, snap).second, last_entry_for_0); + ASSERT_SAME_ENTRY(getEntry(dir, page_id0, snap), last_entry_for_0); EXPECT_ENTRY_NOT_EXIST(dir, page_id1, snap); - ASSERT_SAME_ENTRY(dir->get(page_id2, snap).second, last_entry_for_2); + ASSERT_SAME_ENTRY(getEntry(dir, page_id2, snap), last_entry_for_2); EXPECT_ENTRY_NOT_EXIST(dir, page_id3, snap); } } @@ -2327,14 +1696,14 @@ try { auto snap = dir->createSnapshot(); - auto normal_id = dir->getNormalPageId(357, snap); - EXPECT_EQ(normal_id.low, 352); + auto normal_id = getNormalPageIdU64(dir, 357, snap); + EXPECT_EQ(normal_id, 352); } dir->gcInMemEntries(); { auto snap = dir->createSnapshot(); - auto normal_id = dir->getNormalPageId(357, snap); - EXPECT_EQ(normal_id.low, 352); + auto normal_id = getNormalPageIdU64(dir, 357, snap); + EXPECT_EQ(normal_id, 352); } auto s0 = dir->createSnapshot(); @@ -2352,8 +1721,8 @@ try { auto restored_dir = restore_from_edit(edit); auto snap = restored_dir->createSnapshot(); - auto normal_id = restored_dir->getNormalPageId(357, snap); - EXPECT_EQ(normal_id.low, 352); + auto normal_id = getNormalPageIdU64(restored_dir, 357, snap); + EXPECT_EQ(normal_id, 352); } } CATCH @@ -2396,9 +1765,9 @@ try auto edit = dir->dumpSnapshotToEdit(s0); auto restored_dir = restore_from_edit(edit); auto temp_snap = restored_dir->createSnapshot(); - EXPECT_SAME_ENTRY(restored_dir->get(1, temp_snap).second, entry_1_v2); - EXPECT_SAME_ENTRY(restored_dir->get(2, temp_snap).second, entry_2_v2); - EXPECT_ANY_THROW(restored_dir->get(3, temp_snap)); + EXPECT_SAME_ENTRY(getEntry(restored_dir, 1, temp_snap), entry_1_v2); + EXPECT_SAME_ENTRY(getEntry(restored_dir, 2, temp_snap), entry_2_v2); + EXPECT_ANY_THROW(getEntry(restored_dir, 3, temp_snap)); }; check_s0(); @@ -2422,16 +1791,16 @@ try auto edit = dir->dumpSnapshotToEdit(s1); auto restored_dir = restore_from_edit(edit); auto temp_snap = restored_dir->createSnapshot(); - EXPECT_ANY_THROW(restored_dir->get(1, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(2, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(3, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 1, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 2, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 3, temp_snap)); auto alive_ex = restored_dir->getAliveExternalIds(TEST_NAMESPACE_ID); EXPECT_EQ(alive_ex.size(), 3); EXPECT_GT(alive_ex.count(10), 0); EXPECT_GT(alive_ex.count(20), 0); EXPECT_GT(alive_ex.count(30), 0); - EXPECT_SAME_ENTRY(restored_dir->get(50, temp_snap).second, entry_50); - EXPECT_SAME_ENTRY(restored_dir->get(60, temp_snap).second, entry_60); + EXPECT_SAME_ENTRY(getEntry(restored_dir, 50, temp_snap), entry_50); + EXPECT_SAME_ENTRY(getEntry(restored_dir, 60, temp_snap), entry_60); }; check_s0(); check_s1(); @@ -2460,26 +1829,26 @@ try auto edit = dir->dumpSnapshotToEdit(s2); auto restored_dir = restore_from_edit(edit); auto temp_snap = restored_dir->createSnapshot(); - EXPECT_ANY_THROW(restored_dir->get(1, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(2, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(3, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 1, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 2, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 3, temp_snap)); auto alive_ex = restored_dir->getAliveExternalIds(TEST_NAMESPACE_ID); EXPECT_EQ(alive_ex.size(), 2); EXPECT_GT(alive_ex.count(10), 0); - EXPECT_EQ(restored_dir->getNormalPageId(11, temp_snap).low, 10); + EXPECT_EQ(getNormalPageIdU64(restored_dir, 11, temp_snap), 10); EXPECT_GT(alive_ex.count(20), 0); - EXPECT_EQ(restored_dir->getNormalPageId(21, temp_snap).low, 20); - EXPECT_EQ(restored_dir->getNormalPageId(22, temp_snap).low, 20); + EXPECT_EQ(getNormalPageIdU64(restored_dir, 21, temp_snap), 20); + EXPECT_EQ(getNormalPageIdU64(restored_dir, 22, temp_snap), 20); EXPECT_EQ(alive_ex.count(30), 0); // removed - EXPECT_ANY_THROW(restored_dir->get(50, temp_snap)); - EXPECT_SAME_ENTRY(restored_dir->get(51, temp_snap).second, entry_50); - EXPECT_SAME_ENTRY(restored_dir->get(52, temp_snap).second, entry_50); + EXPECT_ANY_THROW(getEntry(restored_dir, 50, temp_snap)); + EXPECT_SAME_ENTRY(getEntry(restored_dir, 51, temp_snap), entry_50); + EXPECT_SAME_ENTRY(getEntry(restored_dir, 52, temp_snap), entry_50); - EXPECT_SAME_ENTRY(restored_dir->get(60, temp_snap).second, entry_60); - EXPECT_ANY_THROW(restored_dir->get(61, temp_snap)); + EXPECT_SAME_ENTRY(getEntry(restored_dir, 60, temp_snap), entry_60); + EXPECT_ANY_THROW(getEntry(restored_dir, 61, temp_snap)); }; check_s0(); check_s1(); @@ -2500,21 +1869,21 @@ try auto edit = dir->dumpSnapshotToEdit(s3); auto restored_dir = restore_from_edit(edit); auto temp_snap = restored_dir->createSnapshot(); - EXPECT_ANY_THROW(restored_dir->get(1, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(2, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(3, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 1, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 2, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 3, temp_snap)); auto alive_ex = restored_dir->getAliveExternalIds(TEST_NAMESPACE_ID); EXPECT_EQ(alive_ex.size(), 0); EXPECT_EQ(alive_ex.count(10), 0); // removed EXPECT_EQ(alive_ex.count(20), 0); // removed EXPECT_EQ(alive_ex.count(30), 0); // removed - EXPECT_ANY_THROW(restored_dir->get(50, temp_snap)); - EXPECT_SAME_ENTRY(restored_dir->get(51, temp_snap).second, entry_50); - EXPECT_ANY_THROW(restored_dir->get(52, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 50, temp_snap)); + EXPECT_SAME_ENTRY(getEntry(restored_dir, 51, temp_snap), entry_50); + EXPECT_ANY_THROW(getEntry(restored_dir, 52, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(60, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(61, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 60, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 61, temp_snap)); }; check_s0(); check_s1(); @@ -2532,21 +1901,21 @@ try auto edit = dir->dumpSnapshotToEdit(s4); auto restored_dir = restore_from_edit(edit); auto temp_snap = restored_dir->createSnapshot(); - EXPECT_ANY_THROW(restored_dir->get(1, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(2, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(3, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 1, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 2, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 3, temp_snap)); auto alive_ex = restored_dir->getAliveExternalIds(TEST_NAMESPACE_ID); EXPECT_EQ(alive_ex.size(), 0); EXPECT_EQ(alive_ex.count(10), 0); // removed EXPECT_EQ(alive_ex.count(20), 0); // removed EXPECT_EQ(alive_ex.count(30), 0); // removed - EXPECT_ANY_THROW(restored_dir->get(50, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(51, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(52, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 50, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 51, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 52, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(60, temp_snap)); - EXPECT_ANY_THROW(restored_dir->get(61, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 60, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 61, temp_snap)); }; check_s0(); check_s1(); @@ -2584,7 +1953,7 @@ try dir->apply(std::move(edit)); } - auto restore_from_edit = [](const PageEntriesEdit & edit, BlobStore::BlobStats & stats) { + auto restore_from_edit = [](const PageEntriesEdit & edit, BlobStats & stats) { auto ctx = ::DB::tests::TiFlashTestEnv::getContext(); auto provider = ctx.getFileProvider(); auto path = getTemporaryPath(); @@ -2598,8 +1967,8 @@ try auto edit = dir->dumpSnapshotToEdit(snap); auto path = getTemporaryPath(); PSDiskDelegatorPtr delegator = std::make_shared(path); - auto config = BlobStore::Config{}; - BlobStore::BlobStats stats(log, delegator, config); + auto config = BlobConfig{}; + BlobStats stats(log, delegator, config); { const auto & lock = stats.lock(); stats.createStatNotChecking(file_id1, BLOBFILE_LIMIT_SIZE, lock); @@ -2607,9 +1976,9 @@ try } auto restored_dir = restore_from_edit(edit, stats); auto temp_snap = restored_dir->createSnapshot(); - EXPECT_SAME_ENTRY(entry_1_v1, restored_dir->get(2, temp_snap).second); - EXPECT_ANY_THROW(restored_dir->get(1, temp_snap)); - EXPECT_SAME_ENTRY(entry_5_v2, restored_dir->get(5, temp_snap).second); + EXPECT_SAME_ENTRY(entry_1_v1, getEntry(restored_dir, 2, temp_snap)); + EXPECT_ANY_THROW(getEntry(restored_dir, 1, temp_snap)); + EXPECT_SAME_ENTRY(entry_5_v2, getEntry(restored_dir, 5, temp_snap)); // The entry_1_v1 should be restored to stats auto stat_for_file_1 = stats.blobIdToStat(file_id1, /*ignore_not_exist*/ false); diff --git a/dbms/src/Storages/Page/V3/tests/gtest_versioned_entries.cpp b/dbms/src/Storages/Page/V3/tests/gtest_versioned_entries.cpp new file mode 100644 index 00000000000..b95941153e0 --- /dev/null +++ b/dbms/src/Storages/Page/V3/tests/gtest_versioned_entries.cpp @@ -0,0 +1,683 @@ + +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace DB +{ +namespace PS::V3::tests +{ + + +#define INSERT_BLOBID_ENTRY(BLOBID, VERSION) \ + PageEntryV3 entry_v##VERSION{.file_id = (BLOBID), .size = (VERSION), .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; \ + entries.createNewEntry(PageVersion(VERSION), entry_v##VERSION); +#define INSERT_ENTRY(VERSION) INSERT_BLOBID_ENTRY(1, VERSION) +#define INSERT_GC_ENTRY(VERSION, EPOCH) \ + PageEntryV3 entry_gc_v##VERSION##_##EPOCH{.file_id = 2, .size = 100 * (VERSION) + (EPOCH), .padded_size = 0, .tag = 0, .offset = 0x234, .checksum = 0x5678}; \ + entries.createNewEntry(PageVersion((VERSION), (EPOCH)), entry_gc_v##VERSION##_##EPOCH); + +class VersionedEntriesTest : public ::testing::Test +{ +public: + using DerefCounter = std::map>; + std::tuple runClean(UInt64 seq) + { + DerefCounter deref_counter; + PageEntriesV3 removed_entries; + bool all_removed = entries.cleanOutdatedEntries(seq, &deref_counter, &removed_entries, entries.acquireLock()); + return {all_removed, removed_entries, deref_counter}; + } + + std::tuple runDeref(UInt64 seq, PageVersion ver, Int64 decrease_num) + { + PageEntriesV3 removed_entries; + bool all_removed = entries.derefAndClean(seq, buildV3Id(TEST_NAMESPACE_ID, page_id), ver, decrease_num, &removed_entries); + return {all_removed, removed_entries}; + } + +protected: + const PageId page_id = 100; + VersionedPageEntries entries; +}; + +TEST_F(VersionedEntriesTest, InsertGet) +{ + INSERT_ENTRY(2); + INSERT_ENTRY(5); + INSERT_ENTRY(10); + + // Insert some entries with version + ASSERT_FALSE(entries.getEntry(1).has_value()); + ASSERT_SAME_ENTRY(*entries.getEntry(2), entry_v2); + ASSERT_SAME_ENTRY(*entries.getEntry(3), entry_v2); + ASSERT_SAME_ENTRY(*entries.getEntry(4), entry_v2); + for (UInt64 seq = 5; seq < 10; ++seq) + { + ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_v5); + } + for (UInt64 seq = 10; seq < 20; ++seq) + { + ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_v10); + } + + // Insert some entries with version && gc epoch + INSERT_GC_ENTRY(2, 1); + INSERT_GC_ENTRY(5, 1); + INSERT_GC_ENTRY(5, 2); + ASSERT_FALSE(entries.getEntry(1).has_value()); + ASSERT_SAME_ENTRY(*entries.getEntry(2), entry_gc_v2_1); + ASSERT_SAME_ENTRY(*entries.getEntry(3), entry_gc_v2_1); + ASSERT_SAME_ENTRY(*entries.getEntry(4), entry_gc_v2_1); + for (UInt64 seq = 5; seq < 10; ++seq) + { + ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_gc_v5_2); + } + for (UInt64 seq = 10; seq < 20; ++seq) + { + ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_v10); + } + + // Insert delete. Can not get entry with seq >= delete_version. + // But it won't affect reading with old seq. + entries.createDelete(PageVersion(15)); + ASSERT_FALSE(entries.getEntry(1).has_value()); + ASSERT_SAME_ENTRY(*entries.getEntry(2), entry_gc_v2_1); + ASSERT_SAME_ENTRY(*entries.getEntry(3), entry_gc_v2_1); + ASSERT_SAME_ENTRY(*entries.getEntry(4), entry_gc_v2_1); + for (UInt64 seq = 5; seq < 10; ++seq) + { + ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_gc_v5_2); + } + for (UInt64 seq = 10; seq < 15; ++seq) + { + ASSERT_SAME_ENTRY(*entries.getEntry(seq), entry_v10); + } + for (UInt64 seq = 15; seq < 20; ++seq) + { + ASSERT_FALSE(entries.getEntry(seq).has_value()); + } +} + +TEST_F(VersionedEntriesTest, InsertWithLowerVersion) +{ + INSERT_ENTRY(5); + ASSERT_SAME_ENTRY(*entries.getEntry(5), entry_v5); + ASSERT_FALSE(entries.getEntry(2).has_value()); + INSERT_ENTRY(2); + ASSERT_SAME_ENTRY(*entries.getEntry(2), entry_v2); +} + +TEST_F(VersionedEntriesTest, EntryIsVisible) +try +{ + // init state + ASSERT_FALSE(entries.isVisible(0)); + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_FALSE(entries.isVisible(2)); + ASSERT_FALSE(entries.isVisible(10000)); + + // insert some entries + INSERT_ENTRY(2); + INSERT_ENTRY(3); + INSERT_ENTRY(5); + + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_TRUE(entries.isVisible(2)); + ASSERT_TRUE(entries.isVisible(3)); + ASSERT_TRUE(entries.isVisible(4)); + ASSERT_TRUE(entries.isVisible(5)); + ASSERT_TRUE(entries.isVisible(6)); + + // insert delete + entries.createDelete(PageVersion(6)); + + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_TRUE(entries.isVisible(2)); + ASSERT_TRUE(entries.isVisible(3)); + ASSERT_TRUE(entries.isVisible(4)); + ASSERT_TRUE(entries.isVisible(5)); + ASSERT_FALSE(entries.isVisible(6)); + ASSERT_FALSE(entries.isVisible(10000)); + + // insert entry after delete + INSERT_ENTRY(7); + + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_TRUE(entries.isVisible(2)); + ASSERT_TRUE(entries.isVisible(3)); + ASSERT_TRUE(entries.isVisible(4)); + ASSERT_TRUE(entries.isVisible(5)); + ASSERT_FALSE(entries.isVisible(6)); + ASSERT_TRUE(entries.isVisible(7)); + ASSERT_TRUE(entries.isVisible(10000)); +} +CATCH + +TEST_F(VersionedEntriesTest, ExternalPageIsVisible) +try +{ + // init state + ASSERT_FALSE(entries.isVisible(0)); + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_FALSE(entries.isVisible(2)); + ASSERT_FALSE(entries.isVisible(10000)); + + // insert some entries + entries.createNewExternal(PageVersion(2)); + + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_TRUE(entries.isVisible(2)); + ASSERT_TRUE(entries.isVisible(10000)); + + // insert delete + entries.createDelete(PageVersion(6)); + + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_TRUE(entries.isVisible(2)); + ASSERT_TRUE(entries.isVisible(3)); + ASSERT_TRUE(entries.isVisible(4)); + ASSERT_TRUE(entries.isVisible(5)); + ASSERT_FALSE(entries.isVisible(6)); + ASSERT_FALSE(entries.isVisible(10000)); + + // insert entry after delete + entries.createNewExternal(PageVersion(7)); + + // after re-create external page, the visible for 1~5 has changed + ASSERT_FALSE(entries.isVisible(6)); + ASSERT_TRUE(entries.isVisible(7)); + ASSERT_TRUE(entries.isVisible(10000)); +} +CATCH + +TEST_F(VersionedEntriesTest, RefPageIsVisible) +try +{ + // init state + ASSERT_FALSE(entries.isVisible(0)); + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_FALSE(entries.isVisible(2)); + ASSERT_FALSE(entries.isVisible(10000)); + + // insert some entries + entries.createNewRef(PageVersion(2), buildV3Id(TEST_NAMESPACE_ID, 2)); + + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_TRUE(entries.isVisible(2)); + ASSERT_TRUE(entries.isVisible(10000)); + + // insert delete + entries.createDelete(PageVersion(6)); + + ASSERT_FALSE(entries.isVisible(1)); + ASSERT_TRUE(entries.isVisible(2)); + ASSERT_TRUE(entries.isVisible(3)); + ASSERT_TRUE(entries.isVisible(4)); + ASSERT_TRUE(entries.isVisible(5)); + ASSERT_FALSE(entries.isVisible(6)); + ASSERT_FALSE(entries.isVisible(10000)); + + // insert entry after delete + entries.createNewRef(PageVersion(7), buildV3Id(TEST_NAMESPACE_ID, 2)); + + // after re-create ref page, the visible for 1~5 has changed + ASSERT_FALSE(entries.isVisible(6)); + ASSERT_TRUE(entries.isVisible(7)); + ASSERT_TRUE(entries.isVisible(10000)); +} +CATCH + +TEST_F(VersionedEntriesTest, CleanOutdateVersions) +try +{ + // Test running gc on a single page, it should clean all + // outdated versions. + INSERT_ENTRY(2); + INSERT_GC_ENTRY(2, 1); + INSERT_ENTRY(5); + INSERT_GC_ENTRY(5, 1); + INSERT_GC_ENTRY(5, 2); + INSERT_ENTRY(10); + INSERT_ENTRY(11); + entries.createDelete(PageVersion(15)); + + // noting to be removed + auto [all_removed, removed_entries, deref_counter] = runClean(1); + ASSERT_FALSE(all_removed); + ASSERT_EQ(removed_entries.size(), 0); + ASSERT_EQ(deref_counter.size(), 0); + + // <2,0> get removed. + std::tie(all_removed, removed_entries, deref_counter) = runClean(2); + ASSERT_FALSE(all_removed); + ASSERT_EQ(removed_entries.size(), 1); + auto iter = removed_entries.begin(); + ASSERT_SAME_ENTRY(entry_v2, *iter); + ASSERT_SAME_ENTRY(entry_gc_v2_1, *entries.getEntry(2)); + ASSERT_EQ(deref_counter.size(), 0); + + // nothing get removed. + std::tie(all_removed, removed_entries, deref_counter) = runClean(4); + ASSERT_FALSE(all_removed); + ASSERT_EQ(removed_entries.size(), 0); + ASSERT_SAME_ENTRY(entry_gc_v2_1, *entries.getEntry(4)); + ASSERT_EQ(deref_counter.size(), 0); + + // <2,1>, <5,0>, <5,1>, <5,2>, <10,0> get removed. + std::tie(all_removed, removed_entries, deref_counter) = runClean(11); + ASSERT_FALSE(all_removed); + ASSERT_EQ(removed_entries.size(), 5); + iter = removed_entries.begin(); + ASSERT_SAME_ENTRY(entry_v10, *iter); + iter++; + ASSERT_SAME_ENTRY(entry_gc_v5_2, *iter); + iter++; + ASSERT_SAME_ENTRY(entry_gc_v5_1, *iter); + iter++; + ASSERT_SAME_ENTRY(entry_v5, *iter); + iter++; + ASSERT_SAME_ENTRY(entry_gc_v2_1, *iter); + ASSERT_SAME_ENTRY(entry_v11, *entries.getEntry(11)); + ASSERT_EQ(deref_counter.size(), 0); + + // <11,0> get removed, all cleared. + std::tie(all_removed, removed_entries, deref_counter) = runClean(20); + ASSERT_TRUE(all_removed); // should remove this chain + ASSERT_EQ(removed_entries.size(), 1); + ASSERT_FALSE(entries.getEntry(20)); + ASSERT_EQ(deref_counter.size(), 0); +} +CATCH + +TEST_F(VersionedEntriesTest, DeleteMultiTime) +try +{ + entries.createDelete(PageVersion(1)); + INSERT_ENTRY(2); + INSERT_GC_ENTRY(2, 1); + entries.createDelete(PageVersion(15)); + entries.createDelete(PageVersion(17)); + entries.createDelete(PageVersion(16)); + + bool all_removed; + std::map> deref_counter; + PageEntriesV3 removed_entries; + + // <2,0> get removed. + std::tie(all_removed, removed_entries, deref_counter) = runClean(2); + ASSERT_FALSE(all_removed); + ASSERT_EQ(removed_entries.size(), 1); + auto iter = removed_entries.begin(); + ASSERT_SAME_ENTRY(entry_v2, *iter); + ASSERT_SAME_ENTRY(entry_gc_v2_1, *entries.getEntry(2)); + ASSERT_EQ(deref_counter.size(), 0); + + // clear all + std::tie(all_removed, removed_entries, deref_counter) = runClean(20); + ASSERT_EQ(removed_entries.size(), 1); + ASSERT_TRUE(all_removed); // should remove this chain + ASSERT_FALSE(entries.getEntry(20)); + ASSERT_EQ(deref_counter.size(), 0); +} +CATCH + +TEST_F(VersionedEntriesTest, DontCleanWhenBeingRef) +try +{ + bool all_removed; + std::map> deref_counter; + PageEntriesV3 removed_entries; + + INSERT_ENTRY(2); + entries.incrRefCount(PageVersion(2)); + entries.incrRefCount(PageVersion(2)); + entries.createDelete(PageVersion(5)); + + // <2, 0> is not available after seq=5, but not get removed + ASSERT_SAME_ENTRY(entry_v2, *entries.getEntry(4)); + ASSERT_FALSE(entries.getEntry(5)); + + // <2, 0> is not removed since it's being ref + std::tie(all_removed, removed_entries, deref_counter) = runClean(5); + ASSERT_FALSE(all_removed); + ASSERT_EQ(removed_entries.size(), 0); + ASSERT_FALSE(entries.getEntry(5)); + ASSERT_EQ(deref_counter.size(), 0); + + // decrease 1 ref counting + std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 1); + ASSERT_EQ(removed_entries.size(), 0); + ASSERT_FALSE(all_removed); // should not remove this chain + ASSERT_FALSE(entries.getEntry(5)); + + // clear all + std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 1); + ASSERT_EQ(removed_entries.size(), 1); + ASSERT_SAME_ENTRY(removed_entries[0], entry_v2); + ASSERT_TRUE(all_removed); // should remove this chain + ASSERT_FALSE(entries.getEntry(5)); +} +CATCH + +TEST_F(VersionedEntriesTest, DontCleanWhenBeingRef2) +try +{ + bool all_removed; + std::map> deref_counter; + PageEntriesV3 removed_entries; + + INSERT_ENTRY(2); + entries.incrRefCount(PageVersion(2)); + entries.incrRefCount(PageVersion(2)); + entries.createDelete(PageVersion(5)); + + // <2, 0> is not available after seq=5, but not get removed + ASSERT_SAME_ENTRY(entry_v2, *entries.getEntry(4)); + ASSERT_FALSE(entries.getEntry(5)); + + // <2, 0> is not removed since it's being ref + std::tie(all_removed, removed_entries, deref_counter) = runClean(5); + ASSERT_FALSE(all_removed); + ASSERT_EQ(removed_entries.size(), 0); + ASSERT_FALSE(entries.getEntry(5)); + ASSERT_EQ(deref_counter.size(), 0); + + // clear all + std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 2); + ASSERT_EQ(removed_entries.size(), 1); + ASSERT_SAME_ENTRY(removed_entries[0], entry_v2); + ASSERT_TRUE(all_removed); // should remove this chain + ASSERT_FALSE(entries.getEntry(5)); +} +CATCH + +TEST_F(VersionedEntriesTest, CleanDuplicatedWhenBeingRefAndAppliedUpsert) +try +{ + bool all_removed; + std::map> deref_counter; + PageEntriesV3 removed_entries; + + INSERT_ENTRY(2); + entries.incrRefCount(PageVersion(2)); + entries.incrRefCount(PageVersion(2)); + INSERT_GC_ENTRY(2, 1); + INSERT_GC_ENTRY(2, 2); + + // <2, 2> + ASSERT_SAME_ENTRY(entry_gc_v2_2, *entries.getEntry(4)); + + // <2, 2> is not removed since it's being ref, but <2,0> <2,1> is removed since they are replaced by newer version + std::tie(all_removed, removed_entries, deref_counter) = runClean(5); + ASSERT_FALSE(all_removed); + ASSERT_EQ(removed_entries.size(), 2); + ASSERT_SAME_ENTRY(removed_entries[0], entry_gc_v2_1); + ASSERT_SAME_ENTRY(removed_entries[1], entry_v2); + ASSERT_SAME_ENTRY(entry_gc_v2_2, *entries.getEntry(4)); + ASSERT_EQ(deref_counter.size(), 0); + + // clear all + std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 2); + ASSERT_EQ(removed_entries.size(), 0); + ASSERT_FALSE(all_removed); // should not remove this chain + ASSERT_SAME_ENTRY(entry_gc_v2_2, *entries.getEntry(4)); +} +CATCH + +TEST_F(VersionedEntriesTest, CleanDuplicatedWhenBeingRefAndAppliedUpsert2) +try +{ + bool all_removed; + std::map> deref_counter; + PageEntriesV3 removed_entries; + + INSERT_ENTRY(2); + entries.incrRefCount(PageVersion(2)); + entries.incrRefCount(PageVersion(2)); + INSERT_GC_ENTRY(2, 1); + INSERT_GC_ENTRY(2, 2); + entries.createDelete(PageVersion(5)); + + // <2, 2> is not available after seq=5, but not get removed + ASSERT_SAME_ENTRY(entry_gc_v2_2, *entries.getEntry(4)); + ASSERT_FALSE(entries.getEntry(5)); + + // <2, 2> is not removed since it's being ref, but <2,0> <2,1> is removed since they are replaced by newer version + std::tie(all_removed, removed_entries, deref_counter) = runClean(5); + ASSERT_FALSE(all_removed); + ASSERT_EQ(removed_entries.size(), 2); + ASSERT_SAME_ENTRY(removed_entries[0], entry_gc_v2_1); + ASSERT_SAME_ENTRY(removed_entries[1], entry_v2); + ASSERT_FALSE(entries.getEntry(5)); + ASSERT_EQ(deref_counter.size(), 0); + + // clear all + std::tie(all_removed, removed_entries) = runDeref(5, PageVersion(2), 2); + ASSERT_EQ(removed_entries.size(), 1); + ASSERT_SAME_ENTRY(removed_entries[0], entry_gc_v2_2); + ASSERT_TRUE(all_removed); // should remove this chain + ASSERT_FALSE(entries.getEntry(5)); +} +CATCH + +TEST_F(VersionedEntriesTest, ReadAfterGcApplied) +try +{ + bool all_removed; + std::map> deref_counter; + PageEntriesV3 removed_entries; + + INSERT_ENTRY(2); + INSERT_ENTRY(3); + INSERT_ENTRY(5); + + // Read with snapshot seq=2 + ASSERT_SAME_ENTRY(entry_v2, *entries.getEntry(2)); + + // Mock that gc applied and insert <2, 1> + INSERT_GC_ENTRY(2, 1); + + // Now we should read the entry <2, 1> with seq=2 + ASSERT_SAME_ENTRY(entry_gc_v2_1, *entries.getEntry(2)); + + // <2,0> get removed + std::tie(all_removed, removed_entries, deref_counter) = runClean(2); + ASSERT_EQ(removed_entries.size(), 1); +} +CATCH + +TEST_F(VersionedEntriesTest, getEntriesByBlobId) +{ + INSERT_BLOBID_ENTRY(1, 1); + INSERT_BLOBID_ENTRY(1, 2); + INSERT_BLOBID_ENTRY(2, 3); + INSERT_BLOBID_ENTRY(2, 4); + INSERT_BLOBID_ENTRY(1, 5); + INSERT_BLOBID_ENTRY(3, 6); + INSERT_BLOBID_ENTRY(3, 8); + INSERT_BLOBID_ENTRY(1, 11); + + PageId page_id = 100; + auto check_for_blob_id_1 = [&](const PageIdAndVersionedEntries & entries) { + auto it = entries.begin(); + + ASSERT_EQ(std::get<0>(*it).low, page_id); + ASSERT_EQ(std::get<1>(*it).sequence, 1); + ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v1); + + it++; + ASSERT_EQ(std::get<0>(*it).low, page_id); + ASSERT_EQ(std::get<1>(*it).sequence, 2); + ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v2); + + it++; + ASSERT_EQ(std::get<0>(*it).low, page_id); + ASSERT_EQ(std::get<1>(*it).sequence, 5); + ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v5); + + it++; + ASSERT_EQ(std::get<0>(*it).low, page_id); + ASSERT_EQ(std::get<1>(*it).sequence, 11); + ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v11); + }; + auto check_for_blob_id_2 = [&](const PageIdAndVersionedEntries & entries) { + auto it = entries.begin(); + + ASSERT_EQ(std::get<0>(*it).low, page_id); + ASSERT_EQ(std::get<1>(*it).sequence, 3); + ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v3); + + it++; + ASSERT_EQ(std::get<0>(*it).low, page_id); + ASSERT_EQ(std::get<1>(*it).sequence, 4); + ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v4); + }; + auto check_for_blob_id_3 = [&](const PageIdAndVersionedEntries & entries) { + auto it = entries.begin(); + + ASSERT_EQ(std::get<0>(*it).low, page_id); + ASSERT_EQ(std::get<1>(*it).sequence, 6); + ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v6); + + it++; + ASSERT_EQ(std::get<0>(*it).low, page_id); + ASSERT_EQ(std::get<1>(*it).sequence, 8); + ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v8); + }; + + { + std::map blob_entries; + PageSize total_size = entries.getEntriesByBlobIds({/*empty*/}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); + + ASSERT_EQ(blob_entries.size(), 0); + ASSERT_EQ(total_size, 0); + } + + { + std::map blob_entries; + const BlobFileId blob_id = 1; + PageSize total_size = entries.getEntriesByBlobIds({blob_id}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); + + ASSERT_EQ(blob_entries.size(), 1); + ASSERT_EQ(blob_entries[blob_id].size(), 4); + ASSERT_EQ(total_size, 1 + 2 + 5 + 11); + check_for_blob_id_1(blob_entries[blob_id]); + } + + { + std::map blob_entries; + const BlobFileId blob_id = 2; + PageSize total_size = entries.getEntriesByBlobIds({blob_id}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); + + ASSERT_EQ(blob_entries.size(), 1); + ASSERT_EQ(blob_entries[blob_id].size(), 2); + ASSERT_EQ(total_size, 3 + 4); + check_for_blob_id_2(blob_entries[blob_id]); + } + + { + std::map blob_entries; + const BlobFileId blob_id = 3; + PageSize total_size = entries.getEntriesByBlobIds({blob_id}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); + + ASSERT_EQ(blob_entries.size(), 1); + ASSERT_EQ(blob_entries[blob_id].size(), 2); + ASSERT_EQ(total_size, 6 + 8); + check_for_blob_id_3(blob_entries[blob_id]); + } + + // {1, 2} + { + std::map blob_entries; + PageSize total_size = entries.getEntriesByBlobIds({1, 2}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); + + ASSERT_EQ(blob_entries.size(), 2); + ASSERT_EQ(blob_entries[1].size(), 4); + ASSERT_EQ(blob_entries[2].size(), 2); + ASSERT_EQ(total_size, (1 + 2 + 5 + 11) + (3 + 4)); + check_for_blob_id_1(blob_entries[1]); + check_for_blob_id_2(blob_entries[2]); + } + + // {2, 3} + { + std::map blob_entries; + PageSize total_size = entries.getEntriesByBlobIds({3, 2}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); + + ASSERT_EQ(blob_entries.size(), 2); + ASSERT_EQ(blob_entries[2].size(), 2); + ASSERT_EQ(blob_entries[3].size(), 2); + ASSERT_EQ(total_size, (6 + 8) + (3 + 4)); + check_for_blob_id_2(blob_entries[2]); + check_for_blob_id_3(blob_entries[3]); + } + + // {1, 2, 3} + { + std::map blob_entries; + PageSize total_size = entries.getEntriesByBlobIds({1, 3, 2}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); + + ASSERT_EQ(blob_entries.size(), 3); + ASSERT_EQ(blob_entries[1].size(), 4); + ASSERT_EQ(blob_entries[2].size(), 2); + ASSERT_EQ(blob_entries[3].size(), 2); + ASSERT_EQ(total_size, (1 + 2 + 5 + 11) + (6 + 8) + (3 + 4)); + check_for_blob_id_1(blob_entries[1]); + check_for_blob_id_2(blob_entries[2]); + check_for_blob_id_3(blob_entries[3]); + } + + // {1, 2, 3, 100}; blob_id 100 is not exist in actual + { + std::map blob_entries; + PageSize total_size = entries.getEntriesByBlobIds({1, 3, 2, 4}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); + + ASSERT_EQ(blob_entries.size(), 3); // 100 not exist + ASSERT_EQ(blob_entries.find(100), blob_entries.end()); + ASSERT_EQ(blob_entries[1].size(), 4); + ASSERT_EQ(blob_entries[2].size(), 2); + ASSERT_EQ(blob_entries[3].size(), 2); + ASSERT_EQ(total_size, (1 + 2 + 5 + 11) + (6 + 8) + (3 + 4)); + check_for_blob_id_1(blob_entries[1]); + check_for_blob_id_2(blob_entries[2]); + check_for_blob_id_3(blob_entries[3]); + } +} + +#undef INSERT_BLOBID_ENTRY +#undef INSERT_ENTRY +#undef INSERT_GC_ENTRY + +} // namespace PS::V3::tests +} // namespace DB diff --git a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp index 782d08fe6d9..f85c905520f 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp @@ -302,12 +302,22 @@ class WALStoreTest } } +protected: + static void applyWithSameVersion(WALStorePtr & wal, PageEntriesEdit & edit, const PageVersion & version) + { + for (auto & r : edit.getMutRecords()) + { + r.version = version; + } + wal->apply(ser::serializeTo(edit)); + } + private: const bool multi_paths; protected: PSDiskDelegatorPtr delegator; - WALStore::Config config; + WALConfig config; LoggerPtr log; }; @@ -413,7 +423,7 @@ try edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_p1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_p2); size_each_edit.emplace_back(edit.size()); - wal->apply(edit, ver20); + applyWithSameVersion(wal, edit, ver20); } wal.reset(); @@ -446,7 +456,7 @@ try edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_p5); edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); size_each_edit.emplace_back(edit.size()); - wal->apply(edit, ver21); + applyWithSameVersion(wal, edit, ver21); } wal.reset(); @@ -481,7 +491,7 @@ try edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 3), ver21_1, entry_p3_2); edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 5), ver21_1, entry_p5_2); size_each_edit.emplace_back(edit.size()); - wal->apply(edit); + wal->apply(ser::serializeTo(edit)); } wal.reset(); @@ -525,7 +535,7 @@ try edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_p1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_p2); size_each_edit.emplace_back(edit.size()); - wal->apply(edit, ver20); + applyWithSameVersion(wal, edit, ver20); } // Stage 2. Apply with puts and refs @@ -539,7 +549,7 @@ try edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_p5); edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); size_each_edit.emplace_back(edit.size()); - wal->apply(edit, ver21); + applyWithSameVersion(wal, edit, ver21); } // Stage 3. Apply with delete and upsert @@ -554,7 +564,7 @@ try edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 3), ver21_1, entry_p3_2); edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 5), ver21_1, entry_p5_2); size_each_edit.emplace_back(edit.size()); - wal->apply(edit); + wal->apply(ser::serializeTo(edit)); } wal.reset(); @@ -629,7 +639,7 @@ try entry.size = page_id; edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry); } - wal->apply(edit, ver); + applyWithSameVersion(wal, edit, ver); size_each_edit.emplace_back(num_pages_put); ver.sequence += 1; @@ -662,7 +672,7 @@ try // Test for save snapshot (with encryption) LogFilenameSet persisted_log_files = WALStoreReader::listAllFiles(delegator, log); - WALStore::FilesSnapshot file_snap{.current_writting_log_num = 100, // just a fake value + WALStore::FilesSnapshot file_snap{.current_writing_log_num = 100, // just a fake value .persisted_log_files = persisted_log_files}; PageEntriesEdit snap_edit; @@ -674,7 +684,7 @@ try snap_edit.varEntry(buildV3Id(TEST_NAMESPACE_ID, d_10000(rd)), PageVersion(345, 22), entry, 1); } std::tie(wal, reader) = WALStore::create(getCurrentTestName(), enc_provider, delegator, config); - bool done = wal->saveSnapshot(std::move(file_snap), std::move(snap_edit)); + bool done = wal->saveSnapshot(std::move(file_snap), ser::serializeTo(snap_edit), snap_edit.size()); ASSERT_TRUE(done); wal.reset(); reader.reset(); diff --git a/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp b/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp index c9b871c67d2..026ad7a633d 100644 --- a/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp +++ b/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp @@ -62,11 +62,17 @@ ControlOptions ControlOptions::parse(int argc, char ** argv) po::options_description desc("Allowed options"); desc.add_options()("help,h", "produce help message") // ("paths,P", value>(), "store path(s)") // - ("display_mode,D", value()->default_value(1), "Display Mode: 1 is summary information,\n 2 is display all of stored page and version chaim(will be very long),\n 3 is display all blobs(in disk) data distribution. \n 4 is check every data is valid.") // + ("display_mode,D", value()->default_value(1), "Display Mode: 1 is summary information,\n" + " 2 is display all of stored page and version chain(will be very long),\n" + " 3 is display all blobs(in disk) data distribution. \n" + " 4 is check every data is valid.") // ("enable_fo_check,E", value()->default_value(true), "Also check the evert field offsets. This options only works when `display_mode` is 4.") // - ("query_ns_id,N", value()->default_value(DB::TEST_NAMESPACE_ID), "When used `check_page_id`/`query_page_id`/`query_blob_id` to query results. You can specify a namespace id.")("check_page_id,C", value()->default_value(UINT64_MAX), "Check a single Page id, display the exception if meet. And also will check the field offsets.") // - ("query_page_id,W", value()->default_value(UINT64_MAX), "Query a single Page id, and print its version chaim.") // - ("query_blob_id,B", value()->default_value(UINT32_MAX), "Query a single Blob id, and print its data distribution.")("imitative,I", value()->default_value(true), "Use imitative context instead. (encryption is not supported in this mode so that no need to set config_file_path)")("config_file_path", value(), "Path to TiFlash config (tiflash.toml)."); + ("query_ns_id,N", value()->default_value(DB::TEST_NAMESPACE_ID), "When used `check_page_id`/`query_page_id`/`query_blob_id` to query results. You can specify a namespace id.") // + ("check_page_id,C", value()->default_value(UINT64_MAX), "Check a single Page id, display the exception if meet. And also will check the field offsets.") // + ("query_page_id,W", value()->default_value(UINT64_MAX), "Query a single Page id, and print its version chain.") // + ("query_blob_id,B", value()->default_value(UINT32_MAX), "Query a single Blob id, and print its data distribution.") // + ("imitative,I", value()->default_value(true), "Use imitative context instead. (encryption is not supported in this mode so that no need to set config_file_path)") // + ("config_file_path", value(), "Path to TiFlash config (tiflash.toml)."); static_assert(sizeof(DB::PageId) == sizeof(UInt64)); @@ -177,7 +183,7 @@ class PageStorageControlV3 { file_provider_ptr = context.getFileProvider(); } - BlobStore::Config blob_config; + BlobConfig blob_config; PageStorage::Config config; PageStorageImpl ps_v3("PageStorageControlV3", delegator, config, file_provider_ptr); @@ -209,7 +215,7 @@ class PageStorageControlV3 } else { - std::cout << checkAllDatasCrc(mvcc_table_directory, ps_v3.blob_store, options.enable_fo_check) << std::endl; + std::cout << checkAllDataCrc(mvcc_table_directory, ps_v3.blob_store, options.enable_fo_check) << std::endl; } break; } @@ -222,7 +228,7 @@ class PageStorageControlV3 static String getBlobsInfo(BlobStore & blob_store, UInt32 blob_id) { - auto stat_info = [](const BlobStore::BlobStats::BlobStatPtr & stat, const String & path) { + auto stat_info = [](const BlobStats::BlobStatPtr & stat, const String & path) { FmtBuffer stat_str; stat_str.fmtAppend(" stat id: {}\n" " path: {}\n" @@ -438,7 +444,7 @@ class PageStorageControlV3 return error_msg.toString(); } - static String checkAllDatasCrc(PageDirectory::MVCCMapType & mvcc_table_directory, BlobStore & blob_store, bool enable_fo_check) + static String checkAllDataCrc(PageDirectory::MVCCMapType & mvcc_table_directory, BlobStore & blob_store, bool enable_fo_check) { size_t total_pages = mvcc_table_directory.size(); size_t cut_index = 0; From 3030743ea5ea0f9a667d7bc8a9ae15adcbccd449 Mon Sep 17 00:00:00 2001 From: JaySon Date: Fri, 14 Oct 2022 18:39:52 +0800 Subject: [PATCH 05/40] PageStorage: Refactor config (#6138) ref pingcap/tiflash#6071 --- dbms/src/Server/tests/gtest_server_config.cpp | 2 +- dbms/src/Storages/DeltaMerge/StoragePool.cpp | 4 +- dbms/src/Storages/DeltaMerge/WriteBatches.h | 8 +- dbms/src/Storages/Page/Config.cpp | 28 ++++ dbms/src/Storages/Page/Config.h | 126 ++++++++++++++++- dbms/src/Storages/Page/ConfigSettings.cpp | 6 +- dbms/src/Storages/Page/ConfigSettings.h | 4 +- dbms/src/Storages/Page/Page.h | 42 +++--- dbms/src/Storages/Page/PageDefines.h | 6 + dbms/src/Storages/Page/PageStorage.cpp | 14 +- dbms/src/Storages/Page/PageStorage.h | 133 ++---------------- dbms/src/Storages/Page/V2/PageFile.cpp | 70 ++++----- dbms/src/Storages/Page/V2/PageStorage.cpp | 16 +-- dbms/src/Storages/Page/V2/PageStorage.h | 6 +- .../Page/V2/VersionSet/PageEntriesBuilder.cpp | 10 +- .../Page/V2/VersionSet/PageEntriesBuilder.h | 19 ++- .../Page/V2/VersionSet/PageEntriesEdit.h | 10 +- .../PageEntriesVersionSetWithDelta.cpp | 26 ++-- .../src/Storages/Page/V2/gc/DataCompactor.cpp | 2 +- dbms/src/Storages/Page/V2/gc/DataCompactor.h | 4 +- .../src/Storages/Page/V2/gc/LegacyCompactor.h | 2 +- .../Page/V2/tests/gtest_data_compactor.cpp | 4 +- .../Page/V2/tests/gtest_legacy_compactor.cpp | 8 +- .../Page/V2/tests/gtest_page_file.cpp | 10 +- .../Page/V2/tests/gtest_page_storage.cpp | 14 +- .../tests/gtest_page_storage_multi_paths.cpp | 2 +- .../gtest_page_storage_multi_writers.cpp | 6 +- .../test_page_storage_write_disk_full.cpp | 2 +- dbms/src/Storages/Page/V3/Blob/BlobConfig.h | 14 ++ dbms/src/Storages/Page/V3/BlobStore.cpp | 90 ++++++------ dbms/src/Storages/Page/V3/BlobStore.h | 3 + dbms/src/Storages/Page/V3/PageEntry.h | 5 - dbms/src/Storages/Page/V3/PageStorageImpl.cpp | 9 +- dbms/src/Storages/Page/V3/PageStorageImpl.h | 26 +--- dbms/src/Storages/Page/V3/WAL/WALConfig.h | 11 ++ .../Page/V3/tests/gtest_page_storage.cpp | 20 +-- dbms/src/Storages/Page/WriteBatch.h | 104 +++++++++----- .../Page/tools/PageCtl/PageStorageCtlV2.cpp | 20 +-- .../Page/tools/PageCtl/PageStorageCtlV3.cpp | 2 +- .../Page/workload/HeavyMemoryCostInGC.h | 2 +- dbms/src/Storages/Page/workload/HeavyRead.h | 4 +- .../Page/workload/HeavySkewWriteRead.h | 4 +- dbms/src/Storages/Page/workload/HeavyWrite.h | 4 +- .../Page/workload/HighValidBigFileGC.h | 6 +- .../Page/workload/HoldSnapshotsLongTime.h | 4 +- dbms/src/Storages/Page/workload/Normal.h | 2 +- .../src/Storages/Page/workload/PSWorkload.cpp | 2 +- dbms/src/Storages/Page/workload/PSWorkload.h | 2 +- .../workload/PageStorageInMemoryCapacity.h | 4 +- .../Page/workload/ThousandsOfOffset.h | 4 +- .../Storages/Transaction/RegionPersister.cpp | 8 +- .../Storages/Transaction/RegionPersister.h | 4 +- .../tests/gtest_region_persister.cpp | 4 +- 53 files changed, 506 insertions(+), 436 deletions(-) create mode 100644 dbms/src/Storages/Page/Config.cpp diff --git a/dbms/src/Server/tests/gtest_server_config.cpp b/dbms/src/Server/tests/gtest_server_config.cpp index b069c981bf9..a241df04b00 100644 --- a/dbms/src/Server/tests/gtest_server_config.cpp +++ b/dbms/src/Server/tests/gtest_server_config.cpp @@ -289,7 +289,7 @@ dt_page_gc_low_write_prob = 0.2 auto & global_path_pool = global_ctx.getPathPool(); RegionManager region_manager; RegionPersister persister(global_ctx, region_manager); - persister.restore(global_path_pool, nullptr, PageStorage::Config{}); + persister.restore(global_path_pool, nullptr, PageStorageConfig{}); auto verify_persister_reload_config = [&global_ctx](RegionPersister & persister) { DB::Settings & settings = global_ctx.getSettingsRef(); diff --git a/dbms/src/Storages/DeltaMerge/StoragePool.cpp b/dbms/src/Storages/DeltaMerge/StoragePool.cpp index fbe6ab681d8..88e1ee8cdfe 100644 --- a/dbms/src/Storages/DeltaMerge/StoragePool.cpp +++ b/dbms/src/Storages/DeltaMerge/StoragePool.cpp @@ -54,7 +54,7 @@ enum class StorageType Meta = 3, }; -PageStorage::Config extractConfig(const Settings & settings, StorageType subtype) +PageStorageConfig extractConfig(const Settings & settings, StorageType subtype) { #define SET_CONFIG(NAME) \ config.num_write_slots = settings.dt_storage_pool_##NAME##_write_slots; \ @@ -64,7 +64,7 @@ PageStorage::Config extractConfig(const Settings & settings, StorageType subtype config.gc_max_valid_rate = settings.dt_storage_pool_##NAME##_gc_max_valid_rate; \ config.blob_heavy_gc_valid_rate = settings.dt_page_gc_threshold; - PageStorage::Config config = getConfigFromSettings(settings); + PageStorageConfig config = getConfigFromSettings(settings); switch (subtype) { diff --git a/dbms/src/Storages/DeltaMerge/WriteBatches.h b/dbms/src/Storages/DeltaMerge/WriteBatches.h index 2b508fed068..ef2209586da 100644 --- a/dbms/src/Storages/DeltaMerge/WriteBatches.h +++ b/dbms/src/Storages/DeltaMerge/WriteBatches.h @@ -97,7 +97,7 @@ struct WriteBatches : private boost::noncopyable return; for (const auto & w : wb.getWrites()) { - if (unlikely(w.type == WriteBatch::WriteType::DEL)) + if (unlikely(w.type == WriteBatchWriteType::DEL)) throw Exception("Unexpected deletes in " + what); } LOG_FMT_TRACE(logger, "Write into {} : {}", what, wb.toString()); @@ -142,7 +142,7 @@ struct WriteBatches : private boost::noncopyable return; for (const auto & w : wb.getWrites()) { - if (unlikely(w.type != WriteBatch::WriteType::DEL)) + if (unlikely(w.type != WriteBatchWriteType::DEL)) throw Exception("Expected deletes in " + what); } LOG_FMT_TRACE(logger, "Rollback remove from {} : {}", what, wb.toString()); @@ -170,7 +170,7 @@ struct WriteBatches : private boost::noncopyable return; for (const auto & w : wb.getWrites()) { - if (unlikely(w.type != WriteBatch::WriteType::PUT)) + if (unlikely(w.type != WriteBatchWriteType::PUT)) throw Exception("Expected puts in " + what); } LOG_FMT_TRACE(logger, "Write into {} : {}", what, wb.toString()); @@ -194,7 +194,7 @@ struct WriteBatches : private boost::noncopyable return; for (const auto & w : wb.getWrites()) { - if (unlikely(w.type != WriteBatch::WriteType::DEL)) + if (unlikely(w.type != WriteBatchWriteType::DEL)) throw Exception("Expected deletes in " + what); } LOG_FMT_TRACE(logger, "Write into {} : {}", what, wb.toString()); diff --git a/dbms/src/Storages/Page/Config.cpp b/dbms/src/Storages/Page/Config.cpp new file mode 100644 index 00000000000..01e3db1ef32 --- /dev/null +++ b/dbms/src/Storages/Page/Config.cpp @@ -0,0 +1,28 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +namespace DB +{ +namespace MVCC +{ +bool VersionSetConfig::doCleanup() const +{ + return PageUtil::randInt(0, 1000) < prob_cleanup_invalid_snapshot; +} +} // namespace MVCC + +} // namespace DB diff --git a/dbms/src/Storages/Page/Config.h b/dbms/src/Storages/Page/Config.h index 8b5a62656a1..21d50d7fefe 100644 --- a/dbms/src/Storages/Page/Config.h +++ b/dbms/src/Storages/Page/Config.h @@ -14,13 +14,15 @@ #pragma once -// todo move this util into other dir #include -#include +#include +#include -namespace DB::MVCC +namespace DB { -// MVCC config +namespace MVCC +{ +// V2 MVCC config struct VersionSetConfig { size_t compact_hint_delta_deletions = 5000; @@ -35,10 +37,122 @@ struct VersionSetConfig prob_cleanup_invalid_snapshot = prob; } - bool doCleanup() const { return PageUtil::randInt(0, 1000) < prob_cleanup_invalid_snapshot; } + bool doCleanup() const; private: // Probability to cleanup invalid snapshots. 10 out of 1000 by default. size_t prob_cleanup_invalid_snapshot = 10; }; -} // namespace DB::MVCC \ No newline at end of file +} // namespace MVCC + +struct PageStorageConfig +{ + //========================================================================================== + // V2 config + //========================================================================================== + SettingBool sync_on_write = true; + + SettingUInt64 file_roll_size = PAGE_FILE_ROLL_SIZE; + SettingUInt64 file_max_size = PAGE_FILE_MAX_SIZE; + SettingUInt64 file_small_size = PAGE_FILE_SMALL_SIZE; + + SettingUInt64 file_meta_roll_size = PAGE_META_ROLL_SIZE; + + // When the value of gc_force_hardlink_rate is less than or equal to 1, + // It means that candidates whose valid rate is greater than this value will be forced to hardlink(This will reduce the gc duration). + // Otherwise, if gc_force_hardlink_rate is greater than 1, hardlink won't happen + SettingDouble gc_force_hardlink_rate = 2; + + SettingDouble gc_max_valid_rate = 0.35; + SettingUInt64 gc_min_bytes = PAGE_FILE_ROLL_SIZE; + SettingUInt64 gc_min_files = 10; + // Minimum number of legacy files to be selected for compaction + SettingUInt64 gc_min_legacy_num = 3; + + SettingUInt64 gc_max_expect_legacy_files = 100; + SettingDouble gc_max_valid_rate_bound = 1.0; + + // Maximum write concurrency. Must not be changed once the PageStorage object is created. + SettingUInt64 num_write_slots = 1; + + // Maximum seconds of reader / writer idle time. + // 0 for never reclaim idle file descriptor. + SettingUInt64 open_file_max_idle_time = 15; + + // Probability to do gc when write is low. + // The probability is `prob_do_gc_when_write_is_low` out of 1000. + SettingUInt64 prob_do_gc_when_write_is_low = 10; + + MVCC::VersionSetConfig version_set_config; + + //========================================================================================== + // V3 config + //========================================================================================== + SettingUInt64 blob_file_limit_size = BLOBFILE_LIMIT_SIZE; + SettingUInt64 blob_spacemap_type = 2; + SettingUInt64 blob_cached_fd_size = BLOBSTORE_CACHED_FD_SIZE; + SettingDouble blob_heavy_gc_valid_rate = 0.5; + SettingUInt64 blob_block_alignment_bytes = 0; + + SettingUInt64 wal_roll_size = PAGE_META_ROLL_SIZE; + SettingUInt64 wal_max_persisted_log_files = MAX_PERSISTED_LOG_FILES; + + void reload(const PageStorageConfig & rhs) + { + // Reload is not atomic, but should be good enough + + // Reload gc threshold + gc_force_hardlink_rate = rhs.gc_force_hardlink_rate; + gc_max_valid_rate = rhs.gc_max_valid_rate; + gc_min_bytes = rhs.gc_min_bytes; + gc_min_files = rhs.gc_min_files; + gc_min_legacy_num = rhs.gc_min_legacy_num; + prob_do_gc_when_write_is_low = rhs.prob_do_gc_when_write_is_low; + // Reload fd idle time + open_file_max_idle_time = rhs.open_file_max_idle_time; + + // Reload V3 setting + blob_file_limit_size = rhs.blob_file_limit_size; + blob_spacemap_type = rhs.blob_spacemap_type; + blob_cached_fd_size = rhs.blob_cached_fd_size; + blob_heavy_gc_valid_rate = rhs.blob_heavy_gc_valid_rate; + blob_block_alignment_bytes = rhs.blob_block_alignment_bytes; + + wal_roll_size = rhs.wal_roll_size; + wal_max_persisted_log_files = rhs.wal_max_persisted_log_files; + } + + String toDebugStringV2() const + { + return fmt::format( + "PageStorageConfig {{gc_min_files: {}, gc_min_bytes:{}, gc_force_hardlink_rate: {:.3f}, gc_max_valid_rate: {:.3f}, " + "gc_min_legacy_num: {}, gc_max_expect_legacy: {}, gc_max_valid_rate_bound: {:.3f}, prob_do_gc_when_write_is_low: {}, " + "open_file_max_idle_time: {}}}", + gc_min_files, + gc_min_bytes, + gc_force_hardlink_rate.get(), + gc_max_valid_rate.get(), + gc_min_legacy_num, + gc_max_expect_legacy_files.get(), + gc_max_valid_rate_bound.get(), + prob_do_gc_when_write_is_low, + open_file_max_idle_time); + } + + String toDebugStringV3() const + { + return fmt::format( + "PageStorageConfig V3 {{" + "blob_file_limit_size: {}, blob_spacemap_type: {}, " + "blob_cached_fd_size: {}, blob_heavy_gc_valid_rate: {:.3f}, blob_block_alignment_bytes: {}, " + "wal_roll_size: {}, wal_max_persisted_log_files: {}}}", + blob_file_limit_size.get(), + blob_spacemap_type.get(), + blob_cached_fd_size.get(), + blob_heavy_gc_valid_rate.get(), + blob_block_alignment_bytes.get(), + wal_roll_size.get(), + wal_max_persisted_log_files.get()); + } +}; +} // namespace DB diff --git a/dbms/src/Storages/Page/ConfigSettings.cpp b/dbms/src/Storages/Page/ConfigSettings.cpp index f6fc7054cf9..ac405d98c98 100644 --- a/dbms/src/Storages/Page/ConfigSettings.cpp +++ b/dbms/src/Storages/Page/ConfigSettings.cpp @@ -17,7 +17,7 @@ namespace DB { -void mergeConfigFromSettings(const DB::Settings & settings, PageStorage::Config & config) +void mergeConfigFromSettings(const DB::Settings & settings, PageStorageConfig & config) { config.open_file_max_idle_time = settings.dt_open_file_max_idle_seconds; @@ -38,9 +38,9 @@ void mergeConfigFromSettings(const DB::Settings & settings, PageStorage::Config config.blob_heavy_gc_valid_rate = settings.dt_page_gc_threshold; } -PageStorage::Config getConfigFromSettings(const DB::Settings & settings) +PageStorageConfig getConfigFromSettings(const DB::Settings & settings) { - PageStorage::Config config; + PageStorageConfig config; mergeConfigFromSettings(settings, config); return config; } diff --git a/dbms/src/Storages/Page/ConfigSettings.h b/dbms/src/Storages/Page/ConfigSettings.h index 096aec6606e..9c9e6e99c24 100644 --- a/dbms/src/Storages/Page/ConfigSettings.h +++ b/dbms/src/Storages/Page/ConfigSettings.h @@ -20,8 +20,8 @@ namespace DB { struct Settings; -void mergeConfigFromSettings(const DB::Settings & settings, PageStorage::Config & config); +void mergeConfigFromSettings(const DB::Settings & settings, PageStorageConfig & config); -PageStorage::Config getConfigFromSettings(const DB::Settings & settings); +PageStorageConfig getConfigFromSettings(const DB::Settings & settings); } // namespace DB diff --git a/dbms/src/Storages/Page/Page.h b/dbms/src/Storages/Page/Page.h index 5328490e5ad..3fe8cb8f060 100644 --- a/dbms/src/Storages/Page/Page.h +++ b/dbms/src/Storages/Page/Page.h @@ -32,38 +32,48 @@ inline MemHolder createMemHolder(char * memory, const std::function(memory, free); } +struct FieldOffsetInsidePage +{ + size_t index; + size_t offset; + + FieldOffsetInsidePage(size_t index_) // NOLINT(google-explicit-constructor) + : index(index_) + , offset(0) + {} + FieldOffsetInsidePage(size_t index_, size_t offset_) + : index(index_) + , offset(offset_) + {} + + bool operator<(const FieldOffsetInsidePage & rhs) const { return index < rhs.index; } +}; + struct Page { public: - struct FieldOffset + // only take the low u64, ignoring the high u64(NamespaceId) + explicit Page(const PageIdV3Internal & page_id_v3_) + : page_id(page_id_v3_.low) { - size_t index; - size_t offset; - - FieldOffset(size_t index_) // NOLINT(google-explicit-constructor) - : index(index_) - , offset(0) - {} - FieldOffset(size_t index_, size_t offset_) - : index(index_) - , offset(offset_) - {} + } - bool operator<(const FieldOffset & rhs) const { return index < rhs.index; } - }; + Page() + : page_id(INVALID_PAGE_ID) + {} PageId page_id; ByteBuffer data; MemHolder mem_holder; // Field offsets inside this page. - std::set field_offsets; + std::set field_offsets; public: inline bool isValid() const { return page_id != INVALID_PAGE_ID; } ByteBuffer getFieldData(size_t index) const { - auto iter = field_offsets.find(FieldOffset(index)); + auto iter = field_offsets.find(FieldOffsetInsidePage(index)); if (unlikely(iter == field_offsets.end())) throw Exception(fmt::format("Try to getFieldData with invalid field index [page_id={}] [field_index={}]", page_id, index), ErrorCodes::LOGICAL_ERROR); diff --git a/dbms/src/Storages/Page/PageDefines.h b/dbms/src/Storages/Page/PageDefines.h index 330ed7776a3..0feb33494a6 100644 --- a/dbms/src/Storages/Page/PageDefines.h +++ b/dbms/src/Storages/Page/PageDefines.h @@ -61,6 +61,12 @@ static constexpr PageId INVALID_PAGE_ID = 0; using PageIdV3Internal = UInt128; using PageIdV3Internals = std::vector; +inline PageIdV3Internal buildV3Id(NamespaceId n_id, PageId p_id) +{ + // low bits first + return PageIdV3Internal(p_id, n_id); +} + using PageFieldOffset = UInt64; using PageFieldOffsets = std::vector; using PageFieldSizes = std::vector; diff --git a/dbms/src/Storages/Page/PageStorage.cpp b/dbms/src/Storages/Page/PageStorage.cpp index c56d47d16b3..ecc0a5c7c5a 100644 --- a/dbms/src/Storages/Page/PageStorage.cpp +++ b/dbms/src/Storages/Page/PageStorage.cpp @@ -21,7 +21,7 @@ namespace DB PageStoragePtr PageStorage::create( String name, PSDiskDelegatorPtr delegator, - const PageStorage::Config & config, + const PageStorageConfig & config, const FileProviderPtr & file_provider, bool use_v3, bool no_more_insert_to_v2) @@ -501,19 +501,19 @@ void PageWriter::writeIntoMixMode(WriteBatch && write_batch, WriteLimiterPtr wri switch (write.type) { // PUT/PUT_EXTERNAL only for V3 - case WriteBatch::WriteType::PUT: - case WriteBatch::WriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT: + case WriteBatchWriteType::PUT_EXTERNAL: { page_ids_before_ref.insert(write.page_id); break; } // Both need del in v2 and v3 - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: { wb_for_v2.copyWrite(write); break; } - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: { // 1. Try to resolve normal page id PageId resolved_page_id = storage_v3->getNormalPageId(ns_id, @@ -620,7 +620,7 @@ void PageWriter::writeIntoMixMode(WriteBatch && write_batch, WriteLimiterPtr wri } -PageStorage::Config PageWriter::getSettings() const +PageStorageConfig PageWriter::getSettings() const { switch (run_mode) { @@ -641,7 +641,7 @@ PageStorage::Config PageWriter::getSettings() const } } -void PageWriter::reloadSettings(const PageStorage::Config & new_config) const +void PageWriter::reloadSettings(const PageStorageConfig & new_config) const { switch (run_mode) { diff --git a/dbms/src/Storages/Page/PageStorage.h b/dbms/src/Storages/Page/PageStorage.h index 4f89772db8f..f232f2e84d3 100644 --- a/dbms/src/Storages/Page/PageStorage.h +++ b/dbms/src/Storages/Page/PageStorage.h @@ -16,8 +16,6 @@ #include #include -#include -#include #include #include #include @@ -79,130 +77,17 @@ class PageStorage : private boost::noncopyable public: using SnapshotPtr = PageStorageSnapshotPtr; - struct Config - { - //========================================================================================== - // V2 config - //========================================================================================== - SettingBool sync_on_write = true; - - SettingUInt64 file_roll_size = PAGE_FILE_ROLL_SIZE; - SettingUInt64 file_max_size = PAGE_FILE_MAX_SIZE; - SettingUInt64 file_small_size = PAGE_FILE_SMALL_SIZE; - - SettingUInt64 file_meta_roll_size = PAGE_META_ROLL_SIZE; - - // When the value of gc_force_hardlink_rate is less than or equal to 1, - // It means that candidates whose valid rate is greater than this value will be forced to hardlink(This will reduce the gc duration). - // Otherwise, if gc_force_hardlink_rate is greater than 1, hardlink won't happen - SettingDouble gc_force_hardlink_rate = 2; - - SettingDouble gc_max_valid_rate = 0.35; - SettingUInt64 gc_min_bytes = PAGE_FILE_ROLL_SIZE; - SettingUInt64 gc_min_files = 10; - // Minimum number of legacy files to be selected for compaction - SettingUInt64 gc_min_legacy_num = 3; - - SettingUInt64 gc_max_expect_legacy_files = 100; - SettingDouble gc_max_valid_rate_bound = 1.0; - - // Maximum write concurrency. Must not be changed once the PageStorage object is created. - SettingUInt64 num_write_slots = 1; - - // Maximum seconds of reader / writer idle time. - // 0 for never reclaim idle file descriptor. - SettingUInt64 open_file_max_idle_time = 15; - - // Probability to do gc when write is low. - // The probability is `prob_do_gc_when_write_is_low` out of 1000. - SettingUInt64 prob_do_gc_when_write_is_low = 10; - - MVCC::VersionSetConfig version_set_config; - - //========================================================================================== - // V3 config - //========================================================================================== - SettingUInt64 blob_file_limit_size = BLOBFILE_LIMIT_SIZE; - SettingUInt64 blob_spacemap_type = 2; - SettingUInt64 blob_cached_fd_size = BLOBSTORE_CACHED_FD_SIZE; - SettingDouble blob_heavy_gc_valid_rate = 0.5; - SettingUInt64 blob_block_alignment_bytes = 0; - - SettingUInt64 wal_roll_size = PAGE_META_ROLL_SIZE; - SettingUInt64 wal_recover_mode = static_cast(WALRecoveryMode::TolerateCorruptedTailRecords); - SettingUInt64 wal_max_persisted_log_files = MAX_PERSISTED_LOG_FILES; - - void reload(const Config & rhs) - { - // Reload is not atomic, but should be good enough - - // Reload gc threshold - gc_force_hardlink_rate = rhs.gc_force_hardlink_rate; - gc_max_valid_rate = rhs.gc_max_valid_rate; - gc_min_bytes = rhs.gc_min_bytes; - gc_min_files = rhs.gc_min_files; - gc_min_legacy_num = rhs.gc_min_legacy_num; - prob_do_gc_when_write_is_low = rhs.prob_do_gc_when_write_is_low; - // Reload fd idle time - open_file_max_idle_time = rhs.open_file_max_idle_time; - - // Reload V3 setting - blob_file_limit_size = rhs.blob_file_limit_size; - blob_spacemap_type = rhs.blob_spacemap_type; - blob_cached_fd_size = rhs.blob_cached_fd_size; - blob_heavy_gc_valid_rate = rhs.blob_heavy_gc_valid_rate; - blob_block_alignment_bytes = rhs.blob_block_alignment_bytes; - - wal_roll_size = rhs.wal_roll_size; - wal_recover_mode = rhs.wal_recover_mode; - wal_max_persisted_log_files = rhs.wal_max_persisted_log_files; - } - - String toDebugStringV2() const - { - return fmt::format( - "PageStorage::Config {{gc_min_files: {}, gc_min_bytes:{}, gc_force_hardlink_rate: {:.3f}, gc_max_valid_rate: {:.3f}, " - "gc_min_legacy_num: {}, gc_max_expect_legacy: {}, gc_max_valid_rate_bound: {:.3f}, prob_do_gc_when_write_is_low: {}, " - "open_file_max_idle_time: {}}}", - gc_min_files, - gc_min_bytes, - gc_force_hardlink_rate.get(), - gc_max_valid_rate.get(), - gc_min_legacy_num, - gc_max_expect_legacy_files.get(), - gc_max_valid_rate_bound.get(), - prob_do_gc_when_write_is_low, - open_file_max_idle_time); - } - - String toDebugStringV3() const - { - return fmt::format( - "PageStorage::Config V3 {{" - "blob_file_limit_size: {}, blob_spacemap_type: {}, " - "blob_cached_fd_size: {}, blob_heavy_gc_valid_rate: {:.3f}, blob_block_alignment_bytes: {}, " - "wal_roll_size: {}, wal_recover_mode: {}, wal_max_persisted_log_files: {}}}", - blob_file_limit_size.get(), - blob_spacemap_type.get(), - blob_cached_fd_size.get(), - blob_heavy_gc_valid_rate.get(), - blob_block_alignment_bytes.get(), - wal_roll_size.get(), - wal_recover_mode.get(), - wal_max_persisted_log_files.get()); - } - }; - void reloadSettings(const Config & new_config) + void reloadSettings(const PageStorageConfig & new_config) { config.reload(new_config); reloadConfig(); } - Config getSettings() const { return config; } + PageStorageConfig getSettings() const { return config; } // Use a more easy gc config for v2 when all of its data will be transformed to v3. - static Config getEasyGCConfig() + static PageStorageConfig getEasyGCConfig() { - Config gc_config; + PageStorageConfig gc_config; gc_config.file_roll_size = PAGE_FILE_SMALL_SIZE; return gc_config; } @@ -212,7 +97,7 @@ class PageStorage : private boost::noncopyable create( String name, PSDiskDelegatorPtr delegator, - const PageStorage::Config & config, + const PageStorageConfig & config, const FileProviderPtr & file_provider, bool use_v3 = false, bool no_more_insert_to_v2 = false); @@ -220,7 +105,7 @@ class PageStorage : private boost::noncopyable PageStorage( String name, PSDiskDelegatorPtr delegator_, - const Config & config_, + const PageStorageConfig & config_, const FileProviderPtr & file_provider_) : storage_name(std::move(name)) , delegator(std::move(delegator_)) @@ -354,7 +239,7 @@ class PageStorage : private boost::noncopyable String storage_name; // Identify between different Storage PSDiskDelegatorPtr delegator; // Get paths for storing data - Config config; + PageStorageConfig config; FileProviderPtr file_provider; }; @@ -425,10 +310,10 @@ class PageWriter : private boost::noncopyable void writeIntoMixMode(WriteBatch && write_batch, WriteLimiterPtr write_limiter) const; // A wrap of getSettings only used for `RegionPersister::gc` - PageStorage::Config getSettings() const; + PageStorageConfig getSettings() const; // A wrap of reloadSettings only used for `RegionPersister::gc` - void reloadSettings(const PageStorage::Config & new_config) const; + void reloadSettings(const PageStorageConfig & new_config) const; // A wrap of gc only used for `RegionPersister::gc` bool gc(bool not_skip, const WriteLimiterPtr & write_limiter, const ReadLimiterPtr & read_limiter) const; diff --git a/dbms/src/Storages/Page/V2/PageFile.cpp b/dbms/src/Storages/Page/V2/PageFile.cpp index b6cff9bda2c..86cb7ce538e 100644 --- a/dbms/src/Storages/Page/V2/PageFile.cpp +++ b/dbms/src/Storages/Page/V2/PageFile.cpp @@ -65,7 +65,7 @@ namespace PageMetaFormat using WBSize = UInt32; // TODO we should align these alias with type in PageCache using PageTag = UInt64; -using IsPut = std::underlying_type::type; +using IsPut = std::underlying_type::type; using PageOffset = UInt64; using Checksum = UInt64; @@ -98,28 +98,28 @@ std::pair genWriteData( // { meta_write_bytes += sizeof(IsPut); // We don't serialize `PUT_EXTERNAL` for V2, just convert it to `PUT` - if (write.type == WriteBatch::WriteType::PUT_EXTERNAL) - write.type = WriteBatch::WriteType::PUT; + if (write.type == WriteBatchWriteType::PUT_EXTERNAL) + write.type = WriteBatchWriteType::PUT; switch (write.type) { - case WriteBatch::WriteType::PUT: - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::PUT: + case WriteBatchWriteType::UPSERT: if (write.read_buffer) data_write_bytes += write.size; meta_write_bytes += PAGE_META_SIZE; meta_write_bytes += sizeof(UInt64); // size of field_offsets + checksum meta_write_bytes += ((sizeof(UInt64) + sizeof(UInt64)) * write.offsets.size()); break; - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: // For delete page, store page id only. And don't need to write data file. meta_write_bytes += sizeof(PageId); break; - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: // For ref page, store RefPageId -> PageId. And don't need to write data file. meta_write_bytes += (sizeof(PageId) + sizeof(PageId)); break; - case WriteBatch::WriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT_EXTERNAL: throw Exception("Should not serialize with `PUT_EXTERNAL`"); break; } @@ -141,17 +141,17 @@ std::pair genWriteData( // for (auto & write : wb.getWrites()) { // We don't serialize `PUT_EXTERNAL` for V2, just convert it to `PUT` - if (write.type == WriteBatch::WriteType::PUT_EXTERNAL) - write.type = WriteBatch::WriteType::PUT; + if (write.type == WriteBatchWriteType::PUT_EXTERNAL) + write.type = WriteBatchWriteType::PUT; PageUtil::put(meta_pos, static_cast(write.type)); switch (write.type) { - case WriteBatch::WriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT_EXTERNAL: throw Exception("Should not serialize with `PUT_EXTERNAL`"); break; - case WriteBatch::WriteType::PUT: - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::PUT: + case WriteBatchWriteType::UPSERT: { PageFlags flags; Checksum page_checksum = 0; @@ -188,8 +188,8 @@ std::pair genWriteData( // // UPSERT may point to another PageFile PageEntry entry; - entry.file_id = (write.type == WriteBatch::WriteType::PUT ? page_file.getFileId() : write.target_file_id.first); - entry.level = (write.type == WriteBatch::WriteType::PUT ? page_file.getLevel() : write.target_file_id.second); + entry.file_id = (write.type == WriteBatchWriteType::PUT ? page_file.getFileId() : write.target_file_id.first); + entry.level = (write.type == WriteBatchWriteType::PUT ? page_file.getLevel() : write.target_file_id.second); entry.tag = write.tag; entry.size = write.size; entry.offset = page_offset; @@ -215,19 +215,19 @@ std::pair genWriteData( // PageUtil::put(meta_pos, static_cast(field_offset.second)); } - if (write.type == WriteBatch::WriteType::PUT) + if (write.type == WriteBatchWriteType::PUT) edit.put(write.page_id, entry); - else if (write.type == WriteBatch::WriteType::UPSERT) + else if (write.type == WriteBatchWriteType::UPSERT) edit.upsertPage(write.page_id, entry); break; } - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: PageUtil::put(meta_pos, static_cast(write.page_id)); edit.del(write.page_id); break; - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: PageUtil::put(meta_pos, static_cast(write.page_id)); PageUtil::put(meta_pos, static_cast(write.ori_page_id)); @@ -369,14 +369,14 @@ bool PageFile::LinkingMetaAdapter::linkToNewSequenceNext(WriteBatch::SequenceID // recover WriteBatch while (pos < wb_start_pos + wb_bytes_without_checksum) { - const auto write_type = static_cast(PageUtil::get(pos)); + const auto write_type = static_cast(PageUtil::get(pos)); switch (write_type) { - case WriteBatch::WriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT_EXTERNAL: throw Exception("Should not deserialize with PUT_EXTERNAL"); break; - case WriteBatch::WriteType::PUT: - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::PUT: + case WriteBatchWriteType::UPSERT: { PageMetaFormat::PageFlags flags; auto page_id = PageUtil::get(pos); @@ -425,12 +425,12 @@ bool PageFile::LinkingMetaAdapter::linkToNewSequenceNext(WriteBatch::SequenceID edit.upsertPage(page_id, entry); break; } - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: { pos += sizeof(PageId); break; } - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: { // ref_id pos += sizeof(PageId); @@ -608,14 +608,14 @@ void PageFile::MetaMergingReader::moveNext(PageFormat::Version * v) size_t curr_wb_data_offset = 0; while (pos < wb_start_pos + wb_bytes_without_checksum) { - const auto write_type = static_cast(PageUtil::get(pos)); + const auto write_type = static_cast(PageUtil::get(pos)); switch (write_type) { - case WriteBatch::WriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT_EXTERNAL: throw Exception("Should not deserialize with PUT_EXTERNAL"); break; - case WriteBatch::WriteType::PUT: - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::PUT: + case WriteBatchWriteType::UPSERT: { PageMetaFormat::PageFlags flags; @@ -659,12 +659,12 @@ void PageFile::MetaMergingReader::moveNext(PageFormat::Version * v) } } - if (write_type == WriteBatch::WriteType::PUT) + if (write_type == WriteBatchWriteType::PUT) { curr_edit.put(page_id, entry); curr_wb_data_offset += entry.size; } - else if (write_type == WriteBatch::WriteType::UPSERT) + else if (write_type == WriteBatchWriteType::UPSERT) { curr_edit.upsertPage(page_id, entry); // If it is a deatch page, don't move data offset. @@ -672,13 +672,13 @@ void PageFile::MetaMergingReader::moveNext(PageFormat::Version * v) } break; } - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: { auto page_id = PageUtil::get(pos); curr_edit.del(page_id); break; } - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: { const auto ref_id = PageUtil::get(pos); const auto page_id = PageUtil::get(pos); @@ -1022,7 +1022,7 @@ PageMap PageFile::Reader::read(PageFile::Reader::FieldReadInfos & to_read, const char * data_buf = static_cast(alloc(buf_size)); MemHolder mem_holder = createMemHolder(data_buf, [&, buf_size](char * p) { free(p, buf_size); }); - std::set fields_offset_in_page; + std::set fields_offset_in_page; char * pos = data_buf; PageMap page_map; @@ -1093,7 +1093,7 @@ Page PageFile::Reader::read(FieldReadInfo & to_read, const ReadLimiterPtr & read MemHolder mem_holder = createMemHolder(data_buf, [&, buf_size](char * p) { free(p, buf_size); }); Page page_rc; - std::set fields_offset_in_page; + std::set fields_offset_in_page; size_t read_size_this_entry = 0; char * write_offset = data_buf; diff --git a/dbms/src/Storages/Page/V2/PageStorage.cpp b/dbms/src/Storages/Page/V2/PageStorage.cpp index ba78cf6a75b..d743a7c801e 100644 --- a/dbms/src/Storages/Page/V2/PageStorage.cpp +++ b/dbms/src/Storages/Page/V2/PageStorage.cpp @@ -66,13 +66,13 @@ void PageStorage::StatisticsInfo::mergeEdits(const PageEntriesEdit & edit) { for (const auto & record : edit.getRecords()) { - if (record.type == WriteBatch::WriteType::DEL) + if (record.type == WriteBatchWriteType::DEL) deletes++; - else if (record.type == WriteBatch::WriteType::PUT) + else if (record.type == WriteBatchWriteType::PUT) puts++; - else if (record.type == WriteBatch::WriteType::REF) + else if (record.type == WriteBatchWriteType::REF) refs++; - else if (record.type == WriteBatch::WriteType::UPSERT) + else if (record.type == WriteBatchWriteType::UPSERT) upserts++; } } @@ -159,7 +159,7 @@ PageFileSet PageStorage::listAllPageFiles(const FileProviderPtr & file_provider, PageStorage::PageStorage(String name, PSDiskDelegatorPtr delegator_, // - const Config & config_, + const PageStorageConfig & config_, const FileProviderPtr & file_provider_, bool no_more_insert_) : DB::PageStorage(name, delegator_, config_, file_provider_) @@ -187,7 +187,7 @@ PageStorage::PageStorage(String name, } -static inline bool isPageFileSizeFitsWritable(const PageFile & pf, const PageStorage::Config & config) +static inline bool isPageFileSizeFitsWritable(const PageFile & pf, const PageStorageConfig & config) { return pf.getDataFileAppendPos() < config.file_roll_size && pf.getMetaFileAppendPos() < config.file_meta_roll_size; } @@ -918,9 +918,9 @@ struct GcContext size_t num_files_remove_data = 0; size_t num_bytes_remove_data = 0; - PageStorage::Config calculateGcConfig(const PageStorage::Config & config) const + PageStorageConfig calculateGcConfig(const PageStorageConfig & config) const { - PageStorage::Config res = config; + PageStorageConfig res = config; // Each legacy is about serval hundred KiB or serval MiB // It means each time `gc` is called, we will read `num_legacy_file` * serval MiB // Do more agressive GC if there are too many Legacy files diff --git a/dbms/src/Storages/Page/V2/PageStorage.h b/dbms/src/Storages/Page/V2/PageStorage.h index 1fcb76885bb..e441c8b91cf 100644 --- a/dbms/src/Storages/Page/V2/PageStorage.h +++ b/dbms/src/Storages/Page/V2/PageStorage.h @@ -87,10 +87,10 @@ class PageStorage : public DB::PageStorage public: PageStorage(String name, PSDiskDelegatorPtr delegator, // - const Config & config_, + const PageStorageConfig & config_, const FileProviderPtr & file_provider_, bool no_more_insert_ = false); - ~PageStorage() = default; + ~PageStorage() override = default; void restore() override; @@ -200,6 +200,7 @@ class PageStorage : public DB::PageStorage #ifndef NDEBUG // Just for tests, refactor them out later + // clang-format off DB::PageStorage::SnapshotPtr getSnapshot() { return getSnapshot(""); } void write(DB::WriteBatch && wb) { return writeImpl(std::move(wb), nullptr); } DB::PageEntry getEntry(PageId page_id) { return getEntryImpl(TEST_NAMESPACE_ID, page_id, nullptr); } @@ -212,6 +213,7 @@ class PageStorage : public DB::PageStorage PageMap read(const std::vector & page_fields) { return readImpl(TEST_NAMESPACE_ID, page_fields, nullptr, nullptr, true); } void traverse(const std::function & acceptor) { return traverseImpl(acceptor, nullptr); } bool gc() { return gcImpl(false, nullptr, nullptr); } + // clang-format on #endif #ifndef DBMS_PUBLIC_GTEST diff --git a/dbms/src/Storages/Page/V2/VersionSet/PageEntriesBuilder.cpp b/dbms/src/Storages/Page/V2/VersionSet/PageEntriesBuilder.cpp index 3c1542d29af..9f1c88ad90e 100644 --- a/dbms/src/Storages/Page/V2/VersionSet/PageEntriesBuilder.cpp +++ b/dbms/src/Storages/Page/V2/VersionSet/PageEntriesBuilder.cpp @@ -22,14 +22,14 @@ void PageEntriesBuilder::apply(const PageEntriesEdit & edit) { switch (rec.type) { - case WriteBatch::WriteType::PUT_EXTERNAL: - case WriteBatch::WriteType::PUT: + case WriteBatchWriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT: current_version->put(rec.page_id, rec.entry); break; - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: current_version->del(rec.page_id); break; - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: try { current_version->ref(rec.page_id, rec.ori_page_id); @@ -46,7 +46,7 @@ void PageEntriesBuilder::apply(const PageEntriesEdit & edit) } } break; - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::UPSERT: current_version->upsertPage(rec.page_id, rec.entry); break; } diff --git a/dbms/src/Storages/Page/V2/VersionSet/PageEntriesBuilder.h b/dbms/src/Storages/Page/V2/VersionSet/PageEntriesBuilder.h index db965012554..b4e696f2a9b 100644 --- a/dbms/src/Storages/Page/V2/VersionSet/PageEntriesBuilder.h +++ b/dbms/src/Storages/Page/V2/VersionSet/PageEntriesBuilder.h @@ -42,13 +42,22 @@ class PageEntriesBuilder current_version->copyEntries(*old_version); } - ~PageEntriesBuilder() { old_version->release(); } + ~PageEntriesBuilder() + { + old_version->release(); + } void apply(const PageEntriesEdit & edit); - void gcApply(PageEntriesEdit & edit) { gcApplyTemplate(current_version, edit, current_version); } + void gcApply(PageEntriesEdit & edit) + { + gcApplyTemplate(current_version, edit, current_version); + } - PageEntries * build() { return current_version; } + PageEntries * build() + { + return current_version; + } public: template @@ -56,10 +65,10 @@ class PageEntriesBuilder { for (auto & rec : edit.getRecords()) { - if (unlikely(rec.type == WriteBatch::WriteType::PUT)) + if (unlikely(rec.type == WriteBatchWriteType::PUT)) throw Exception("Should use UPDATE for gc edits, please check your code!!", ErrorCodes::LOGICAL_ERROR); - if (rec.type != WriteBatch::WriteType::UPSERT) + if (rec.type != WriteBatchWriteType::UPSERT) continue; // Gc only apply MOVE_NORMAL_PAGE for updating normal page entries const auto old_page_entry = old_version->findNormalPageEntry(rec.page_id); diff --git a/dbms/src/Storages/Page/V2/VersionSet/PageEntriesEdit.h b/dbms/src/Storages/Page/V2/VersionSet/PageEntriesEdit.h index 814736476f7..f077392a19a 100644 --- a/dbms/src/Storages/Page/V2/VersionSet/PageEntriesEdit.h +++ b/dbms/src/Storages/Page/V2/VersionSet/PageEntriesEdit.h @@ -30,7 +30,7 @@ class PageEntriesEdit void put(PageId page_id, const PageEntry & entry) { EditRecord record{}; - record.type = WriteBatch::WriteType::PUT; + record.type = WriteBatchWriteType::PUT; record.page_id = page_id; record.entry = entry; records.emplace_back(record); @@ -39,7 +39,7 @@ class PageEntriesEdit void upsertPage(PageId page_id, const PageEntry & entry) { EditRecord record{}; - record.type = WriteBatch::WriteType::UPSERT; + record.type = WriteBatchWriteType::UPSERT; record.page_id = page_id; record.entry = entry; records.emplace_back(record); @@ -48,7 +48,7 @@ class PageEntriesEdit void del(PageId page_id) { EditRecord record{}; - record.type = WriteBatch::WriteType::DEL; + record.type = WriteBatchWriteType::DEL; record.page_id = page_id; records.emplace_back(record); } @@ -56,7 +56,7 @@ class PageEntriesEdit void ref(PageId ref_id, PageId page_id) { EditRecord record{}; - record.type = WriteBatch::WriteType::REF; + record.type = WriteBatchWriteType::REF; record.page_id = ref_id; record.ori_page_id = page_id; records.emplace_back(record); @@ -76,7 +76,7 @@ class PageEntriesEdit struct EditRecord { - WriteBatch::WriteType type; + WriteBatchWriteType type; PageId page_id; PageId ori_page_id; PageEntry entry; diff --git a/dbms/src/Storages/Page/V2/VersionSet/PageEntriesVersionSetWithDelta.cpp b/dbms/src/Storages/Page/V2/VersionSet/PageEntriesVersionSetWithDelta.cpp index 6b77da2603f..a3256f34491 100644 --- a/dbms/src/Storages/Page/V2/VersionSet/PageEntriesVersionSetWithDelta.cpp +++ b/dbms/src/Storages/Page/V2/VersionSet/PageEntriesVersionSetWithDelta.cpp @@ -433,17 +433,17 @@ void DeltaVersionEditAcceptor::apply(PageEntriesEdit & edit) { switch (rec.type) { - case WriteBatch::WriteType::PUT_EXTERNAL: - case WriteBatch::WriteType::PUT: + case WriteBatchWriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT: this->applyPut(rec); break; - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: this->applyDel(rec); break; - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: this->applyRef(rec); break; - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::UPSERT: throw Exception("WriteType::UPSERT should only write by gcApply!", ErrorCodes::LOGICAL_ERROR); break; } @@ -452,7 +452,7 @@ void DeltaVersionEditAcceptor::apply(PageEntriesEdit & edit) void DeltaVersionEditAcceptor::applyPut(PageEntriesEdit::EditRecord & rec) { - assert(rec.type == WriteBatch::WriteType::PUT); + assert(rec.type == WriteBatchWriteType::PUT); /// Note that any changes on `current_version` will break the consistency of `view`. /// We should postpone changes to the last of this function. @@ -493,7 +493,7 @@ void DeltaVersionEditAcceptor::applyPut(PageEntriesEdit::EditRecord & rec) void DeltaVersionEditAcceptor::applyDel(PageEntriesEdit::EditRecord & rec) { - assert(rec.type == WriteBatch::WriteType::DEL); + assert(rec.type == WriteBatchWriteType::DEL); /// Note that any changes on `current_version` will break the consistency of `view`. /// We should postpone changes to the last of this function. @@ -509,7 +509,7 @@ void DeltaVersionEditAcceptor::applyDel(PageEntriesEdit::EditRecord & rec) void DeltaVersionEditAcceptor::applyRef(PageEntriesEdit::EditRecord & rec) { - assert(rec.type == WriteBatch::WriteType::REF); + assert(rec.type == WriteBatchWriteType::REF); /// Note that any changes on `current_version` will break the consistency of `view`. /// We should postpone changes to the last of this function. @@ -563,14 +563,14 @@ void DeltaVersionEditAcceptor::applyInplace(const String & name, { switch (rec.type) { - case WriteBatch::WriteType::PUT_EXTERNAL: - case WriteBatch::WriteType::PUT: + case WriteBatchWriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT: current->put(rec.page_id, rec.entry); break; - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: current->del(rec.page_id); break; - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: // Shorten ref-path in case there is RefPage to RefPage try { @@ -581,7 +581,7 @@ void DeltaVersionEditAcceptor::applyInplace(const String & name, LOG_FMT_WARNING(log, "{} Ignore invalid RefPage in DeltaVersionEditAcceptor::applyInplace, RefPage{} to non-exist Page{}", name, rec.page_id, rec.ori_page_id); } break; - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::UPSERT: current->upsertPage(rec.page_id, rec.entry); break; } diff --git a/dbms/src/Storages/Page/V2/gc/DataCompactor.cpp b/dbms/src/Storages/Page/V2/gc/DataCompactor.cpp index 3e5a25125ae..856e0250719 100644 --- a/dbms/src/Storages/Page/V2/gc/DataCompactor.cpp +++ b/dbms/src/Storages/Page/V2/gc/DataCompactor.cpp @@ -33,7 +33,7 @@ namespace PS::V2 template DataCompactor::DataCompactor( const PageStorage & storage, - PageStorage::Config gc_config, + PageStorageConfig gc_config, const WriteLimiterPtr & write_limiter_, const ReadLimiterPtr & read_limiter_) : storage_name(storage.storage_name) diff --git a/dbms/src/Storages/Page/V2/gc/DataCompactor.h b/dbms/src/Storages/Page/V2/gc/DataCompactor.h index eede1775cdf..dd838768371 100644 --- a/dbms/src/Storages/Page/V2/gc/DataCompactor.h +++ b/dbms/src/Storages/Page/V2/gc/DataCompactor.h @@ -42,7 +42,7 @@ class DataCompactor : private boost::noncopyable }; public: - DataCompactor(const PageStorage & storage, PageStorage::Config gc_config, const WriteLimiterPtr & write_limiter_, const ReadLimiterPtr & read_limiter_); + DataCompactor(const PageStorage & storage, PageStorageConfig gc_config, const WriteLimiterPtr & write_limiter_, const ReadLimiterPtr & read_limiter_); /** * Take a snapshot from PageStorage and try to migrate data if some PageFiles used rate is low. @@ -119,7 +119,7 @@ class DataCompactor : private boost::noncopyable PSDiskDelegatorPtr delegator; FileProviderPtr file_provider; - const PageStorage::Config config; + const PageStorageConfig config; Poco::Logger * log; Poco::Logger * page_file_log; diff --git a/dbms/src/Storages/Page/V2/gc/LegacyCompactor.h b/dbms/src/Storages/Page/V2/gc/LegacyCompactor.h index fd3e6c12b33..7ba64396ca2 100644 --- a/dbms/src/Storages/Page/V2/gc/LegacyCompactor.h +++ b/dbms/src/Storages/Page/V2/gc/LegacyCompactor.h @@ -68,7 +68,7 @@ class LegacyCompactor : private boost::noncopyable PSDiskDelegatorPtr delegator; FileProviderPtr file_provider; - const PageStorage::Config & config; + const PageStorageConfig & config; Poco::Logger * log; Poco::Logger * page_file_log; diff --git a/dbms/src/Storages/Page/V2/tests/gtest_data_compactor.cpp b/dbms/src/Storages/Page/V2/tests/gtest_data_compactor.cpp index b273842ec74..531695aa0bb 100644 --- a/dbms/src/Storages/Page/V2/tests/gtest_data_compactor.cpp +++ b/dbms/src/Storages/Page/V2/tests/gtest_data_compactor.cpp @@ -44,7 +44,7 @@ try { CHECK_TESTS_WITH_DATA_ENABLED; - PageStorage::Config config; + PageStorageConfig config; config.num_write_slots = 2; #ifndef GENERATE_TEST_DATA const Strings test_paths = TiFlashTestEnv::findTestDataPath("page_storage_compactor_migrate"); @@ -135,7 +135,7 @@ try for (size_t i = 0; i < records.size(); ++i) { const auto & rec = records[i]; - EXPECT_EQ(rec.type, WriteBatch::WriteType::UPSERT); + EXPECT_EQ(rec.type, WriteBatchWriteType::UPSERT); // Page 1, 2, 6 is moved to PageFile{2,1} if (rec.page_id == 1 || rec.page_id == 2 || rec.page_id == 6) { diff --git a/dbms/src/Storages/Page/V2/tests/gtest_legacy_compactor.cpp b/dbms/src/Storages/Page/V2/tests/gtest_legacy_compactor.cpp index 64a146693a2..2cd383bba41 100644 --- a/dbms/src/Storages/Page/V2/tests/gtest_legacy_compactor.cpp +++ b/dbms/src/Storages/Page/V2/tests/gtest_legacy_compactor.cpp @@ -35,7 +35,7 @@ namespace DB::PS::V2::tests TEST(LegacyCompactor_test, WriteMultipleBatchRead) try { - PageStorage::Config config; + PageStorageConfig config; Poco::Logger * log = &Poco::Logger::get("LegacyCompactor_test"); PageEntriesVersionSetWithDelta original_version("test", config.version_set_config, log); @@ -81,7 +81,7 @@ try auto writes = wb.getWrites(); for (auto w : writes) { - if (w.type == WriteBatch::WriteType::UPSERT) + if (w.type == WriteBatchWriteType::UPSERT) { auto entry = snapshot->version()->findNormalPageEntry(w.page_id); if (entry) @@ -89,7 +89,7 @@ try else FAIL() << "Cannot find specified page"; } - else if (w.type == WriteBatch::WriteType::REF) + else if (w.type == WriteBatchWriteType::REF) edit.ref(w.page_id, w.ori_page_id); else FAIL() << "Snapshot writes should only contain UPSERT and REF"; @@ -173,7 +173,7 @@ try const FileProviderPtr file_provider = ctx.getFileProvider(); StoragePathPool spool = ctx.getPathPool().withTable("test", "t", false); auto delegator = spool.getPSDiskDelegatorSingle("meta"); - PageStorage storage("compact_test", delegator, PageStorage::Config{}, file_provider); + PageStorage storage("compact_test", delegator, PageStorageConfig{}, file_provider); PageStorage::ListPageFilesOption opt; opt.ignore_checkpoint = false; diff --git a/dbms/src/Storages/Page/V2/tests/gtest_page_file.cpp b/dbms/src/Storages/Page/V2/tests/gtest_page_file.cpp index cb7a5106cbe..351daabe5fa 100644 --- a/dbms/src/Storages/Page/V2/tests/gtest_page_file.cpp +++ b/dbms/src/Storages/Page/V2/tests/gtest_page_file.cpp @@ -88,11 +88,11 @@ TEST(Page_test, GetField) Page page; page.data = ByteBuffer(c_buff, c_buff + buf_sz); - std::set fields{// {field_index, data_offset} - {2, 0}, - {3, 20}, - {9, 99}, - {10086, 1000}}; + std::set fields{// {field_index, data_offset} + {2, 0}, + {3, 20}, + {9, 99}, + {10086, 1000}}; page.field_offsets = fields; ASSERT_EQ(page.data.size(), buf_sz); diff --git a/dbms/src/Storages/Page/V2/tests/gtest_page_storage.cpp b/dbms/src/Storages/Page/V2/tests/gtest_page_storage.cpp index 28421d6781d..4793304c530 100644 --- a/dbms/src/Storages/Page/V2/tests/gtest_page_storage.cpp +++ b/dbms/src/Storages/Page/V2/tests/gtest_page_storage.cpp @@ -71,7 +71,7 @@ class PageStorage_test : public DB::base::TiFlashStorageTestBasic storage = reopenWithConfig(config); } - std::shared_ptr reopenWithConfig(const PageStorage::Config & config_) + std::shared_ptr reopenWithConfig(const PageStorageConfig & config_) { auto delegator = path_pool->getPSDiskDelegatorSingle("log"); auto storage = std::make_shared("test.t", delegator, config_, file_provider); @@ -80,7 +80,7 @@ class PageStorage_test : public DB::base::TiFlashStorageTestBasic } protected: - PageStorage::Config config; + PageStorageConfig config; std::shared_ptr storage; std::unique_ptr path_pool; const FileProviderPtr file_provider; @@ -463,7 +463,7 @@ try ASSERT_EQ(page_files.size(), 1UL); } - PageStorage::Config config; + PageStorageConfig config; config.file_roll_size = 10; // make it easy to renew a new page file for write storage = reopenWithConfig(config); @@ -487,7 +487,7 @@ try c_buff[i] = i % 0xff; } - PageStorage::Config tmp_config = config; + PageStorageConfig tmp_config = config; tmp_config.file_roll_size = 128 * MB; storage = reopenWithConfig(tmp_config); @@ -787,7 +787,7 @@ try } // Restore, the broken meta should be ignored - storage = reopenWithConfig(PageStorage::Config{}); + storage = reopenWithConfig(PageStorageConfig{}); { size_t num_pages = 0; @@ -816,7 +816,7 @@ try } // Restore again, we should be able to read page 1 - storage = reopenWithConfig(PageStorage::Config{}); + storage = reopenWithConfig(PageStorageConfig{}); { size_t num_pages = 0; @@ -890,7 +890,7 @@ try } // Restore again, we should be able to read page 1 - storage = reopenWithConfig(PageStorage::Config{}); + storage = reopenWithConfig(PageStorageConfig{}); { size_t num_pages = 0; diff --git a/dbms/src/Storages/Page/V2/tests/gtest_page_storage_multi_paths.cpp b/dbms/src/Storages/Page/V2/tests/gtest_page_storage_multi_paths.cpp index c2dac3867cf..4b985dd525b 100644 --- a/dbms/src/Storages/Page/V2/tests/gtest_page_storage_multi_paths.cpp +++ b/dbms/src/Storages/Page/V2/tests/gtest_page_storage_multi_paths.cpp @@ -79,7 +79,7 @@ class PageStorageMultiPaths_test : public DB::base::TiFlashStorageTestBasic } protected: - PageStorage::Config config; + PageStorageConfig config; std::shared_ptr storage; const FileProviderPtr file_provider; }; diff --git a/dbms/src/Storages/Page/V2/tests/gtest_page_storage_multi_writers.cpp b/dbms/src/Storages/Page/V2/tests/gtest_page_storage_multi_writers.cpp index 8d688538b3e..58aca9a177b 100644 --- a/dbms/src/Storages/Page/V2/tests/gtest_page_storage_multi_writers.cpp +++ b/dbms/src/Storages/Page/V2/tests/gtest_page_storage_multi_writers.cpp @@ -63,7 +63,7 @@ class PageStorageMultiWriters_test : public DB::base::TiFlashStorageTestBasic storage = reopenWithConfig(config); } - std::shared_ptr reopenWithConfig(const PageStorage::Config & config_) + std::shared_ptr reopenWithConfig(const PageStorageConfig & config_) { auto spool = db_context->getPathPool().withTable("test", "t", false); auto delegator = spool.getPSDiskDelegatorSingle("log"); @@ -73,7 +73,7 @@ class PageStorageMultiWriters_test : public DB::base::TiFlashStorageTestBasic } protected: - PageStorage::Config config; + PageStorageConfig config; std::shared_ptr storage; const FileProviderPtr file_provider; }; @@ -371,7 +371,7 @@ try size_t timeout_s = 5 * 60; srand(0x123987); - PageStorage::Config curr_config = config; + PageStorageConfig curr_config = config; curr_config.num_write_slots = num_write_slots; storage = reopenWithConfig(curr_config); diff --git a/dbms/src/Storages/Page/V2/tests/test_page_storage_write_disk_full.cpp b/dbms/src/Storages/Page/V2/tests/test_page_storage_write_disk_full.cpp index 476e72309b6..c47ca6041a4 100644 --- a/dbms/src/Storages/Page/V2/tests/test_page_storage_write_disk_full.cpp +++ b/dbms/src/Storages/Page/V2/tests/test_page_storage_write_disk_full.cpp @@ -152,7 +152,7 @@ int main(int argc, char ** argv) file.remove(true); // Create PageStorage - DB::PageStorage::Config config; + DB::PageStorageConfig config; config.file_roll_size = 96UL * 1024 * 1024; PSPtr ps = std::make_shared(path, config); diff --git a/dbms/src/Storages/Page/V3/Blob/BlobConfig.h b/dbms/src/Storages/Page/V3/Blob/BlobConfig.h index 6323af708ef..bc16d08c5f8 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobConfig.h +++ b/dbms/src/Storages/Page/V3/Blob/BlobConfig.h @@ -15,6 +15,7 @@ #pragma once #include +#include #include #include #include @@ -41,5 +42,18 @@ struct BlobConfig block_alignment_bytes, heavy_gc_valid_rate); } + + static BlobConfig from(const PageStorageConfig & config) + { + BlobConfig blob_config; + + blob_config.file_limit_size = config.blob_file_limit_size; + blob_config.cached_fd_size = config.blob_cached_fd_size; + blob_config.spacemap_type = config.blob_spacemap_type; + blob_config.heavy_gc_valid_rate = config.blob_heavy_gc_valid_rate; + blob_config.block_alignment_bytes = config.blob_block_alignment_bytes; + + return blob_config; + } }; } // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/BlobStore.cpp b/dbms/src/Storages/Page/V3/BlobStore.cpp index f565e3dd930..10d6ded388f 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.cpp +++ b/dbms/src/Storages/Page/V3/BlobStore.cpp @@ -157,13 +157,12 @@ FileUsageStatistics BlobStore::getFileUsageStatistics() const PageEntriesEdit BlobStore::handleLargeWrite(DB::WriteBatch & wb, const WriteLimiterPtr & write_limiter) { - auto ns_id = wb.getNamespaceId(); PageEntriesEdit edit; for (auto & write : wb.getWrites()) { switch (write.type) { - case WriteBatch::WriteType::PUT: + case WriteBatchWriteType::PUT: { ChecksumClass digest; PageEntryV3 entry; @@ -212,23 +211,23 @@ PageEntriesEdit BlobStore::handleLargeWrite(DB::WriteBatch & wb, const WriteLimi throw e; } - edit.put(buildV3Id(ns_id, write.page_id), entry); + edit.put(wb.getFullPageId(write.page_id), entry); break; } - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: { - edit.del(buildV3Id(ns_id, write.page_id)); + edit.del(wb.getFullPageId(write.page_id)); break; } - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: { - edit.ref(buildV3Id(ns_id, write.page_id), buildV3Id(ns_id, write.ori_page_id)); + edit.ref(wb.getFullPageId(write.page_id), wb.getFullPageId(write.ori_page_id)); break; } - case WriteBatch::WriteType::PUT_EXTERNAL: - edit.putExternal(buildV3Id(ns_id, write.page_id)); + case WriteBatchWriteType::PUT_EXTERNAL: + edit.putExternal(wb.getFullPageId(write.page_id)); break; - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::UPSERT: throw Exception(fmt::format("Unknown write type: {}", write.type)); } } @@ -244,7 +243,6 @@ PageEntriesEdit BlobStore::write(DB::WriteBatch & wb, const WriteLimiterPtr & wr PageEntriesEdit edit; - auto ns_id = wb.getNamespaceId(); if (all_page_data_size == 0) { // Shortcut for WriteBatch that don't need to persist blob data. @@ -252,24 +250,24 @@ PageEntriesEdit BlobStore::write(DB::WriteBatch & wb, const WriteLimiterPtr & wr { switch (write.type) { - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: { - edit.del(buildV3Id(ns_id, write.page_id)); + edit.del(wb.getFullPageId(write.page_id)); break; } - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: { - edit.ref(buildV3Id(ns_id, write.page_id), buildV3Id(ns_id, write.ori_page_id)); + edit.ref(wb.getFullPageId(write.page_id), wb.getFullPageId(write.ori_page_id)); break; } - case WriteBatch::WriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT_EXTERNAL: { // putExternal won't have data. - edit.putExternal(buildV3Id(ns_id, write.page_id)); + edit.putExternal(wb.getFullPageId(write.page_id)); break; } - case WriteBatch::WriteType::PUT: - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::PUT: + case WriteBatchWriteType::UPSERT: throw Exception(fmt::format("write batch have a invalid total size [write_type={}]", static_cast(write.type)), ErrorCodes::LOGICAL_ERROR); } @@ -309,7 +307,7 @@ PageEntriesEdit BlobStore::write(DB::WriteBatch & wb, const WriteLimiterPtr & wr { switch (write.type) { - case WriteBatch::WriteType::PUT: + case WriteBatchWriteType::PUT: { ChecksumClass digest; PageEntryV3 entry; @@ -350,23 +348,23 @@ PageEntriesEdit BlobStore::write(DB::WriteBatch & wb, const WriteLimiterPtr & wr } buffer_pos += write.size; - edit.put(buildV3Id(ns_id, write.page_id), entry); + edit.put(wb.getFullPageId(write.page_id), entry); break; } - case WriteBatch::WriteType::DEL: + case WriteBatchWriteType::DEL: { - edit.del(buildV3Id(ns_id, write.page_id)); + edit.del(wb.getFullPageId(write.page_id)); break; } - case WriteBatch::WriteType::REF: + case WriteBatchWriteType::REF: { - edit.ref(buildV3Id(ns_id, write.page_id), buildV3Id(ns_id, write.ori_page_id)); + edit.ref(wb.getFullPageId(write.page_id), wb.getFullPageId(write.ori_page_id)); break; } - case WriteBatch::WriteType::PUT_EXTERNAL: - edit.putExternal(buildV3Id(ns_id, write.page_id)); + case WriteBatchWriteType::PUT_EXTERNAL: + edit.putExternal(wb.getFullPageId(write.page_id)); break; - case WriteBatch::WriteType::UPSERT: + case WriteBatchWriteType::UPSERT: throw Exception(fmt::format("Unknown write type: {}", write.type)); } } @@ -533,7 +531,7 @@ void BlobStore::read(PageIDAndEntriesV3 & entries, const PageHandler & handler, ProfileEvents::increment(ProfileEvents::PSMReadPages, entries.size()); // Sort in ascending order by offset in file. - std::sort(entries.begin(), entries.end(), [](const PageIDAndEntryV3 & a, const PageIDAndEntryV3 & b) { + std::sort(entries.begin(), entries.end(), [](const auto & a, const auto & b) { return a.second.offset < b.second.offset; }); @@ -549,9 +547,8 @@ void BlobStore::read(PageIDAndEntriesV3 & entries, const PageHandler & handler, for (const auto & [page_id_v3, entry] : entries) { (void)entry; - LOG_FMT_DEBUG(log, "Read entry [page_id={}] without entry size.", page_id_v3); - Page page; - page.page_id = page_id_v3.low; + LOG_DEBUG(log, "Read entry [page_id={}] without entry size.", page_id_v3); + Page page(page_id_v3); handler(page_id_v3.low, page); } return; @@ -584,8 +581,7 @@ void BlobStore::read(PageIDAndEntriesV3 & entries, const PageHandler & handler, } } - Page page; - page.page_id = page_id_v3.low; + Page page(page_id_v3); page.data = ByteBuffer(data_buf, data_buf + entry.size); page.mem_holder = mem_holder; handler(page_id_v3.low, page); @@ -632,7 +628,7 @@ PageMap BlobStore::read(FieldReadInfos & to_read, const ReadLimiterPtr & read_li free(p, buf_size); }); - std::set fields_offset_in_page; + std::set fields_offset_in_page; char * pos = data_buf; PageMap page_map; for (const auto & [page_id_v3, entry, fields] : to_read) @@ -676,8 +672,7 @@ PageMap BlobStore::read(FieldReadInfos & to_read, const ReadLimiterPtr & read_li write_offset += size_to_read; } - Page page; - page.page_id = page_id_v3.low; + Page page(page_id_v3); page.data = ByteBuffer(pos, write_offset); page.mem_holder = mem_holder; page.field_offsets.swap(fields_offset_in_page); @@ -705,7 +700,7 @@ PageMap BlobStore::read(PageIDAndEntriesV3 & entries, const ReadLimiterPtr & rea ProfileEvents::increment(ProfileEvents::PSMReadPages, entries.size()); // Sort in ascending order by offset in file. - std::sort(entries.begin(), entries.end(), [](const PageIDAndEntryV3 & a, const PageIDAndEntryV3 & b) { + std::sort(entries.begin(), entries.end(), [](const auto & a, const auto & b) { return a.second.offset < b.second.offset; }); @@ -724,9 +719,8 @@ PageMap BlobStore::read(PageIDAndEntriesV3 & entries, const ReadLimiterPtr & rea for (const auto & [page_id_v3, entry] : entries) { (void)entry; - LOG_FMT_DEBUG(log, "Read entry [page_id={}] without entry size.", page_id_v3); - Page page; - page.page_id = page_id_v3.low; + LOG_DEBUG(log, "Read entry [page_id={}] without entry size.", page_id_v3); + Page page(page_id_v3); page_map.emplace(page_id_v3.low, page); } return page_map; @@ -761,8 +755,7 @@ PageMap BlobStore::read(PageIDAndEntriesV3 & entries, const ReadLimiterPtr & rea } } - Page page; - page.page_id = page_id_v3.low; + Page page(page_id_v3); page.data = ByteBuffer(pos, pos + entry.size); page.mem_holder = mem_holder; page_map.emplace(page_id_v3.low, page); @@ -783,8 +776,7 @@ Page BlobStore::read(const PageIDAndEntryV3 & id_entry, const ReadLimiterPtr & r { if (!id_entry.second.isValid()) { - Page page_not_found; - page_not_found.page_id = INVALID_PAGE_ID; + Page page_not_found(buildV3Id(id_entry.first.high, INVALID_PAGE_ID)); return page_not_found; } @@ -795,9 +787,8 @@ Page BlobStore::read(const PageIDAndEntryV3 & id_entry, const ReadLimiterPtr & r // The `buf_size` will be 0, we need avoid calling malloc/free with size 0. if (buf_size == 0) { - LOG_FMT_DEBUG(log, "Read entry [page_id={}] without entry size.", page_id_v3); - Page page; - page.page_id = page_id_v3.low; + LOG_DEBUG(log, "Read entry [page_id={}] without entry size.", page_id_v3); + Page page(page_id_v3); return page; } @@ -825,8 +816,7 @@ Page BlobStore::read(const PageIDAndEntryV3 & id_entry, const ReadLimiterPtr & r } } - Page page; - page.page_id = page_id_v3.low; + Page page(page_id_v3); page.data = ByteBuffer(data_buf, data_buf + buf_size); page.mem_holder = mem_holder; diff --git a/dbms/src/Storages/Page/V3/BlobStore.h b/dbms/src/Storages/Page/V3/BlobStore.h index af1ac994a3d..c0357d353ab 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.h +++ b/dbms/src/Storages/Page/V3/BlobStore.h @@ -18,12 +18,15 @@ #include #include #include +#include +#include #include #include #include #include #include #include +#include #include #include diff --git a/dbms/src/Storages/Page/V3/PageEntry.h b/dbms/src/Storages/Page/V3/PageEntry.h index c26f7399bdd..65a9b3955d3 100644 --- a/dbms/src/Storages/Page/V3/PageEntry.h +++ b/dbms/src/Storages/Page/V3/PageEntry.h @@ -79,11 +79,6 @@ using PageEntriesV3 = std::vector; using PageIDAndEntryV3 = std::pair; using PageIDAndEntriesV3 = std::vector; -inline PageIdV3Internal buildV3Id(NamespaceId n_id, PageId p_id) -{ - // low bits first - return PageIdV3Internal(p_id, n_id); -} inline String toDebugString(const PageEntryV3 & entry) { diff --git a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp index eb60ffa5112..02bf9069191 100644 --- a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp +++ b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -39,11 +40,11 @@ namespace PS::V3 PageStorageImpl::PageStorageImpl( String name, PSDiskDelegatorPtr delegator_, - const Config & config_, + const PageStorageConfig & config_, const FileProviderPtr & file_provider_) : DB::PageStorage(name, delegator_, config_, file_provider_) , log(Logger::get("PageStorage", name)) - , blob_store(name, file_provider_, delegator, parseBlobConfig(config_)) + , blob_store(name, file_provider_, delegator, BlobConfig::from(config_)) { LOG_FMT_INFO(log, "PageStorageImpl start. Config{{ {} }}", config.toDebugStringV3()); } @@ -52,7 +53,7 @@ PageStorageImpl::~PageStorageImpl() = default; void PageStorageImpl::reloadConfig() { - blob_store.reloadConfig(parseBlobConfig(config)); + blob_store.reloadConfig(BlobConfig::from(config)); } void PageStorageImpl::restore() @@ -64,7 +65,7 @@ void PageStorageImpl::restore() PageDirectoryFactory factory; page_directory = factory .setBlobStore(blob_store) - .create(storage_name, file_provider, delegator, parseWALConfig(config)); + .create(storage_name, file_provider, delegator, WALConfig::from(config)); } PageId PageStorageImpl::getMaxId() diff --git a/dbms/src/Storages/Page/V3/PageStorageImpl.h b/dbms/src/Storages/Page/V3/PageStorageImpl.h index eabaff90504..0eefa04fe7c 100644 --- a/dbms/src/Storages/Page/V3/PageStorageImpl.h +++ b/dbms/src/Storages/Page/V3/PageStorageImpl.h @@ -33,35 +33,11 @@ class PageStorageImpl : public DB::PageStorage PageStorageImpl( String name, PSDiskDelegatorPtr delegator, - const Config & config_, + const PageStorageConfig & config_, const FileProviderPtr & file_provider_); ~PageStorageImpl() override; - static BlobConfig parseBlobConfig(const Config & config) - { - BlobConfig blob_config; - - blob_config.file_limit_size = config.blob_file_limit_size; - blob_config.cached_fd_size = config.blob_cached_fd_size; - blob_config.spacemap_type = config.blob_spacemap_type; - blob_config.heavy_gc_valid_rate = config.blob_heavy_gc_valid_rate; - blob_config.block_alignment_bytes = config.blob_block_alignment_bytes; - - return blob_config; - } - - static WALConfig parseWALConfig(const Config & config) - { - WALConfig wal_config; - - wal_config.roll_size = config.wal_roll_size; - wal_config.max_persisted_log_files = config.wal_max_persisted_log_files; - wal_config.setRecoverMode(config.wal_recover_mode); - - return wal_config; - } - void reloadConfig() override; void restore() override; diff --git a/dbms/src/Storages/Page/V3/WAL/WALConfig.h b/dbms/src/Storages/Page/V3/WAL/WALConfig.h index 642f08f97e3..b4cd3256707 100644 --- a/dbms/src/Storages/Page/V3/WAL/WALConfig.h +++ b/dbms/src/Storages/Page/V3/WAL/WALConfig.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -45,6 +46,16 @@ struct WALConfig { return static_cast(wal_recover_mode.get()); } + + static WALConfig from(const PageStorageConfig & config) + { + WALConfig wal_config; + + wal_config.roll_size = config.wal_roll_size; + wal_config.max_persisted_log_files = config.wal_max_persisted_log_files; + + return wal_config; + } }; } // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp b/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp index 0c86fbb52ec..f4670fb4598 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp @@ -63,7 +63,7 @@ class PageStorageTest : public DB::base::TiFlashStorageTestBasic page_storage->restore(); } - std::shared_ptr reopenWithConfig(const PageStorage::Config & config_) + std::shared_ptr reopenWithConfig(const PageStorageConfig & config_) { auto path = getTemporaryPath(); delegator = std::make_shared(path); @@ -77,7 +77,7 @@ class PageStorageTest : public DB::base::TiFlashStorageTestBasic FileProviderPtr file_provider; std::unique_ptr path_pool; PSDiskDelegatorPtr delegator; - PageStorage::Config config; + PageStorageConfig config; std::shared_ptr page_storage; std::list snapshots_holder; @@ -788,7 +788,7 @@ try } // Restore, the broken meta should be ignored - page_storage = reopenWithConfig(PageStorage::Config{}); + page_storage = reopenWithConfig(PageStorageConfig{}); { size_t num_pages = 0; @@ -817,7 +817,7 @@ try } // Restore again, we should be able to read page 1 - page_storage = reopenWithConfig(PageStorage::Config{}); + page_storage = reopenWithConfig(PageStorageConfig{}); { size_t num_pages = 0; @@ -892,7 +892,7 @@ try } // Restore again, we should be able to read page 1 - page_storage = reopenWithConfig(PageStorage::Config{}); + page_storage = reopenWithConfig(PageStorageConfig{}); { size_t num_pages = 0; @@ -1565,7 +1565,7 @@ TEST_F(PageStorageTest, EntryTagAfterFullGC) try { { - PageStorage::Config config; + PageStorageConfig config; config.blob_heavy_gc_valid_rate = 1.0; /// always run full gc page_storage = reopenWithConfig(config); } @@ -1615,7 +1615,7 @@ TEST_F(PageStorageTest, DumpPageStorageSnapshot) try { { - PageStorage::Config config; + PageStorageConfig config; config.blob_heavy_gc_valid_rate = 1.0; /// always run full gc config.wal_roll_size = 1 * 1024 * 1024; /// make the wal file more easy to roll config.wal_max_persisted_log_files = 10; /// avoid checkpoint when gc @@ -1669,7 +1669,7 @@ try ASSERT_TRUE(done_snapshot); { - PageStorage::Config config; + PageStorageConfig config; page_storage = reopenWithConfig(config); } @@ -1681,7 +1681,7 @@ TEST_F(PageStorageTest, DumpPageStorageSnapshotWithRefPage) try { { - PageStorage::Config config; + PageStorageConfig config; config.blob_heavy_gc_valid_rate = 1.0; /// always run full gc config.wal_roll_size = 1 * 1024 * 1024; /// make the wal file more easy to roll config.wal_max_persisted_log_files = 10; /// avoid checkpoint when gc @@ -1745,7 +1745,7 @@ try ASSERT_TRUE(done_snapshot); { - PageStorage::Config config; + PageStorageConfig config; page_storage = reopenWithConfig(config); } diff --git a/dbms/src/Storages/Page/WriteBatch.h b/dbms/src/Storages/Page/WriteBatch.h index 30180874fe6..1359fb77e7d 100644 --- a/dbms/src/Storages/Page/WriteBatch.h +++ b/dbms/src/Storages/Page/WriteBatch.h @@ -27,31 +27,31 @@ namespace ErrorCodes extern const int LOGICAL_ERROR; } // namespace ErrorCodes +enum class WriteBatchWriteType : UInt8 +{ + DEL = 0, + // Create / Update a page, will implicitly create a RefPage{id} -> Page{id}. + PUT = 1, + // Create a RefPage{ref_id} -> Page{id} + REF = 2, + // Create or update a Page. Now only used by GC. + // Compare to `PUT`, this type won't create the RefPage{id} -> Page{id} by default. + UPSERT = 3, + // Create an external page. + // In V2, it is the same as `PUT`; In V3, we treated it as a different type from `PUT` + // to get its lifetime management correct. + PUT_EXTERNAL = 4, +}; + class WriteBatch : private boost::noncopyable { public: - enum class WriteType : UInt8 - { - DEL = 0, - // Create / Update a page, will implicitly create a RefPage{id} -> Page{id}. - PUT = 1, - // Create a RefPage{ref_id} -> Page{id} - REF = 2, - // Create or update a Page. Now only used by GC. - // Compare to `PUT`, this type won't create the RefPage{id} -> Page{id} by default. - UPSERT = 3, - // Create an external page. - // In V2, it is the same as `PUT`; In V3, we treated it as a different type from `PUT` - // to get its lifetime management correct. - PUT_EXTERNAL = 4, - }; - using SequenceID = UInt64; private: struct Write { - WriteType type; + WriteBatchWriteType type; PageId page_id; UInt64 tag; // Page's data and size @@ -90,7 +90,7 @@ class WriteBatch : private boost::noncopyable void putPage(PageId page_id, UInt64 tag, const ReadBufferPtr & read_buffer, PageSize size, const PageFieldSizes & data_sizes = {}) { - // Conver from data_sizes to the offset of each field + // Convert from data_sizes to the offset of each field PageFieldOffsetChecksums offsets; PageFieldOffset off = 0; for (auto data_sz : data_sizes) @@ -110,7 +110,7 @@ class WriteBatch : private boost::noncopyable ErrorCodes::LOGICAL_ERROR); } - Write w{WriteType::PUT, page_id, tag, read_buffer, size, 0, std::move(offsets), 0, 0, {}}; + Write w{WriteBatchWriteType::PUT, page_id, tag, read_buffer, size, 0, std::move(offsets), 0, 0, {}}; total_data_size += size; writes.emplace_back(std::move(w)); } @@ -118,7 +118,7 @@ class WriteBatch : private boost::noncopyable void putExternal(PageId page_id, UInt64 tag) { // External page's data is not managed by PageStorage, which means data is empty. - Write w{WriteType::PUT_EXTERNAL, page_id, tag, nullptr, 0, 0, {}, 0, 0, {}}; + Write w{WriteBatchWriteType::PUT_EXTERNAL, page_id, tag, nullptr, 0, 0, {}, 0, 0, {}}; writes.emplace_back(std::move(w)); } @@ -131,7 +131,7 @@ class WriteBatch : private boost::noncopyable UInt32 size, const PageFieldOffsetChecksums & offsets) { - Write w{WriteType::UPSERT, page_id, tag, read_buffer, size, 0, offsets, 0, 0, file_id}; + Write w{WriteBatchWriteType::UPSERT, page_id, tag, read_buffer, size, 0, offsets, 0, 0, file_id}; writes.emplace_back(std::move(w)); total_data_size += size; } @@ -147,33 +147,42 @@ class WriteBatch : private boost::noncopyable UInt64 page_checksum, const PageFieldOffsetChecksums & offsets) { - Write w{WriteType::UPSERT, page_id, tag, nullptr, size, 0, offsets, page_offset, page_checksum, file_id}; + Write w{WriteBatchWriteType::UPSERT, page_id, tag, nullptr, size, 0, offsets, page_offset, page_checksum, file_id}; writes.emplace_back(std::move(w)); } // Add RefPage{ref_id} -> Page{page_id} void putRefPage(PageId ref_id, PageId page_id) { - Write w{WriteType::REF, ref_id, 0, nullptr, 0, page_id, {}, 0, 0, {}}; + Write w{WriteBatchWriteType::REF, ref_id, 0, nullptr, 0, page_id, {}, 0, 0, {}}; writes.emplace_back(std::move(w)); } void delPage(PageId page_id) { - Write w{WriteType::DEL, page_id, 0, nullptr, 0, 0, {}, 0, 0, {}}; + Write w{WriteBatchWriteType::DEL, page_id, 0, nullptr, 0, 0, {}, 0, 0, {}}; writes.emplace_back(std::move(w)); } - bool empty() const { return writes.empty(); } + bool empty() const + { + return writes.empty(); + } - const Writes & getWrites() const { return writes; } - Writes & getWrites() { return writes; } + const Writes & getWrites() const + { + return writes; + } + Writes & getWrites() + { + return writes; + } size_t putWriteCount() const { size_t count = 0; for (const auto & w : writes) - count += (w.type == WriteType::PUT); + count += (w.type == WriteBatchWriteType::PUT); return count; } @@ -191,9 +200,9 @@ class WriteBatch : private boost::noncopyable void copyWrites(const Writes & writes_) { - for (const auto & write_ : writes_) + for (const auto & w : writes_) { - copyWrite(write_); + copyWrite(w); } } @@ -205,14 +214,31 @@ class WriteBatch : private boost::noncopyable total_data_size = 0; } - SequenceID getSequence() const { return sequence; } + SequenceID getSequence() const + { + return sequence; + } - size_t getTotalDataSize() const { return total_data_size; } + size_t getTotalDataSize() const + { + return total_data_size; + } // `setSequence` should only called by internal method of PageStorage. - void setSequence(SequenceID seq) { sequence = seq; } + void setSequence(SequenceID seq) + { + sequence = seq; + } - NamespaceId getNamespaceId() const { return namespace_id; } + NamespaceId getNamespaceId() const + { + return namespace_id; + } + + PageIdV3Internal getFullPageId(PageId id) const + { + return buildV3Id(namespace_id, id); + } String toString() const { @@ -223,19 +249,19 @@ class WriteBatch : private boost::noncopyable [this](const auto w, FmtBuffer & fb) { switch (w.type) { - case WriteType::PUT: + case WriteBatchWriteType::PUT: fb.fmtAppend("{}.{}", namespace_id, w.page_id); break; - case WriteType::REF: + case WriteBatchWriteType::REF: fb.fmtAppend("{}.{} > {}.{}", namespace_id, w.page_id, namespace_id, w.ori_page_id); break; - case WriteType::DEL: + case WriteBatchWriteType::DEL: fb.fmtAppend("X{}.{}", namespace_id, w.page_id); break; - case WriteType::UPSERT: + case WriteBatchWriteType::UPSERT: fb.fmtAppend("U{}.{}", namespace_id, w.page_id); break; - case WriteType::PUT_EXTERNAL: + case WriteBatchWriteType::PUT_EXTERNAL: fb.fmtAppend("E{}.{}", namespace_id, w.page_id); break; default: diff --git a/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV2.cpp b/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV2.cpp index f9488c4dfd9..e3374b36bc1 100644 --- a/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV2.cpp +++ b/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV2.cpp @@ -70,11 +70,11 @@ enum DebugMode }; void dump_all_entries(PageFileSet & page_files, int32_t mode = DebugMode::DUMP_ALL_ENTRIES); -void list_all_capacity(const PageFileSet & page_files, PageStorage & storage, const PageStorage::Config & config); +void list_all_capacity(const PageFileSet & page_files, PageStorage & storage, const DB::PageStorageConfig & config); -PageStorage::Config parse_storage_config(int argc, char ** argv, Poco::Logger * logger) +DB::PageStorageConfig parse_storage_config(int argc, char ** argv, Poco::Logger * logger) { - PageStorage::Config config; + DB::PageStorageConfig config; if (argc > 4) { size_t num = strtoull(argv[4], nullptr, 10); @@ -173,7 +173,7 @@ try return 0; } - PageStorage::Config config = parse_storage_config(argc, argv, logger); + DB::PageStorageConfig config = parse_storage_config(argc, argv, logger); PageStorage storage("PageCtl", delegator, config, file_provider); storage.restore(); switch (mode) @@ -246,24 +246,24 @@ void dump_all_entries(PageFileSet & page_files, int32_t mode) printf("%s\tseq: %9llu\t", page_file.toString().c_str(), sequence); switch (record.type) { - case DB::WriteBatch::WriteType::PUT_EXTERNAL: - case DB::WriteBatch::WriteType::PUT: + case DB::WriteBatchWriteType::PUT_EXTERNAL: + case DB::WriteBatchWriteType::PUT: printf("PUT"); printPageEntry(record.page_id, record.entry); id_and_caches.emplace_back(std::make_pair(record.page_id, record.entry)); break; - case DB::WriteBatch::WriteType::UPSERT: + case DB::WriteBatchWriteType::UPSERT: printf("UPSERT"); printPageEntry(record.page_id, record.entry); id_and_caches.emplace_back(std::make_pair(record.page_id, record.entry)); break; - case DB::WriteBatch::WriteType::DEL: + case DB::WriteBatchWriteType::DEL: printf("DEL\t%lld\t%llu\t%u\n", // record.page_id, page_file.getFileId(), page_file.getLevel()); break; - case DB::WriteBatch::WriteType::REF: + case DB::WriteBatchWriteType::REF: printf("REF\t%lld\t%lld\t\t%llu\t%u\n", // record.page_id, record.ori_page_id, @@ -292,7 +292,7 @@ void dump_all_entries(PageFileSet & page_files, int32_t mode) } } -void list_all_capacity(const PageFileSet & page_files, PageStorage & storage, const PageStorage::Config & config) +void list_all_capacity(const PageFileSet & page_files, PageStorage & storage, const DB::PageStorageConfig & config) { static constexpr double MB = 1.0 * 1024 * 1024; diff --git a/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp b/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp index 026ad7a633d..09a852c8b3b 100644 --- a/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp +++ b/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp @@ -185,7 +185,7 @@ class PageStorageControlV3 } BlobConfig blob_config; - PageStorage::Config config; + PageStorageConfig config; PageStorageImpl ps_v3("PageStorageControlV3", delegator, config, file_provider_ptr); ps_v3.restore(); PageDirectory::MVCCMapType & mvcc_table_directory = ps_v3.page_directory->mvcc_table_directory; diff --git a/dbms/src/Storages/Page/workload/HeavyMemoryCostInGC.h b/dbms/src/Storages/Page/workload/HeavyMemoryCostInGC.h index 3daaf10ffb3..9bd2fd44a39 100644 --- a/dbms/src/Storages/Page/workload/HeavyMemoryCostInGC.h +++ b/dbms/src/Storages/Page/workload/HeavyMemoryCostInGC.h @@ -49,7 +49,7 @@ class HeavyMemoryCostInGC { stop_watch.start(); - DB::PageStorage::Config config; + DB::PageStorageConfig config; initPageStorage(config, name()); metrics_dumper = std::make_shared(1); diff --git a/dbms/src/Storages/Page/workload/HeavyRead.h b/dbms/src/Storages/Page/workload/HeavyRead.h index 80023f95988..79101605ce1 100644 --- a/dbms/src/Storages/Page/workload/HeavyRead.h +++ b/dbms/src/Storages/Page/workload/HeavyRead.h @@ -48,7 +48,7 @@ class HeavyRead : public StressWorkload void run() override { - DB::PageStorage::Config config; + DB::PageStorageConfig config; initPageStorage(config, name()); PSWriter::fillAllPages(ps); @@ -70,4 +70,4 @@ class HeavyRead : public StressWorkload } } }; -} // namespace DB::PS::tests \ No newline at end of file +} // namespace DB::PS::tests diff --git a/dbms/src/Storages/Page/workload/HeavySkewWriteRead.h b/dbms/src/Storages/Page/workload/HeavySkewWriteRead.h index 0e75bc0d3e5..71f0df43af9 100644 --- a/dbms/src/Storages/Page/workload/HeavySkewWriteRead.h +++ b/dbms/src/Storages/Page/workload/HeavySkewWriteRead.h @@ -48,7 +48,7 @@ class HeavySkewWriteRead : public StressWorkload void run() override { pool.addCapacity(1 + options.num_writers + options.num_readers); - DB::PageStorage::Config config; + DB::PageStorageConfig config; initPageStorage(config, name()); metrics_dumper = std::make_shared(1); @@ -85,4 +85,4 @@ class HeavySkewWriteRead : public StressWorkload return true; } }; -} // namespace DB::PS::tests \ No newline at end of file +} // namespace DB::PS::tests diff --git a/dbms/src/Storages/Page/workload/HeavyWrite.h b/dbms/src/Storages/Page/workload/HeavyWrite.h index 54b7585ee20..4e88e0f34f3 100644 --- a/dbms/src/Storages/Page/workload/HeavyWrite.h +++ b/dbms/src/Storages/Page/workload/HeavyWrite.h @@ -47,7 +47,7 @@ class HeavyWrite : public StressWorkload void run() override { - DB::PageStorage::Config config; + DB::PageStorageConfig config; initPageStorage(config, name()); metrics_dumper = std::make_shared(1); @@ -72,4 +72,4 @@ class HeavyWrite : public StressWorkload return true; } }; -} // namespace DB::PS::tests \ No newline at end of file +} // namespace DB::PS::tests diff --git a/dbms/src/Storages/Page/workload/HighValidBigFileGC.h b/dbms/src/Storages/Page/workload/HighValidBigFileGC.h index cc3b5b45135..87405b0ef3f 100644 --- a/dbms/src/Storages/Page/workload/HighValidBigFileGC.h +++ b/dbms/src/Storages/Page/workload/HighValidBigFileGC.h @@ -58,7 +58,7 @@ class HighValidBigFileGCWorkload { stop_watch.start(); - DB::PageStorage::Config config; + DB::PageStorageConfig config; config.file_max_size = 8ULL * DB::GB; config.file_roll_size = 8ULL * DB::GB; initPageStorage(config, name()); @@ -79,7 +79,7 @@ class HighValidBigFileGCWorkload // Generate normal data in the same Pagefile { - DB::PageStorage::Config config; + DB::PageStorageConfig config; config.file_max_size = DB::PAGE_FILE_MAX_SIZE; config.file_roll_size = DB::PAGE_FILE_ROLL_SIZE; initPageStorage(config, name()); @@ -129,4 +129,4 @@ class HighValidBigFileGCWorkload private: UInt64 gc_time_ms = 0; }; -} // namespace DB::PS::tests \ No newline at end of file +} // namespace DB::PS::tests diff --git a/dbms/src/Storages/Page/workload/HoldSnapshotsLongTime.h b/dbms/src/Storages/Page/workload/HoldSnapshotsLongTime.h index 071a104010c..81816f72375 100644 --- a/dbms/src/Storages/Page/workload/HoldSnapshotsLongTime.h +++ b/dbms/src/Storages/Page/workload/HoldSnapshotsLongTime.h @@ -49,7 +49,7 @@ class HoldSnapshotsLongTime : public StressWorkload void run() override { pool.addCapacity(1 + options.num_writers + options.num_readers); - DB::PageStorage::Config config; + DB::PageStorageConfig config; initPageStorage(config, name()); metrics_dumper = std::make_shared(1); @@ -94,4 +94,4 @@ class HoldSnapshotsLongTime : public StressWorkload return true; } }; -} // namespace DB::PS::tests \ No newline at end of file +} // namespace DB::PS::tests diff --git a/dbms/src/Storages/Page/workload/Normal.h b/dbms/src/Storages/Page/workload/Normal.h index 164f17b9d61..033f226bf89 100644 --- a/dbms/src/Storages/Page/workload/Normal.h +++ b/dbms/src/Storages/Page/workload/Normal.h @@ -44,7 +44,7 @@ class NormalWorkload { pool.addCapacity(1 + options.num_writers + options.num_readers); - DB::PageStorage::Config config; + DB::PageStorageConfig config; config.num_write_slots = options.num_writer_slots; initPageStorage(config); diff --git a/dbms/src/Storages/Page/workload/PSWorkload.cpp b/dbms/src/Storages/Page/workload/PSWorkload.cpp index 81f13527f48..f9ff0b40c08 100644 --- a/dbms/src/Storages/Page/workload/PSWorkload.cpp +++ b/dbms/src/Storages/Page/workload/PSWorkload.cpp @@ -65,7 +65,7 @@ void StressWorkload::onDumpResult() } } -void StressWorkload::initPageStorage(DB::PageStorage::Config & config, String path_prefix) +void StressWorkload::initPageStorage(DB::PageStorageConfig & config, String path_prefix) { DB::FileProviderPtr file_provider = std::make_shared(std::make_shared(false), false); diff --git a/dbms/src/Storages/Page/workload/PSWorkload.h b/dbms/src/Storages/Page/workload/PSWorkload.h index 26a9c24d6da..0c048227a4d 100644 --- a/dbms/src/Storages/Page/workload/PSWorkload.h +++ b/dbms/src/Storages/Page/workload/PSWorkload.h @@ -65,7 +65,7 @@ class StressWorkload virtual void onDumpResult(); protected: - void initPageStorage(DB::PageStorage::Config & config, String path_prefix = ""); + void initPageStorage(DB::PageStorageConfig & config, String path_prefix = ""); void startBackgroundTimer(); diff --git a/dbms/src/Storages/Page/workload/PageStorageInMemoryCapacity.h b/dbms/src/Storages/Page/workload/PageStorageInMemoryCapacity.h index 337c732e6f7..15372c4076c 100644 --- a/dbms/src/Storages/Page/workload/PageStorageInMemoryCapacity.h +++ b/dbms/src/Storages/Page/workload/PageStorageInMemoryCapacity.h @@ -134,7 +134,7 @@ class PageStorageInMemoryCapacity : public StressWorkload std::tie(total_mem, begin_virtual_size, begin_resident_size) = getCurrentMemory(); pool.addCapacity(1 + options.num_writers + options.num_readers); - DB::PageStorage::Config config; + DB::PageStorageConfig config; initPageStorage(config, name()); metrics_dumper = std::make_shared(1); @@ -174,4 +174,4 @@ class PageStorageInMemoryCapacity : public StressWorkload std::round(resident_used) ? (total_mem / ((double)resident_used / page_writen)) : 0)); } }; -} // namespace DB::PS::tests \ No newline at end of file +} // namespace DB::PS::tests diff --git a/dbms/src/Storages/Page/workload/ThousandsOfOffset.h b/dbms/src/Storages/Page/workload/ThousandsOfOffset.h index 0232ea235f1..4bb7a3042c8 100644 --- a/dbms/src/Storages/Page/workload/ThousandsOfOffset.h +++ b/dbms/src/Storages/Page/workload/ThousandsOfOffset.h @@ -70,7 +70,7 @@ class ThousandsOfOffset : public StressWorkload void run() override { pool.addCapacity(1 + options.num_writers + options.num_readers); - DB::PageStorage::Config config; + DB::PageStorageConfig config; initPageStorage(config, name()); metrics_dumper = std::make_shared(1); @@ -169,4 +169,4 @@ class ThousandsOfOffset : public StressWorkload return true; } }; -} // namespace DB::PS::tests \ No newline at end of file +} // namespace DB::PS::tests diff --git a/dbms/src/Storages/Transaction/RegionPersister.cpp b/dbms/src/Storages/Transaction/RegionPersister.cpp index bbd9bcd9687..8f880a556e7 100644 --- a/dbms/src/Storages/Transaction/RegionPersister.cpp +++ b/dbms/src/Storages/Transaction/RegionPersister.cpp @@ -148,7 +148,7 @@ RegionPersister::RegionPersister(Context & global_context_, const RegionManager , log(Logger::get("RegionPersister")) {} -PageStorage::Config RegionPersister::getPageStorageSettings() const +PageStorageConfig RegionPersister::getPageStorageSettings() const { if (!page_writer) { @@ -158,7 +158,7 @@ PageStorage::Config RegionPersister::getPageStorageSettings() const return page_writer->getSettings(); } -PS::V1::PageStorage::Config getV1PSConfig(const PS::V2::PageStorage::Config & config) +PS::V1::PageStorage::Config getV1PSConfig(const PageStorageConfig & config) { PS::V1::PageStorage::Config c; c.sync_on_write = config.sync_on_write; @@ -215,7 +215,7 @@ void RegionPersister::forceTransformKVStoreV2toV3() page_writer->writeIntoV2(std::move(write_batch_del_v2), nullptr); } -RegionMap RegionPersister::restore(PathPool & path_pool, const TiFlashRaftProxyHelper * proxy_helper, PageStorage::Config config) +RegionMap RegionPersister::restore(PathPool & path_pool, const TiFlashRaftProxyHelper * proxy_helper, PageStorageConfig config) { { auto delegator = path_pool.getPSDiskDelegatorRaft(); @@ -376,7 +376,7 @@ bool RegionPersister::gc() { if (page_writer) { - PageStorage::Config config = getConfigFromSettings(global_context.getSettingsRef()); + PageStorageConfig config = getConfigFromSettings(global_context.getSettingsRef()); page_writer->reloadSettings(config); return page_writer->gc(false, nullptr, nullptr); } diff --git a/dbms/src/Storages/Transaction/RegionPersister.h b/dbms/src/Storages/Transaction/RegionPersister.h index 5f179488684..ea5682487cb 100644 --- a/dbms/src/Storages/Transaction/RegionPersister.h +++ b/dbms/src/Storages/Transaction/RegionPersister.h @@ -51,13 +51,13 @@ class RegionPersister final : private boost::noncopyable void drop(RegionID region_id, const RegionTaskLock &); void persist(const Region & region); void persist(const Region & region, const RegionTaskLock & lock); - RegionMap restore(PathPool & path_pool, const TiFlashRaftProxyHelper * proxy_helper = nullptr, PageStorage::Config config = PageStorage::Config{}); + RegionMap restore(PathPool & path_pool, const TiFlashRaftProxyHelper * proxy_helper = nullptr, PageStorageConfig config = PageStorageConfig{}); bool gc(); using RegionCacheWriteElement = std::tuple; static void computeRegionWriteBuffer(const Region & region, RegionCacheWriteElement & region_write_buffer); - PageStorage::Config getPageStorageSettings() const; + PageStorageConfig getPageStorageSettings() const; FileUsageStatistics getFileUsageStatistics() const; diff --git a/dbms/src/Storages/Transaction/tests/gtest_region_persister.cpp b/dbms/src/Storages/Transaction/tests/gtest_region_persister.cpp index 2f3ed021d79..edd946af7f3 100644 --- a/dbms/src/Storages/Transaction/tests/gtest_region_persister.cpp +++ b/dbms/src/Storages/Transaction/tests/gtest_region_persister.cpp @@ -247,7 +247,7 @@ try RegionMap regions; const TableID table_id = 100; - PageStorage::Config config; + PageStorageConfig config; config.file_roll_size = 128 * MB; { UInt64 diff = 0; @@ -321,7 +321,7 @@ try RegionMap regions; TableID table_id = 100; - PageStorage::Config config; + PageStorageConfig config; config.file_roll_size = 16 * 1024; RegionManager region_manager; DB::Timestamp tso = 0; From f837392c7211d1d7a814b7c777bba28cc784258d Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 7 Sep 2022 20:13:35 +0800 Subject: [PATCH 06/40] Support using string as PageId Signed-off-by: JaySon-Huang --- dbms/CMakeLists.txt | 1 + dbms/src/Storages/Page/PageDefines.h | 3 + dbms/src/Storages/Page/UniversalPage.h | 86 ++++++ dbms/src/Storages/Page/UniversalPageStorage.h | 167 ++++++++++++ dbms/src/Storages/Page/UniversalWriteBatch.h | 184 +++++++++++++ dbms/src/Storages/Page/V3/Blob/BlobStat.h | 1 + dbms/src/Storages/Page/V3/BlobStore.cpp | 113 +++++--- dbms/src/Storages/Page/V3/BlobStore.h | 124 +++++++-- dbms/src/Storages/Page/V3/PageDirectory.cpp | 230 ++++++++++------ dbms/src/Storages/Page/V3/PageDirectory.h | 136 ++++++--- .../Page/V3/PageDirectory/ExternalIdTrait.h | 66 +++++ .../PageDirectory/ExternalIdsByNamespace.cpp | 27 +- .../V3/PageDirectory/ExternalIdsByNamespace.h | 21 +- .../Storages/Page/V3/PageDirectoryFactory.cpp | 48 +++- .../Storages/Page/V3/PageDirectoryFactory.h | 58 +++- dbms/src/Storages/Page/V3/PageEntriesEdit.h | 47 ++-- dbms/src/Storages/Page/V3/PageEntry.h | 1 - dbms/src/Storages/Page/V3/PageStorageImpl.cpp | 18 +- dbms/src/Storages/Page/V3/PageStorageImpl.h | 5 +- dbms/src/Storages/Page/V3/WAL/serialize.cpp | 192 ++++++++++--- dbms/src/Storages/Page/V3/WAL/serialize.h | 23 +- .../Storages/Page/V3/tests/entries_helper.h | 9 +- .../Page/V3/tests/gtest_blob_store.cpp | 129 ++++----- .../Page/V3/tests/gtest_page_directory.cpp | 257 ++++++++++-------- .../Page/V3/tests/gtest_page_storage.cpp | 2 +- .../Page/V3/tests/gtest_versioned_entries.cpp | 24 +- .../Page/V3/tests/gtest_wal_store.cpp | 92 +++++-- .../Page/tools/PageCtl/PageStorageCtlV3.cpp | 42 +-- .../Page/universal/UniversalPageStorage.cpp | 50 ++++ 29 files changed, 1614 insertions(+), 542 deletions(-) create mode 100644 dbms/src/Storages/Page/UniversalPage.h create mode 100644 dbms/src/Storages/Page/UniversalPageStorage.h create mode 100644 dbms/src/Storages/Page/UniversalWriteBatch.h create mode 100644 dbms/src/Storages/Page/V3/PageDirectory/ExternalIdTrait.h create mode 100644 dbms/src/Storages/Page/universal/UniversalPageStorage.cpp diff --git a/dbms/CMakeLists.txt b/dbms/CMakeLists.txt index c5813f9735a..c7dc6d3dd89 100644 --- a/dbms/CMakeLists.txt +++ b/dbms/CMakeLists.txt @@ -100,6 +100,7 @@ add_headers_and_sources(dbms src/Storages/Page/V3/WAL) add_headers_and_sources(dbms src/Storages/Page/V3/spacemap) add_headers_and_sources(dbms src/Storages/Page/V3/PageDirectory) add_headers_and_sources(dbms src/Storages/Page/V3/Blob) +add_headers_and_sources(dbms src/Storages/Page/universal) add_headers_and_sources(dbms src/Storages/Page/) add_headers_and_sources(dbms src/TiDB) add_headers_and_sources(dbms src/Client) diff --git a/dbms/src/Storages/Page/PageDefines.h b/dbms/src/Storages/Page/PageDefines.h index 0feb33494a6..2a2aa921103 100644 --- a/dbms/src/Storages/Page/PageDefines.h +++ b/dbms/src/Storages/Page/PageDefines.h @@ -85,6 +85,9 @@ using BlobFileOffset = UInt64; static constexpr BlobFileId INVALID_BLOBFILE_ID = 0; static constexpr BlobFileOffset INVALID_BLOBFILE_OFFSET = std::numeric_limits::max(); +using UniversalPageId = String; +using UniversalPageIds = std::vector; + struct ByteBuffer { using Pos = char *; diff --git a/dbms/src/Storages/Page/UniversalPage.h b/dbms/src/Storages/Page/UniversalPage.h new file mode 100644 index 00000000000..25545579678 --- /dev/null +++ b/dbms/src/Storages/Page/UniversalPage.h @@ -0,0 +1,86 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace DB +{ + +struct UniversalPage +{ +public: + explicit UniversalPage(const UniversalPageId & page_id_) + : page_id(page_id_) + { + } + + UniversalPageId page_id; + ByteBuffer data; + MemHolder mem_holder; + // Field offsets inside this page. + std::set field_offsets; + +public: + inline bool isValid() const { return !page_id.empty(); } + + ByteBuffer getFieldData(size_t index) const + { + auto iter = field_offsets.find(FieldOffsetInsidePage(index)); + if (unlikely(iter == field_offsets.end())) + throw Exception(fmt::format("Try to getFieldData with invalid field index [page_id={}] [field_index={}]", page_id, index), + ErrorCodes::LOGICAL_ERROR); + + PageFieldOffset beg = iter->offset; + ++iter; + PageFieldOffset end = (iter == field_offsets.end() ? data.size() : iter->offset); + assert(beg <= data.size()); + assert(end <= data.size()); + return ByteBuffer(data.begin() + beg, data.begin() + end); + } + + inline static PageFieldSizes fieldOffsetsToSizes(const PageFieldOffsetChecksums & field_offsets, size_t data_size) + { + PageFieldSizes field_size = {}; + + auto it = field_offsets.begin(); + while (it != field_offsets.end()) + { + PageFieldOffset beg = it->first; + ++it; + field_size.emplace_back(it == field_offsets.end() ? data_size - beg : it->first - beg); + } + return field_size; + } + + size_t fieldSize() const + { + return field_offsets.size(); + } +}; + +using UniversalPages = std::vector; +using UniversalPageMap = std::map; + +} // namespace DB diff --git a/dbms/src/Storages/Page/UniversalPageStorage.h b/dbms/src/Storages/Page/UniversalPageStorage.h new file mode 100644 index 00000000000..e5b1350d7e4 --- /dev/null +++ b/dbms/src/Storages/Page/UniversalPageStorage.h @@ -0,0 +1,167 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DB +{ +class FileProvider; +using FileProviderPtr = std::shared_ptr; +class PathCapacityMetrics; +using PathCapacityMetricsPtr = std::shared_ptr; +class PSDiskDelegator; +using PSDiskDelegatorPtr = std::shared_ptr; +class Context; +class WriteLimiter; +using WriteLimiterPtr = std::shared_ptr; +class ReadLimiter; +using ReadLimiterPtr = std::shared_ptr; + +class UniversalPageStorage; +using UniversalPageStoragePtr = std::shared_ptr; + +class KVStoreReader; + +class UniversalPageStorage final +{ +public: + using SnapshotPtr = PageStorageSnapshotPtr; + struct Config + { + }; + +public: + static UniversalPageStoragePtr + create( + String name, + PSDiskDelegatorPtr delegator, + const UniversalPageStorage::Config & config, + const FileProviderPtr & file_provider); + + UniversalPageStorage( + String name, + PSDiskDelegatorPtr delegator_, + const Config & config_, + const FileProviderPtr & file_provider_) + : storage_name(std::move(name)) + , delegator(std::move(delegator_)) + , config(config_) + , file_provider(file_provider_) + { + } + + ~UniversalPageStorage() = default; + + void restore(); + + SnapshotPtr getSnapshot(const String & tracing_id) const + { + return page_directory->createSnapshot(tracing_id); + } + + // Get some statistics of all living snapshots and the oldest living snapshot. + SnapshotsStatistics getSnapshotsStat() const + { + return page_directory->getSnapshotsStat(); + } + + FileUsageStatistics getFileUsageStatistics() const + { + return blob_store->getFileUsageStatistics(); + } + + void write(UniversalWriteBatch && write_batch, const WriteLimiterPtr & write_limiter = nullptr) + { + UNUSED(write_batch, write_limiter); + } + + UniversalPageMap read(const UniversalPageId & page_ids, const ReadLimiterPtr & read_limiter = nullptr, SnapshotPtr snapshot = {}) + { + UNUSED(page_ids, read_limiter, snapshot); + throw Exception("", ErrorCodes::NOT_IMPLEMENTED); + } + + using FieldIndices = std::vector; + using PageReadFields = std::pair; + + UniversalPageMap read(const std::vector & page_fields, const ReadLimiterPtr & read_limiter = nullptr, SnapshotPtr snapshot = {}) + { + UNUSED(page_fields, read_limiter, snapshot); + throw Exception("", ErrorCodes::NOT_IMPLEMENTED); + } + + UniversalPage read(const PageReadFields & page_field, const ReadLimiterPtr & read_limiter = nullptr, SnapshotPtr snapshot = {}) + { + UNUSED(page_field, read_limiter, snapshot); + throw Exception("", ErrorCodes::NOT_IMPLEMENTED); + } + + // We may skip the GC to reduce useless reading by default. + bool gc(bool not_skip = false, const WriteLimiterPtr & write_limiter = nullptr, const ReadLimiterPtr & read_limiter = nullptr) + { + UNUSED(not_skip, write_limiter, read_limiter); + return false; + } + + // Register and unregister external pages GC callbacks + // Note that user must ensure that it is safe to call `scanner` and `remover` even after unregister. + void registerExternalPagesCallbacks(const ExternalPageCallbacks & callbacks) { UNUSED(callbacks); } + void unregisterExternalPagesCallbacks(NamespaceId /*ns_id*/) {} + + String storage_name; // Identify between different Storage + PSDiskDelegatorPtr delegator; // Get paths for storing data + Config config; + FileProviderPtr file_provider; + + PS::V3::universal::PageDirectoryPtr page_directory; + PS::V3::universal::BlobStorePtr blob_store; +}; + +class KVStoreReader +{ +public: + KVStoreReader(UniversalPageStorage & storage) + : uni_storage(storage) + {} + + bool isAppliedIndexExceed(PageId page_id, UInt64 applied_index) + { + // assume use this format + UniversalPageId uni_page_id = fmt::format("k_{}", page_id); + auto snap = uni_storage.getSnapshot(""); + const auto & [id, entry] = uni_storage.page_directory->getByIDOrNull(uni_page_id, snap); + return (entry.isValid() && entry.tag > applied_index); + } + + void traverse(const std::function & /*acceptor*/) + { + // Only traverse pages with id prefix + throw Exception("", ErrorCodes::NOT_IMPLEMENTED); + } + +private: + UniversalPageStorage & uni_storage; +}; + +} // namespace DB diff --git a/dbms/src/Storages/Page/UniversalWriteBatch.h b/dbms/src/Storages/Page/UniversalWriteBatch.h new file mode 100644 index 00000000000..ea8a2e9f11c --- /dev/null +++ b/dbms/src/Storages/Page/UniversalWriteBatch.h @@ -0,0 +1,184 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +#include + +namespace DB +{ +namespace ErrorCodes +{ +extern const int LOGICAL_ERROR; +} // namespace ErrorCodes + +class UniversalWriteBatch : private boost::noncopyable +{ +private: + struct Write + { + WriteBatchWriteType type; + UniversalPageId page_id; + UInt64 tag; + // Page's data and size + ReadBufferPtr read_buffer; + PageSize size; + // RefPage's origin page + UniversalPageId ori_page_id; + // Fields' offset inside Page's data + PageFieldOffsetChecksums offsets; + + /// The meta and data may not be the same PageFile, (read_buffer == nullptr) + /// use `target_file_id`, `page_offset`, `page_checksum` to indicate where + /// data is actually store in. + /// Should only use by `UPSERT` now. + + UInt64 page_offset; + UInt64 page_checksum; + PageFileIdAndLevel target_file_id; + }; + using Writes = std::vector; + +public: + UniversalWriteBatch() = default; + + void putPage(UniversalPageId page_id, UInt64 tag, const ReadBufferPtr & read_buffer, PageSize size, const PageFieldSizes & data_sizes = {}) + { + // Convert from data_sizes to the offset of each field + PageFieldOffsetChecksums offsets; + PageFieldOffset off = 0; + for (auto data_sz : data_sizes) + { + offsets.emplace_back(off, 0); + off += data_sz; + } + if (unlikely(!data_sizes.empty() && off != size)) + { + throw Exception(fmt::format( + "Try to put Page with fields, but page size and fields total size not match " + "[page_id={}] [num_fields={}] [page_size={}] [all_fields_size={}]", + page_id, + data_sizes.size(), + size, + off), + ErrorCodes::LOGICAL_ERROR); + } + + Write w{WriteBatchWriteType::PUT, page_id, tag, read_buffer, size, "", std::move(offsets), 0, 0, {}}; + total_data_size += size; + writes.emplace_back(std::move(w)); + } + + void putExternal(UniversalPageId page_id, UInt64 tag) + { + // External page's data is not managed by PageStorage, which means data is empty. + Write w{WriteBatchWriteType::PUT_EXTERNAL, page_id, tag, nullptr, 0, "", {}, 0, 0, {}}; + writes.emplace_back(std::move(w)); + } + + // Add RefPage{ref_id} -> Page{page_id} + void putRefPage(UniversalPageId ref_id, UniversalPageId page_id) + { + Write w{WriteBatchWriteType::REF, ref_id, 0, nullptr, 0, page_id, {}, 0, 0, {}}; + writes.emplace_back(std::move(w)); + } + + void delPage(UniversalPageId page_id) + { + Write w{WriteBatchWriteType::DEL, page_id, 0, nullptr, 0, "", {}, 0, 0, {}}; + writes.emplace_back(std::move(w)); + } + + bool empty() const + { + return writes.empty(); + } + + const Writes & getWrites() const + { + return writes; + } + Writes & getWrites() + { + return writes; + } + + size_t putWriteCount() const + { + size_t count = 0; + for (const auto & w : writes) + count += (w.type == WriteBatchWriteType::PUT); + return count; + } + + void swap(UniversalWriteBatch & o) + { + writes.swap(o.writes); + std::swap(o.total_data_size, total_data_size); + } + + void clear() + { + Writes tmp; + writes.swap(tmp); + total_data_size = 0; + } + + size_t getTotalDataSize() const + { + return total_data_size; + } + + static UniversalPageId getFullPageId(const UniversalPageId & id) { return id; } + + String toString() const + { + FmtBuffer fmt_buffer; + fmt_buffer.joinStr( + writes.begin(), + writes.end(), + [](const auto & w, FmtBuffer & fb) { + switch (w.type) + { + case WriteBatchWriteType::PUT: + fb.fmtAppend("{}", w.page_id); + break; + case WriteBatchWriteType::REF: + fb.fmtAppend("{} > {}", w.page_id, w.ori_page_id); + break; + case WriteBatchWriteType::DEL: + fb.fmtAppend("X{}", w.page_id); + break; + case WriteBatchWriteType::PUT_EXTERNAL: + fb.fmtAppend("E{}", w.page_id); + break; + default: + fb.fmtAppend("Unknow {}", w.page_id); + break; + }; + }, + ","); + return fmt_buffer.toString(); + } + +private: + Writes writes; + size_t total_data_size = 0; +}; +} // namespace DB diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.h b/dbms/src/Storages/Page/V3/Blob/BlobStat.h index 531eb2441f9..20f1565a25b 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.h +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.h @@ -182,6 +182,7 @@ class BlobStats #endif void restoreByEntry(const PageEntryV3 & entry); void restore(); + template friend class PageDirectoryFactory; #ifndef DBMS_PUBLIC_GTEST diff --git a/dbms/src/Storages/Page/V3/BlobStore.cpp b/dbms/src/Storages/Page/V3/BlobStore.cpp index 10d6ded388f..f82d9da714d 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.cpp +++ b/dbms/src/Storages/Page/V3/BlobStore.cpp @@ -65,7 +65,8 @@ using ChecksumClass = Digest::CRC64; * BlobStore methods * *********************/ -BlobStore::BlobStore(String storage_name, const FileProviderPtr & file_provider_, PSDiskDelegatorPtr delegator_, const BlobConfig & config_) +template +BlobStore::BlobStore(String storage_name, const FileProviderPtr & file_provider_, PSDiskDelegatorPtr delegator_, const BlobConfig & config_) : delegator(std::move(delegator_)) , file_provider(file_provider_) , config(config_) @@ -75,7 +76,8 @@ BlobStore::BlobStore(String storage_name, const FileProviderPtr & file_provider_ { } -void BlobStore::registerPaths() +template +void BlobStore::registerPaths() { for (const auto & path : delegator->listPaths()) { @@ -109,7 +111,8 @@ void BlobStore::registerPaths() } } -void BlobStore::reloadConfig(const BlobConfig & rhs) +template +void BlobStore::reloadConfig(const BlobConfig & rhs) { // Currently, we don't add any config for `file_limit_size`, so it won't reload at run time. // And if we support it in the future(although it seems there is no need to do that), @@ -123,7 +126,8 @@ void BlobStore::reloadConfig(const BlobConfig & rhs) config.heavy_gc_valid_rate = rhs.heavy_gc_valid_rate; } -FileUsageStatistics BlobStore::getFileUsageStatistics() const +template +FileUsageStatistics BlobStore::getFileUsageStatistics() const { FileUsageStatistics usage; @@ -155,9 +159,11 @@ FileUsageStatistics BlobStore::getFileUsageStatistics() const return usage; } -PageEntriesEdit BlobStore::handleLargeWrite(DB::WriteBatch & wb, const WriteLimiterPtr & write_limiter) +template +typename Trait::PageEntriesEdit +BlobStore::handleLargeWrite(typename Trait::WriteBatch & wb, const WriteLimiterPtr & write_limiter) { - PageEntriesEdit edit; + typename Trait::PageEntriesEdit edit; for (auto & write : wb.getWrites()) { switch (write.type) @@ -235,13 +241,15 @@ PageEntriesEdit BlobStore::handleLargeWrite(DB::WriteBatch & wb, const WriteLimi return edit; } -PageEntriesEdit BlobStore::write(DB::WriteBatch & wb, const WriteLimiterPtr & write_limiter) +template +typename Trait::PageEntriesEdit +BlobStore::write(typename Trait::WriteBatch & wb, const WriteLimiterPtr & write_limiter) { ProfileEvents::increment(ProfileEvents::PSMWritePages, wb.putWriteCount()); const size_t all_page_data_size = wb.getTotalDataSize(); - PageEntriesEdit edit; + typename Trait::PageEntriesEdit edit; if (all_page_data_size == 0) { @@ -397,7 +405,8 @@ PageEntriesEdit BlobStore::write(DB::WriteBatch & wb, const WriteLimiterPtr & wr return edit; } -void BlobStore::remove(const PageEntriesV3 & del_entries) +template +void BlobStore::remove(const PageEntriesV3 & del_entries) { std::set blob_updated; for (const auto & entry : del_entries) @@ -445,7 +454,8 @@ void BlobStore::remove(const PageEntriesV3 & del_entries) } } -std::pair BlobStore::getPosFromStats(size_t size) +template +std::pair BlobStore::getPosFromStats(size_t size) { BlobStatPtr stat; @@ -495,7 +505,8 @@ std::pair BlobStore::getPosFromStats(size_t size) return std::make_pair(stat->id, offset); } -void BlobStore::removePosFromStats(BlobFileId blob_id, BlobFileOffset offset, size_t size) +template +void BlobStore::removePosFromStats(BlobFileId blob_id, BlobFileOffset offset, size_t size) { bool need_remove_stat = false; const auto & stat = blob_stats.blobIdToStat(blob_id); @@ -521,7 +532,8 @@ void BlobStore::removePosFromStats(BlobFileId blob_id, BlobFileOffset offset, si } } -void BlobStore::read(PageIDAndEntriesV3 & entries, const PageHandler & handler, const ReadLimiterPtr & read_limiter) +template +void BlobStore::read(typename Trait::PageIdAndEntries & entries, const typename Trait::PageHandler & handler, const ReadLimiterPtr & read_limiter) { if (entries.empty()) { @@ -548,8 +560,8 @@ void BlobStore::read(PageIDAndEntriesV3 & entries, const PageHandler & handler, { (void)entry; LOG_DEBUG(log, "Read entry [page_id={}] without entry size.", page_id_v3); - Page page(page_id_v3); - handler(page_id_v3.low, page); + typename Trait::Page page(page_id_v3); + handler(ExternalIdTrait::getU64ID(page_id_v3), page); } return; } @@ -581,14 +593,15 @@ void BlobStore::read(PageIDAndEntriesV3 & entries, const PageHandler & handler, } } - Page page(page_id_v3); + typename Trait::Page page(page_id_v3); page.data = ByteBuffer(data_buf, data_buf + entry.size); page.mem_holder = mem_holder; - handler(page_id_v3.low, page); + handler(ExternalIdTrait::getU64ID(page_id_v3), page); } } -PageMap BlobStore::read(FieldReadInfos & to_read, const ReadLimiterPtr & read_limiter) +template +typename Trait::PageMap BlobStore::read(typename Trait::FieldReadInfos & to_read, const ReadLimiterPtr & read_limiter) { if (to_read.empty()) { @@ -601,7 +614,7 @@ PageMap BlobStore::read(FieldReadInfos & to_read, const ReadLimiterPtr & read_li std::sort( to_read.begin(), to_read.end(), - [](const FieldReadInfo & a, const FieldReadInfo & b) { return a.entry.offset < b.entry.offset; }); + [](const typename Trait::FieldReadInfo & a, const typename Trait::FieldReadInfo & b) { return a.entry.offset < b.entry.offset; }); // allocate data_buf that can hold all pages with specify fields @@ -630,7 +643,7 @@ PageMap BlobStore::read(FieldReadInfos & to_read, const ReadLimiterPtr & read_li std::set fields_offset_in_page; char * pos = data_buf; - PageMap page_map; + typename Trait::PageMap page_map; for (const auto & [page_id_v3, entry, fields] : to_read) { size_t read_size_this_entry = 0; @@ -672,12 +685,12 @@ PageMap BlobStore::read(FieldReadInfos & to_read, const ReadLimiterPtr & read_li write_offset += size_to_read; } - Page page(page_id_v3); + typename Trait::Page page(page_id_v3); page.data = ByteBuffer(pos, write_offset); page.mem_holder = mem_holder; page.field_offsets.swap(fields_offset_in_page); fields_offset_in_page.clear(); - page_map.emplace(page_id_v3.low, std::move(page)); + page_map.emplace(ExternalIdTrait::getU64ID(page_id_v3), std::move(page)); pos = write_offset; } @@ -690,7 +703,8 @@ PageMap BlobStore::read(FieldReadInfos & to_read, const ReadLimiterPtr & read_li return page_map; } -PageMap BlobStore::read(PageIDAndEntriesV3 & entries, const ReadLimiterPtr & read_limiter) +template +typename Trait::PageMap BlobStore::read(typename Trait::PageIdAndEntries & entries, const ReadLimiterPtr & read_limiter) { if (entries.empty()) { @@ -715,13 +729,13 @@ PageMap BlobStore::read(PageIDAndEntriesV3 & entries, const ReadLimiterPtr & rea // The `buf_size` will be 0, we need avoid calling malloc/free with size 0. if (buf_size == 0) { - PageMap page_map; + typename Trait::PageMap page_map; for (const auto & [page_id_v3, entry] : entries) { (void)entry; LOG_DEBUG(log, "Read entry [page_id={}] without entry size.", page_id_v3); - Page page(page_id_v3); - page_map.emplace(page_id_v3.low, page); + typename Trait::Page page(page_id_v3); + page_map.emplace(ExternalIdTrait::getU64ID(page_id_v3), page); } return page_map; } @@ -732,7 +746,7 @@ PageMap BlobStore::read(PageIDAndEntriesV3 & entries, const ReadLimiterPtr & rea }); char * pos = data_buf; - PageMap page_map; + typename Trait::PageMap page_map; for (const auto & [page_id_v3, entry] : entries) { auto blob_file = read(page_id_v3, entry.file_id, entry.offset, pos, entry.size, read_limiter); @@ -755,10 +769,10 @@ PageMap BlobStore::read(PageIDAndEntriesV3 & entries, const ReadLimiterPtr & rea } } - Page page(page_id_v3); + typename Trait::Page page(page_id_v3); page.data = ByteBuffer(pos, pos + entry.size); page.mem_holder = mem_holder; - page_map.emplace(page_id_v3.low, page); + page_map.emplace(ExternalIdTrait::getU64ID(page_id_v3), page); pos += entry.size; } @@ -772,11 +786,12 @@ PageMap BlobStore::read(PageIDAndEntriesV3 & entries, const ReadLimiterPtr & rea return page_map; } -Page BlobStore::read(const PageIDAndEntryV3 & id_entry, const ReadLimiterPtr & read_limiter) +template +typename Trait::Page BlobStore::read(const typename Trait::PageIdAndEntry & id_entry, const ReadLimiterPtr & read_limiter) { if (!id_entry.second.isValid()) { - Page page_not_found(buildV3Id(id_entry.first.high, INVALID_PAGE_ID)); + typename Trait::Page page_not_found(ExternalIdTrait::getInvalidID()); return page_not_found; } @@ -788,7 +803,7 @@ Page BlobStore::read(const PageIDAndEntryV3 & id_entry, const ReadLimiterPtr & r if (buf_size == 0) { LOG_DEBUG(log, "Read entry [page_id={}] without entry size.", page_id_v3); - Page page(page_id_v3); + typename Trait::Page page(page_id_v3); return page; } @@ -816,14 +831,22 @@ Page BlobStore::read(const PageIDAndEntryV3 & id_entry, const ReadLimiterPtr & r } } - Page page(page_id_v3); + typename Trait::Page page(page_id_v3); page.data = ByteBuffer(data_buf, data_buf + buf_size); page.mem_holder = mem_holder; return page; } -BlobFilePtr BlobStore::read(const PageIdV3Internal & page_id_v3, BlobFileId blob_id, BlobFileOffset offset, char * buffers, size_t size, const ReadLimiterPtr & read_limiter, bool background) +template +BlobFilePtr BlobStore::read( + const typename Trait::PageId & page_id_v3, + BlobFileId blob_id, + BlobFileOffset offset, + char * buffers, + size_t size, + const ReadLimiterPtr & read_limiter, + bool background) { assert(buffers != nullptr); BlobFilePtr blob_file = getBlobFile(blob_id); @@ -931,7 +954,8 @@ struct BlobStoreGCInfo } }; -std::vector BlobStore::getGCStats() +template +std::vector BlobStore::getGCStats() { // Get a copy of stats map to avoid the big lock on stats map const auto stats_list = blob_stats.getStats(); @@ -1035,13 +1059,15 @@ std::vector BlobStore::getGCStats() } -PageEntriesEdit BlobStore::gc(std::map & entries_need_gc, - const PageSize & total_page_size, - const WriteLimiterPtr & write_limiter, - const ReadLimiterPtr & read_limiter) +template +typename Trait::PageEntriesEdit +BlobStore::gc(typename Trait::GcEntriesMap & entries_need_gc, + const PageSize & total_page_size, + const WriteLimiterPtr & write_limiter, + const ReadLimiterPtr & read_limiter) { std::vector> written_blobs; - PageEntriesEdit edit; + PageEntriesEdit edit; if (total_page_size == 0) { @@ -1187,7 +1213,8 @@ PageEntriesEdit BlobStore::gc(std::map & } -String BlobStore::getBlobFileParentPath(BlobFileId blob_id) +template +String BlobStore::getBlobFileParentPath(BlobFileId blob_id) { PageFileIdAndLevel id_lvl{blob_id, 0}; String parent_path = delegator->getPageFilePath(id_lvl); @@ -1198,7 +1225,8 @@ String BlobStore::getBlobFileParentPath(BlobFileId blob_id) return parent_path; } -BlobFilePtr BlobStore::getBlobFile(BlobFileId blob_id) +template +BlobFilePtr BlobStore::getBlobFile(BlobFileId blob_id) { return cached_files.getOrSet(blob_id, [this, blob_id]() -> BlobFilePtr { return std::make_shared(getBlobFileParentPath(blob_id), blob_id, file_provider, delegator); @@ -1206,5 +1234,8 @@ BlobFilePtr BlobStore::getBlobFile(BlobFileId blob_id) .first; } +template class BlobStore; +template class BlobStore; + } // namespace PS::V3 } // namespace DB diff --git a/dbms/src/Storages/Page/V3/BlobStore.h b/dbms/src/Storages/Page/V3/BlobStore.h index c0357d353ab..bec5777c5b3 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.h +++ b/dbms/src/Storages/Page/V3/BlobStore.h @@ -20,9 +20,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include @@ -40,8 +43,9 @@ extern const int LOGICAL_ERROR; namespace PS::V3 { -using PageIdAndVersionedEntries = std::vector>; + +template class BlobStore : private Allocator { public: @@ -55,43 +59,41 @@ class BlobStore : private Allocator std::vector getGCStats(); - PageEntriesEdit gc(std::map & entries_need_gc, - const PageSize & total_page_size, - const WriteLimiterPtr & write_limiter = nullptr, - const ReadLimiterPtr & read_limiter = nullptr); + typename Trait::PageEntriesEdit + gc(typename Trait::GcEntriesMap & entries_need_gc, + const PageSize & total_page_size, + const WriteLimiterPtr & write_limiter = nullptr, + const ReadLimiterPtr & read_limiter = nullptr); - PageEntriesEdit write(DB::WriteBatch & wb, const WriteLimiterPtr & write_limiter = nullptr); + typename Trait::PageEntriesEdit + write(typename Trait::WriteBatch & wb, const WriteLimiterPtr & write_limiter = nullptr); void remove(const PageEntriesV3 & del_entries); - PageMap read(PageIDAndEntriesV3 & entries, const ReadLimiterPtr & read_limiter = nullptr); - - Page read(const PageIDAndEntryV3 & entry, const ReadLimiterPtr & read_limiter = nullptr); + typename Trait::PageMap read(typename Trait::PageIdAndEntries & entries, const ReadLimiterPtr & read_limiter = nullptr); - void read(PageIDAndEntriesV3 & entries, const PageHandler & handler, const ReadLimiterPtr & read_limiter = nullptr); + typename Trait::Page read(const typename Trait::PageIdAndEntry & entry, const ReadLimiterPtr & read_limiter = nullptr); - struct FieldReadInfo - { - PageIdV3Internal page_id; - PageEntryV3 entry; - std::vector fields; + void read(typename Trait::PageIdAndEntries & entries, const typename Trait::PageHandler & handler, const ReadLimiterPtr & read_limiter = nullptr); - FieldReadInfo(PageIdV3Internal id_, PageEntryV3 entry_, std::vector fields_) - : page_id(id_) - , entry(entry_) - , fields(std::move(fields_)) - {} - }; - using FieldReadInfos = std::vector; - PageMap read(FieldReadInfos & to_read, const ReadLimiterPtr & read_limiter = nullptr); + typename Trait::PageMap read(typename Trait::FieldReadInfos & to_read, const ReadLimiterPtr & read_limiter = nullptr); #ifndef DBMS_PUBLIC_GTEST private: #endif + using ExternalIdTrait = typename Trait::ExternalIdTrait; - PageEntriesEdit handleLargeWrite(DB::WriteBatch & wb, const WriteLimiterPtr & write_limiter = nullptr); + typename Trait::PageEntriesEdit + handleLargeWrite(typename Trait::WriteBatch & wb, const WriteLimiterPtr & write_limiter = nullptr); - BlobFilePtr read(const PageIdV3Internal & page_id_v3, BlobFileId blob_id, BlobFileOffset offset, char * buffers, size_t size, const ReadLimiterPtr & read_limiter = nullptr, bool background = false); + BlobFilePtr read( + const typename Trait::PageId & page_id_v3, + BlobFileId blob_id, + BlobFileOffset offset, + char * buffers, + size_t size, + const ReadLimiterPtr & read_limiter = nullptr, + bool background = false); /** * Ask BlobStats to get a span from BlobStat. @@ -110,6 +112,7 @@ class BlobStore : private Allocator BlobFilePtr getBlobFile(BlobFileId blob_id); + template friend class PageDirectoryFactory; friend class PageStorageControlV3; @@ -128,7 +131,76 @@ class BlobStore : private Allocator DB::LRUCache cached_files; }; -using BlobStorePtr = std::shared_ptr; + +namespace u128 +{ +struct BlobStoreTrait +{ + using PageId = PageIdV3Internal; + using PageEntriesEdit = PageEntriesEdit; + using GcEntries = std::vector>; + using GcEntriesMap = std::map; + using PageIdAndEntry = PageIDAndEntryV3; + using PageIdAndEntries = PageIDAndEntriesV3; + using Page = Page; + using PageMap = PageMap; + using PageHandler = PageHandler; + + using ExternalIdTrait = ExternalIdTrait; + using WriteBatch = DB::WriteBatch; + + struct FieldReadInfo + { + PageId page_id; + PageEntryV3 entry; + std::vector fields; + + FieldReadInfo(const PageId & id_, PageEntryV3 entry_, std::vector fields_) + : page_id(id_) + , entry(entry_) + , fields(std::move(fields_)) + {} + }; + using FieldReadInfos = std::vector; +}; + +using BlobStorePtr = std::shared_ptr>; +} // namespace u128 + +namespace universal +{ +struct BlobStoreTrait +{ + using PageId = UniversalPageId; + using PageEntriesEdit = PageEntriesEdit; + using GcEntries = std::vector>; + using GcEntriesMap = std::map; + using PageIdAndEntry = std::pair; + using PageIdAndEntries = std::vector; + using Page = UniversalPage; + // TODO: universal pagemap/handler may should not filter by prefix + using PageMap = std::map; + using PageHandler = std::function; + + using ExternalIdTrait = ExternalIdTrait; + using WriteBatch = UniversalWriteBatch; + + struct FieldReadInfo + { + PageId page_id; + PageEntryV3 entry; + std::vector fields; + + FieldReadInfo(const PageId & id_, PageEntryV3 entry_, std::vector fields_) + : page_id(id_) + , entry(entry_) + , fields(std::move(fields_)) + {} + }; + using FieldReadInfos = std::vector; +}; +using BlobStorePtr = std::shared_ptr>; +} // namespace universal } // namespace PS::V3 } // namespace DB diff --git a/dbms/src/Storages/Page/V3/PageDirectory.cpp b/dbms/src/Storages/Page/V3/PageDirectory.cpp index e95016e8eca..b22ce35cd82 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectory.cpp @@ -67,7 +67,8 @@ namespace PS::V3 * VersionedPageEntries methods * ********************************/ -void VersionedPageEntries::createNewEntry(const PageVersion & ver, const PageEntryV3 & entry) +template +void VersionedPageEntries::createNewEntry(const PageVersion & ver, const PageEntryV3 & entry) { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_DELETE) @@ -120,7 +121,8 @@ void VersionedPageEntries::createNewEntry(const PageVersion & ver, const PageEnt // Create a new external version with version=`ver`. // If create success, then return a shared_ptr as a holder for page_id. The holder // will be release when this external version is totally removed. -std::shared_ptr VersionedPageEntries::createNewExternal(const PageVersion & ver) +template +typename Trait::PageIdSharedPtr VersionedPageEntries::createNewExternal(const PageVersion & ver) { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_DELETE) @@ -131,7 +133,7 @@ std::shared_ptr VersionedPageEntries::createNewExternal(const delete_ver = PageVersion(0); being_ref_count = 1; // return the new created holder to caller to set the page_id - external_holder = std::make_shared(0, 0); + external_holder = std::make_shared(0, 0); return external_holder; } @@ -147,7 +149,7 @@ std::shared_ptr VersionedPageEntries::createNewExternal(const delete_ver = PageVersion(0); being_ref_count = 1; // return the new created holder to caller to set the page_id - external_holder = std::make_shared(0, 0); + external_holder = std::make_shared(0, 0); return external_holder; } else @@ -173,7 +175,8 @@ std::shared_ptr VersionedPageEntries::createNewExternal(const } // Create a new delete version with version=`ver`. -void VersionedPageEntries::createDelete(const PageVersion & ver) +template +void VersionedPageEntries::createDelete(const PageVersion & ver) { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_ENTRY) @@ -208,7 +211,8 @@ void VersionedPageEntries::createDelete(const PageVersion & ver) // Create a new reference version with version=`ver` and `ori_page_id_`. // If create success, then return true, otherwise return false. -bool VersionedPageEntries::createNewRef(const PageVersion & ver, PageIdV3Internal ori_page_id_) +template +bool VersionedPageEntries::createNewRef(const PageVersion & ver, const typename Trait::PageId & ori_page_id_) { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_DELETE) @@ -261,7 +265,8 @@ bool VersionedPageEntries::createNewRef(const PageVersion & ver, PageIdV3Interna ErrorCodes::PS_DIR_APPLY_INVALID_STATUS); } -std::shared_ptr VersionedPageEntries::fromRestored(const PageEntriesEdit::EditRecord & rec) +template +typename Trait::PageIdSharedPtr VersionedPageEntries::fromRestored(const typename Trait::EditRecord & rec) { auto page_lock = acquireLock(); if (rec.type == EditRecordType::VAR_REF) @@ -278,7 +283,7 @@ std::shared_ptr VersionedPageEntries::fromRestored(const PageE is_deleted = false; create_ver = rec.version; being_ref_count = rec.being_ref_count; - external_holder = std::make_shared(rec.page_id); + external_holder = std::make_shared(rec.page_id); return external_holder; } else if (rec.type == EditRecordType::VAR_ENTRY) @@ -293,8 +298,9 @@ std::shared_ptr VersionedPageEntries::fromRestored(const PageE } } -std::tuple -VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV3 * entry) +template +std::tuple +VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV3 * entry) { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_ENTRY) @@ -306,11 +312,11 @@ VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV if (!ignore_delete && iter->second.isDelete()) { // the page is not visible - return {ResolveResult::FAIL, buildV3Id(0, 0), PageVersion(0)}; + return {ResolveResult::FAIL, ExternalIdTrait::getInvalidID(), PageVersion(0)}; } // If `ignore_delete` is true, we need the page entry even if it is logical deleted. - // Checkout the details in `PageDirectory::get`. + // Checkout the details in `PageDirectory::get`. // Ignore all "delete" while (iter != entries.begin() && iter->second.isDelete()) @@ -323,7 +329,7 @@ VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV // copy and return the entry if (entry != nullptr) *entry = iter->second.entry; - return {ResolveResult::TO_NORMAL, buildV3Id(0, 0), PageVersion(0)}; + return {ResolveResult::TO_NORMAL, ExternalIdTrait::getInvalidID(), PageVersion(0)}; } // else fallthrough to FAIL } // else fallthrough to FAIL @@ -335,7 +341,7 @@ VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV bool ok = ignore_delete || (!is_deleted || seq < delete_ver.sequence); if (create_ver.sequence <= seq && ok) { - return {ResolveResult::TO_NORMAL, buildV3Id(0, 0), PageVersion(0)}; + return {ResolveResult::TO_NORMAL, ExternalIdTrait::getInvalidID(), PageVersion(0)}; } } else if (type == EditRecordType::VAR_REF) @@ -351,10 +357,11 @@ VersionedPageEntries::resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV LOG_FMT_WARNING(&Poco::Logger::get("VersionedPageEntries"), "Can't resolve the EditRecordType {}", type); } - return {ResolveResult::FAIL, buildV3Id(0, 0), PageVersion(0)}; + return {ResolveResult::FAIL, ExternalIdTrait::getInvalidID(), PageVersion(0)}; } -std::optional VersionedPageEntries::getEntry(UInt64 seq) const +template +std::optional VersionedPageEntries::getEntry(UInt64 seq) const { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_ENTRY) @@ -371,7 +378,8 @@ std::optional VersionedPageEntries::getEntry(UInt64 seq) const return std::nullopt; } -std::optional VersionedPageEntries::getLastEntry() const +template +std::optional VersionedPageEntries::getLastEntry() const { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_ENTRY) @@ -390,7 +398,8 @@ std::optional VersionedPageEntries::getLastEntry() const // Returns true when **this id** is "visible" by `seq`. // If this page id is marked as deleted or not created, it is "not visible". // Note that not visible does not means this id can be GC. -bool VersionedPageEntries::isVisible(UInt64 seq) const +template +bool VersionedPageEntries::isVisible(UInt64 seq) const { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_DELETE) @@ -423,7 +432,8 @@ bool VersionedPageEntries::isVisible(UInt64 seq) const ErrorCodes::LOGICAL_ERROR); } -Int64 VersionedPageEntries::incrRefCount(const PageVersion & ver) +template +Int64 VersionedPageEntries::incrRefCount(const PageVersion & ver) { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_ENTRY) @@ -460,10 +470,11 @@ Int64 VersionedPageEntries::incrRefCount(const PageVersion & ver) throw Exception(fmt::format("The entry to be added ref count is not found [ver={}] [state={}]", ver, toDebugString()), ErrorCodes::LOGICAL_ERROR); } -PageSize VersionedPageEntries::getEntriesByBlobIds( +template +PageSize VersionedPageEntries::getEntriesByBlobIds( const std::unordered_set & blob_ids, - PageIdV3Internal page_id, - std::map & blob_versioned_entries) + const typename Trait::PageId & page_id, + typename Trait::GcEntriesMap & blob_versioned_entries) { // blob_file_0, [, // , @@ -493,9 +504,10 @@ PageSize VersionedPageEntries::getEntriesByBlobIds( return total_entries_size; } -bool VersionedPageEntries::cleanOutdatedEntries( +template +bool VersionedPageEntries::cleanOutdatedEntries( UInt64 lowest_seq, - std::map> * normal_entries_to_deref, + typename Trait::EntriesDerefMap * normal_entries_to_deref, PageEntriesV3 * entries_removed, const PageLock & /*page_lock*/, bool keep_last_valid_var_entry) @@ -540,7 +552,7 @@ bool VersionedPageEntries::cleanOutdatedEntries( auto iter = MapUtils::findLess(entries, PageVersion(lowest_seq + 1)); // If we can't find any seq lower than `lowest_seq` then // all version in this list don't need gc. - if (iter == entries.begin() || iter == entries.end()) + if (iter == entries.begin() || iter == entries.end()) // NOLINT(misc-redundant-expression) { return false; } @@ -597,7 +609,14 @@ bool VersionedPageEntries::cleanOutdatedEntries( return entries.empty() || (entries.size() == 1 && entries.begin()->second.isDelete()); } -bool VersionedPageEntries::derefAndClean(UInt64 lowest_seq, PageIdV3Internal page_id, const PageVersion & deref_ver, const Int64 deref_count, PageEntriesV3 * entries_removed, bool keep_last_valid_var_entry) +template +bool VersionedPageEntries::derefAndClean( + UInt64 lowest_seq, + const typename Trait::PageId & page_id, + const PageVersion & deref_ver, + const Int64 deref_count, + PageEntriesV3 * entries_removed, + bool keep_last_valid_var_entry) { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_EXTERNAL) @@ -644,7 +663,8 @@ bool VersionedPageEntries::derefAndClean(UInt64 lowest_seq, PageIdV3Internal pag throw Exception(fmt::format("calling derefAndClean with invalid state [state={}]", toDebugString())); } -void VersionedPageEntries::collapseTo(const UInt64 seq, const PageIdV3Internal page_id, PageEntriesEdit & edit) +template +void VersionedPageEntries::collapseTo(const UInt64 seq, const typename Trait::PageId & page_id, typename Trait::PageEntriesEdit & edit) { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_REF) @@ -726,11 +746,13 @@ void VersionedPageEntries::collapseTo(const UInt64 seq, const PageIdV3Internal p throw Exception(fmt::format("Calling collapseTo with invalid state [state={}]", toDebugString())); } + /************************** * PageDirectory methods * *************************/ -PageDirectory::PageDirectory(String storage_name, WALStorePtr && wal_, UInt64 max_persisted_log_files_) +template +PageDirectory::PageDirectory(String storage_name, WALStorePtr && wal_, UInt64 max_persisted_log_files_) : max_page_id(0) , sequence(0) , wal(std::move(wal_)) @@ -739,7 +761,8 @@ PageDirectory::PageDirectory(String storage_name, WALStorePtr && wal_, UInt64 ma { } -PageDirectorySnapshotPtr PageDirectory::createSnapshot(const String & tracing_id) const +template +PageDirectorySnapshotPtr PageDirectory::createSnapshot(const String & tracing_id) const { auto snap = std::make_shared(sequence.load(), tracing_id); { @@ -751,7 +774,8 @@ PageDirectorySnapshotPtr PageDirectory::createSnapshot(const String & tracing_id return snap; } -SnapshotsStatistics PageDirectory::getSnapshotsStat() const +template +SnapshotsStatistics PageDirectory::getSnapshotsStat() const { SnapshotsStatistics stat; DB::Int64 num_snapshots_removed = 0; @@ -791,7 +815,9 @@ SnapshotsStatistics PageDirectory::getSnapshotsStat() const return stat; } -PageIDAndEntryV3 PageDirectory::getByIDImpl(PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const +template +typename Trait::PageIdAndEntry +PageDirectory::getByIDImpl(const typename Trait::PageId & page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const { PageEntryV3 entry_got; @@ -823,12 +849,12 @@ PageIDAndEntryV3 PageDirectory::getByIDImpl(PageIdV3Internal page_id, const Page // resolve ref id 11 to 10 with seq=2, and continue to ignore all "delete"s in the version chain in // page 10 until we find the "entryX". - PageIdV3Internal id_to_resolve = page_id; + typename Trait::PageId id_to_resolve = page_id; PageVersion ver_to_resolve(snap->sequence, 0); bool ok = true; while (ok) { - MVCCMapType::const_iterator iter; + typename MVCCMapType::const_iterator iter; { std::shared_lock read_lock(table_rw_mutex); iter = mvcc_table_directory.find(id_to_resolve); @@ -845,7 +871,7 @@ PageIDAndEntryV3 PageDirectory::getByIDImpl(PageIdV3Internal page_id, const Page } else { - return PageIDAndEntryV3{page_id, PageEntryV3{.file_id = INVALID_BLOBFILE_ID}}; + return typename Trait::PageIdAndEntry{page_id, PageEntryV3{.file_id = INVALID_BLOBFILE_ID}}; } } } @@ -853,7 +879,7 @@ PageIDAndEntryV3 PageDirectory::getByIDImpl(PageIdV3Internal page_id, const Page switch (resolve_state) { case ResolveResult::TO_NORMAL: - return PageIDAndEntryV3(page_id, entry_got); + return typename Trait::PageIdAndEntry{page_id, entry_got}; case ResolveResult::FAIL: ok = false; break; @@ -878,22 +904,24 @@ PageIDAndEntryV3 PageDirectory::getByIDImpl(PageIdV3Internal page_id, const Page } else { - return PageIDAndEntryV3{page_id, PageEntryV3{.file_id = INVALID_BLOBFILE_ID}}; + return typename Trait::PageIdAndEntry{page_id, PageEntryV3{.file_id = INVALID_BLOBFILE_ID}}; } } -std::pair PageDirectory::getByIDsImpl(const PageIdV3Internals & page_ids, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const +template +typename Trait::PageIdAndEntriesWithError +PageDirectory::getByIDsImpl(const typename Trait::PageIds & page_ids, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const { PageEntryV3 entry_got; - PageIds page_not_found = {}; + typename Trait::PageIds page_not_found = {}; const PageVersion init_ver_to_resolve(snap->sequence, 0); - auto get_one = [&entry_got, init_ver_to_resolve, throw_on_not_exist, this](PageIdV3Internal page_id, PageVersion ver_to_resolve, size_t idx) { - PageIdV3Internal id_to_resolve = page_id; + auto get_one = [&entry_got, init_ver_to_resolve, throw_on_not_exist, this](const typename Trait::PageId & page_id, PageVersion ver_to_resolve, size_t idx) { + typename Trait::PageId id_to_resolve = page_id; bool ok = true; while (ok) { - MVCCMapType::const_iterator iter; + typename MVCCMapType::const_iterator iter; { std::shared_lock read_lock(table_rw_mutex); iter = mvcc_table_directory.find(id_to_resolve); @@ -939,7 +967,7 @@ std::pair PageDirectory::getByIDsImpl(const PageIdV } }; - PageIDAndEntriesV3 id_entries; + typename Trait::PageIdAndEntries id_entries; for (size_t idx = 0; idx < page_ids.size(); ++idx) { if (auto ok = get_one(page_ids[idx], init_ver_to_resolve, idx); ok) @@ -955,15 +983,16 @@ std::pair PageDirectory::getByIDsImpl(const PageIdV return std::make_pair(id_entries, page_not_found); } -PageIdV3Internal PageDirectory::getNormalPageId(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap_, bool throw_on_not_exist) const +template +typename Trait::PageId PageDirectory::getNormalPageId(const typename Trait::PageId & page_id, const DB::PageStorageSnapshotPtr & snap_, bool throw_on_not_exist) const { auto snap = toConcreteSnapshot(snap_); - PageIdV3Internal id_to_resolve = page_id; + typename Trait::PageId id_to_resolve = page_id; PageVersion ver_to_resolve(snap->sequence, 0); bool keep_resolve = true; while (keep_resolve) { - MVCCMapType::const_iterator iter; + typename MVCCMapType::const_iterator iter; { std::shared_lock read_lock(table_rw_mutex); iter = mvcc_table_directory.find(id_to_resolve); @@ -975,7 +1004,7 @@ PageIdV3Internal PageDirectory::getNormalPageId(PageIdV3Internal page_id, const } else { - return buildV3Id(0, INVALID_PAGE_ID); + return ExternalIdTrait::getInvalidID(); } } } @@ -1012,19 +1041,21 @@ PageIdV3Internal PageDirectory::getNormalPageId(PageIdV3Internal page_id, const } else { - return buildV3Id(0, INVALID_PAGE_ID); + return ExternalIdTrait::getInvalidID(); } } -PageId PageDirectory::getMaxId() const +template +PageId PageDirectory::getMaxId() const { std::shared_lock read_lock(table_rw_mutex); return max_page_id; } -std::set PageDirectory::getAllPageIds() +template +typename Trait::PageIdSet PageDirectory::getAllPageIds() { - std::set page_ids; + typename Trait::PageIdSet page_ids; std::shared_lock read_lock(table_rw_mutex); for (auto & [page_id, versioned] : mvcc_table_directory) @@ -1035,10 +1066,11 @@ std::set PageDirectory::getAllPageIds() return page_ids; } -void PageDirectory::applyRefEditRecord( +template +void PageDirectory::applyRefEditRecord( MVCCMapType & mvcc_table_directory, const VersionedPageEntriesPtr & version_list, - const PageEntriesEdit::EditRecord & rec, + const typename Trait::EditRecord & rec, const PageVersion & version) { // Assume the `mvcc_table_directory` is: @@ -1072,13 +1104,13 @@ void PageDirectory::applyRefEditRecord( // non-collapse ref chain is much harder and long ref chain make the time of accessing an entry // not stable. - auto [resolve_success, resolved_id, resolved_ver] = [&mvcc_table_directory, ori_page_id = rec.ori_page_id](PageIdV3Internal id_to_resolve, PageVersion ver_to_resolve) - -> std::tuple { + auto [resolve_success, resolved_id, resolved_ver] = [&mvcc_table_directory, ori_page_id = rec.ori_page_id](typename Trait::PageId id_to_resolve, PageVersion ver_to_resolve) + -> std::tuple { while (true) { auto resolve_ver_iter = mvcc_table_directory.find(id_to_resolve); if (resolve_ver_iter == mvcc_table_directory.end()) - return {false, buildV3Id(0, 0), PageVersion(0)}; + return {false, ExternalIdTrait::getInvalidID(), PageVersion(0)}; const VersionedPageEntriesPtr & resolve_version_list = resolve_ver_iter->second; auto [resolve_state, next_id_to_resolve, next_ver_to_resolve] = resolve_version_list->resolveToPageId( @@ -1135,7 +1167,8 @@ void PageDirectory::applyRefEditRecord( } } -void PageDirectory::apply(PageEntriesEdit && edit, const WriteLimiterPtr & write_limiter) +template +void PageDirectory::apply(typename Trait::PageEntriesEdit && edit, const WriteLimiterPtr & write_limiter) { // Note that we need to make sure increasing `sequence` in order, so it // also needs to be protected by `write_lock` throughout the `apply` @@ -1149,18 +1182,18 @@ void PageDirectory::apply(PageEntriesEdit && edit, const WriteLimiterPtr & write { r.version = new_version; } - wal->apply(ser::serializeTo(edit), write_limiter); + wal->apply(Trait::Serializer::serializeTo(edit), write_limiter); // stage 2, create entry version list for page_id. for (const auto & r : edit.getRecords()) { // Protected in write_lock - max_page_id = std::max(max_page_id, r.page_id.low); + max_page_id = std::max(max_page_id, ExternalIdTrait::getU64ID(r.page_id)); auto [iter, created] = mvcc_table_directory.insert(std::make_pair(r.page_id, nullptr)); if (created) { - iter->second = std::make_shared(); + iter->second = std::make_shared>(); } auto & version_list = iter->second; @@ -1207,7 +1240,8 @@ void PageDirectory::apply(PageEntriesEdit && edit, const WriteLimiterPtr & write sequence.fetch_add(1); } -void PageDirectory::gcApply(PageEntriesEdit && migrated_edit, const WriteLimiterPtr & write_limiter) +template +void PageDirectory::gcApply(typename Trait::PageEntriesEdit && migrated_edit, const WriteLimiterPtr & write_limiter) { // Increase the epoch for migrated records for (auto & record : migrated_edit.getMutRecords()) @@ -1216,12 +1250,12 @@ void PageDirectory::gcApply(PageEntriesEdit && migrated_edit, const WriteLimiter } // Apply migrate edit into WAL with the increased epoch version - wal->apply(ser::serializeTo(migrated_edit), write_limiter); + wal->apply(Trait::Serializer::serializeTo(migrated_edit), write_limiter); // Apply migrate edit to the mvcc map for (const auto & record : migrated_edit.getRecords()) { - MVCCMapType::const_iterator iter; + typename MVCCMapType::const_iterator iter; { std::shared_lock read_lock(table_rw_mutex); iter = mvcc_table_directory.find(record.page_id); @@ -1239,18 +1273,19 @@ void PageDirectory::gcApply(PageEntriesEdit && migrated_edit, const WriteLimiter LOG_FMT_INFO(log, "GC apply done. [edit size={}]", migrated_edit.size()); } -std::pair, PageSize> -PageDirectory::getEntriesByBlobIds(const std::vector & blob_ids) const +template +std::pair +PageDirectory::getEntriesByBlobIds(const std::vector & blob_ids) const { std::unordered_set blob_id_set; for (const auto blob_id : blob_ids) blob_id_set.insert(blob_id); assert(blob_id_set.size() == blob_ids.size()); - std::map blob_versioned_entries; + typename Trait::GcEntriesMap blob_versioned_entries; PageSize total_page_size = 0; - MVCCMapType::const_iterator iter; + typename MVCCMapType::const_iterator iter; { std::shared_lock read_lock(table_rw_mutex); iter = mvcc_table_directory.cbegin(); @@ -1293,7 +1328,8 @@ PageDirectory::getEntriesByBlobIds(const std::vector & blob_ids) con return std::make_pair(std::move(blob_versioned_entries), total_page_size); } -bool PageDirectory::tryDumpSnapshot(const ReadLimiterPtr & read_limiter, const WriteLimiterPtr & write_limiter, bool force) +template +bool PageDirectory::tryDumpSnapshot(const ReadLimiterPtr & read_limiter, const WriteLimiterPtr & write_limiter, bool force) { bool done_any_io = false; // In order not to make read amplification too high, only apply compact logs when ... @@ -1308,22 +1344,43 @@ bool PageDirectory::tryDumpSnapshot(const ReadLimiterPtr & read_limiter, const W auto log_num = files_snap.persisted_log_files.rbegin()->log_num; auto identifier = fmt::format("{}.dump_{}", wal->name(), log_num); auto snapshot_reader = wal->createReaderForFiles(identifier, files_snap.persisted_log_files, read_limiter); - PageDirectoryFactory factory; - // we just use the `collapsed_dir` to dump edit of the snapshot, should never call functions like `apply` that - // persist new logs into disk. So we pass `nullptr` as `wal` to the factory. - PageDirectoryPtr collapsed_dir = factory.createFromReader( - identifier, - std::move(snapshot_reader), - /* wal */ nullptr, - /* for_dump_snapshot */ true); + auto collapsed_dir = [&]() { + // we just use the `collapsed_dir` to dump edit of the snapshot, should never call functions like `apply` that + // persist new logs into disk. So we pass `nullptr` as `wal` to the factory. + static_assert(std::is_same_v || std::is_same_v, + "unknown impl"); + if constexpr (std::is_same_v) + { + u128::PageDirectoryFactory factory; + return factory.createFromReader( + identifier, + std::move(snapshot_reader), + /* wal */ nullptr, + /* for_dump_snapshot */ true); + } + else if constexpr (std::is_same_v) + { + universal::PageDirectoryFactory factory; + return factory.createFromReader( + identifier, + std::move(snapshot_reader), + /* wal */ nullptr, + /* for_dump_snapshot */ true); + } + }(); // The records persisted in `files_snap` is older than or equal to all records in `edit` auto edit_from_disk = collapsed_dir->dumpSnapshotToEdit(); - done_any_io = wal->saveSnapshot(std::move(files_snap), ser::serializeTo(edit_from_disk), edit_from_disk.size(), write_limiter); + done_any_io = wal->saveSnapshot( + std::move(files_snap), + Trait::Serializer::serializeTo(edit_from_disk), + edit_from_disk.size(), + write_limiter); } return done_any_io; } -PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries, bool keep_last_valid_var_entry) +template +PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries, bool keep_last_valid_var_entry) { UInt64 lowest_seq = sequence.load(); @@ -1365,7 +1422,7 @@ PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries, bool ke } PageEntriesV3 all_del_entries; - MVCCMapType::iterator iter; + typename MVCCMapType::iterator iter; { std::shared_lock read_lock(table_rw_mutex); iter = mvcc_table_directory.begin(); @@ -1378,7 +1435,7 @@ PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries, bool ke // The page_id that we need to decrease ref count // { id_0: , id_1: <...>, ... } - std::map> normal_entries_to_deref; + std::map> normal_entries_to_deref; // Iterate all page_id and try to clean up useless var entries while (true) { @@ -1414,7 +1471,7 @@ PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries, bool ke // Iterate all page_id that need to decrease ref count of specified version. for (const auto & [page_id, deref_counter] : normal_entries_to_deref) { - MVCCMapType::iterator iter; + typename MVCCMapType::iterator iter; { std::shared_lock read_lock(table_rw_mutex); iter = mvcc_table_directory.find(page_id); @@ -1459,15 +1516,16 @@ PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries, bool ke return all_del_entries; } -PageEntriesEdit PageDirectory::dumpSnapshotToEdit(PageDirectorySnapshotPtr snap) +template +typename Trait::PageEntriesEdit PageDirectory::dumpSnapshotToEdit(PageDirectorySnapshotPtr snap) { if (!snap) { snap = createSnapshot(/*tracing_id*/ ""); } - PageEntriesEdit edit; - MVCCMapType::iterator iter; + typename Trait::PageEntriesEdit edit; + typename MVCCMapType::iterator iter; { std::shared_lock read_lock(table_rw_mutex); iter = mvcc_table_directory.begin(); @@ -1490,5 +1548,11 @@ PageEntriesEdit PageDirectory::dumpSnapshotToEdit(PageDirectorySnapshotPtr snap) return edit; } +template class VersionedPageEntries; +template class VersionedPageEntries; + +template class PageDirectory; +template class PageDirectory; + } // namespace PS::V3 } // namespace DB diff --git a/dbms/src/Storages/Page/V3/PageDirectory.h b/dbms/src/Storages/Page/V3/PageDirectory.h index 669b6feb24e..fd9db0c838f 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.h +++ b/dbms/src/Storages/Page/V3/PageDirectory.h @@ -27,7 +27,9 @@ #include #include #include +#include #include +#include #include #include @@ -42,6 +44,7 @@ extern const Metric PSMVCCNumSnapshots; namespace DB::PS::V3 { + class PageDirectorySnapshot : public DB::PageStorageSnapshot { public: @@ -56,7 +59,7 @@ class PageDirectorySnapshot : public DB::PageStorageSnapshot CurrentMetrics::add(CurrentMetrics::PSMVCCNumSnapshots); } - ~PageDirectorySnapshot() + ~PageDirectorySnapshot() override { CurrentMetrics::sub(CurrentMetrics::PSMVCCNumSnapshots); } @@ -80,7 +83,7 @@ using PageDirectorySnapshotPtr = std::shared_ptr; struct EntryOrDelete { - bool is_delete; + bool is_delete = true; Int64 being_ref_count = 1; PageEntryV3 entry; @@ -131,8 +134,6 @@ struct EntryOrDelete } }; -class VersionedPageEntries; -using VersionedPageEntriesPtr = std::shared_ptr; using PageLock = std::lock_guard; enum class ResolveResult @@ -142,6 +143,7 @@ enum class ResolveResult TO_NORMAL, }; +template class VersionedPageEntries { public: @@ -161,15 +163,15 @@ class VersionedPageEntries void createNewEntry(const PageVersion & ver, const PageEntryV3 & entry); - bool createNewRef(const PageVersion & ver, PageIdV3Internal ori_page_id); + bool createNewRef(const PageVersion & ver, const typename Trait::PageId & ori_page_id); - std::shared_ptr createNewExternal(const PageVersion & ver); + typename Trait::PageIdSharedPtr createNewExternal(const PageVersion & ver); void createDelete(const PageVersion & ver); - std::shared_ptr fromRestored(const PageEntriesEdit::EditRecord & rec); + typename Trait::PageIdSharedPtr fromRestored(const typename Trait::EditRecord & rec); - std::tuple + std::tuple resolveToPageId(UInt64 seq, bool ignore_delete, PageEntryV3 * entry); Int64 incrRefCount(const PageVersion & ver); @@ -187,8 +189,8 @@ class VersionedPageEntries */ PageSize getEntriesByBlobIds( const std::unordered_set & blob_ids, - PageIdV3Internal page_id, - std::map & blob_versioned_entries); + const typename Trait::PageId & page_id, + typename Trait::GcEntriesMap & blob_versioned_entries); /** * Given a `lowest_seq`, this will clean all outdated entries before `lowest_seq`. @@ -204,19 +206,19 @@ class VersionedPageEntries */ bool cleanOutdatedEntries( UInt64 lowest_seq, - std::map> * normal_entries_to_deref, + typename Trait::EntriesDerefMap * normal_entries_to_deref, PageEntriesV3 * entries_removed, const PageLock & page_lock, bool keep_last_valid_var_entry = false); bool derefAndClean( UInt64 lowest_seq, - PageIdV3Internal page_id, + const typename Trait::PageId & page_id, const PageVersion & deref_ver, Int64 deref_count, PageEntriesV3 * entries_removed, bool keep_last_valid_var_entry = false); - void collapseTo(UInt64 seq, PageIdV3Internal page_id, PageEntriesEdit & edit); + void collapseTo(UInt64 seq, const typename Trait::PageId & page_id, typename Trait::PageEntriesEdit & edit); size_t size() const { @@ -241,6 +243,9 @@ class VersionedPageEntries } friend class PageStorageControlV3; +private: + using ExternalIdTrait = typename Trait::ExternalIdTrait; + private: mutable std::mutex m; @@ -260,11 +265,11 @@ class VersionedPageEntries // The deleted version, valid when type == VAR_REF/VAR_EXTERNAL && is_deleted = true PageVersion delete_ver; // Original page id, valid when type == VAR_REF - PageIdV3Internal ori_page_id; + typename Trait::PageId ori_page_id; // Being ref counter, valid when type == VAR_EXTERNAL Int64 being_ref_count; // A shared ptr to a holder, valid when type == VAR_EXTERNAL - std::shared_ptr external_holder; + typename Trait::PageIdSharedPtr external_holder; }; // `PageDirectory` store multi-versions entries for the same @@ -274,8 +279,7 @@ class VersionedPageEntries // User should call `gc` periodic to remove outdated version // of entries in order to keep the memory consumption as well // as the restoring time in a reasonable level. -class PageDirectory; -using PageDirectoryPtr = std::unique_ptr; +template class PageDirectory { public: @@ -285,36 +289,36 @@ class PageDirectory SnapshotsStatistics getSnapshotsStat() const; - PageIDAndEntryV3 getByID(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap) const + typename Trait::PageIdAndEntry getByID(const typename Trait::PageId & page_id, const DB::PageStorageSnapshotPtr & snap) const { return getByIDImpl(page_id, toConcreteSnapshot(snap), /*throw_on_not_exist=*/true); } - PageIDAndEntryV3 getByIDOrNull(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap) const + typename Trait::PageIdAndEntry getByIDOrNull(const typename Trait::PageId & page_id, const DB::PageStorageSnapshotPtr & snap) const { return getByIDImpl(page_id, toConcreteSnapshot(snap), /*throw_on_not_exist=*/false); } - PageIDAndEntriesV3 getByIDs(const PageIdV3Internals & page_ids, const DB::PageStorageSnapshotPtr & snap) const + typename Trait::PageIdAndEntries getByIDs(const typename Trait::PageIds & page_ids, const DB::PageStorageSnapshotPtr & snap) const { return std::get<0>(getByIDsImpl(page_ids, toConcreteSnapshot(snap), /*throw_on_not_exist=*/true)); } - std::pair getByIDsOrNull(PageIdV3Internals page_ids, const DB::PageStorageSnapshotPtr & snap) const + typename Trait::PageIdAndEntriesWithError getByIDsOrNull(const typename Trait::PageIds & page_ids, const DB::PageStorageSnapshotPtr & snap) const { return getByIDsImpl(page_ids, toConcreteSnapshot(snap), /*throw_on_not_exist=*/false); } - PageIdV3Internal getNormalPageId(PageIdV3Internal page_id, const DB::PageStorageSnapshotPtr & snap_, bool throw_on_not_exist) const; + typename Trait::PageId getNormalPageId(const typename Trait::PageId & page_id, const DB::PageStorageSnapshotPtr & snap, bool throw_on_not_exist) const; PageId getMaxId() const; - std::set getAllPageIds(); + typename Trait::PageIdSet getAllPageIds(); - void apply(PageEntriesEdit && edit, const WriteLimiterPtr & write_limiter = nullptr); + void apply(typename Trait::PageEntriesEdit && edit, const WriteLimiterPtr & write_limiter = nullptr); - std::pair, PageSize> + std::pair getEntriesByBlobIds(const std::vector & blob_ids) const; - void gcApply(PageEntriesEdit && migrated_edit, const WriteLimiterPtr & write_limiter = nullptr); + void gcApply(typename Trait::PageEntriesEdit && migrated_edit, const WriteLimiterPtr & write_limiter = nullptr); /// When create PageDirectory for dump snapshot, we should keep the last valid var_entry when it is deleted. /// Because there may be some upsert entry in later wal files, and we should keep the valid var_entry and the delete entry to delete the later upsert entry. @@ -326,9 +330,13 @@ class PageDirectory // When dump snapshot, we need to keep the last valid entry. Check out `tryDumpSnapshot` for the reason. PageEntriesV3 gcInMemEntries(bool return_removed_entries = true, bool keep_last_valid_var_entry = false); +private: + using ExternalIdTrait = typename Trait::ExternalIdTrait; + +public: // Get the external id that is not deleted or being ref by another id by // `ns_id`. - std::set getAliveExternalIds(NamespaceId ns_id) const + std::set getAliveExternalIds(const typename ExternalIdTrait::Prefix & ns_id) const { return external_ids_by_ns.getAliveIds(ns_id); } @@ -336,12 +344,12 @@ class PageDirectory // After table dropped, the `getAliveIds` with specified // `ns_id` will not be cleaned. We need this method to // cleanup all external id ptrs. - void unregisterNamespace(NamespaceId ns_id) + void unregisterNamespace(const typename ExternalIdTrait::Prefix & ns_id) { external_ids_by_ns.unregisterNamespace(ns_id); } - PageEntriesEdit dumpSnapshotToEdit(PageDirectorySnapshotPtr snap = nullptr); + typename Trait::PageEntriesEdit dumpSnapshotToEdit(PageDirectorySnapshotPtr snap = nullptr); size_t numPages() const { @@ -352,24 +360,27 @@ class PageDirectory // No copying and no moving DISALLOW_COPY_AND_MOVE(PageDirectory); + template friend class PageDirectoryFactory; friend class PageStorageControlV3; private: - PageIDAndEntryV3 getByIDImpl(PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const; - std::pair - getByIDsImpl(const PageIdV3Internals & page_ids, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const; + typename Trait::PageIdAndEntry + getByIDImpl(const typename Trait::PageId & page_id, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const; + typename Trait::PageIdAndEntriesWithError + getByIDsImpl(const typename Trait::PageIds & page_ids, const PageDirectorySnapshotPtr & snap, bool throw_on_not_exist) const; private: // Only `std::map` is allow for `MVCCMap`. Cause `std::map::insert` ensure that // "No iterators or references are invalidated" // https://en.cppreference.com/w/cpp/container/map/insert - using MVCCMapType = std::map; + using VersionedPageEntriesPtr = std::shared_ptr>; + using MVCCMapType = std::map; static void applyRefEditRecord( MVCCMapType & mvcc_table_directory, const VersionedPageEntriesPtr & version_list, - const PageEntriesEdit::EditRecord & rec, + const typename Trait::EditRecord & rec, const PageVersion & version); static inline PageDirectorySnapshotPtr @@ -387,11 +398,66 @@ class PageDirectory mutable std::mutex snapshots_mutex; mutable std::list> snapshots; - mutable ExternalIdsByNamespace external_ids_by_ns; + mutable ExternalIdsByNamespace external_ids_by_ns; WALStorePtr wal; const UInt64 max_persisted_log_files; LoggerPtr log; }; +namespace universal +{ +struct PageDirectoryTrait +{ + using PageId = UniversalPageId; + using PageIdSharedPtr = std::shared_ptr; + using PageEntriesEdit = DB::PS::V3::PageEntriesEdit; + using EditRecord = PageEntriesEdit::EditRecord; + + using EntriesDerefMap = std::map>; + + using GcEntries = std::vector>; + using GcEntriesMap = std::map; + + using PageIdSet = std::set; + using PageIds = std::vector; + using PageIdAndEntry = std::pair; + using PageIdAndEntries = std::vector; + using PageIdAndEntriesWithError = std::pair; + + using ExternalIdTrait = ExternalIdTrait; + using Serializer = Serializer; +}; + +using PageDirectoryPtr = std::unique_ptr>; +} // namespace universal +namespace u128 +{ +struct PageDirectoryTrait +{ + using PageId = PageIdV3Internal; + using PageIdSharedPtr = std::shared_ptr; + using PageEntriesEdit = DB::PS::V3::PageEntriesEdit; + using EditRecord = PageEntriesEdit::EditRecord; + + using EntriesDerefMap = std::map>; + + using GcEntries = std::vector>; + using GcEntriesMap = std::map; + + using PageIdSet = std::set; + using PageIds = std::vector; + using PageIdAndEntry = PageIDAndEntryV3; + using PageIdAndEntries = PageIDAndEntriesV3; + using PageIdAndEntriesWithError = std::pair; + + using ExternalIdTrait = ExternalIdTrait; + using Serializer = Serializer; +}; +using PageDirectoryPtr = std::unique_ptr>; +using VersionedPageEntries = DB::PS::V3::VersionedPageEntries; +using VersionedPageEntriesPtr = std::shared_ptr; +} // namespace u128 + + } // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdTrait.h b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdTrait.h new file mode 100644 index 00000000000..0e0e8576be8 --- /dev/null +++ b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdTrait.h @@ -0,0 +1,66 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include + +namespace DB::PS::V3 +{ +namespace u128 +{ +struct ExternalIdTrait +{ + using U64PageId = DB::PageId; + using PageId = PageIdV3Internal; + using Prefix = NamespaceId; + + static inline PageId getInvalidID() + { + return buildV3Id(0, DB::INVALID_PAGE_ID); + } + static inline U64PageId getU64ID(PageId page_id) + { + return page_id.low; + } + static inline Prefix getPrefix(const PageId & page_id) + { + return page_id.high; + } +}; +} // namespace u128 +namespace universal +{ +struct ExternalIdTrait +{ + using U64PageId = DB::PageId; + using PageId = UniversalPageId; + using Prefix = String; + + static inline PageId getInvalidID() + { + return ""; + } + static inline U64PageId getU64ID(const PageId & /*page_id*/) + { + // FIXME: we need to ignore some page_id with prefix + return 0; + } + static inline Prefix getPrefix(const PageId & /*page_id*/) + { + // FIXME + return ""; + } +}; +} // namespace universal +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.cpp b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.cpp index 34934297d30..835db635472 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.cpp @@ -19,27 +19,31 @@ namespace DB::PS::V3 { -void ExternalIdsByNamespace::addExternalIdUnlock(const std::shared_ptr & external_id) +template +void ExternalIdsByNamespace::addExternalIdUnlock(const std::shared_ptr & external_id) { - const NamespaceId & ns_id = external_id->high; + const Prefix & ns_id = Trait::getPrefix(*external_id); // create a new ExternalIds if the ns_id is not exists, else return // the existing one. auto [ns_iter, new_inserted] = ids_by_ns.try_emplace(ns_id, ExternalIds{}); - ns_iter->second.emplace_back(std::weak_ptr(external_id)); + ns_iter->second.emplace_back(std::weak_ptr(external_id)); } -void ExternalIdsByNamespace::addExternalId(const std::shared_ptr & external_id) +template +void ExternalIdsByNamespace::addExternalId(const std::shared_ptr & external_id) { std::unique_lock map_guard(mu); addExternalIdUnlock(external_id); } -std::set ExternalIdsByNamespace::getAliveIds(NamespaceId ns_id) const +template +std::set +ExternalIdsByNamespace::getAliveIds(const Prefix & ns_id) const { - // Now we assume a lock among all NamespaceIds is good enough. + // Now we assume a lock among all prefixes is good enough. std::unique_lock map_guard(mu); - std::set valid_external_ids; + std::set valid_external_ids; auto ns_iter = ids_by_ns.find(ns_id); if (ns_iter == ids_by_ns.end()) return valid_external_ids; @@ -57,7 +61,7 @@ std::set ExternalIdsByNamespace::getAliveIds(NamespaceId ns_id) const } else { - valid_external_ids.emplace(holder->low); + valid_external_ids.emplace(Trait::getU64ID(*holder)); ++iter; } } @@ -69,10 +73,15 @@ std::set ExternalIdsByNamespace::getAliveIds(NamespaceId ns_id) const return valid_external_ids; } -void ExternalIdsByNamespace::unregisterNamespace(NamespaceId ns_id) +template +void ExternalIdsByNamespace::unregisterNamespace(const Prefix & ns_id) { std::unique_lock map_guard(mu); // free all weak_ptrs of this namespace ids_by_ns.erase(ns_id); } + +template class ExternalIdsByNamespace; +template class ExternalIdsByNamespace; + } // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h index 01cae5ebe20..49124c1fba5 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h +++ b/dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -28,30 +29,35 @@ namespace DB::PS::V3 // A thread-safe class to manage external ids. // Manage all external ids by NamespaceId. +template class ExternalIdsByNamespace { +private: + using PageId = typename Trait::PageId; + using Prefix = typename Trait::Prefix; + public: ExternalIdsByNamespace() = default; // Add a external ids - void addExternalId(const std::shared_ptr & external_id); + void addExternalId(const std::shared_ptr & external_id); // non thread-safe version, only for restore - void addExternalIdUnlock(const std::shared_ptr & external_id); + void addExternalIdUnlock(const std::shared_ptr & external_id); // Get all alive external ids of given `ns_id` // Will also cleanup the invalid external ids. - std::set getAliveIds(NamespaceId ns_id) const; + std::set getAliveIds(const Prefix & ns_id) const; // After table dropped, the `getAliveIds` with specified // `ns_id` will not be cleaned. We need this method to // cleanup all external id ptrs. - void unregisterNamespace(NamespaceId ns_id); + void unregisterNamespace(const Prefix & ns_id); // Check whether `ns_id` exist. Expose for testing. // Note that the result is meaningless unless `getAliveIds` // or `unregisterNamespace` is called to cleanup invalid // external ids. - bool existNamespace(NamespaceId ns_id) const + bool existNamespace(const Prefix & ns_id) const { std::lock_guard map_guard(mu); return ids_by_ns.count(ns_id) > 0; @@ -63,8 +69,9 @@ class ExternalIdsByNamespace mutable std::mutex mu; // Only store weak_ptrs. The weak_ptrs will be invalid after the external id // in PageDirectory get removed. - using ExternalIds = std::list>; - using NamespaceMap = std::unordered_map; + using ExternalIds = std::list>; + using NamespaceMap = std::unordered_map; mutable NamespaceMap ids_by_ns; }; + } // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp index d3d99c93891..b882f4789af 100644 --- a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp @@ -20,6 +20,7 @@ #include #include +#include namespace DB { @@ -29,15 +30,19 @@ extern const int PS_DIR_APPLY_INVALID_STATUS; } // namespace ErrorCodes namespace PS::V3 { -PageDirectoryPtr PageDirectoryFactory::create(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, WALConfig config) +template +typename Trait::PageDirectoryPtr +PageDirectoryFactory::create(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, WALConfig config) { auto [wal, reader] = WALStore::create(storage_name, file_provider, delegator, config); return createFromReader(storage_name, reader, std::move(wal)); } -PageDirectoryPtr PageDirectoryFactory::createFromReader(String storage_name, WALStoreReaderPtr reader, WALStorePtr wal, bool for_dump_snapshot) +template +typename Trait::PageDirectoryPtr +PageDirectoryFactory::createFromReader(String storage_name, WALStoreReaderPtr reader, WALStorePtr wal, bool for_dump_snapshot) { - PageDirectoryPtr dir = std::make_unique(storage_name, std::move(wal)); + typename Trait::PageDirectoryPtr dir = std::make_unique(storage_name, std::move(wal)); loadFromDisk(dir, std::move(reader)); // Reset the `sequence` to the maximum of persisted. @@ -75,11 +80,13 @@ PageDirectoryPtr PageDirectoryFactory::createFromReader(String storage_name, WAL return dir; } -PageDirectoryPtr PageDirectoryFactory::createFromEdit(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, const PageEntriesEdit & edit) +template +typename Trait::PageDirectoryPtr +PageDirectoryFactory::createFromEdit(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, const typename Trait::PageEntriesEdit & edit) { auto [wal, reader] = WALStore::create(storage_name, file_provider, delegator, WALConfig()); (void)reader; - PageDirectoryPtr dir = std::make_unique(std::move(storage_name), std::move(wal)); + typename Trait::PageDirectoryPtr dir = std::make_unique(std::move(storage_name), std::move(wal)); loadEdit(dir, edit); // Reset the `sequence` to the maximum of persisted. dir->sequence = max_applied_ver.sequence; @@ -114,7 +121,8 @@ PageDirectoryPtr PageDirectoryFactory::createFromEdit(String storage_name, FileP return dir; } -void PageDirectoryFactory::loadEdit(const PageDirectoryPtr & dir, const PageEntriesEdit & edit) +template +void PageDirectoryFactory::loadEdit(const typename Trait::PageDirectoryPtr & dir, const typename Trait::PageEntriesEdit & edit) { for (const auto & r : edit.getRecords()) { @@ -125,17 +133,25 @@ void PageDirectoryFactory::loadEdit(const PageDirectoryPtr & dir, const PageEntr } } -void PageDirectoryFactory::applyRecord( - const PageDirectoryPtr & dir, - const PageEntriesEdit::EditRecord & r) +template +void PageDirectoryFactory::applyRecord( + const typename Trait::PageDirectoryPtr & dir, + const typename Trait::PageEntriesEdit::EditRecord & r) { auto [iter, created] = dir->mvcc_table_directory.insert(std::make_pair(r.page_id, nullptr)); if (created) { - iter->second = std::make_shared(); + if constexpr (std::is_same_v) + { + iter->second = std::make_shared>(); + } + else if constexpr (std::is_same_v) + { + iter->second = std::make_shared>(); + } } - dir->max_page_id = std::max(dir->max_page_id, r.page_id.low); + dir->max_page_id = std::max(dir->max_page_id, ExternalIdTrait::getU64ID(r.page_id)); const auto & version_list = iter->second; const auto & restored_version = r.version; @@ -175,7 +191,7 @@ void PageDirectoryFactory::applyRecord( version_list->createDelete(restored_version); break; case EditRecordType::REF: - PageDirectory::applyRefEditRecord( + Trait::PageDirectoryType::applyRefEditRecord( dir->mvcc_table_directory, version_list, r, @@ -193,7 +209,8 @@ void PageDirectoryFactory::applyRecord( } } -void PageDirectoryFactory::loadFromDisk(const PageDirectoryPtr & dir, WALStoreReaderPtr && reader) +template +void PageDirectoryFactory::loadFromDisk(const typename Trait::PageDirectoryPtr & dir, WALStoreReaderPtr && reader) { while (reader->remained()) { @@ -209,9 +226,12 @@ void PageDirectoryFactory::loadFromDisk(const PageDirectoryPtr & dir, WALStoreRe } // apply the edit read - auto edit = ser::deserializeFrom(record.value()); + auto edit = Trait::Serializer::deserializeFrom(record.value()); loadEdit(dir, edit); } } + +template class PageDirectoryFactory; +template class PageDirectoryFactory; } // namespace PS::V3 } // namespace DB diff --git a/dbms/src/Storages/Page/V3/PageDirectoryFactory.h b/dbms/src/Storages/Page/V3/PageDirectoryFactory.h index 20512893013..a45ad708c95 100644 --- a/dbms/src/Storages/Page/V3/PageDirectoryFactory.h +++ b/dbms/src/Storages/Page/V3/PageDirectoryFactory.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -27,8 +28,6 @@ using PSDiskDelegatorPtr = std::shared_ptr; namespace PS::V3 { -class PageDirectory; -using PageDirectoryPtr = std::unique_ptr; class WALStoreReader; using WALStoreReaderPtr = std::shared_ptr; @@ -36,41 +35,76 @@ using WALStoreReaderPtr = std::shared_ptr; * A helper class for creating `PageDirectory` instance and restore data from disk. * During restoring data, we need to restore `BlobStore::BlobStats` at the same time. */ +template class PageDirectoryFactory { public: PageVersion max_applied_ver; - PageDirectoryFactory & setBlobStore(BlobStore & blob_store) + PageDirectoryFactory & setBlobStore(BlobStore & blob_store) + { + blob_stats = &blob_store.blob_stats; + return *this; + } + PageDirectoryFactory & setBlobStore(BlobStore & blob_store) { blob_stats = &blob_store.blob_stats; return *this; } - PageDirectoryPtr create(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, WALConfig config); + typename Trait::PageDirectoryPtr create(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, WALConfig config); - PageDirectoryPtr createFromReader(String storage_name, WALStoreReaderPtr reader, WALStorePtr wal, bool for_dump_snapshot = false); + typename Trait::PageDirectoryPtr createFromReader(String storage_name, WALStoreReaderPtr reader, WALStorePtr wal, bool for_dump_snapshot = false); // just for test - PageDirectoryPtr createFromEdit(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, const PageEntriesEdit & edit); + typename Trait::PageDirectoryPtr createFromEdit(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, const typename Trait::PageEntriesEdit & edit); // just for test - PageDirectoryFactory & setBlobStats(BlobStats & blob_stats_) + PageDirectoryFactory & setBlobStats(BlobStats & blob_stats_) { blob_stats = &blob_stats_; return *this; } private: - void loadFromDisk(const PageDirectoryPtr & dir, WALStoreReaderPtr && reader); - void loadEdit(const PageDirectoryPtr & dir, const PageEntriesEdit & edit); + using ExternalIdTrait = typename Trait::ExternalIdTrait; + + void loadFromDisk(const typename Trait::PageDirectoryPtr & dir, WALStoreReaderPtr && reader); + void loadEdit(const typename Trait::PageDirectoryPtr & dir, const typename Trait::PageEntriesEdit & edit); static void applyRecord( - const PageDirectoryPtr & dir, - const PageEntriesEdit::EditRecord & r); + const typename Trait::PageDirectoryPtr & dir, + const typename Trait::PageEntriesEdit::EditRecord & r); BlobStats * blob_stats = nullptr; }; -} // namespace PS::V3 +namespace universal +{ +struct FactoryTrait +{ + using PageDirectoryPtr = DB::PS::V3::universal::PageDirectoryPtr; + using PageDirectoryType = PageDirectory; + using PageEntriesEdit = DB::PS::V3::universal::PageEntriesEdit; + using ExternalIdTrait = ExternalIdTrait; + using Serializer = Serializer; +}; +using PageDirectoryFactory = DB::PS::V3::PageDirectoryFactory; +} // namespace universal + +namespace u128 +{ +struct FactoryTrait +{ + using PageDirectoryPtr = DB::PS::V3::u128::PageDirectoryPtr; + using PageDirectoryType = PageDirectory; + using PageEntriesEdit = DB::PS::V3::u128::PageEntriesEdit; + using ExternalIdTrait = ExternalIdTrait; + using Serializer = Serializer; +}; +using PageDirectoryFactory = DB::PS::V3::PageDirectoryFactory; +} // namespace u128 + + +} // namespace PS::V3 } // namespace DB diff --git a/dbms/src/Storages/Page/V3/PageEntriesEdit.h b/dbms/src/Storages/Page/V3/PageEntriesEdit.h index 6b33990629b..61a95bbb00a 100644 --- a/dbms/src/Storages/Page/V3/PageEntriesEdit.h +++ b/dbms/src/Storages/Page/V3/PageEntriesEdit.h @@ -112,8 +112,12 @@ inline const char * typeToString(EditRecordType t) } /// Page entries change to apply to PageDirectory +template class PageEntriesEdit { +public: + using PageId = PageIdType; + public: PageEntriesEdit() = default; @@ -122,7 +126,7 @@ class PageEntriesEdit records.reserve(capacity); } - void put(PageIdV3Internal page_id, const PageEntryV3 & entry) + void put(const PageId & page_id, const PageEntryV3 & entry) { EditRecord record{}; record.type = EditRecordType::PUT; @@ -131,7 +135,7 @@ class PageEntriesEdit records.emplace_back(record); } - void putExternal(PageIdV3Internal page_id) + void putExternal(const PageId & page_id) { EditRecord record{}; record.type = EditRecordType::PUT_EXTERNAL; @@ -139,7 +143,7 @@ class PageEntriesEdit records.emplace_back(record); } - void upsertPage(PageIdV3Internal page_id, const PageVersion & ver, const PageEntryV3 & entry) + void upsertPage(const PageId & page_id, const PageVersion & ver, const PageEntryV3 & entry) { EditRecord record{}; record.type = EditRecordType::UPSERT; @@ -149,7 +153,7 @@ class PageEntriesEdit records.emplace_back(record); } - void del(PageIdV3Internal page_id) + void del(const PageId & page_id) { EditRecord record{}; record.type = EditRecordType::DEL; @@ -157,7 +161,7 @@ class PageEntriesEdit records.emplace_back(record); } - void ref(PageIdV3Internal ref_id, PageIdV3Internal page_id) + void ref(const PageId & ref_id, const PageId & page_id) { EditRecord record{}; record.type = EditRecordType::REF; @@ -166,7 +170,7 @@ class PageEntriesEdit records.emplace_back(record); } - void varRef(PageIdV3Internal ref_id, const PageVersion & ver, PageIdV3Internal ori_page_id) + void varRef(const PageId & ref_id, const PageVersion & ver, const PageId & ori_page_id) { EditRecord record{}; record.type = EditRecordType::VAR_REF; @@ -176,7 +180,7 @@ class PageEntriesEdit records.emplace_back(record); } - void varExternal(PageIdV3Internal page_id, const PageVersion & create_ver, Int64 being_ref_count) + void varExternal(const PageId & page_id, const PageVersion & create_ver, Int64 being_ref_count) { EditRecord record{}; record.type = EditRecordType::VAR_EXTERNAL; @@ -186,7 +190,7 @@ class PageEntriesEdit records.emplace_back(record); } - void varEntry(PageIdV3Internal page_id, const PageVersion & ver, const PageEntryV3 & entry, Int64 being_ref_count) + void varEntry(const PageId & page_id, const PageVersion & ver, const PageEntryV3 & entry, Int64 being_ref_count) { EditRecord record{}; record.type = EditRecordType::VAR_ENTRY; @@ -197,7 +201,7 @@ class PageEntriesEdit records.emplace_back(record); } - void varDel(PageIdV3Internal page_id, const PageVersion & delete_ver) + void varDel(const PageId & page_id, const PageVersion & delete_ver) { EditRecord record{}; record.type = EditRecordType::VAR_DELETE; @@ -214,20 +218,12 @@ class PageEntriesEdit struct EditRecord { - EditRecordType type; - PageIdV3Internal page_id; - PageIdV3Internal ori_page_id; + EditRecordType type{EditRecordType::DEL}; + PageId page_id{}; + PageId ori_page_id{}; PageVersion version; PageEntryV3 entry; - Int64 being_ref_count; - - EditRecord() - : type(EditRecordType::DEL) - , page_id(0) - , ori_page_id(0) - , version(0, 0) - , being_ref_count(1) - {} + Int64 being_ref_count{1}; }; using EditRecords = std::vector; @@ -272,6 +268,15 @@ class PageEntriesEdit return *this; } }; +namespace u128 +{ +using PageEntriesEdit = PageEntriesEdit; +} +namespace universal +{ +using PageEntriesEdit = PageEntriesEdit; +} + } // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/PageEntry.h b/dbms/src/Storages/Page/V3/PageEntry.h index 65a9b3955d3..929aa15d000 100644 --- a/dbms/src/Storages/Page/V3/PageEntry.h +++ b/dbms/src/Storages/Page/V3/PageEntry.h @@ -79,7 +79,6 @@ using PageEntriesV3 = std::vector; using PageIDAndEntryV3 = std::pair; using PageIDAndEntriesV3 = std::vector; - inline String toDebugString(const PageEntryV3 & entry) { return fmt::format("PageEntryV3{{file: {}, offset: 0x{:X}, size: {}, checksum: 0x{:X}, tag: {}, field_offsets_size: {}}}", diff --git a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp index 02bf9069191..e5626915dd9 100644 --- a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp +++ b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +63,7 @@ void PageStorageImpl::restore() // TODO: Speedup restoring blob_store.registerPaths(); - PageDirectoryFactory factory; + u128::PageDirectoryFactory factory; page_directory = factory .setBlobStore(blob_store) .create(storage_name, file_provider, delegator, WALConfig::from(config)); @@ -191,7 +192,7 @@ PageMap PageStorageImpl::readImpl(NamespaceId ns_id, const PageIds & page_ids, c { Page page_not_found; page_not_found.page_id = INVALID_PAGE_ID; - page_map[page_id_not_found] = page_not_found; + page_map[page_id_not_found.low] = page_not_found; } return page_map; } @@ -218,7 +219,12 @@ PageIds PageStorageImpl::readImpl(NamespaceId ns_id, const PageIds & page_ids, c { auto [page_entries, page_ids_not_found] = page_directory->getByIDsOrNull(page_id_v3s, snapshot); blob_store.read(page_entries, handler, read_limiter); - return page_ids_not_found; + PageIds page_ids_not_found_u64(page_ids_not_found.size()); + for (size_t index = 0; index < page_ids_not_found.size(); ++index) + { + page_ids_not_found_u64[index] = page_ids_not_found[index].low; + } + return page_ids_not_found_u64; } } @@ -229,7 +235,7 @@ PageMap PageStorageImpl::readImpl(NamespaceId ns_id, const std::vectorgetSnapshot(""); } - BlobStore::FieldReadInfos read_infos; + u128::BlobStoreTrait::FieldReadInfos read_infos; PageIds page_ids_not_found; for (const auto & [page_id, field_indices] : page_fields) { @@ -237,7 +243,7 @@ PageMap PageStorageImpl::readImpl(NamespaceId ns_id, const std::vector friend class PageDirectoryFactory; friend class PageStorageControlV3; #ifndef DBMS_PUBLIC_GTEST @@ -141,9 +142,9 @@ class PageStorageImpl : public DB::PageStorage LoggerPtr log; - PageDirectoryPtr page_directory; + u128::PageDirectoryPtr page_directory; - BlobStore blob_store; + BlobStore blob_store; std::atomic gc_is_running = false; diff --git a/dbms/src/Storages/Page/V3/WAL/serialize.cpp b/dbms/src/Storages/Page/V3/WAL/serialize.cpp index 6b7bc9b8a21..5a6bf1b4511 100644 --- a/dbms/src/Storages/Page/V3/WAL/serialize.cpp +++ b/dbms/src/Storages/Page/V3/WAL/serialize.cpp @@ -21,7 +21,9 @@ #include #include -namespace DB::PS::V3::ser +#include + +namespace DB::PS::V3 { inline void serializeVersionTo(const PageVersion & version, WriteBuffer & buf) { @@ -78,7 +80,18 @@ inline void deserializeEntryFrom(ReadBuffer & buf, PageEntryV3 & entry) } } -void serializePutTo(const PageEntriesEdit::EditRecord & record, WriteBuffer & buf) +inline void deserializeUniversalPageIDFrom(ReadBuffer & buf, UniversalPageId & page_id) +{ + readStringBinary(page_id, buf); +} + +inline void deserializeUInt128PageIDFrom(ReadBuffer & buf, PageIdV3Internal & page_id) +{ + readIntBinary(page_id, buf); +} + +template +void serializePutTo(const EditRecord & record, WriteBuffer & buf) { assert(record.type == EditRecordType::PUT || record.type == EditRecordType::UPSERT || record.type == EditRecordType::VAR_ENTRY); @@ -86,23 +99,38 @@ void serializePutTo(const PageEntriesEdit::EditRecord & record, WriteBuffer & bu UInt32 flags = 0; writeIntBinary(flags, buf); - writeIntBinary(record.page_id, buf); + if constexpr (std::is_same_v) + { + writeIntBinary(record.page_id, buf); + } + else if constexpr (std::is_same_v) + { + writeStringBinary(record.page_id, buf); + } serializeVersionTo(record.version, buf); writeIntBinary(record.being_ref_count, buf); serializeEntryTo(record.entry, buf); } -void deserializePutFrom([[maybe_unused]] const EditRecordType record_type, ReadBuffer & buf, PageEntriesEdit & edit) +template +void deserializePutFrom([[maybe_unused]] const EditRecordType record_type, ReadBuffer & buf, EditType & edit) { assert(record_type == EditRecordType::PUT || record_type == EditRecordType::UPSERT || record_type == EditRecordType::VAR_ENTRY); UInt32 flags = 0; readIntBinary(flags, buf); - PageEntriesEdit::EditRecord rec; + typename EditType::EditRecord rec; rec.type = record_type; - readIntBinary(rec.page_id, buf); + if constexpr (std::is_same_v) + { + deserializeUInt128PageIDFrom(buf, rec.page_id); + } + else if constexpr (std::is_same_v) + { + deserializeUniversalPageIDFrom(buf, rec.page_id); + } deserializeVersionFrom(buf, rec.version); readIntBinary(rec.being_ref_count, buf); @@ -110,81 +138,126 @@ void deserializePutFrom([[maybe_unused]] const EditRecordType record_type, ReadB edit.appendRecord(rec); } -void serializeRefTo(const PageEntriesEdit::EditRecord & record, WriteBuffer & buf) +template +void serializeRefTo(const EditRecord & record, WriteBuffer & buf) { assert(record.type == EditRecordType::REF || record.type == EditRecordType::VAR_REF); writeIntBinary(record.type, buf); - writeIntBinary(record.page_id, buf); - writeIntBinary(record.ori_page_id, buf); + if constexpr (std::is_same_v) + { + writeIntBinary(record.page_id, buf); + writeIntBinary(record.ori_page_id, buf); + } + else if constexpr (std::is_same_v) + { + writeStringBinary(record.page_id, buf); + writeStringBinary(record.ori_page_id, buf); + } serializeVersionTo(record.version, buf); assert(record.entry.file_id == INVALID_BLOBFILE_ID); } -void deserializeRefFrom([[maybe_unused]] const EditRecordType record_type, ReadBuffer & buf, PageEntriesEdit & edit) +template +void deserializeRefFrom([[maybe_unused]] const EditRecordType record_type, ReadBuffer & buf, EditType & edit) { assert(record_type == EditRecordType::REF || record_type == EditRecordType::VAR_REF); - PageEntriesEdit::EditRecord rec; + typename EditType::EditRecord rec; rec.type = record_type; - readIntBinary(rec.page_id, buf); - readIntBinary(rec.ori_page_id, buf); + if constexpr (std::is_same_v) + { + deserializeUInt128PageIDFrom(buf, rec.page_id); + deserializeUInt128PageIDFrom(buf, rec.ori_page_id); + } + else if constexpr (std::is_same_v) + { + deserializeUniversalPageIDFrom(buf, rec.page_id); + deserializeUniversalPageIDFrom(buf, rec.ori_page_id); + } deserializeVersionFrom(buf, rec.version); edit.appendRecord(rec); } - -void serializePutExternalTo(const PageEntriesEdit::EditRecord & record, WriteBuffer & buf) +template +void serializePutExternalTo(const EditRecord & record, WriteBuffer & buf) { assert(record.type == EditRecordType::PUT_EXTERNAL || record.type == EditRecordType::VAR_EXTERNAL); writeIntBinary(record.type, buf); - writeIntBinary(record.page_id, buf); + if constexpr (std::is_same_v) + { + writeIntBinary(record.page_id, buf); + } + else if constexpr (std::is_same_v) + { + writeStringBinary(record.page_id, buf); + } serializeVersionTo(record.version, buf); writeIntBinary(record.being_ref_count, buf); } -void deserializePutExternalFrom([[maybe_unused]] const EditRecordType record_type, ReadBuffer & buf, PageEntriesEdit & edit) +template +void deserializePutExternalFrom([[maybe_unused]] const EditRecordType record_type, ReadBuffer & buf, EditType & edit) { assert(record_type == EditRecordType::PUT_EXTERNAL || record_type == EditRecordType::VAR_EXTERNAL); - PageEntriesEdit::EditRecord rec; + typename EditType::EditRecord rec; rec.type = record_type; - readIntBinary(rec.page_id, buf); + if constexpr (std::is_same_v) + { + deserializeUInt128PageIDFrom(buf, rec.page_id); + } + else if constexpr (std::is_same_v) + { + deserializeUniversalPageIDFrom(buf, rec.page_id); + } deserializeVersionFrom(buf, rec.version); readIntBinary(rec.being_ref_count, buf); edit.appendRecord(rec); } -void serializeDelTo(const PageEntriesEdit::EditRecord & record, WriteBuffer & buf) +template +void serializeDelTo(const EditRecord & record, WriteBuffer & buf) { assert(record.type == EditRecordType::DEL || record.type == EditRecordType::VAR_DELETE); writeIntBinary(record.type, buf); - writeIntBinary(record.page_id, buf); + if constexpr (std::is_same_v) + { + writeIntBinary(record.page_id, buf); + } + else if constexpr (std::is_same_v) + { + writeStringBinary(record.page_id, buf); + } serializeVersionTo(record.version, buf); } -void deserializeDelFrom([[maybe_unused]] const EditRecordType record_type, ReadBuffer & buf, PageEntriesEdit & edit) +template +void deserializeDelFrom([[maybe_unused]] const EditRecordType record_type, ReadBuffer & buf, EditType & edit) { assert(record_type == EditRecordType::DEL || record_type == EditRecordType::VAR_DELETE); - PageIdV3Internal page_id; - readIntBinary(page_id, buf); - PageVersion version; - deserializeVersionFrom(buf, version); - - PageEntriesEdit::EditRecord rec; + typename EditType::EditRecord rec; rec.type = record_type; - rec.page_id = page_id; - rec.version = version; + if constexpr (std::is_same_v) + { + deserializeUInt128PageIDFrom(buf, rec.page_id); + } + else if constexpr (std::is_same_v) + { + deserializeUniversalPageIDFrom(buf, rec.page_id); + } + deserializeVersionFrom(buf, rec.version); edit.appendRecord(rec); } -void deserializeFrom(ReadBuffer & buf, PageEntriesEdit & edit) +template +void deserializeFrom(ReadBuffer & buf, EditType & edit) { EditRecordType record_type; while (!buf.eof()) @@ -223,7 +296,9 @@ void deserializeFrom(ReadBuffer & buf, PageEntriesEdit & edit) } } -String serializeTo(const PageEntriesEdit & edit) +namespace u128 +{ +String Serializer::serializeTo(const PageEntriesEdit & edit) { WriteBufferFromOwnString buf; UInt32 version = 1; @@ -253,18 +328,63 @@ String serializeTo(const PageEntriesEdit & edit) } return buf.releaseStr(); } +u128::PageEntriesEdit Serializer::deserializeFrom(std::string_view record) +{ + u128::PageEntriesEdit edit; + ReadBufferFromMemory buf(record.data(), record.size()); + UInt32 version = 0; + readIntBinary(version, buf); + if (version != 1) + throw Exception(fmt::format("Unknown version for PageEntriesEdit deser [version={}]", version), ErrorCodes::LOGICAL_ERROR); -PageEntriesEdit deserializeFrom(std::string_view record) + DB::PS::V3::deserializeFrom(buf, edit); + return edit; +} +} // namespace u128 +namespace universal +{ +String Serializer::serializeTo(const PageEntriesEdit & edit) +{ + WriteBufferFromOwnString buf; + UInt32 version = 1; + writeIntBinary(version, buf); + for (const auto & record : edit.getRecords()) + { + switch (record.type) + { + case EditRecordType::PUT: + case EditRecordType::UPSERT: + case EditRecordType::VAR_ENTRY: + serializePutTo(record, buf); + break; + case EditRecordType::REF: + case EditRecordType::VAR_REF: + serializeRefTo(record, buf); + break; + case EditRecordType::VAR_DELETE: + case EditRecordType::DEL: + serializeDelTo(record, buf); + break; + case EditRecordType::PUT_EXTERNAL: + case EditRecordType::VAR_EXTERNAL: + serializePutExternalTo(record, buf); + break; + } + } + return buf.releaseStr(); +} +universal::PageEntriesEdit Serializer::deserializeFrom(std::string_view record) { - PageEntriesEdit edit; + universal::PageEntriesEdit edit; ReadBufferFromMemory buf(record.data(), record.size()); UInt32 version = 0; readIntBinary(version, buf); if (version != 1) throw Exception(fmt::format("Unknown version for PageEntriesEdit deser [version={}]", version), ErrorCodes::LOGICAL_ERROR); - deserializeFrom(buf, edit); + DB::PS::V3::deserializeFrom(buf, edit); return edit; } +} // namespace universal -} // namespace DB::PS::V3::ser +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/WAL/serialize.h b/dbms/src/Storages/Page/V3/WAL/serialize.h index 4f37970a841..e4c4ba06afe 100644 --- a/dbms/src/Storages/Page/V3/WAL/serialize.h +++ b/dbms/src/Storages/Page/V3/WAL/serialize.h @@ -18,9 +18,22 @@ #include -namespace DB::PS::V3::ser +namespace DB::PS::V3 { -String serializeTo(const PageEntriesEdit & edit); -PageEntriesEdit deserializeFrom(std::string_view record); - -} // namespace DB::PS::V3::ser +namespace u128 +{ +struct Serializer +{ + static String serializeTo(const PageEntriesEdit & edit); + static PageEntriesEdit deserializeFrom(std::string_view record); +}; +} // namespace u128 +namespace universal +{ +struct Serializer +{ + static String serializeTo(const PageEntriesEdit & edit); + static PageEntriesEdit deserializeFrom(std::string_view record); +}; +} // namespace universal +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/tests/entries_helper.h b/dbms/src/Storages/Page/V3/tests/entries_helper.h index a651bfc5e04..3e8d1d55055 100644 --- a/dbms/src/Storages/Page/V3/tests/entries_helper.h +++ b/dbms/src/Storages/Page/V3/tests/entries_helper.h @@ -25,6 +25,7 @@ #include #include #include +#include #include namespace DB @@ -81,7 +82,7 @@ inline ::testing::AssertionResult getEntryCompare( const char * page_id_expr, const char * snap_expr, const PageEntryV3 & expected_entry, - const PageDirectoryPtr & dir, + const u128::PageDirectoryPtr & dir, const PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap) { @@ -140,7 +141,7 @@ inline ::testing::AssertionResult getEntriesCompare( const char * page_ids_expr, const char * snap_expr, const PageIDAndEntriesV3 & expected_entries, - const PageDirectoryPtr & dir, + const u128::PageDirectoryPtr & dir, const PageIdV3Internals page_ids, const PageDirectorySnapshotPtr & snap) { @@ -214,7 +215,7 @@ inline ::testing::AssertionResult getEntryNotExist( const char * dir_expr, const char * page_id_expr, const char * snap_expr, - const PageDirectoryPtr & dir, + const u128::PageDirectoryPtr & dir, const PageIdV3Internal page_id, const PageDirectorySnapshotPtr & snap) { @@ -254,7 +255,7 @@ inline ::testing::AssertionResult getEntriesNotExist( const char * dir_expr, const char * page_ids_expr, const char * snap_expr, - const PageDirectoryPtr & dir, + const u128::PageDirectoryPtr & dir, const PageIdV3Internals page_ids, const PageDirectorySnapshotPtr & snap) { diff --git a/dbms/src/Storages/Page/V3/tests/gtest_blob_store.cpp b/dbms/src/Storages/Page/V3/tests/gtest_blob_store.cpp index 255a598c834..c92e06fc396 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_blob_store.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_blob_store.cpp @@ -73,7 +73,7 @@ try { const auto file_provider = DB::tests::TiFlashTestEnv::getContext().getFileProvider(); config.file_limit_size = 2560; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); BlobFileId file_id1 = 10; BlobFileId file_id2 = 12; @@ -148,7 +148,7 @@ try config.file_limit_size = 1024; // Generate blob [1,2,3] - auto write_blob_datas = [](BlobStore & blob_store) { + auto write_blob_datas = [](BlobStore & blob_store) { WriteBatch write_batch; PageId page_id = 55; size_t buff_size = 1024; @@ -192,7 +192,7 @@ try return true; }; - auto restore_blobs = [](BlobStore & blob_store, std::vector blob_ids) { + auto restore_blobs = [](BlobStore & blob_store, std::vector blob_ids) { blob_store.registerPaths(); for (const auto & id : blob_ids) { @@ -210,12 +210,12 @@ try // Case 1, all of blob been restored { auto test_paths = delegator->listPaths(); - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); write_blob_datas(blob_store); ASSERT_TRUE(check_in_disk_file(test_paths, {1, 2, 3})); - auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); restore_blobs(blob_store_check, {1, 2, 3}); blob_store_check.blob_stats.restore(); @@ -231,12 +231,12 @@ try // Case 2, only recover blob 1 { auto test_paths = delegator->listPaths(); - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); write_blob_datas(blob_store); ASSERT_TRUE(check_in_disk_file(test_paths, {1, 2, 3})); - auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); restore_blobs(blob_store_check, {1}); blob_store_check.blob_stats.restore(); @@ -252,12 +252,12 @@ try // Case 3, only recover blob 2 { auto test_paths = delegator->listPaths(); - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); write_blob_datas(blob_store); ASSERT_TRUE(check_in_disk_file(test_paths, {1, 2, 3})); - auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); restore_blobs(blob_store_check, {2}); blob_store_check.blob_stats.restore(); @@ -273,12 +273,12 @@ try // Case 4, only recover blob 3 { auto test_paths = delegator->listPaths(); - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); write_blob_datas(blob_store); ASSERT_TRUE(check_in_disk_file(test_paths, {1, 2, 3})); - auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); restore_blobs(blob_store_check, {3}); blob_store_check.blob_stats.restore(); @@ -294,12 +294,12 @@ try // Case 5, recover a not exist blob { auto test_paths = delegator->listPaths(); - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); write_blob_datas(blob_store); ASSERT_TRUE(check_in_disk_file(test_paths, {1, 2, 3})); - auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store_check = BlobStore(getCurrentTestName(), file_provider, delegator, config); ASSERT_THROW(restore_blobs(blob_store_check, {4}), DB::Exception); } } @@ -313,7 +313,7 @@ TEST_F(BlobStoreTest, testWriteRead) size_t buff_nums = 21; size_t buff_size = 123; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); char c_buff[buff_size * buff_nums]; WriteBatch wb; @@ -330,7 +330,7 @@ TEST_F(BlobStoreTest, testWriteRead) } ASSERT_EQ(wb.getTotalDataSize(), buff_nums * buff_size); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); ASSERT_EQ(edit.size(), buff_nums); char c_buff_read[buff_size * buff_nums]; @@ -398,11 +398,11 @@ TEST_F(BlobStoreTest, testWriteReadWithIOLimiter) size_t buff_size = 10ul * 1024; const size_t rate_target = buff_size - 1; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); char c_buff[wb_nums * buff_size]; WriteBatch wbs[wb_nums]; - PageEntriesEdit edits[wb_nums]; + u128::PageEntriesEdit edits[wb_nums]; for (size_t i = 0; i < wb_nums; ++i) { @@ -511,7 +511,7 @@ try size_t buff_size = 120; WriteBatch wb; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); char c_buff[buff_size]; for (size_t j = 0; j < buff_size; ++j) @@ -525,14 +525,17 @@ try wb.putPage(page_id1, /* tag */ 0, buff1, buff_size, {20, 40, 40, 20}); wb.putPage(page_id2, /* tag */ 0, buff2, buff_size, {10, 50, 20, 20, 20}); wb.putPage(page_id3, /* tag */ 0, buff3, buff_size, {10, 5, 20, 20, 15, 5, 15, 30}); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); ASSERT_EQ(edit.size(), 3); - BlobStore::FieldReadInfo read_info1(buildV3Id(TEST_NAMESPACE_ID, page_id1), edit.getRecords()[0].entry, {0, 1, 2, 3}); - BlobStore::FieldReadInfo read_info2(buildV3Id(TEST_NAMESPACE_ID, page_id2), edit.getRecords()[1].entry, {2, 4}); - BlobStore::FieldReadInfo read_info3(buildV3Id(TEST_NAMESPACE_ID, page_id3), edit.getRecords()[2].entry, {1, 3}); + using BlobFieldReadInfo = u128::BlobStoreTrait::FieldReadInfo; + using BlobFieldReadInfos = u128::BlobStoreTrait::FieldReadInfos; - BlobStore::FieldReadInfos read_infos = {read_info1, read_info2, read_info3}; + BlobFieldReadInfo read_info1(buildV3Id(TEST_NAMESPACE_ID, page_id1), edit.getRecords()[0].entry, {0, 1, 2, 3}); + BlobFieldReadInfo read_info2(buildV3Id(TEST_NAMESPACE_ID, page_id2), edit.getRecords()[1].entry, {2, 4}); + BlobFieldReadInfo read_info3(buildV3Id(TEST_NAMESPACE_ID, page_id3), edit.getRecords()[2].entry, {1, 3}); + + BlobFieldReadInfos read_infos = {read_info1, read_info2, read_info3}; const auto & page_map = blob_store.read(read_infos, nullptr); ASSERT_EQ(page_map.size(), 3); @@ -584,7 +587,7 @@ TEST_F(BlobStoreTest, testFeildOffsetWriteRead) off += data_sz; } - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); char c_buff[buff_size * buff_nums]; WriteBatch wb; @@ -601,7 +604,7 @@ TEST_F(BlobStoreTest, testFeildOffsetWriteRead) } ASSERT_EQ(wb.getTotalDataSize(), buff_nums * buff_size); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); ASSERT_EQ(edit.size(), buff_nums); char c_buff_read[buff_size * buff_nums]; @@ -641,7 +644,7 @@ TEST_F(BlobStoreTest, testWrite) try { const auto file_provider = DB::tests::TiFlashTestEnv::getContext().getFileProvider(); - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); PageId page_id = 50; const size_t buff_size = 1024; @@ -662,7 +665,7 @@ try wb.putPage(page_id, /*tag*/ 0, buff1, buff_size); wb.putPage(page_id, /*tag*/ 0, buff2, buff_size); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); ASSERT_EQ(edit.size(), 2); auto records = edit.getRecords(); @@ -689,7 +692,7 @@ try wb.delPage(page_id + 1); wb.delPage(page_id); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); ASSERT_EQ(edit.size(), 3); auto records = edit.getRecords(); @@ -722,7 +725,7 @@ try wb.putRefPage(page_id + 1, page_id); wb.delPage(page_id); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); auto records = edit.getRecords(); auto record = records[0]; @@ -752,7 +755,7 @@ TEST_F(BlobStoreTest, DISABLED_testWriteOutOfLimitSize) { config.file_limit_size = buff_size - 1; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); WriteBatch wb; char c_buff[buff_size]; @@ -776,7 +779,7 @@ TEST_F(BlobStoreTest, DISABLED_testWriteOutOfLimitSize) size_t buffer_sizes[] = {buff_size, buff_size - 1, buff_size / 2 + 1}; for (const auto & buf_size : buffer_sizes) { - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); WriteBatch wb; char c_buff1[buf_size]; @@ -819,7 +822,7 @@ TEST_F(BlobStoreTest, testBlobStoreGcStats) size_t buff_size = 1024; size_t buff_nums = 10; PageId page_id = 50; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); std::list remove_entries_idx1 = {1, 3, 4, 7, 9}; std::list remove_entries_idx2 = {6, 8}; @@ -917,7 +920,7 @@ TEST_F(BlobStoreTest, testBlobStoreGcStats2) size_t buff_size = 1024; size_t buff_nums = 10; PageId page_id = 50; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); std::list remove_entries_idx = {0, 1, 2, 3, 4, 5, 6, 7}; WriteBatch wb; @@ -977,7 +980,7 @@ TEST_F(BlobStoreTest, GC) size_t buff_nums = 21; size_t buff_size = 123; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config); char c_buff[buff_size * buff_nums]; WriteBatch wb; @@ -994,16 +997,15 @@ TEST_F(BlobStoreTest, GC) } ASSERT_EQ(wb.getTotalDataSize(), buff_nums * buff_size); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); ASSERT_EQ(edit.size(), buff_nums); - PageIdAndVersionedEntries versioned_pageid_entries; + u128::PageDirectoryTrait::GcEntries versioned_pageid_entries; for (const auto & record : edit.getRecords()) { versioned_pageid_entries.emplace_back(buildV3Id(TEST_NAMESPACE_ID, page_id), 1, record.entry); } - std::map gc_context; - gc_context[1] = versioned_pageid_entries; + u128::PageDirectoryTrait::GcEntriesMap gc_context{{1, versioned_pageid_entries}}; // Before we do BlobStore we need change BlobFile0 to Read-Only auto stat = blob_store.blob_stats.blobIdToStat(1); @@ -1045,12 +1047,12 @@ try BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 100; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); char c_buff[buff_size * buff_nums]; WriteBatch wb; - std::map gc_context; + u128::PageDirectoryTrait::GcEntriesMap gc_context; for (size_t i = 0; i < buff_nums; ++i) { @@ -1061,13 +1063,13 @@ try ReadBufferPtr buff = std::make_shared(const_cast(c_buff + i * buff_size), buff_size); wb.putPage(page_id, /* tag */ 0, buff, buff_size); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); const auto & records = edit.getRecords(); ASSERT_EQ(records.size(), 1); if (gc_context.find(records[0].entry.file_id) == gc_context.end()) { - PageIdAndVersionedEntries versioned_pageid_entries; + u128::PageDirectoryTrait::GcEntries versioned_pageid_entries; versioned_pageid_entries.emplace_back(page_id, 1, records[0].entry); gc_context[records[0].entry.file_id] = std::move(versioned_pageid_entries); } @@ -1096,12 +1098,13 @@ try BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 100; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); char c_buff[buff_size * buff_nums]; WriteBatch wb; - BlobStore::FieldReadInfos read_infos; + using BlobFieldReadInfos = u128::BlobStoreTrait::FieldReadInfos; + BlobFieldReadInfos read_infos; for (size_t i = 0; i < buff_nums; ++i) { for (size_t j = 0; j < buff_size; ++j) @@ -1112,11 +1115,11 @@ try ReadBufferPtr buff = std::make_shared(const_cast(c_buff + i * buff_size), buff_size); PageFieldSizes field_sizes{1, 2, 4, 8, (buff_size - 1 - 2 - 4 - 8)}; wb.putPage(page_id, /* tag */ 0, buff, buff_size, field_sizes); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); const auto & records = edit.getRecords(); ASSERT_EQ(records.size(), 1); - read_infos.emplace_back(BlobStore::FieldReadInfo(buildV3Id(TEST_NAMESPACE_ID, page_id), records[0].entry, {0, 1, 2, 3, 4})); + read_infos.emplace_back(u128::BlobStoreTrait::FieldReadInfo(buildV3Id(TEST_NAMESPACE_ID, page_id), records[0].entry, {0, 1, 2, 3, 4})); page_id++; wb.clear(); @@ -1141,7 +1144,7 @@ try BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 400; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); // PUT page_id 50 into blob 1 range [0,200] { @@ -1151,7 +1154,7 @@ try WriteBatch wb; ReadBufferPtr buff = std::make_shared(const_cast(c_buff), size_200); wb.putPage(page_id, /* tag */ 0, buff, size_200); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); const auto & records = edit.getRecords(); ASSERT_EQ(records.size(), 1); @@ -1178,7 +1181,7 @@ try WriteBatch wb; ReadBufferPtr buff = std::make_shared(const_cast(c_buff), size_500); wb.putPage(page_id, /* tag */ 0, buff, size_500); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); const auto & records = edit.getRecords(); ASSERT_EQ(records.size(), 1); @@ -1210,7 +1213,7 @@ try WriteBatch wb; ReadBufferPtr buff = std::make_shared(const_cast(c_buff), size_100); wb.putPage(page_id, /* tag */ 0, buff, size_100); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); const auto & records = edit.getRecords(); ASSERT_EQ(records.size(), 1); @@ -1237,7 +1240,7 @@ try WriteBatch wb; ReadBufferPtr buff = std::make_shared(const_cast(c_buff), size_300); wb.putPage(page_id, /* tag */ 0, buff, size_300); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); const auto & records = edit.getRecords(); ASSERT_EQ(records.size(), 1); @@ -1268,7 +1271,7 @@ try wb.putPage(page_id++, /* tag */ 0, std::make_shared(const_cast(c_buff3), sizeof(c_buff3)), sizeof(c_buff3)); wb.putPage(page_id++, /* tag */ 0, std::make_shared(const_cast(c_buff4), sizeof(c_buff4)), sizeof(c_buff4)); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); const auto & records = edit.getRecords(); ASSERT_EQ(records.size(), 4); @@ -1307,7 +1310,7 @@ try BlobConfig config_with_small_file_limit_size; config_with_small_file_limit_size.file_limit_size = 400; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); { size_t size_500 = 500; @@ -1316,7 +1319,7 @@ try WriteBatch wb; ReadBufferPtr buff = std::make_shared(const_cast(c_buff), size_500); wb.putPage(page_id, /* tag */ 0, buff, size_500); - PageEntriesEdit edit = blob_store.write(wb, nullptr); + u128::PageEntriesEdit edit = blob_store.write(wb, nullptr); const auto & gc_info = blob_store.getGCStats(); ASSERT_TRUE(gc_info.empty()); @@ -1342,7 +1345,7 @@ try PageEntryV3 entry_from_write; { - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); size_t size_500 = 500; char c_buff[size_500]; @@ -1356,7 +1359,7 @@ try } { - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); blob_store.registerPaths(); blob_store.blob_stats.restoreByEntry(entry_from_write); @@ -1382,7 +1385,7 @@ try PageEntryV3 entry_from_write1; PageEntryV3 entry_from_write2; { - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); size_t size_500 = 500; size_t size_200 = 200; char c_buff1[size_500]; @@ -1406,7 +1409,7 @@ try config_with_small_file_limit_size.file_limit_size = 400; { - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); blob_store.registerPaths(); blob_store.blob_stats.restoreByEntry(entry_from_write1); blob_store.blob_stats.restoreByEntry(entry_from_write2); @@ -1454,7 +1457,7 @@ try PageEntryV3 entry_from_write1; PageEntryV3 entry_from_write2; PageEntryV3 entry_from_write3; - auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); + auto blob_store = BlobStore(getCurrentTestName(), file_provider, delegator, config_with_small_file_limit_size); { size_t size_100 = 100; size_t size_500 = 500; @@ -1497,11 +1500,9 @@ try const auto & blob_need_gc2 = blob_store.getGCStats(); ASSERT_EQ(blob_need_gc2.size(), 1); - std::map gc_context; - PageIdAndVersionedEntries versioned_pageid_entries; - versioned_pageid_entries.emplace_back(page_id2, 1, entry_from_write2); - gc_context[1] = versioned_pageid_entries; - PageEntriesEdit gc_edit = blob_store.gc(gc_context, 500); + u128::PageDirectoryTrait::GcEntries gc_entries{{buildV3Id(TEST_NAMESPACE_ID, page_id2), PageVersion(1), entry_from_write2}}; + u128::PageDirectoryTrait::GcEntriesMap gc_context{{1, gc_entries}}; + u128::PageEntriesEdit gc_edit = blob_store.gc(gc_context, 500); const auto & records = gc_edit.getRecords(); ASSERT_EQ(records.size(), 1); ASSERT_EQ(records[0].entry.file_id, 2); diff --git a/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp b/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp index 8a7140cc938..7cccc88a97d 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_page_directory.cpp @@ -50,7 +50,7 @@ namespace PS::V3::tests TEST(ExternalIdsByNamespaceTest, Simple) { NamespaceId ns_id = 100; - ExternalIdsByNamespace external_ids_by_ns; + ExternalIdsByNamespace external_ids_by_ns; { ASSERT_FALSE(external_ids_by_ns.existNamespace(ns_id)); @@ -111,28 +111,28 @@ class PageDirectoryTest : public DB::base::TiFlashStorageTestBasic dir = restoreFromDisk(); } - static PageDirectoryPtr restoreFromDisk() + static u128::PageDirectoryPtr restoreFromDisk() { auto path = getTemporaryPath(); auto ctx = DB::tests::TiFlashTestEnv::getContext(); FileProviderPtr provider = ctx.getFileProvider(); PSDiskDelegatorPtr delegator = std::make_shared(path); - PageDirectoryFactory factory; + u128::PageDirectoryFactory factory; return factory.create("PageDirectoryTest", provider, delegator, WALConfig()); } protected: - static PageId getNormalPageIdU64(const PageDirectoryPtr & d, PageId page_id, const PageDirectorySnapshotPtr & snap) + static PageId getNormalPageIdU64(const u128::PageDirectoryPtr & d, PageId page_id, const PageDirectorySnapshotPtr & snap) { return d->getNormalPageId(buildV3Id(TEST_NAMESPACE_ID, page_id), snap, true).low; } - static PageEntryV3 getEntry(const PageDirectoryPtr & d, PageId page_id, const PageDirectorySnapshotPtr & snap) + static PageEntryV3 getEntry(const u128::PageDirectoryPtr & d, PageId page_id, const PageDirectorySnapshotPtr & snap) { return d->getByID(buildV3Id(TEST_NAMESPACE_ID, page_id), snap).second; } protected: - PageDirectoryPtr dir; + u128::PageDirectoryPtr dir; LoggerPtr log; }; @@ -145,7 +145,7 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); dir->apply(std::move(edit)); } @@ -155,7 +155,7 @@ try PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } @@ -172,7 +172,7 @@ try PageEntryV3 entry2_v2{.file_id = 2 + 102, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2_v2); dir->apply(std::move(edit)); @@ -193,7 +193,7 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry1); dir->apply(std::move(edit)); } @@ -203,7 +203,7 @@ try PageEntryV3 entry2{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x1234, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry2); dir->apply(std::move(edit)); } @@ -221,7 +221,7 @@ try page_id++; PageEntryV3 entry3{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x12345, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry1); edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry2); edit.put(buildV3Id(TEST_NAMESPACE_ID, page_id), entry3); @@ -243,7 +243,7 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); @@ -256,7 +256,7 @@ try PageEntryV3 entry3{.file_id = 3, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry4{.file_id = 4, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry3); edit.put(buildV3Id(TEST_NAMESPACE_ID, 4), entry4); @@ -288,14 +288,14 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } @@ -306,14 +306,14 @@ try // Update on ref page is not allowed PageEntryV3 entry_updated{.file_id = 999, .size = 16, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x123}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry_updated); ASSERT_ANY_THROW(dir->apply(std::move(edit))); } PageEntryV3 entry_updated2{.file_id = 777, .size = 16, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x123}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_updated2); ASSERT_ANY_THROW(dir->apply(std::move(edit))); } @@ -326,14 +326,14 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } @@ -343,7 +343,7 @@ try // Delete 3, 2 won't get deleted. { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 3)); dir->apply(std::move(edit)); } @@ -355,7 +355,7 @@ try // Delete 2, 3 won't get deleted. { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } @@ -376,14 +376,14 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } @@ -393,7 +393,7 @@ try // Ref 4 -> 3 { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); dir->apply(std::move(edit)); } @@ -414,14 +414,14 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } @@ -431,7 +431,7 @@ try { // Ref 3 -> 2 again, should be idempotent - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } @@ -442,7 +442,7 @@ try EXPECT_ENTRY_EQ(entry2, dir, 3, snap2); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 3)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); @@ -458,7 +458,7 @@ try { // Adding ref after deleted. // It will invalid snap1 and snap2 - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } @@ -481,14 +481,14 @@ try PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); } { // Ref 3->2 - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 2)); dir->apply(std::move(edit)); } @@ -498,7 +498,7 @@ try { // Ref 4 -> 3, collapse to 4 -> 2 - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); dir->apply(std::move(edit)); } @@ -514,7 +514,7 @@ CATCH TEST_F(PageDirectoryTest, RefWontDeadLock) { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; { // 1. batch.putExternal(0, 0); PageEntryV3 entry1; @@ -526,7 +526,7 @@ TEST_F(PageDirectoryTest, RefWontDeadLock) dir->apply(std::move(edit)); - PageEntriesEdit edit2; + u128::PageEntriesEdit edit2; { // 1. batch.putRefPage(2, 1); // ref 2 -> 1 -> 0 edit2.ref(buildV3Id(TEST_NAMESPACE_ID, 2), buildV3Id(TEST_NAMESPACE_ID, 1)); @@ -543,7 +543,7 @@ TEST_F(PageDirectoryTest, IdempotentNewExtPageAfterAllCleaned) // Make sure creating ext page after itself and all its reference are clean // is idempotent { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); auto alive_ids = dir->getAliveExternalIds(TEST_NAMESPACE_ID); @@ -552,7 +552,7 @@ TEST_F(PageDirectoryTest, IdempotentNewExtPageAfterAllCleaned) } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); // should be idempotent dir->apply(std::move(edit)); auto alive_ids = dir->getAliveExternalIds(TEST_NAMESPACE_ID); @@ -561,7 +561,7 @@ TEST_F(PageDirectoryTest, IdempotentNewExtPageAfterAllCleaned) } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); dir->gcInMemEntries(); // clean in memory @@ -572,7 +572,7 @@ TEST_F(PageDirectoryTest, IdempotentNewExtPageAfterAllCleaned) { // Add again after deleted - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); auto alive_ids = dir->getAliveExternalIds(TEST_NAMESPACE_ID); @@ -588,7 +588,7 @@ try PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry3{.file_id = 3, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry2); dir->apply(std::move(edit)); @@ -596,7 +596,7 @@ try // Applying ref to not exist entry is not allowed { // Ref 4-> 999 - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry3); edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 999)); ASSERT_ANY_THROW(dir->apply(std::move(edit))); @@ -609,22 +609,22 @@ try { PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry1); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 2), buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 1)); ASSERT_ANY_THROW({ dir->apply(std::move(edit)); }); } @@ -635,22 +635,22 @@ TEST_F(PageDirectoryTest, RefToDeletedExtPageTwoHops) try { { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 2), buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 1)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 3), buildV3Id(TEST_NAMESPACE_ID, 1)); ASSERT_ANY_THROW({ dir->apply(std::move(edit)); }); } @@ -663,39 +663,39 @@ try // Fix issue: https://github.com/pingcap/tiflash/issues/5570 PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 951), entry1); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 954), buildV3Id(TEST_NAMESPACE_ID, 951)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 951)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 951)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 972), buildV3Id(TEST_NAMESPACE_ID, 954)); edit.ref(buildV3Id(TEST_NAMESPACE_ID, 985), buildV3Id(TEST_NAMESPACE_ID, 954)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 954)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 998), buildV3Id(TEST_NAMESPACE_ID, 985)); edit.ref(buildV3Id(TEST_NAMESPACE_ID, 1011), buildV3Id(TEST_NAMESPACE_ID, 985)); dir->apply(std::move(edit)); @@ -712,7 +712,7 @@ try PageId id = 50; PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, id), entry1); dir->apply(std::move(edit)); } @@ -774,7 +774,7 @@ try if (del_in_same_wb) { // create ref and del in the same write batch - PageEntriesEdit edit; + u128::PageEntriesEdit edit; for (const auto & x : new_ref_page_ids) edit.ref(buildV3Id(TEST_NAMESPACE_ID, x.first), buildV3Id(TEST_NAMESPACE_ID, x.second)); for (const auto x : delete_ref_page_ids) @@ -785,13 +785,13 @@ try { // first create all ref, then del in another write batch { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; for (const auto & x : new_ref_page_ids) edit.ref(buildV3Id(TEST_NAMESPACE_ID, x.first), buildV3Id(TEST_NAMESPACE_ID, x.second)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; for (const auto x : delete_ref_page_ids) edit.del(buildV3Id(TEST_NAMESPACE_ID, x)); dir->apply(std::move(edit)); @@ -819,7 +819,7 @@ try { PageId id = 50; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, id)); dir->apply(std::move(edit)); } @@ -876,7 +876,7 @@ try if (del_in_same_wb) { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; for (const auto & x : new_ref_page_ids) edit.ref(buildV3Id(TEST_NAMESPACE_ID, x.first), buildV3Id(TEST_NAMESPACE_ID, x.second)); for (const auto x : delete_ref_page_ids) @@ -886,13 +886,13 @@ try else { { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; for (const auto & x : new_ref_page_ids) edit.ref(buildV3Id(TEST_NAMESPACE_ID, x.first), buildV3Id(TEST_NAMESPACE_ID, x.second)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; for (const auto x : delete_ref_page_ids) edit.del(buildV3Id(TEST_NAMESPACE_ID, x)); dir->apply(std::move(edit)); @@ -925,7 +925,7 @@ TEST_F(PageDirectoryTest, NormalPageId) try { { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 9), PageEntryV3{}); edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); @@ -938,7 +938,7 @@ try EXPECT_ANY_THROW(getNormalPageIdU64(dir, 12, s0)); // not exist at all { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); edit.ref(buildV3Id(TEST_NAMESPACE_ID, 12), buildV3Id(TEST_NAMESPACE_ID, 10)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); @@ -956,7 +956,7 @@ try EXPECT_EQ(9, getNormalPageIdU64(dir, 14, s1)); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 14)); dir->apply(std::move(edit)); @@ -970,7 +970,7 @@ try EXPECT_ANY_THROW(getNormalPageIdU64(dir, 14, s2)); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 12)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 13)); dir->apply(std::move(edit)); @@ -992,7 +992,7 @@ class PageDirectoryGCTest : public PageDirectoryTest #define INSERT_ENTRY_TO(PAGE_ID, VERSION, BLOB_FILE_ID) \ PageEntryV3 entry_v##VERSION{.file_id = (BLOB_FILE_ID), .size = (VERSION), .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; \ { \ - PageEntriesEdit edit; \ + u128::PageEntriesEdit edit; \ edit.put(buildV3Id(TEST_NAMESPACE_ID, (PAGE_ID)), entry_v##VERSION); \ dir->apply(std::move(edit)); \ } @@ -1004,7 +1004,7 @@ class PageDirectoryGCTest : public PageDirectoryTest auto snapshot##VERSION = dir->createSnapshot(); #define INSERT_DELETE(PAGE_ID) \ { \ - PageEntriesEdit edit; \ + u128::PageEntriesEdit edit; \ edit.del(buildV3Id(TEST_NAMESPACE_ID, (PAGE_ID))); \ dir->apply(std::move(edit)); \ } @@ -1286,7 +1286,7 @@ try INSERT_ENTRY(another_page_id, 7); PageEntryV3 entry_v8{.file_id = 1, .size = 8, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, page_id)); edit.put(buildV3Id(TEST_NAMESPACE_ID, another_page_id), entry_v8); dir->apply(std::move(edit)); @@ -1391,7 +1391,7 @@ try EXPECT_EQ(entries_in_file2.size(), 2); // 2 entries for 1 page id EXPECT_EQ(entries_in_file3.size(), 1); // 1 entries for 1 page id - PageEntriesEdit gc_migrate_entries; + u128::PageEntriesEdit gc_migrate_entries; for (const auto & [file_id, entries] : candidate_entries_1.first) { (void)file_id; @@ -1447,7 +1447,7 @@ try // `page_id` get removed EXPECT_EQ(dir->numPages(), 1); - PageEntriesEdit gc_migrate_entries; + u128::PageEntriesEdit gc_migrate_entries; for (const auto & [file_id, entries] : candidate_entries_1.first) { (void)file_id; @@ -1476,12 +1476,12 @@ try // 10->entry1, 11->10=>11->entry1; del 10->entry1 PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 10), entry1); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); @@ -1494,7 +1494,7 @@ try // del 11->entry1 { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); dir->apply(std::move(edit)); } @@ -1513,17 +1513,17 @@ try // 10->entry1, 11->10=>11->entry1; del 10->entry1 PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 10), entry1); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 12), buildV3Id(TEST_NAMESPACE_ID, 10)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); @@ -1536,7 +1536,7 @@ try // del 11->entry1 { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 12)); dir->apply(std::move(edit)); @@ -1556,17 +1556,17 @@ try // 10->entry1, 11->10, 12->10 PageEntryV3 entry1{.file_id = 1, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 10), entry1); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 12), buildV3Id(TEST_NAMESPACE_ID, 10)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); @@ -1580,7 +1580,7 @@ try // upsert 10->entry2 PageEntryV3 entry2{.file_id = 2, .size = 1024, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; auto full_gc_entries = dir->getEntriesByBlobIds({1}); auto ids = full_gc_entries.first.at(1); ASSERT_EQ(ids.size(), 1); @@ -1600,14 +1600,14 @@ try // del 11->entry2 { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); dir->apply(std::move(edit)); EXPECT_EQ(dir->gcInMemEntries().size(), 0); } // del 12->entry2 { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 12)); dir->apply(std::move(edit)); // entry2 get removed @@ -1623,12 +1623,12 @@ try { // 10->ext, 11->10=>11->ext; del 10->ext { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); dir->apply(std::move(edit)); @@ -1644,7 +1644,7 @@ try // del 11->ext { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); dir->apply(std::move(edit)); } @@ -1663,33 +1663,33 @@ TEST_F(PageDirectoryGCTest, GCOnRefedExternalEntries2) try { { - PageEntriesEdit edit; // ingest + u128::PageEntriesEdit edit; // ingest edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 352)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 353), buildV3Id(TEST_NAMESPACE_ID, 352)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; // ingest done + u128::PageEntriesEdit edit; // ingest done edit.del(buildV3Id(TEST_NAMESPACE_ID, 352)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; // split + u128::PageEntriesEdit edit; // split edit.ref(buildV3Id(TEST_NAMESPACE_ID, 357), buildV3Id(TEST_NAMESPACE_ID, 353)); edit.ref(buildV3Id(TEST_NAMESPACE_ID, 359), buildV3Id(TEST_NAMESPACE_ID, 353)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; // split done + u128::PageEntriesEdit edit; // split done edit.del(buildV3Id(TEST_NAMESPACE_ID, 353)); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; // one of segment delta-merge + u128::PageEntriesEdit edit; // one of segment delta-merge edit.del(buildV3Id(TEST_NAMESPACE_ID, 359)); dir->apply(std::move(edit)); } @@ -1708,13 +1708,13 @@ try auto s0 = dir->createSnapshot(); auto edit = dir->dumpSnapshotToEdit(s0); - auto restore_from_edit = [](const PageEntriesEdit & edit) { - auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); + auto restore_from_edit = [](const u128::PageEntriesEdit & edit) { + auto deseri_edit = u128::Serializer::deserializeFrom(u128::Serializer::serializeTo(edit)); auto ctx = DB::tests::TiFlashTestEnv::getContext(); auto provider = ctx.getFileProvider(); auto path = getTemporaryPath(); PSDiskDelegatorPtr delegator = std::make_shared(path); - PageDirectoryFactory factory; + u128::PageDirectoryFactory factory; auto d = factory.createFromEdit(getCurrentTestName(), provider, delegator, deseri_edit); return d; }; @@ -1731,13 +1731,13 @@ CATCH TEST_F(PageDirectoryGCTest, DumpAndRestore) try { - auto restore_from_edit = [](const PageEntriesEdit & edit) { - auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); + auto restore_from_edit = [](const u128::PageEntriesEdit & edit) { + auto deseri_edit = u128::Serializer::deserializeFrom(u128::Serializer::serializeTo(edit)); auto ctx = DB::tests::TiFlashTestEnv::getContext(); auto provider = ctx.getFileProvider(); auto path = getTemporaryPath(); PSDiskDelegatorPtr delegator = std::make_shared(path); - PageDirectoryFactory factory; + u128::PageDirectoryFactory factory; auto d = factory.createFromEdit(getCurrentTestName(), provider, delegator, deseri_edit); return d; }; @@ -1747,14 +1747,14 @@ try PageEntryV3 entry_2_v1{.file_id = 2, .size = 1, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry_2_v2{.file_id = 2, .size = 2, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_1_v1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_1_v2); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_2_v1); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_2_v2); edit.del(buildV3Id(TEST_NAMESPACE_ID, 3)); dir->apply(std::move(edit)); @@ -1776,7 +1776,7 @@ try PageEntryV3 entry_50{.file_id = 1, .size = 50, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry_60{.file_id = 1, .size = 90, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 2)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 1)); edit.putExternal(buildV3Id(TEST_NAMESPACE_ID, 10)); @@ -1806,7 +1806,7 @@ try check_s1(); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 11), buildV3Id(TEST_NAMESPACE_ID, 10)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 10)); @@ -1856,7 +1856,7 @@ try { // only 51->50 left - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 11)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 21)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 22)); @@ -1892,7 +1892,7 @@ try { // only 51->50 left - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.del(buildV3Id(TEST_NAMESPACE_ID, 51)); dir->apply(std::move(edit)); } @@ -1940,25 +1940,25 @@ try PageEntryV3 entry_5_v1{.file_id = file_id2, .size = 255, .padded_size = 0, .tag = 0, .offset = 0x100, .checksum = 0x4567}; PageEntryV3 entry_5_v2{.file_id = file_id2, .size = 255, .padded_size = 0, .tag = 0, .offset = 0x400, .checksum = 0x4567}; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_1_v1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_5_v1); dir->apply(std::move(edit)); } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.ref(buildV3Id(TEST_NAMESPACE_ID, 2), buildV3Id(TEST_NAMESPACE_ID, 1)); edit.del(buildV3Id(TEST_NAMESPACE_ID, 1)); edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_5_v2); // replaced for page 5 entry dir->apply(std::move(edit)); } - auto restore_from_edit = [](const PageEntriesEdit & edit, BlobStats & stats) { + auto restore_from_edit = [](const u128::PageEntriesEdit & edit, BlobStats & stats) { auto ctx = ::DB::tests::TiFlashTestEnv::getContext(); auto provider = ctx.getFileProvider(); auto path = getTemporaryPath(); PSDiskDelegatorPtr delegator = std::make_shared(path); - PageDirectoryFactory factory; + u128::PageDirectoryFactory factory; auto d = factory.setBlobStats(stats).createFromEdit(getCurrentTestName(), provider, delegator, edit); return d; }; @@ -1997,18 +1997,18 @@ try PageEntryV3 entry_50_1{.file_id = 1, .size = 7890, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry_50_2{.file_id = 2, .size = 7890, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; - auto restore_from_edit = [](const PageEntriesEdit & edit) { + auto restore_from_edit = [](const u128::PageEntriesEdit & edit) { auto ctx = ::DB::tests::TiFlashTestEnv::getContext(); auto provider = ctx.getFileProvider(); auto path = getTemporaryPath(); PSDiskDelegatorPtr delegator = std::make_shared(path); - PageDirectoryFactory factory; + u128::PageDirectoryFactory factory; auto d = factory.createFromEdit(getCurrentTestName(), provider, delegator, edit); return d; }; { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 50), entry_50_1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 50), entry_50_2); edit.ref(buildV3Id(TEST_NAMESPACE_ID, 51), buildV3Id(TEST_NAMESPACE_ID, 50)); @@ -2026,5 +2026,36 @@ CATCH #undef INSERT_ENTRY_ACQ_SNAP #undef INSERT_DELETE + +class PageDirectoryStringTest : public DB::base::TiFlashStorageTestBasic +{ +public: + PageDirectoryStringTest() + : log(Logger::get("PageDirectoryStringTest")) + {} + + void SetUp() override + { + auto path = getTemporaryPath(); + dropDataOnDisk(path); + dir = restoreFromDisk(); + } + + static u128::PageDirectoryPtr restoreFromDisk() + { + auto path = getTemporaryPath(); + auto ctx = DB::tests::TiFlashTestEnv::getContext(); + FileProviderPtr provider = ctx.getFileProvider(); + PSDiskDelegatorPtr delegator = std::make_shared(path); + u128::PageDirectoryFactory factory; + return factory.create("PageDirectoryTest", provider, delegator, WALConfig()); + } + +protected: + u128::PageDirectoryPtr dir; + + LoggerPtr log; +}; + } // namespace PS::V3::tests } // namespace DB diff --git a/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp b/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp index f4670fb4598..140a9b65173 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp @@ -136,7 +136,7 @@ try char c_buff[wb_nums * buff_size]; WriteBatch wbs[wb_nums]; - PageEntriesEdit edits[wb_nums]; + u128::PageEntriesEdit edits[wb_nums]; for (size_t i = 0; i < wb_nums; ++i) { diff --git a/dbms/src/Storages/Page/V3/tests/gtest_versioned_entries.cpp b/dbms/src/Storages/Page/V3/tests/gtest_versioned_entries.cpp index b95941153e0..004c22177a9 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_versioned_entries.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_versioned_entries.cpp @@ -68,7 +68,7 @@ class VersionedEntriesTest : public ::testing::Test protected: const PageId page_id = 100; - VersionedPageEntries entries; + u128::VersionedPageEntries entries; }; TEST_F(VersionedEntriesTest, InsertGet) @@ -529,7 +529,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) INSERT_BLOBID_ENTRY(1, 11); PageId page_id = 100; - auto check_for_blob_id_1 = [&](const PageIdAndVersionedEntries & entries) { + auto check_for_blob_id_1 = [&](const u128::PageDirectoryTrait::GcEntries & entries) { auto it = entries.begin(); ASSERT_EQ(std::get<0>(*it).low, page_id); @@ -551,7 +551,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) ASSERT_EQ(std::get<1>(*it).sequence, 11); ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v11); }; - auto check_for_blob_id_2 = [&](const PageIdAndVersionedEntries & entries) { + auto check_for_blob_id_2 = [&](const u128::PageDirectoryTrait::GcEntries & entries) { auto it = entries.begin(); ASSERT_EQ(std::get<0>(*it).low, page_id); @@ -563,7 +563,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) ASSERT_EQ(std::get<1>(*it).sequence, 4); ASSERT_SAME_ENTRY(std::get<2>(*it), entry_v4); }; - auto check_for_blob_id_3 = [&](const PageIdAndVersionedEntries & entries) { + auto check_for_blob_id_3 = [&](const u128::PageDirectoryTrait::GcEntries & entries) { auto it = entries.begin(); ASSERT_EQ(std::get<0>(*it).low, page_id); @@ -577,7 +577,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) }; { - std::map blob_entries; + u128::PageDirectoryTrait::GcEntriesMap blob_entries; PageSize total_size = entries.getEntriesByBlobIds({/*empty*/}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); ASSERT_EQ(blob_entries.size(), 0); @@ -585,7 +585,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) } { - std::map blob_entries; + u128::PageDirectoryTrait::GcEntriesMap blob_entries; const BlobFileId blob_id = 1; PageSize total_size = entries.getEntriesByBlobIds({blob_id}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); @@ -596,7 +596,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) } { - std::map blob_entries; + u128::PageDirectoryTrait::GcEntriesMap blob_entries; const BlobFileId blob_id = 2; PageSize total_size = entries.getEntriesByBlobIds({blob_id}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); @@ -607,7 +607,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) } { - std::map blob_entries; + u128::PageDirectoryTrait::GcEntriesMap blob_entries; const BlobFileId blob_id = 3; PageSize total_size = entries.getEntriesByBlobIds({blob_id}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); @@ -619,7 +619,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) // {1, 2} { - std::map blob_entries; + u128::PageDirectoryTrait::GcEntriesMap blob_entries; PageSize total_size = entries.getEntriesByBlobIds({1, 2}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); ASSERT_EQ(blob_entries.size(), 2); @@ -632,7 +632,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) // {2, 3} { - std::map blob_entries; + u128::PageDirectoryTrait::GcEntriesMap blob_entries; PageSize total_size = entries.getEntriesByBlobIds({3, 2}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); ASSERT_EQ(blob_entries.size(), 2); @@ -645,7 +645,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) // {1, 2, 3} { - std::map blob_entries; + u128::PageDirectoryTrait::GcEntriesMap blob_entries; PageSize total_size = entries.getEntriesByBlobIds({1, 3, 2}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); ASSERT_EQ(blob_entries.size(), 3); @@ -660,7 +660,7 @@ TEST_F(VersionedEntriesTest, getEntriesByBlobId) // {1, 2, 3, 100}; blob_id 100 is not exist in actual { - std::map blob_entries; + u128::PageDirectoryTrait::GcEntriesMap blob_entries; PageSize total_size = entries.getEntriesByBlobIds({1, 3, 2, 4}, buildV3Id(TEST_NAMESPACE_ID, page_id), blob_entries); ASSERT_EQ(blob_entries.size(), 3); // 100 not exist diff --git a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp index f85c905520f..a629d6ad9b1 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp @@ -38,20 +38,25 @@ TEST(WALSeriTest, AllPuts) PageEntryV3 entry_p1{.file_id = 1, .size = 1, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry_p2{.file_id = 1, .size = 2, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageVersion ver20(/*seq=*/20); - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_p1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_p2); for (auto & rec : edit.getMutRecords()) rec.version = ver20; - auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); + auto deseri_edit = u128::Serializer::deserializeFrom(u128::Serializer::serializeTo(edit)); ASSERT_EQ(deseri_edit.size(), 2); auto iter = deseri_edit.getRecords().begin(); EXPECT_EQ(iter->type, EditRecordType::PUT); EXPECT_EQ(iter->page_id.low, 1); EXPECT_EQ(iter->version, ver20); EXPECT_SAME_ENTRY(iter->entry, entry_p1); + ++iter; + EXPECT_EQ(iter->type, EditRecordType::PUT); + EXPECT_EQ(iter->page_id.low, 2); + EXPECT_EQ(iter->version, ver20); + EXPECT_SAME_ENTRY(iter->entry, entry_p2); } TEST(WALSeriTest, PutsAndRefsAndDels) @@ -60,7 +65,7 @@ try PageEntryV3 entry_p3{.file_id = 1, .size = 3, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageEntryV3 entry_p5{.file_id = 1, .size = 5, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageVersion ver21(/*seq=*/21); - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry_p3); edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_p5); @@ -71,7 +76,7 @@ try for (auto & rec : edit.getMutRecords()) rec.version = ver21; - auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); + auto deseri_edit = u128::Serializer::deserializeFrom(u128::Serializer::serializeTo(edit)); ASSERT_EQ(deseri_edit.size(), 6); auto iter = deseri_edit.getRecords().begin(); EXPECT_EQ(iter->type, EditRecordType::PUT); @@ -110,12 +115,12 @@ TEST(WALSeriTest, Upserts) PageEntryV3 entry_p5_2{.file_id = 2, .size = 5, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageVersion ver20_1(/*seq=*/20, /*epoch*/ 1); PageVersion ver21_1(/*seq=*/21, /*epoch*/ 1); - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 1), ver20_1, entry_p1_2); edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 3), ver21_1, entry_p3_2); edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 5), ver21_1, entry_p5_2); - auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); + auto deseri_edit = u128::Serializer::deserializeFrom(u128::Serializer::serializeTo(edit)); ASSERT_EQ(deseri_edit.size(), 3); auto iter = deseri_edit.getRecords().begin(); EXPECT_EQ(iter->type, EditRecordType::UPSERT); @@ -140,12 +145,12 @@ TEST(WALSeriTest, RefExternalAndEntry) PageVersion ver2_0(/*seq=*/2, /*epoch*/ 0); PageVersion ver3_0(/*seq=*/3, /*epoch*/ 0); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.varExternal(buildV3Id(TEST_NAMESPACE_ID, 1), ver1_0, 2); edit.varDel(buildV3Id(TEST_NAMESPACE_ID, 1), ver2_0); edit.varRef(buildV3Id(TEST_NAMESPACE_ID, 2), ver3_0, buildV3Id(TEST_NAMESPACE_ID, 1)); - auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); + auto deseri_edit = u128::Serializer::deserializeFrom(u128::Serializer::serializeTo(edit)); ASSERT_EQ(deseri_edit.size(), 3); auto iter = deseri_edit.getRecords().begin(); EXPECT_EQ(iter->type, EditRecordType::VAR_EXTERNAL); @@ -164,13 +169,13 @@ TEST(WALSeriTest, RefExternalAndEntry) } { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; PageEntryV3 entry_p1_2{.file_id = 2, .size = 1, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; edit.varEntry(buildV3Id(TEST_NAMESPACE_ID, 1), ver1_0, entry_p1_2, 2); edit.varDel(buildV3Id(TEST_NAMESPACE_ID, 1), ver2_0); edit.varRef(buildV3Id(TEST_NAMESPACE_ID, 2), ver3_0, buildV3Id(TEST_NAMESPACE_ID, 1)); - auto deseri_edit = DB::PS::V3::ser::deserializeFrom(DB::PS::V3::ser::serializeTo(edit)); + auto deseri_edit = u128::Serializer::deserializeFrom(u128::Serializer::serializeTo(edit)); ASSERT_EQ(deseri_edit.size(), 3); auto iter = deseri_edit.getRecords().begin(); EXPECT_EQ(iter->type, EditRecordType::VAR_ENTRY); @@ -189,6 +194,33 @@ TEST(WALSeriTest, RefExternalAndEntry) } } +// TODO: more tests about universal seri/deseri +TEST(WALUinversalSeriTest, AllPuts) +{ + PageEntryV3 entry_p1{.file_id = 1, .size = 1, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; + PageEntryV3 entry_p2{.file_id = 1, .size = 2, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; + PageVersion ver20(/*seq=*/20); + universal::PageEntriesEdit edit; + edit.put("1", entry_p1); + edit.put("2", entry_p2); + + for (auto & rec : edit.getMutRecords()) + rec.version = ver20; + + auto deseri_edit = universal::Serializer::deserializeFrom(universal::Serializer::serializeTo(edit)); + ASSERT_EQ(deseri_edit.size(), 2); + auto iter = deseri_edit.getRecords().begin(); + EXPECT_EQ(iter->type, EditRecordType::PUT); + EXPECT_EQ(iter->page_id, "1"); + EXPECT_EQ(iter->version, ver20); + EXPECT_SAME_ENTRY(iter->entry, entry_p1); + ++iter; + EXPECT_EQ(iter->type, EditRecordType::PUT); + EXPECT_EQ(iter->page_id, "2"); + EXPECT_EQ(iter->version, ver20); + EXPECT_SAME_ENTRY(iter->entry, entry_p2); +} + TEST(WALLognameTest, parsing) { LoggerPtr log = Logger::get("WALLognameTest"); @@ -303,13 +335,13 @@ class WALStoreTest } protected: - static void applyWithSameVersion(WALStorePtr & wal, PageEntriesEdit & edit, const PageVersion & version) + static void applyWithSameVersion(WALStorePtr & wal, u128::PageEntriesEdit & edit, const PageVersion & version) { for (auto & r : edit.getMutRecords()) { r.version = version; } - wal->apply(ser::serializeTo(edit)); + wal->apply(u128::Serializer::serializeTo(edit)); } private: @@ -419,7 +451,7 @@ try PageEntryV3 entry_p2{.file_id = 1, .size = 2, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageVersion ver20(/*seq=*/20); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_p1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_p2); size_each_edit.emplace_back(edit.size()); @@ -438,7 +470,7 @@ try if (!record) break; // Details of each edit is verified in `WALSeriTest` - auto edit = ser::deserializeFrom(record.value()); + auto edit = u128::Serializer::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()); num_applied_edit += 1; } @@ -450,7 +482,7 @@ try PageEntryV3 entry_p5{.file_id = 1, .size = 5, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageVersion ver21(/*seq=*/21); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry_p3); edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_p5); @@ -471,7 +503,7 @@ try if (!record) break; // Details of each edit is verified in `WALSeriTest` - auto edit = ser::deserializeFrom(record.value()); + auto edit = u128::Serializer::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()); num_applied_edit += 1; } @@ -486,12 +518,12 @@ try PageVersion ver20_1(/*seq=*/20, /*epoch*/ 1); PageVersion ver21_1(/*seq=*/21, /*epoch*/ 1); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 1), ver20_1, entry_p1_2); edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 3), ver21_1, entry_p3_2); edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 5), ver21_1, entry_p5_2); size_each_edit.emplace_back(edit.size()); - wal->apply(ser::serializeTo(edit)); + wal->apply(u128::Serializer::serializeTo(edit)); } wal.reset(); @@ -506,7 +538,7 @@ try if (!record) break; // Details of each edit is verified in `WALSeriTest` - auto edit = ser::deserializeFrom(record.value()); + auto edit = u128::Serializer::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()); num_applied_edit += 1; } @@ -531,7 +563,7 @@ try PageEntryV3 entry_p2{.file_id = 1, .size = 2, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageVersion ver20(/*seq=*/20); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 1), entry_p1); edit.put(buildV3Id(TEST_NAMESPACE_ID, 2), entry_p2); size_each_edit.emplace_back(edit.size()); @@ -543,7 +575,7 @@ try PageEntryV3 entry_p5{.file_id = 1, .size = 5, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; PageVersion ver21(/*seq=*/21); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.put(buildV3Id(TEST_NAMESPACE_ID, 3), entry_p3); edit.ref(buildV3Id(TEST_NAMESPACE_ID, 4), buildV3Id(TEST_NAMESPACE_ID, 3)); edit.put(buildV3Id(TEST_NAMESPACE_ID, 5), entry_p5); @@ -559,12 +591,12 @@ try PageVersion ver20_1(/*seq=*/20, /*epoch*/ 1); PageVersion ver21_1(/*seq=*/21, /*epoch*/ 1); { - PageEntriesEdit edit; + u128::PageEntriesEdit edit; edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 1), ver20_1, entry_p1_2); edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 3), ver21_1, entry_p3_2); edit.upsertPage(buildV3Id(TEST_NAMESPACE_ID, 5), ver21_1, entry_p5_2); size_each_edit.emplace_back(edit.size()); - wal->apply(ser::serializeTo(edit)); + wal->apply(u128::Serializer::serializeTo(edit)); } wal.reset(); @@ -578,7 +610,7 @@ try if (!record) break; // Details of each edit is verified in `WALSeriTest` - auto edit = ser::deserializeFrom(record.value()); + auto edit = u128::Serializer::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()) << fmt::format("edit size not match at idx={}", num_applied_edit); num_applied_edit += 1; } @@ -598,7 +630,7 @@ try break; } // Details of each edit is verified in `WALSeriTest` - auto edit = ser::deserializeFrom(record.value()); + auto edit = u128::Serializer::deserializeFrom(record.value()); EXPECT_EQ(size_each_edit[num_applied_edit], edit.size()) << fmt::format("edit size not match at idx={}", num_applied_edit); num_applied_edit += 1; } @@ -631,7 +663,7 @@ try for (size_t i = 0; i < num_edits_test; ++i) { PageEntryV3 entry{.file_id = 2, .size = 1, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; - PageEntriesEdit edit; + u128::PageEntriesEdit edit; const size_t num_pages_put = d_20(rd); for (size_t p = 0; p < num_pages_put; ++p) { @@ -659,7 +691,7 @@ try // else it just run to the end of file. break; } - auto edit = ser::deserializeFrom(record.value()); + auto edit = u128::Serializer::deserializeFrom(record.value()); num_pages_read += edit.size(); EXPECT_EQ(size_each_edit[num_edits_read], edit.size()) << fmt::format("at idx={}", num_edits_read); num_edits_read += 1; @@ -675,7 +707,7 @@ try WALStore::FilesSnapshot file_snap{.current_writing_log_num = 100, // just a fake value .persisted_log_files = persisted_log_files}; - PageEntriesEdit snap_edit; + u128::PageEntriesEdit snap_edit; PageEntryV3 entry{.file_id = 2, .size = 1, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; std::uniform_int_distribution<> d_10000(0, 10000); // just fill in some random entry @@ -684,7 +716,7 @@ try snap_edit.varEntry(buildV3Id(TEST_NAMESPACE_ID, d_10000(rd)), PageVersion(345, 22), entry, 1); } std::tie(wal, reader) = WALStore::create(getCurrentTestName(), enc_provider, delegator, config); - bool done = wal->saveSnapshot(std::move(file_snap), ser::serializeTo(snap_edit), snap_edit.size()); + bool done = wal->saveSnapshot(std::move(file_snap), u128::Serializer::serializeTo(snap_edit), snap_edit.size()); ASSERT_TRUE(done); wal.reset(); reader.reset(); @@ -702,7 +734,7 @@ try // else it just run to the end of file. break; } - auto edit = ser::deserializeFrom(record.value()); + auto edit = u128::Serializer::deserializeFrom(record.value()); num_pages_read += edit.size(); num_edits_read += 1; } diff --git a/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp b/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp index 09a852c8b3b..bd270e53182 100644 --- a/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp +++ b/dbms/src/Storages/Page/tools/PageCtl/PageStorageCtlV3.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include + namespace DB::PS::V3 { extern "C" { @@ -148,7 +150,7 @@ class PageStorageControlV3 } else { - PageDirectory::MVCCMapType type; + PageDirectory::MVCCMapType type; CLIService service(getPageStorageV3Info, options, options.config_file_path, run_raftstore_proxy_ffi); service.run({""}); } @@ -188,7 +190,7 @@ class PageStorageControlV3 PageStorageConfig config; PageStorageImpl ps_v3("PageStorageControlV3", delegator, config, file_provider_ptr); ps_v3.restore(); - PageDirectory::MVCCMapType & mvcc_table_directory = ps_v3.page_directory->mvcc_table_directory; + PageDirectory::MVCCMapType & mvcc_table_directory = ps_v3.page_directory->mvcc_table_directory; switch (options.display_mode) { @@ -226,7 +228,7 @@ class PageStorageControlV3 return 0; } - static String getBlobsInfo(BlobStore & blob_store, UInt32 blob_id) + static String getBlobsInfo(BlobStore & blob_store, UInt32 blob_id) { auto stat_info = [](const BlobStats::BlobStatPtr & stat, const String & path) { FmtBuffer stat_str; @@ -276,9 +278,9 @@ class PageStorageControlV3 return stats_info.toString(); } - static String getDirectoryInfo(PageDirectory::MVCCMapType & mvcc_table_directory, UInt64 ns_id, UInt64 page_id) + static String getDirectoryInfo(PageDirectory::MVCCMapType & mvcc_table_directory, UInt64 ns_id, UInt64 page_id) { - auto page_info = [](UInt128 page_internal_id_, const VersionedPageEntriesPtr & versioned_entries) { + auto page_info = [](UInt128 page_internal_id_, const PageDirectory::VersionedPageEntriesPtr & versioned_entries) { FmtBuffer page_str; page_str.fmtAppend(" page id {}\n", page_internal_id_); page_str.fmtAppend(" {}\n", versioned_entries->toDebugString()); @@ -341,10 +343,10 @@ class PageStorageControlV3 return directory_info.toString(); } - static String getSummaryInfo(PageDirectory::MVCCMapType & mvcc_table_directory, BlobStore & blob_store) + static String getSummaryInfo(PageDirectory::MVCCMapType & mvcc_table_directory, BlobStore & blob_store) { - UInt64 longest_version_chaim = 0; - UInt64 shortest_version_chaim = UINT64_MAX; + UInt64 longest_version_chain = 0; + UInt64 shortest_version_chain = UINT64_MAX; FmtBuffer dir_summary_info; dir_summary_info.append(" Directory summary info: \n"); @@ -352,14 +354,14 @@ class PageStorageControlV3 for (const auto & [internal_id, versioned_entries] : mvcc_table_directory) { (void)internal_id; - longest_version_chaim = std::max(longest_version_chaim, versioned_entries->size()); - shortest_version_chaim = std::min(shortest_version_chaim, versioned_entries->size()); + longest_version_chain = std::max(longest_version_chain, versioned_entries->size()); + shortest_version_chain = std::min(shortest_version_chain, versioned_entries->size()); } - dir_summary_info.fmtAppend(" total pages: {}, longest version chaim: {} , shortest version chaim: {} \n\n", + dir_summary_info.fmtAppend(" total pages: {}, longest version chain: {} , shortest version chain: {} \n\n", mvcc_table_directory.size(), - longest_version_chaim, - shortest_version_chaim); + longest_version_chain, + shortest_version_chain); dir_summary_info.append(" Blobs summary info: \n"); const auto & blob_stats = blob_store.blob_stats.getStats(); @@ -388,7 +390,7 @@ class PageStorageControlV3 return dir_summary_info.toString(); } - static String checkSinglePage(PageDirectory::MVCCMapType & mvcc_table_directory, BlobStore & blob_store, UInt64 ns_id, UInt64 page_id) + static String checkSinglePage(PageDirectory::MVCCMapType & mvcc_table_directory, BlobStore & blob_store, UInt64 ns_id, UInt64 page_id) { const auto & page_internal_id = buildV3Id(ns_id, page_id); const auto & it = mvcc_table_directory.find(page_internal_id); @@ -420,8 +422,8 @@ class PageStorageControlV3 DB::PageStorage::FieldIndices indices(entry.field_offsets.size()); std::iota(std::begin(indices), std::end(indices), 0); - BlobStore::FieldReadInfos infos; - BlobStore::FieldReadInfo info(page_internal_id, entry, indices); + u128::BlobStoreTrait::FieldReadInfos infos; + u128::BlobStoreTrait::FieldReadInfo info(page_internal_id, entry, indices); infos.emplace_back(info); blob_store.read(infos); } @@ -444,12 +446,12 @@ class PageStorageControlV3 return error_msg.toString(); } - static String checkAllDataCrc(PageDirectory::MVCCMapType & mvcc_table_directory, BlobStore & blob_store, bool enable_fo_check) + static String checkAllDataCrc(PageDirectory::MVCCMapType & mvcc_table_directory, BlobStore & blob_store, bool enable_fo_check) { size_t total_pages = mvcc_table_directory.size(); size_t cut_index = 0; size_t index = 0; - std::cout << fmt::format("Begin to check all of datas CRC. enable_fo_check={}", static_cast(enable_fo_check)) << std::endl; + std::cout << fmt::format("Begin to check all of data CRC. enable_fo_check={}", static_cast(enable_fo_check)) << std::endl; std::list> error_versioned_pages; for (const auto & [internal_id, versioned_entries] : mvcc_table_directory) @@ -482,8 +484,8 @@ class PageStorageControlV3 DB::PageStorage::FieldIndices indices(entry.field_offsets.size()); std::iota(std::begin(indices), std::end(indices), 0); - BlobStore::FieldReadInfos infos; - BlobStore::FieldReadInfo info(internal_id, entry, indices); + u128::BlobStoreTrait::FieldReadInfos infos; + u128::BlobStoreTrait::FieldReadInfo info(internal_id, entry, indices); infos.emplace_back(info); blob_store.read(infos); } diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp new file mode 100644 index 00000000000..5bf9d37bea1 --- /dev/null +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp @@ -0,0 +1,50 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +namespace DB +{ + +UniversalPageStoragePtr UniversalPageStorage::create( + String name, + PSDiskDelegatorPtr delegator, + const UniversalPageStorage::Config & config, + const FileProviderPtr & file_provider) +{ + UniversalPageStoragePtr storage = std::make_shared(name, delegator, config, file_provider); + PS::V3::BlobConfig blob_config; // FIXME: parse from config + storage->blob_store = std::make_shared>( + name, + file_provider, + delegator, + blob_config); + return storage; +} + +void UniversalPageStorage::restore() +{ + blob_store->registerPaths(); + + PS::V3::universal::PageDirectoryFactory factory; + PS::V3::WALConfig wal_config; // FIXME: parse from config + page_directory = factory.setBlobStore(*blob_store).create(storage_name, file_provider, delegator, wal_config); +} + +} // namespace DB From 913be727c89e1762eea567697ef39d94bd730b49 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 12 Oct 2022 19:24:30 +0800 Subject: [PATCH 07/40] Add UniversalWriteBatch::merge Signed-off-by: JaySon-Huang --- dbms/src/Storages/Page/UniversalWriteBatch.h | 11 +- .../Page/universal/UniversalPageStorage.cpp | 12 +- .../{ => universal}/UniversalPageStorage.h | 12 +- .../universal/tests/gtest_page_storage.cpp | 107 ++++++++++++++++++ 4 files changed, 129 insertions(+), 13 deletions(-) rename dbms/src/Storages/Page/{ => universal}/UniversalPageStorage.h (96%) create mode 100644 dbms/src/Storages/Page/universal/tests/gtest_page_storage.cpp diff --git a/dbms/src/Storages/Page/UniversalWriteBatch.h b/dbms/src/Storages/Page/UniversalWriteBatch.h index ea8a2e9f11c..02b4d48b04f 100644 --- a/dbms/src/Storages/Page/UniversalWriteBatch.h +++ b/dbms/src/Storages/Page/UniversalWriteBatch.h @@ -133,6 +133,15 @@ class UniversalWriteBatch : private boost::noncopyable std::swap(o.total_data_size, total_data_size); } + void merge(UniversalWriteBatch & rhs) + { + writes.reserve(writes.size() + rhs.writes.size()); + for (const auto & r : rhs.writes) + { + writes.emplace_back(r); + } + } + void clear() { Writes tmp; @@ -145,7 +154,7 @@ class UniversalWriteBatch : private boost::noncopyable return total_data_size; } - static UniversalPageId getFullPageId(const UniversalPageId & id) { return id; } + static const UniversalPageId & getFullPageId(const UniversalPageId & id) { return id; } String toString() const { diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp index 5bf9d37bea1..cecefd96556 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include #include #include #include +#include namespace DB { @@ -25,16 +25,15 @@ namespace DB UniversalPageStoragePtr UniversalPageStorage::create( String name, PSDiskDelegatorPtr delegator, - const UniversalPageStorage::Config & config, + const PageStorageConfig & config, const FileProviderPtr & file_provider) { UniversalPageStoragePtr storage = std::make_shared(name, delegator, config, file_provider); - PS::V3::BlobConfig blob_config; // FIXME: parse from config storage->blob_store = std::make_shared>( name, file_provider, delegator, - blob_config); + PS::V3::BlobConfig::from(config)); return storage; } @@ -43,8 +42,9 @@ void UniversalPageStorage::restore() blob_store->registerPaths(); PS::V3::universal::PageDirectoryFactory factory; - PS::V3::WALConfig wal_config; // FIXME: parse from config - page_directory = factory.setBlobStore(*blob_store).create(storage_name, file_provider, delegator, wal_config); + page_directory = factory + .setBlobStore(*blob_store) + .create(storage_name, file_provider, delegator, PS::V3::WALConfig::from(config)); } } // namespace DB diff --git a/dbms/src/Storages/Page/UniversalPageStorage.h b/dbms/src/Storages/Page/universal/UniversalPageStorage.h similarity index 96% rename from dbms/src/Storages/Page/UniversalPageStorage.h rename to dbms/src/Storages/Page/universal/UniversalPageStorage.h index e5b1350d7e4..3fbf7cff68c 100644 --- a/dbms/src/Storages/Page/UniversalPageStorage.h +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.h @@ -14,6 +14,9 @@ #pragma once +#include +#include +#include #include #include #include @@ -47,22 +50,19 @@ class UniversalPageStorage final { public: using SnapshotPtr = PageStorageSnapshotPtr; - struct Config - { - }; public: static UniversalPageStoragePtr create( String name, PSDiskDelegatorPtr delegator, - const UniversalPageStorage::Config & config, + const PageStorageConfig & config, const FileProviderPtr & file_provider); UniversalPageStorage( String name, PSDiskDelegatorPtr delegator_, - const Config & config_, + const PageStorageConfig & config_, const FileProviderPtr & file_provider_) : storage_name(std::move(name)) , delegator(std::move(delegator_)) @@ -131,7 +131,7 @@ class UniversalPageStorage final String storage_name; // Identify between different Storage PSDiskDelegatorPtr delegator; // Get paths for storing data - Config config; + PageStorageConfig config; FileProviderPtr file_provider; PS::V3::universal::PageDirectoryPtr page_directory; diff --git a/dbms/src/Storages/Page/universal/tests/gtest_page_storage.cpp b/dbms/src/Storages/Page/universal/tests/gtest_page_storage.cpp new file mode 100644 index 00000000000..4ef9324fb88 --- /dev/null +++ b/dbms/src/Storages/Page/universal/tests/gtest_page_storage.cpp @@ -0,0 +1,107 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +namespace DB +{ +namespace PS::universal::tests +{ +class UniPageStorageTest : public DB::base::TiFlashStorageTestBasic +{ +public: + void SetUp() override + { + TiFlashStorageTestBasic::SetUp(); + auto path = getTemporaryPath(); + createIfNotExist(path); + file_provider = DB::tests::TiFlashTestEnv::getGlobalContext().getFileProvider(); + delegator = std::make_shared(path); + page_storage = UniversalPageStorage::create("test.t", delegator, config, file_provider); + page_storage->restore(); + + for (size_t i = 0; i < buf_sz; ++i) + { + c_buff[i] = i % 0xff; + } + + log = Logger::get("PageStorageTest"); + } + + std::shared_ptr reopenWithConfig(const PageStorageConfig & config_) + { + auto path = getTemporaryPath(); + delegator = std::make_shared(path); + auto storage = UniversalPageStorage::create("test.t", delegator, config_, file_provider); + storage->restore(); + return storage; + } + +protected: + FileProviderPtr file_provider; + PSDiskDelegatorPtr delegator; + PageStorageConfig config; + std::shared_ptr page_storage; + + LoggerPtr log; + + static constexpr size_t buf_sz = 1024; + char c_buff[buf_sz] = {}; +}; + +TEST_F(UniPageStorageTest, RaftLog) +{ + UInt64 tag = 0; + { + UniversalWriteBatch wb; + c_buff[0] = 10; + c_buff[1] = 1; + wb.putPage(RaftLogReader::toFullPageId(10, 1), tag, std::make_shared(c_buff, buf_sz), buf_sz); + c_buff[0] = 10; + c_buff[1] = 4; + wb.putPage(RaftLogReader::toFullPageId(10, 4), tag, std::make_shared(c_buff, buf_sz), buf_sz); + c_buff[0] = 10; + c_buff[1] = 5; + wb.putPage(RaftLogReader::toFullPageId(10, 5), tag, std::make_shared(c_buff, buf_sz), buf_sz); + c_buff[0] = 10; + c_buff[1] = 6; + wb.putPage(RaftLogReader::toFullPageId(10, 6), tag, std::make_shared(c_buff, buf_sz), buf_sz); + c_buff[0] = 10; + c_buff[1] = 7; + wb.putPage(RaftLogReader::toFullPageId(10, 7), tag, std::make_shared(c_buff, buf_sz), buf_sz); + c_buff[0] = 10; + c_buff[1] = 10; + wb.putPage(RaftLogReader::toFullPageId(10, 10), tag, std::make_shared(c_buff, buf_sz), buf_sz); + + c_buff[0] = 100; + c_buff[1] = 1; + wb.putPage(RaftLogReader::toFullPageId(100, 7), tag, std::make_shared(c_buff, buf_sz), buf_sz); + + wb.putPage(RaftLogReader::toFullPageId(255, 10), tag, std::make_shared(c_buff, buf_sz), buf_sz); + + page_storage->write(std::move(wb)); + } + + RaftLogReader raft_log_reader(*page_storage); + auto checker = [this](const DB::UniversalPage & page) { + LOG_INFO(log, "{}", page.page_id); + }; + raft_log_reader.traverse(RaftLogReader::toFullPageId(10, 0), RaftLogReader::toFullPageId(101, 0), checker); +} +} // namespace PS::universal::tests +} // namespace DB From 34a9c9662a5451a146e7a9382cb6f4b2318516fa Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Thu, 13 Oct 2022 14:12:57 +0800 Subject: [PATCH 08/40] Add example for read/write RaftLog Signed-off-by: JaySon-Huang --- dbms/src/Storages/Page/V3/PageDirectory.cpp | 19 ++++++- dbms/src/Storages/Page/V3/PageDirectory.h | 4 +- .../Page/V3/tests/gtest_page_storage.cpp | 2 - .../Page/universal/UniversalPageStorage.cpp | 8 +++ .../Page/universal/UniversalPageStorage.h | 54 ++++++++++++++++--- 5 files changed, 76 insertions(+), 11 deletions(-) diff --git a/dbms/src/Storages/Page/V3/PageDirectory.cpp b/dbms/src/Storages/Page/V3/PageDirectory.cpp index b22ce35cd82..3f09d33e3e8 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectory.cpp @@ -1056,8 +1056,8 @@ template typename Trait::PageIdSet PageDirectory::getAllPageIds() { typename Trait::PageIdSet page_ids; - std::shared_lock read_lock(table_rw_mutex); + std::shared_lock read_lock(table_rw_mutex); for (auto & [page_id, versioned] : mvcc_table_directory) { (void)versioned; @@ -1066,6 +1066,23 @@ typename Trait::PageIdSet PageDirectory::getAllPageIds() return page_ids; } +template +typename Trait::PageIdSet PageDirectory::getRangePageIds(const typename Trait::PageId & start, const typename Trait::PageId & end) +{ + typename Trait::PageIdSet page_ids; + + std::shared_lock read_lock(table_rw_mutex); + for (auto iter = mvcc_table_directory.lower_bound(start); + iter != mvcc_table_directory.end(); + ++iter) + { + if (iter->first >= end) + break; + page_ids.insert(iter->first); + } + return page_ids; +} + template void PageDirectory::applyRefEditRecord( MVCCMapType & mvcc_table_directory, diff --git a/dbms/src/Storages/Page/V3/PageDirectory.h b/dbms/src/Storages/Page/V3/PageDirectory.h index fd9db0c838f..7c58c21471c 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.h +++ b/dbms/src/Storages/Page/V3/PageDirectory.h @@ -152,7 +152,7 @@ class VersionedPageEntries , is_deleted(false) , create_ver(0) , delete_ver(0) - , ori_page_id(0) + , ori_page_id{} , being_ref_count(1) {} @@ -313,6 +313,8 @@ class PageDirectory typename Trait::PageIdSet getAllPageIds(); + typename Trait::PageIdSet getRangePageIds(const typename Trait::PageId & start, const typename Trait::PageId & end); + void apply(typename Trait::PageEntriesEdit && edit, const WriteLimiterPtr & write_limiter = nullptr); std::pair diff --git a/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp b/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp index 140a9b65173..2d4de975fdf 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp @@ -75,12 +75,10 @@ class PageStorageTest : public DB::base::TiFlashStorageTestBasic protected: FileProviderPtr file_provider; - std::unique_ptr path_pool; PSDiskDelegatorPtr delegator; PageStorageConfig config; std::shared_ptr page_storage; - std::list snapshots_holder; size_t fixed_test_buff_size = 1024; size_t epoch_offset = 0; diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp index cecefd96556..8a36aa63deb 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp @@ -47,4 +47,12 @@ void UniversalPageStorage::restore() .create(storage_name, file_provider, delegator, PS::V3::WALConfig::from(config)); } +void UniversalPageStorage::write(UniversalWriteBatch && write_batch, const WriteLimiterPtr & write_limiter) const +{ + if (unlikely(write_batch.empty())) + return; + + auto edit = blob_store->write(write_batch, write_limiter); + page_directory->apply(std::move(edit), write_limiter); +} } // namespace DB diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.h b/dbms/src/Storages/Page/universal/UniversalPageStorage.h index 3fbf7cff68c..e888ddcb5b3 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.h +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.h @@ -25,6 +25,7 @@ #include #include #include +#include #include namespace DB @@ -91,10 +92,7 @@ class UniversalPageStorage final return blob_store->getFileUsageStatistics(); } - void write(UniversalWriteBatch && write_batch, const WriteLimiterPtr & write_limiter = nullptr) - { - UNUSED(write_batch, write_limiter); - } + void write(UniversalWriteBatch && write_batch, const WriteLimiterPtr & write_limiter = nullptr) const; UniversalPageMap read(const UniversalPageId & page_ids, const ReadLimiterPtr & read_limiter = nullptr, SnapshotPtr snapshot = {}) { @@ -138,17 +136,23 @@ class UniversalPageStorage final PS::V3::universal::BlobStorePtr blob_store; }; -class KVStoreReader +class KVStoreReader final { public: - KVStoreReader(UniversalPageStorage & storage) + explicit KVStoreReader(UniversalPageStorage & storage) : uni_storage(storage) {} + static UniversalPageId toFullPageId(PageId page_id) + { + // TODO: Does it need to be mem comparable? + return fmt::format("k_{}", page_id); + } + bool isAppliedIndexExceed(PageId page_id, UInt64 applied_index) { // assume use this format - UniversalPageId uni_page_id = fmt::format("k_{}", page_id); + UniversalPageId uni_page_id = toFullPageId(page_id); auto snap = uni_storage.getSnapshot(""); const auto & [id, entry] = uni_storage.page_directory->getByIDOrNull(uni_page_id, snap); return (entry.isValid() && entry.tag > applied_index); @@ -164,4 +168,40 @@ class KVStoreReader UniversalPageStorage & uni_storage; }; +class RaftLogReader final +{ +public: + explicit RaftLogReader(UniversalPageStorage & storage) + : uni_storage(storage) + {} + + static UniversalPageId toFullPageId(NamespaceId ns_id, PageId page_id) + { + // TODO: Does it need to be mem comparable? + WriteBufferFromOwnString buff; + writeString("r_", buff); + RecordKVFormat::encodeUInt64(ns_id, buff); + writeString("_", buff); + RecordKVFormat::encodeUInt64(page_id, buff); + return buff.releaseStr(); + // return fmt::format("r_{}_{}", ns_id, page_id); + } + + // scan the pages between [start, end) + void traverse(const UniversalPageId & start, const UniversalPageId & end, const std::function & acceptor) + { + // always traverse with the latest snapshot + auto snapshot = uni_storage.getSnapshot(fmt::format("scan_r_{}_{}", start, end)); + const auto page_ids = uni_storage.page_directory->getRangePageIds(start, end); + for (const auto & page_id : page_ids) + { + const auto page_id_and_entry = uni_storage.page_directory->getByID(page_id, snapshot); + acceptor(uni_storage.blob_store->read(page_id_and_entry)); + } + } + +private: + UniversalPageStorage & uni_storage; +}; + } // namespace DB From 6842fe95230cd82c4172e541725908c899f2a64a Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Thu, 20 Oct 2022 16:19:52 +0800 Subject: [PATCH 09/40] Make PageWorkload work for uni --- .../Storages/Page/V3/PageDirectoryFactory.cpp | 4 +- .../Page/universal/UniversalPageStorage.h | 11 ++ .../Page/workload/HeavyMemoryCostInGC.h | 6 +- dbms/src/Storages/Page/workload/HeavyRead.h | 2 +- .../Page/workload/HighValidBigFileGC.h | 2 +- .../Page/workload/HoldSnapshotsLongTime.h | 4 +- dbms/src/Storages/Page/workload/Normal.h | 2 +- .../Storages/Page/workload/PSBackground.cpp | 13 +- .../src/Storages/Page/workload/PSBackground.h | 12 +- .../src/Storages/Page/workload/PSRunnable.cpp | 149 ++++++++++++------ dbms/src/Storages/Page/workload/PSRunnable.h | 40 +++-- .../Storages/Page/workload/PSStressEnv.cpp | 13 +- dbms/src/Storages/Page/workload/PSStressEnv.h | 11 +- .../src/Storages/Page/workload/PSWorkload.cpp | 56 ++++--- dbms/src/Storages/Page/workload/PSWorkload.h | 8 +- 15 files changed, 209 insertions(+), 124 deletions(-) diff --git a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp index b882f4789af..70df01b9d79 100644 --- a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp @@ -141,11 +141,11 @@ void PageDirectoryFactory::applyRecord( auto [iter, created] = dir->mvcc_table_directory.insert(std::make_pair(r.page_id, nullptr)); if (created) { - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { iter->second = std::make_shared>(); } - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) { iter->second = std::make_shared>(); } diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.h b/dbms/src/Storages/Page/universal/UniversalPageStorage.h index e888ddcb5b3..d4a1d6ced51 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.h +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.h @@ -158,6 +158,17 @@ class KVStoreReader final return (entry.isValid() && entry.tag > applied_index); } + void read(const PageIds & page_ids, std::function handler) const + { + UniversalPageIds uni_page_ids; + uni_page_ids.reserve(page_ids.size()); + for (const auto & pid : page_ids) + uni_page_ids.emplace_back(toFullPageId(pid)); + auto snap = uni_storage.getSnapshot(""); + auto page_entries = uni_storage.page_directory->getByIDs(uni_page_ids, snap); + uni_storage.blob_store->read(page_entries, handler, nullptr); + } + void traverse(const std::function & /*acceptor*/) { // Only traverse pages with id prefix diff --git a/dbms/src/Storages/Page/workload/HeavyMemoryCostInGC.h b/dbms/src/Storages/Page/workload/HeavyMemoryCostInGC.h index 9bd2fd44a39..f9c98c090e3 100644 --- a/dbms/src/Storages/Page/workload/HeavyMemoryCostInGC.h +++ b/dbms/src/Storages/Page/workload/HeavyMemoryCostInGC.h @@ -66,7 +66,7 @@ class HeavyMemoryCostInGC pool.joinAll(); stop_watch.stop(); - gc = std::make_shared(ps); + gc = std::make_shared(ps, uni_ps); gc->doGcOnce(); } @@ -78,7 +78,9 @@ class HeavyMemoryCostInGC void onFailed() override { LOG_WARNING(StressEnv::logger, - fmt::format("Memory Peak is {} , it should not bigger than {} ", metrics_dumper->getMemoryPeak(), 5 * 1024 * 1024)); + "Memory Peak is {} , it should not bigger than {} ", + metrics_dumper->getMemoryPeak(), + 5 * 1024 * 1024); } }; } // namespace DB::PS::tests diff --git a/dbms/src/Storages/Page/workload/HeavyRead.h b/dbms/src/Storages/Page/workload/HeavyRead.h index 79101605ce1..ad8c4451a00 100644 --- a/dbms/src/Storages/Page/workload/HeavyRead.h +++ b/dbms/src/Storages/Page/workload/HeavyRead.h @@ -50,7 +50,7 @@ class HeavyRead : public StressWorkload { DB::PageStorageConfig config; initPageStorage(config, name()); - PSWriter::fillAllPages(ps); + PSWriter::fillAllPages(ps, uni_ps); metrics_dumper = std::make_shared(1); metrics_dumper->start(); diff --git a/dbms/src/Storages/Page/workload/HighValidBigFileGC.h b/dbms/src/Storages/Page/workload/HighValidBigFileGC.h index 87405b0ef3f..28e2cb8e6b8 100644 --- a/dbms/src/Storages/Page/workload/HighValidBigFileGC.h +++ b/dbms/src/Storages/Page/workload/HighValidBigFileGC.h @@ -96,7 +96,7 @@ class HighValidBigFileGCWorkload onDumpResult(); } - gc = std::make_shared(ps); + gc = std::make_shared(ps, uni_ps); gc->doGcOnce(); gc_time_ms = gc->getElapsedMilliseconds(); { diff --git a/dbms/src/Storages/Page/workload/HoldSnapshotsLongTime.h b/dbms/src/Storages/Page/workload/HoldSnapshotsLongTime.h index 81816f72375..40b30adbee1 100644 --- a/dbms/src/Storages/Page/workload/HoldSnapshotsLongTime.h +++ b/dbms/src/Storages/Page/workload/HoldSnapshotsLongTime.h @@ -58,7 +58,7 @@ class HoldSnapshotsLongTime : public StressWorkload stress_time = std::make_shared(60); stress_time->start(); - scanner = std::make_shared(ps); + scanner = std::make_shared(ps, uni_ps); scanner->start(); // 90-100 snapshots will be generated. @@ -79,7 +79,7 @@ class HoldSnapshotsLongTime : public StressWorkload stop_watch.stop(); } - gc = std::make_shared(ps); + gc = std::make_shared(ps, uni_ps); // Normal GC gc->doGcOnce(); diff --git a/dbms/src/Storages/Page/workload/Normal.h b/dbms/src/Storages/Page/workload/Normal.h index 033f226bf89..feaf76dc097 100644 --- a/dbms/src/Storages/Page/workload/Normal.h +++ b/dbms/src/Storages/Page/workload/Normal.h @@ -56,7 +56,7 @@ class NormalWorkload // init all pages in PageStorage if (options.init_pages || options.just_init_pages) { - PSWriter::fillAllPages(ps); + PSWriter::fillAllPages(ps, uni_ps); LOG_INFO(StressEnv::logger, "All pages have been init."); if (options.just_init_pages) { diff --git a/dbms/src/Storages/Page/workload/PSBackground.cpp b/dbms/src/Storages/Page/workload/PSBackground.cpp index 39ed7476c6b..60c3613dc16 100644 --- a/dbms/src/Storages/Page/workload/PSBackground.cpp +++ b/dbms/src/Storages/Page/workload/PSBackground.cpp @@ -18,6 +18,8 @@ #include #include +#include "Storages/Page/Snapshot.h" + namespace DB::PS::tests { @@ -54,7 +56,10 @@ void PSGc::doGcOnce() auto tracker = MemoryTracker::create(); tracker->setDescription("(Stress Test GC)"); current_memory_tracker = tracker.get(); - ps->gc(); + if (ps) + ps->gc(); + else + uni_ps->gc(); current_memory_tracker = nullptr; } catch (...) @@ -76,7 +81,11 @@ void PSScanner::onTime(Poco::Timer & /*timer*/) try { LOG_FMT_INFO(StressEnv::logger, "Scanner start"); - auto stat = ps->getSnapshotsStat(); + SnapshotsStatistics stat; + if (ps) + stat = ps->getSnapshotsStat(); + else + stat = uni_ps->getSnapshotsStat(); LOG_FMT_INFO( StressEnv::logger, "Scanner get {} snapshots, longest lifetime: {:.3f}s longest from thread: {}, tracing_id: {}", diff --git a/dbms/src/Storages/Page/workload/PSBackground.h b/dbms/src/Storages/Page/workload/PSBackground.h index c91dad1361f..c393ef933ce 100644 --- a/dbms/src/Storages/Page/workload/PSBackground.h +++ b/dbms/src/Storages/Page/workload/PSBackground.h @@ -97,12 +97,14 @@ using PSMetricsDumperPtr = std::shared_ptr; class PSGc { PSPtr ps; + UniPSPtr uni_ps; public: - explicit PSGc(const PSPtr & ps_) + explicit PSGc(const PSPtr & ps_, const UniPSPtr & uni_ps_) : ps(ps_) + , uni_ps(uni_ps_) { - assert(ps != nullptr); + assert(ps != nullptr || uni_ps != nullptr); gc_timer.setStartInterval(1000); gc_timer.setPeriodicInterval(30 * 1000); } @@ -127,12 +129,14 @@ using PSGcPtr = std::shared_ptr; class PSScanner { PSPtr ps; + UniPSPtr uni_ps; public: - explicit PSScanner(const PSPtr & ps_) + explicit PSScanner(const PSPtr & ps_, const UniPSPtr & uni_ps_) : ps(ps_) + , uni_ps(uni_ps_) { - assert(ps != nullptr); + assert(ps != nullptr || uni_ps != nullptr); scanner_timer.setStartInterval(1000); scanner_timer.setPeriodicInterval(30 * 1000); diff --git a/dbms/src/Storages/Page/workload/PSRunnable.cpp b/dbms/src/Storages/Page/workload/PSRunnable.cpp index 545e40d46a6..9ab07ef76b3 100644 --- a/dbms/src/Storages/Page/workload/PSRunnable.cpp +++ b/dbms/src/Storages/Page/workload/PSRunnable.cpp @@ -18,14 +18,25 @@ #include #include #include +#include +#include +#include #include +#include #include #include +#include #include +#include "Storages/Page/PageDefines.h" +#include "Storages/Page/UniversalPage.h" + namespace DB::PS::tests { + +using UniReader = KVStoreReader; + void PSRunnable::run() try { @@ -56,6 +67,8 @@ size_t PSRunnable::getPagesUsed() const return pages_used; } +/// PSWriter /// + size_t PSWriter::approx_page_mb = 2; void PSWriter::setApproxPageSize(size_t size_mb) { @@ -72,10 +85,6 @@ DB::ReadBufferPtr PSWriter::genRandomData(const DB::PageId pageId, DB::MemHolder const size_t buff_sz = approx_page_mb * DB::MB + dist(size_gen); char * buff = static_cast(malloc(buff_sz)); // NOLINT - if (buff == nullptr) - { - throw DB::Exception("Alloc fix memory failed.", DB::ErrorCodes::LOGICAL_ERROR); - } const char buff_ch = pageId % 0xFF; memset(buff, buff_ch, buff_sz); @@ -90,32 +99,37 @@ void PSWriter::updatedRandomData() size_t memory_size = approx_page_mb * DB::MB * 2; if (memory == nullptr) { - memory = static_cast(malloc(memory_size)); // NOLINT - if (memory == nullptr) - { - throw DB::Exception("Alloc fix memory failed.", DB::ErrorCodes::LOGICAL_ERROR); - } + memory.reset(new char[memory_size]); for (size_t i = 0; i < memory_size; i++) { - memset(memory + i, i % 0xFF, sizeof(char)); + memory[i] = i % 0xFF; } } std::uniform_int_distribution<> dist(0, memory_size / 2 - 1); size_t gen_size = dist(gen); - buff_ptr = std::make_shared(memory + gen_size, memory_size - gen_size); + buff_ptr = std::make_shared(memory.get() + gen_size, memory_size - gen_size); } -void PSWriter::fillAllPages(const PSPtr & ps) +void PSWriter::fillAllPages(const PSPtr & ps, const UniPSPtr & uni_ps) { for (DB::PageId page_id = 0; page_id <= MAX_PAGE_ID_DEFAULT; ++page_id) { DB::MemHolder holder; DB::ReadBufferPtr buff = genRandomData(page_id, holder); - DB::WriteBatch wb{DB::TEST_NAMESPACE_ID}; - wb.putPage(page_id, 0, buff, buff->buffer().size()); - ps->write(std::move(wb)); + if (ps) + { + DB::WriteBatch wb{DB::TEST_NAMESPACE_ID}; + wb.putPage(page_id, 0, buff, buff->buffer().size()); + ps->write(std::move(wb)); + } + else + { + DB::UniversalWriteBatch wb; + wb.putPage(UniReader::toFullPageId(page_id), 0, buff, buff->buffer().size()); + uni_ps->write(std::move(wb)); + } if (page_id % 100 == 0) LOG_FMT_INFO(StressEnv::logger, "writer wrote page {}", page_id); } @@ -126,9 +140,18 @@ bool PSWriter::runImpl() const DB::PageId page_id = genRandomPageId(); updatedRandomData(); - DB::WriteBatch wb{DB::TEST_NAMESPACE_ID}; - wb.putPage(page_id, 0, buff_ptr, buff_ptr->buffer().size()); - ps->write(std::move(wb)); + if (ps) + { + DB::WriteBatch wb{DB::TEST_NAMESPACE_ID}; + wb.putPage(page_id, 0, buff_ptr, buff_ptr->buffer().size()); + ps->write(std::move(wb)); + } + else + { + DB::UniversalWriteBatch wb; + wb.putPage(UniReader::toFullPageId(page_id), 0, buff_ptr, buff_ptr->buffer().size()); + uni_ps->write(std::move(wb)); + } ++pages_used; bytes_used += buff_ptr->buffer().size(); return true; @@ -140,6 +163,8 @@ DB::PageId PSWriter::genRandomPageId() return static_cast(std::round(distribution(gen))) % max_page_id; } +/// PSCommonWriter /// + void PSCommonWriter::updatedRandomData() { // Calculate the fixed memory size @@ -149,15 +174,10 @@ void PSCommonWriter::updatedRandomData() if (memory == nullptr) { - memory = static_cast(malloc(memory_size)); // NOLINT - if (memory == nullptr) - { - throw DB::Exception("Alloc fix memory failed.", DB::ErrorCodes::LOGICAL_ERROR); - } - + memory.reset(new char[memory_size]); for (size_t i = 0; i < memory_size; i++) { - memset(memory + i, i % 0xFF, sizeof(char)); + memory[i] = i % 0xFF; } } @@ -166,7 +186,7 @@ void PSCommonWriter::updatedRandomData() size_t gen_size = genBufferSize(); for (size_t i = 0; i < batch_buffer_nums; ++i) { - buff_ptrs.emplace_back(std::make_shared(memory + i * single_buff_size, gen_size)); + buff_ptrs.emplace_back(std::make_shared(memory.get() + i * single_buff_size, gen_size)); } } @@ -176,17 +196,31 @@ bool PSCommonWriter::runImpl() { const DB::PageId page_id = genRandomPageId(); - DB::WriteBatch wb{DB::TEST_NAMESPACE_ID}; updatedRandomData(); - - for (auto & buffptr : buff_ptrs) + if (ps) { - wb.putPage(page_id, 0, buffptr, buffptr->buffer().size()); - ++pages_used; - bytes_used += buffptr->buffer().size(); + DB::WriteBatch wb{DB::TEST_NAMESPACE_ID}; + for (auto & buffptr : buff_ptrs) + { + wb.putPage(page_id, 0, buffptr, buffptr->buffer().size()); + ++pages_used; + bytes_used += buffptr->buffer().size(); + } + + ps->write(std::move(wb)); } + else + { + DB::UniversalWriteBatch wb; + for (auto & buffptr : buff_ptrs) + { + wb.putPage(UniReader::toFullPageId(page_id), 0, buffptr, buffptr->buffer().size()); + ++pages_used; + bytes_used += buffptr->buffer().size(); + } - ps->write(std::move(wb)); + uni_ps->write(std::move(wb)); + } return (batch_buffer_limit == 0 || bytes_used < batch_buffer_limit); } @@ -241,6 +275,7 @@ size_t PSCommonWriter::genBufferSize() return batch_buffer_size; } +/// PSReader /// DB::PageIds PSReader::genRandomPageIds() { @@ -257,17 +292,30 @@ bool PSReader::runImpl() { DB::PageIds page_ids = genRandomPageIds(); - DB::PageHandler handler = [&](DB::PageId page_id, const DB::Page & page) { - (void)page_id; - // use `sleep` to mock heavy read - if (heavy_read_delay_ms > 0) - { - usleep(heavy_read_delay_ms * 1000); - } - ++pages_used; - bytes_used += page.data.size(); - }; - ps->read(DB::TEST_NAMESPACE_ID, page_ids, handler); + if (ps) + { + DB::PageHandler handler = [&](DB::PageId, const DB::Page & page) { + // use `sleep` to mock heavy read + if (heavy_read_delay_ms > 0) + { + usleep(heavy_read_delay_ms * 1000); + } + ++pages_used; + bytes_used += page.data.size(); + }; + ps->read(DB::TEST_NAMESPACE_ID, page_ids, handler); + } + else + { + auto handler = [&](const PageId &, const UniversalPage & page) { + if (heavy_read_delay_ms > 0) + usleep(heavy_read_delay_ms * 1000); + ++pages_used; + bytes_used += page.data.size(); + }; + UniReader reader(*uni_ps); + reader.read(page_ids, handler); + } return true; } @@ -291,6 +339,8 @@ void PSReader::setReadPageNums(size_t page_read_once_) page_read_once = page_read_once_; } +/// PSWindowWriter /// + void PSWindowWriter::setWindowSize(size_t window_size_) { window_size = window_size_; @@ -390,9 +440,16 @@ DB::PageIds PSWindowReader::genRandomPageIds() return page_ids; } +/// PSSnapshotReader /// + bool PSSnapshotReader::runImpl() { - snapshots.emplace_back(ps->getSnapshot("")); + PageStorageSnapshotPtr snap; + if (ps) + snap = ps->getSnapshot(""); + else + snap = uni_ps->getSnapshot(""); + snapshots.emplace_back(snap); usleep(snapshot_get_interval_ms * 1000); return true; } @@ -402,6 +459,8 @@ void PSSnapshotReader::setSnapshotGetIntervalMs(size_t snapshot_get_interval_ms_ snapshot_get_interval_ms = snapshot_get_interval_ms_; } +/// PSIncreaseWriter /// + bool PSIncreaseWriter::runImpl() { return PSCommonWriter::runImpl() && begin_page_id < end_page_id; diff --git a/dbms/src/Storages/Page/workload/PSRunnable.h b/dbms/src/Storages/Page/workload/PSRunnable.h index b723236391d..c47d1625616 100644 --- a/dbms/src/Storages/Page/workload/PSRunnable.h +++ b/dbms/src/Storages/Page/workload/PSRunnable.h @@ -41,20 +41,15 @@ class PSWriter : public PSRunnable static size_t approx_page_mb; public: - PSWriter(const PSPtr & ps_, DB::UInt32 index_) + PSWriter(const PSPtr & ps_, const UniPSPtr & uni_ps_, DB::UInt32 index_) : ps(ps_) + , uni_ps(uni_ps_) , index(index_) { gen.seed(time(nullptr)); } - ~PSWriter() override - { - if (memory != nullptr) - { - free(memory); - } - } + ~PSWriter() override = default; String description() override { @@ -67,7 +62,7 @@ class PSWriter : public PSRunnable virtual void updatedRandomData(); - static void fillAllPages(const PSPtr & ps); + static void fillAllPages(const PSPtr & ps, const UniPSPtr & uni_ps); bool runImpl() override; @@ -76,10 +71,11 @@ class PSWriter : public PSRunnable protected: PSPtr ps; + UniPSPtr uni_ps; DB::UInt32 index = 0; std::mt19937 gen; DB::PageId max_page_id = MAX_PAGE_ID_DEFAULT; - char * memory = nullptr; + std::shared_ptr memory; DB::ReadBufferPtr buff_ptr; }; @@ -89,8 +85,8 @@ class PSWriter : public PSRunnable class PSCommonWriter : public PSWriter { public: - PSCommonWriter(const PSPtr & ps_, DB::UInt32 index_) - : PSWriter(ps_, index_) + PSCommonWriter(const PSPtr & ps_, const UniPSPtr & uni_ps_, DB::UInt32 index_) + : PSWriter(ps_, uni_ps_, index_) {} void updatedRandomData() override; @@ -145,8 +141,8 @@ class PSCommonWriter : public PSWriter class PSWindowWriter : public PSCommonWriter { public: - PSWindowWriter(const PSPtr & ps_, DB::UInt32 index_) - : PSCommonWriter(ps_, index_) + PSWindowWriter(const PSPtr & ps_, const UniPSPtr & uni_ps_, DB::UInt32 index_) + : PSCommonWriter(ps_, uni_ps_, index_) {} String description() override { return fmt::format("(Stress Test Window Writer {})", index); } @@ -166,8 +162,8 @@ class PSWindowWriter : public PSCommonWriter class PSIncreaseWriter : public PSCommonWriter { public: - PSIncreaseWriter(const PSPtr & ps_, DB::UInt32 index_) - : PSCommonWriter(ps_, index_) + PSIncreaseWriter(const PSPtr & ps_, const UniPSPtr & uni_ps_, DB::UInt32 index_) + : PSCommonWriter(ps_, uni_ps_, index_) {} String description() override { return fmt::format("(Stress Test Increase Writer {})", index); } @@ -187,8 +183,9 @@ class PSIncreaseWriter : public PSCommonWriter class PSReader : public PSRunnable { public: - PSReader(const PSPtr & ps_, DB::UInt32 index_) + PSReader(const PSPtr & ps_, const UniPSPtr & uni_ps_, DB::UInt32 index_) : ps(ps_) + , uni_ps(uni_ps_) , index(index_) { gen.seed(time(nullptr)); @@ -211,6 +208,7 @@ class PSReader : public PSRunnable protected: PSPtr ps; + UniPSPtr uni_ps; std::mt19937 gen; size_t heavy_read_delay_ms = 0; size_t page_read_once = 5; @@ -233,8 +231,8 @@ class PSReader : public PSRunnable class PSWindowReader : public PSReader { public: - PSWindowReader(const PSPtr & ps_, DB::UInt32 index_) - : PSReader(ps_, index_) + PSWindowReader(const PSPtr & ps_, const UniPSPtr & uni_ps_, DB::UInt32 index_) + : PSReader(ps_, uni_ps_, index_) {} void setWindowSize(size_t window_size); @@ -259,8 +257,8 @@ class PSWindowReader : public PSReader class PSSnapshotReader : public PSReader { public: - PSSnapshotReader(const PSPtr & ps_, DB::UInt32 index_) - : PSReader(ps_, index_) + PSSnapshotReader(const PSPtr & ps_, const UniPSPtr & uni_ps_, DB::UInt32 index_) + : PSReader(ps_, uni_ps_, index_) {} bool runImpl() override; diff --git a/dbms/src/Storages/Page/workload/PSStressEnv.cpp b/dbms/src/Storages/Page/workload/PSStressEnv.cpp index f5cead0a158..27ee5a21216 100644 --- a/dbms/src/Storages/Page/workload/PSStressEnv.cpp +++ b/dbms/src/Storages/Page/workload/PSStressEnv.cpp @@ -30,7 +30,7 @@ namespace DB::PS::tests { -Poco::Logger * StressEnv::logger; +LoggerPtr StressEnv::logger; void StressEnv::initGlobalLogger() { Poco::AutoPtr channel = new Poco::ConsoleChannel(std::cerr); @@ -38,7 +38,7 @@ void StressEnv::initGlobalLogger() Poco::AutoPtr formatting_channel(new Poco::FormattingChannel(formatter, channel)); Poco::Logger::root().setChannel(formatting_channel); Poco::Logger::root().setLevel("trace"); - logger = &Poco::Logger::get("root"); + logger = Logger::get("root"); } StressEnv StressEnv::parse(int argc, char ** argv) @@ -89,9 +89,9 @@ StressEnv StressEnv::parse(int argc, char ** argv) opt.verify = options["verify"].as(); opt.running_ps_version = options["running_ps_version"].as(); - if (opt.running_ps_version != 2 && opt.running_ps_version != 3) + if (opt.running_ps_version != 2 && opt.running_ps_version != 3 && opt.running_ps_version != 4) { - std::cerr << "Invalid running_ps_version, this arg should be 2 or 3." << std::endl; + std::cerr << "Invalid running_ps_version, this arg should be 2/3/4" << std::endl; std::cerr << desc << std::endl; exit(0); } @@ -117,15 +117,14 @@ void setupSignal() void StressEnv::setup() { CurrentMemoryTracker::disableThreshold(); + #ifdef FIU_ENABLE fiu_init(0); -#endif - - for (const auto & fp : failpoints) { DB::FailPointHelper::enableFailPoint(fp); } +#endif // drop dir if exists bool all_directories_not_exist = true; diff --git a/dbms/src/Storages/Page/workload/PSStressEnv.h b/dbms/src/Storages/Page/workload/PSStressEnv.h index e67cb325430..64fb8a16021 100644 --- a/dbms/src/Storages/Page/workload/PSStressEnv.h +++ b/dbms/src/Storages/Page/workload/PSStressEnv.h @@ -16,18 +16,15 @@ #include #include +#include #include #include -namespace Poco -{ -class Logger; -} - namespace DB::PS::tests { using PSPtr = std::shared_ptr; +using UniPSPtr = std::shared_ptr; enum StressEnvStat { @@ -72,7 +69,7 @@ class StressEnvStatus struct StressEnv { - static Poco::Logger * logger; + static LoggerPtr logger; size_t num_writers = 1; size_t num_readers = 4; @@ -99,7 +96,7 @@ struct StressEnv ", clean_before_run: {}, timeout_s: {}, read_delay_ms: {}, num_writer_slots: {}" ", avg_page_size_mb: {}, paths: [{}], failpoints: [{}]" ", status_interval: {}, situation_mask: {}, verify: {}" - ", running_pagestorage_version : {}." + ", running_pagestorage_version: {}" "}}", num_writers, num_readers, diff --git a/dbms/src/Storages/Page/workload/PSWorkload.cpp b/dbms/src/Storages/Page/workload/PSWorkload.cpp index f9ff0b40c08..0d47119aa37 100644 --- a/dbms/src/Storages/Page/workload/PSWorkload.cpp +++ b/dbms/src/Storages/Page/workload/PSWorkload.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,12 +26,11 @@ namespace DB::PS::tests void StressWorkload::onDumpResult() { UInt64 time_interval = stop_watch.elapsedMilliseconds(); - LOG_INFO(options.logger, fmt::format("result in {}ms", time_interval)); + LOG_INFO(options.logger, "result in {}ms", time_interval); double seconds_run = 1.0 * time_interval / 1000; size_t total_pages_written = 0; size_t total_bytes_written = 0; - for (auto & writer : writers) { total_pages_written += writer->pages_used; @@ -39,7 +39,6 @@ void StressWorkload::onDumpResult() size_t total_pages_read = 0; size_t total_bytes_read = 0; - for (auto & reader : readers) { total_pages_read += reader->pages_used; @@ -47,17 +46,15 @@ void StressWorkload::onDumpResult() } LOG_INFO(options.logger, - fmt::format( - "W: {} pages, {:.4f} GB, {:.4f} GB/s", - total_pages_written, - static_cast(total_bytes_written) / DB::GB, - static_cast(total_bytes_written) / DB::GB / seconds_run)); + "W: {} pages, {:.4f} GB, {:.4f} GB/s", + total_pages_written, + static_cast(total_bytes_written) / DB::GB, + static_cast(total_bytes_written) / DB::GB / seconds_run); LOG_INFO(options.logger, - fmt::format( - "R: {} pages, {:.4f} GB, {:.4f} GB/s", - total_pages_read, - static_cast(total_bytes_read) / DB::GB, - static_cast(total_bytes_read) / DB::GB / seconds_run)); + "R: {} pages, {:.4f} GB, {:.4f} GB/s", + total_pages_read, + static_cast(total_bytes_read) / DB::GB, + static_cast(total_bytes_read) / DB::GB / seconds_run); if (options.status_interval != 0) { @@ -67,7 +64,7 @@ void StressWorkload::onDumpResult() void StressWorkload::initPageStorage(DB::PageStorageConfig & config, String path_prefix) { - DB::FileProviderPtr file_provider = std::make_shared(std::make_shared(false), false); + auto file_provider = std::make_shared(std::make_shared(false), false); if (path_prefix.empty()) { @@ -93,32 +90,39 @@ void StressWorkload::initPageStorage(DB::PageStorageConfig & config, String path { ps = std::make_shared("stress_test", delegator, config, file_provider); } + else if (options.running_ps_version == 4) + { + uni_ps = DB::UniversalPageStorage::create("stress_test", delegator, config, file_provider); + } else { throw DB::Exception(fmt::format("Invalid PageStorage version {}", options.running_ps_version)); } - ps->restore(); - + size_t num_of_pages = 0; + if (ps) { - size_t num_of_pages = 0; - ps->traverse([&num_of_pages](const DB::Page & page) { - (void)page; + ps->restore(); + ps->traverse([&num_of_pages](const DB::Page &) { num_of_pages++; }); - LOG_INFO(StressEnv::logger, fmt::format("Recover {} pages.", num_of_pages)); } + else + { + uni_ps->restore(); + } + LOG_INFO(StressEnv::logger, "Restore {} pages from disk", num_of_pages); } void StressWorkload::startBackgroundTimer() { // A background thread that do GC - gc = std::make_shared(ps); + gc = std::make_shared(ps, uni_ps); gc->start(); // A background thread that scan all pages - scanner = std::make_shared(ps); + scanner = std::make_shared(ps, uni_ps); scanner->start(); if (options.status_interval > 0) @@ -143,8 +147,8 @@ void StressWorkloadManger::runWorkload() String name; WorkloadCreator func; std::tie(name, func) = get(NORMAL_WORKLOAD); - auto workload = std::shared_ptr(func(options)); - LOG_INFO(StressEnv::logger, fmt::format("Start Running {} , {}", name, workload->desc())); + auto workload = func(options); + LOG_INFO(StressEnv::logger, "Start running workload {}, {}", name, workload->desc()); workload->run(); if (!options.just_init_pages) { @@ -164,11 +168,11 @@ void StressWorkloadManger::runWorkload() auto & name = it.second.first; auto & creator = it.second.second; auto workload = creator(options); - LOG_INFO(StressEnv::logger, fmt::format("Start Running {} , {}", name, workload->desc())); + LOG_INFO(StressEnv::logger, "Start Running {}, {}", name, workload->desc()); workload->run(); if (options.verify && !workload->verify()) { - LOG_WARNING(StressEnv::logger, fmt::format("work load : {} failed.", name)); + LOG_WARNING(StressEnv::logger, "work load: {} failed.", name); workload->onFailed(); break; } diff --git a/dbms/src/Storages/Page/workload/PSWorkload.h b/dbms/src/Storages/Page/workload/PSWorkload.h index 0c048227a4d..bdcd774e34c 100644 --- a/dbms/src/Storages/Page/workload/PSWorkload.h +++ b/dbms/src/Storages/Page/workload/PSWorkload.h @@ -75,7 +75,7 @@ class StressWorkload writers.clear(); for (size_t i = 0; i < nums_writers; ++i) { - auto writer = std::make_shared(ps, i); + auto writer = std::make_shared(ps, uni_ps, i); if (writer_configure) { writer_configure(writer); @@ -91,7 +91,7 @@ class StressWorkload readers.clear(); for (size_t i = 0; i < nums_readers; ++i) { - auto reader = std::make_shared(ps, i); + auto reader = std::make_shared(ps, uni_ps, i); if (reader_configure) { reader_configure(reader); @@ -105,9 +105,11 @@ class StressWorkload StressEnv options; Poco::ThreadPool pool; - PSPtr ps; DB::PSDiskDelegatorPtr delegator; + PSPtr ps; + UniPSPtr uni_ps; + std::list> writers; std::list> readers; From af946d728e679d5a15d58887b70f08ca3258cf1e Mon Sep 17 00:00:00 2001 From: lidezhu Date: Thu, 20 Oct 2022 21:15:25 +0800 Subject: [PATCH 10/40] alpha version --- dbms/src/Interpreters/Context.cpp | 19 +++ dbms/src/Interpreters/Context.h | 6 + dbms/src/Server/MetricsPrometheus.cpp | 83 +++++------ dbms/src/Server/Server.cpp | 3 + .../Page/universal/UniversalPageStorage.h | 15 ++ dbms/src/Storages/Transaction/ProxyFFI.cpp | 135 ++++++++++++++++++ dbms/src/Storages/Transaction/ProxyFFI.h | 21 +++ 7 files changed, 241 insertions(+), 41 deletions(-) diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index f1c04025bd1..539b09a2349 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -159,6 +160,7 @@ struct ContextShared IORateLimiter io_rate_limiter; PageStorageRunMode storage_run_mode = PageStorageRunMode::ONLY_V3; DM::GlobalStoragePoolPtr global_storage_pool; + UniversalPageStoragePtr uni_page_storage; /// Named sessions. The user could specify session identifier to reuse settings and temporary tables in subsequent requests. class SessionKeyHash @@ -1615,6 +1617,23 @@ DM::GlobalStoragePoolPtr Context::getGlobalStoragePool() const return shared->global_storage_pool; } +void Context::initializeGlobalUniversalPageStorage(const PathPool & path_pool, const FileProviderPtr & file_provider) +{ + auto lock = getLock(); + if (shared->uni_page_storage) + throw Exception("UniversalPageStorage has already been initialized.", ErrorCodes::LOGICAL_ERROR); + + shared->uni_page_storage = UniversalPageStorage::create("global", path_pool.getPSDiskDelegatorGlobalMulti("global"), {}, file_provider); + shared->uni_page_storage->restore(); + LOG_INFO(shared->log, "initialized GlobalUniversalPageStorage"); +} + +UniversalPageStoragePtr Context::getGlobalUniversalPageStorage() const +{ + auto lock = getLock(); + return shared->uni_page_storage; +} + UInt16 Context::getTCPPort() const { auto lock = getLock(); diff --git a/dbms/src/Interpreters/Context.h b/dbms/src/Interpreters/Context.h index 34fdc0536aa..d1a1ced9757 100644 --- a/dbms/src/Interpreters/Context.h +++ b/dbms/src/Interpreters/Context.h @@ -120,6 +120,9 @@ using Dependencies = std::vector; using TableAndCreateAST = std::pair; using TableAndCreateASTs = std::map; +class UniversalPageStorage; +using UniversalPageStoragePtr = std::shared_ptr; + /** A set of known objects that can be used in the query. * Consists of a shared part (always common to all sessions and queries) * and copied part (which can be its own for each session or query). @@ -421,6 +424,9 @@ class Context bool initializeGlobalStoragePoolIfNeed(const PathPool & path_pool); DM::GlobalStoragePoolPtr getGlobalStoragePool() const; + void initializeGlobalUniversalPageStorage(const PathPool & path_pool, const FileProviderPtr & file_provider); + UniversalPageStoragePtr getGlobalUniversalPageStorage() const; + /// Call after initialization before using system logs. Call for global context. void initializeSystemLogs(); diff --git a/dbms/src/Server/MetricsPrometheus.cpp b/dbms/src/Server/MetricsPrometheus.cpp index 3ec06885fad..92c32423796 100644 --- a/dbms/src/Server/MetricsPrometheus.cpp +++ b/dbms/src/Server/MetricsPrometheus.cpp @@ -233,47 +233,48 @@ MetricsPrometheus::~MetricsPrometheus() void MetricsPrometheus::run() { - auto & tiflash_metrics = TiFlashMetrics::instance(); - for (ProfileEvents::Event event = 0; event < ProfileEvents::end(); event++) - { - const auto value = ProfileEvents::counters[event].load(std::memory_order_relaxed); - tiflash_metrics.registered_profile_events[event]->Set(value); - } - - for (CurrentMetrics::Metric metric = 0; metric < CurrentMetrics::end(); metric++) - { - const auto value = CurrentMetrics::values[metric].load(std::memory_order_relaxed); - tiflash_metrics.registered_current_metrics[metric]->Set(value); - } - - auto async_metric_values = async_metrics.getValues(); - for (const auto & metric : async_metric_values) - { - const auto & origin_name = metric.first; - const auto & value = metric.second; - if (!tiflash_metrics.registered_async_metrics.count(origin_name)) - { - // Register this async metric into registry on flight, as async metrics are not accumulated at once. - auto prometheus_name = TiFlashMetrics::async_metrics_prefix + metric.first; - // Prometheus doesn't allow metric name containing dot. - std::replace(prometheus_name.begin(), prometheus_name.end(), '.', '_'); - auto & family = prometheus::BuildGauge() - .Name(prometheus_name) - .Help("System asynchronous metric " + prometheus_name) - .Register(*(tiflash_metrics.registry)); - // Use original name as key for the sake of further accesses. - tiflash_metrics.registered_async_metrics.emplace(origin_name, &family.Add({})); - } - tiflash_metrics.registered_async_metrics[origin_name]->Set(value); - } - - if (gateway != nullptr) - { - if (auto return_code = gateway->Push(); return_code != 200) - { - LOG_FMT_WARNING(log, "Failed to push metrics to gateway, return code is {}", return_code); - } - } + (void)async_metrics; +// auto & tiflash_metrics = TiFlashMetrics::instance(); +// for (ProfileEvents::Event event = 0; event < ProfileEvents::end(); event++) +// { +// const auto value = ProfileEvents::counters[event].load(std::memory_order_relaxed); +// tiflash_metrics.registered_profile_events[event]->Set(value); +// } +// +// for (CurrentMetrics::Metric metric = 0; metric < CurrentMetrics::end(); metric++) +// { +// const auto value = CurrentMetrics::values[metric].load(std::memory_order_relaxed); +// tiflash_metrics.registered_current_metrics[metric]->Set(value); +// } +// +// auto async_metric_values = async_metrics.getValues(); +// for (const auto & metric : async_metric_values) +// { +// const auto & origin_name = metric.first; +// const auto & value = metric.second; +// if (!tiflash_metrics.registered_async_metrics.count(origin_name)) +// { +// // Register this async metric into registry on flight, as async metrics are not accumulated at once. +// auto prometheus_name = TiFlashMetrics::async_metrics_prefix + metric.first; +// // Prometheus doesn't allow metric name containing dot. +// std::replace(prometheus_name.begin(), prometheus_name.end(), '.', '_'); +// auto & family = prometheus::BuildGauge() +// .Name(prometheus_name) +// .Help("System asynchronous metric " + prometheus_name) +// .Register(*(tiflash_metrics.registry)); +// // Use original name as key for the sake of further accesses. +// tiflash_metrics.registered_async_metrics.emplace(origin_name, &family.Add({})); +// } +// tiflash_metrics.registered_async_metrics[origin_name]->Set(value); +// } +// +// if (gateway != nullptr) +// { +// if (auto return_code = gateway->Push(); return_code != 200) +// { +// LOG_FMT_WARNING(log, "Failed to push metrics to gateway, return code is {}", return_code); +// } +// } } } // namespace DB diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index 34f63b32579..3271092363d 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -1087,6 +1087,9 @@ int Server::main(const std::vector & /*args*/) global_context->initializeGlobalStoragePoolIfNeed(global_context->getPathPool()); LOG_FMT_INFO(log, "Global PageStorage run mode is {}", static_cast(global_context->getPageStorageRunMode())); + /// + global_context->initializeGlobalUniversalPageStorage(global_context->getPathPool(), global_context->getFileProvider()); + /// Initialize RateLimiter. global_context->initializeRateLimiter(config(), bg_pool, blockable_bg_pool); diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.h b/dbms/src/Storages/Page/universal/UniversalPageStorage.h index d4a1d6ced51..0266162d6bd 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.h +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.h @@ -211,6 +211,21 @@ class RaftLogReader final } } + UniversalPage read(const UniversalPageId & page_id) + { + // always traverse with the latest snapshot + auto snapshot = uni_storage.getSnapshot(fmt::format("read_{}", page_id)); + const auto page_id_and_entry = uni_storage.page_directory->getByIDOrNull(page_id, snapshot); + if (page_id_and_entry.second.isValid()) + { + return uni_storage.blob_store->read(page_id_and_entry); + } + else + { + return UniversalPage({}); + } + } + private: UniversalPageStorage & uni_storage; }; diff --git a/dbms/src/Storages/Transaction/ProxyFFI.cpp b/dbms/src/Storages/Transaction/ProxyFFI.cpp index d66875c268d..f6019c6235a 100644 --- a/dbms/src/Storages/Transaction/ProxyFFI.cpp +++ b/dbms/src/Storages/Transaction/ProxyFFI.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -157,6 +159,136 @@ uint8_t TryFlushData(EngineStoreServerWrap * server, uint64_t region_id, uint8_t } } +RawCppPtr CreateWriteBatch() +{ + return GenRawCppPtr(new UniversalWriteBatch(), RawCppPtrTypeImpl::WriteBatch); +} + +void WriteBatchPutPage(RawVoidPtr ptr, BaseBuffView page_id, BaseBuffView value) +{ + auto * wb = reinterpret_cast(ptr); + ReadBufferPtr buff = std::make_shared(value.data, value.len); + wb->putPage(UniversalPageId(page_id.data, page_id.len), 0, buff, value.len); +} + +void WriteBatchDelPage(RawVoidPtr ptr, BaseBuffView page_id) +{ + auto * wb = reinterpret_cast(ptr); + wb->delPage(UniversalPageId(page_id.data, page_id.len)); +} + +uint64_t WriteBatchSize(RawVoidPtr ptr) +{ + auto * wb = reinterpret_cast(ptr); + return wb->getTotalDataSize(); +} + +uint8_t WriteBatchIsEmpty(RawVoidPtr ptr) +{ + auto * wb = reinterpret_cast(ptr); + return wb->empty(); +} + +void WriteBatchMerge(RawVoidPtr lhs, RawVoidPtr rhs) +{ + auto * lwb = reinterpret_cast(lhs); + auto * rwb = reinterpret_cast(rhs); + lwb->merge(*rwb); + // TODO: do we need clear rhs here? +} + +void WriteBatchClear(RawVoidPtr ptr) +{ + auto * wb = reinterpret_cast(ptr); + wb->clear(); +} + +void ConsumeWriteBatch(const EngineStoreServerWrap * server, RawVoidPtr ptr) +{ + try + { + auto uni_ps = server->tmt->getContext().getGlobalUniversalPageStorage(); + auto * wb = reinterpret_cast(ptr); + uni_ps->write(std::move(*wb)); + // TODO: verify that clear is allowed after std::move and the wb is reusable + wb->clear(); + } + catch (...) + { + tryLogCurrentException(__PRETTY_FUNCTION__); + exit(-1); + } +} + +CppStrWithView HandleReadPage(const EngineStoreServerWrap * server, BaseBuffView page_id) +{ + try + { + auto uni_ps = server->tmt->getContext().getGlobalUniversalPageStorage(); + RaftLogReader reader(*uni_ps); + UniversalPageId id{page_id.data, page_id.len}; + auto page = reader.read(id); + // FIXME: avoid this extra copy + if (page.isValid()) + { + auto * value = new String(page.data.begin(), page.data.size()); + return CppStrWithView{.inner = GenRawCppPtr(value, RawCppPtrTypeImpl::String), .view = BaseBuffView{value->data(), value->size()}}; + } + else + { + return CppStrWithView{.inner = GenRawCppPtr(), .view = BaseBuffView{}}; + } + } + catch (...) + { + tryLogCurrentException(__PRETTY_FUNCTION__); + exit(-1); + } +} + +CppStrWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffView start_page_id, BaseBuffView end_page_id) +{ + try + { + auto uni_ps = server->tmt->getContext().getGlobalUniversalPageStorage(); + RaftLogReader reader(*uni_ps); + UniversalPageId start_id{start_page_id.data, start_page_id.len}; + UniversalPageId end_id{end_page_id.data, end_page_id.len}; + std::vector pages; + // FIXME: avoid all extra copy + auto checker = [&](const DB::UniversalPage & page) { + pages.push_back(page); + }; + reader.traverse(start_id, end_id, checker); + // FIXME: reclaim the space + auto * data = static_cast(malloc(pages.size() * sizeof(CppStrWithView))); + for (size_t i = 0; i < pages.size(); i++) + { + auto & page = pages[i]; + auto * target = reinterpret_cast(data) + i; + if (page.isValid()) + { + auto * value = new String(page.data.begin(), page.data.size()); + target->inner = GenRawCppPtr(value, RawCppPtrTypeImpl::String); + BaseBuffView temp{.data = value->data(), .len = value->size()}; + memcpy(reinterpret_cast(target) + sizeof(RawCppPtr), &temp, sizeof(BaseBuffView)); + } + else + { + target->inner = GenRawCppPtr(); + BaseBuffView temp{.data = nullptr, .len = 0}; + memcpy(reinterpret_cast(target) + sizeof(RawCppPtr), &temp, sizeof(BaseBuffView)); + } + } + return CppStrWithViewVec{.inner = reinterpret_cast(data), .len = pages.size() }; + } + catch (...) + { + tryLogCurrentException(__PRETTY_FUNCTION__); + exit(-1); + } +} + static_assert(sizeof(RaftStoreProxyFFIHelper) == sizeof(TiFlashRaftProxyHelper)); static_assert(alignof(RaftStoreProxyFFIHelper) == alignof(TiFlashRaftProxyHelper)); @@ -451,6 +583,9 @@ void GcRawCppPtr(RawVoidPtr ptr, RawCppPtrType type) case RawCppPtrTypeImpl::WakerNotifier: delete reinterpret_cast(ptr); break; + case RawCppPtrTypeImpl::WriteBatch: + delete reinterpret_cast(ptr); + break; default: LOG_FMT_ERROR(&Poco::Logger::get(__FUNCTION__), "unknown type {}", type); exit(-1); diff --git a/dbms/src/Storages/Transaction/ProxyFFI.h b/dbms/src/Storages/Transaction/ProxyFFI.h index fde97041873..7507ae1e2ac 100644 --- a/dbms/src/Storages/Transaction/ProxyFFI.h +++ b/dbms/src/Storages/Transaction/ProxyFFI.h @@ -58,6 +58,7 @@ enum class RawCppPtrTypeImpl : RawCppPtrType String, PreHandledSnapshotWithFiles, WakerNotifier, + WriteBatch, }; RawCppPtr GenRawCppPtr(RawVoidPtr ptr_ = nullptr, RawCppPtrTypeImpl type_ = RawCppPtrTypeImpl::None); @@ -127,6 +128,16 @@ EngineStoreApplyRes HandleWriteRaftCmd(const EngineStoreServerWrap * server, RaftCmdHeader header); uint8_t NeedFlushData(EngineStoreServerWrap * server, uint64_t region_id); uint8_t TryFlushData(EngineStoreServerWrap * server, uint64_t region_id, uint8_t until_succeed, uint64_t index, uint64_t term); +RawCppPtr CreateWriteBatch(); +void WriteBatchPutPage(RawVoidPtr ptr, BaseBuffView page_id, BaseBuffView value); +void WriteBatchDelPage(RawVoidPtr ptr, BaseBuffView page_id); +uint64_t WriteBatchSize(RawVoidPtr ptr); +uint8_t WriteBatchIsEmpty(RawVoidPtr ptr); +void WriteBatchMerge(RawVoidPtr lhs, RawVoidPtr rhs); +void WriteBatchClear(RawVoidPtr ptr); +void ConsumeWriteBatch(const EngineStoreServerWrap * server, RawVoidPtr ptr); +CppStrWithView HandleReadPage(const EngineStoreServerWrap * server, BaseBuffView page_id); +CppStrWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffView start_page_id, BaseBuffView end_page_id); void AtomicUpdateProxy(EngineStoreServerWrap * server, RaftStoreProxyFFIHelper * proxy); void HandleDestroy(EngineStoreServerWrap * server, uint64_t region_id); EngineStoreApplyRes HandleIngestSST(EngineStoreServerWrap * server, SSTViewVec snaps, RaftCmdHeader header); @@ -163,6 +174,16 @@ inline EngineStoreServerHelper GetEngineStoreServerHelper( .fn_handle_admin_raft_cmd = HandleAdminRaftCmd, .fn_need_flush_data = NeedFlushData, .fn_try_flush_data = TryFlushData, + .fn_create_write_batch = CreateWriteBatch, + .fn_write_batch_put_page = WriteBatchPutPage, + .fn_write_batch_del_page = WriteBatchDelPage, + .fn_write_batch_size = WriteBatchSize, + .fn_write_batch_is_empty = WriteBatchIsEmpty, + .fn_write_batch_merge = WriteBatchMerge, + .fn_write_batch_clear = WriteBatchClear, + .fn_consume_write_batch = ConsumeWriteBatch, + .fn_handle_read_page = HandleReadPage, + .fn_handle_scan_page = HandleScanPage, .fn_atomic_update_proxy = AtomicUpdateProxy, .fn_handle_destroy = HandleDestroy, .fn_handle_ingest_sst = HandleIngestSST, From 54b7c73ae217e0f5307842304c16e33b0e12da3d Mon Sep 17 00:00:00 2001 From: lidezhu Date: Fri, 21 Oct 2022 11:33:20 +0800 Subject: [PATCH 11/40] update proxy --- contrib/tiflash-proxy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/tiflash-proxy b/contrib/tiflash-proxy index ac4614fdfbb..2dd7f67d42f 160000 --- a/contrib/tiflash-proxy +++ b/contrib/tiflash-proxy @@ -1 +1 @@ -Subproject commit ac4614fdfbb9ac88beb09d5044d707bd703d65d6 +Subproject commit 2dd7f67d42f2d594296c11df58cf9b97a913f8e1 From 59a20c6a6e65a1cb0f63e739ddc11918621afb99 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Fri, 21 Oct 2022 13:38:08 +0800 Subject: [PATCH 12/40] uncomment --- dbms/src/Server/MetricsPrometheus.cpp | 83 +++++++++++++-------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/dbms/src/Server/MetricsPrometheus.cpp b/dbms/src/Server/MetricsPrometheus.cpp index 92c32423796..3ec06885fad 100644 --- a/dbms/src/Server/MetricsPrometheus.cpp +++ b/dbms/src/Server/MetricsPrometheus.cpp @@ -233,48 +233,47 @@ MetricsPrometheus::~MetricsPrometheus() void MetricsPrometheus::run() { - (void)async_metrics; -// auto & tiflash_metrics = TiFlashMetrics::instance(); -// for (ProfileEvents::Event event = 0; event < ProfileEvents::end(); event++) -// { -// const auto value = ProfileEvents::counters[event].load(std::memory_order_relaxed); -// tiflash_metrics.registered_profile_events[event]->Set(value); -// } -// -// for (CurrentMetrics::Metric metric = 0; metric < CurrentMetrics::end(); metric++) -// { -// const auto value = CurrentMetrics::values[metric].load(std::memory_order_relaxed); -// tiflash_metrics.registered_current_metrics[metric]->Set(value); -// } -// -// auto async_metric_values = async_metrics.getValues(); -// for (const auto & metric : async_metric_values) -// { -// const auto & origin_name = metric.first; -// const auto & value = metric.second; -// if (!tiflash_metrics.registered_async_metrics.count(origin_name)) -// { -// // Register this async metric into registry on flight, as async metrics are not accumulated at once. -// auto prometheus_name = TiFlashMetrics::async_metrics_prefix + metric.first; -// // Prometheus doesn't allow metric name containing dot. -// std::replace(prometheus_name.begin(), prometheus_name.end(), '.', '_'); -// auto & family = prometheus::BuildGauge() -// .Name(prometheus_name) -// .Help("System asynchronous metric " + prometheus_name) -// .Register(*(tiflash_metrics.registry)); -// // Use original name as key for the sake of further accesses. -// tiflash_metrics.registered_async_metrics.emplace(origin_name, &family.Add({})); -// } -// tiflash_metrics.registered_async_metrics[origin_name]->Set(value); -// } -// -// if (gateway != nullptr) -// { -// if (auto return_code = gateway->Push(); return_code != 200) -// { -// LOG_FMT_WARNING(log, "Failed to push metrics to gateway, return code is {}", return_code); -// } -// } + auto & tiflash_metrics = TiFlashMetrics::instance(); + for (ProfileEvents::Event event = 0; event < ProfileEvents::end(); event++) + { + const auto value = ProfileEvents::counters[event].load(std::memory_order_relaxed); + tiflash_metrics.registered_profile_events[event]->Set(value); + } + + for (CurrentMetrics::Metric metric = 0; metric < CurrentMetrics::end(); metric++) + { + const auto value = CurrentMetrics::values[metric].load(std::memory_order_relaxed); + tiflash_metrics.registered_current_metrics[metric]->Set(value); + } + + auto async_metric_values = async_metrics.getValues(); + for (const auto & metric : async_metric_values) + { + const auto & origin_name = metric.first; + const auto & value = metric.second; + if (!tiflash_metrics.registered_async_metrics.count(origin_name)) + { + // Register this async metric into registry on flight, as async metrics are not accumulated at once. + auto prometheus_name = TiFlashMetrics::async_metrics_prefix + metric.first; + // Prometheus doesn't allow metric name containing dot. + std::replace(prometheus_name.begin(), prometheus_name.end(), '.', '_'); + auto & family = prometheus::BuildGauge() + .Name(prometheus_name) + .Help("System asynchronous metric " + prometheus_name) + .Register(*(tiflash_metrics.registry)); + // Use original name as key for the sake of further accesses. + tiflash_metrics.registered_async_metrics.emplace(origin_name, &family.Add({})); + } + tiflash_metrics.registered_async_metrics[origin_name]->Set(value); + } + + if (gateway != nullptr) + { + if (auto return_code = gateway->Push(); return_code != 200) + { + LOG_FMT_WARNING(log, "Failed to push metrics to gateway, return code is {}", return_code); + } + } } } // namespace DB From 826733e3be485c6de43b8b327c1656b9aa9dca63 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Fri, 21 Oct 2022 17:21:39 +0800 Subject: [PATCH 13/40] avoid check raft engine path --- contrib/tiflash-proxy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/tiflash-proxy b/contrib/tiflash-proxy index 2dd7f67d42f..43e97a747f4 160000 --- a/contrib/tiflash-proxy +++ b/contrib/tiflash-proxy @@ -1 +1 @@ -Subproject commit 2dd7f67d42f2d594296c11df58cf9b97a913f8e1 +Subproject commit 43e97a747f49a4c28754cf0c7fb40cfd246dcf3c From 493851a5be3c3eea761d3326e7a31dce9d791a8b Mon Sep 17 00:00:00 2001 From: lidezhu Date: Fri, 21 Oct 2022 19:47:50 +0800 Subject: [PATCH 14/40] fix isEmpty --- contrib/tiflash-proxy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/tiflash-proxy b/contrib/tiflash-proxy index 43e97a747f4..fb4f1134126 160000 --- a/contrib/tiflash-proxy +++ b/contrib/tiflash-proxy @@ -1 +1 @@ -Subproject commit 43e97a747f49a4c28754cf0c7fb40cfd246dcf3c +Subproject commit fb4f1134126b67d25059fcf18f52dcd03bd0ff39 From 3d716acb18eb07cb2e173ae6a28f11ae808e79bd Mon Sep 17 00:00:00 2001 From: lidezhu Date: Sat, 22 Oct 2022 15:44:34 +0800 Subject: [PATCH 15/40] fix put page --- dbms/src/Storages/Transaction/ProxyFFI.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dbms/src/Storages/Transaction/ProxyFFI.cpp b/dbms/src/Storages/Transaction/ProxyFFI.cpp index f6019c6235a..1953857bc75 100644 --- a/dbms/src/Storages/Transaction/ProxyFFI.cpp +++ b/dbms/src/Storages/Transaction/ProxyFFI.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -167,8 +168,12 @@ RawCppPtr CreateWriteBatch() void WriteBatchPutPage(RawVoidPtr ptr, BaseBuffView page_id, BaseBuffView value) { auto * wb = reinterpret_cast(ptr); - ReadBufferPtr buff = std::make_shared(value.data, value.len); - wb->putPage(UniversalPageId(page_id.data, page_id.len), 0, buff, value.len); + MemoryWriteBuffer buf(0, value.len); + buf.write(value.data, value.len); + auto data_size = buf.count(); + assert(data_size == value.len); + wb->putPage(UniversalPageId(page_id.data, page_id.len), 0, buf.tryGetReadBuffer(), data_size); + std::cout << "page " << Redact::keyToHexString(page_id.data, page_id.len) << " value " << Redact::keyToHexString(value.data, value.len) << std::endl; } void WriteBatchDelPage(RawVoidPtr ptr, BaseBuffView page_id) From 4036baa8b04b7c58e93eb6404115b52081303b3e Mon Sep 17 00:00:00 2001 From: lidezhu Date: Sat, 22 Oct 2022 17:34:57 +0800 Subject: [PATCH 16/40] Hackathon: avoid unnecessary copy --- contrib/tiflash-proxy | 2 +- .../Page/universal/UniversalPageStorage.h | 12 +++++ dbms/src/Storages/Transaction/ProxyFFI.cpp | 52 +++++++++++-------- dbms/src/Storages/Transaction/ProxyFFI.h | 7 ++- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/contrib/tiflash-proxy b/contrib/tiflash-proxy index fb4f1134126..3f83bff2378 160000 --- a/contrib/tiflash-proxy +++ b/contrib/tiflash-proxy @@ -1 +1 @@ -Subproject commit fb4f1134126b67d25059fcf18f52dcd03bd0ff39 +Subproject commit 3f83bff237851ff24edce7fbb6258685690905d4 diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.h b/dbms/src/Storages/Page/universal/UniversalPageStorage.h index 0266162d6bd..e84bbab273c 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.h +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.h @@ -211,6 +211,18 @@ class RaftLogReader final } } + void traverse2(const UniversalPageId & start, const UniversalPageId & end, const std::function & acceptor) + { + // always traverse with the latest snapshot + auto snapshot = uni_storage.getSnapshot(fmt::format("scan_r_{}_{}", start, end)); + const auto page_ids = uni_storage.page_directory->getRangePageIds(start, end); + for (const auto & page_id : page_ids) + { + const auto page_id_and_entry = uni_storage.page_directory->getByID(page_id, snapshot); + acceptor(uni_storage.blob_store->read(page_id_and_entry)); + } + } + UniversalPage read(const UniversalPageId & page_id) { // always traverse with the latest snapshot diff --git a/dbms/src/Storages/Transaction/ProxyFFI.cpp b/dbms/src/Storages/Transaction/ProxyFFI.cpp index 1953857bc75..24160aa7d0e 100644 --- a/dbms/src/Storages/Transaction/ProxyFFI.cpp +++ b/dbms/src/Storages/Transaction/ProxyFFI.cpp @@ -173,7 +173,7 @@ void WriteBatchPutPage(RawVoidPtr ptr, BaseBuffView page_id, BaseBuffView value) auto data_size = buf.count(); assert(data_size == value.len); wb->putPage(UniversalPageId(page_id.data, page_id.len), 0, buf.tryGetReadBuffer(), data_size); - std::cout << "page " << Redact::keyToHexString(page_id.data, page_id.len) << " value " << Redact::keyToHexString(value.data, value.len) << std::endl; +// std::cout << "page " << Redact::keyToHexString(page_id.data, page_id.len) << " value " << Redact::keyToHexString(value.data, value.len) << std::endl; } void WriteBatchDelPage(RawVoidPtr ptr, BaseBuffView page_id) @@ -225,23 +225,21 @@ void ConsumeWriteBatch(const EngineStoreServerWrap * server, RawVoidPtr ptr) } } -CppStrWithView HandleReadPage(const EngineStoreServerWrap * server, BaseBuffView page_id) +PageWithView HandleReadPage(const EngineStoreServerWrap * server, BaseBuffView page_id) { try { auto uni_ps = server->tmt->getContext().getGlobalUniversalPageStorage(); RaftLogReader reader(*uni_ps); UniversalPageId id{page_id.data, page_id.len}; - auto page = reader.read(id); - // FIXME: avoid this extra copy - if (page.isValid()) + auto * page = new UniversalPage(reader.read(id)); + if (page->isValid()) { - auto * value = new String(page.data.begin(), page.data.size()); - return CppStrWithView{.inner = GenRawCppPtr(value, RawCppPtrTypeImpl::String), .view = BaseBuffView{value->data(), value->size()}}; + return PageWithView{.inner = GenRawCppPtr(page, RawCppPtrTypeImpl::UniversalPage), .view = BaseBuffView{page->data.begin(), page->data.size()}}; } else { - return CppStrWithView{.inner = GenRawCppPtr(), .view = BaseBuffView{}}; + return PageWithView{.inner = GenRawCppPtr(), .view = BaseBuffView{}}; } } catch (...) @@ -251,7 +249,7 @@ CppStrWithView HandleReadPage(const EngineStoreServerWrap * server, BaseBuffView } } -CppStrWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffView start_page_id, BaseBuffView end_page_id) +PageWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffView start_page_id, BaseBuffView end_page_id) { try { @@ -259,23 +257,19 @@ CppStrWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffV RaftLogReader reader(*uni_ps); UniversalPageId start_id{start_page_id.data, start_page_id.len}; UniversalPageId end_id{end_page_id.data, end_page_id.len}; - std::vector pages; - // FIXME: avoid all extra copy - auto checker = [&](const DB::UniversalPage & page) { - pages.push_back(page); + std::vector pages; + auto checker = [&](DB::UniversalPage page) { + pages.push_back(new UniversalPage(std::move(page))); }; - reader.traverse(start_id, end_id, checker); - // FIXME: reclaim the space - auto * data = static_cast(malloc(pages.size() * sizeof(CppStrWithView))); + reader.traverse2(start_id, end_id, checker); + auto * data = static_cast(malloc(pages.size() * sizeof(PageWithView))); for (size_t i = 0; i < pages.size(); i++) { - auto & page = pages[i]; - auto * target = reinterpret_cast(data) + i; - if (page.isValid()) + auto * target = reinterpret_cast(data) + i; + if (pages[i]->isValid()) { - auto * value = new String(page.data.begin(), page.data.size()); - target->inner = GenRawCppPtr(value, RawCppPtrTypeImpl::String); - BaseBuffView temp{.data = value->data(), .len = value->size()}; + target->inner = GenRawCppPtr(pages[i], RawCppPtrTypeImpl::UniversalPage); + BaseBuffView temp{.data = pages[i]->data.begin(), .len = pages[i]->data.size()}; memcpy(reinterpret_cast(target) + sizeof(RawCppPtr), &temp, sizeof(BaseBuffView)); } else @@ -285,7 +279,7 @@ CppStrWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffV memcpy(reinterpret_cast(target) + sizeof(RawCppPtr), &temp, sizeof(BaseBuffView)); } } - return CppStrWithViewVec{.inner = reinterpret_cast(data), .len = pages.size() }; + return PageWithViewVec{.inner = reinterpret_cast(data), .len = pages.size() }; } catch (...) { @@ -294,6 +288,15 @@ CppStrWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffV } } +void GcPageWithViewVec(PageWithView * inner, uint64_t len) +{ + for (size_t i = 0; i < len; i++) + { + GcRawCppPtr(inner[i].inner.ptr, inner[i].inner.type); + } + delete inner; +} + static_assert(sizeof(RaftStoreProxyFFIHelper) == sizeof(TiFlashRaftProxyHelper)); static_assert(alignof(RaftStoreProxyFFIHelper) == alignof(TiFlashRaftProxyHelper)); @@ -591,6 +594,9 @@ void GcRawCppPtr(RawVoidPtr ptr, RawCppPtrType type) case RawCppPtrTypeImpl::WriteBatch: delete reinterpret_cast(ptr); break; + case RawCppPtrTypeImpl::UniversalPage: + delete reinterpret_cast(ptr); + break; default: LOG_FMT_ERROR(&Poco::Logger::get(__FUNCTION__), "unknown type {}", type); exit(-1); diff --git a/dbms/src/Storages/Transaction/ProxyFFI.h b/dbms/src/Storages/Transaction/ProxyFFI.h index 7507ae1e2ac..66053421616 100644 --- a/dbms/src/Storages/Transaction/ProxyFFI.h +++ b/dbms/src/Storages/Transaction/ProxyFFI.h @@ -59,6 +59,7 @@ enum class RawCppPtrTypeImpl : RawCppPtrType PreHandledSnapshotWithFiles, WakerNotifier, WriteBatch, + UniversalPage, }; RawCppPtr GenRawCppPtr(RawVoidPtr ptr_ = nullptr, RawCppPtrTypeImpl type_ = RawCppPtrTypeImpl::None); @@ -136,8 +137,9 @@ uint8_t WriteBatchIsEmpty(RawVoidPtr ptr); void WriteBatchMerge(RawVoidPtr lhs, RawVoidPtr rhs); void WriteBatchClear(RawVoidPtr ptr); void ConsumeWriteBatch(const EngineStoreServerWrap * server, RawVoidPtr ptr); -CppStrWithView HandleReadPage(const EngineStoreServerWrap * server, BaseBuffView page_id); -CppStrWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffView start_page_id, BaseBuffView end_page_id); +PageWithView HandleReadPage(const EngineStoreServerWrap * server, BaseBuffView page_id); +PageWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffView start_page_id, BaseBuffView end_page_id); +void GcPageWithViewVec(PageWithView * inner, uint64_t len); void AtomicUpdateProxy(EngineStoreServerWrap * server, RaftStoreProxyFFIHelper * proxy); void HandleDestroy(EngineStoreServerWrap * server, uint64_t region_id); EngineStoreApplyRes HandleIngestSST(EngineStoreServerWrap * server, SSTViewVec snaps, RaftCmdHeader header); @@ -184,6 +186,7 @@ inline EngineStoreServerHelper GetEngineStoreServerHelper( .fn_consume_write_batch = ConsumeWriteBatch, .fn_handle_read_page = HandleReadPage, .fn_handle_scan_page = HandleScanPage, + .fn_gc_page_with_view_vec = GcPageWithViewVec, .fn_atomic_update_proxy = AtomicUpdateProxy, .fn_handle_destroy = HandleDestroy, .fn_handle_ingest_sst = HandleIngestSST, From c5ea4f27f929041220e136c9a1730f6af6ec1d36 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Mon, 31 Oct 2022 12:59:51 +0800 Subject: [PATCH 17/40] try add gc for UniversalPageStorage --- dbms/src/Interpreters/Context.cpp | 30 ++++- .../Page/universal/UniversalPageStorage.cpp | 122 ++++++++++++++++++ .../Page/universal/UniversalPageStorage.h | 51 +++++++- 3 files changed, 196 insertions(+), 7 deletions(-) diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index 539b09a2349..e3e7cc3fd12 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -66,6 +66,8 @@ #include #include + + #include #include #include @@ -107,6 +109,23 @@ namespace FailPoints extern const char force_context_path[]; } // namespace FailPoints +struct UniversalPageStorageWrapper +{ + UniversalPageStoragePtr uni_page_storage; + BackgroundProcessingPool::TaskHandle gc_handle; + + void restore(Context & global_context) + { + uni_page_storage->restore(); + gc_handle = global_context.getBackgroundPool().addTask( + [this, global_context] { + return this->uni_page_storage->gc(); + }, + false); + } +}; +using UniversalPageStorageWrapperPtr = std::shared_ptr; + /** Set of known objects (environment), that could be used in query. * Shared (global) part. Order of members (especially, order of destruction) is very important. @@ -160,7 +179,7 @@ struct ContextShared IORateLimiter io_rate_limiter; PageStorageRunMode storage_run_mode = PageStorageRunMode::ONLY_V3; DM::GlobalStoragePoolPtr global_storage_pool; - UniversalPageStoragePtr uni_page_storage; + UniversalPageStorageWrapperPtr uni_page_storage_wrapper; /// Named sessions. The user could specify session identifier to reuse settings and temporary tables in subsequent requests. class SessionKeyHash @@ -1620,18 +1639,19 @@ DM::GlobalStoragePoolPtr Context::getGlobalStoragePool() const void Context::initializeGlobalUniversalPageStorage(const PathPool & path_pool, const FileProviderPtr & file_provider) { auto lock = getLock(); - if (shared->uni_page_storage) + if (shared->uni_page_storage_wrapper) throw Exception("UniversalPageStorage has already been initialized.", ErrorCodes::LOGICAL_ERROR); - shared->uni_page_storage = UniversalPageStorage::create("global", path_pool.getPSDiskDelegatorGlobalMulti("global"), {}, file_provider); - shared->uni_page_storage->restore(); + shared->uni_page_storage_wrapper = std::make_shared(); + shared->uni_page_storage_wrapper->uni_page_storage = UniversalPageStorage::create("global", path_pool.getPSDiskDelegatorGlobalMulti("global"), {}, file_provider); + shared->uni_page_storage_wrapper->restore(*this); LOG_INFO(shared->log, "initialized GlobalUniversalPageStorage"); } UniversalPageStoragePtr Context::getGlobalUniversalPageStorage() const { auto lock = getLock(); - return shared->uni_page_storage; + return shared->uni_page_storage_wrapper->uni_page_storage; } UInt16 Context::getTCPPort() const diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp index 8a36aa63deb..9c08faf28ec 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include @@ -55,4 +56,125 @@ void UniversalPageStorage::write(UniversalWriteBatch && write_batch, const Write auto edit = blob_store->write(write_batch, write_limiter); page_directory->apply(std::move(edit), write_limiter); } + +String UniversalPageStorage::GCTimeStatistics::toLogging() const +{ + const std::string_view stage_suffix = [this]() { + switch (stage) + { + case GCStageType::Unknown: + return " "; + case GCStageType::OnlyInMem: + return " without full gc"; + case GCStageType::FullGCNothingMoved: + return " without moving any entry"; + case GCStageType::FullGC: + return ""; + } + }(); + const auto get_external_msg = [this]() -> String { + if (clean_external_page_ms == 0) + return String(""); + static constexpr double SCALE_NS_TO_MS = 1'000'000.0; + return fmt::format(" [external_callbacks={}] [external_gc={}ms] [scanner={:.2f}ms] [get_alive={:.2f}ms] [remover={:.2f}ms]", + num_external_callbacks, + clean_external_page_ms, + external_page_scan_ns / SCALE_NS_TO_MS, + external_page_get_alive_ns / SCALE_NS_TO_MS, + external_page_remove_ns / SCALE_NS_TO_MS); + }; + return fmt::format("GC finished{}." + " [total time={}ms]" + " [dump snapshots={}ms] [gc in mem entries={}ms]" + " [blobstore remove entries={}ms] [blobstore get status={}ms]" + " [get gc entries={}ms] [blobstore full gc={}ms]" + " [gc apply={}ms]" + "{}", // a placeholder for external page gc at last + stage_suffix, + total_cost_ms, + dump_snapshots_ms, + gc_in_mem_entries_ms, + blobstore_remove_entries_ms, + blobstore_get_gc_stats_ms, + full_gc_get_entries_ms, + full_gc_blobstore_copy_ms, + full_gc_apply_ms, + get_external_msg()); +} + +UniversalPageStorage::GCTimeStatistics UniversalPageStorage::doGC(const WriteLimiterPtr & write_limiter, const ReadLimiterPtr & read_limiter) +{ + Stopwatch gc_watch; + SCOPE_EXIT({ + GET_METRIC(tiflash_storage_page_gc_count, type_v3).Increment(); + GET_METRIC(tiflash_storage_page_gc_duration_seconds, type_v3).Observe(gc_watch.elapsedSeconds()); + bool is_running = true; + gc_is_running.compare_exchange_strong(is_running, false); + }); + + GCTimeStatistics statistics; + + // 1. Do the MVCC gc, clean up expired snapshot. + // And get the expired entries. + if (page_directory->tryDumpSnapshot(read_limiter, write_limiter)) + { + GET_METRIC(tiflash_storage_page_gc_count, type_v3_mvcc_dumped).Increment(); + } + statistics.dump_snapshots_ms = gc_watch.elapsedMillisecondsFromLastTime(); + + const auto & del_entries = page_directory->gcInMemEntries(); + statistics.gc_in_mem_entries_ms = gc_watch.elapsedMillisecondsFromLastTime(); + + // 2. Remove the expired entries in BlobStore. + // It won't delete the data on the disk. + // It will only update the SpaceMap which in memory. + blob_store->remove(del_entries); + statistics.blobstore_remove_entries_ms = gc_watch.elapsedMillisecondsFromLastTime(); + + // 3. Analyze the status of each Blob in order to obtain the Blobs that need to do `full GC`. + // Blobs that do not need to do full GC will also do ftruncate to reduce space amplification. + const auto & blob_ids_need_gc = blob_store->getGCStats(); + statistics.blobstore_get_gc_stats_ms = gc_watch.elapsedMillisecondsFromLastTime(); + if (blob_ids_need_gc.empty()) + { + statistics.stage = GCStageType::OnlyInMem; + statistics.total_cost_ms = gc_watch.elapsedMilliseconds(); + return statistics; + } + + // Execute full gc + GET_METRIC(tiflash_storage_page_gc_count, type_v3_bs_full_gc).Increment(blob_ids_need_gc.size()); + // 4. Filter out entries in MVCC by BlobId. + // We also need to filter the version of the entry. + // So that the `gc_apply` can proceed smoothly. + auto [blob_gc_info, total_page_size] = page_directory->getEntriesByBlobIds(blob_ids_need_gc); + statistics.full_gc_get_entries_ms = gc_watch.elapsedMillisecondsFromLastTime(); + if (blob_gc_info.empty()) + { + statistics.stage = GCStageType::FullGCNothingMoved; + statistics.total_cost_ms = gc_watch.elapsedMilliseconds(); + return statistics; + } + + // 5. Do the BlobStore GC + // After BlobStore GC, these entries will be migrated to a new blob. + // Then we should notify MVCC apply the change. + PS::V3::universal::PageEntriesEdit gc_edit = blob_store->gc(blob_gc_info, total_page_size, write_limiter, read_limiter); + statistics.full_gc_blobstore_copy_ms = gc_watch.elapsedMillisecondsFromLastTime(); + RUNTIME_CHECK_MSG(!gc_edit.empty(), "Something wrong after BlobStore GC"); + + // 6. MVCC gc apply + // MVCC will apply the migrated entries. + // Also it will generate a new version for these entries. + // Note that if the process crash between step 5 and step 6, the stats in BlobStore will + // be reset to correct state during restore. If any exception thrown, then some BlobFiles + // will be remained as "read-only" files while entries in them are useless in actual. + // Those BlobFiles should be cleaned during next restore. + page_directory->gcApply(std::move(gc_edit), write_limiter); + statistics.full_gc_apply_ms = gc_watch.elapsedMillisecondsFromLastTime(); + + statistics.stage = GCStageType::FullGC; + statistics.total_cost_ms = gc_watch.elapsedMilliseconds(); + return statistics; +} } // namespace DB diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.h b/dbms/src/Storages/Page/universal/UniversalPageStorage.h index e84bbab273c..2fe631903b2 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.h +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.h @@ -72,6 +72,41 @@ class UniversalPageStorage final { } + enum class GCStageType + { + Unknown, + OnlyInMem, + FullGCNothingMoved, + FullGC, + }; + + struct GCTimeStatistics + { + GCStageType stage = GCStageType::Unknown; + bool executeNextImmediately() const { return stage == GCStageType::FullGC; }; + + UInt64 total_cost_ms = 0; + + UInt64 dump_snapshots_ms = 0; + UInt64 gc_in_mem_entries_ms = 0; + UInt64 blobstore_remove_entries_ms = 0; + UInt64 blobstore_get_gc_stats_ms = 0; + // Full GC + UInt64 full_gc_get_entries_ms = 0; + UInt64 full_gc_blobstore_copy_ms = 0; + UInt64 full_gc_apply_ms = 0; + + // GC external page + UInt64 clean_external_page_ms = 0; + UInt64 num_external_callbacks = 0; + // ms is usually too big for these operation, store by ns (10^-9) + UInt64 external_page_scan_ns = 0; + UInt64 external_page_get_alive_ns = 0; + UInt64 external_page_remove_ns = 0; + + String toLogging() const; + }; + ~UniversalPageStorage() = default; void restore(); @@ -118,10 +153,20 @@ class UniversalPageStorage final // We may skip the GC to reduce useless reading by default. bool gc(bool not_skip = false, const WriteLimiterPtr & write_limiter = nullptr, const ReadLimiterPtr & read_limiter = nullptr) { - UNUSED(not_skip, write_limiter, read_limiter); - return false; + // If another thread is running gc, just return; + bool v = false; + if (!gc_is_running.compare_exchange_strong(v, true)) + return false; + + const GCTimeStatistics statistics = doGC(write_limiter, read_limiter); + assert(statistics.stage != GCStageType::Unknown); // `doGC` must set the stage + LOG_DEBUG(log, statistics.toLogging()); + + return statistics.executeNextImmediately(); } + GCTimeStatistics doGC(const WriteLimiterPtr & write_limiter, const ReadLimiterPtr & read_limiter); + // Register and unregister external pages GC callbacks // Note that user must ensure that it is safe to call `scanner` and `remover` even after unregister. void registerExternalPagesCallbacks(const ExternalPageCallbacks & callbacks) { UNUSED(callbacks); } @@ -134,6 +179,8 @@ class UniversalPageStorage final PS::V3::universal::PageDirectoryPtr page_directory; PS::V3::universal::BlobStorePtr blob_store; + + std::atomic gc_is_running = false; }; class KVStoreReader final From 024ef9eb1ca194f10dcc9bf76bf0221e172cab3d Mon Sep 17 00:00:00 2001 From: lidezhu Date: Mon, 31 Oct 2022 13:28:10 +0800 Subject: [PATCH 18/40] fix build --- dbms/src/Storages/Page/universal/UniversalPageStorage.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.h b/dbms/src/Storages/Page/universal/UniversalPageStorage.h index 2fe631903b2..16ac8db08dc 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.h +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.h @@ -69,6 +69,7 @@ class UniversalPageStorage final , delegator(std::move(delegator_)) , config(config_) , file_provider(file_provider_) + , log(Logger::get("UniversalPageStorage", name)) { } @@ -153,6 +154,7 @@ class UniversalPageStorage final // We may skip the GC to reduce useless reading by default. bool gc(bool not_skip = false, const WriteLimiterPtr & write_limiter = nullptr, const ReadLimiterPtr & read_limiter = nullptr) { + std::ignore = not_skip; // If another thread is running gc, just return; bool v = false; if (!gc_is_running.compare_exchange_strong(v, true)) @@ -181,6 +183,8 @@ class UniversalPageStorage final PS::V3::universal::BlobStorePtr blob_store; std::atomic gc_is_running = false; + + LoggerPtr log; }; class KVStoreReader final From 2bd24170d45b37acfab0aa0c49a9a3175af98b79 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Mon, 31 Oct 2022 17:13:56 +0800 Subject: [PATCH 19/40] add some log for debug --- dbms/src/Storages/Transaction/ProxyFFI.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dbms/src/Storages/Transaction/ProxyFFI.cpp b/dbms/src/Storages/Transaction/ProxyFFI.cpp index 24160aa7d0e..bb80dcbada9 100644 --- a/dbms/src/Storages/Transaction/ProxyFFI.cpp +++ b/dbms/src/Storages/Transaction/ProxyFFI.cpp @@ -162,6 +162,7 @@ uint8_t TryFlushData(EngineStoreServerWrap * server, uint64_t region_id, uint8_t RawCppPtr CreateWriteBatch() { + LOG_DEBUG(&Poco::Logger::get("ProxyFFIDebug"), "create write batch"); return GenRawCppPtr(new UniversalWriteBatch(), RawCppPtrTypeImpl::WriteBatch); } @@ -592,6 +593,7 @@ void GcRawCppPtr(RawVoidPtr ptr, RawCppPtrType type) delete reinterpret_cast(ptr); break; case RawCppPtrTypeImpl::WriteBatch: + LOG_DEBUG(&Poco::Logger::get("ProxyFFIDebug"), "destroy write batch"); delete reinterpret_cast(ptr); break; case RawCppPtrTypeImpl::UniversalPage: From 07bd32a81219d43cc27afc5ee8108d843cf48367 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Mon, 31 Oct 2022 19:17:51 +0800 Subject: [PATCH 20/40] decrease gc interval --- dbms/src/Interpreters/Context.cpp | 3 ++- dbms/src/Storages/Transaction/ProxyFFI.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index e3e7cc3fd12..67cfd068836 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -121,7 +121,8 @@ struct UniversalPageStorageWrapper [this, global_context] { return this->uni_page_storage->gc(); }, - false); + false, + 1000); } }; using UniversalPageStorageWrapperPtr = std::shared_ptr; diff --git a/dbms/src/Storages/Transaction/ProxyFFI.cpp b/dbms/src/Storages/Transaction/ProxyFFI.cpp index bb80dcbada9..a36e705b3a5 100644 --- a/dbms/src/Storages/Transaction/ProxyFFI.cpp +++ b/dbms/src/Storages/Transaction/ProxyFFI.cpp @@ -162,7 +162,7 @@ uint8_t TryFlushData(EngineStoreServerWrap * server, uint64_t region_id, uint8_t RawCppPtr CreateWriteBatch() { - LOG_DEBUG(&Poco::Logger::get("ProxyFFIDebug"), "create write batch"); +// LOG_DEBUG(&Poco::Logger::get("ProxyFFIDebug"), "create write batch"); return GenRawCppPtr(new UniversalWriteBatch(), RawCppPtrTypeImpl::WriteBatch); } @@ -236,6 +236,7 @@ PageWithView HandleReadPage(const EngineStoreServerWrap * server, BaseBuffView p auto * page = new UniversalPage(reader.read(id)); if (page->isValid()) { +// LOG_DEBUG(&Poco::Logger::get("ProxyFFIDebug"), "handle read page"); return PageWithView{.inner = GenRawCppPtr(page, RawCppPtrTypeImpl::UniversalPage), .view = BaseBuffView{page->data.begin(), page->data.size()}}; } else @@ -280,6 +281,7 @@ PageWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffVie memcpy(reinterpret_cast(target) + sizeof(RawCppPtr), &temp, sizeof(BaseBuffView)); } } +// LOG_DEBUG(&Poco::Logger::get("ProxyFFIDebug"), "handle scan page {}", pages.size()); return PageWithViewVec{.inner = reinterpret_cast(data), .len = pages.size() }; } catch (...) @@ -593,7 +595,7 @@ void GcRawCppPtr(RawVoidPtr ptr, RawCppPtrType type) delete reinterpret_cast(ptr); break; case RawCppPtrTypeImpl::WriteBatch: - LOG_DEBUG(&Poco::Logger::get("ProxyFFIDebug"), "destroy write batch"); +// LOG_DEBUG(&Poco::Logger::get("ProxyFFIDebug"), "destroy write batch"); delete reinterpret_cast(ptr); break; case RawCppPtrTypeImpl::UniversalPage: From 308cf7cf10de8d7b0426883ad5d09c96a133a99c Mon Sep 17 00:00:00 2001 From: JaySon Date: Wed, 26 Oct 2022 15:29:57 +0800 Subject: [PATCH 21/40] fix gc --- dbms/src/Storages/Page/V3/PageDirectory.cpp | 36 +++----- dbms/src/Storages/Page/V3/PageDirectory.h | 10 +-- .../Storages/Page/V3/PageDirectoryFactory.cpp | 8 +- .../Storages/Page/V3/PageDirectoryFactory.h | 2 +- dbms/src/Storages/Page/V3/WALStore.cpp | 27 +++--- dbms/src/Storages/Page/V3/WALStore.h | 20 +++-- .../Page/V3/tests/gtest_page_storage.cpp | 24 ++++- .../Page/V3/tests/gtest_wal_store.cpp | 89 ++++++++++++++++++- 8 files changed, 155 insertions(+), 61 deletions(-) diff --git a/dbms/src/Storages/Page/V3/PageDirectory.cpp b/dbms/src/Storages/Page/V3/PageDirectory.cpp index 3f09d33e3e8..b448728e15f 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectory.cpp @@ -509,8 +509,7 @@ bool VersionedPageEntries::cleanOutdatedEntries( UInt64 lowest_seq, typename Trait::EntriesDerefMap * normal_entries_to_deref, PageEntriesV3 * entries_removed, - const PageLock & /*page_lock*/, - bool keep_last_valid_var_entry) + const PageLock & /*page_lock*/) { if (type == EditRecordType::VAR_EXTERNAL) { @@ -560,11 +559,8 @@ bool VersionedPageEntries::cleanOutdatedEntries( // If the first version less than is entry, // then we can remove those entries prev of it. // If the first version less than is delete, - // we may keep the first valid entry before the delete entry in the following case: - // 1) if `keep_last_valid_var_entry` is true - // (this is only used when dump snapshot because there may be some upsert entry in later wal files, - // so we need keep the last valid entry here to avoid the delete entry being removed) - // 2) if `being_ref_count` > 1(this means the entry is ref by other entries) + // we may keep the first valid entry before the delete entry + // if `being_ref_count` > 1 (this means the entry is ref by other entries) bool last_entry_is_delete = !iter->second.isEntry(); --iter; // keep the first version less than while (true) @@ -578,7 +574,7 @@ bool VersionedPageEntries::cleanOutdatedEntries( { if (last_entry_is_delete) { - if (!keep_last_valid_var_entry && iter->second.being_ref_count == 1) + if (iter->second.being_ref_count == 1) { if (entries_removed) { @@ -610,13 +606,7 @@ bool VersionedPageEntries::cleanOutdatedEntries( } template -bool VersionedPageEntries::derefAndClean( - UInt64 lowest_seq, - const typename Trait::PageId & page_id, - const PageVersion & deref_ver, - const Int64 deref_count, - PageEntriesV3 * entries_removed, - bool keep_last_valid_var_entry) +bool VersionedPageEntries::derefAndClean(UInt64 lowest_seq, const typename Trait::PageId & page_id, const PageVersion & deref_ver, const Int64 deref_count, PageEntriesV3 * entries_removed) { auto page_lock = acquireLock(); if (type == EditRecordType::VAR_EXTERNAL) @@ -657,7 +647,7 @@ bool VersionedPageEntries::derefAndClean( // Clean outdated entries after decreased the ref-counter // set `normal_entries_to_deref` to be nullptr to ignore cleaning ref-var-entries - return cleanOutdatedEntries(lowest_seq, /*normal_entries_to_deref*/ nullptr, entries_removed, page_lock, keep_last_valid_var_entry); + return cleanOutdatedEntries(lowest_seq, /*normal_entries_to_deref*/ nullptr, entries_removed, page_lock); } throw Exception(fmt::format("calling derefAndClean with invalid state [state={}]", toDebugString())); @@ -1372,8 +1362,7 @@ bool PageDirectory::tryDumpSnapshot(const ReadLimiterPtr & read_limiter, return factory.createFromReader( identifier, std::move(snapshot_reader), - /* wal */ nullptr, - /* for_dump_snapshot */ true); + /* wal */ nullptr); } else if constexpr (std::is_same_v) { @@ -1381,8 +1370,7 @@ bool PageDirectory::tryDumpSnapshot(const ReadLimiterPtr & read_limiter, return factory.createFromReader( identifier, std::move(snapshot_reader), - /* wal */ nullptr, - /* for_dump_snapshot */ true); + /* wal */ nullptr); } }(); // The records persisted in `files_snap` is older than or equal to all records in `edit` @@ -1397,7 +1385,7 @@ bool PageDirectory::tryDumpSnapshot(const ReadLimiterPtr & read_limiter, } template -PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries, bool keep_last_valid_var_entry) +PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries) { UInt64 lowest_seq = sequence.load(); @@ -1462,8 +1450,7 @@ PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries, lowest_seq, &normal_entries_to_deref, return_removed_entries ? &all_del_entries : nullptr, - iter->second->acquireLock(), - keep_last_valid_var_entry); + iter->second->acquireLock()); { std::unique_lock write_lock(table_rw_mutex); @@ -1501,8 +1488,7 @@ PageEntriesV3 PageDirectory::gcInMemEntries(bool return_removed_entries, page_id, /*deref_ver=*/deref_counter.first, /*deref_count=*/deref_counter.second, - return_removed_entries ? &all_del_entries : nullptr, - keep_last_valid_var_entry); + return_removed_entries ? &all_del_entries : nullptr); if (all_deleted) { diff --git a/dbms/src/Storages/Page/V3/PageDirectory.h b/dbms/src/Storages/Page/V3/PageDirectory.h index 7c58c21471c..e2c6c12de74 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.h +++ b/dbms/src/Storages/Page/V3/PageDirectory.h @@ -200,7 +200,6 @@ class VersionedPageEntries * to be decreased the ref count by `derefAndClean`. * The elem is > * `entries_removed`: Return the entries removed from the version list - * `keep_last_valid_var_entry`: Keep the last valid entry, useful for dumping snapshot. * * Return `true` iff this page can be totally removed from the whole `PageDirectory`. */ @@ -208,15 +207,13 @@ class VersionedPageEntries UInt64 lowest_seq, typename Trait::EntriesDerefMap * normal_entries_to_deref, PageEntriesV3 * entries_removed, - const PageLock & page_lock, - bool keep_last_valid_var_entry = false); + const PageLock & page_lock); bool derefAndClean( UInt64 lowest_seq, const typename Trait::PageId & page_id, const PageVersion & deref_ver, Int64 deref_count, - PageEntriesV3 * entries_removed, - bool keep_last_valid_var_entry = false); + PageEntriesV3 * entries_removed); void collapseTo(UInt64 seq, const typename Trait::PageId & page_id, typename Trait::PageEntriesEdit & edit); @@ -329,8 +326,7 @@ class PageDirectory // Perform a GC for in-memory entries and return the removed entries. // If `return_removed_entries` is false, then just return an empty set. - // When dump snapshot, we need to keep the last valid entry. Check out `tryDumpSnapshot` for the reason. - PageEntriesV3 gcInMemEntries(bool return_removed_entries = true, bool keep_last_valid_var_entry = false); + PageEntriesV3 gcInMemEntries(bool return_removed_entries = true); private: using ExternalIdTrait = typename Trait::ExternalIdTrait; diff --git a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp index 70df01b9d79..c34574cf89b 100644 --- a/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp @@ -40,7 +40,7 @@ PageDirectoryFactory::create(String storage_name, FileProviderPtr & file_ template typename Trait::PageDirectoryPtr -PageDirectoryFactory::createFromReader(String storage_name, WALStoreReaderPtr reader, WALStorePtr wal, bool for_dump_snapshot) +PageDirectoryFactory::createFromReader(String storage_name, WALStoreReaderPtr reader, WALStorePtr wal) { typename Trait::PageDirectoryPtr dir = std::make_unique(storage_name, std::move(wal)); loadFromDisk(dir, std::move(reader)); @@ -51,10 +51,10 @@ PageDirectoryFactory::createFromReader(String storage_name, WALStoreReade // After restoring from the disk, we need cleanup all invalid entries in memory, or it will // try to run GC again on some entries that are already marked as invalid in BlobStore. // It's no need to remove the expired entries in BlobStore, so skip filling removed_entries to improve performance. - dir->gcInMemEntries(/*return_removed_entries=*/false, /* keep_last_delete_entry */ for_dump_snapshot); - LOG_FMT_INFO(DB::Logger::get("PageDirectoryFactory", storage_name), "PageDirectory restored [max_page_id={}] [max_applied_ver={}]", dir->getMaxId(), dir->sequence); + dir->gcInMemEntries(/*return_removed_entries=*/false); + LOG_INFO(DB::Logger::get(storage_name), "PageDirectory restored [max_page_id={}] [max_applied_ver={}]", dir->getMaxId(), dir->sequence); - if (!for_dump_snapshot && blob_stats) + if (blob_stats) { // After all entries restored to `mvcc_table_directory`, only apply // the latest entry to `blob_stats`, or we may meet error since diff --git a/dbms/src/Storages/Page/V3/PageDirectoryFactory.h b/dbms/src/Storages/Page/V3/PageDirectoryFactory.h index a45ad708c95..bee04874e03 100644 --- a/dbms/src/Storages/Page/V3/PageDirectoryFactory.h +++ b/dbms/src/Storages/Page/V3/PageDirectoryFactory.h @@ -54,7 +54,7 @@ class PageDirectoryFactory typename Trait::PageDirectoryPtr create(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, WALConfig config); - typename Trait::PageDirectoryPtr createFromReader(String storage_name, WALStoreReaderPtr reader, WALStorePtr wal, bool for_dump_snapshot = false); + typename Trait::PageDirectoryPtr createFromReader(String storage_name, WALStoreReaderPtr reader, WALStorePtr wal); // just for test typename Trait::PageDirectoryPtr createFromEdit(String storage_name, FileProviderPtr & file_provider, PSDiskDelegatorPtr & delegator, const typename Trait::PageEntriesEdit & edit); diff --git a/dbms/src/Storages/Page/V3/WALStore.cpp b/dbms/src/Storages/Page/V3/WALStore.cpp index 3d006f1931b..06d5f3879fd 100644 --- a/dbms/src/Storages/Page/V3/WALStore.cpp +++ b/dbms/src/Storages/Page/V3/WALStore.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -82,20 +83,26 @@ void WALStore::apply(String && serialized_edit, const WriteLimiterPtr & write_li { std::lock_guard lock(log_file_mutex); - // Roll to a new log file - // TODO: Make it configurable if (log_file == nullptr || log_file->writtenBytes() > config.roll_size) { - auto log_num = last_log_num++; - auto [new_log_file, filename] = createLogWriter({log_num, 0}, false); - (void)filename; - log_file.swap(new_log_file); + // Roll to a new log file + rollToNewLogWriter(lock); } log_file->addRecord(payload, serialized_edit.size(), write_limiter); } } +Format::LogNumberType WALStore::rollToNewLogWriter(const std::lock_guard &) +{ + // Roll to a new log file + auto log_num = last_log_num++; + auto [new_log_file, filename] = createLogWriter({log_num, 0}, false); + UNUSED(filename); + log_file.swap(new_log_file); + return log_num; +} + std::tuple, LogFilename> WALStore::createLogWriter( const std::pair & new_log_lvl, bool manual_flush) @@ -135,9 +142,7 @@ std::tuple, LogFilename> WALStore::createLogWriter( new_log_lvl.first, /*recycle*/ true, /*manual_flush*/ manual_flush); - return { - std::move(log_writer), - log_filename}; + return {std::move(log_writer), log_filename}; } WALStore::FilesSnapshot WALStore::getFilesSnapshot() const @@ -185,7 +190,7 @@ bool WALStore::saveSnapshot( if (files_snap.persisted_log_files.empty()) return false; - LOG_FMT_INFO(logger, "Saving directory snapshot"); + LOG_FMT_INFO(logger, "Saving directory snapshot [num_records={}]", num_records); // Use {largest_log_num, 1} to save the `edit` const auto log_num = files_snap.persisted_log_files.rbegin()->log_num; @@ -226,7 +231,7 @@ bool WALStore::saveSnapshot( files_snap.persisted_log_files.begin(), files_snap.persisted_log_files.end(), [](const auto & arg, FmtBuffer & fb) { - fb.fmtAppend("{}", arg.filename(arg.stage)); + fb.append(arg.filename(arg.stage)); }, ", "); fmt_buf.fmtAppend("] [num_records={}] [file={}] [size={}].", diff --git a/dbms/src/Storages/Page/V3/WALStore.h b/dbms/src/Storages/Page/V3/WALStore.h index 91f02c67771..12b9923a428 100644 --- a/dbms/src/Storages/Page/V3/WALStore.h +++ b/dbms/src/Storages/Page/V3/WALStore.h @@ -35,6 +35,10 @@ class PSDiskDelegator; using PSDiskDelegatorPtr = std::shared_ptr; namespace PS::V3 { +namespace tests +{ +class WALStoreTest; +} class WALStore; using WALStorePtr = std::unique_ptr; @@ -74,6 +78,7 @@ class WALStore } }; + FilesSnapshot getFilesSnapshot() const; bool saveSnapshot( @@ -84,19 +89,22 @@ class WALStore const String & name() { return storage_name; } + friend class tests::WALStoreTest; // for testing + private: - WALStore( - String storage_name, - const PSDiskDelegatorPtr & delegator_, - const FileProviderPtr & provider_, - Format::LogNumberType last_log_num_, - WALConfig config); + WALStore(String storage_name, + const PSDiskDelegatorPtr & delegator_, + const FileProviderPtr & provider_, + Format::LogNumberType last_log_num_, + WALConfig config); std::tuple, LogFilename> createLogWriter( const std::pair & new_log_lvl, bool manual_flush); + Format::LogNumberType rollToNewLogWriter(const std::lock_guard &); + private: const String storage_name; PSDiskDelegatorPtr delegator; diff --git a/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp b/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp index 2d4de975fdf..e122b397f47 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_page_storage.cpp @@ -1635,7 +1635,7 @@ try page_storage->write(std::move(batch)); } - // create a snapshot to avoid gc + // create a snapshot to avoid page0 being GC-ed auto snap = page_storage->getSnapshot(); { @@ -1644,21 +1644,29 @@ try page_storage->write(std::move(batch)); } +<<<<<<< HEAD auto getLogFileNum = [&]() { auto log_files = WALStoreReader::listAllFiles(delegator, Logger::get("PageStorageTest", "")); +======= + auto get_log_file_num = [&]() { + auto log_files = WALStoreReader::listAllFiles(delegator, Logger::get()); +>>>>>>> 47480fc3a (PageStorage: Fix peak memory usage when running GC on PageDirectory (#6168)) return log_files.size(); }; // write until there are more than one wal file - while (getLogFileNum() <= 1) + while (get_log_file_num() <= 1) { WriteBatch batch; PageId page_id1 = 130; batch.putPage(page_id1, 0, std::make_shared(c_buff, buf_sz), buf_sz, {}); page_storage->write(std::move(batch)); } + + // read with latest snapshot, we can not get page0 ASSERT_ANY_THROW(page_storage->read(page_id0)); + // after the page0 get deleted in previouse log file, // write an upsert entry into the current writing log file auto done_full_gc = page_storage->gc(); EXPECT_TRUE(done_full_gc); @@ -1671,6 +1679,8 @@ try page_storage = reopenWithConfig(config); } + // After restored from disk, we should not see page0 again + // or it could be an entry pointing to a non-exist BlobFile ASSERT_ANY_THROW(page_storage->read(page_id0)); } CATCH @@ -1720,13 +1730,18 @@ try page_storage->write(std::move(batch)); } +<<<<<<< HEAD auto getLogFileNum = [&]() { auto log_files = WALStoreReader::listAllFiles(delegator, Logger::get("PageStorageTest", "")); +======= + auto get_log_file_num = [&]() { + auto log_files = WALStoreReader::listAllFiles(delegator, Logger::get()); +>>>>>>> 47480fc3a (PageStorage: Fix peak memory usage when running GC on PageDirectory (#6168)) return log_files.size(); }; // write until there are more than one wal file - while (getLogFileNum() <= 1) + while (get_log_file_num() <= 1) { WriteBatch batch; PageId page_id2 = 130; @@ -1735,6 +1750,7 @@ try } ASSERT_ANY_THROW(page_storage->read(page_id0)); + // after the page0 get deleted in previouse log file, // write an upsert entry into the current writing log file auto done_full_gc = page_storage->gc(); EXPECT_TRUE(done_full_gc); @@ -1747,6 +1763,8 @@ try page_storage = reopenWithConfig(config); } + // After restored from disk, we should not see page0 again + // or it could be an entry pointing to a non-exist BlobFile ASSERT_ANY_THROW(page_storage->read(page_id0)); } CATCH diff --git a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp index a629d6ad9b1..72858fd56ec 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_wal_store.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include @@ -29,6 +30,8 @@ #include #include +#include +#include #include namespace DB::PS::V3::tests @@ -335,7 +338,11 @@ class WALStoreTest } protected: +<<<<<<< HEAD static void applyWithSameVersion(WALStorePtr & wal, u128::PageEntriesEdit & edit, const PageVersion & version) +======= + static void applyWithSameVersion(const WALStorePtr & wal, PageEntriesEdit & edit, const PageVersion & version) +>>>>>>> 47480fc3a (PageStorage: Fix peak memory usage when running GC on PageDirectory (#6168)) { for (auto & r : edit.getMutRecords()) { @@ -344,6 +351,18 @@ class WALStoreTest wal->apply(u128::Serializer::serializeTo(edit)); } + static void rollToNewLogWriter(const WALStorePtr & wal) + { + std::lock_guard guard(wal->log_file_mutex); + wal->rollToNewLogWriter(guard); + } + + size_t getNumLogFiles() + { + auto log_files = WALStoreReader::listAllFiles(delegator, log); + return log_files.size(); + } + private: const bool multi_paths; @@ -353,9 +372,10 @@ class WALStoreTest LoggerPtr log; }; -TEST_P(WALStoreTest, FindCheckpointFile) +TEST(WALStoreReaderTest, FindCheckpointFile) { - auto path = getTemporaryPath(); + auto log = Logger::get(); + auto path = base::TiFlashStorageTestBasic::getTemporaryPath(); { // no checkpoint @@ -704,8 +724,7 @@ try // Test for save snapshot (with encryption) LogFilenameSet persisted_log_files = WALStoreReader::listAllFiles(delegator, log); - WALStore::FilesSnapshot file_snap{.current_writing_log_num = 100, // just a fake value - .persisted_log_files = persisted_log_files}; + WALStore::FilesSnapshot file_snap{.persisted_log_files = persisted_log_files}; u128::PageEntriesEdit snap_edit; PageEntryV3 entry{.file_id = 2, .size = 1, .padded_size = 0, .tag = 0, .offset = 0x123, .checksum = 0x4567}; @@ -743,6 +762,68 @@ try } CATCH +TEST_P(WALStoreTest, GetFileSnapshot) +{ + auto ctx = DB::tests::TiFlashTestEnv::getContext(); + auto provider = ctx.getFileProvider(); + auto path = getTemporaryPath(); + + auto [wal, reader] = WALStore::create(getCurrentTestName(), provider, delegator, config); + ASSERT_NE(wal, nullptr); + + // running gc right before any writes is skip + ASSERT_FALSE(wal->tryGetFilesSnapshot(1, false).isValid()); + + // generate log_1_0, log_2_0, log_3_0 + rollToNewLogWriter(wal); + rollToNewLogWriter(wal); + rollToNewLogWriter(wal); + + ASSERT_EQ(getNumLogFiles(), 3); + // num of files not exceed 5, skip + ASSERT_FALSE(wal->tryGetFilesSnapshot(5, false).isValid()); + // num of files not exceed 3, skip + ASSERT_FALSE(wal->tryGetFilesSnapshot(3, false).isValid()); + // num of files not exceed 3, but still valid when `force` is true + ASSERT_TRUE(wal->tryGetFilesSnapshot(3, true).isValid()); + + rollToNewLogWriter(wal); + // num of files exceed 3, return + { + ASSERT_EQ(getNumLogFiles(), 4); + auto files = wal->tryGetFilesSnapshot(3, false); + ASSERT_TRUE(files.isValid()); + ASSERT_EQ(files.persisted_log_files.size(), 4); + ASSERT_EQ(files.persisted_log_files.begin()->log_num, 1); + ASSERT_EQ(files.persisted_log_files.rbegin()->log_num, 4); + ASSERT_EQ(getNumLogFiles(), 4); + } + + { + // write new edit, new log file generated + PageEntriesEdit edit; + edit.del(buildV3Id(TEST_NAMESPACE_ID, 100)); + wal->apply(ser::serializeTo(edit)); + } + + { + ASSERT_EQ(getNumLogFiles(), 5); + auto files = wal->tryGetFilesSnapshot(3, false); + ASSERT_TRUE(files.isValid()); + ASSERT_EQ(files.persisted_log_files.size(), 5); + ASSERT_EQ(files.persisted_log_files.begin()->log_num, 1); + ASSERT_EQ(files.persisted_log_files.rbegin()->log_num, 5); + ASSERT_EQ(getNumLogFiles(), 5); + + // empty + PageEntriesEdit snap_edit; + bool done = wal->saveSnapshot(std::move(files), ser::serializeTo(snap_edit), snap_edit.size()); + ASSERT_TRUE(done); + ASSERT_EQ(getNumLogFiles(), 1); + } +} + + INSTANTIATE_TEST_CASE_P( Disks, WALStoreTest, From 1c5834533134fd65b4bf7e462490ed7967bd77d6 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 2 Nov 2022 13:11:15 +0800 Subject: [PATCH 22/40] try fix space allocation --- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 41ddd77d03a..7236eb054a3 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -255,8 +255,10 @@ class STDMapSpaceMap if (it->second == size) { + bool is_champion = it->first <= hint_biggest_offset && hint_biggest_offset < it->first + it->second; + assert(hint_biggest_offset + hint_biggest_cap <= it->first + it->second); // It is not champion, just return - if (it->first != hint_biggest_offset) + if (!is_champion) { free_map.erase(it); max_cap = hint_biggest_cap; From a8f07d6993d2a6d900cd56b5f73a9dc131d2fdd6 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 2 Nov 2022 14:55:27 +0800 Subject: [PATCH 23/40] try fix space allocation again --- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 7236eb054a3..0c47cdb9590 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -253,10 +253,14 @@ class STDMapSpaceMap // Update return start offset = it->first; - if (it->second == size) + bool is_champion = it->first <= hint_biggest_offset && hint_biggest_offset < it->first + it->second; + if (is_champion) { - bool is_champion = it->first <= hint_biggest_offset && hint_biggest_offset < it->first + it->second; + // TODO: change to exception assert(hint_biggest_offset + hint_biggest_cap <= it->first + it->second); + } + if (it->second == size) + { // It is not champion, just return if (!is_champion) { @@ -279,7 +283,7 @@ class STDMapSpaceMap it = free_map.insert(/*hint=*/it, {k, v}); // Use the `it` after erased as a hint, should be good for performance // It is not champion, just return - if (k - size != hint_biggest_offset) + if (!is_champion) { max_cap = hint_biggest_cap; return std::make_tuple(offset, max_cap, last_offset == offset); From a643cdde0c1d657543ff2beea9a3ba0b3b0e715c Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 2 Nov 2022 18:02:19 +0800 Subject: [PATCH 24/40] add some metric --- dbms/src/Common/TiFlashMetrics.h | 9 ++++++++- dbms/src/Storages/Page/V3/PageDirectory.cpp | 8 ++++++++ dbms/src/Storages/Page/V3/PageStorageImpl.cpp | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/dbms/src/Common/TiFlashMetrics.h b/dbms/src/Common/TiFlashMetrics.h index 3385b075295..65453ded273 100644 --- a/dbms/src/Common/TiFlashMetrics.h +++ b/dbms/src/Common/TiFlashMetrics.h @@ -160,6 +160,13 @@ namespace DB F(type_v3, {{"type", "v3"}}, ExpBuckets{0.0005, 2, 20})) \ M(tiflash_storage_page_write_batch_size, "The size of each write batch in bytes", Histogram, \ F(type_v3, {{"type", "v3"}}, ExpBuckets{4 * 1024, 4, 10})) \ + M(tiflash_storage_page_write_duration_seconds, "The duration of each write batch", Histogram, \ + F(type_total, {{"type", "total"}}, ExpBuckets{0.0001, 2, 20}), \ + F(type_blob, {{"type", "blob"}}, ExpBuckets{0.0001, 2, 20}), \ + /* the bucket range for apply in memory is 50us ~ 120s */ \ + F(type_latch, {{"type", "latch"}}, ExpBuckets{0.00005, 1.8, 26}), \ + F(type_wal, {{"type", "wal"}}, ExpBuckets{0.00005, 1.8, 26}), \ + F(type_commit, {{"type", "commmit"}}, ExpBuckets{0.00005, 1.8, 26})) \ M(tiflash_storage_logical_throughput_bytes, "The logical throughput of read tasks of storage in bytes", Histogram, \ F(type_read, {{"type", "read"}}, EqualWidthBuckets{1 * 1024 * 1024, 60, 50 * 1024 * 1024})) \ M(tiflash_storage_io_limiter, "Storage I/O limiter metrics", Counter, F(type_fg_read_req_bytes, {"type", "fg_read_req_bytes"}), \ @@ -237,7 +244,7 @@ namespace DB struct ExpBuckets { const double start; - const int base; + const double base; const size_t size; inline operator prometheus::Histogram::BucketBoundaries() const && { diff --git a/dbms/src/Storages/Page/V3/PageDirectory.cpp b/dbms/src/Storages/Page/V3/PageDirectory.cpp index b448728e15f..72b366b1492 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectory.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -1177,10 +1179,13 @@ void PageDirectory::applyRefEditRecord( template void PageDirectory::apply(typename Trait::PageEntriesEdit && edit, const WriteLimiterPtr & write_limiter) { + Stopwatch watch; // Note that we need to make sure increasing `sequence` in order, so it // also needs to be protected by `write_lock` throughout the `apply` // TODO: It is totally serialized, make it a pipeline std::unique_lock write_lock(table_rw_mutex); + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_latch).Observe(watch.elapsedSeconds()); + watch.restart(); UInt64 last_sequence = sequence.load(); PageVersion new_version(last_sequence + 1, 0); @@ -1190,6 +1195,9 @@ void PageDirectory::apply(typename Trait::PageEntriesEdit && edit, const r.version = new_version; } wal->apply(Trait::Serializer::serializeTo(edit), write_limiter); + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_wal).Observe(watch.elapsedSeconds()); + watch.restart(); + SCOPE_EXIT({ GET_METRIC(tiflash_storage_page_write_duration_seconds, type_commit).Observe(watch.elapsedSeconds()); }); // stage 2, create entry version list for page_id. for (const auto & r : edit.getRecords()) diff --git a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp index e5626915dd9..d2553cf3e9a 100644 --- a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp +++ b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp @@ -118,9 +118,12 @@ void PageStorageImpl::writeImpl(DB::WriteBatch && write_batch, const WriteLimite { if (unlikely(write_batch.empty())) return; + Stopwatch watch; + SCOPE_EXIT({ GET_METRIC(tiflash_storage_page_write_duration_seconds, type_total).Observe(watch.elapsedSeconds()); }); // Persist Page data to BlobStore auto edit = blob_store.write(write_batch, write_limiter); + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_blob).Observe(watch.elapsedSeconds()); page_directory->apply(std::move(edit), write_limiter); } From 4d5446bff4d416916cbd3d991d006e74ea17b965 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 2 Nov 2022 18:34:22 +0800 Subject: [PATCH 25/40] fix metric --- dbms/src/Storages/Page/V3/PageStorageImpl.cpp | 3 --- dbms/src/Storages/Page/universal/UniversalPageStorage.cpp | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp index d2553cf3e9a..e5626915dd9 100644 --- a/dbms/src/Storages/Page/V3/PageStorageImpl.cpp +++ b/dbms/src/Storages/Page/V3/PageStorageImpl.cpp @@ -118,12 +118,9 @@ void PageStorageImpl::writeImpl(DB::WriteBatch && write_batch, const WriteLimite { if (unlikely(write_batch.empty())) return; - Stopwatch watch; - SCOPE_EXIT({ GET_METRIC(tiflash_storage_page_write_duration_seconds, type_total).Observe(watch.elapsedSeconds()); }); // Persist Page data to BlobStore auto edit = blob_store.write(write_batch, write_limiter); - GET_METRIC(tiflash_storage_page_write_duration_seconds, type_blob).Observe(watch.elapsedSeconds()); page_directory->apply(std::move(edit), write_limiter); } diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp index 9c08faf28ec..8e4e9653c15 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.cpp @@ -53,7 +53,10 @@ void UniversalPageStorage::write(UniversalWriteBatch && write_batch, const Write if (unlikely(write_batch.empty())) return; + Stopwatch watch; + SCOPE_EXIT({ GET_METRIC(tiflash_storage_page_write_duration_seconds, type_total).Observe(watch.elapsedSeconds()); }); auto edit = blob_store->write(write_batch, write_limiter); + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_blob).Observe(watch.elapsedSeconds()); page_directory->apply(std::move(edit), write_limiter); } From fb2fe26abf867143d1e2739fe63b67e6ec48777f Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 2 Nov 2022 19:22:48 +0800 Subject: [PATCH 26/40] add more metric --- dbms/src/Common/TiFlashMetrics.h | 5 ++++- dbms/src/Storages/Page/V3/BlobStore.cpp | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dbms/src/Common/TiFlashMetrics.h b/dbms/src/Common/TiFlashMetrics.h index 65453ded273..f965631e814 100644 --- a/dbms/src/Common/TiFlashMetrics.h +++ b/dbms/src/Common/TiFlashMetrics.h @@ -166,7 +166,10 @@ namespace DB /* the bucket range for apply in memory is 50us ~ 120s */ \ F(type_latch, {{"type", "latch"}}, ExpBuckets{0.00005, 1.8, 26}), \ F(type_wal, {{"type", "wal"}}, ExpBuckets{0.00005, 1.8, 26}), \ - F(type_commit, {{"type", "commmit"}}, ExpBuckets{0.00005, 1.8, 26})) \ + F(type_commit, {{"type", "commmit"}}, ExpBuckets{0.00005, 1.8, 26}), \ + F(type_edit, {{"type", "edit"}}, ExpBuckets{0.00005, 1.8, 26}), \ + F(type_get_stat, {{"type", "get_stat"}}, ExpBuckets{0.00005, 1.8, 26}), \ + F(type_blob_write, {{"type", "blob_write"}}, ExpBuckets{0.00005, 1.8, 26})) \ M(tiflash_storage_logical_throughput_bytes, "The logical throughput of read tasks of storage in bytes", Histogram, \ F(type_read, {{"type", "read"}}, EqualWidthBuckets{1 * 1024 * 1024, 60, 50 * 1024 * 1024})) \ M(tiflash_storage_io_limiter, "Storage I/O limiter metrics", Counter, F(type_fg_read_req_bytes, {"type", "fg_read_req_bytes"}), \ diff --git a/dbms/src/Storages/Page/V3/BlobStore.cpp b/dbms/src/Storages/Page/V3/BlobStore.cpp index f82d9da714d..6c70faeb2f9 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.cpp +++ b/dbms/src/Storages/Page/V3/BlobStore.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -245,6 +246,7 @@ template typename Trait::PageEntriesEdit BlobStore::write(typename Trait::WriteBatch & wb, const WriteLimiterPtr & write_limiter) { + Stopwatch watch; ProfileEvents::increment(ProfileEvents::PSMWritePages, wb.putWriteCount()); const size_t all_page_data_size = wb.getTotalDataSize(); @@ -390,10 +392,15 @@ BlobStore::write(typename Trait::WriteBatch & wb, const WriteLimiterPtr & ErrorCodes::LOGICAL_ERROR); } + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_edit).Observe(watch.elapsedSeconds()); + watch.restart(); try { auto blob_file = getBlobFile(blob_id); + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_get_stat).Observe(watch.elapsedSeconds()); + watch.restart(); blob_file->write(buffer, offset_in_file, all_page_data_size, write_limiter); + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_blob_write).Observe(watch.elapsedSeconds()); } catch (DB::Exception & e) { From 1ad8bc4f6cf46463885be117d616bca7cc49bba8 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 2 Nov 2022 20:07:24 +0800 Subject: [PATCH 27/40] fix metric --- dbms/src/Storages/Page/V3/BlobStore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/Storages/Page/V3/BlobStore.cpp b/dbms/src/Storages/Page/V3/BlobStore.cpp index 6c70faeb2f9..64749dba9c2 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.cpp +++ b/dbms/src/Storages/Page/V3/BlobStore.cpp @@ -310,6 +310,8 @@ BlobStore::write(typename Trait::WriteBatch & wb, const WriteLimiterPtr & size_t actually_allocated_size = all_page_data_size + replenish_size; auto [blob_id, offset_in_file] = getPosFromStats(actually_allocated_size); + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_get_stat).Observe(watch.elapsedSeconds()); + watch.restart(); size_t offset_in_allocated = 0; @@ -397,8 +399,6 @@ BlobStore::write(typename Trait::WriteBatch & wb, const WriteLimiterPtr & try { auto blob_file = getBlobFile(blob_id); - GET_METRIC(tiflash_storage_page_write_duration_seconds, type_get_stat).Observe(watch.elapsedSeconds()); - watch.restart(); blob_file->write(buffer, offset_in_file, all_page_data_size, write_limiter); GET_METRIC(tiflash_storage_page_write_duration_seconds, type_blob_write).Observe(watch.elapsedSeconds()); } From 0561c2307139261bd300ee62ff913da6ccf70ead Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 2 Nov 2022 22:03:18 +0800 Subject: [PATCH 28/40] add more metric --- dbms/src/Common/TiFlashMetrics.h | 1 + dbms/src/Storages/Page/V3/BlobStore.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/dbms/src/Common/TiFlashMetrics.h b/dbms/src/Common/TiFlashMetrics.h index f965631e814..7757590c9ea 100644 --- a/dbms/src/Common/TiFlashMetrics.h +++ b/dbms/src/Common/TiFlashMetrics.h @@ -169,6 +169,7 @@ namespace DB F(type_commit, {{"type", "commmit"}}, ExpBuckets{0.00005, 1.8, 26}), \ F(type_edit, {{"type", "edit"}}, ExpBuckets{0.00005, 1.8, 26}), \ F(type_get_stat, {{"type", "get_stat"}}, ExpBuckets{0.00005, 1.8, 26}), \ + F(type_get_stat_latch, {{"type", "get_stat_latch"}}, ExpBuckets{0.00005, 1.8, 26}), \ F(type_blob_write, {{"type", "blob_write"}}, ExpBuckets{0.00005, 1.8, 26})) \ M(tiflash_storage_logical_throughput_bytes, "The logical throughput of read tasks of storage in bytes", Histogram, \ F(type_read, {{"type", "read"}}, EqualWidthBuckets{1 * 1024 * 1024, 60, 50 * 1024 * 1024})) \ diff --git a/dbms/src/Storages/Page/V3/BlobStore.cpp b/dbms/src/Storages/Page/V3/BlobStore.cpp index 64749dba9c2..9a2d706bf7b 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.cpp +++ b/dbms/src/Storages/Page/V3/BlobStore.cpp @@ -464,6 +464,7 @@ void BlobStore::remove(const PageEntriesV3 & del_entries) template std::pair BlobStore::getPosFromStats(size_t size) { + Stopwatch watch; BlobStatPtr stat; auto lock_stat = [size, this, &stat]() { @@ -485,6 +486,8 @@ std::pair BlobStore::getPosFromStats(size_t s return stat->lock(); }(); + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_get_stat_latch).Observe(watch.elapsedSeconds()); + // We need to assume that this insert will reduce max_cap. // Because other threads may also be waiting for BlobStats to chooseStat during this time. // If max_cap is not reduced, it may cause the same BlobStat to accept multiple buffers and exceed its max_cap. From 142afe9cd89993389b05e4d6a0d304cd9640949c Mon Sep 17 00:00:00 2001 From: lidezhu Date: Thu, 3 Nov 2022 14:28:05 +0800 Subject: [PATCH 29/40] add more metric --- dbms/src/Common/TiFlashMetrics.h | 4 +++- dbms/src/Storages/Page/V3/BlobStore.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dbms/src/Common/TiFlashMetrics.h b/dbms/src/Common/TiFlashMetrics.h index 7757590c9ea..52235b40456 100644 --- a/dbms/src/Common/TiFlashMetrics.h +++ b/dbms/src/Common/TiFlashMetrics.h @@ -170,7 +170,9 @@ namespace DB F(type_edit, {{"type", "edit"}}, ExpBuckets{0.00005, 1.8, 26}), \ F(type_get_stat, {{"type", "get_stat"}}, ExpBuckets{0.00005, 1.8, 26}), \ F(type_get_stat_latch, {{"type", "get_stat_latch"}}, ExpBuckets{0.00005, 1.8, 26}), \ - F(type_blob_write, {{"type", "blob_write"}}, ExpBuckets{0.00005, 1.8, 26})) \ + F(type_blob_write, {{"type", "blob_write"}}, ExpBuckets{0.00005, 1.8, 26}), \ + F(type_choose_stat, {{"type", "choose_stat"}}, ExpBuckets{0.00005, 1.8, 26}), \ + F(type_lock_stat, {{"type", "lock_stat"}}, ExpBuckets{0.00005, 1.8, 26})) \ M(tiflash_storage_logical_throughput_bytes, "The logical throughput of read tasks of storage in bytes", Histogram, \ F(type_read, {{"type", "read"}}, EqualWidthBuckets{1 * 1024 * 1024, 60, 50 * 1024 * 1024})) \ M(tiflash_storage_io_limiter, "Storage I/O limiter metrics", Counter, F(type_fg_read_req_bytes, {"type", "fg_read_req_bytes"}), \ diff --git a/dbms/src/Storages/Page/V3/BlobStore.cpp b/dbms/src/Storages/Page/V3/BlobStore.cpp index 9a2d706bf7b..ac2b1a06c09 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.cpp +++ b/dbms/src/Storages/Page/V3/BlobStore.cpp @@ -468,9 +468,15 @@ std::pair BlobStore::getPosFromStats(size_t s BlobStatPtr stat; auto lock_stat = [size, this, &stat]() { + Stopwatch watch_inner; auto lock_stats = blob_stats.lock(); BlobFileId blob_file_id = INVALID_BLOBFILE_ID; std::tie(stat, blob_file_id) = blob_stats.chooseStat(size, lock_stats); + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_choose_stat).Observe(watch_inner.elapsedSeconds()); + watch_inner.restart(); + SCOPE_EXIT({ + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_lock_stat).Observe(watch_inner.elapsedSeconds()); + }); if (stat == nullptr) { // No valid stat for putting data with `size`, create a new one From 86feaa8eb778870f9757b8904f3fa2b1de8ec968 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Mon, 7 Nov 2022 15:11:22 +0800 Subject: [PATCH 30/40] try lock less --- dbms/src/Storages/Page/V3/Blob/BlobStat.cpp | 14 +++++++++----- dbms/src/Storages/Page/V3/Blob/BlobStat.h | 7 +++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp index e494b8108d4..57c29fc5d33 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp @@ -157,6 +157,10 @@ BlobStats::BlobStatPtr BlobStats::createStatNotChecking(BlobFileId blob_file_id, /// If creating a new BlobFile, we need to register the BlobFile's path to delegator, so it's necessary to call `addPageFileUsedSize` here. delegator->addPageFileUsedSize({blob_file_id, 0}, 0, path, true); stats_map[path].emplace_back(stat); + if (stats_map_next_index.find(path) == stats_map_next_index.end()) + { + stats_map_next_index[path] = 0; + } return stat; } @@ -216,16 +220,16 @@ std::pair BlobStats::chooseStat(size_t buf_s for (path_iter_idx = 0; path_iter_idx < stats_map.size(); ++path_iter_idx) { // Try to find a suitable stat under current path (path=`stats_iter->first`) - for (const auto & stat : stats_iter->second) + for (size_t i = 0; i < stats_iter->second.size(); i++) { + const auto & stat = (stats_iter->second)[stats_map_next_index[stats_iter->first]]; auto lock = stat->lock(); // TODO: will it bring performance regression? - if (stat->isNormal() - && stat->sm_max_caps >= buf_size - && stat->sm_valid_rate < smallest_valid_rate) + if (stat->isNormal() && stat->sm_max_caps >= buf_size) { - smallest_valid_rate = stat->sm_valid_rate; stat_ptr = stat; + break; } + stats_map_next_index[stats_iter->first] = (stats_map_next_index[stats_iter->first] + 1) % stats_iter->second.size(); } // Already find the available stat under current path. diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.h b/dbms/src/Storages/Page/V3/Blob/BlobStat.h index 20f1565a25b..b214de0e7e6 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.h +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.h @@ -53,6 +53,8 @@ class BlobStats struct BlobStat { + String parent_path; + const BlobFileId id; std::atomic type; @@ -168,7 +170,7 @@ class BlobStats BlobStatPtr blobIdToStat(BlobFileId file_id, bool ignore_not_exist = false); - using StatsMap = std::map>; + using StatsMap = std::map>; StatsMap getStats() const { auto guard = lock(); @@ -196,7 +198,8 @@ class BlobStats BlobFileId roll_id = 1; // Index for selecting next path for creating new blobfile UInt32 stats_map_path_index = 0; - std::map> stats_map; + std::map> stats_map; + std::map stats_map_next_index; }; } // namespace DB::PS::V3 From 0d4e5f6fffbd6950918e87a2eb582a932efa6acf Mon Sep 17 00:00:00 2001 From: lidezhu Date: Mon, 7 Nov 2022 15:29:02 +0800 Subject: [PATCH 31/40] fix build --- dbms/src/Storages/Page/V3/Blob/BlobStat.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp index 57c29fc5d33..2c7e340f4fa 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp @@ -167,7 +167,10 @@ BlobStats::BlobStatPtr BlobStats::createStatNotChecking(BlobFileId blob_file_id, void BlobStats::eraseStat(const BlobStatPtr && stat, const std::lock_guard &) { PageFileIdAndLevel id_lvl{stat->id, 0}; - stats_map[delegator->getPageFilePath(id_lvl)].remove(stat); + auto & stats = stats_map[delegator->getPageFilePath(id_lvl)]; + auto iter = std::find(stats.begin(), stats.end(), stat); + assert(iter != stats.end()); + stats.erase(iter); } void BlobStats::eraseStat(BlobFileId blob_file_id, const std::lock_guard & lock) @@ -201,7 +204,6 @@ void BlobStats::eraseStat(BlobFileId blob_file_id, const std::lock_guard BlobStats::chooseStat(size_t buf_size, const std::lock_guard &) { BlobStatPtr stat_ptr = nullptr; - double smallest_valid_rate = 2; // No stats exist if (stats_map.empty()) From b59a9f8524c2bc63219d52b8c21049a0beb545fa Mon Sep 17 00:00:00 2001 From: lidezhu Date: Mon, 7 Nov 2022 16:51:40 +0800 Subject: [PATCH 32/40] increase gc time --- dbms/src/Interpreters/Context.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index 67cfd068836..e3e7cc3fd12 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -121,8 +121,7 @@ struct UniversalPageStorageWrapper [this, global_context] { return this->uni_page_storage->gc(); }, - false, - 1000); + false); } }; using UniversalPageStorageWrapperPtr = std::shared_ptr; From e4509c5682da689339bf1eb424abacef17d21a16 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Mon, 7 Nov 2022 16:54:51 +0800 Subject: [PATCH 33/40] fix crash --- dbms/src/Storages/Page/V3/Blob/BlobStat.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp index 2c7e340f4fa..51d51ee8033 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp @@ -224,6 +224,7 @@ std::pair BlobStats::chooseStat(size_t buf_s // Try to find a suitable stat under current path (path=`stats_iter->first`) for (size_t i = 0; i < stats_iter->second.size(); i++) { + stats_map_next_index[stats_iter->first] = stats_map_next_index[stats_iter->first] % stats_iter->second.size(); const auto & stat = (stats_iter->second)[stats_map_next_index[stats_iter->first]]; auto lock = stat->lock(); // TODO: will it bring performance regression? if (stat->isNormal() && stat->sm_max_caps >= buf_size) @@ -231,7 +232,7 @@ std::pair BlobStats::chooseStat(size_t buf_s stat_ptr = stat; break; } - stats_map_next_index[stats_iter->first] = (stats_map_next_index[stats_iter->first] + 1) % stats_iter->second.size(); + stats_map_next_index[stats_iter->first] += 1; } // Already find the available stat under current path. From effeb076d96ba601655bf4c664d612febf07e1ff Mon Sep 17 00:00:00 2001 From: lidezhu Date: Tue, 8 Nov 2022 17:37:58 +0800 Subject: [PATCH 34/40] try reduce lock contention --- dbms/src/Storages/Page/V3/Blob/BlobStat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp index 51d51ee8033..3fc9a44357c 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp @@ -226,13 +226,13 @@ std::pair BlobStats::chooseStat(size_t buf_s { stats_map_next_index[stats_iter->first] = stats_map_next_index[stats_iter->first] % stats_iter->second.size(); const auto & stat = (stats_iter->second)[stats_map_next_index[stats_iter->first]]; + stats_map_next_index[stats_iter->first] += 1; auto lock = stat->lock(); // TODO: will it bring performance regression? if (stat->isNormal() && stat->sm_max_caps >= buf_size) { stat_ptr = stat; break; } - stats_map_next_index[stats_iter->first] += 1; } // Already find the available stat under current path. From 8045678b114a85e4893d5aff5686cbf6df0b2dd8 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Tue, 8 Nov 2022 17:42:34 +0800 Subject: [PATCH 35/40] try increase gc interval --- dbms/src/Interpreters/Context.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index e3e7cc3fd12..a904bdb92c0 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -113,16 +113,28 @@ struct UniversalPageStorageWrapper { UniversalPageStoragePtr uni_page_storage; BackgroundProcessingPool::TaskHandle gc_handle; + std::atomic last_try_gc_time = Clock::now(); void restore(Context & global_context) { uni_page_storage->restore(); gc_handle = global_context.getBackgroundPool().addTask( [this, global_context] { - return this->uni_page_storage->gc(); + return this->gc(); }, false); } + + bool gc() + { + Timepoint now = Clock::now(); + const std::chrono::seconds try_gc_period(60); + if (now < (last_try_gc_time.load() + try_gc_period)) + return false; + + last_try_gc_time = now; + return this->uni_page_storage->gc(); + } }; using UniversalPageStorageWrapperPtr = std::shared_ptr; From 81031a6e52110cd963723fb4a540e9d22ff58375 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 9 Nov 2022 16:58:57 +0800 Subject: [PATCH 36/40] try improve gc logic --- contrib/tiflash-proxy | 2 +- dbms/src/Storages/Page/V3/Blob/BlobStat.cpp | 27 ++++--------- dbms/src/Storages/Page/V3/PageDirectory.cpp | 13 +++++++ dbms/src/Storages/Page/V3/PageDirectory.h | 2 + .../Page/universal/UniversalPageStorage.h | 5 +++ dbms/src/Storages/Transaction/ProxyFFI.cpp | 39 +++++++++++++++++++ dbms/src/Storages/Transaction/ProxyFFI.h | 4 ++ 7 files changed, 71 insertions(+), 21 deletions(-) diff --git a/contrib/tiflash-proxy b/contrib/tiflash-proxy index 3f83bff2378..4a4606fade6 160000 --- a/contrib/tiflash-proxy +++ b/contrib/tiflash-proxy @@ -1 +1 @@ -Subproject commit 3f83bff237851ff24edce7fbb6258685690905d4 +Subproject commit 4a4606fade6109bb766c05908f7c9e59a539fb21 diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp index 3fc9a44357c..b455f3563e4 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp @@ -18,6 +18,7 @@ #include #include +#include "ext/scope_guard.h" namespace ProfileEvents { @@ -203,8 +204,6 @@ void BlobStats::eraseStat(BlobFileId blob_file_id, const std::lock_guard BlobStats::chooseStat(size_t buf_size, const std::lock_guard &) { - BlobStatPtr stat_ptr = nullptr; - // No stats exist if (stats_map.empty()) { @@ -219,6 +218,10 @@ std::pair BlobStats::chooseStat(size_t buf_s std::advance(stats_iter, stats_map_path_index); size_t path_iter_idx = 0; + SCOPE_EXIT({ + // advance the `stats_map_path_idx` without size checking + stats_map_path_index += path_iter_idx + 1; + }); for (path_iter_idx = 0; path_iter_idx < stats_map.size(); ++path_iter_idx) { // Try to find a suitable stat under current path (path=`stats_iter->first`) @@ -230,17 +233,10 @@ std::pair BlobStats::chooseStat(size_t buf_s auto lock = stat->lock(); // TODO: will it bring performance regression? if (stat->isNormal() && stat->sm_max_caps >= buf_size) { - stat_ptr = stat; - break; + return std::make_pair(stat, INVALID_BLOBFILE_ID); } } - // Already find the available stat under current path. - if (stat_ptr != nullptr) - { - break; - } - // Try to find stat in the next path. stats_iter++; if (stats_iter == stats_map.end()) @@ -249,16 +245,7 @@ std::pair BlobStats::chooseStat(size_t buf_s } } - // advance the `stats_map_path_idx` without size checking - stats_map_path_index += path_iter_idx + 1; - - // Can not find a suitable stat under all paths - if (stat_ptr == nullptr) - { - return std::make_pair(nullptr, roll_id); - } - - return std::make_pair(stat_ptr, INVALID_BLOBFILE_ID); + return std::make_pair(nullptr, roll_id); } BlobStats::BlobStatPtr BlobStats::blobIdToStat(BlobFileId file_id, bool ignore_not_exist) diff --git a/dbms/src/Storages/Page/V3/PageDirectory.cpp b/dbms/src/Storages/Page/V3/PageDirectory.cpp index 72b366b1492..cd890937398 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.cpp +++ b/dbms/src/Storages/Page/V3/PageDirectory.cpp @@ -1075,6 +1075,19 @@ typename Trait::PageIdSet PageDirectory::getRangePageIds(const typename T return page_ids; } +template +typename Trait::PageIds PageDirectory::getLowerBound(const typename Trait::PageId & start) +{ + typename Trait::PageIds page_ids; + + std::shared_lock read_lock(table_rw_mutex); + if (auto iter = mvcc_table_directory.lower_bound(start); iter != mvcc_table_directory.end()) + { + page_ids.emplace_back(iter->first); + } + return page_ids; +} + template void PageDirectory::applyRefEditRecord( MVCCMapType & mvcc_table_directory, diff --git a/dbms/src/Storages/Page/V3/PageDirectory.h b/dbms/src/Storages/Page/V3/PageDirectory.h index e2c6c12de74..c3185f94bfa 100644 --- a/dbms/src/Storages/Page/V3/PageDirectory.h +++ b/dbms/src/Storages/Page/V3/PageDirectory.h @@ -312,6 +312,8 @@ class PageDirectory typename Trait::PageIdSet getRangePageIds(const typename Trait::PageId & start, const typename Trait::PageId & end); + typename Trait::PageIds getLowerBound(const typename Trait::PageId & start); + void apply(typename Trait::PageEntriesEdit && edit, const WriteLimiterPtr & write_limiter = nullptr); std::pair diff --git a/dbms/src/Storages/Page/universal/UniversalPageStorage.h b/dbms/src/Storages/Page/universal/UniversalPageStorage.h index 16ac8db08dc..f8088ff7dbe 100644 --- a/dbms/src/Storages/Page/universal/UniversalPageStorage.h +++ b/dbms/src/Storages/Page/universal/UniversalPageStorage.h @@ -289,6 +289,11 @@ class RaftLogReader final } } + UniversalPageIds getLowerBound(const UniversalPageId & page_id) + { + return uni_storage.page_directory->getLowerBound(page_id); + } + private: UniversalPageStorage & uni_storage; }; diff --git a/dbms/src/Storages/Transaction/ProxyFFI.cpp b/dbms/src/Storages/Transaction/ProxyFFI.cpp index a36e705b3a5..892648c9e54 100644 --- a/dbms/src/Storages/Transaction/ProxyFFI.cpp +++ b/dbms/src/Storages/Transaction/ProxyFFI.cpp @@ -300,6 +300,45 @@ void GcPageWithViewVec(PageWithView * inner, uint64_t len) delete inner; } +void PurgePageStorage(const EngineStoreServerWrap * server) +{ + try + { + auto uni_ps = server->tmt->getContext().getGlobalUniversalPageStorage(); + uni_ps->gc(); + } + catch (...) + { + tryLogCurrentException(__PRETTY_FUNCTION__); + exit(-1); + } +} + +CppStrWithView SeekPSKey(const EngineStoreServerWrap * server, BaseBuffView raw_page_id) +{ + try + { + auto uni_ps = server->tmt->getContext().getGlobalUniversalPageStorage(); + RaftLogReader reader(*uni_ps); + UniversalPageId page_id{raw_page_id.data, raw_page_id.len}; + auto page_ids = reader.getLowerBound(page_id); + if (page_ids.empty()) + { + return CppStrWithView{.inner = GenRawCppPtr(), .view = BaseBuffView{}}; + } + else + { + auto * s = RawCppString::New(page_ids[0]); + return CppStrWithView{.inner = GenRawCppPtr(s, RawCppPtrTypeImpl::String), .view = BaseBuffView{s->data(), s->size()}}; + } + } + catch (...) + { + tryLogCurrentException(__PRETTY_FUNCTION__); + exit(-1); + } +} + static_assert(sizeof(RaftStoreProxyFFIHelper) == sizeof(TiFlashRaftProxyHelper)); static_assert(alignof(RaftStoreProxyFFIHelper) == alignof(TiFlashRaftProxyHelper)); diff --git a/dbms/src/Storages/Transaction/ProxyFFI.h b/dbms/src/Storages/Transaction/ProxyFFI.h index 66053421616..0ae27b1e16a 100644 --- a/dbms/src/Storages/Transaction/ProxyFFI.h +++ b/dbms/src/Storages/Transaction/ProxyFFI.h @@ -140,6 +140,8 @@ void ConsumeWriteBatch(const EngineStoreServerWrap * server, RawVoidPtr ptr); PageWithView HandleReadPage(const EngineStoreServerWrap * server, BaseBuffView page_id); PageWithViewVec HandleScanPage(const EngineStoreServerWrap * server, BaseBuffView start_page_id, BaseBuffView end_page_id); void GcPageWithViewVec(PageWithView * inner, uint64_t len); +void PurgePageStorage(const EngineStoreServerWrap * server); +CppStrWithView SeekPSKey(const EngineStoreServerWrap * server, BaseBuffView raw_page_id); void AtomicUpdateProxy(EngineStoreServerWrap * server, RaftStoreProxyFFIHelper * proxy); void HandleDestroy(EngineStoreServerWrap * server, uint64_t region_id); EngineStoreApplyRes HandleIngestSST(EngineStoreServerWrap * server, SSTViewVec snaps, RaftCmdHeader header); @@ -187,6 +189,8 @@ inline EngineStoreServerHelper GetEngineStoreServerHelper( .fn_handle_read_page = HandleReadPage, .fn_handle_scan_page = HandleScanPage, .fn_gc_page_with_view_vec = GcPageWithViewVec, + .fn_handle_purge_pagestorage = PurgePageStorage, + .fn_handle_seek_ps_key = SeekPSKey, .fn_atomic_update_proxy = AtomicUpdateProxy, .fn_handle_destroy = HandleDestroy, .fn_handle_ingest_sst = HandleIngestSST, From 53febb7603671704bf280ea7c0243791a4d431e0 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 9 Nov 2022 18:14:33 +0800 Subject: [PATCH 37/40] decrease gc interval to 10s --- dbms/src/Interpreters/Context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index a904bdb92c0..047f7168891 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -128,7 +128,7 @@ struct UniversalPageStorageWrapper bool gc() { Timepoint now = Clock::now(); - const std::chrono::seconds try_gc_period(60); + const std::chrono::seconds try_gc_period(10); if (now < (last_try_gc_time.load() + try_gc_period)) return false; From e95765c1bff1ef60aec3fe9db5ba7d0ef1795e73 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 9 Nov 2022 19:05:40 +0800 Subject: [PATCH 38/40] try remove unnecessary delete --- contrib/tiflash-proxy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/tiflash-proxy b/contrib/tiflash-proxy index 4a4606fade6..ae5205414b7 160000 --- a/contrib/tiflash-proxy +++ b/contrib/tiflash-proxy @@ -1 +1 @@ -Subproject commit 4a4606fade6109bb766c05908f7c9e59a539fb21 +Subproject commit ae5205414b7b8c3b6eee6307026cab2f716f46b2 From 86eb27e8c5c5f60cea465631808b6cb579a3f143 Mon Sep 17 00:00:00 2001 From: lidezhu Date: Wed, 9 Nov 2022 22:10:34 +0800 Subject: [PATCH 39/40] add more metric --- dbms/src/Common/TiFlashMetrics.h | 3 ++- dbms/src/Storages/Page/V3/Blob/BlobStat.cpp | 2 +- dbms/src/Storages/Page/V3/BlobStore.cpp | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dbms/src/Common/TiFlashMetrics.h b/dbms/src/Common/TiFlashMetrics.h index 52235b40456..45780510757 100644 --- a/dbms/src/Common/TiFlashMetrics.h +++ b/dbms/src/Common/TiFlashMetrics.h @@ -172,7 +172,8 @@ namespace DB F(type_get_stat_latch, {{"type", "get_stat_latch"}}, ExpBuckets{0.00005, 1.8, 26}), \ F(type_blob_write, {{"type", "blob_write"}}, ExpBuckets{0.00005, 1.8, 26}), \ F(type_choose_stat, {{"type", "choose_stat"}}, ExpBuckets{0.00005, 1.8, 26}), \ - F(type_lock_stat, {{"type", "lock_stat"}}, ExpBuckets{0.00005, 1.8, 26})) \ + F(type_lock_stat, {{"type", "lock_stat"}}, ExpBuckets{0.00005, 1.8, 26}), \ + F(type_get_pos_from_stat, {{"type", "get_pos_from_stat"}}, ExpBuckets{0.00005, 1.8, 26})) \ M(tiflash_storage_logical_throughput_bytes, "The logical throughput of read tasks of storage in bytes", Histogram, \ F(type_read, {{"type", "read"}}, EqualWidthBuckets{1 * 1024 * 1024, 60, 50 * 1024 * 1024})) \ M(tiflash_storage_io_limiter, "Storage I/O limiter metrics", Counter, F(type_fg_read_req_bytes, {"type", "fg_read_req_bytes"}), \ diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp index b455f3563e4..ab8930327a2 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp @@ -284,7 +284,7 @@ BlobFileOffset BlobStats::BlobStat::getPosFromStat(size_t buf_size, const std::l bool expansion = true; std::tie(offset, max_cap, expansion) = smap->searchInsertOffset(buf_size); - ProfileEvents::increment(expansion ? ProfileEvents::PSV3MBlobExpansion : ProfileEvents::PSV3MBlobReused); +// ProfileEvents::increment(expansion ? ProfileEvents::PSV3MBlobExpansion : ProfileEvents::PSV3MBlobReused); /** * Whatever `searchInsertOffset` success or failed, diff --git a/dbms/src/Storages/Page/V3/BlobStore.cpp b/dbms/src/Storages/Page/V3/BlobStore.cpp index ac2b1a06c09..01ce819c78e 100644 --- a/dbms/src/Storages/Page/V3/BlobStore.cpp +++ b/dbms/src/Storages/Page/V3/BlobStore.cpp @@ -493,6 +493,10 @@ std::pair BlobStore::getPosFromStats(size_t s }(); GET_METRIC(tiflash_storage_page_write_duration_seconds, type_get_stat_latch).Observe(watch.elapsedSeconds()); + watch.restart(); + SCOPE_EXIT({ + GET_METRIC(tiflash_storage_page_write_duration_seconds, type_get_pos_from_stat).Observe(watch.elapsedSeconds()); + }); // We need to assume that this insert will reduce max_cap. // Because other threads may also be waiting for BlobStats to chooseStat during this time. From d7bf188465aa2ea2affab46210e8fc11d384217b Mon Sep 17 00:00:00 2001 From: lidezhu Date: Thu, 10 Nov 2022 09:13:16 +0800 Subject: [PATCH 40/40] try use unique_lock --- dbms/src/Storages/Page/V3/Blob/BlobStat.cpp | 8 ++++---- dbms/src/Storages/Page/V3/Blob/BlobStat.h | 13 +++++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp index ab8930327a2..1377bb63ab4 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.cpp @@ -230,8 +230,8 @@ std::pair BlobStats::chooseStat(size_t buf_s stats_map_next_index[stats_iter->first] = stats_map_next_index[stats_iter->first] % stats_iter->second.size(); const auto & stat = (stats_iter->second)[stats_map_next_index[stats_iter->first]]; stats_map_next_index[stats_iter->first] += 1; - auto lock = stat->lock(); // TODO: will it bring performance regression? - if (stat->isNormal() && stat->sm_max_caps >= buf_size) + auto lock = stat->defer_lock(); // TODO: will it bring performance regression? + if (lock.try_lock() && stat->isNormal() && stat->sm_max_caps >= buf_size) { return std::make_pair(stat, INVALID_BLOBFILE_ID); } @@ -277,7 +277,7 @@ BlobStats::BlobStatPtr BlobStats::blobIdToStat(BlobFileId file_id, bool ignore_n * BlobStat methods * ********************/ -BlobFileOffset BlobStats::BlobStat::getPosFromStat(size_t buf_size, const std::lock_guard &) +BlobFileOffset BlobStats::BlobStat::getPosFromStat(size_t buf_size, const std::unique_lock &) { BlobFileOffset offset = 0; UInt64 max_cap = 0; @@ -315,7 +315,7 @@ BlobFileOffset BlobStats::BlobStat::getPosFromStat(size_t buf_size, const std::l return offset; } -size_t BlobStats::BlobStat::removePosFromStat(BlobFileOffset offset, size_t buf_size, const std::lock_guard &) +size_t BlobStats::BlobStat::removePosFromStat(BlobFileOffset offset, size_t buf_size, const std::unique_lock &) { if (!smap->markFree(offset, buf_size)) { diff --git a/dbms/src/Storages/Page/V3/Blob/BlobStat.h b/dbms/src/Storages/Page/V3/Blob/BlobStat.h index b214de0e7e6..4e0a5b9d87b 100644 --- a/dbms/src/Storages/Page/V3/Blob/BlobStat.h +++ b/dbms/src/Storages/Page/V3/Blob/BlobStat.h @@ -81,9 +81,14 @@ class BlobStats , sm_max_caps(sm_max_caps_) {} - [[nodiscard]] std::lock_guard lock() + [[nodiscard]] std::unique_lock lock() { - return std::lock_guard(sm_lock); + return std::unique_lock(sm_lock); + } + + [[nodiscard]] std::unique_lock defer_lock() + { + return std::unique_lock(sm_lock, std::defer_lock); } bool isNormal() const @@ -101,12 +106,12 @@ class BlobStats type.store(BlobStatType::READ_ONLY); } - BlobFileOffset getPosFromStat(size_t buf_size, const std::lock_guard &); + BlobFileOffset getPosFromStat(size_t buf_size, const std::unique_lock &); /** * The return value is the valid data size remained in the BlobFile after the remove */ - size_t removePosFromStat(BlobFileOffset offset, size_t buf_size, const std::lock_guard &); + size_t removePosFromStat(BlobFileOffset offset, size_t buf_size, const std::unique_lock &); /** * This method is only used when blobstore restore