384 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * 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.
 | |
|  */
 | |
| 
 | |
| #include <gtest/gtest.h>
 | |
| #include "lib/file/ob_file.h"
 | |
| #include "lib/ob_define.h"
 | |
| #include "storage/blocksstable/ob_data_file_prepare.h"
 | |
| #include "storage/slog/simple_ob_storage_redo_module.h"
 | |
| #include "lib/container/ob_se_array.h"
 | |
| #include "share/ob_simple_mem_limit_getter.h"
 | |
| #include <thread>
 | |
| 
 | |
| #define private public
 | |
| #include "share/rc/ob_tenant_base.h"
 | |
| #include "storage/slog/ob_storage_log_replayer.h"
 | |
| #include "storage/slog/ob_storage_log_reader.h"
 | |
| #include "storage/slog/ob_storage_logger_manager.h"
 | |
| #undef private
 | |
| 
 | |
| namespace oceanbase
 | |
| {
 | |
| using namespace common;
 | |
| static ObSimpleMemLimitGetter getter;
 | |
| 
 | |
| namespace storage
 | |
| {
 | |
| 
 | |
| class TestStorageLogReplay : public TestDataFilePrepare
 | |
| {
 | |
| public:
 | |
|   TestStorageLogReplay()
 | |
|     : TestDataFilePrepare(&getter, "TestStorageLogReplay")
 | |
|   {
 | |
|   }
 | |
|   virtual ~TestStorageLogReplay() = default;
 | |
| 
 | |
|   virtual void SetUp() override;
 | |
|   virtual void TearDown();
 | |
|   void build_storage(int64_t cnt);
 | |
| 
 | |
| public:
 | |
|   static const int64_t MAX_FILE_SIZE = 256 * 1024 * 1024;
 | |
| 
 | |
| public:
 | |
|   ObStorageLogReplayer replayer_;
 | |
|   char dir_[128];
 | |
|   ObLogCursor replay_start_cursor_;
 | |
|   ObLogCursor replay_finish_cursor_;
 | |
|   blocksstable::ObLogFileSpec log_file_spec_;
 | |
|   SimpleObStorageModule tenant_storage_;
 | |
| };
 | |
| 
 | |
| void TestStorageLogReplay::SetUp()
 | |
| {
 | |
|   system("rm -rf ./test_storage_log_replay");
 | |
|   MEMCPY(dir_, "./test_storage_log_replay", sizeof("./test_storage_log_replay"));
 | |
|   replay_start_cursor_.file_id_ = 1;
 | |
|   replay_start_cursor_.log_id_ = 1;
 | |
|   replay_start_cursor_.offset_ = 0;
 | |
|   log_file_spec_.retry_write_policy_ = "normal";
 | |
|   log_file_spec_.log_create_policy_ = "normal";
 | |
|   log_file_spec_.log_write_policy_ = "truncate";
 | |
|   TestDataFilePrepare::TearDown();
 | |
|   TestDataFilePrepare::SetUp();
 | |
|   FileDirectoryUtils::create_full_path("./test_storage_log_replay");
 | |
|   SLOGGERMGR.init(dir_, MAX_FILE_SIZE, log_file_spec_);
 | |
|   static ObTenantBase tenant_ctx(10);
 | |
|   ObTenantEnv::set_tenant(&tenant_ctx);
 | |
|   ObTenantIOManager *io_service = nullptr;
 | |
|   EXPECT_EQ(OB_SUCCESS, ObTenantIOManager::mtl_init(io_service));
 | |
| }
 | |
| 
 | |
| void TestStorageLogReplay::TearDown()
 | |
| {
 | |
|   SLOGGERMGR.destroy();
 | |
|   system("rm -rf ./test_storage_log_replay");
 | |
|   TestDataFilePrepare::TearDown();
 | |
| }
 | |
| 
 | |
| void TestStorageLogReplay::build_storage(int64_t cnt)
 | |
| {
 | |
|   tenant_storage_.slog_cnt_ = cnt;
 | |
|   for (int i = 0; i < cnt; i++) {
 | |
|     tenant_storage_.slogs_[i].block_cnt_ = ObRandom::rand(1, 1024);
 | |
|     for (int j = 0; j < tenant_storage_.slogs_[i].block_cnt_; j++) {
 | |
|       tenant_storage_.slogs_[i].blocks_[j] = ObRandom::rand(0, 10<<20);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| TEST_F(TestStorageLogReplay, test_basic)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   SimpleObStorageModule redo_module;
 | |
| 
 | |
|   // test invalid initialization
 | |
|   ret = replayer_.init(nullptr, log_file_spec_);
 | |
|   ASSERT_NE(OB_SUCCESS, ret);
 | |
|   // test invalid unregister
 | |
|   ret = replayer_.unregister_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE);
 | |
|   ASSERT_NE(OB_SUCCESS, ret);
 | |
|   // test invalid register
 | |
|   ret = replayer_.register_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE, &redo_module);
 | |
| 
 | |
|   // test normal initialization
 | |
|   ret = replayer_.init(dir_, log_file_spec_);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   // test no redo log
 | |
|   ret = replayer_.replay(replay_start_cursor_, replay_finish_cursor_, OB_SERVER_TENANT_ID);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ASSERT_EQ(1, replay_finish_cursor_.file_id_);
 | |
|   ASSERT_EQ(1, replay_finish_cursor_.log_id_);
 | |
|   ASSERT_EQ(0, replay_finish_cursor_.offset_);
 | |
| 
 | |
|   // test normal replay (single write)
 | |
|   build_storage(ObRandom::rand(1, 127));
 | |
| 
 | |
|   ObStorageLogger *tmp_slogger = OB_NEW(ObStorageLogger, ObModIds::TEST);
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->init(SLOGGERMGR, 500));
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->start());
 | |
| 
 | |
|   ObTenantBase tenant_base(10);
 | |
|   tenant_base.set(tmp_slogger);
 | |
|   ObTenantEnv::set_tenant(&tenant_base);
 | |
|   ASSERT_EQ(OB_SUCCESS, tenant_base.init());
 | |
| 
 | |
|   ObTenantSwitchGuard guard;
 | |
|   guard.switch_to(10);
 | |
|   ObStorageLogger *slogger = MTL(ObStorageLogger*);
 | |
|   slogger->is_start_ = false;
 | |
|   slogger->start_log(replay_start_cursor_);
 | |
| 
 | |
|   ObStorageLogParam log_param;
 | |
|   log_param.cmd_ = ObIRedoModule::gen_cmd(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE,
 | |
|       ObRedoLogSubType::OB_REDO_LOG_CREATE_LS);
 | |
|   for (int i = 0; i < tenant_storage_.slog_cnt_; i++) {
 | |
|     log_param.data_ = &tenant_storage_.slogs_[i];
 | |
|     ret = slogger->write_log(log_param);
 | |
|     ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   }
 | |
|   replayer_.destroy();
 | |
|   ret = replayer_.init(slogger->get_dir(), log_file_spec_);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
| 
 | |
|   ret = replayer_.register_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE, &redo_module);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ret = replayer_.replay(replay_start_cursor_, replay_finish_cursor_, OB_SERVER_TENANT_ID);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ASSERT_TRUE(tenant_storage_ == redo_module);
 | |
