[CP] [CP][Bugfix] fix memory leak when tenant has been destroyed
This commit is contained in:
		@ -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;
 | 
				
			||||||
 | 
				
			|||||||
@ -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_;
 | 
				
			||||||
 | 
				
			|||||||
@ -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));
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user