Tablet normalized leak diagnosis
This commit is contained in:
parent
5346749b1e
commit
452b98a7c1
@ -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<ObSharedBlocksWriteCtx, 16> tablet_meta_write_ctxs;
|
||||
common::ObSEArray<ObSharedBlocksWriteCtx, 16> 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<ObTabletPointer*>(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
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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, "",
|
||||
|
@ -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
|
||||
|
@ -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<ObTablet> &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;
|
||||
|
@ -35,13 +35,14 @@ class ObTabletHandle : public ObMetaObjGuard<ObTablet>
|
||||
private:
|
||||
typedef ObMetaObjGuard<ObTablet> 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<ObTablet> &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<char *>(obj_));
|
||||
}
|
||||
private:
|
||||
int32_t index_; // initialize as -1
|
||||
WashTabletPriority wash_priority_;
|
||||
bool allow_copy_and_assign_;
|
||||
DEFINE_OBJ_LEAK_DEBUG_NODE(node_);
|
||||
|
244
src/storage/meta_mem/ob_tablet_leak_checker.cpp
Normal file
244
src/storage/meta_mem/ob_tablet_leak_checker.cpp
Normal file
@ -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<ObTabletHandleIndexMap::TabletHandleFootprint,
|
||||
int32_t>::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
|
113
src/storage/meta_mem/ob_tablet_leak_checker.h
Normal file
113
src/storage/meta_mem/ob_tablet_leak_checker.h
Normal file
@ -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<int32_t>(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
|
@ -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<int>(ObITable::TableType::DATA_MEMTABLE)] = &memtable_pool_;
|
||||
@ -1791,6 +1809,51 @@ int ObTenantMetaMemMgr::get_meta_mem_status(common::ObIArray<ObTenantMetaMemStat
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTenantMetaMemMgr::register_into_tb_map(const char *file, const int line,
|
||||
const char *func, int32_t &index) {
|
||||
int ret = OB_SUCCESS;
|
||||
ObTenantMetaMemMgr *t3m = MTL(ObTenantMetaMemMgr*);
|
||||
|
||||
if (OB_NOT_NULL(t3m) && !t3m->is_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<const void*>(ObMetaObjBufferHelper::get_obj_buffer(node)), KP(node));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_tablet_handle_leak_checker_enabled()) {
|
||||
leak_checker_.dump_pinned_tablet_info();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -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<ObTabletPointer> 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<CandidateTabletInfo, HeapCompare, DEFAULT_TABLET_WASH_HEAP_COUNT> Heap;
|
||||
typedef common::ObDList<ObMetaObjBufferNode> TabletBufferList;
|
||||
typedef common::hash::ObHashSet<MinMinorSSTableInfo, common::hash::NoPthreadDefendMode> SSTableSet;
|
||||
typedef common::hash::ObHashSet<ObTabletMapKey, hash::NoPthreadDefendMode> 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<share::ObLSID, memtable::ObMemtableSet*> gc_memtable_map_;
|
||||
ObTabletLeakChecker leak_checker_;
|
||||
|
||||
ObTenantMetaObjPool<memtable::ObMemtable> memtable_pool_;
|
||||
ObTenantMetaObjPool<ObNormalTabletBuffer> 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_;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -36,6 +36,10 @@ using namespace storage;
|
||||
using namespace blocksstable;
|
||||
using namespace share;
|
||||
|
||||
int storage::ObTenantMetaMemMgr::fetch_tenant_config()
|
||||
{
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
|
||||
namespace unittest
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user