|   ret = replayer_.unregister_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   replayer_.destroy();
 | |
|   redo_module.reset();
 | |
| 
 | |
| 
 | |
|   // test normal replay (batch write)
 | |
|   build_storage(ObRandom::rand(1, 127));
 | |
| 
 | |
|   // mock drop tenant
 | |
|   tmp_slogger->~ObStorageLogger();
 | |
|   OB_DELETE(ObStorageLogger, ObModIds::TEST, tmp_slogger);
 | |
| 
 | |
|   tmp_slogger = OB_NEW(ObStorageLogger, ObModIds::TEST);
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->init(SLOGGERMGR, 500));
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->start());
 | |
| 
 | |
|   tenant_base.set(tmp_slogger);
 | |
|   ObTenantEnv::set_tenant(&tenant_base);
 | |
| 
 | |
|   guard.switch_to(10);
 | |
|   slogger = MTL(ObStorageLogger*);
 | |
|   slogger->is_start_ = false;
 | |
|   slogger->start_log(replay_finish_cursor_);
 | |
| 
 | |
|   ObSEArray<ObStorageLogParam, 10> param_arr;
 | |
|   log_param.cmd_ = ObIRedoModule::gen_cmd(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE,
 | |
|       ObRedoLogSubType::OB_REDO_LOG_CREATE_LS);
 | |
