// owner: jiahua.cjh // owner group: storage /** * 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 #define private public #define protected public #include "lib/ob_errno.h" #include "lib/allocator/page_arena.h" #include "lib/oblog/ob_log.h" #include "share/rc/ob_tenant_base.h" #include "mtlenv/mock_tenant_module_env.h" #include "mtlenv/storage/medium_info_helper.h" #include "unittest/storage/test_tablet_helper.h" #include "unittest/storage/test_dml_common.h" #include "storage/tablet/ob_tablet.h" #define USING_LOG_PREFIX STORAGE using namespace oceanbase::common; using namespace oceanbase::share; using namespace oceanbase::storage; namespace oceanbase { int ObClusterVersion::get_tenant_data_version(const uint64_t tenant_id, uint64_t &data_version) { data_version = DATA_VERSION_4_3_2_0; return OB_SUCCESS; } namespace unittest { class TestMigrationTabletParam : public ::testing::Test { public: TestMigrationTabletParam() = default; virtual ~TestMigrationTabletParam() = default; public: static constexpr uint64_t TENANT_ID = 1001; static const share::ObLSID LS_ID; public: static void SetUpTestCase(); static void TearDownTestCase(); public: static int create_ls(const uint64_t tenant_id, const share::ObLSID &ls_id, ObLSHandle &ls_handle); static int remove_ls(const share::ObLSID &ls_id); int create_tablet(const common::ObTabletID &tablet_id, ObTabletHandle &tablet_handle); static int insert_data_into_mds_data(ObArenaAllocator &allocator, mds::MdsDumpKV &kv); static bool is_user_data_equal(const ObTabletCreateDeleteMdsUserData &left, const ObTabletCreateDeleteMdsUserData &right); public: ObArenaAllocator allocator_; }; const share::ObLSID TestMigrationTabletParam::LS_ID(1234); void TestMigrationTabletParam::SetUpTestCase() { int ret = OB_SUCCESS; ret = MockTenantModuleEnv::get_instance().init(); ASSERT_EQ(OB_SUCCESS, ret); ObServerStorageMetaService::get_instance().is_started_ = true; // create ls ObLSHandle ls_handle; ret = create_ls(TENANT_ID, LS_ID, ls_handle); ASSERT_EQ(OB_SUCCESS, ret); } void TestMigrationTabletParam::TearDownTestCase() { int ret = OB_SUCCESS; // remove ls ret = remove_ls(LS_ID); ASSERT_EQ(OB_SUCCESS, ret); MockTenantModuleEnv::get_instance().destroy(); } int TestMigrationTabletParam::create_ls(const uint64_t tenant_id, const share::ObLSID &ls_id, ObLSHandle &ls_handle) { int ret = OB_SUCCESS; ret = TestDmlCommon::create_ls(tenant_id, ls_id, ls_handle); return ret; } int TestMigrationTabletParam::remove_ls(const share::ObLSID &ls_id) { int ret = OB_SUCCESS; ret = MTL(ObLSService*)->remove_ls(ls_id); return ret; } int TestMigrationTabletParam::create_tablet(const common::ObTabletID &tablet_id, ObTabletHandle &tablet_handle) { int ret = OB_SUCCESS; const uint64_t table_id = 1234567; share::schema::ObTableSchema table_schema; ObLSHandle ls_handle; ObLS *ls = nullptr; if (OB_FAIL(MTL(ObLSService*)->get_ls(LS_ID, ls_handle, ObLSGetMod::STORAGE_MOD))) { LOG_WARN("failed to get ls", K(ret)); } else if (OB_ISNULL(ls = ls_handle.get_ls())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ls is null", K(ret), KP(ls)); } else if (OB_FAIL(build_test_schema(table_schema, table_id))) { LOG_WARN("failed to build table schema"); } else if (OB_FAIL(TestTabletHelper::create_tablet(ls_handle, tablet_id, table_schema, allocator_, ObTabletStatus::MAX, share::SCN::invalid_scn(), tablet_handle))) { LOG_WARN("failed to create tablet", K(ret)); } return ret; } int TestMigrationTabletParam::insert_data_into_mds_data(ObArenaAllocator &allocator, mds::MdsDumpKV &kv) { int ret = OB_SUCCESS; ObTabletCreateDeleteMdsUserData user_data; user_data.tablet_status_ = ObTabletStatus::NORMAL; const int64_t serialize_size = user_data.get_serialize_size(); char *buffer = static_cast(allocator.alloc(serialize_size)); int64_t pos = 0; if (OB_ISNULL(buffer)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc memory", K(ret), K(serialize_size)); } else if (OB_FAIL(user_data.serialize(buffer, serialize_size, pos))) { LOG_WARN("fail to serialize user data", K(ret)); } else { kv.v_.user_data_.assign(buffer, serialize_size); } return ret; } bool TestMigrationTabletParam::is_user_data_equal(const ObTabletCreateDeleteMdsUserData &left, const ObTabletCreateDeleteMdsUserData &right) { const bool res = left.tablet_status_ == right.tablet_status_ && left.transfer_scn_ == right.transfer_scn_ && left.transfer_ls_id_ == right.transfer_ls_id_ && left.data_type_ == right.data_type_ && left.create_commit_scn_ == right.create_commit_scn_ && left.create_commit_version_ == right.create_commit_version_ && left.delete_commit_version_ == right.delete_commit_version_ && left.start_transfer_commit_version_ == right.start_transfer_commit_version_; return res; } TEST_F(TestMigrationTabletParam, migration) { int ret = OB_SUCCESS; // create tablet const common::ObTabletID tablet_id(ObTimeUtility::fast_current_time() % 10000000000000); ObTabletHandle tablet_handle; ObTabletStatus status(ObTabletStatus::MAX); share::SCN create_commit_scn; create_commit_scn = share::SCN::plus(share::SCN::min_scn(), 100); ret = create_tablet(tablet_id, tablet_handle); ASSERT_EQ(OB_SUCCESS, ret); ObTablet *tablet = tablet_handle.get_obj(); ASSERT_NE(nullptr, tablet); // write data to mds table { ObTabletCreateDeleteMdsUserData user_data; user_data.tablet_status_ = ObTabletStatus::NORMAL; user_data.data_type_ = ObTabletMdsUserDataType::CREATE_TABLET; mds::MdsCtx ctx(mds::MdsWriter(transaction::ObTransID(123))); ret = tablet->set_tablet_status(user_data, ctx); ASSERT_EQ(OB_SUCCESS, ret); share::SCN redo_scn = share::SCN::plus(share::SCN::min_scn(), 50); ctx.on_redo(redo_scn); ctx.on_commit(create_commit_scn, create_commit_scn); } // { // // build migration param v2 // ObMigrationTabletParam param_v2; // ret = tablet->build_migration_tablet_param(param_v2); // ASSERT_EQ(OB_NOT_SUPPORTED, ret); // // insert some data into migration param // ret = insert_data_into_mds_data(allocator_, param_v2.mds_data_.tablet_status_committed_kv_); // ASSERT_EQ(OB_SUCCESS, ret); // param_v2.version_ = ObMigrationTabletParam::PARAM_VERSION_V2; // int64_t serialize_size = param_v2.get_serialize_size(); // char *buffer = new char[serialize_size](); // int64_t pos = 0; // ret = param_v2.serialize(buffer, serialize_size, pos); // ASSERT_EQ(OB_SUCCESS, ret); // ASSERT_EQ(serialize_size, pos); // // param v2 deserialize // ObMigrationTabletParam param2; // pos = 0; // ret = param2.deserialize(buffer, serialize_size, pos); // ASSERT_EQ(OB_SUCCESS, ret); // ASSERT_EQ(pos, serialize_size); // ASSERT_TRUE(param2.is_valid()); // delete [] buffer; // } { // build migration param v3 ObMigrationTabletParam param_v3; ret = tablet->build_migration_tablet_param(param_v3); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(true, param_v3.version_ == ObMigrationTabletParam::PARAM_VERSION_V3); // insert some data into migration param ret = insert_data_into_mds_data(allocator_, param_v3.mds_data_.tablet_status_committed_kv_); ASSERT_EQ(OB_SUCCESS, ret); int64_t serialize_size = param_v3.get_serialize_size(); char *buffer = new char[serialize_size](); int64_t pos = 0; ret = param_v3.serialize(buffer, serialize_size, pos); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(serialize_size, pos); // param v3 deserialize ObMigrationTabletParam param2; pos = 0; ret = param2.deserialize(buffer, serialize_size, pos); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(pos, serialize_size); ASSERT_TRUE(param2.is_valid()); delete [] buffer; } } TEST_F(TestMigrationTabletParam, transfer) { int ret = OB_SUCCESS; // create tablet const common::ObTabletID tablet_id(ObTimeUtility::fast_current_time() % 10000000000000); ObTabletHandle tablet_handle; ObTabletStatus status(ObTabletStatus::MAX); ret = create_tablet(tablet_id, tablet_handle); ASSERT_EQ(OB_SUCCESS, ret); ObTablet *tablet = tablet_handle.get_obj(); ASSERT_NE(nullptr, tablet); // write data to mds table { ObTabletCreateDeleteMdsUserData user_data; user_data.tablet_status_ = ObTabletStatus::TRANSFER_OUT; user_data.data_type_ = ObTabletMdsUserDataType::START_TRANSFER_OUT; user_data.transfer_scn_ = share::SCN::plus(share::SCN::min_scn(), 60); share::SCN transfer_commit_scn; transfer_commit_scn = share::SCN::plus(share::SCN::min_scn(), 70); mds::MdsCtx ctx(mds::MdsWriter(transaction::ObTransID(123))); ret = tablet->set_tablet_status(user_data, ctx); ASSERT_EQ(OB_SUCCESS, ret); share::SCN redo_scn = user_data.transfer_scn_; ctx.on_redo(redo_scn); ctx.on_commit(transfer_commit_scn, transfer_commit_scn); } // write medium info { compaction::ObMediumCompactionInfoKey key(100); compaction::ObMediumCompactionInfo info; ret = MediumInfoHelper::build_medium_compaction_info(allocator_, info, 100); ASSERT_EQ(OB_SUCCESS, ret); mds::MdsCtx ctx(mds::MdsWriter(transaction::ObTransID(777))); ret = tablet->set(key, info, ctx, 1_s/*lock_timeout_us*/); ASSERT_EQ(OB_SUCCESS, ret); share::SCN redo_scn = share::SCN::plus(share::SCN::min_scn(), 110); ctx.on_redo(redo_scn); share::SCN commit_scn = share::SCN::plus(share::SCN::min_scn(), 120); ctx.on_commit(commit_scn, commit_scn); } { // build transfer tablet param v3 ObMigrationTabletParam param_v3; ASSERT_EQ(false, param_v3.is_valid()); share::ObLSID dst_ls_id(1001); const int64_t data_version = DATA_VERSION_4_3_2_0; ret = tablet->build_transfer_tablet_param(data_version, dst_ls_id, param_v3); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(true, param_v3.is_valid()); ASSERT_EQ(true, param_v3.version_ == ObMigrationTabletParam::PARAM_VERSION_V3); ASSERT_EQ(param_v3.last_persisted_committed_tablet_status_.data_type_, ObTabletMdsUserDataType::START_TRANSFER_IN); ASSERT_EQ(param_v3.last_persisted_committed_tablet_status_.tablet_status_, ObTabletStatus::TRANSFER_IN); int64_t serialize_size = param_v3.get_serialize_size(); char *buffer = new char[serialize_size](); int64_t pos = 0; ret = param_v3.serialize(buffer, serialize_size, pos); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(serialize_size, pos); // param v3 deserialize ObMigrationTabletParam param2; pos = 0; ret = param2.deserialize(buffer, serialize_size, pos); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(pos, serialize_size); ASSERT_TRUE(param2.is_valid()); ASSERT_EQ(true, is_user_data_equal(param_v3.last_persisted_committed_tablet_status_, param2.last_persisted_committed_tablet_status_)); ObMigrationTabletParam test_param; test_param.assign(param_v3); ASSERT_EQ(true, is_user_data_equal(param_v3.last_persisted_committed_tablet_status_, test_param.last_persisted_committed_tablet_status_)); delete [] buffer; } } TEST_F(TestMigrationTabletParam, empty_shell_transfer) { int ret = OB_SUCCESS; // create tablet const common::ObTabletID tablet_id(ObTimeUtility::fast_current_time() % 10000000000000); share::schema::ObTableSchema schema; ObLSHandle ls_handle; ObLS *ls = nullptr; ObLSTabletService *ls_tablet_service = nullptr; if (OB_FAIL(MTL(ObLSService*)->get_ls(LS_ID, ls_handle, ObLSGetMod::STORAGE_MOD))) { LOG_WARN("failed to get ls", K(ret)); } else if (OB_ISNULL(ls = ls_handle.get_ls())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ls is null", K(ret), KP(ls)); } else { ls_tablet_service = ls->get_tablet_svr(); } ASSERT_NE(nullptr, ls_tablet_service); TestSchemaUtils::prepare_data_schema(schema); ret = TestTabletHelper::create_tablet(ls_handle, tablet_id, schema, allocator_, ObTabletStatus::Status::DELETED); ASSERT_EQ(OB_SUCCESS, ret); ret = ls_tablet_service->update_tablet_to_empty_shell(tablet_id); ASSERT_EQ(OB_SUCCESS, ret); ObTabletHandle empty_shell_tablet_handle; ret = ls_tablet_service->get_tablet(tablet_id, empty_shell_tablet_handle, 0, ObMDSGetTabletMode::READ_WITHOUT_CHECK); ASSERT_EQ(OB_SUCCESS, ret); ObTablet *empty_shell_tablet = empty_shell_tablet_handle.get_obj(); ASSERT_NE(nullptr, empty_shell_tablet); { // build transfer tablet param v3 ObMigrationTabletParam param_v3; ASSERT_EQ(false, param_v3.is_valid()); share::ObLSID dst_ls_id(1001); const int64_t data_version = DATA_VERSION_4_3_2_0; ret = empty_shell_tablet->build_transfer_tablet_param(data_version, dst_ls_id, param_v3); ASSERT_EQ(OB_ERR_UNEXPECTED, ret); } { // build migration tablet param v3 ObMigrationTabletParam param_v3; ASSERT_EQ(false, param_v3.is_valid()); ASSERT_EQ(false, param_v3.is_valid()); ret = empty_shell_tablet->build_migration_tablet_param(param_v3); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(true, param_v3.is_valid()); ASSERT_EQ(true, param_v3.version_ == ObMigrationTabletParam::PARAM_VERSION_V3); ObMigrationTabletParam test_param; test_param.assign(param_v3); ASSERT_EQ(true, is_user_data_equal(param_v3.last_persisted_committed_tablet_status_, test_param.last_persisted_committed_tablet_status_)); } } } // namespace unittest } // namespace oceanbase int main(int argc, char **argv) { system("rm -rf test_migration_tablet_param.log*"); OB_LOGGER.set_file_name("test_migration_tablet_param.log", true); OB_LOGGER.set_log_level("INFO"); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }