diff --git a/mittest/mtlenv/mock_tenant_module_env.h b/mittest/mtlenv/mock_tenant_module_env.h index 3a5163e64..3a0c6afe1 100644 --- a/mittest/mtlenv/mock_tenant_module_env.h +++ b/mittest/mtlenv/mock_tenant_module_env.h @@ -92,6 +92,7 @@ #include "observer/table/ob_htable_lock_mgr.h" #include "observer/table/ob_table_session_pool.h" #include "share/index_usage/ob_index_usage_info_mgr.h" +#include "storage/tenant_snapshot/ob_tenant_snapshot_service.h" namespace oceanbase { @@ -715,6 +716,7 @@ int MockTenantModuleEnv::init() MTL_BIND2(mtl_new_default, table::ObTableApiSessPoolMgr::mtl_init, mtl_start_default, mtl_stop_default, mtl_wait_default, mtl_destroy_default); MTL_BIND2(mtl_new_default, ObIndexUsageInfoMgr::mtl_init, mtl_start_default, mtl_stop_default, mtl_wait_default, mtl_destroy_default); MTL_BIND2(mtl_new_default, storage::ObTabletMemtableMgrPool::mtl_init, nullptr, nullptr, nullptr, mtl_destroy_default); + MTL_BIND2(mtl_new_default, ObTenantSnapshotService::mtl_init, mtl_start_default, mtl_stop_default, nullptr, mtl_destroy_default); } if (OB_FAIL(ret)) { diff --git a/mittest/mtlenv/storage/CMakeLists.txt b/mittest/mtlenv/storage/CMakeLists.txt index 3b5cb61bd..02ba8d916 100644 --- a/mittest/mtlenv/storage/CMakeLists.txt +++ b/mittest/mtlenv/storage/CMakeLists.txt @@ -33,5 +33,6 @@ storage_dml_unittest(test_ls_tablet_info_writer_and_reader test_ls_tablet_info_w add_subdirectory(checkpoint) add_subdirectory(blocksstable) +add_subdirectory(tenant_snapshot) target_link_libraries(test_memtable PUBLIC mock_tx_ctx mock_tx_log_adapter) diff --git a/mittest/mtlenv/storage/tenant_snapshot/CMakeLists.txt b/mittest/mtlenv/storage/tenant_snapshot/CMakeLists.txt new file mode 100644 index 000000000..730226081 --- /dev/null +++ b/mittest/mtlenv/storage/tenant_snapshot/CMakeLists.txt @@ -0,0 +1,3 @@ +storage_unittest(test_tenant_snapshot_mgr) +storage_unittest(test_tenant_snapshot_def) +storage_unittest(test_ls_snapshot_mgr) \ No newline at end of file diff --git a/mittest/mtlenv/storage/tenant_snapshot/test_ls_snapshot_mgr.cpp b/mittest/mtlenv/storage/tenant_snapshot/test_ls_snapshot_mgr.cpp new file mode 100644 index 000000000..523a062b3 --- /dev/null +++ b/mittest/mtlenv/storage/tenant_snapshot/test_ls_snapshot_mgr.cpp @@ -0,0 +1,100 @@ +/** + * 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 STORAGE + +#include + +#define private public +#define protected public + +#include "lib/oblog/ob_log.h" +#include "mtlenv/mock_tenant_module_env.h" +#include "storage/tenant_snapshot/ob_ls_snapshot_mgr.h" +#include "storage/slog_ckpt/ob_tenant_meta_snapshot_handler.h" +#include "rootserver/tenant_snapshot/ob_tenant_snapshot_util.h" +#include "share/tenant_snapshot/ob_tenant_snapshot_id.h" +#undef private + +namespace oceanbase +{ +namespace unittest +{ + +class TestLSSnapshotMgr : public ::testing::Test +{ +public: + static void SetUpTestCase() + { + EXPECT_EQ(OB_SUCCESS, MockTenantModuleEnv::get_instance().init()); + } + static void TearDownTestCase() + { + MockTenantModuleEnv::get_instance().destroy(); + } + virtual void SetUp() + { + ASSERT_EQ(OB_SUCCESS, mgr_.init(&meta_handler_)); + } + virtual void TearDown() + { + mgr_.destroy(); + } + +public: + ObLSSnapshotMgr mgr_; + ObTenantMetaSnapshotHandler meta_handler_; +}; + +TEST_F(TestLSSnapshotMgr, test_ls_snapshot_acquire_and_get) +{ + uint64_t tenant_id = 1002; + ObLSID ls_id(1001); + ObTenantSnapshotID tsnap_id; + ObLSSnapshot *ls_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, + rootserver::ObTenantSnapshotUtil::generate_tenant_snapshot_id(tenant_id, tsnap_id)); + ASSERT_EQ(OB_SUCCESS, mgr_.acquire_ls_snapshot(tsnap_id, ls_id, ls_snapshot)); + ASSERT_NE(nullptr, ls_snapshot); + mgr_.revert_ls_snapshot(ls_snapshot); + + ObLSSnapshot *ls_snapshot_ptr2 = nullptr; + ASSERT_EQ(OB_SUCCESS, mgr_.get_ls_snapshot(tsnap_id, ls_id, ls_snapshot_ptr2)); + ASSERT_EQ(ls_snapshot, ls_snapshot_ptr2); + mgr_.revert_ls_snapshot(ls_snapshot_ptr2); +} + +TEST_F(TestLSSnapshotMgr, test_del_ls_snapshot) +{ + uint64_t tenant_id = 1002; + ObLSID ls_id(1001); + ObTenantSnapshotID tsnap_id; + ObLSSnapshot *ls_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, + rootserver::ObTenantSnapshotUtil::generate_tenant_snapshot_id(tenant_id, tsnap_id)); + ASSERT_EQ(OB_SUCCESS, mgr_.acquire_ls_snapshot(tsnap_id, ls_id, ls_snapshot)); + ASSERT_NE(nullptr, ls_snapshot); + ASSERT_EQ(OB_SUCCESS, mgr_.del_ls_snapshot(tsnap_id, ls_id)); + mgr_.revert_ls_snapshot(ls_snapshot); +} + +} // namespace storage +} // namespace oceanbase + +int main(int argc, char **argv) +{ + system("rm -f test_ls_snapshot_mgr.log*"); + ::testing::InitGoogleTest(&argc, argv); + OB_LOGGER.set_log_level("INFO"); + OB_LOGGER.set_file_name("test_ls_snapshot_mgr.log", true); + return RUN_ALL_TESTS(); +} diff --git a/mittest/mtlenv/storage/tenant_snapshot/test_tenant_snapshot_def.cpp b/mittest/mtlenv/storage/tenant_snapshot/test_tenant_snapshot_def.cpp new file mode 100644 index 000000000..b06de7114 --- /dev/null +++ b/mittest/mtlenv/storage/tenant_snapshot/test_tenant_snapshot_def.cpp @@ -0,0 +1,137 @@ +/** + * 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 STORAGE + +#include + +#define private public +#define protected public + +#include "lib/oblog/ob_log.h" +#include "mtlenv/mock_tenant_module_env.h" +#include "storage/tenant_snapshot/ob_ls_snapshot_mgr.h" +#include "storage/slog_ckpt/ob_tenant_meta_snapshot_handler.h" +#include "rootserver/tenant_snapshot/ob_tenant_snapshot_util.h" +#include "share/tenant_snapshot/ob_tenant_snapshot_id.h" +#undef private + +namespace oceanbase +{ +namespace unittest +{ + +class TestTenantSnapshotDef : public ::testing::Test +{ +public: + static void SetUpTestCase() + { + EXPECT_EQ(OB_SUCCESS, MockTenantModuleEnv::get_instance().init()); + } + static void TearDownTestCase() + { + MockTenantModuleEnv::get_instance().destroy(); + } + virtual void SetUp() + { + ASSERT_EQ(OB_SUCCESS, ls_snapshot_mgr_.init(&meta_handler_)); + ASSERT_EQ(OB_SUCCESS, tsnap_mgr_.init(&ls_snapshot_mgr_, &meta_handler_)); + } + virtual void TearDown() + { + tsnap_mgr_.destroy(); + } + +public: + ObLSSnapshotMgr ls_snapshot_mgr_; + ObTenantSnapshotMgr tsnap_mgr_; + ObTenantMetaSnapshotHandler meta_handler_; +}; + +TEST_F(TestTenantSnapshotDef, test_build_all_ls_snapshot) +{ + int ret = OB_SUCCESS; + uint64_t tenant_id = 1002; + ObTenantSnapshotID tsnap_id; + ObLSSnapshot *ls_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, + rootserver::ObTenantSnapshotUtil::generate_tenant_snapshot_id(tenant_id, tsnap_id)); + ObTenantSnapshot *tenant_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, tsnap_mgr_.acquire_tenant_snapshot(tsnap_id, tenant_snapshot)); + ASSERT_NE(nullptr, tenant_snapshot); + + ObArray creating_ls_id_arr; + ASSERT_EQ(OB_SUCCESS, creating_ls_id_arr.push_back(ObLSID(1))); + ASSERT_EQ(OB_SUCCESS, creating_ls_id_arr.push_back(ObLSID(1001))); + ASSERT_EQ(2, creating_ls_id_arr.size()); + + tenant_snapshot->build_all_snapshots_(creating_ls_id_arr); + ObArray ls_ids; + ASSERT_EQ(OB_SUCCESS, meta_handler_.get_all_ls_snapshot(tsnap_id, ls_ids)); + tsnap_mgr_.revert_tenant_snapshot(tenant_snapshot); + + + bool is_tenant_snap_exist = false; + ObArray snapshot_ids; + meta_handler_.get_all_tenant_snapshot(snapshot_ids); + ARRAY_FOREACH_N(snapshot_ids, i, count) { + if (snapshot_ids.at(i).id() == tsnap_id.id()) { + is_tenant_snap_exist = true; + } + } + ASSERT_TRUE(is_tenant_snap_exist); +} + +TEST_F(TestTenantSnapshotDef, test_gc_tenant_snapshot) +{ + int ret = OB_SUCCESS; + uint64_t tenant_id = 1002; + ObTenantSnapshotID tsnap_id; + ObLSSnapshot *ls_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, + rootserver::ObTenantSnapshotUtil::generate_tenant_snapshot_id(tenant_id, tsnap_id)); + ObTenantSnapshot *tenant_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, tsnap_mgr_.acquire_tenant_snapshot(tsnap_id, tenant_snapshot)); + ASSERT_NE(nullptr, tenant_snapshot); + + ObArray creating_ls_id_arr; + ASSERT_EQ(OB_SUCCESS, creating_ls_id_arr.push_back(ObLSID(1))); + ASSERT_EQ(OB_SUCCESS, creating_ls_id_arr.push_back(ObLSID(1001))); + ASSERT_EQ(2, creating_ls_id_arr.size()); + + tenant_snapshot->build_all_snapshots_(creating_ls_id_arr); + + bool is_tenant_snap_exist = false; + ObArray snapshot_ids; + meta_handler_.get_all_tenant_snapshot(snapshot_ids); + ARRAY_FOREACH_N(snapshot_ids, i, count) { + if (snapshot_ids.at(i).id() == tsnap_id.id()) { + is_tenant_snap_exist = true; + } + } + ASSERT_TRUE(is_tenant_snap_exist); + ASSERT_EQ(OB_SUCCESS, tenant_snapshot->gc_tenant_snapshot_()); + ASSERT_FALSE(tenant_snapshot->meta_existed_); + tsnap_mgr_.revert_tenant_snapshot(tenant_snapshot); +} + +} // namespace storage +} // namespace oceanbase + +int main(int argc, char **argv) +{ + system("rm -f test_tenant_snapshot_def.log*"); + ::testing::InitGoogleTest(&argc, argv); + OB_LOGGER.set_log_level("INFO"); + OB_LOGGER.set_file_name("test_tenant_snapshot_def.log", true); + return RUN_ALL_TESTS(); +} diff --git a/mittest/mtlenv/storage/tenant_snapshot/test_tenant_snapshot_mgr.cpp b/mittest/mtlenv/storage/tenant_snapshot/test_tenant_snapshot_mgr.cpp new file mode 100644 index 000000000..3e641e0ad --- /dev/null +++ b/mittest/mtlenv/storage/tenant_snapshot/test_tenant_snapshot_mgr.cpp @@ -0,0 +1,105 @@ +/** + * 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 STORAGE + +#include + +#define private public +#define protected public + +#include "lib/oblog/ob_log.h" +#include "mtlenv/mock_tenant_module_env.h" +#include "rootserver/tenant_snapshot/ob_tenant_snapshot_util.h" +#include "storage/tenant_snapshot/ob_tenant_snapshot_mgr.h" +#undef private + +namespace oceanbase +{ +namespace unittest +{ + +class TestTenantSnapshotMgr : public ::testing::Test +{ +public: + static void SetUpTestCase() + { + EXPECT_EQ(OB_SUCCESS, MockTenantModuleEnv::get_instance().init()); + } + static void TearDownTestCase() + { + MockTenantModuleEnv::get_instance().destroy(); + } + virtual void SetUp() + { + ASSERT_EQ(OB_SUCCESS, ls_snapshot_mgr_.init(&meta_handler_)); + ASSERT_EQ(OB_SUCCESS, tsnap_mgr_.init(&ls_snapshot_mgr_, &meta_handler_)); + } + virtual void TearDown() + { + ls_snapshot_mgr_.destroy(); + tsnap_mgr_.destroy(); + } + +public: + ObTenantSnapshotMgr tsnap_mgr_; + ObLSSnapshotMgr ls_snapshot_mgr_; + ObTenantMetaSnapshotHandler meta_handler_; +}; + +TEST_F(TestTenantSnapshotMgr, test_acquire_and_get) +{ + uint64_t tenant_id = 1002; + ObLSID ls_id(1001); + ObTenantSnapshotID tsnap_id; + ObLSSnapshot *ls_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, + rootserver::ObTenantSnapshotUtil::generate_tenant_snapshot_id(tenant_id, tsnap_id)); + ObTenantSnapshot *tenant_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, tsnap_mgr_.acquire_tenant_snapshot(tsnap_id, tenant_snapshot)); + ASSERT_NE(nullptr, tenant_snapshot); + tsnap_mgr_.revert_tenant_snapshot(tenant_snapshot); + + ObTenantSnapshot *tsnap_ptr = nullptr; + ASSERT_EQ(OB_SUCCESS, tsnap_mgr_.get_tenant_snapshot(tsnap_id, tsnap_ptr)); + ASSERT_EQ(tenant_snapshot, tsnap_ptr); + tsnap_mgr_.revert_tenant_snapshot(tsnap_ptr); +} + +TEST_F(TestTenantSnapshotMgr, test_del_tenant_snapshot) +{ + uint64_t tenant_id = 1002; + ObLSID ls_id(1001); + ObTenantSnapshotID tsnap_id; + ObLSSnapshot *ls_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, + rootserver::ObTenantSnapshotUtil::generate_tenant_snapshot_id(tenant_id, tsnap_id)); + ObTenantSnapshot *tenant_snapshot = nullptr; + ASSERT_EQ(OB_SUCCESS, tsnap_mgr_.acquire_tenant_snapshot(tsnap_id, tenant_snapshot)); + ASSERT_NE(nullptr, tenant_snapshot); + ASSERT_EQ(OB_SUCCESS, tsnap_mgr_.del_tenant_snapshot(tsnap_id)); + ASSERT_EQ(0, tsnap_mgr_.tenant_snapshot_map_.size()); + + tsnap_mgr_.revert_tenant_snapshot(tenant_snapshot); +} + +} // namespace storage +} // namespace oceanbase + +int main(int argc, char **argv) +{ + system("rm -f test_tenant_snapshot_mgr.log*"); + ::testing::InitGoogleTest(&argc, argv); + OB_LOGGER.set_log_level("INFO"); + OB_LOGGER.set_file_name("test_tenant_snapshot_mgr.log", true); + return RUN_ALL_TESTS(); +} diff --git a/mittest/simple_server/CMakeLists.txt b/mittest/simple_server/CMakeLists.txt index e5b158e84..0cb6a2a3f 100644 --- a/mittest/simple_server/CMakeLists.txt +++ b/mittest/simple_server/CMakeLists.txt @@ -104,6 +104,7 @@ ob_unittest_observer(test_keep_alive_min_start_scn test_keep_alive_min_start_scn ob_unittest_observer(test_ls_replica test_ls_replica.cpp) ob_unittest_observer(test_create_clone_tenant_resource_pool test_create_clone_tenant_resource_pool.cpp) ob_unittest_observer(test_tablet_autoinc_mgr test_tablet_autoinc_mgr.cpp) +ob_unittest_observer(test_tenant_snapshot_service test_tenant_snapshot_service.cpp) # TODO(muwei.ym): open later ob_ha_unittest_observer(test_transfer_handler storage_ha/test_transfer_handler.cpp) ob_ha_unittest_observer(test_transfer_and_restart_basic storage_ha/test_transfer_and_restart_basic.cpp) diff --git a/mittest/simple_server/test_tenant_snapshot_service.cpp b/mittest/simple_server/test_tenant_snapshot_service.cpp new file mode 100644 index 000000000..edd3cf196 --- /dev/null +++ b/mittest/simple_server/test_tenant_snapshot_service.cpp @@ -0,0 +1,263 @@ +/** + * Copyright (c) 2022 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 USING_LOG_PREFIX STORAGE +#define protected public +#define private public + +#include "env/ob_simple_cluster_test_base.h" +#include "lib/mysqlclient/ob_mysql_result.h" +#include "mtlenv/mock_tenant_module_env.h" +#include "rootserver/tenant_snapshot/ob_tenant_snapshot_util.h" +#include "storage/tenant_snapshot/ob_tenant_snapshot_service.h" + +namespace oceanbase +{ +namespace unittest +{ +static const char *default_tenant_name = "tt1"; +static const char *default_snapshot_name = "snapshot_1"; + +class TestTenantSnapshotService : public ObSimpleClusterTestBase +{ +public: + TestTenantSnapshotService() : ObSimpleClusterTestBase("test_tenant_snapshot_service_") {} + virtual ~TestTenantSnapshotService(){} + void user_create_tenant_snapshot(ObTenantSnapshotID &snapshot_id, + const int tenant_id, + ObString tenant_name = default_tenant_name, + ObString snapshot_name = default_snapshot_name); + void user_drop_tenant_snapshot(ObString tenant_name = default_tenant_name, + ObString snapshot_name = default_snapshot_name); + bool is_tenant_snapshot_meta_exist(const ObTenantSnapshotID &snapshot_id); + bool is_ls_snapshot_meta_exist(const ObTenantSnapshotID &snapshot_id); + void open_log_archive(const int tenant_id = 1, + ObString tenant_name = default_tenant_name); +}; + +void TestTenantSnapshotService::open_log_archive(const int tenant_id, ObString tenant_name) +{ + int ret = OB_SUCCESS; + char cur_dir[OB_MAX_FILE_NAME_LENGTH]; + ASSERT_NE(nullptr, getcwd(cur_dir, OB_MAX_FILE_NAME_LENGTH)); + SERVER_LOG(INFO, "get cwd as log_archive_dest", K(ObString(cur_dir))); + + MTL_SWITCH(tenant_id) { + common::ObMySQLProxy *sql_proxy = GCTX.sql_proxy_; + ObSqlString sql; + int64_t affected_rows = -1; + sql.assign_fmt("alter system set archive_lag_target = '10s' tenant = %s", tenant_name.ptr()); + ASSERT_EQ(OB_SUCCESS, sql_proxy->write(tenant_id, sql.ptr(), affected_rows)); + + sql.assign_fmt("alter system set log_archive_dest = 'location=file://%s/log_arch' tenant = %s", + cur_dir, tenant_name.ptr()); + ASSERT_EQ(OB_SUCCESS, sql_proxy->write(tenant_id, sql.ptr(), affected_rows)); + + sql.assign_fmt("alter system archivelog tenant = %s", tenant_name.ptr()); + ASSERT_EQ(OB_SUCCESS, sql_proxy->write(tenant_id, sql.ptr(), affected_rows)); + + sql.assign_fmt("ALTER SYSTEM MINOR FREEZE TENANT = %s", tenant_name.ptr()); + ASSERT_EQ(OB_SUCCESS, sql_proxy->write(tenant_id, sql.ptr(), affected_rows)); + + SERVER_LOG(INFO, "open log archive service succ"); + sleep(60); // wait for archive log + SERVER_LOG(INFO, "ready to create tenant snapshot after sleep"); + } + ASSERT_EQ(OB_SUCCESS, ret); +} + +void TestTenantSnapshotService::user_create_tenant_snapshot(ObTenantSnapshotID &snapshot_id, + const int tenant_id, + ObString tenant_name, + ObString snapshot_name) +{ + int ret = OB_SUCCESS; + SERVER_LOG(INFO, "TestTenantSnapshotService begin creating tenant snapshot..."); + common::ObMySQLProxy *sql_proxy = GCTX.sql_proxy_; + + uint64_t tmp_tenant_id = OB_INVALID_TENANT_ID; + ObSqlString sql; + int64_t affected_rows = 0; + int64_t max_retry_cnt = 1; + + ObTenantSnapItem item; + ObTenantSnapshotTableOperator table_operator; + ASSERT_NE(nullptr, GCTX.sql_proxy_); + ASSERT_EQ(OB_SUCCESS, table_operator.init(tenant_id, GCTX.sql_proxy_)); + do { + if (OB_FAIL(rootserver::ObTenantSnapshotUtil::create_tenant_snapshot(tenant_name, + snapshot_name, + tmp_tenant_id, + snapshot_id))) { + if (OB_ERR_TENANT_SNAPSHOT == ret) { + ASSERT_LE(0, max_retry_cnt); + ASSERT_NE(nullptr, GCTX.sql_proxy_); + sql.assign_fmt("ALTER SYSTEM MINOR FREEZE TENANT = %s", tenant_name.ptr()); + ASSERT_EQ(OB_SUCCESS, sql_proxy->write(tenant_id, sql.ptr(), affected_rows)); + sleep(20); // wait for observer creating tenant snapshot and ls_snap + max_retry_cnt++; + SERVER_LOG(INFO, "wait for creating minor freeze complete", K(max_retry_cnt), K(snapshot_name)); + } else { + SERVER_LOG(WARN, "fail to create tenant snapshot", + KR(ret), K(tenant_name), K(snapshot_name), K(tmp_tenant_id)); + break; + } + } else { + SERVER_LOG(INFO, "create tenant snapshot succ", K(tenant_name), K(snapshot_name), K(snapshot_id)); + break; // create snapshot succ + } + } while (max_retry_cnt < 20); + + int count = 0; + while(OB_SUCC(ret)){ // wait for tenant snapshot status become NORMAL + ob_usleep(1 * 1000 * 1000L); // 1s + item.reset(); + ASSERT_EQ(OB_SUCCESS, table_operator.get_tenant_snap_item(snapshot_id, true, item)); + SERVER_LOG(WARN, "get tenant snapshot", K(item)); + if (ObTenantSnapStatus::NORMAL == item.get_status()) { + SERVER_LOG(INFO, "TestTenantSnapshotService create tenant snapshot succ", K(snapshot_id), K(item)); + break; + } else if (ObTenantSnapStatus::CREATING == item.get_status() + || ObTenantSnapStatus::DECIDED == item.get_status()) { + SERVER_LOG(INFO, "notify_scheduler one more time", K(++count)); + ASSERT_EQ(OB_SUCCESS, rootserver::ObTenantSnapshotUtil::notify_scheduler(tenant_id)); + } else { + SERVER_LOG(ERROR, "unexpected tenant snapshot status", KR(ret), K(item)); + ASSERT_TRUE(false); + } + } + SERVER_LOG(INFO, "TestTenantSnapshotService create tenant snapshot finish", K(snapshot_id), K(item)); + ASSERT_EQ(OB_SUCCESS, ret); +} + +void TestTenantSnapshotService::user_drop_tenant_snapshot(ObString tenant_name, ObString snapshot_name) +{ + ASSERT_EQ(OB_SUCCESS, rootserver::ObTenantSnapshotUtil::drop_tenant_snapshot(tenant_name, snapshot_name)); +} + +bool TestTenantSnapshotService::is_tenant_snapshot_meta_exist(const ObTenantSnapshotID &snapshot_id) +{ + int ret = OB_SUCCESS; + ObTenantSnapshotService *tenant_snapshot_service = MTL(ObTenantSnapshotService *); + EXPECT_NE(nullptr, tenant_snapshot_service); + + bool is_tenant_snap_exist = false; + ObArray snapshot_ids; + tenant_snapshot_service->meta_handler_.get_all_tenant_snapshot(snapshot_ids); + ARRAY_FOREACH_N(snapshot_ids, i, count) { + if (snapshot_ids.at(i).id() == snapshot_id.id()) { + is_tenant_snap_exist = true; + } + } + SERVER_LOG(INFO, "after create tenant snapshot, all tenant snapshot ids", K(snapshot_ids.size()), K(snapshot_ids)); + return is_tenant_snap_exist; +} + +bool TestTenantSnapshotService::is_ls_snapshot_meta_exist(const ObTenantSnapshotID &snapshot_id) +{ + int ret = OB_SUCCESS; + ObTenantSnapshotService *tenant_snapshot_service = MTL(ObTenantSnapshotService *); + EXPECT_NE(nullptr, tenant_snapshot_service); + ObArray ls_ids; + tenant_snapshot_service->meta_handler_.get_all_ls_snapshot(snapshot_id, ls_ids); + SERVER_LOG(INFO, "after create tenant snapshot, get ls_ids", K(ls_ids)); + return ls_ids.size() > 0; +} + +TEST_F(TestTenantSnapshotService, test_create_tenant_snapshot) +{ + int ret = OB_SUCCESS; + uint64_t tenant_id = 0; + ASSERT_EQ(OB_SUCCESS, create_tenant()); + ASSERT_EQ(OB_SUCCESS, get_tenant_id(tenant_id)); + ASSERT_NE(0, tenant_id); + open_log_archive(); // open log archive before creating tenant snapshot + ASSERT_FALSE(HasFatalFailure()); + + MTL_SWITCH(tenant_id) + { + SERVER_LOG(INFO, "switch to tenant", K(MTL_ID()), K(tenant_id)); + ObTenantSnapshotService *tenant_snapshot_service = MTL(ObTenantSnapshotService *); + ASSERT_NE(nullptr, tenant_snapshot_service); + + ObTenantSnapshotID snapshot_id; + user_create_tenant_snapshot(snapshot_id, tenant_id); + ASSERT_FALSE(HasFatalFailure()); + ASSERT_EQ(true, is_tenant_snapshot_meta_exist(snapshot_id)); + ASSERT_EQ(true, is_ls_snapshot_meta_exist(snapshot_id)); + + // simulate delayed rpc try to create the same snapshot + obrpc::ObInnerCreateTenantSnapshotArg create_arg; + create_arg.set_tenant_id(tenant_id); + create_arg.set_tenant_snapshot_id(snapshot_id); + ASSERT_EQ(true, create_arg.is_valid()); + tenant_snapshot_service->running_mode_ = ObTenantSnapshotService::NORMAL; + tenant_snapshot_service->run_in_normal_mode_(); + ASSERT_EQ(ObTenantSnapshotService::NORMAL, tenant_snapshot_service->running_mode_); + ASSERT_EQ(true, tenant_snapshot_service->meta_loaded_); + // create_tenant_snapshot() do nothing for existed snapshot + ASSERT_EQ(OB_SUCCESS, tenant_snapshot_service->create_tenant_snapshot(create_arg)); + } + ASSERT_EQ(OB_SUCCESS, ret); +} + +TEST_F(TestTenantSnapshotService, test_drop_tenant_snapshot) +{ + int ret = OB_SUCCESS; + uint64_t tenant_id = 0; + ASSERT_EQ(OB_SUCCESS, get_tenant_id(tenant_id)); + ASSERT_NE(0, tenant_id); + + MTL_SWITCH(tenant_id) + { + SERVER_LOG(INFO, "switch to tenant", K(MTL_ID()), K(tenant_id)); + ObTenantSnapshotService *tenant_snapshot_service = MTL(ObTenantSnapshotService *); + ASSERT_NE(nullptr, tenant_snapshot_service); + + ObTenantSnapItem item; + ObTenantSnapshotTableOperator table_operator; + ASSERT_EQ(OB_SUCCESS, table_operator.init(tenant_id, GCTX.sql_proxy_)); + ASSERT_EQ(OB_SUCCESS, table_operator.get_tenant_snap_item(default_snapshot_name, false, item)); + + ObTenantSnapshotID snapshot_id(item.get_tenant_snapshot_id()); + ASSERT_EQ(true, is_tenant_snapshot_meta_exist(snapshot_id)); + ASSERT_EQ(true, is_ls_snapshot_meta_exist(snapshot_id)); + + user_drop_tenant_snapshot(default_tenant_name, default_snapshot_name); + ASSERT_FALSE(HasFatalFailure()); + obrpc::ObInnerDropTenantSnapshotArg drop_arg; + drop_arg.set_tenant_id(tenant_id); + drop_arg.set_tenant_snapshot_id(snapshot_id); + ASSERT_EQ(true, drop_arg.is_valid()); + tenant_snapshot_service->running_mode_ = ObTenantSnapshotService::NORMAL; + tenant_snapshot_service->run_in_normal_mode_(); + ASSERT_EQ(ObTenantSnapshotService::NORMAL, tenant_snapshot_service->running_mode_); + ASSERT_EQ(true, tenant_snapshot_service->meta_loaded_); + ASSERT_EQ(OB_SUCCESS, tenant_snapshot_service->drop_tenant_snapshot(drop_arg)); + sleep(10); // wait for background gc complete + ASSERT_EQ(false, is_tenant_snapshot_meta_exist(snapshot_id)); + ASSERT_EQ(false, is_ls_snapshot_meta_exist(snapshot_id)); + } + ASSERT_EQ(OB_SUCCESS, ret); +} + +} // unittest +} // oceanbase + +int main(int argc, char **argv) +{ + oceanbase::unittest::init_log_and_gtest(argc, argv); + oceanbase::common::ObLogger::get_logger().set_log_level("INFO"); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file