|   for (int i = 0; i < tenant_storage_.slog_cnt_; i++) {
 | |
|     log_param.data_ = &(tenant_storage_.slogs_[i]);
 | |
|     param_arr.push_back(log_param);
 | |
|   }
 | |
|   ret = slogger->get_active_cursor(replay_start_cursor_);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ret = slogger->write_log(param_arr);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
| 
 | |
|   ret = replayer_.init(slogger->get_dir(), log_file_spec_);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ret = replayer_.register_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE, &redo_module);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ret = replayer_.replay(replay_start_cursor_, replay_finish_cursor_, OB_SERVER_TENANT_ID);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ASSERT_TRUE(tenant_storage_ == redo_module);
 | |
|   ret = replayer_.unregister_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   replayer_.destroy();
 | |
|   redo_module.reset();
 | |
| 
 | |
| 
 | |
|   // test different sub_type and checkpoint
 | |
|   build_storage(ObRandom::rand(1, 127));
 | |
|   slogger->get_active_cursor(replay_start_cursor_);
 | |
| 
 | |
|   for (int i = 0; i < tenant_storage_.slog_cnt_; i++) {
 | |
|     log_param.data_ = &tenant_storage_.slogs_[i];
 | |
|     ret = slogger->write_log(log_param);
 | |
|     ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   }
 | |
| 
 | |
|   tenant_storage_.slog_cnt_++;
 | |
|   int tmp_cnt = tenant_storage_.slog_cnt_ - 1;
 | |
|   tenant_storage_.slogs_[tmp_cnt].blocks_[0] = 3214;
 | |
|   tenant_storage_.slogs_[tmp_cnt].block_cnt_ = 1;
 | |
|   log_param.data_ = &(tenant_storage_.slogs_[tmp_cnt]);
 | |
|   log_param.cmd_ = ObIRedoModule::gen_cmd(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE,
 | |
|       ObRedoLogSubType::OB_REDO_LOG_DELETE_LS);
 | |
|   ret = slogger->write_log(log_param);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
| 
 | |
|   ret = replayer_.init(slogger->get_dir(), log_file_spec_);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ret = replayer_.register_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE, &redo_module);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ret = replayer_.replay(replay_start_cursor_, replay_finish_cursor_, OB_SERVER_TENANT_ID);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ASSERT_FALSE(tenant_storage_ == redo_module);
 | |
| 
 | |
|   for (int i = 0; i < tmp_cnt; i++) {
 | |
|     ASSERT_TRUE(tenant_storage_.slogs_[i] == redo_module.slogs_[i]);
 | |
|   }
 | |
|   ASSERT_TRUE(tenant_storage_.slogs_[tmp_cnt] != redo_module.slogs_[tmp_cnt]);
 | |
| }
 | |
| 
 | |
| TEST_F(TestStorageLogReplay, test_switch_file_replay)
 | |
