380 lines
13 KiB
C++
380 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_);
|
|
}
|
|
|
|
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();
|
|
}
|