Tablet normalized leak diagnosis

This commit is contained in:
ND501 2024-02-06 15:26:28 +00:00 committed by ob-robot
parent 5346749b1e
commit 452b98a7c1
15 changed files with 725 additions and 123 deletions

View File

@ -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

View File

@ -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)) {

View File

@ -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, "",

View File

@ -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

View File

@ -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;

View File

@ -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_);

View 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

View 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

View File

@ -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;
}

View File

@ -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_;
};

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -36,6 +36,10 @@ using namespace storage;
using namespace blocksstable;
using namespace share;
int storage::ObTenantMetaMemMgr::fetch_tenant_config()
{
return OB_SUCCESS;
}
namespace unittest
{