| {
 | |
|   // replay start cursor is the end of the first file and slogs are dumped to the second file
 | |
|   int ret = OB_SUCCESS;
 | |
|   ObLogCursor write_start_cursor;
 | |
|   write_start_cursor.file_id_ = 1;
 | |
|   write_start_cursor.log_id_ = 1;
 | |
|   SimpleObStorageModule redo_module;
 | |
| 
 | |
|   ObStorageLogger *tmp_slogger = OB_NEW(ObStorageLogger, ObModIds::TEST);
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->init(SLOGGERMGR, 500));
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->start());
 | |
| 
 | |
|   ObTenantBase tenant_base(10);
 | |
|   tenant_base.set(tmp_slogger);
 | |
|   ObTenantEnv::set_tenant(&tenant_base);
 | |
|   ASSERT_EQ(OB_SUCCESS, tenant_base.init());
 | |
| 
 | |
|   ObTenantSwitchGuard guard;
 | |
|   guard.switch_to(10);
 | |
|   ObStorageLogger *slogger = MTL(ObStorageLogger*);
 | |
|   slogger->is_start_ = false;
 | |
|   slogger->start_log(write_start_cursor);
 | |
| 
 | |
|   ObStorageLogParam log_param;
 | |
|   log_param.cmd_ = ObIRedoModule::gen_cmd(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE,
 | |
|       ObRedoLogSubType::OB_REDO_LOG_CREATE_LS);
 | |
| 
 | |
|   build_storage(ObRandom::rand(1, 127));
 | |
|   for (int i = 0; i < tenant_storage_.slog_cnt_; i++) {
 | |
|     log_param.data_ = &tenant_storage_.slogs_[i];
 | |
|     ret = slogger->write_log(log_param);
 | |
|     ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   }
 | |
|   slogger->get_active_cursor(replay_start_cursor_);
 | |
| 
 | |
|   build_storage(ObRandom::rand(1, 127));
 | |
|   write_start_cursor.file_id_ = 2;
 | |
|   write_start_cursor.log_id_ = replay_start_cursor_.log_id_;
 | |
|   write_start_cursor.offset_ = 0;
 | |
| 
 | |
|   // mock drop tenant
 | |
|   tmp_slogger->~ObStorageLogger();
 | |
|   OB_DELETE(ObStorageLogger, ObModIds::TEST, tmp_slogger);
 | |
| 
 | |
|   tmp_slogger = OB_NEW(ObStorageLogger, ObModIds::TEST);
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->init(SLOGGERMGR, 500));
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->start());
 | |
| 
 | |
|   tenant_base.set(tmp_slogger);
 | |
|   ObTenantEnv::set_tenant(&tenant_base);
 | |
| 
 | |
|   guard.switch_to(10);
 | |
|   slogger = MTL(ObStorageLogger*);
 | |
|   slogger->is_start_ = false;
 | |
|   slogger->start_log(write_start_cursor);
 | |
| 
 | |
|   for (int i = 0; i < tenant_storage_.slog_cnt_; i++) {
 | |
|     log_param.data_ = &tenant_storage_.slogs_[i];
 | |
|     ret = slogger->write_log(log_param);
 | |
|     ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   }
 | |
|   ret = replayer_.init(slogger->get_dir(), log_file_spec_);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ret = replayer_.register_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE, &redo_module);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ret = replayer_.replay(replay_start_cursor_, replay_finish_cursor_, OB_SERVER_TENANT_ID);
 | |
|   ASSERT_EQ(OB_SUCCESS, ret);
 | |
|   ASSERT_TRUE(tenant_storage_ == redo_module);
 | |
| }
 | |
| 
 | |
| TEST_F(TestStorageLogReplay, test_mock_restart)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   ObLogCursor write_start_cursor;
 | |
|   write_start_cursor.file_id_ = 1;
 | |
|   write_start_cursor.log_id_ = 1;
 | |
|   SimpleObStorageModule redo_module;
 | |
| 
 | |
