/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX STORAGETEST #include #define protected public #define private public #include "mittest/mtlenv/mock_tenant_module_env.h" #include "mittest/shared_storage/clean_residual_data.h" namespace oceanbase { namespace storage { using namespace oceanbase::common; class TestSSPhysicalBlockManager : public ::testing::Test { public: TestSSPhysicalBlockManager() {} virtual ~TestSSPhysicalBlockManager() {} static void SetUpTestCase(); static void TearDownTestCase(); virtual void SetUp(); virtual void TearDown(); int serialize_super_block(char *buf, const int64_t buf_size, const ObSSMicroCacheSuperBlock &super_block); int deserialize_super_block(char *buf, const int64_t buf_size, ObSSMicroCacheSuperBlock &super_block); void check_super_block_identical( const ObSSMicroCacheSuperBlock &super_block1, const ObSSMicroCacheSuperBlock &super_block2); void check_phy_block_reserve_cnt(const int64_t expect_cnt, const ObSSPhyBlockType type); public: class TestSSPhyBlockMgrThread : public Threads { public: enum class TestParallelType { TEST_PARALLEL_ALLOCATE_BLOCK, TEST_PARALLEL_ALLOCATE_BLOCK_AND_CHECK_REUSE_VERSION, TEST_PARALLEL_ALLOCATE_BLOCK_AND_RESIZE, }; public: TestSSPhyBlockMgrThread(ObTenantBase *tenant_base, ObSSPhysicalBlockManager *phy_blk_mgr, int64_t normal_blk_cnt, int64_t phy_ckpt_blk_cnt, int64_t micro_ckpt_blk_cnt, int64_t reorgan_blk_cnt, TestParallelType type) : tenant_base_(tenant_base), phy_blk_mgr_(phy_blk_mgr), data_blk_cnt_(normal_blk_cnt), phy_ckpt_blk_cnt_(phy_ckpt_blk_cnt), micro_ckpt_blk_cnt_(micro_ckpt_blk_cnt), reorgan_blk_cnt_(reorgan_blk_cnt), ori_total_file_size_(phy_blk_mgr->total_file_size_), type_(type), fail_cnt_(0) {} void run(int64_t idx) final { ObTenantEnv::set_tenant(tenant_base_); if (type_ == TestParallelType::TEST_PARALLEL_ALLOCATE_BLOCK) { parallel_allocate_block(idx); } else if (type_ == TestParallelType::TEST_PARALLEL_ALLOCATE_BLOCK_AND_CHECK_REUSE_VERSION) { parallel_allocate_block_and_check_reuse_version(idx); } else if (type_ == TestParallelType::TEST_PARALLEL_ALLOCATE_BLOCK_AND_RESIZE) { parallel_allocate_block_and_resize(idx); } } int64_t get_fail_cnt() { return ATOMIC_LOAD(&fail_cnt_); } private: int parallel_allocate_block(int64_t idx) { int ret = OB_SUCCESS; int64_t blk_cnt = 0; ObSSPhyBlockType blk_type = ObSSPhyBlockType::SS_INVALID_BLK_TYPE; if (idx < 5) { blk_cnt = data_blk_cnt_; blk_type = ObSSPhyBlockType::SS_CACHE_DATA_BLK; } else if (idx < 10) { blk_cnt = micro_ckpt_blk_cnt_; blk_type = ObSSPhyBlockType::SS_MICRO_META_CKPT_BLK; } else if (idx < 11) { blk_cnt = phy_ckpt_blk_cnt_; blk_type = ObSSPhyBlockType::SS_PHY_BLOCK_CKPT_BLK; } else { blk_cnt = reorgan_blk_cnt_; blk_type = ObSSPhyBlockType::SS_REORGAN_BLK; } int64_t block_idx = -1; ObArray block_idx_arr; bool succ_free = false; for (int64_t i = 0; OB_SUCC(ret) && i < blk_cnt; i++) { ObSSPhysicalBlockHandle phy_block_handle; if (OB_FAIL(phy_blk_mgr_->alloc_block(block_idx, phy_block_handle, blk_type))) { LOG_WARN("fail to allocate block", KR(ret)); } else if (OB_FAIL(block_idx_arr.push_back(block_idx))) { LOG_WARN("fail to push back block_idx", KR(ret), K(block_idx)); } else { phy_block_handle.get_ptr()->is_sealed_ = true; } } for (int64_t i = 0; OB_SUCC(ret) && i < blk_cnt; i++) { block_idx = block_idx_arr[i]; if (OB_FAIL(phy_blk_mgr_->add_reusable_block(block_idx))) { LOG_WARN("fail to add block into reusable_set", KR(ret), K(block_idx)); } else if (OB_FAIL(phy_blk_mgr_->free_block(block_idx, succ_free)) || (succ_free != true)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to allocate block", KR(ret), K(block_idx), K(succ_free)); } } if (OB_FAIL(ret)) { ATOMIC_INC(&fail_cnt_); } return ret; } int parallel_allocate_block_and_check_reuse_version(int64_t idx) { int ret = OB_SUCCESS; int64_t block_idx = -1; common::ObArray block_idx_arr; bool succ_free = false; for (int64_t epoch = 0; OB_SUCC(ret) && epoch < 10; epoch++) { for (int64_t i = 0; OB_SUCC(ret) && i < data_blk_cnt_; i++) { ObSSPhysicalBlockHandle phy_block_handle; if (OB_FAIL( phy_blk_mgr_->alloc_block(block_idx, phy_block_handle, ObSSPhyBlockType::SS_CACHE_DATA_BLK))) { LOG_WARN("fail to allocate block", KR(ret)); } else if (OB_FAIL(block_idx_arr.push_back(block_idx))) { LOG_WARN("fail to push back block_idx", KR(ret), K(block_idx)); } else { phy_block_handle.get_ptr()->is_sealed_ = true; } } for (int64_t i = 0; OB_SUCC(ret) && i < block_idx_arr.count(); i++) { block_idx = block_idx_arr[i]; if (OB_FAIL(phy_blk_mgr_->add_reusable_block(block_idx))) { LOG_WARN("fail to add block into reusable_set", KR(ret), K(block_idx)); } else if (OB_FAIL(phy_blk_mgr_->free_block(block_idx, succ_free)) && (succ_free != true)) { LOG_WARN("fail to allocate block", KR(ret), K(block_idx), K(succ_free)); } } block_idx_arr.reuse(); } if (OB_FAIL(ret)) { ATOMIC_INC(&fail_cnt_); } return ret; } int parallel_allocate_block_and_resize(int64_t idx) { int ret = OB_SUCCESS; int64_t block_idx = -1; common::ObArray phy_block_arr; common::ObArray block_idx_arr; if (idx >= 5) { for (int64_t i = 0; OB_SUCC(ret) && i < data_blk_cnt_; i++) { ObSSPhysicalBlockHandle phy_block_handle; if (OB_FAIL(phy_blk_mgr_->alloc_block(block_idx, phy_block_handle, ObSSPhyBlockType::SS_CACHE_DATA_BLK))) { LOG_WARN("fail to allocate block", KR(ret), K(block_idx)); } else if (OB_FAIL(block_idx_arr.push_back(block_idx))) { LOG_WARN("fail to push back block idx", KR(ret), K(block_idx)); } else if (OB_FAIL(phy_block_arr.push_back(phy_block_handle.get_ptr()))) { LOG_WARN("fail to push back phy_block", KR(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < block_idx_arr.count(); i++) { block_idx = block_idx_arr[i]; ObSSPhysicalBlockHandle phy_block_handle; if (OB_FAIL(phy_blk_mgr_->get_block_handle(block_idx, phy_block_handle))) { LOG_WARN("fail to get block handle", KR(ret), K(block_idx)); } else if (phy_block_handle.get_ptr() != phy_block_arr[i]) { ret = OB_ERR_UNEXPECTED; LOG_WARN("phy_block not match", KR(ret), KP(phy_block_handle.get_ptr()), KP(phy_block_arr[i])); } } } else { int64_t new_file_size = 1L * (idx + 1) * ori_total_file_size_; // may fail for resizing smaller, ignore it. phy_blk_mgr_->resize_file_size(new_file_size, phy_blk_mgr_->block_size_); } if (OB_FAIL(ret)) { ATOMIC_INC(&fail_cnt_); } return ret; } private: ObTenantBase *tenant_base_; ObSSPhysicalBlockManager *phy_blk_mgr_; int64_t data_blk_cnt_; int64_t phy_ckpt_blk_cnt_; int64_t micro_ckpt_blk_cnt_; int64_t reorgan_blk_cnt_; int64_t ori_total_file_size_; TestParallelType type_; int64_t fail_cnt_; }; }; void TestSSPhysicalBlockManager::SetUpTestCase() { GCTX.startup_mode_ = observer::ObServerMode::SHARED_STORAGE_MODE; EXPECT_EQ(OB_SUCCESS, MockTenantModuleEnv::get_instance().init()); } void TestSSPhysicalBlockManager::TearDownTestCase() { int ret = OB_SUCCESS; if (OB_FAIL(ResidualDataCleanerHelper::clean_in_mock_env())) { LOG_WARN("failed to clean residual data", KR(ret)); } MockTenantModuleEnv::get_instance().destroy(); } void TestSSPhysicalBlockManager::SetUp() { ObSSMicroCache *micro_cache = MTL(ObSSMicroCache *); micro_cache->stop(); micro_cache->wait(); micro_cache->destroy(); ASSERT_EQ(OB_SUCCESS, micro_cache->init(MTL_ID(), (1L << 32))); micro_cache->start(); } void TestSSPhysicalBlockManager::TearDown() { ObSSMicroCache *micro_cache = MTL(ObSSMicroCache*); ASSERT_NE(nullptr, micro_cache); micro_cache->stop(); micro_cache->wait(); micro_cache->destroy(); } int TestSSPhysicalBlockManager::serialize_super_block( char *buf, const int64_t buf_size, const ObSSMicroCacheSuperBlock &super_block) { int ret = OB_SUCCESS; ObSSPhyBlockCommonHeader common_header; int64_t pos = common_header.header_size_; if (OB_UNLIKELY(nullptr == buf || buf_size <= common_header.header_size_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), KP(buf), K(buf_size)); } else if (OB_FAIL(super_block.serialize(buf, buf_size, pos))) { LOG_WARN("fail to serialize super_block", KR(ret), KP(buf), K(buf_size), K(pos)); } else { common_header.set_payload_size(pos - common_header.header_size_); common_header.set_block_type(ObSSPhyBlockType::SS_SUPER_BLK); common_header.calc_payload_checksum(buf + common_header.header_size_, common_header.payload_size_); pos = 0; if (OB_FAIL(common_header.serialize(buf, buf_size, pos))) { LOG_WARN("fail to serialize common header", KR(ret), KP(buf), K(buf_size), K(pos)); } else if (OB_UNLIKELY(pos != common_header.header_size_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("pos is wrong", KR(ret), K(pos), K_(common_header.header_size)); } } return ret; } int TestSSPhysicalBlockManager::deserialize_super_block( char *buf, const int64_t buf_size, ObSSMicroCacheSuperBlock &super_block) { int ret = OB_SUCCESS; int64_t pos = 0; ObSSPhyBlockCommonHeader common_header; ObSSMicroCacheSuperBlock tmp_super_blk; if (OB_UNLIKELY(nullptr == buf || buf_size <= common_header.header_size_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), KP(buf), K(buf_size)); } else if (OB_FAIL(common_header.deserialize(buf, buf_size, pos))) { LOG_WARN("fail to deserialize common header", KR(ret), KP(buf), K(buf_size), K(pos)); } else if (OB_UNLIKELY(common_header.header_size_ != pos)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("deserialized pos is unexpected", KR(ret), K(common_header), K(pos)); } else if (OB_UNLIKELY(!common_header.is_valid() || (!common_header.is_super_blk()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("deserialized common header is invalid or wrong type", KR(ret), K(common_header)); } else if (OB_FAIL(common_header.check_payload_checksum(buf + pos, common_header.payload_size_))) { LOG_WARN("fail to check common header payload checksum", KR(ret), K(common_header), KP(buf), K(pos)); } else if (OB_FAIL(tmp_super_blk.deserialize(buf, buf_size, pos))) { LOG_WARN("fail to deserialize super_block", KR(ret), KP(buf), K(buf_size), K(pos)); } else if (OB_UNLIKELY(!tmp_super_blk.is_valid())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("deserialized super_block is invalid", KR(ret), K(tmp_super_blk), K(pos)); } else { super_block = tmp_super_blk; } return ret; } void TestSSPhysicalBlockManager::check_super_block_identical( const ObSSMicroCacheSuperBlock &super_block1, const ObSSMicroCacheSuperBlock &super_block2) { ASSERT_EQ(super_block1.micro_ckpt_time_us_, super_block2.micro_ckpt_time_us_); ASSERT_EQ(super_block1.cache_file_size_, super_block2.cache_file_size_); ASSERT_EQ(super_block1.modify_time_us_, super_block2.modify_time_us_); ASSERT_EQ(super_block1.micro_ckpt_entry_list_.count(), super_block2.micro_ckpt_entry_list_.count()); for (int64_t i = 0; i < super_block2.micro_ckpt_entry_list_.count(); ++i) { ASSERT_EQ(super_block1.micro_ckpt_entry_list_[i], super_block2.micro_ckpt_entry_list_[i]); } ASSERT_EQ(super_block1.blk_ckpt_entry_list_.count(), super_block2.blk_ckpt_entry_list_.count()); for (int64_t i = 0; i < super_block2.blk_ckpt_entry_list_.count(); ++i) { ASSERT_EQ(super_block1.blk_ckpt_entry_list_[i], super_block2.blk_ckpt_entry_list_[i]); } } TEST_F(TestSSPhysicalBlockManager, physical_block) { ObSSPhysicalBlockManager &phy_blk_mgr = MTL(ObSSMicroCache *)->phy_blk_mgr_; ObSSMicroCacheStat &cache_stat = phy_blk_mgr.cache_stat_; SSPhyBlockCntInfo &blk_cnt_info = phy_blk_mgr.blk_cnt_info_; ASSERT_EQ(true, blk_cnt_info.is_valid()); ASSERT_LT(0, blk_cnt_info.total_blk_cnt_); ASSERT_EQ(blk_cnt_info.total_blk_cnt_, blk_cnt_info.super_blk_cnt_ + blk_cnt_info.shared_blk_cnt_ + blk_cnt_info.phy_ckpt_blk_cnt_); const int64_t data_blk_min_cnt = MAX(blk_cnt_info.reorgan_blk_cnt_, blk_cnt_info.shared_blk_cnt_ * MIN_CACHE_DATA_BLOCK_CNT_PCT / 100); const int64_t micro_blk_min_cnt = MAX(2, blk_cnt_info.shared_blk_cnt_ * MIN_MICRO_CKPT_BLOCK_CNT_PCT / 100); ASSERT_EQ(data_blk_min_cnt, blk_cnt_info.data_blk_.min_cnt_); ASSERT_EQ(data_blk_min_cnt, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(micro_blk_min_cnt, blk_cnt_info.meta_blk_.min_cnt_); ASSERT_EQ(micro_blk_min_cnt, blk_cnt_info.meta_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.shared_blk_cnt_, blk_cnt_info.data_blk_.min_cnt_ + blk_cnt_info.meta_blk_.max_cnt_); ASSERT_EQ(blk_cnt_info.shared_blk_cnt_, blk_cnt_info.data_blk_.max_cnt_ + blk_cnt_info.meta_blk_.min_cnt_); ASSERT_EQ(data_blk_min_cnt, cache_stat.phy_blk_stat().data_blk_cnt_); ASSERT_EQ(micro_blk_min_cnt, cache_stat.phy_blk_stat().meta_blk_cnt_); ObSSPhysicalBlockHandle phy_blk_handle; int64_t phy_blk_idx = -1; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.alloc_block(phy_blk_idx, phy_blk_handle, ObSSPhyBlockType::SS_CACHE_DATA_BLK)); ASSERT_LT(0, phy_blk_idx); ASSERT_EQ(true, phy_blk_handle.is_valid()); ASSERT_EQ(1, blk_cnt_info.data_blk_.used_cnt_); ASSERT_EQ(1, cache_stat.phy_blk_stat().data_blk_used_cnt_); phy_blk_handle()->valid_len_ = 50; bool is_empty = false; ASSERT_EQ(OB_SUCCESS, phy_blk_handle()->dec_valid_len(phy_blk_idx, -50)); ASSERT_EQ(true, phy_blk_handle()->is_empty()); ASSERT_EQ(1, phy_blk_mgr.reusable_set_.size()); ASSERT_EQ(2, phy_blk_handle()->ref_cnt_); bool succ_free = false; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.free_block(phy_blk_idx, succ_free)); ASSERT_EQ(false, succ_free); phy_blk_handle.reset(); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.free_block(phy_blk_idx, succ_free)); ASSERT_EQ(true, succ_free); // test double free phy_block succ_free = false; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.free_block(phy_blk_idx, succ_free)); ASSERT_EQ(false, succ_free); ASSERT_EQ(0, blk_cnt_info.data_blk_.used_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().data_blk_used_cnt_); } TEST_F(TestSSPhysicalBlockManager, super_block) { ObSSPhysicalBlockManager &phy_blk_mgr = MTL(ObSSMicroCache *)->phy_blk_mgr_; ASSERT_EQ(true, phy_blk_mgr.is_inited_); phy_blk_mgr.super_block_.reset(); ASSERT_EQ(false, phy_blk_mgr.super_block_.is_valid()); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.format_ss_super_block()); ASSERT_EQ(true, phy_blk_mgr.super_block_.is_valid()); ObSSMicroCacheSuperBlock super_blk; ASSERT_EQ(false, super_blk.is_valid()); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.get_ss_super_block(super_blk)); ASSERT_EQ(true, super_blk.is_valid()); super_blk.modify_time_us_ = 1000001; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.update_ss_super_block(super_blk)); ASSERT_EQ(true, phy_blk_mgr.super_block_.is_valid()); ASSERT_EQ(super_blk.modify_time_us_, phy_blk_mgr.super_block_.modify_time_us_); ASSERT_EQ(false, super_blk.is_valid_checkpoint()); } TEST_F(TestSSPhysicalBlockManager, physical_block_manager) { int ret = OB_SUCCESS; ObSSPhysicalBlockManager &phy_blk_mgr = MTL(ObSSMicroCache *)->phy_blk_mgr_; ObSSMicroCacheStat &cache_stat = phy_blk_mgr.cache_stat_; SSPhyBlockCntInfo &blk_cnt_info = phy_blk_mgr.blk_cnt_info_; ASSERT_EQ(true, phy_blk_mgr.is_inited_); // 1. allocate all avaliable cache_data_block const int64_t data_blk_cnt = blk_cnt_info.cache_limit_blk_cnt(); ASSERT_LT(0, data_blk_cnt); int64_t block_idx = -1; ObSSPhysicalBlockHandle phy_blk_handle; ObArray data_blk_idx_arr; for (int64_t i = 0; OB_SUCC(ret) && i < data_blk_cnt; i++) { ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.alloc_block(block_idx, phy_blk_handle, ObSSPhyBlockType::SS_CACHE_DATA_BLK)); ASSERT_EQ(OB_SUCCESS, data_blk_idx_arr.push_back(block_idx)); ASSERT_EQ(true, phy_blk_handle.is_valid()); phy_blk_handle.get_ptr()->is_sealed_ = true; phy_blk_handle.reset(); } ASSERT_LT(blk_cnt_info.data_blk_.min_cnt_, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(data_blk_cnt, blk_cnt_info.data_blk_.used_cnt_); ASSERT_EQ(data_blk_cnt, cache_stat.phy_blk_stat().data_blk_used_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.max_cnt_, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.max_cnt_, cache_stat.phy_blk_stat().data_blk_cnt_); int64_t shared_blk_used_cnt = blk_cnt_info.data_blk_.hold_cnt_ + blk_cnt_info.meta_blk_.hold_cnt_; ASSERT_EQ(shared_blk_used_cnt, blk_cnt_info.shared_blk_used_cnt_); ASSERT_EQ(shared_blk_used_cnt, cache_stat.phy_blk_stat().shared_blk_used_cnt_); { // no free cache_data_block to allocate. ASSERT_EQ(OB_EAGAIN, phy_blk_mgr.alloc_block(block_idx, phy_blk_handle, ObSSPhyBlockType::SS_CACHE_DATA_BLK)); } // 2. free all cache_data_blk bool succ_free = false; for (int64_t i = 0; OB_SUCC(ret) && i < data_blk_cnt; i++) { succ_free = false; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.add_reusable_block(data_blk_idx_arr.at(i))); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.free_block(data_blk_idx_arr.at(i), succ_free)); ASSERT_EQ(true, succ_free); } ASSERT_EQ(0, blk_cnt_info.data_blk_.used_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().data_blk_used_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.min_cnt_, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.min_cnt_, cache_stat.phy_blk_stat().data_blk_cnt_); // 3. allocate all phy_block_ckpt_block int64_t phy_ckpt_blk_cnt = phy_blk_mgr.blk_cnt_info_.phy_ckpt_blk_cnt_; ASSERT_LT(0, phy_ckpt_blk_cnt); block_idx = -1; ObArray phy_ckpt_blk_idx_arr; for (int64_t i = 0; OB_SUCC(ret) && i < phy_ckpt_blk_cnt; i++) { ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.alloc_block(block_idx, phy_blk_handle, ObSSPhyBlockType::SS_PHY_BLOCK_CKPT_BLK)); ASSERT_EQ(OB_SUCCESS, phy_ckpt_blk_idx_arr.push_back(block_idx)); ASSERT_EQ(true, phy_blk_handle.is_valid()); phy_blk_handle.get_ptr()->is_sealed_ = true; phy_blk_handle.reset(); } ASSERT_EQ(phy_ckpt_blk_cnt, blk_cnt_info.phy_ckpt_blk_used_cnt_); ASSERT_EQ(phy_ckpt_blk_cnt, cache_stat.phy_blk_stat().phy_ckpt_blk_used_cnt_); { // no free ckpt_block to allocate. ASSERT_EQ(OB_EAGAIN, phy_blk_mgr.alloc_block(block_idx, phy_blk_handle, ObSSPhyBlockType::SS_PHY_BLOCK_CKPT_BLK)); } // 4. free all phy_block_ckpt_block succ_free = false; for (int64_t i = 0; OB_SUCC(ret) && i < phy_ckpt_blk_cnt; i++) { succ_free = false; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.add_reusable_block(phy_ckpt_blk_idx_arr.at(i))); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.free_block(phy_ckpt_blk_idx_arr.at(i), succ_free)); ASSERT_EQ(true, succ_free); } ASSERT_EQ(0, blk_cnt_info.phy_ckpt_blk_used_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().phy_ckpt_blk_used_cnt_); // 5. allocate all micro_meta_ckpt_block const int64_t micro_ckpt_blk_cnt = blk_cnt_info.meta_blk_.max_cnt_; ASSERT_LT(0, micro_ckpt_blk_cnt); block_idx = -1; ObArray micro_ckpt_blk_idx_arr; for (int64_t i = 0; OB_SUCC(ret) && i < micro_ckpt_blk_cnt; i++) { ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.alloc_block(block_idx, phy_blk_handle, ObSSPhyBlockType::SS_MICRO_META_CKPT_BLK)); ASSERT_EQ(OB_SUCCESS, micro_ckpt_blk_idx_arr.push_back(block_idx)); ASSERT_EQ(true, phy_blk_handle.is_valid()); phy_blk_handle.get_ptr()->is_sealed_ = true; phy_blk_handle.reset(); } ASSERT_LT(blk_cnt_info.meta_blk_.min_cnt_, blk_cnt_info.meta_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.meta_blk_.max_cnt_, blk_cnt_info.meta_blk_.hold_cnt_); ASSERT_EQ(micro_ckpt_blk_cnt, blk_cnt_info.meta_blk_.used_cnt_); ASSERT_EQ(micro_ckpt_blk_cnt, phy_blk_mgr.cache_stat_.phy_blk_stat().meta_blk_used_cnt_); ASSERT_EQ(micro_ckpt_blk_cnt, blk_cnt_info.meta_blk_.hold_cnt_); ASSERT_EQ(micro_ckpt_blk_cnt, phy_blk_mgr.cache_stat_.phy_blk_stat().meta_blk_cnt_); shared_blk_used_cnt = blk_cnt_info.data_blk_.hold_cnt_ + blk_cnt_info.meta_blk_.hold_cnt_; ASSERT_EQ(shared_blk_used_cnt, blk_cnt_info.shared_blk_used_cnt_); ASSERT_EQ(shared_blk_used_cnt, cache_stat.phy_blk_stat().shared_blk_used_cnt_); { // no free ckpt_block to allocate. ASSERT_EQ(OB_EAGAIN, phy_blk_mgr.alloc_block(block_idx, phy_blk_handle, ObSSPhyBlockType::SS_MICRO_META_CKPT_BLK)); } // 6. free all micro_meta_blockckpt_block succ_free = false; for (int64_t i = 0; OB_SUCC(ret) && i < micro_ckpt_blk_cnt; i++) { succ_free = false; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.add_reusable_block(micro_ckpt_blk_idx_arr.at(i))); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.free_block(micro_ckpt_blk_idx_arr.at(i), succ_free)); ASSERT_EQ(true, succ_free); } ASSERT_EQ(0, blk_cnt_info.meta_blk_.used_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().meta_blk_used_cnt_); ASSERT_EQ(blk_cnt_info.meta_blk_.min_cnt_, blk_cnt_info.meta_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.meta_blk_.min_cnt_, cache_stat.phy_blk_stat().meta_blk_cnt_); // 7. allocate all reorgan_block const int64_t reorgan_blk_cnt = blk_cnt_info.data_blk_.max_cnt_; block_idx = -1; ObArray reorgan_blk_idx_arr; for (int64_t i = 0; OB_SUCC(ret) && i < reorgan_blk_cnt; i++) { ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.alloc_block(block_idx, phy_blk_handle, ObSSPhyBlockType::SS_REORGAN_BLK)); ASSERT_EQ(OB_SUCCESS, reorgan_blk_idx_arr.push_back(block_idx)); ASSERT_EQ(true, phy_blk_handle.is_valid()); phy_blk_handle.get_ptr()->is_sealed_ = true; phy_blk_handle.reset(); } ASSERT_LT(blk_cnt_info.data_blk_.min_cnt_, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.max_cnt_, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(reorgan_blk_cnt, blk_cnt_info.data_blk_.used_cnt_); ASSERT_EQ(reorgan_blk_cnt, cache_stat.phy_blk_stat().data_blk_used_cnt_); ASSERT_EQ(reorgan_blk_cnt, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(reorgan_blk_cnt, cache_stat.phy_blk_stat().data_blk_cnt_); shared_blk_used_cnt = blk_cnt_info.data_blk_.hold_cnt_ + blk_cnt_info.meta_blk_.hold_cnt_; ASSERT_EQ(shared_blk_used_cnt, blk_cnt_info.shared_blk_used_cnt_); ASSERT_EQ(shared_blk_used_cnt, cache_stat.phy_blk_stat().shared_blk_used_cnt_); { // no free reorgan_block to allocate. ASSERT_EQ(OB_EAGAIN, phy_blk_mgr.alloc_block(block_idx, phy_blk_handle, ObSSPhyBlockType::SS_REORGAN_BLK)); } // 8. free all reorgan_block succ_free = false; for (int64_t i = 0; OB_SUCC(ret) && i < reorgan_blk_cnt; i++) { succ_free = false; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.add_reusable_block(reorgan_blk_idx_arr.at(i))); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.free_block(reorgan_blk_idx_arr.at(i), succ_free)); ASSERT_EQ(true, succ_free); } ASSERT_EQ(0, blk_cnt_info.data_blk_.used_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().data_blk_used_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.min_cnt_, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.min_cnt_, cache_stat.phy_blk_stat().data_blk_cnt_); } TEST_F(TestSSPhysicalBlockManager, reusable_set) { int ret = OB_SUCCESS; ObSSPhysicalBlockManager &phy_blk_mgr = MTL(ObSSMicroCache *)->phy_blk_mgr_; ASSERT_EQ(true, phy_blk_mgr.is_inited_); ObSSPhysicalBlockHandle handle; int64_t block_idx = -1; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.alloc_block(block_idx, handle, ObSSPhyBlockType::SS_CACHE_DATA_BLK)); ASSERT_GT(block_idx, 1); bool is_exist = false; handle.get_ptr()->set_valid_len(256); hash::ObHashSet::iterator iter = phy_blk_mgr.reusable_set_.begin(); for (; iter != phy_blk_mgr.reusable_set_.end() && !is_exist; iter++) { if (block_idx == iter->first) { is_exist = true; } } ASSERT_EQ(false, is_exist); bool is_empty = false; ASSERT_EQ(OB_SUCCESS, handle()->dec_valid_len(block_idx, -256)); ASSERT_EQ(true, handle()->is_empty()); is_exist = false; iter = phy_blk_mgr.reusable_set_.begin(); for (; iter != phy_blk_mgr.reusable_set_.end() && !is_exist; iter++) { if (block_idx == iter->first) { is_exist = true; } } ASSERT_EQ(true, is_exist); handle.reset(); bool succ_free = false; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.free_block(block_idx, succ_free)); ASSERT_EQ(true, succ_free); } TEST_F(TestSSPhysicalBlockManager, resize_file_size) { int ret = OB_SUCCESS; const static uint32_t BLOCK_SIZE = (1 << 21); // 1. total_block count is less than count of a sub_arr int64_t total_block_cnt = ObSSPhysicalBlockManager::PHY_BLOCK_SUB_ARR_SIZE / sizeof(ObSSPhysicalBlock) - 1; int64_t file_size = BLOCK_SIZE * total_block_cnt; ObSSMicroCacheStat cache_stat; ObSSPhysicalBlockManager blk_mgr(cache_stat); ASSERT_EQ(OB_SUCCESS, blk_mgr.init(MTL_ID(), file_size, BLOCK_SIZE)); SSPhyBlockCntInfo &blk_cnt_info = blk_mgr.blk_cnt_info_; int64_t max_data_cnt = blk_cnt_info.cache_limit_blk_cnt(); int64_t max_phy_ckpt_cnt = blk_cnt_info.phy_ckpt_blk_cnt_; ObArray phy_blk_idxs; ObArray phy_blocks; for (int64_t i = 0; i < max_data_cnt; i++) { int64_t block_idx = -1; ObSSPhysicalBlockHandle phy_block_handle; ASSERT_EQ(OB_SUCCESS, blk_mgr.alloc_block(block_idx, phy_block_handle, ObSSPhyBlockType::SS_CACHE_DATA_BLK)); ASSERT_EQ(true, phy_block_handle.is_valid()); phy_block_handle.get_ptr()->is_sealed_ = true; ASSERT_EQ(OB_SUCCESS, phy_blocks.push_back(phy_block_handle.get_ptr())); ASSERT_EQ(OB_SUCCESS, phy_blk_idxs.push_back(block_idx)); } for (int64_t i = 0; i < max_phy_ckpt_cnt; ++i) { int64_t block_idx = -1; ObSSPhysicalBlockHandle phy_block_handle; ASSERT_EQ(OB_SUCCESS, blk_mgr.alloc_block(block_idx, phy_block_handle, ObSSPhyBlockType::SS_PHY_BLOCK_CKPT_BLK)); ASSERT_EQ(true, phy_block_handle.is_valid()); phy_block_handle.get_ptr()->is_sealed_ = true; ASSERT_EQ(OB_SUCCESS, phy_blocks.push_back(phy_block_handle.get_ptr())); ASSERT_EQ(OB_SUCCESS, phy_blk_idxs.push_back(block_idx)); } // 2. resize file_size const int64_t old_min_data_blk_cnt = blk_cnt_info.data_blk_.min_cnt_; const int64_t old_max_data_blk_cnt = blk_cnt_info.data_blk_.max_cnt_; const int64_t old_used_data_blk_cnt = blk_cnt_info.data_blk_.used_cnt_; const int64_t old_min_micro_blk_cnt = blk_cnt_info.meta_blk_.min_cnt_; const int64_t old_max_micro_blk_cnt = blk_cnt_info.meta_blk_.max_cnt_; const int64_t old_micro_blk_cnt = blk_cnt_info.meta_blk_.used_cnt_; ASSERT_EQ(OB_SUCCESS, blk_mgr.format_ss_super_block()); total_block_cnt += ObSSPhysicalBlockManager::PHY_BLOCK_SUB_ARR_SIZE / sizeof(ObSSPhysicalBlock); file_size = BLOCK_SIZE * total_block_cnt; ASSERT_EQ(OB_SUCCESS, blk_mgr.resize_file_size(file_size, BLOCK_SIZE)); ASSERT_LT(old_min_data_blk_cnt, blk_cnt_info.data_blk_.min_cnt_); ASSERT_LT(old_max_data_blk_cnt, blk_cnt_info.data_blk_.max_cnt_); ASSERT_EQ(old_used_data_blk_cnt, blk_cnt_info.data_blk_.used_cnt_); ASSERT_LE(old_min_micro_blk_cnt, blk_cnt_info.meta_blk_.min_cnt_); ASSERT_LT(old_max_micro_blk_cnt, blk_cnt_info.meta_blk_.max_cnt_); ASSERT_EQ(old_micro_blk_cnt, blk_cnt_info.meta_blk_.used_cnt_); ASSERT_LE(blk_cnt_info.data_blk_.min_cnt_, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.meta_blk_.min_cnt_, blk_cnt_info.meta_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.shared_blk_used_cnt_, blk_cnt_info.data_blk_.hold_cnt_ + blk_cnt_info.meta_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.shared_blk_used_cnt_, cache_stat.phy_blk_stat().shared_blk_used_cnt_); ASSERT_EQ(blk_cnt_info.shared_blk_cnt_, cache_stat.phy_blk_stat().shared_blk_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.hold_cnt_, cache_stat.phy_blk_stat().data_blk_cnt_); ASSERT_EQ(blk_cnt_info.meta_blk_.hold_cnt_, cache_stat.phy_blk_stat().meta_blk_cnt_); // alloc more cache_data block after resize int64_t new_max_data_cnt = blk_cnt_info.cache_limit_blk_cnt(); ASSERT_LT(max_data_cnt, new_max_data_cnt); int64_t new_max_phy_ckpt_cnt = blk_cnt_info.phy_ckpt_blk_cnt_; ASSERT_LE(max_phy_ckpt_cnt, new_max_phy_ckpt_cnt); for (int64_t i = max_data_cnt; i < new_max_data_cnt; i++) { int64_t block_idx = -1; ObSSPhysicalBlockHandle phy_block_handle; ASSERT_EQ(OB_SUCCESS, blk_mgr.alloc_block(block_idx, phy_block_handle, ObSSPhyBlockType::SS_CACHE_DATA_BLK)); ASSERT_EQ(true, phy_block_handle.is_valid()); phy_block_handle.get_ptr()->is_sealed_ = true; ASSERT_EQ(OB_SUCCESS, phy_blocks.push_back(phy_block_handle.get_ptr())); ASSERT_EQ(OB_SUCCESS, phy_blk_idxs.push_back(block_idx)); } for (int64_t i = max_phy_ckpt_cnt; i < new_max_phy_ckpt_cnt; ++i) { int64_t block_idx = -1; ObSSPhysicalBlockHandle phy_block_handle; ASSERT_EQ(OB_SUCCESS, blk_mgr.alloc_block(block_idx, phy_block_handle, ObSSPhyBlockType::SS_PHY_BLOCK_CKPT_BLK)); ASSERT_EQ(true, phy_block_handle.is_valid()); phy_block_handle.get_ptr()->is_sealed_ = true; ASSERT_EQ(OB_SUCCESS, phy_blocks.push_back(phy_block_handle.get_ptr())); ASSERT_EQ(OB_SUCCESS, phy_blk_idxs.push_back(block_idx)); } // 3. check the original phy_block's ptr not changed for (int64_t i = 0; OB_SUCC(ret) && i < max_data_cnt + max_phy_ckpt_cnt; i++) { const int64_t block_idx = phy_blk_idxs.at(i); ObSSPhysicalBlockHandle handle; ASSERT_EQ(OB_SUCCESS, blk_mgr.get_block_handle(block_idx, handle)); ASSERT_EQ(true, handle.is_valid()); ASSERT_EQ(phy_blocks.at(i), handle.get_ptr()); } // 4. check handle ObSSPhysicalBlockHandle handle1; handle1.set_ptr(phy_blocks.at(0)); ASSERT_EQ(2, handle1.ptr_->ref_cnt_); ObSSPhysicalBlockHandle handle2; ASSERT_EQ(OB_SUCCESS, handle2.assign(handle1)); ASSERT_EQ(3, handle2.ptr_->ref_cnt_); handle2.reset(); handle1.reset(); // 5. free all allocated phy_blocks bool succ_free = false; for (int64_t i = 0; OB_SUCC(ret) && i < phy_blk_idxs.count(); i++) { succ_free = false; const int64_t block_idx = phy_blk_idxs.at(i); ASSERT_EQ(OB_SUCCESS, blk_mgr.add_reusable_block(block_idx)); ASSERT_EQ(OB_SUCCESS, blk_mgr.free_block(block_idx, succ_free)); ASSERT_EQ(true, succ_free); } ASSERT_EQ(0, blk_cnt_info.data_blk_.used_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().data_blk_used_cnt_); ASSERT_EQ(0, blk_cnt_info.phy_ckpt_blk_used_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().phy_ckpt_blk_used_cnt_); } /* Multiple threads allocate/free blocks in parallel. */ TEST_F(TestSSPhysicalBlockManager, test_parallel_allocate_block) { int ret = OB_SUCCESS; const static uint64_t FILE_SIZE = (1L << 32); const static uint32_t BLOCK_SIZE = (1 << 21); ObSSMicroCacheStat cache_stat; ObSSPhysicalBlockManager blk_mgr(cache_stat); const uint64_t tenant_id = MTL_ID(); ASSERT_EQ(true, is_valid_tenant_id(tenant_id)); ASSERT_EQ(OB_SUCCESS, blk_mgr.init(tenant_id, FILE_SIZE, BLOCK_SIZE)); SSPhyBlockCntInfo &blk_cnt_info = blk_mgr.blk_cnt_info_; const int64_t max_reorgan_blk_cnt = blk_cnt_info.reorgan_blk_cnt_ * 2; const int64_t max_data_blk_cnt = blk_cnt_info.shared_blk_cnt_ * (MIN_CACHE_DATA_BLOCK_CNT_PCT + 5) / 100 - max_reorgan_blk_cnt; // 85% const int64_t max_micro_ckpt_cnt = blk_cnt_info.shared_blk_cnt_ * (MIN_MICRO_CKPT_BLOCK_CNT_PCT + 5) / 100; // 9% const int64_t data_blk_thread_num = 5; const int64_t micro_ckpt_blk_thread_num = 5; const int64_t phy_ckpt_blk_thread_num = 1; const int64_t reorgan_blk_thread_num = 1; int64_t data_blk_cnt = max_data_blk_cnt / data_blk_thread_num; int64_t micro_ckpt_cnt = max_micro_ckpt_cnt / micro_ckpt_blk_thread_num; int64_t phy_ckpt_cnt = blk_cnt_info.phy_ckpt_blk_cnt_ / phy_ckpt_blk_thread_num; int64_t reorgan_blk_cnt = max_reorgan_blk_cnt / reorgan_blk_thread_num; TestSSPhysicalBlockManager::TestSSPhyBlockMgrThread threads(ObTenantEnv::get_tenant(), &blk_mgr, data_blk_cnt, phy_ckpt_cnt, micro_ckpt_cnt, max_reorgan_blk_cnt, TestSSPhyBlockMgrThread::TestParallelType::TEST_PARALLEL_ALLOCATE_BLOCK); threads.set_thread_count(12); threads.start(); threads.wait(); ASSERT_EQ(0, threads.get_fail_cnt()); ASSERT_EQ(0, blk_cnt_info.data_blk_.used_cnt_); ASSERT_EQ(0, blk_cnt_info.meta_blk_.used_cnt_); ASSERT_EQ(0, blk_cnt_info.phy_ckpt_blk_used_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.min_cnt_, blk_cnt_info.data_blk_.hold_cnt_); ASSERT_EQ(blk_cnt_info.meta_blk_.min_cnt_, blk_cnt_info.meta_blk_.hold_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().data_blk_used_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().meta_blk_used_cnt_); ASSERT_EQ(0, cache_stat.phy_blk_stat().phy_ckpt_blk_used_cnt_); ASSERT_EQ(blk_cnt_info.data_blk_.hold_cnt_, cache_stat.phy_blk_stat().data_blk_cnt_); ASSERT_EQ(blk_cnt_info.meta_blk_.hold_cnt_, cache_stat.phy_blk_stat().meta_blk_cnt_); const int64_t shared_blk_used_cnt = blk_cnt_info.data_blk_.hold_cnt_ + blk_cnt_info.meta_blk_.hold_cnt_; ASSERT_EQ(shared_blk_used_cnt, blk_cnt_info.shared_blk_used_cnt_); ASSERT_EQ(shared_blk_used_cnt, cache_stat.phy_blk_stat().shared_blk_used_cnt_); } /* Multiple threads allocate/free normal blocks in parallel for multiple rounds and check reuse version. */ TEST_F(TestSSPhysicalBlockManager, test_parallel_allocate_block_and_check_reuse_version) { int ret = OB_SUCCESS; const static uint64_t FILE_SIZE = (1L << 40); const static uint32_t BLOCK_SIZE = (1 << 21); ObSSMicroCacheStat cache_stat; ObSSPhysicalBlockManager blk_mgr(cache_stat); const uint64_t tenant_id = MTL_ID(); ASSERT_EQ(true, is_valid_tenant_id(tenant_id)); ASSERT_EQ(OB_SUCCESS, blk_mgr.init(tenant_id, FILE_SIZE, BLOCK_SIZE)); const int32_t thread_cnt = 2; int64_t data_blk_cnt = blk_mgr.blk_cnt_info_.cache_limit_blk_cnt() / thread_cnt; data_blk_cnt = MIN(2000, data_blk_cnt); int64_t phy_ckpt_blk_cnt = 0; int64_t micro_ckpt_blk_cnt = 0; int64_t reorgan_blk_cnt = 0; int64_t ori_total_reuse_version = 0; for (int64_t i = 2; OB_SUCC(ret) && i < blk_mgr.blk_cnt_info_.total_blk_cnt_; i++) { ObSSPhysicalBlockHandle handle; ASSERT_EQ(OB_SUCCESS, blk_mgr.get_block_handle(i, handle)); handle.get_ptr()->reuse_version_ = 1; ++ori_total_reuse_version; } TestSSPhysicalBlockManager::TestSSPhyBlockMgrThread threads(ObTenantEnv::get_tenant(), &blk_mgr, data_blk_cnt, phy_ckpt_blk_cnt, micro_ckpt_blk_cnt, reorgan_blk_cnt, TestSSPhyBlockMgrThread::TestParallelType::TEST_PARALLEL_ALLOCATE_BLOCK_AND_CHECK_REUSE_VERSION); threads.set_thread_count(thread_cnt); threads.start(); threads.wait(); int64_t block_idx = -1; const int64_t data_blk_used_cnt = blk_mgr.blk_cnt_info_.data_blk_.used_cnt_; ASSERT_EQ(0, data_blk_used_cnt); int64_t total_reuse_version = 0; for (int64_t i = 2; OB_SUCC(ret) && i < blk_mgr.blk_cnt_info_.total_blk_cnt_; i++) { ObSSPhysicalBlockHandle handle; ASSERT_EQ(OB_SUCCESS, blk_mgr.get_block_handle(i, handle)); total_reuse_version += handle.get_ptr()->reuse_version_; } ASSERT_EQ(0, threads.get_fail_cnt()); ASSERT_EQ(data_blk_cnt * 10 * thread_cnt, total_reuse_version - ori_total_reuse_version); } /* Multiple threads allocate cache_data_blocks and resize file size in parallel. */ TEST_F(TestSSPhysicalBlockManager, test_parallel_allocate_block_and_resize) { int ret = OB_SUCCESS; ObSSPhysicalBlockManager &phy_blk_mgr = MTL(ObSSMicroCache *)->phy_blk_mgr_; const int64_t ori_file_size = phy_blk_mgr.total_file_size_; const int64_t thread_cnt = 10; int64_t data_blk_cnt = phy_blk_mgr.blk_cnt_info_.cache_limit_blk_cnt() / thread_cnt; data_blk_cnt = MIN(2000, data_blk_cnt); int64_t phy_ckpt_blk_cnt = 0; int64_t micro_ckpt_blk_cnt = 0; int64_t reorgan_blk_cnt = 0; TestSSPhysicalBlockManager::TestSSPhyBlockMgrThread threads(ObTenantEnv::get_tenant(), &phy_blk_mgr, data_blk_cnt, phy_ckpt_blk_cnt, micro_ckpt_blk_cnt, reorgan_blk_cnt, TestSSPhyBlockMgrThread::TestParallelType::TEST_PARALLEL_ALLOCATE_BLOCK_AND_RESIZE); threads.set_thread_count(thread_cnt); threads.start(); threads.wait(); ASSERT_EQ(data_blk_cnt * 5, phy_blk_mgr.blk_cnt_info_.data_blk_.used_cnt_); ASSERT_EQ(ori_file_size * 5, phy_blk_mgr.total_file_size_); ASSERT_EQ(0, threads.get_fail_cnt()); } /* Test two scenarios: 1: Both super_blocks are correct, read the latest one 2: One of the super_blocks is correct and the other is incorrect, read the correct one */ TEST_F(TestSSPhysicalBlockManager, test_double_write_super_blk) { int ret = OB_SUCCESS; ObTenantFileManager *tnt_file_mgr = MTL(ObTenantFileManager*); ObSSPhysicalBlockManager &phy_blk_mgr = MTL(ObSSMicroCache *)->phy_blk_mgr_; ObMemAttr attr(OB_SERVER_TENANT_ID, "test"); const int64_t align_size = SS_MEM_BUF_ALIGNMENT; char *buf = static_cast(ob_malloc_align(SS_MEM_BUF_ALIGNMENT, align_size, attr)); ASSERT_NE(nullptr, buf); // Scenario 1 const int64_t old_cache_file_size = phy_blk_mgr.total_file_size_ * 2; const int64_t new_cache_file_size = phy_blk_mgr.total_file_size_ * 4; ObSSMicroCacheSuperBlock old_super_blk(old_cache_file_size); ObSSMicroCacheSuperBlock new_super_blk(new_cache_file_size); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.update_ss_super_block(old_super_blk)); new_super_blk.modify_time_us_ = old_super_blk.modify_time_us_ + 888888; ASSERT_EQ(OB_SUCCESS, serialize_super_block(buf, align_size, new_super_blk)); int64_t write_size = 0; ASSERT_EQ(OB_SUCCESS, tnt_file_mgr->pwrite_cache_block(0, align_size, buf, write_size)); ObSSMicroCacheSuperBlock super_blk; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.read_ss_super_block(super_blk)); check_super_block_identical(phy_blk_mgr.super_block_, new_super_blk); // Scenario 2 ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.update_ss_super_block(new_super_blk)); const int64_t fake_cache_file_size = phy_blk_mgr.total_file_size_ * 8; ObSSMicroCacheSuperBlock fake_super_blk(new_cache_file_size); fake_super_blk.modify_time_us_ = new_super_blk.modify_time_us_ + 888888; ASSERT_EQ(OB_SUCCESS, serialize_super_block(buf, align_size, fake_super_blk)); buf[fake_super_blk.get_serialize_size() - 3] = '#'; // simulate data error ObSSMicroCacheSuperBlock tmp_super_block; ASSERT_NE(OB_SUCCESS, deserialize_super_block(buf, align_size, tmp_super_block)); write_size = 0; ASSERT_EQ(OB_SUCCESS, tnt_file_mgr->pwrite_cache_block(0, align_size, buf, write_size)); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.read_ss_super_block(super_blk)); check_super_block_identical(phy_blk_mgr.super_block_, new_super_blk); ob_free_align(buf); } TEST_F(TestSSPhysicalBlockManager, test_scan_reorgan_blk) { int ret = OB_SUCCESS; ObSSMicroCache *micro_cache = MTL(ObSSMicroCache *); ObSSPhysicalBlockManager &phy_blk_mgr = micro_cache->phy_blk_mgr_; ObSSReleaseCacheTask &arc_task = micro_cache->task_runner_.release_cache_task_; arc_task.is_inited_ = false; const int64_t block_size = phy_blk_mgr.get_block_size(); int64_t total_data_blk_cnt = phy_blk_mgr.blk_cnt_info_.cache_limit_blk_cnt(); ASSERT_LT(10, total_data_blk_cnt); int64_t block_idx = -1; ObSSPhysicalBlockHandle phy_blk_handle; ObArray normal_blk_idx_arr; for (int64_t i = 0; OB_SUCC(ret) && i < total_data_blk_cnt; i++) { ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.alloc_block(block_idx, phy_blk_handle, ObSSPhyBlockType::SS_CACHE_DATA_BLK)); ASSERT_EQ(OB_SUCCESS, normal_blk_idx_arr.push_back(block_idx)); ASSERT_EQ(true, phy_blk_handle.is_valid()); phy_blk_handle()->is_sealed_ = true; phy_blk_handle()->is_free_ = false; phy_blk_handle()->block_type_ = static_cast(ObSSPhyBlockType::SS_CACHE_DATA_BLK); phy_blk_handle()->valid_len_ = phy_blk_mgr.get_block_size(); ASSERT_EQ(false, phy_blk_handle()->can_reorganize(block_size)); } ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.scan_sparse_blocks()); ASSERT_EQ(0, phy_blk_mgr.get_sparse_block_cnt()); const int64_t dec_len = -1 * phy_blk_mgr.get_block_size() * 0.2; for (int64_t i = 0; i < 10; i++) { const int64_t block_idx = normal_blk_idx_arr[i]; ObSSPhysicalBlockHandle phy_blk_handle; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.get_block_handle(block_idx, phy_blk_handle)); ASSERT_EQ(OB_SUCCESS, phy_blk_handle()->dec_valid_len(block_idx, dec_len)); } ASSERT_EQ(10, phy_blk_mgr.get_sparse_block_cnt()); for (int64_t i = 0; i < 10; ++i) { const int64_t block_idx = normal_blk_idx_arr[i]; ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.delete_sparse_block(block_idx)); } ASSERT_EQ(0, phy_blk_mgr.get_sparse_block_cnt()); ASSERT_EQ(OB_SUCCESS, phy_blk_mgr.scan_sparse_blocks()); ASSERT_EQ(10, phy_blk_mgr.get_sparse_block_cnt()); } } // namespace storage } // namespace oceanbase int main(int argc, char **argv) { system("rm -f test_ss_physical_block_manager.log*"); OB_LOGGER.set_file_name("test_ss_physical_block_manager.log", true, true); OB_LOGGER.set_log_level("INFO"); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }