diff --git a/mittest/mtlenv/storage/test_tenant_meta_mem_mgr.cpp b/mittest/mtlenv/storage/test_tenant_meta_mem_mgr.cpp index b8ed9f74c..549e2cbe9 100644 --- a/mittest/mtlenv/storage/test_tenant_meta_mem_mgr.cpp +++ b/mittest/mtlenv/storage/test_tenant_meta_mem_mgr.cpp @@ -19,6 +19,7 @@ #include "storage/tablet/ob_tablet_persister.h" #include "storage/meta_mem/ob_tenant_meta_mem_mgr.h" +#include "storage/meta_mem/ob_tablet_leak_checker.h" #include "storage/ls/ob_ls.h" #include "storage/schema_utils.h" #include "storage/mock_ob_log_handler.h" @@ -97,6 +98,7 @@ public: static const int64_t TEST_ROWKEY_COLUMN_CNT = 3; static const int64_t TEST_COLUMN_CNT = 6; static const uint64_t TEST_TENANT_ID = 1; + static const uint64_t TEST_ANOTHER_TENANT_ID = 2; static const int64_t TEST_LS_ID = 101; public: @@ -142,6 +144,8 @@ void TestTenantMetaMemMgr::SetUp() ret = t3m_.init(); ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(ObTabletHandleIndexMap::get_instance()->init(), OB_SUCCESS); + ObTenantBase *tenant_base = MTL_CTX(); tenant_base->set(&t3m_); TestSchemaUtils::prepare_data_schema(table_schema_); @@ -163,6 +167,8 @@ void TestTenantMetaMemMgr::TearDown() t3m_.wait(); t3m_.destroy(); + ObTabletHandleIndexMap::get_instance()->reset(); + // return to the old t3m to make ls destroy success. ObTenantBase *tenant_base = MTL_CTX(); tenant_base->set(old_t3m); @@ -912,102 +918,6 @@ TEST_F(TestTenantMetaMemMgr, test_wash_no_sstable_tablet) ASSERT_EQ(0, t3m_.tablet_buffer_pool_.inner_used_num_); } -/*TEST_F(TestTenantMetaMemMgr, test_not_wash_in_tx_tablet) -{ - int ret = OB_SUCCESS; - const ObTabletID tablet_id(1234567890); - const ObTabletMapKey key(ls_id_, tablet_id); - ObTablet *tablet = nullptr; - ObLSHandle ls_handle; - ObTabletHandle handle; - - ObLSService *ls_svr = MTL(ObLSService*); - ret = ls_svr->get_ls(ls_id_, ls_handle, ObLSGetMod::STORAGE_MOD); - ASSERT_EQ(common::OB_SUCCESS, ret); - - ret = t3m_.create_msd_tablet(WashTabletPriority::WTP_HIGH, key, ls_handle, handle); - handle.t3m_ = &t3m_; // temporary code, use local t3m - ASSERT_EQ(common::OB_SUCCESS, ret); - ASSERT_EQ(0, t3m_.tablet_buffer_pool_.inner_used_num_); - ASSERT_EQ(1, t3m_.tablet_map_.map_.size()); - ASSERT_TRUE(handle.is_valid()); - - tablet = handle.get_obj(); - ASSERT_TRUE(nullptr != tablet); - ASSERT_TRUE(tablet->pointer_hdl_.is_valid()); - - common::ObSEArray tablet_meta_write_ctxs; - common::ObSEArray sstable_meta_write_ctxs; - checkpoint::ObCheckpointExecutor ckpt_executor; - checkpoint::ObDataCheckpoint data_checkpoint; - ObLS ls; - ObLSTxService ls_tx_service(&ls); - ObLSWRSHandler ls_loop_worker; - ObLSTabletService ls_tablet_svr; - MockObLogHandler log_handler; - ObFreezer freezer; - ObTableSchema table_schema; - prepare_data_schema(table_schema); - - ret = freezer.init(&ls); - ASSERT_EQ(common::OB_SUCCESS, ret); - - share::SCN create_scn; - create_scn.convert_from_ts(ObTimeUtility::fast_current_time()); - - ObTabletID empty_tablet_id; - ObTabletTableStoreFlag store_flag; - store_flag.set_with_major_sstable(); - bool make_empty_co_sstable = false; - ret = tablet->init(allocator_, ls_id_, tablet_id, tablet_id, - create_scn, create_scn.get_val_for_tx(), table_schema, lib::Worker::CompatMode::MYSQL, - store_flag, make_empty_co_sstable, &freezer); - ASSERT_EQ(common::OB_SUCCESS, ret); - ASSERT_EQ(1, tablet->get_ref()); - - ObTabletHandle new_handle; - ASSERT_EQ(common::OB_SUCCESS, t3m_.acquire_tablet_from_pool(ObTabletPoolType::TP_NORMAL, WashTabletPriority::WTP_HIGH, key, new_handle)); - ASSERT_EQ(common::OB_SUCCESS, ObTabletPersister::persist_and_fill_tablet( - *tablet, allocator_, tablet_meta_write_ctxs, sstable_meta_write_ctxs, new_handle)); - ASSERT_EQ(common::OB_SUCCESS, ObTabletPersister::persist_4k_tablet(allocator_, new_handle)); - - ret = t3m_.compare_and_swap_tablet(key, new_handle, new_handle); - tablet = new_handle.get_obj(); - ASSERT_EQ(common::OB_SUCCESS, ret); - ASSERT_EQ(1, t3m_.tablet_map_.map_.size()); - ASSERT_EQ(1, t3m_.tablet_map_.map_.size()); - new_handle.reset(); - - // get tablet pointer - ObTabletPointer *tablet_ptr = static_cast(handle.get_obj()->pointer_hdl_.get_resource_ptr()); - - // pin tabet - ASSERT_EQ(common::OB_SUCCESS, t3m_.insert_pinned_tablet(key)); - void *free_obj = nullptr; - ret = t3m_.try_wash_tablet(typeid(ObTenantMetaMemMgr::ObNormalTabletBuffer), free_obj); - ASSERT_EQ(common::OB_SUCCESS, ret); - ASSERT_EQ(nullptr, free_obj); // pinned tablet can't be washed. - ASSERT_EQ(1, t3m_.tablet_map_.map_.size()); - ASSERT_EQ(1, t3m_.tablet_buffer_pool_.inner_used_num_); - - // unpin tablet - ASSERT_EQ(common::OB_SUCCESS, t3m_.erase_pinned_tablet(key)); - ret = t3m_.try_wash_tablet(typeid(ObTenantMetaMemMgr::ObNormalTabletBuffer), free_obj); - ASSERT_EQ(common::OB_SUCCESS, ret); // wash succeeded - ASSERT_NE(nullptr, free_obj); - t3m_.tablet_buffer_pool_.free_obj(free_obj); - ASSERT_EQ(1, t3m_.tablet_map_.map_.size()); - ASSERT_EQ(0, t3m_.tablet_buffer_pool_.inner_used_num_); - - ObTabletHandle tmp_handle; - ret = t3m_.tablet_map_.erase(key, tmp_handle); - ASSERT_EQ(common::OB_SUCCESS, ret); - ASSERT_EQ(0, t3m_.tablet_map_.map_.size()); - tmp_handle.reset(); - gc_all_tablets(); - ASSERT_EQ(0, t3m_.tablet_buffer_pool_.inner_used_num_); -}*/ - TEST_F(TestTenantMetaMemMgr, test_get_tablet_with_allocator) { int ret = OB_SUCCESS; @@ -1521,6 +1431,176 @@ TEST_F(TestTenantMetaMemMgr, test_heap) ASSERT_EQ(0, heap.count()); } +TEST_F(TestTenantMetaMemMgr, test_leak_checker) +{ + auto t3m = MTL(ObTenantMetaMemMgr*); + auto before_enabled = t3m->is_tablet_leak_checker_enabled_; + t3m->last_access_tenant_config_ts_ = common::ObClockGenerator::getClock(); + t3m->is_tablet_leak_checker_enabled_ = true; + + struct GetRefMapSizeFunc + { + int operator()() + { + int res = 0; + for (int i = 0; i < ObTabletHandleIndexMap::REF_ARRAY_SIZE; ++i) { + int val = 0; + for (int j = 0; j < ObTabletHandleIndexMap::REF_BUCKET_SIZE; ++j) { + val += ATOMIC_LOAD(&( + MTL(ObTenantMetaMemMgr *)->leak_checker_ + .tb_ref_bucket_[i + j * ObTabletHandleIndexMap::REF_ARRAY_SIZE])); + } + if (val != 0) { + res++; + } + } + return res; + } + }; + GetRefMapSizeFunc functor; + int32_t initial_size = functor(); + + ObLSHandle ls_handle; + ASSERT_EQ(OB_SUCCESS, MTL(ObLSService *)->get_ls(ls_id_, ls_handle, ObLSGetMod::STORAGE_MOD)); + + // Construct tablet handle, did not increase ref cnt + ObTabletHandle tb_handle_1; + int32_t index_1 = tb_handle_1.index_; + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_1], 0); + ASSERT_EQ(functor(), initial_size); + // Set tablet object, increase ref cnt + const ObTabletID tablet_id_1(3000); + MTL(ObTenantMetaMemMgr *)->create_msd_tablet(WashTabletPriority::WTP_HIGH, + ObTabletMapKey(ls_id_, tablet_id_1), + ls_handle, + tb_handle_1); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_1], 1); + ASSERT_EQ(functor(), initial_size + 1); + LOG_INFO("test_leak_checker, should be log pinned tablet info here (maybe n lines)"); + MTL(ObTenantMetaMemMgr *)->leak_checker_.dump_pinned_tablet_info(); + // Reset tablet handle, decrease ref cnt + tb_handle_1.reset(); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_1], 0); + ASSERT_EQ(functor(), initial_size); + LOG_INFO("test_leak_checker, should be log pinned tablet info here (maybe n-1 lines)"); + MTL(ObTenantMetaMemMgr *)->leak_checker_.dump_pinned_tablet_info(); + + // Set tablet at one t3m, reset at another t3m + ObTabletHandle tb_handle_2; + int32_t index_2 = tb_handle_2.index_; + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_2], 0); + ASSERT_EQ(functor(), initial_size); + const ObTabletID tablet_id_2(3001); + MTL(ObTenantMetaMemMgr *)->create_msd_tablet(WashTabletPriority::WTP_HIGH, + ObTabletMapKey(ls_id_, tablet_id_2), + ls_handle, + tb_handle_2); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_2], 1); + ASSERT_EQ(functor(), initial_size + 1); + LOG_INFO("test_leak_checker, should be log pinned tablet info here (maybe n lines)"); + MTL(ObTenantMetaMemMgr *)->leak_checker_.dump_pinned_tablet_info(); + // Change default t3m + ObTenantMetaMemMgr *true_t3m = MTL(ObTenantMetaMemMgr*); + ObTenantMetaMemMgr another_t3m(TEST_ANOTHER_TENANT_ID); + ASSERT_EQ(OB_SUCCESS, another_t3m.init()); + share::ObTenantEnv::get_tenant_local()->set(&another_t3m); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*), &another_t3m); + ASSERT_EQ(functor(), 0); + tb_handle_2.reset(); + LOG_INFO("test_leak_checker, should be log pinned tablet info here (maybe n-1 lines)"); + MTL(ObTenantMetaMemMgr *)->leak_checker_.dump_pinned_tablet_info(); + + // Change default t3m back + share::ObTenantEnv::get_tenant_local()->set(true_t3m); + // Delete useless tablet + MTL(ObTenantMetaMemMgr *)->del_tablet(ObTabletMapKey(ls_id_, tablet_id_1)); + MTL(ObTenantMetaMemMgr *)->del_tablet(ObTabletMapKey(ls_id_, tablet_id_2)); + + t3m->is_tablet_leak_checker_enabled_ = before_enabled; +} + +TEST_F(TestTenantMetaMemMgr, test_leak_checker_copy) +{ + ObLSHandle ls_handle; + ASSERT_EQ(OB_SUCCESS, MTL(ObLSService *)->get_ls(ls_id_, ls_handle, ObLSGetMod::STORAGE_MOD)); + + auto t3m = MTL(ObTenantMetaMemMgr*); + auto before_enabled = t3m->is_tablet_leak_checker_enabled_; + t3m->last_access_tenant_config_ts_ = common::ObClockGenerator::getClock(); + t3m->is_tablet_leak_checker_enabled_ = true; + + { + ObTabletHandle tb_handle_1; + int32_t index_1 = tb_handle_1.index_; + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_1], 0); + const ObTabletID tablet_id_1(3000); + ASSERT_EQ(OB_SUCCESS, + MTL(ObTenantMetaMemMgr *)->create_msd_tablet(WashTabletPriority::WTP_HIGH, + ObTabletMapKey(ls_id_, tablet_id_1), + ls_handle, tb_handle_1)); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_1], 1); + ObTabletHandle tb_handle_2; + tb_handle_2 = tb_handle_1; + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[tb_handle_2.index_], 1); + MTL(ObTenantMetaMemMgr *)->del_tablet(ObTabletMapKey(ls_id_, tablet_id_1)); + } + + t3m->leak_checker_.dump_pinned_tablet_info(); + t3m->is_tablet_leak_checker_enabled_ = before_enabled; +} + +TEST_F(TestTenantMetaMemMgr, test_leak_checker_switch) +{ + ObLSHandle ls_handle; + ASSERT_EQ(OB_SUCCESS, MTL(ObLSService *)->get_ls(ls_id_, ls_handle, ObLSGetMod::STORAGE_MOD)); + + auto t3m = MTL(ObTenantMetaMemMgr*); + auto before_enabled = t3m->is_tablet_leak_checker_enabled_; + + { + // new handle_1 with leak_checker enabled + t3m->last_access_tenant_config_ts_ = common::ObClockGenerator::getClock(); + t3m->is_tablet_leak_checker_enabled_ = true; + ObTabletHandle tb_handle_1; + int32_t index_1 = tb_handle_1.index_; + const ObTabletID tablet_id_1(3000); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_1], 0); + ASSERT_EQ(OB_SUCCESS, + MTL(ObTenantMetaMemMgr *)->create_msd_tablet(WashTabletPriority::WTP_HIGH, + ObTabletMapKey(ls_id_, tablet_id_1), + ls_handle, tb_handle_1)); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_1], 1); + + // new handle_2 with leak_checker disabled + t3m->last_access_tenant_config_ts_ = common::ObClockGenerator::getClock(); + t3m->is_tablet_leak_checker_enabled_ = false; + ObTabletHandle tb_handle_2; + int32_t index_2 = tb_handle_2.index_; + const ObTabletID tablet_id_2(5000); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_2], 0); + ASSERT_EQ(OB_SUCCESS, + MTL(ObTenantMetaMemMgr *)->create_msd_tablet(WashTabletPriority::WTP_HIGH, + ObTabletMapKey(ls_id_, tablet_id_2), + ls_handle, tb_handle_2)); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_2], 0); + + // destroy handle_1 with leak_checker disabled, dec ref failed (switch-off) + tb_handle_1.reset(); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_1], 1); + + // destroy handle_2 with leak_checker enabled, dec ref failed (invalid index) + t3m->last_access_tenant_config_ts_ = common::ObClockGenerator::getClock(); + t3m->is_tablet_leak_checker_enabled_ = true; + tb_handle_2.reset(); + ASSERT_EQ(MTL(ObTenantMetaMemMgr*)->leak_checker_.tb_ref_bucket_[index_2], 0); + + MTL(ObTenantMetaMemMgr *)->del_tablet(ObTabletMapKey(ls_id_, tablet_id_1)); + MTL(ObTenantMetaMemMgr *)->del_tablet(ObTabletMapKey(ls_id_, tablet_id_2)); + } + + t3m->is_tablet_leak_checker_enabled_ = before_enabled; +} + } // end namespace storage } // end namespace oceanbase diff --git a/src/observer/ob_server.cpp b/src/observer/ob_server.cpp index cd85da7f2..f755088ca 100644 --- a/src/observer/ob_server.cpp +++ b/src/observer/ob_server.cpp @@ -93,6 +93,8 @@ #include "storage/blocksstable/ob_storage_cache_suite.h" #include "storage/tablelock/ob_table_lock_rpc_client.h" #include "storage/compaction/ob_compaction_diagnose.h" +#include "storage/meta_mem/ob_tenant_meta_mem_mgr.h" +#include "storage/meta_mem/ob_tablet_leak_checker.h" #include "share/ash/ob_active_sess_hist_task.h" #include "share/ash/ob_active_sess_hist_list.h" #include "share/ob_server_blacklist.h" @@ -293,6 +295,8 @@ int ObServer::init(const ObServerOptions &opts, const ObPLogWriterCfg &log_cfg) LOG_ERROR("init tz_info_mgr failed", KR(ret)); } else if (OB_FAIL(ObSqlTaskFactory::get_instance().init())) { LOG_ERROR("init sql task factory failed", KR(ret)); + } else if (OB_FAIL(ObTabletHandleIndexMap::get_instance()->init())) { + LOG_ERROR("init leak checker hash map and qsync lock failed", K(ret)); } if (OB_SUCC(ret)) { diff --git a/src/share/parameter/ob_parameter_seed.ipp b/src/share/parameter/ob_parameter_seed.ipp index 05a9188ec..5c04fbd34 100755 --- a/src/share/parameter/ob_parameter_seed.ipp +++ b/src/share/parameter/ob_parameter_seed.ipp @@ -1695,6 +1695,9 @@ DEF_INT(_ha_tablet_info_batch_count, OB_TENANT_PARAMETER, "0", "[0,]", DEF_TIME(_ha_rpc_timeout, OB_TENANT_PARAMETER, "0", "[0,120s]", "the rpc timeout for storage high availability. Range:[0, 120s]", ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_BOOL(_enable_trace_tablet_leak, OB_TENANT_PARAMETER, "False", + "enable t3m tablet leak checker. The default value is False", + ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); // for set errsim module types, format like transfer;migration ERRSIM_DEF_STR_LIST(errsim_module_types, OB_TENANT_PARAMETER, "", diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt index 31aff6aea..31f03c66c 100644 --- a/src/storage/CMakeLists.txt +++ b/src/storage/CMakeLists.txt @@ -553,6 +553,7 @@ ob_set_subtarget(ob_storage common_mixed checkpoint/ob_checkpoint_executor.cpp checkpoint/ob_data_checkpoint.cpp checkpoint/ob_freeze_checkpoint.cpp + meta_mem/ob_tablet_leak_checker.cpp meta_mem/ob_meta_obj_struct.cpp meta_mem/ob_tablet_handle.cpp meta_mem/ob_tablet_map_key.cpp diff --git a/src/storage/meta_mem/ob_tablet_handle.cpp b/src/storage/meta_mem/ob_tablet_handle.cpp index 879e9c1fb..b0248d709 100644 --- a/src/storage/meta_mem/ob_tablet_handle.cpp +++ b/src/storage/meta_mem/ob_tablet_handle.cpp @@ -13,31 +13,29 @@ #define USING_LOG_PREFIX STORAGE #include "storage/meta_mem/ob_tablet_handle.h" +#include "storage/meta_mem/ob_tablet_leak_checker.h" #include "storage/tablet/ob_tablet.h" #include "storage/meta_mem/ob_tenant_meta_mem_mgr.h" namespace oceanbase { namespace storage { -ObTabletHandle::ObTabletHandle() +ObTabletHandle::ObTabletHandle(const char *file /* __builtin_FILE() */, + const int line /* __builtin_LINE() */, + const char *func /* __builtin_FUNCTION() */) : Base(), + index_(ObTabletHandleIndexMap::LEAK_CHECKER_INITIAL_INDEX), wash_priority_(WashTabletPriority::WTP_MAX), allow_copy_and_assign_(true) { + // tablet leak checker related + register_into_leak_checker(file, line, func); INIT_OBJ_LEAK_DEBUG_NODE(node_, this, share::LEAK_CHECK_OBJ_TABLET_HANDLE, MTL_ID()); } -ObTabletHandle::ObTabletHandle( - const Base &other, - const WashTabletPriority priority) - : Base(other), - wash_priority_(priority), - allow_copy_and_assign_(true) -{ -} - ObTabletHandle::ObTabletHandle(const ObTabletHandle &other) : Base(), + index_(ObTabletHandleIndexMap::LEAK_CHECKER_INITIAL_INDEX), wash_priority_(WashTabletPriority::WTP_MAX), allow_copy_and_assign_(true) { @@ -52,16 +50,41 @@ ObTabletHandle::~ObTabletHandle() ObTabletHandle &ObTabletHandle::operator=(const ObTabletHandle &other) { + int ret = OB_SUCCESS; + if (this != &other) { abort_unless(other.allow_copy_and_assign_); reset(); Base::operator=(other); + if (OB_FAIL(inc_ref_in_leak_checker(this->t3m_))) { + LOG_WARN("failed to inc ref in leak checker", K(ret), K(index_), KP(this->t3m_)); + } wash_priority_ = other.wash_priority_; allow_copy_and_assign_ = other.allow_copy_and_assign_; } return *this; } +void ObTabletHandle::set_obj(ObMetaObj &obj) +{ + Base::set_obj(obj); + // tablet leak checker related + int ret = OB_SUCCESS; + if (OB_FAIL(inc_ref_in_leak_checker(obj.t3m_))) { + LOG_WARN("failed to inc ref in leak checker", K(ret), K(index_), KP(this->t3m_)); + } +} + +void ObTabletHandle::set_obj(ObTablet *obj, common::ObIAllocator *allocator, ObTenantMetaMemMgr *t3m) +{ + Base::set_obj(obj, allocator, t3m); + // tablet leak checker related + int ret = OB_SUCCESS; + if (OB_FAIL(inc_ref_in_leak_checker(t3m))) { + LOG_WARN("failed to inc ref in leak checker", K(ret), K(index_), KP(this->t3m_)); + } +} + void ObTabletHandle::reset() { if (nullptr != obj_) { @@ -95,6 +118,11 @@ void ObTabletHandle::reset() } } obj_ = nullptr; + // tablet leak checker related + int ret = OB_SUCCESS; + if (OB_FAIL(dec_ref_in_leak_checker(t3m_))) { + LOG_WARN("failed to dec ref in leak checker", K(ret), K(index_), KP(this->t3m_)); + } } } wash_priority_ = WashTabletPriority::WTP_MAX; @@ -104,6 +132,39 @@ void ObTabletHandle::reset() t3m_ = nullptr; } +int ObTabletHandle::register_into_leak_checker(const char *file, const int line, const char *func) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObTenantMetaMemMgr::register_into_tb_map(file, line, func, index_))) { + LOG_WARN("fail to ObTabletHandle register into tb map", K(ret), K(file), K(func), K(index_)); + } + return ret; +} + +int ObTabletHandle::inc_ref_in_leak_checker(ObTenantMetaMemMgr *t3m) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(t3m)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get t3m pointer", K(ret), KP(t3m)); + } else if (OB_FAIL(t3m->inc_ref_in_leak_checker(index_))) { + LOG_WARN("fail to inc ref in tb ref map", K(ret), K(index_), KP(t3m)); + } + return ret; +} + +int ObTabletHandle::dec_ref_in_leak_checker(ObTenantMetaMemMgr *t3m) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(t3m)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get t3m pointer", K(ret), KP(t3m)); + } else if (OB_FAIL(t3m->dec_ref_in_leak_checker(index_))) { + LOG_WARN("fail to dec ref in tb ref map", K(ret), K(index_), KP(t3m)); + } + return ret; +} + int64_t ObTabletHandle::calc_wash_score(const WashTabletPriority priority) const { int ret = OB_SUCCESS; diff --git a/src/storage/meta_mem/ob_tablet_handle.h b/src/storage/meta_mem/ob_tablet_handle.h index 74db482a0..8f198c92b 100644 --- a/src/storage/meta_mem/ob_tablet_handle.h +++ b/src/storage/meta_mem/ob_tablet_handle.h @@ -35,13 +35,14 @@ class ObTabletHandle : public ObMetaObjGuard private: typedef ObMetaObjGuard Base; public: - ObTabletHandle(); - ObTabletHandle( - const Base &other, - const WashTabletPriority priority); + ObTabletHandle(const char *file = __builtin_FILE(), + const int line = __builtin_LINE(), + const char *func = __builtin_FUNCTION()); ObTabletHandle(const ObTabletHandle &other); virtual ~ObTabletHandle(); ObTabletHandle &operator = (const ObTabletHandle &other); + virtual void set_obj(ObMetaObj &obj) override; + virtual void set_obj(ObTablet *obj, common::ObIAllocator *allocator, ObTenantMetaMemMgr *t3m) override; virtual void reset() override; virtual bool need_hold_time_check() const override { return true; } void set_wash_priority(const WashTabletPriority priority) { wash_priority_ = priority; } @@ -52,12 +53,16 @@ public: int64_t get_buf_len() const { return get_buf_header().buf_len_; } DECLARE_VIRTUAL_TO_STRING; private: + int register_into_leak_checker(const char *file, const int line, const char *func); + int inc_ref_in_leak_checker(ObTenantMetaMemMgr *t3m); + int dec_ref_in_leak_checker(ObTenantMetaMemMgr *t3m); int64_t calc_wash_score(const WashTabletPriority priority) const; ObMetaObjBufferHeader &get_buf_header() const { return ObMetaObjBufferHelper::get_buffer_header(reinterpret_cast(obj_)); } private: + int32_t index_; // initialize as -1 WashTabletPriority wash_priority_; bool allow_copy_and_assign_; DEFINE_OBJ_LEAK_DEBUG_NODE(node_); diff --git a/src/storage/meta_mem/ob_tablet_leak_checker.cpp b/src/storage/meta_mem/ob_tablet_leak_checker.cpp new file mode 100644 index 000000000..279a0d82d --- /dev/null +++ b/src/storage/meta_mem/ob_tablet_leak_checker.cpp @@ -0,0 +1,244 @@ +/** + * 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 "lib/ob_errno.h" +#include "lib/oblog/ob_log_module.h" +#include "storage/meta_mem/ob_tablet_leak_checker.h" + +namespace oceanbase +{ +namespace storage +{ + +ObTabletHandleIndexMap::TabletHandleFootprint::TabletHandleFootprint() +{ + MEMSET(footprint_, 0, FOOTPRINT_LEN); +} + +ObTabletHandleIndexMap::TabletHandleFootprint::TabletHandleFootprint( + const char *file, const int line, const char *func) +{ + int ret = OB_SUCCESS; + MEMSET(footprint_, 0, FOOTPRINT_LEN); + const int nwrite = snprintf(footprint_, FOOTPRINT_LEN, "%d, %s, %s", line, func, file); + if (OB_UNLIKELY(nwrite < 0 || nwrite > FOOTPRINT_LEN)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to write footprint info of TabletHandleFootprint", K(nwrite), + KCSTRING(file), K(line), KCSTRING(func)); + } +} + +int ObTabletHandleIndexMap::TabletHandleFootprint::assign(const TabletHandleFootprint &other) +{ + int ret = OB_SUCCESS; + if (this != &other) { + const char * dest = STRNCPY(footprint_, other.footprint_, FOOTPRINT_LEN); + if (OB_UNLIKELY(dest != footprint_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to assign footprint", K(ret), KP(dest), KP(footprint_)); + } + } + return ret; +} + +ObTabletHandleIndexMap::ObTabletHandleIndexMap() : max_index_(0), is_inited_(false) +{ +} + +int ObTabletHandleIndexMap::reset() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(tb_map_.destroy())) { + LOG_WARN("failed to destroy tb map", K(ret)); + } + rw_lock_.destroy(); + is_inited_ = false; + return ret; +} + +int ObTabletHandleIndexMap::init() +{ + int ret = OB_SUCCESS; + + if (OB_UNLIKELY(is_inited_)) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTabletHandleIndexMap init twice", K(ret), K(is_inited_)); + } else if (OB_FAIL(tb_map_.create(REF_ARRAY_SIZE, "T3MTBMap"))) { + LOG_WARN("failed to init tb map", K(ret)); + } else if (OB_FAIL(rw_lock_.init(lib::ObMemAttr(OB_SERVER_TENANT_ID, "T3MQSyncLock")))) { + LOG_WARN("failed to init rw lock", K(ret)); + } else { + is_inited_ = true; + } + + if (OB_FAIL(ret) || OB_UNLIKELY(!is_inited_)) { + // init failed, reset + reset(); + } + + return ret; +} + +int ObTabletHandleIndexMap::register_handle(const char *file, const int line, + const char *func, int32_t &index) +{ + int ret = OB_SUCCESS; + index = ObTabletHandleIndexMap::LEAK_CHECKER_INITIAL_INDEX; + const int64_t cpu_id = icpu_id(); + TabletHandleFootprint thf(file, line, func); + + // Try to read existed index + int32_t val = -1; + ret = tb_map_.get_refactored(thf, val); + if (ret != OB_SUCCESS && ret != OB_HASH_NOT_EXIST) { + LOG_WARN("fail to get from tb_map_", K(ret), K(thf.footprint_), K(val)); + } + + // No existed index, fetch write lock and set index + if (ret == OB_HASH_NOT_EXIST) { + ObQSyncLockWriteGuard guard(rw_lock_); + val = ATOMIC_LOAD(&max_index_); + if (OB_FAIL(tb_map_.set_refactored(thf, val, 0 /* is_overwrite */))) { + if (ret == OB_HASH_EXIST) { // try again + if (OB_UNLIKELY(OB_FAIL(tb_map_.get_refactored(thf, val)))) { + LOG_WARN("fail to re-get from tb_map_", K(ret), K(thf.footprint_), K(val)); + } else { + // Other thread has registered TabletHandle, no need to set, do nothing + } + } else { + LOG_WARN("fail to set refactored", K(ret), K(thf.footprint_), K(val)); + } + } else { + ATOMIC_INC(&max_index_); + } + } + + // Return index value with reference + if (OB_SUCC(ret)) { + // `tb_ref_bucket_` is divided into REF_BUCKET_SIZE buckets. + // `cpu_id` determine the bucket, `val_ptr` determine the slot. + index = val + (REF_ARRAY_SIZE * (murmurhash(&cpu_id, sizeof(cpu_id), 0) % REF_BUCKET_SIZE)); + } else { + LOG_WARN("fail to assign to index", K(ret), K(val)); + } + + return ret; +} + +int ObTabletHandleIndexMap::foreach(PrintToLogTraversal &op) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(tb_map_.foreach_refactored(op))) { + LOG_WARN("failed to foreach in tb map", K(ret)); + } + return ret; +} + +int ObTabletHandleIndexMap::PrintToLogTraversal::operator() ( + common::hash::HashMapTypes::pair_type &pair) +{ + if (temporal_ref_map_[pair.second] != 0) { + int index = pair.second; + int ref_cnt = temporal_ref_map_[pair.second]; + char code_pos[512]; + MEMSET(code_pos, 0, sizeof(code_pos)); + int begin_at = 0; + int len = STRLEN(pair.first.footprint_); + for (begin_at = len - 1; + begin_at >= 0 && pair.first.footprint_[begin_at] != '/'; --begin_at) { + } + int cur = 0; + for (int i = begin_at + 1; i >= 0 && i < len; ++i) { + code_pos[cur++] = pair.first.footprint_[i]; + } + code_pos[cur++] = ':'; + for (int i = 0; i < len && pair.first.footprint_[i] != ','; ++i) { + code_pos[cur++] = pair.first.footprint_[i]; + } + LOG_INFO("There is a un-released ObTabletHandle", K(code_pos), K(ref_cnt), + K(index), K(pair.first.footprint_)); + } + return OB_SUCCESS; +} + +ObTabletLeakChecker::ObTabletLeakChecker() +{ + MEMSET(tb_ref_bucket_, 0, sizeof(tb_ref_bucket_)); +} + +int ObTabletLeakChecker::inc_ref(const int32_t index) +{ + int ret = OB_SUCCESS; + + if (index == ObTabletHandleIndexMap::LEAK_CHECKER_INITIAL_INDEX) { + // do nothing + } else if (OB_LIKELY(index < ObTabletHandleIndexMap::REF_ARRAY_SIZE * ObTabletHandleIndexMap::REF_BUCKET_SIZE && + index >= 0)) { + if (ATOMIC_LOAD(&(tb_ref_bucket_[index])) < 0) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("error ref when inc", K(ret), K(ATOMIC_LOAD(&(tb_ref_bucket_[index]))), K(index)); + } else { + ATOMIC_INC(&(tb_ref_bucket_[index])); + } + } else { + ret = OB_INVALID_ARGUMENT; + LOG_ERROR("unexpected index value", K(ret), K(index)); + } + + return ret; +} + +int ObTabletLeakChecker::dec_ref(const int32_t index) +{ + int ret = OB_SUCCESS; + + if (index == ObTabletHandleIndexMap::LEAK_CHECKER_INITIAL_INDEX) { + // do nothing + } else if (OB_LIKELY(index < ObTabletHandleIndexMap::REF_ARRAY_SIZE * ObTabletHandleIndexMap::REF_BUCKET_SIZE && + index >= 0)) { + const int new_ref_cnt = ATOMIC_SAF(&(tb_ref_bucket_[index]), 1); + if (new_ref_cnt < 0) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("unexpected ref count", K(ret), K(new_ref_cnt), K(index)); + } + } else { + ret = OB_INVALID_ARGUMENT; + LOG_ERROR("unexpected index value", K(ret), K(index)); + } + + return ret; +} + +void ObTabletLeakChecker::dump_pinned_tablet_info() +{ + int ret = OB_SUCCESS; + ObTabletHandleIndexMap::PrintToLogTraversal callback; + // Print tb ref map to log + for (int i = 0; i < ObTabletHandleIndexMap::REF_ARRAY_SIZE; ++i) { + int ref_cnt = 0; + for (int j = 0; j < ObTabletHandleIndexMap::REF_BUCKET_SIZE; ++j) { + ref_cnt += ATOMIC_LOAD(&tb_ref_bucket_[i + j * ObTabletHandleIndexMap::REF_ARRAY_SIZE]); + } + callback.set_data(i, ref_cnt); + } + if (OB_FAIL(ObTabletHandleIndexMap::get_instance()->foreach(callback))) { + LOG_WARN("fail to foreach on tb_map_", K(ret)); + } else { + LOG_INFO("dump pinned tablet info finished"); + } +} + +} // namespace storage +} // namespace oceanbase \ No newline at end of file diff --git a/src/storage/meta_mem/ob_tablet_leak_checker.h b/src/storage/meta_mem/ob_tablet_leak_checker.h new file mode 100644 index 000000000..62cf3e245 --- /dev/null +++ b/src/storage/meta_mem/ob_tablet_leak_checker.h @@ -0,0 +1,113 @@ +/** + * 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. + */ + +#ifndef OCEANBASE_STORAGE_OB_TABLET_LEAK_CHECKER +#define OCEANBASE_STORAGE_OB_TABLET_LEAK_CHECKER + +#include "lib/hash/ob_hashmap.h" +#include "lib/lock/ob_qsync_lock.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObTenantMetaMemMgr; +class ObTabletLeakChecker; + +class ObTabletHandleIndexMap final +{ +public: + static const int32_t LEAK_CHECKER_INITIAL_INDEX = -1; + static const int64_t REF_ARRAY_SIZE = 1024; + static const int64_t REF_BUCKET_SIZE = 32; +public: + struct TabletHandleFootprint final + { + public: + TabletHandleFootprint(); + TabletHandleFootprint(const char *file, const int line, const char *func); + int assign(const TabletHandleFootprint &other); + static const int32_t FOOTPRINT_LEN = 512; + char footprint_[FOOTPRINT_LEN]; + }; + struct TabletHandleFootprintHashFunc final + { + public: + int operator()(const TabletHandleFootprint &key, uint64_t &res) const + { + res = murmurhash(key.footprint_, static_cast(strlen(key.footprint_)), 0); + return OB_SUCCESS; + } + }; + struct TabletHandleFootprintEqual final + { + public: + bool operator()(const TabletHandleFootprint &lhs, const TabletHandleFootprint &rhs) const + { + return STRCMP(lhs.footprint_, rhs.footprint_) == 0; + } + }; + struct PrintToLogTraversal { + public: + PrintToLogTraversal() { MEMSET(temporal_ref_map_, 0, sizeof(temporal_ref_map_)); } + int operator()(common::hash::HashMapTypes< + ObTabletHandleIndexMap::TabletHandleFootprint, + int32_t>::pair_type &pair); + void set_data(int32_t index, int32_t ref_cnt) { + temporal_ref_map_[index] = ref_cnt; + } + private: + int32_t temporal_ref_map_[ObTabletHandleIndexMap::REF_ARRAY_SIZE]; + }; +public: + ObTabletHandleIndexMap(); + int reset(); + int init(); + int register_handle(const char *file, const int line, + const char *func, int32_t &index); + int foreach(PrintToLogTraversal &op); + static ObTabletHandleIndexMap* get_instance() { + static ObTabletHandleIndexMap tb_handle_index_map; + return &tb_handle_index_map; + } + +private: + common::hash::ObHashMap< + TabletHandleFootprint, int32_t, common::hash::SpinReadWriteDefendMode, + TabletHandleFootprintHashFunc, TabletHandleFootprintEqual> + tb_map_; + common::ObQSyncLock rw_lock_; + volatile int32_t max_index_; + bool is_inited_; +private: + DISALLOW_COPY_AND_ASSIGN(ObTabletHandleIndexMap); +}; + +class ObTabletLeakChecker final +{ +public: + ObTabletLeakChecker(); + int inc_ref(const int32_t index); + int dec_ref(const int32_t index); + void dump_pinned_tablet_info(); +private: + int32_t tb_ref_bucket_[ObTabletHandleIndexMap::REF_BUCKET_SIZE * + ObTabletHandleIndexMap::REF_ARRAY_SIZE]; +private: + DISALLOW_COPY_AND_ASSIGN(ObTabletLeakChecker); +}; + +} // namespace storage +} // namespace oceanbase + +#endif // OCEANBASE_STORAGE_OB_TABLET_LEAK_CHECKER \ No newline at end of file diff --git a/src/storage/meta_mem/ob_tenant_meta_mem_mgr.cpp b/src/storage/meta_mem/ob_tenant_meta_mem_mgr.cpp index 7b3e134aa..a5843d890 100644 --- a/src/storage/meta_mem/ob_tenant_meta_mem_mgr.cpp +++ b/src/storage/meta_mem/ob_tenant_meta_mem_mgr.cpp @@ -141,6 +141,8 @@ ObTenantMetaMemMgr::ObTenantMetaMemMgr(const uint64_t tenant_id) tx_ctx_memtable_pool_(tenant_id, MAX_TX_CTX_MEMTABLE_CNT_IN_OBJ_POOL, "TxCtxMemObj", ObCtxIds::DEFAULT_CTX_ID), lock_memtable_pool_(tenant_id, MAX_LOCK_MEMTABLE_CNT_IN_OBJ_POOL, "LockMemObj", ObCtxIds::DEFAULT_CTX_ID), meta_cache_io_allocator_(), + last_access_tenant_config_ts_(-1), + is_tablet_leak_checker_enabled_(false), is_inited_(false) { for (int64_t i = 0; i < ObITable::TableType::MAX_TABLE_TYPE; i++) { @@ -192,6 +194,8 @@ int ObTenantMetaMemMgr::init() LOG_WARN("fail to create thread for t3m", K(ret)); } else if (OB_FAIL(meta_cache_io_allocator_.init(OB_MALLOC_MIDDLE_BLOCK_SIZE, "StorMetaCacheIO", tenant_id_, mem_limit))) { LOG_WARN("fail to init storage meta cache io allocator", K(ret), K_(tenant_id), K(mem_limit)); + } else if (OB_FAIL(fetch_tenant_config())) { + LOG_WARN("fail to fetch tenant config", K(ret)); } else { init_pool_arr(); is_inited_ = true; @@ -203,6 +207,20 @@ int ObTenantMetaMemMgr::init() return ret; } +int ObTenantMetaMemMgr::fetch_tenant_config() +{ + int ret = OB_SUCCESS; + omt::ObTenantConfigGuard tenant_config(TENANT_CONF(tenant_id_)); + if (!tenant_config.is_valid()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid tenant config", K(ret), K(tenant_id_)); + } else { + is_tablet_leak_checker_enabled_ = tenant_config->_enable_trace_tablet_leak; + LOG_INFO("fetch tenant config", K(tenant_id_), K(is_tablet_leak_checker_enabled_)); + } + return ret; +} + void ObTenantMetaMemMgr::init_pool_arr() { pool_arr_[static_cast(ObITable::TableType::DATA_MEMTABLE)] = &memtable_pool_; @@ -1791,6 +1809,51 @@ int ObTenantMetaMemMgr::get_meta_mem_status(common::ObIArrayis_tablet_handle_leak_checker_enabled()) { + // do nothing + } else if (OB_FAIL(ObTabletHandleIndexMap::get_instance()->register_handle(file, line, func, index))) { + LOG_WARN("failed to register handle", KP(t3m), K(file), K(line), K(func), K(index)); + } + + return ret; +} + +int ObTenantMetaMemMgr::inc_ref_in_leak_checker(const int32_t index) +{ + int ret = OB_SUCCESS; + + if (!is_tablet_handle_leak_checker_enabled()) { + // do nothing + } else if (OB_FAIL(leak_checker_.inc_ref(index))) { + LOG_WARN("failed to inc ref in leak checker", K(index)); + } + + return ret; +} + +int ObTenantMetaMemMgr::dec_ref_in_leak_checker(const int32_t index) +{ + int ret = OB_SUCCESS; + + if (!is_tablet_handle_leak_checker_enabled()) { + // do nothing + } else if (OB_FAIL(leak_checker_.dec_ref(index))) { + LOG_WARN("failed to dec ref in leak checker", K(ret), K(index)); + } + + return ret; +} + +bool ObTenantMetaMemMgr::is_tablet_handle_leak_checker_enabled() +{ + return is_tablet_leak_checker_enabled_; +} + int ObTenantMetaMemMgr::del_tablet(const ObTabletMapKey &key) { int ret = OB_SUCCESS; @@ -2028,6 +2091,11 @@ int ObTenantMetaMemMgr::dump_tablet_info() FLOG_INFO("dump large tablet buffer", "buffer", static_cast(ObMetaObjBufferHelper::get_obj_buffer(node)), KP(node)); } } + + if (is_tablet_handle_leak_checker_enabled()) { + leak_checker_.dump_pinned_tablet_info(); + } + return ret; } diff --git a/src/storage/meta_mem/ob_tenant_meta_mem_mgr.h b/src/storage/meta_mem/ob_tenant_meta_mem_mgr.h index 1f97683a7..b87ef064e 100644 --- a/src/storage/meta_mem/ob_tenant_meta_mem_mgr.h +++ b/src/storage/meta_mem/ob_tenant_meta_mem_mgr.h @@ -35,6 +35,7 @@ #include "storage/meta_mem/ob_tablet_map_key.h" #include "storage/meta_mem/ob_tablet_pointer.h" #include "storage/meta_mem/ob_tenant_meta_obj_pool.h" +#include "storage/meta_mem/ob_tablet_leak_checker.h" #include "storage/tablet/ob_tablet_memtable_mgr.h" #include "storage/tablet/ob_tablet.h" #include "storage/tablet/ob_full_tablet_creator.h" @@ -152,6 +153,8 @@ public: return lib::is_mini_mode() ? MIN_MODE_MAX_MEMTABLE_CNT_IN_OBJ_POOL : MAX_MEMTABLE_CNT_IN_OBJ_POOL; } + static int register_into_tb_map(const char *file, const int line, const char *func, int32_t &index); + static int get_tablet_pool_type(const int64_t tablet_size, ObTabletPoolType &type) { int ret = OB_SUCCESS; @@ -278,6 +281,9 @@ public: int release_memtable_and_mds_table_for_ls_offline(const ObTabletMapKey &key); TO_STRING_KV(K_(tenant_id), K_(is_inited), "tablet count", tablet_map_.count()); + + int inc_ref_in_leak_checker(const int32_t index); + int dec_ref_in_leak_checker(const int32_t index); private: int fill_buffer_infos( const ObTabletPoolType pool_type, @@ -290,6 +296,7 @@ private: const bool is_old, const share::SCN &ls_checkpoint, share::SCN &min_end_scn); + int fetch_tenant_config(); private: typedef ObResourceValueStore TabletValueStore; @@ -415,24 +422,12 @@ private: static const int64_t DEFAULT_TABLET_WASH_HEAP_COUNT = 16; static const int64_t DEFAULT_MINOR_SSTABLE_SET_COUNT = 49999; static const int64_t SSTABLE_GC_MAX_TIME = 500; // 500us + static const int64_t LEAK_CHECKER_CONFIG_REFRESH_TIMEOUT = 10000000 * 10; // 10s typedef common::ObBinaryHeap Heap; typedef common::ObDList TabletBufferList; typedef common::hash::ObHashSet SSTableSet; typedef common::hash::ObHashSet PinnedTabletSet; - class TenantMetaAllocator : public common::ObFIFOAllocator - { - public: - TenantMetaAllocator(const uint64_t tenant_id, TryWashTabletFunc &wash_func) - : common::ObFIFOAllocator(tenant_id), wash_func_(wash_func) {}; - virtual ~TenantMetaAllocator() = default; - TO_STRING_KV("used", used(), "total", total()); - protected: - virtual void *alloc_align(const int64_t size, const int64_t align) override; - private: - TryWashTabletFunc &wash_func_; - }; - private: int acquire_tablet(const ObTabletPoolType type, ObTabletHandle &tablet_handle); int acquire_tablet(ObITenantMetaObjPool *pool, ObTablet *&tablet); @@ -473,6 +468,7 @@ private: int push_memtable_into_gc_map_(memtable::ObMemtable *memtable); void batch_gc_memtable_(); void batch_destroy_memtable_(memtable::ObMemtableSet *memtable_set); + bool is_tablet_handle_leak_checker_enabled(); private: common::SpinRWLock wash_lock_; @@ -491,6 +487,7 @@ private: common::ObLinkQueue free_tables_queue_; common::ObSpinLock gc_queue_lock_; common::hash::ObHashMap gc_memtable_map_; + ObTabletLeakChecker leak_checker_; ObTenantMetaObjPool memtable_pool_; ObTenantMetaObjPool tablet_buffer_pool_; @@ -508,7 +505,9 @@ private: TabletBufferList large_tablet_header_; common::ObConcurrentFIFOAllocator meta_cache_io_allocator_; + int64_t last_access_tenant_config_ts_; + bool is_tablet_leak_checker_enabled_; bool is_inited_; }; diff --git a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result index 54b999b05..f86940971 100644 --- a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result +++ b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result @@ -301,6 +301,7 @@ _enable_skip_index _enable_system_tenant_memory_limit _enable_tenant_sql_net_thread _enable_trace_session_leak +_enable_trace_tablet_leak _enable_transaction_internal_routing _enable_values_table_folding _enable_var_assign_use_das diff --git a/unittest/share/scheduler/test_dag_net_in_dag_scheduler.cpp b/unittest/share/scheduler/test_dag_net_in_dag_scheduler.cpp index 2fef835a4..95bc0a3e5 100644 --- a/unittest/share/scheduler/test_dag_net_in_dag_scheduler.cpp +++ b/unittest/share/scheduler/test_dag_net_in_dag_scheduler.cpp @@ -55,10 +55,17 @@ using namespace lib; namespace storage { + int64_t ObTenantMetaMemMgr::cal_adaptive_bucket_num() { return 1000; } + +int ObTenantMetaMemMgr::fetch_tenant_config() +{ + return OB_SUCCESS; +} + } namespace unittest diff --git a/unittest/storage/test_partition_incremental_range_spliter.cpp b/unittest/storage/test_partition_incremental_range_spliter.cpp index 5fba6ef4a..9169fe3ab 100644 --- a/unittest/storage/test_partition_incremental_range_spliter.cpp +++ b/unittest/storage/test_partition_incremental_range_spliter.cpp @@ -29,10 +29,17 @@ namespace storage using namespace blocksstable; using namespace common; +class ObTenantMetaMemMgr; + void ObCompactionBufferWriter::reset() { } +int ObTenantMetaMemMgr::fetch_tenant_config() +{ + return OB_SUCCESS; +} + static int get_number(const char *str, const char *&endpos, int64_t &num) { int ret = OB_SUCCESS; diff --git a/unittest/storage/test_tablet_pointer_map.cpp b/unittest/storage/test_tablet_pointer_map.cpp index b507c87e1..f0b92cd4e 100644 --- a/unittest/storage/test_tablet_pointer_map.cpp +++ b/unittest/storage/test_tablet_pointer_map.cpp @@ -35,6 +35,11 @@ int64_t ObTenantMetaMemMgr::cal_adaptive_bucket_num() return 1000; } +int ObTenantMetaMemMgr::fetch_tenant_config() +{ + return OB_SUCCESS; +} + int ObTabletPointerMap::load_meta_obj( const ObTabletMapKey &key, ObTabletPointer *meta_pointer, diff --git a/unittest/storage/tx_table/test_tx_ctx_table.cpp b/unittest/storage/tx_table/test_tx_ctx_table.cpp index 57430f776..637d5440e 100644 --- a/unittest/storage/tx_table/test_tx_ctx_table.cpp +++ b/unittest/storage/tx_table/test_tx_ctx_table.cpp @@ -36,6 +36,10 @@ using namespace storage; using namespace blocksstable; using namespace share; +int storage::ObTenantMetaMemMgr::fetch_tenant_config() +{ + return OB_SUCCESS; +} namespace unittest {