From 9002e5b34dd7728f103a886d19073aa95da971ad Mon Sep 17 00:00:00 2001 From: WeiXinChan Date: Wed, 17 Jan 2024 08:43:54 +0000 Subject: [PATCH] [CP][Bugfix][OBKV]fix session pool hold too much memory when login frequently --- src/observer/table/ob_table_session_pool.cpp | 18 +++++++++++++----- src/observer/table/ob_table_session_pool.h | 13 ++++++++----- .../observer/table/test_table_sess_pool.cpp | 5 ++--- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/observer/table/ob_table_session_pool.cpp b/src/observer/table/ob_table_session_pool.cpp index d24493e9d..c446cc517 100644 --- a/src/observer/table/ob_table_session_pool.cpp +++ b/src/observer/table/ob_table_session_pool.cpp @@ -33,7 +33,7 @@ int ObTableApiSessPoolMgr::mtl_init(ObTableApiSessPoolMgr *&mgr) /* start tableapi retired session task - - 60 second interval + - 5 second interval - repeated */ int ObTableApiSessPoolMgr::start() @@ -45,7 +45,7 @@ int ObTableApiSessPoolMgr::start() LOG_WARN("table api session pool mgr isn't inited", K(ret)); } else if (OB_FAIL(TG_SCHEDULE(MTL(omt::ObSharedTimer*)->get_tg_id(), elimination_task_, - ELIMINATE_SESSION_DELAY/* 60s */, + ELIMINATE_SESSION_DELAY/* 5s */, true/* repeat */))) { LOG_WARN("failed to schedule tableapi retired session task", K(ret)); } else { @@ -377,7 +377,7 @@ int ObTableApiSessPool::move_node_to_retired_list(ObTableApiSessNode *node) 1. remove session val in free_list. 2. remove session node from retired_nodes_ when node is empty. 3. free node memory. - 4. delete 1000 session nodes per times + 4. delete 2000 session nodes per times */ int ObTableApiSessPool::evict_retired_sess() { @@ -387,7 +387,7 @@ int ObTableApiSessPool::evict_retired_sess() ObLockGuard guard(retired_nodes_lock_); // lock retired_nodes_ DLIST_FOREACH_REMOVESAFE_X(node, retired_nodes_, delete_count < BACKCROUND_TASK_DELETE_SESS_NUM) { - if (cur_time - node->get_last_active_ts() < SESS_RETIRE_TIME) { + if (cur_time - node->get_last_active_ts() < SESS_UPDATE_TIME_INTERVAL) { // do nothing, this node maybe is from ObTableApiSessNodeReplaceOp, some threads maybe is using it. // we remove it next retire task. } else if (OB_FAIL(node->remove_unused_sess())) { @@ -545,23 +545,31 @@ int ObTableApiSessPool::create_and_add_node_safe(ObTableApiCredential &credentia /* 1. only call in login 2. move old to retired list when node exist, create new node otherwise. + 3. if the update interval is less than 5 seconds, ignore this update. */ int ObTableApiSessPool::update_sess(ObTableApiCredential &credential) { int ret = OB_SUCCESS; - ObTableApiSessNode *node = nullptr; const uint64_t key = credential.hash_val_; + int64_t cur_time = ObTimeUtility::current_time(); + if (OB_FAIL(get_sess_node(key, node))) { if (OB_HASH_NOT_EXIST == ret) { // not exist, create if (OB_FAIL(create_and_add_node_safe(credential))) { LOG_WARN("fail to create and add node", K(ret), K(credential)); + } else { + ATOMIC_STORE(&last_update_ts_, cur_time); } } else { LOG_WARN("fail to get session node", K(ret), K(key)); } + } else if (cur_time - last_update_ts_ < SESS_UPDATE_TIME_INTERVAL) { + // if the update interval is less than 5 seconds, ignore this update. } else if (OB_FAIL(replace_sess_node_safe(credential))) { // exist, create and replace old node LOG_WARN("fail to replace session node", K(ret), K(credential)); + } else { + ATOMIC_STORE(&last_update_ts_, cur_time); } return ret; diff --git a/src/observer/table/ob_table_session_pool.h b/src/observer/table/ob_table_session_pool.h index 4aaf32d37..e619617cc 100644 --- a/src/observer/table/ob_table_session_pool.h +++ b/src/observer/table/ob_table_session_pool.h @@ -70,7 +70,7 @@ private: int create_session_pool_safe(); int create_session_pool_unsafe(); private: - static const int64_t ELIMINATE_SESSION_DELAY = 60 * 1000 * 1000; // 60s + static const int64_t ELIMINATE_SESSION_DELAY = 5 * 1000 * 1000; // 5s bool is_inited_; common::ObArenaAllocator allocator_; ObTableApiSessPool *pool_; @@ -87,13 +87,15 @@ class ObTableApiSessPool final public: // key is ObTableApiCredential.hash_val_ typedef common::hash::ObHashMap CacheKeyNodeMap; - static const int64_t SESS_POOL_DEFAULT_BUCKET_NUM = 10; // 取决于客户端登录的用户数量 - static const int64_t SESS_RETIRE_TIME = 300 * 1000000; // 超过300s未被访问的session会被标记淘汰 - static const int64_t BACKCROUND_TASK_DELETE_SESS_NUM = 1000; // 后台任务每次删除淘汰的session node数量 + static const int64_t SESS_POOL_DEFAULT_BUCKET_NUM = 10; // default user number + static const int64_t SESS_RETIRE_TIME = 300 * 1000 * 1000; // marked as retired more than 300 seconds are not accessed + static const int64_t BACKCROUND_TASK_DELETE_SESS_NUM = 2000; // number of eliminated session nodes in background task per time + static const int64_t SESS_UPDATE_TIME_INTERVAL = 5 * 1000 * 1000; // the update interval cannot exceed 5 seconds public: explicit ObTableApiSessPool() : allocator_("TbSessPool", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()), - is_inited_(false) + is_inited_(false), + last_update_ts_(0) {} ~ObTableApiSessPool() { destroy(); }; TO_STRING_KV(K_(is_inited), @@ -120,6 +122,7 @@ private: // 前台login时、后台淘汰时都会操作retired_nodes_,因此需要加锁 common::ObDList retired_nodes_; ObSpinLock retired_nodes_lock_; // for lock retired_nodes_ + int64_t last_update_ts_; private: DISALLOW_COPY_AND_ASSIGN(ObTableApiSessPool); }; diff --git a/unittest/observer/table/test_table_sess_pool.cpp b/unittest/observer/table/test_table_sess_pool.cpp index 1f4190ecd..44c44178e 100644 --- a/unittest/observer/table/test_table_sess_pool.cpp +++ b/unittest/observer/table/test_table_sess_pool.cpp @@ -170,8 +170,7 @@ TEST_F(TestTableSessPool, mgr_update_session) ASSERT_NE(nullptr, mgr->pool_); ASSERT_TRUE(mgr->pool_->is_inited_); ASSERT_EQ(1, mgr->pool_->key_node_map_.size()); - ASSERT_EQ(1, mgr->pool_->retired_nodes_.size_); - ASSERT_EQ(node, mgr->pool_->retired_nodes_.get_last()); + ASSERT_EQ(0, mgr->pool_->retired_nodes_.size_); ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(new_cred->hash_val_, node)); ASSERT_NE(nullptr, node); ASSERT_TRUE(node->sess_lists_.free_list_.is_empty()); @@ -184,7 +183,7 @@ TEST_F(TestTableSessPool, mgr_update_session) ASSERT_NE(nullptr, mgr->pool_); ASSERT_TRUE(mgr->pool_->is_inited_); ASSERT_EQ(2, mgr->pool_->key_node_map_.size()); - ASSERT_EQ(1, mgr->pool_->retired_nodes_.size_); + ASSERT_EQ(0, mgr->pool_->retired_nodes_.size_); ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(new_cred->hash_val_, node)); ASSERT_NE(nullptr, node); ASSERT_TRUE(node->sess_lists_.free_list_.is_empty());