[CP] [CP][Bugfix] fix memory leak when tenant has been destroyed

This commit is contained in:
WeiXinChan
2024-05-23 05:53:14 +00:00
committed by ob-robot
parent 80741a994a
commit a222a2b040
3 changed files with 119 additions and 54 deletions

View File

@ -16,6 +16,7 @@
using namespace oceanbase::share; using namespace oceanbase::share;
using namespace oceanbase::common; using namespace oceanbase::common;
using namespace oceanbase::lib;
namespace oceanbase namespace oceanbase
{ {
@ -512,8 +513,11 @@ int ObTableApiSessPool::create_node_safe(ObTableApiCredential &credential, ObTab
LOG_WARN("fail to alloc mem for ObTableApiSessNode", K(ret), K(sizeof(ObTableApiSessNode))); LOG_WARN("fail to alloc mem for ObTableApiSessNode", K(ret), K(sizeof(ObTableApiSessNode)));
} else { } else {
tmp_node = new (buf) ObTableApiSessNode(credential); tmp_node = new (buf) ObTableApiSessNode(credential);
tmp_node->last_active_ts_ = ObTimeUtility::current_time(); if (OB_FAIL(tmp_node->init())) {
node = tmp_node; LOG_WARN("fail to init session node", K(ret));
} else {
node = tmp_node;
}
} }
return ret; return ret;
@ -643,6 +647,30 @@ void ObTableApiSessNodeVal::give_back_to_free_list()
} }
} }
int ObTableApiSessNode::init()
{
int ret = OB_SUCCESS;
if (!is_inited_) {
MemoryContext tmp_mem_ctx = nullptr;
ContextParam param;
param.set_mem_attr(MTL_ID(), "TbSessNod", ObCtxIds::DEFAULT_CTX_ID)
.set_properties(lib::ALLOC_THREAD_SAFE);
if (OB_FAIL(ROOT_CONTEXT->CREATE_CONTEXT(tmp_mem_ctx, param))) {
LOG_WARN("fail to create mem context", K(ret));
} else if (OB_ISNULL(tmp_mem_ctx)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null mem context ", K(ret));
} else {
mem_ctx_ = tmp_mem_ctx;
last_active_ts_ = ObTimeUtility::fast_current_time();
is_inited_ = true;
}
}
return ret;
}
void ObTableApiSessNode::destroy() void ObTableApiSessNode::destroy()
{ {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
@ -653,34 +681,45 @@ void ObTableApiSessNode::destroy()
ObTableApiSessNodeVal *rm_sess = free_list.remove(sess); ObTableApiSessNodeVal *rm_sess = free_list.remove(sess);
if (OB_NOT_NULL(rm_sess)) { if (OB_NOT_NULL(rm_sess)) {
rm_sess->destroy(); rm_sess->destroy();
if (OB_NOT_NULL(mem_ctx_)) {
mem_ctx_->free(rm_sess);
}
} }
} }
DLIST_FOREACH_REMOVESAFE(sess, used_list) { DLIST_FOREACH_REMOVESAFE(sess, used_list) {
ObTableApiSessNodeVal *rm_sess = used_list.remove(sess); ObTableApiSessNodeVal *rm_sess = used_list.remove(sess);
if (OB_NOT_NULL(rm_sess)) { if (OB_NOT_NULL(rm_sess)) {
rm_sess->destroy(); rm_sess->destroy();
if (OB_NOT_NULL(mem_ctx_)) {
mem_ctx_->free(rm_sess);
}
} }
} }
ObLockGuard<ObSpinLock> alloc_guard(allocator_lock_); // lock allocator_ if (OB_NOT_NULL(mem_ctx_)) {
allocator_.reset(); DESTROY_CONTEXT(mem_ctx_);
}
} }
int ObTableApiSessNode::remove_unused_sess() int ObTableApiSessNode::remove_unused_sess()
{ {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
ObDList<ObTableApiSessNodeVal> &free_list = sess_lists_.free_list_; if (IS_NOT_INIT) {
if (free_list.is_empty()) { ret = OB_NOT_INIT;
// do nothing LOG_WARN("session node is not inited", K(ret));
} else { } else {
ObLockGuard<ObSpinLock> guard(sess_lists_.lock_); ObDList<ObTableApiSessNodeVal> &free_list = sess_lists_.free_list_;
DLIST_FOREACH_REMOVESAFE(sess, free_list) { if (free_list.is_empty()) {
ObTableApiSessNodeVal *rm_sess = free_list.remove(sess); // do nothing
if (OB_NOT_NULL(rm_sess)) { } else {
rm_sess->~ObTableApiSessNodeVal(); ObLockGuard<ObSpinLock> guard(sess_lists_.lock_);
ObLockGuard<ObSpinLock> alloc_guard(allocator_lock_); // lock allocator_ DLIST_FOREACH_REMOVESAFE(sess, free_list) {
allocator_.free(rm_sess); ObTableApiSessNodeVal *rm_sess = free_list.remove(sess);
rm_sess = nullptr; if (OB_NOT_NULL(rm_sess) && OB_NOT_NULL(mem_ctx_)) {
rm_sess->~ObTableApiSessNodeVal();
mem_ctx_->free(rm_sess);
rm_sess = nullptr;
}
} }
} }
} }
@ -696,19 +735,25 @@ int ObTableApiSessNode::remove_unused_sess()
int ObTableApiSessNode::get_sess_node_val(ObTableApiSessNodeVal *&val) int ObTableApiSessNode::get_sess_node_val(ObTableApiSessNodeVal *&val)
{ {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
ObTableApiSessNodeVal *tmp_val = nullptr;
ObDList<ObTableApiSessNodeVal> &free_list = sess_lists_.free_list_;
ObDList<ObTableApiSessNodeVal> &used_list = sess_lists_.used_list_;
ObLockGuard<ObSpinLock> guard(sess_lists_.lock_); if (IS_NOT_INIT) {
if (!free_list.is_empty()) { ret = OB_NOT_INIT;
tmp_val = free_list.remove_first(); LOG_WARN("session node is not inited", K(ret));
// move to used list } else {
if (false == (used_list.add_last(tmp_val))) { ObTableApiSessNodeVal *tmp_val = nullptr;
ret = OB_ERR_UNEXPECTED; ObDList<ObTableApiSessNodeVal> &free_list = sess_lists_.free_list_;
LOG_WARN("fail to add sess val to used list", K(ret), K(*tmp_val)); ObDList<ObTableApiSessNodeVal> &used_list = sess_lists_.used_list_;
} else {
val = tmp_val; ObLockGuard<ObSpinLock> guard(sess_lists_.lock_);
if (!free_list.is_empty()) {
tmp_val = free_list.remove_first();
// move to used list
if (false == (used_list.add_last(tmp_val))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to add sess val to used list", K(ret), K(*tmp_val));
} else {
val = tmp_val;
}
} }
} }
@ -724,30 +769,41 @@ int ObTableApiSessNode::get_sess_node_val(ObTableApiSessNodeVal *&val)
int ObTableApiSessNode::extend_and_get_sess_val(ObTableApiSessGuard &guard) int ObTableApiSessNode::extend_and_get_sess_val(ObTableApiSessGuard &guard)
{ {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
ObLockGuard<ObSpinLock> alloc_guard(allocator_lock_); // lock allocator_
void *buf = nullptr;
if (OB_ISNULL(buf = allocator_.alloc(sizeof(ObTableApiSessNodeVal)))) { if (IS_NOT_INIT) {
ret = OB_ALLOCATE_MEMORY_FAILED; ret = OB_NOT_INIT;
LOG_WARN("fail to alloc mem for ObTableApiSessNodeVal", K(ret), K(sizeof(ObTableApiSessNodeVal))); LOG_WARN("session node is not inited", K(ret));
} else if (OB_ISNULL(mem_ctx_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("memory context is null", K(ret));
} else { } else {
ObTableApiSessNodeVal *val = new (buf) ObTableApiSessNodeVal(this, credential_.tenant_id_); ObTableApiSessNodeVal *val = nullptr;
if (OB_FAIL(val->init_sess_info())) { void *buf = nullptr;
LOG_WARN("fail to init sess info", K(ret), K(*val)); ObMemAttr attr(MTL_ID(), "TbSessNodVal", ObCtxIds::DEFAULT_CTX_ID);
if (OB_ISNULL(buf = mem_ctx_->allocf(sizeof(ObTableApiSessNodeVal), attr))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to alloc mem for ObTableApiSessNodeVal", K(ret), K(sizeof(ObTableApiSessNodeVal)));
} else { } else {
ObLockGuard<ObSpinLock> lock_guard(sess_lists_.lock_); val = new (buf) ObTableApiSessNodeVal(this, credential_.tenant_id_);
if (false == (sess_lists_.used_list_.add_last(val))) { if (OB_FAIL(val->init_sess_info())) {
ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to init sess info", K(ret), K(*val));
LOG_WARN("fail to add sess val to list", K(ret), K(*val));
} else { } else {
guard.sess_node_val_ = val; ObLockGuard<ObSpinLock> lock_guard(sess_lists_.lock_);
if (false == (sess_lists_.used_list_.add_last(val))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to add sess val to list", K(ret), K(*val));
} else {
guard.sess_node_val_ = val;
}
} }
} }
}
if (OB_FAIL(ret) && OB_NOT_NULL(buf)) { if (OB_FAIL(ret) && OB_NOT_NULL(val)) {
allocator_.free(buf); val->~ObTableApiSessNodeVal();
buf = nullptr; mem_ctx_->free(val);
val = nullptr;
buf = nullptr;
}
} }
return ret; return ret;

View File

@ -164,14 +164,16 @@ friend class ObTableApiSessPool;
friend class ObTableApiSessNodeVal; friend class ObTableApiSessNodeVal;
public: public:
explicit ObTableApiSessNode(ObTableApiCredential &credential) explicit ObTableApiSessNode(ObTableApiCredential &credential)
: allocator_("TbSessNode", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()), : is_inited_(false),
mem_ctx_(nullptr),
sess_lists_(), sess_lists_(),
last_active_ts_(0), last_active_ts_(0),
credential_(credential) credential_(credential)
{ {
} }
~ObTableApiSessNode() { destroy(); } ~ObTableApiSessNode() { destroy(); }
TO_STRING_KV(K_(sess_lists), TO_STRING_KV(K_(is_inited),
K_(sess_lists),
K_(last_active_ts), K_(last_active_ts),
K_(credential)); K_(credential));
class SessList class SessList
@ -189,6 +191,7 @@ public:
DISALLOW_COPY_AND_ASSIGN(SessList); DISALLOW_COPY_AND_ASSIGN(SessList);
}; };
public: public:
int init();
void destroy(); void destroy();
bool is_empty() const { return sess_lists_.is_empty(); } bool is_empty() const { return sess_lists_.is_empty(); }
int get_sess_node_val(ObTableApiSessNodeVal *&val); int get_sess_node_val(ObTableApiSessNodeVal *&val);
@ -198,8 +201,8 @@ public:
private: private:
int extend_and_get_sess_val(ObTableApiSessGuard &guard); int extend_and_get_sess_val(ObTableApiSessGuard &guard);
private: private:
common::ObArenaAllocator allocator_; bool is_inited_;
ObSpinLock allocator_lock_; // for lock allocator_ lib::MemoryContext mem_ctx_;
SessList sess_lists_; SessList sess_lists_;
int64_t last_active_ts_; int64_t last_active_ts_;
ObTableApiCredential credential_; ObTableApiCredential credential_;

View File

@ -132,9 +132,12 @@ TEST_F(TestTableSessPool, mgr_get_session)
ASSERT_NE(0, node->last_active_ts_); ASSERT_NE(0, node->last_active_ts_);
// add mock val to node // add mock val to node
ObTableApiSessNodeVal val(node, MTL_ID()); void *buf = nullptr;
val.is_inited_ = true; ObMemAttr attr(MTL_ID(), "TbSessNodVal", ObCtxIds::DEFAULT_CTX_ID);
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(&val)); ASSERT_NE(nullptr, buf = node->mem_ctx_->allocf(sizeof(ObTableApiSessNodeVal), attr));
ObTableApiSessNodeVal *val = new (buf) ObTableApiSessNodeVal(node, MTL_ID());
val->is_inited_ = true;
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(val));
ObTableApiSessGuard guard; ObTableApiSessGuard guard;
ASSERT_EQ(OB_SUCCESS, mgr->get_sess_info(*mock_cred_, guard)); ASSERT_EQ(OB_SUCCESS, mgr->get_sess_info(*mock_cred_, guard));
@ -216,9 +219,12 @@ TEST_F(TestTableSessPool, mgr_sess_recycle)
// add mock val to node // add mock val to node
ObTableApiSessNode *node; ObTableApiSessNode *node;
ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(mock_cred_->hash_val_, node)); ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(mock_cred_->hash_val_, node));
ObTableApiSessNodeVal val(node, MTL_ID()); void *buf = nullptr;
val.is_inited_ = true; ObMemAttr attr(MTL_ID(), "TbSessNodVal", ObCtxIds::DEFAULT_CTX_ID);
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(&val)); ASSERT_NE(nullptr, buf = node->mem_ctx_->allocf(sizeof(ObTableApiSessNodeVal), attr));
ObTableApiSessNodeVal *val = new (buf) ObTableApiSessNodeVal(node, MTL_ID());
val->is_inited_ = true;
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(val));
ObTableApiSessGuard guard; ObTableApiSessGuard guard;
ASSERT_EQ(OB_SUCCESS, mgr->get_sess_info(*mock_cred_, guard)); ASSERT_EQ(OB_SUCCESS, mgr->get_sess_info(*mock_cred_, guard));