[Bugfix]tableapi session pool split to tenant

This commit is contained in:
WeiXinChan
2023-09-13 06:19:37 +00:00
committed by ob-robot
parent 1238115c82
commit 68c5f0ce3e
13 changed files with 555 additions and 713 deletions

View File

@ -1,256 +1,229 @@
#include <gtest/gtest.h>
#define private public // 获取私有成员
#include "observer/table/ob_table_session_pool.h"
#include "lib/utility/ob_test_util.h"
#include "share/ob_thread_pool.h"
#include "mtlenv/mock_tenant_module_env.h"
#include "share/rc/ob_tenant_base.h"
using namespace oceanbase;
using namespace oceanbase::common;
using namespace oceanbase::table;
using namespace oceanbase::sql;
using namespace oceanbase::share;
using namespace oceanbase::storage;
class TestTableSessPool: public ::testing::Test
{
public:
const int64_t TENANT_CNT = 10;
const int64_t USER_CNT = 100;
const int64_t NODE_CNT = 100;
const int64_t SESS_CNT = 10;
public:
TestTableSessPool() {}
virtual ~TestTableSessPool() {}
void prepare_sess_pool(ObTableApiSessPoolMgr &mgr);
static void SetUpTestCase()
{
EXPECT_EQ(OB_SUCCESS, MockTenantModuleEnv::get_instance().init());
}
static void TearDownTestCase()
{
MockTenantModuleEnv::get_instance().destroy();
}
void SetUp()
{
ASSERT_TRUE(MockTenantModuleEnv::get_instance().is_inited());
TABLEAPI_SESS_POOL_MGR->init();
create_credential(1, mock_cred_);
}
void TearDown()
{
TABLEAPI_SESS_POOL_MGR->destroy();
}
private:
void create_credential(uint64_t user_id, ObTableApiCredential *&cred);
private:
ObArenaAllocator allocator_;
ObTableApiCredential *mock_cred_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(TestTableSessPool);
};
// 10租户,100用户,每个用户下面挂10个session
void TestTableSessPool::prepare_sess_pool(ObTableApiSessPoolMgr &mgr)
void TestTableSessPool::create_credential(uint64_t user_id, ObTableApiCredential *&cred)
{
ASSERT_EQ(OB_SUCCESS, mgr.init());
uint64_t tenant_ids[TENANT_CNT];
uint64_t user_ids[USER_CNT];
ObTableApiSessPoolGuard pool_guards[TENANT_CNT];
for (uint64_t i = 0; i < TENANT_CNT; i++) {
tenant_ids[i] = i + 1;
ASSERT_EQ(OB_SUCCESS, mgr.extend_sess_pool(tenant_ids[i], pool_guards[i]));
ObTableApiSessPool *tmp_pool = pool_guards[i].get_sess_pool();
ASSERT_NE(nullptr, tmp_pool);
for (uint64_t j = 0; j < USER_CNT; j++) {
user_ids[j] = j;
ASSERT_EQ(OB_SUCCESS, mgr.get_session_pool(tenant_ids[i], pool_guards[i]));
ObTableApiSessPool *pool = pool_guards[i].get_sess_pool();
ASSERT_NE(nullptr, pool);
ObTableApiCredential credential;
credential.tenant_id_ = tenant_ids[i];
credential.user_id_ = user_ids[j];
ASSERT_EQ(OB_SUCCESS, pool->update_sess(credential));
ObTableApiSessNode *node = nullptr;
ASSERT_EQ(OB_SUCCESS, tmp_pool->get_sess_node(user_ids[j], node));
ASSERT_NE(nullptr, node);
for (int64_t k = 0; k < SESS_CNT; k++) {
void *buf = node->allocator_.alloc(sizeof(ObTableApiSessNodeVal));
ASSERT_NE(nullptr, buf);
ObTableApiSessNodeVal *val = new (buf) ObTableApiSessNodeVal(tenant_ids[i], node);
val->is_inited_ = true;
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(val));
}
}
}
void *buf = nullptr;
buf = allocator_.alloc(sizeof(ObTableApiCredential));
cred = new (buf) ObTableApiCredential();
cred->cluster_id_ = 0;
cred->tenant_id_ = 1;
cred->user_id_ = user_id;
cred->database_id_ = 1;
cred->expire_ts_ = 0;
cred->hash(cred->hash_val_);
}
TEST_F(TestTableSessPool, get_session)
TEST_F(TestTableSessPool, test_mgr_init)
{
uint64_t tenant_id = 1;
uint64_t user_id = 0;
uint64_t key = user_id;
ObTableApiSessPoolMgr mgr;
ASSERT_EQ(OB_SUCCESS, mgr.init());
ObTableApiSessPoolGuard pool_guard;
ASSERT_EQ(OB_HASH_NOT_EXIST, mgr.get_session_pool(tenant_id, pool_guard));
ASSERT_EQ(nullptr, pool_guard.get_sess_pool());
ASSERT_EQ(OB_SUCCESS, mgr.extend_sess_pool(tenant_id, pool_guard));
ObTableApiSessPool *pool = pool_guard.get_sess_pool();
ASSERT_TRUE(nullptr != pool);
ASSERT_TRUE(pool->is_inited_);
ASSERT_EQ(1, pool->ref_count_);
ASSERT_EQ(false, pool->is_deleted_);
ASSERT_EQ(tenant_id, pool->tenant_id_);
ObTableApiSessGuard sess_guard;
ObTableApiCredential credential;
credential.tenant_id_ = tenant_id;
credential.user_id_ = user_id;
ASSERT_EQ(OB_SUCCESS, pool->update_sess(credential));
ObTableApiSessNode *node = nullptr;
ASSERT_EQ(OB_SUCCESS, pool->get_sess_node(key, node));
ASSERT_TRUE(nullptr != node);
ASSERT_TRUE(node->is_empty());
void *buf = node->allocator_.alloc(sizeof(ObTableApiSessNodeVal));
ASSERT_NE(nullptr, buf);
ObTableApiSessNodeVal *new_val = new (buf) ObTableApiSessNodeVal(tenant_id, node);
new_val->is_inited_ = true;
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(new_val));
ASSERT_FALSE(mgr.is_inited_);
ASSERT_EQ(nullptr, mgr.pool_);
ASSERT_EQ(nullptr, mgr.elimination_task_.sess_pool_mgr_);
ASSERT_EQ(OB_SYS_TENANT_ID, MTL_ID());
ASSERT_TRUE(TABLEAPI_SESS_POOL_MGR->is_inited_);
ASSERT_EQ(nullptr, TABLEAPI_SESS_POOL_MGR->pool_);
ASSERT_EQ(TABLEAPI_SESS_POOL_MGR, TABLEAPI_SESS_POOL_MGR->elimination_task_.sess_pool_mgr_);
}
TEST_F(TestTableSessPool, remove_session)
TEST_F(TestTableSessPool, test_pool_init)
{
int64_t tenant_id = 1;
uint64_t user_id = 0;
ObTableApiCredential credential;
credential.tenant_id_ = tenant_id;
credential.user_id_ = user_id;
ObTableApiSessNode node(credential);
for (int64_t i = 0; i < SESS_CNT; i++) {
void *buf = node.allocator_.alloc(sizeof(ObTableApiSessNodeVal));
ASSERT_NE(nullptr, buf);
ObTableApiSessNodeVal *val = new (buf) ObTableApiSessNodeVal(tenant_id, &node);
val->is_inited_ = true;
ASSERT_EQ(true, node.sess_lists_.free_list_.add_last(val));
}
ASSERT_EQ(false, node.is_empty());
ASSERT_EQ(SESS_CNT, node.sess_lists_.free_list_.get_size());
node.remove_unused_sess();
ASSERT_EQ(0, node.sess_lists_.free_list_.get_size());
ObTableApiSessPool pool;
ASSERT_FALSE(pool.is_inited_);
ASSERT_TRUE(pool.key_node_map_.empty());
ASSERT_TRUE(pool.retired_nodes_.is_empty());
}
TEST_F(TestTableSessPool, retire_session)
TEST_F(TestTableSessPool, test_node_init)
{
int ret = 0;
ObTableApiSessPoolMgr mgr;
prepare_sess_pool(mgr);
ObTableApiSessPoolForeachOp op;
ASSERT_EQ(OB_SUCCESS, mgr.sess_pool_map_.foreach_refactored(op));
const ObTableApiSessPoolForeachOp::TelantIdArray &tenant_ids = op.get_telant_id_array();
ASSERT_EQ(TENANT_CNT, tenant_ids.count());
const int64_t N = tenant_ids.count();
// 1. 标记淘汰
for (int64_t i = 0; i < N; i++) {
uint64_t tenant_id = tenant_ids.at(i);
ObTableApiSessPoolGuard pool_guard;
ASSERT_EQ(OB_SUCCESS, mgr.get_session_pool(tenant_id, pool_guard));
ObTableApiSessPool *pool = pool_guard.get_sess_pool();
ASSERT_NE(nullptr, pool);
ObTableApiSessForeachOp op;
ASSERT_EQ(OB_SUCCESS, pool->key_node_map_.foreach_refactored(op));
const ObTableApiSessForeachOp::SessKvArray &kvs = op.get_key_value_array();
ASSERT_EQ(NODE_CNT, kvs.count());
for (int64_t j = 0; j < kvs.count(); j++) {
if (j % 2 == 0) {
const ObTableApiSessForeachOp::ObTableApiSessKV &kv = kvs.at(j);
ASSERT_EQ(OB_SUCCESS, pool->move_sess_to_retired_list(kv.key_));
}
}
}
// 2. 触发淘汰
ASSERT_EQ(OB_SUCCESS, mgr.elimination_task_.run_recycle_retired_sess_task());
// 3. 检查
for (int64_t i = 0; i < N; i++) {
uint64_t tenant_id = tenant_ids.at(i);
ObTableApiSessPoolGuard pool_guard;
ASSERT_EQ(OB_SUCCESS, mgr.get_session_pool(tenant_id, pool_guard));
ObTableApiSessPool *pool = pool_guard.get_sess_pool();
ASSERT_NE(nullptr, pool);
ObTableApiSessForeachOp op;
ASSERT_EQ(OB_SUCCESS, pool->key_node_map_.foreach_refactored(op));
const ObTableApiSessForeachOp::SessKvArray &kvs = op.get_key_value_array();
ASSERT_EQ(NODE_CNT/2, kvs.count());
for (int64_t j = 0; j < kvs.count(); j++) {
const ObTableApiSessForeachOp::ObTableApiSessKV &kv = kvs.at(j);
ASSERT_EQ(SESS_CNT, kv.node_->sess_lists_.free_list_.get_size());
}
}
ObTableApiSessNode node(*mock_cred_);
ASSERT_TRUE(node.sess_lists_.free_list_.is_empty());
ASSERT_TRUE(node.sess_lists_.used_list_.is_empty());
ASSERT_EQ(0, node.last_active_ts_);
}
TEST_F(TestTableSessPool, reference_session)
TEST_F(TestTableSessPool, test_node_val_init)
{
// prepare
ObTableApiSessPoolMgr mgr;
ASSERT_EQ(OB_SUCCESS, mgr.init());
uint64_t tenant_id = 1;
uint64_t user_id = 0;
ObTableApiSessPoolGuard pool_guard;
ASSERT_EQ(OB_SUCCESS, mgr.extend_sess_pool(tenant_id, pool_guard));
ObTableApiSessPool *pool = pool_guard.get_sess_pool();
ASSERT_NE(nullptr, pool);
ObTableApiCredential credential;
credential.tenant_id_ = tenant_id;
credential.user_id_ = user_id;
ASSERT_EQ(OB_SUCCESS, pool->update_sess(credential));
ObTableApiSessNode *node = nullptr;
ASSERT_EQ(OB_SUCCESS, pool->get_sess_node(user_id, node));
ObTableApiSessNode node(*mock_cred_);
ObTableApiSessNodeVal val(&node);
ASSERT_FALSE(val.is_inited_);
ASSERT_EQ(&node, val.owner_node_);
}
TEST_F(TestTableSessPool, test_sess_guard_init)
{
ObTableApiSessGuard guard;
ASSERT_EQ(nullptr, guard.sess_node_val_);
}
TEST_F(TestTableSessPool, mgr_get_session)
{
ASSERT_EQ(OB_SYS_TENANT_ID, MTL_ID());
ObTableApiSessPoolMgr *mgr = TABLEAPI_SESS_POOL_MGR;
// first time will create a new node
ASSERT_EQ(OB_SUCCESS, mgr->update_sess(*mock_cred_));
ASSERT_NE(nullptr, mgr->pool_);
ASSERT_TRUE(mgr->pool_->is_inited_);
ASSERT_EQ(1, mgr->pool_->key_node_map_.size());
ASSERT_EQ(0, mgr->pool_->retired_nodes_.size_);
ObTableApiSessNode *node;
ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(mock_cred_->user_id_, node));
ASSERT_NE(nullptr, node);
void *buf = node->allocator_.alloc(sizeof(ObTableApiSessNodeVal));
ASSERT_NE(nullptr, buf);
ObTableApiSessNodeVal *val = new (buf) ObTableApiSessNodeVal(tenant_id, node);
val->is_inited_ = true;
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(val));
// get and retire
{
// get
ObTableApiSessGuard guard;
ASSERT_EQ(OB_SUCCESS, pool->get_sess_info(credential, guard));
ASSERT_NE(nullptr, guard.get_sess_node_val());
// mark retire
ObTableApiSessForeachOp op;
ASSERT_EQ(OB_SUCCESS, pool->key_node_map_.foreach_refactored(op));
const ObTableApiSessForeachOp::SessKvArray &kvs = op.get_key_value_array();
ASSERT_EQ(1, kvs.count());
const ObTableApiSessForeachOp::ObTableApiSessKV &kv = kvs.at(0);
// run retire task
ASSERT_EQ(OB_SUCCESS, mgr.elimination_task_.run_recycle_retired_sess_task());
// check
op.reset();
ASSERT_EQ(OB_SUCCESS, pool->key_node_map_.foreach_refactored(op));
const ObTableApiSessForeachOp::SessKvArray &new_kvs = op.get_key_value_array();
ASSERT_EQ(1, new_kvs.count());
}
// retire after def ref
ASSERT_EQ(OB_SUCCESS, mgr.elimination_task_.run_recycle_retired_sess_task());
// check
ObTableApiSessPoolForeachOp op;
ASSERT_EQ(OB_SUCCESS, mgr.sess_pool_map_.foreach_refactored(op));
const ObTableApiSessPoolForeachOp::TelantIdArray &arr = op.get_telant_id_array();
ASSERT_EQ(1, arr.count());
ASSERT_TRUE(node->sess_lists_.free_list_.is_empty());
ASSERT_TRUE(node->sess_lists_.used_list_.is_empty());
ASSERT_NE(0, node->last_active_ts_);
// add mock val to node
ObTableApiSessNodeVal val(node);
val.is_inited_ = true;
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(&val));
ObTableApiSessGuard guard;
ASSERT_EQ(OB_SUCCESS, mgr->get_sess_info(*mock_cred_, guard));
ASSERT_NE(nullptr, guard.sess_node_val_);
ASSERT_NE(nullptr, guard.get_sess_node_val());
const ObTableApiCredential *cred = nullptr;
ASSERT_EQ(OB_SUCCESS, guard.get_credential(cred));
ASSERT_NE(nullptr, cred);
}
TEST_F(TestTableSessPool, retire_session_then_get_session)
TEST_F(TestTableSessPool, mgr_update_session)
{
uint64_t tenant_id = 1;
uint64_t user_id = 0;
ObTableApiSessPoolMgr mgr;
ASSERT_EQ(OB_SUCCESS, mgr.init());
ObTableApiSessPoolGuard pool_guard;
ASSERT_EQ(OB_SUCCESS, mgr.extend_sess_pool(tenant_id, pool_guard));
ObTableApiCredential credential;
credential.tenant_id_ = tenant_id;
credential.user_id_ = user_id;
ASSERT_EQ(OB_SUCCESS, mgr.update_sess(credential));
ASSERT_EQ(OB_SYS_TENANT_ID, MTL_ID());
ObTableApiSessPoolMgr *mgr = TABLEAPI_SESS_POOL_MGR;
// first time will create a new node
ASSERT_EQ(OB_SUCCESS, mgr->update_sess(*mock_cred_));
ASSERT_NE(nullptr, mgr->pool_);
ASSERT_TRUE(mgr->pool_->is_inited_);
ASSERT_EQ(1, mgr->pool_->key_node_map_.size());
ASSERT_EQ(0, mgr->pool_->retired_nodes_.size_);
ObTableApiSessNode *node;
ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(mock_cred_->user_id_, node));
ASSERT_NE(nullptr, node);
ASSERT_TRUE(node->sess_lists_.free_list_.is_empty());
ASSERT_TRUE(node->sess_lists_.used_list_.is_empty());
ASSERT_NE(0, node->last_active_ts_);
// second time will do replace
ObTableApiCredential *new_cred = nullptr;
create_credential(1, new_cred);
ASSERT_NE(nullptr, new_cred);
ASSERT_EQ(OB_SUCCESS, mgr->update_sess(*new_cred));
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(OB_SUCCESS, mgr->pool_->get_sess_node(new_cred->user_id_, node));
ASSERT_NE(nullptr, node);
ASSERT_TRUE(node->sess_lists_.free_list_.is_empty());
ASSERT_TRUE(node->sess_lists_.used_list_.is_empty());
ASSERT_NE(0, node->last_active_ts_);
// update another key is 2 node.
create_credential(2, new_cred);
ASSERT_NE(nullptr, new_cred);
ASSERT_EQ(OB_SUCCESS, mgr->update_sess(*new_cred));
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(OB_SUCCESS, mgr->pool_->get_sess_node(new_cred->user_id_, node));
ASSERT_NE(nullptr, node);
ASSERT_TRUE(node->sess_lists_.free_list_.is_empty());
ASSERT_TRUE(node->sess_lists_.used_list_.is_empty());
ASSERT_NE(0, node->last_active_ts_);
}
// 塞一个ObTableApiSessNodeVal
ObTableApiSessPool *pool = pool_guard.get_sess_pool();
ObTableApiSessNode *node = nullptr;
ASSERT_EQ(OB_SUCCESS, pool->get_sess_node(user_id, node));
void *buf = node->allocator_.alloc(sizeof(ObTableApiSessNodeVal));
ASSERT_NE(nullptr, buf);
ObTableApiSessNodeVal *val = new (buf) ObTableApiSessNodeVal(tenant_id, node);
val->is_inited_ = true;
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(val));
TEST_F(TestTableSessPool, mgr_destroy)
{
ASSERT_EQ(OB_SYS_TENANT_ID, MTL_ID());
ObTableApiSessPoolMgr *mgr = TABLEAPI_SESS_POOL_MGR;
ASSERT_EQ(OB_SUCCESS, mgr->update_sess(*mock_cred_));
ASSERT_NE(nullptr, mgr->pool_);
ObTableApiSessNode *node;
ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(mock_cred_->user_id_, node));
mgr->destroy();
ASSERT_FALSE(mgr->is_inited_);
ASSERT_EQ(nullptr, mgr->pool_);
ASSERT_EQ(0, mgr->allocator_.total());
ASSERT_EQ(0, mgr->allocator_.used());
}
// 第一次获取了session
ObTableApiSessGuard sess_guard;
ASSERT_EQ(OB_SUCCESS, mgr.get_sess_info(credential, sess_guard));
sess_guard.~ObTableApiSessGuard(); // 模仿访问结束,析构
TEST_F(TestTableSessPool, mgr_sess_recycle)
{
ASSERT_EQ(OB_SYS_TENANT_ID, MTL_ID());
ObTableApiSessPoolMgr *mgr = TABLEAPI_SESS_POOL_MGR;
ASSERT_EQ(OB_SUCCESS, mgr->update_sess(*mock_cred_));
ASSERT_NE(nullptr, mgr->pool_);
// 长时间没有访问ob,session被放到淘汰链表,后台定时回收
ASSERT_EQ(OB_SUCCESS, pool->get_sess_node(user_id, node));
ASSERT_EQ(OB_SUCCESS, pool->move_sess_to_retired_list(user_id));
ASSERT_EQ(1, pool->retired_nodes_.size_);
ASSERT_EQ(OB_SUCCESS, mgr.elimination_task_.run_recycle_retired_sess_task());
ASSERT_EQ(0, pool->retired_nodes_.size_);
// add mock val to node
ObTableApiSessNode *node;
ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(mock_cred_->user_id_, node));
ObTableApiSessNodeVal val(node);
val.is_inited_ = true;
ASSERT_EQ(true, node->sess_lists_.free_list_.add_last(&val));
// 连接隔了很长时间,突然又访问db
ASSERT_EQ(OB_HASH_NOT_EXIST, pool->get_sess_node(user_id, node));
ObTableApiSessGuard guard;
ASSERT_EQ(OB_SUCCESS, mgr->get_sess_info(*mock_cred_, guard));
mgr->elimination_task_.runTimerTask();
ASSERT_EQ(1, mgr->pool_->key_node_map_.size());
ASSERT_EQ(0, mgr->pool_->retired_nodes_.size_);
guard.~ObTableApiSessGuard();
// 新的访问会创建新的池子
ASSERT_EQ(OB_SUCCESS, mgr.get_or_create_sess_pool(credential, pool_guard));
// 3min not access
ASSERT_EQ(OB_SUCCESS, mgr->pool_->get_sess_node(mock_cred_->user_id_, node));
node->last_active_ts_ = node->last_active_ts_ - ObTableApiSessPool::SESS_RETIRE_TIME;
mgr->elimination_task_.run_retire_sess_task();
ASSERT_EQ(0, mgr->pool_->key_node_map_.size());
ASSERT_EQ(1, mgr->pool_->retired_nodes_.size_);
mgr->elimination_task_.run_recycle_retired_sess_task();
ASSERT_EQ(0, mgr->pool_->key_node_map_.size());
ASSERT_EQ(0, mgr->pool_->retired_nodes_.size_);
}
int main(int argc, char **argv)