|   ObStorageLogger *tmp_slogger = OB_NEW(ObStorageLogger, ObModIds::TEST);
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->init(SLOGGERMGR, 500));
 | |
|   ASSERT_EQ(OB_SUCCESS, tmp_slogger->start());
 | |
| 
 | |
|   ObTenantBase tenant_base(10);
 | |
|   tenant_base.set(tmp_slogger);
 | |
|   ObTenantEnv::set_tenant(&tenant_base);
 | |
|   ASSERT_EQ(OB_SUCCESS, tenant_base.init());
 | |
| 
 | |
|   ObTenantSwitchGuard guard;
 | |
|   guard.switch_to(10);
 | |
|   ObStorageLogger *slogger = MTL(ObStorageLogger*);
 | |
|   slogger->is_start_ = false;
 | |
|   slogger->start_log(write_start_cursor);
 | |
| 
 | |
|   ObStorageLogParam log_param;
 | |
|   log_param.cmd_ = ObIRedoModule::gen_cmd(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE,
 | |
|       ObRedoLogSubType::OB_REDO_LOG_CREATE_LS);
 | |
| 
 | |
|   build_storage(40);
 | |
|   // first time to write slog
 | |
|   for (int i = 0; i < tenant_storage_.slog_cnt_; i++) {
 | |
|     log_param.data_ = &tenant_storage_.slogs_[i];
 | |
|     ASSERT_EQ(OB_SUCCESS, slogger->write_log(log_param));
 | |
|   }
 | |
|   // replay first slog file
 | |
|   ASSERT_EQ(OB_SUCCESS, replayer_.init(slogger->get_dir(), log_file_spec_));
 | |
|   ASSERT_EQ(OB_SUCCESS, replayer_.register_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE, &redo_module));
 | |
|   ASSERT_EQ(OB_SUCCESS, replayer_.replay(replay_start_cursor_, replay_finish_cursor_, OB_SERVER_TENANT_ID));
 | |
|   replayer_.destroy();
 | |
|   redo_module.reset();
 | |
| 
 | |
|   // reset slogger and set its start cursor as replay_finish_cursor
 | |
|   slogger->destroy();
 | |
|   ASSERT_EQ(OB_SUCCESS, slogger->init(SLOGGERMGR, 500));
 | |
|   ASSERT_EQ(OB_SUCCESS, slogger->start());
 | |
|   slogger->is_start_ = false;
 | |
|   ASSERT_EQ(OB_SUCCESS, slogger->start_log(replay_finish_cursor_));
 | |
| 
 | |
|   build_storage(30);
 | |
|   // second time to write slog
 | |
|   for (int i = 0; i < tenant_storage_.slog_cnt_; i++) {
 | |
|     log_param.data_ = &tenant_storage_.slogs_[i];
 | |
|     ASSERT_EQ(OB_SUCCESS, slogger->write_log(log_param));
 | |
|   }
 | |
|   // replay first and second slog files
 | |
|   ASSERT_EQ(OB_SUCCESS, replayer_.init(slogger->get_dir(), log_file_spec_));
 | |
|   ASSERT_EQ(OB_SUCCESS, replayer_.register_redo_module(ObRedoLogMainType::OB_REDO_LOG_TENANT_STORAGE, &redo_module));
 | |
|   ASSERT_EQ(OB_SUCCESS, replayer_.replay(replay_start_cursor_, replay_finish_cursor_, OB_SERVER_TENANT_ID));
 | |
| }
 | |
| 
 | |
| }
 | |
| }
 | |
| 
 | |
| int main(int argc, char **argv)
 | |
| {
 | |
|   system("rm -f test_storage_log_replay.log*");
 | |
|   OB_LOGGER.set_file_name("test_storage_log_replay.log", true);
 | |
|   OB_LOGGER.set_log_level("INFO");
 | |
|   testing::InitGoogleTest(&argc, argv);
 | |
|   return RUN_ALL_TESTS();
 | |
| }
 | 
