patch 4.0

This commit is contained in:
wangzelin.wzl
2022-10-24 10:34:53 +08:00
parent 4ad6e00ec3
commit 93a1074b0c
10533 changed files with 2588271 additions and 2299373 deletions

View File

@ -16,62 +16,67 @@
#include "lib/string/ob_sql_string.h"
#include "lib/stat/ob_session_stat.h"
#include "lib/mysqlclient/ob_mysql_proxy.h"
#include "lib/utility/ob_tracepoint.h"
#include "share/inner_table/ob_inner_table_schema_constants.h"
#include "share/ob_resource_limit.h"
#include "io/easy_io.h"
#include "rpc/ob_rpc_define.h"
#include "sql/ob_sql_trans_control.h"
#include "observer/mysql/obsm_handler.h"
#include "observer/mysql/obsm_struct.h"
#include "rpc/obmysql/obsm_struct.h"
#include "observer/ob_server_struct.h"
#include "sql/monitor/ob_security_audit_utils.h"
#include "sql/session/ob_user_resource_mgr.h"
#include "sql/monitor/full_link_trace/ob_flt_control_info_mgr.h"
using namespace oceanbase::common;
using namespace oceanbase::sql;
using namespace oceanbase::share;
using namespace oceanbase::observer;
ObSQLSessionMgr::SessionPool::SessionPool() : session_pool_()
ObSQLSessionMgr::SessionPool::SessionPool()
: session_pool_()
{
MEMSET(session_array, 0, POOL_CAPACIPY * sizeof(ObSQLSessionInfo*));
MEMSET(session_array, 0, POOL_CAPACIPY * sizeof(ObSQLSessionInfo *));
}
int ObSQLSessionMgr::SessionPool::init()
{
int ret = OB_SUCCESS;
char* session_buf = reinterpret_cast<char*>(session_array);
OZ(session_pool_.init(POOL_CAPACIPY, session_buf));
char *session_buf = reinterpret_cast<char *>(session_array);
OZ (session_pool_.init(POOL_CAPACIPY, session_buf));
return ret;
}
int ObSQLSessionMgr::SessionPool::pop_session(uint64_t tenant_id, ObSQLSessionInfo*& session)
int ObSQLSessionMgr::SessionPool::pop_session(uint64_t tenant_id, ObSQLSessionInfo *&session)
{
int ret = OB_SUCCESS;
session = NULL;
if (OB_FAIL(session_pool_.pop(session))) {
if (ret != OB_ENTRY_NOT_EXIST) {
LOG_WARN(
"failed to pop session", K(ret), K(tenant_id), K(session_pool_.get_total()), K(session_pool_.get_free()));
LOG_WARN("failed to pop session", K(ret),
K(tenant_id), K(session_pool_.get_total()), K(session_pool_.get_free()));
} else {
ret = OB_SUCCESS;
LOG_DEBUG("session pool is empty",
K(tenant_id), K(session_pool_.get_total()), K(session_pool_.get_free()), K(lbt()));
K(tenant_id), K(session_pool_.get_total()), K(session_pool_.get_free()));
}
}
return ret;
}
int ObSQLSessionMgr::SessionPool::push_session(uint64_t tenant_id, ObSQLSessionInfo*& session)
int ObSQLSessionMgr::SessionPool::push_session(uint64_t tenant_id, ObSQLSessionInfo *&session)
{
int ret = OB_SUCCESS;
if (OB_NOT_NULL(session)) {
if (OB_FAIL(session_pool_.push(session))) {
if (ret != OB_SIZE_OVERFLOW) {
LOG_WARN(
"failed to push session", K(ret), K(tenant_id), K(session_pool_.get_total()), K(session_pool_.get_free()));
LOG_WARN("failed to push session", K(ret),
K(tenant_id), K(session_pool_.get_total()), K(session_pool_.get_free()));
} else {
ret = OB_SUCCESS;
LOG_INFO(
"session pool is full", K(tenant_id), K(session_pool_.get_total()), K(session_pool_.get_free()), K(lbt()));
LOG_DEBUG("session pool is full",
K(tenant_id), K(session_pool_.get_total()), K(session_pool_.get_free()));
}
} else {
session = NULL;
@ -85,51 +90,55 @@ int64_t ObSQLSessionMgr::SessionPool::count() const
return session_pool_.get_total();
}
int ObSQLSessionMgr::SessionPoolMap::get_session_pool(uint64_t tenant_id, SessionPool*& session_pool)
int ObSQLSessionMgr::SessionPoolMap::get_session_pool(uint64_t tenant_id,
SessionPool *&session_pool)
{
int ret = OB_SUCCESS;
uint64_t block_id = get_block_id(tenant_id);
uint64_t slot_id = get_slot_id(tenant_id);
SessionPoolBlock* pool_block = NULL;
SessionPoolBlock *pool_block = NULL;
if (block_id < pool_blocks_.count()) {
OX(pool_block = pool_blocks_.at(block_id));
OX (pool_block = pool_blocks_.at(block_id));
} else {
OZ(create_pool_block(block_id, pool_block));
OZ (create_pool_block(block_id, pool_block));
}
OV(OB_NOT_NULL(pool_block), OB_ERR_UNEXPECTED, tenant_id, block_id, slot_id);
OX(session_pool = ATOMIC_LOAD(&((*pool_block)[slot_id])));
OV (OB_NOT_NULL(pool_block), OB_ERR_UNEXPECTED, tenant_id, block_id, slot_id);
OX (session_pool = ATOMIC_LOAD(&((*pool_block)[slot_id])));
if (OB_ISNULL(session_pool)) {
OZ(create_session_pool(*pool_block, slot_id, session_pool));
OZ (create_session_pool(*pool_block, slot_id, session_pool));
}
return ret;
}
int ObSQLSessionMgr::SessionPoolMap::create_pool_block(uint64_t block_id, SessionPoolBlock*& pool_block)
int ObSQLSessionMgr::SessionPoolMap::create_pool_block(uint64_t block_id,
SessionPoolBlock *&pool_block)
{
int ret = OB_SUCCESS;
void* buf = NULL;
void *buf = NULL;
ObLockGuard<ObSpinLock> lock_guard(lock_);
while (OB_SUCC(ret) && block_id >= pool_blocks_.count()) {
OV(OB_NOT_NULL(buf = alloc_.alloc(sizeof(SessionPoolBlock))), OB_ALLOCATE_MEMORY_FAILED, block_id);
OX(MEMSET(buf, 0, sizeof(SessionPoolBlock)));
OZ(pool_blocks_.push_back(static_cast<SessionPoolBlock*>(buf)), block_id);
OV (OB_NOT_NULL(buf = alloc_.alloc(sizeof(SessionPoolBlock))),
OB_ALLOCATE_MEMORY_FAILED, block_id);
OX (MEMSET(buf, 0, sizeof(SessionPoolBlock)));
OZ (pool_blocks_.push_back(static_cast<SessionPoolBlock *>(buf)), block_id);
}
OX(pool_block = pool_blocks_.at(block_id));
OX (pool_block = pool_blocks_.at(block_id));
return ret;
}
int ObSQLSessionMgr::SessionPoolMap::create_session_pool(
SessionPoolBlock& pool_block, uint64_t slot_id, SessionPool*& session_pool)
int ObSQLSessionMgr::SessionPoolMap::create_session_pool(SessionPoolBlock &pool_block,
uint64_t slot_id,
SessionPool *&session_pool)
{
int ret = OB_SUCCESS;
void* buf = NULL;
OV(slot_id < SLOT_PER_BLOCK);
void *buf = NULL;
OV (slot_id < SLOT_PER_BLOCK);
ObLockGuard<ObSpinLock> lock_guard(lock_);
if (OB_ISNULL(session_pool = ATOMIC_LOAD(&(pool_block[slot_id])))) {
OV(OB_NOT_NULL(buf = alloc_.alloc(sizeof(SessionPool))), OB_ALLOCATE_MEMORY_FAILED);
OV(OB_NOT_NULL(session_pool = new (buf) SessionPool()));
OZ(session_pool->init());
OX(ATOMIC_STORE(&(pool_block[slot_id]), session_pool));
OV (OB_NOT_NULL(buf = alloc_.alloc(sizeof(SessionPool))), OB_ALLOCATE_MEMORY_FAILED);
OV (OB_NOT_NULL(session_pool = new (buf) SessionPool()));
OZ (session_pool->init());
OX (ATOMIC_STORE(&(pool_block[slot_id]), session_pool));
}
return ret;
}
@ -147,95 +156,113 @@ uint64_t ObSQLSessionMgr::SessionPoolMap::get_slot_id(uint64_t tenant_id) const
int ObSQLSessionMgr::ValueAlloc::clean_tenant(uint64_t tenant_id)
{
int ret = OB_SUCCESS;
SessionPool* session_pool = NULL;
ObSQLSessionInfo* session = NULL;
SessionPool *session_pool = NULL;
ObSQLSessionInfo *session = NULL;
if (is_valid_tenant_id(tenant_id)) {
OX(session_pool_map_.get_session_pool(tenant_id, session_pool));
OX (session_pool_map_.get_session_pool(tenant_id, session_pool));
}
if (OB_NOT_NULL(session_pool)) {
// Note that there is no design guarantee that the session pool must be completely cleaned.
// There is a very low probability of session leak.
// 1. In the production system, deleting tenants is a very rare operation.
// 2. In the production system, before deleting a tenant, we must ensure that the business
// layer will no longer access the tenant.
// Under the above premise, theoretically, the tenant will have no active session.
// 3. When stopping an observer, even if a few sessions are missing, they will be releasedi
// with the end of the process.
// 4. In the case of unit migration, a few sessions may not be released, but in the future,
// the unit can be reused after migrating back.
// 注意,这里并没有从设计上保证session池一定被彻底清空,有极低概率会有少量遗留session:
// 1. 在生产系统中,删除租户是非常少见的操作。
// 2. 在生产系统中,删除租户前一定会先保证业务层不再访问该租户。
// 以上前提下,理论上该session池已经没有任何操作。
// 3. 正常停掉某个observer,但即使有少数session遗漏,也会随着进程结束而释放。
// 4. unit迁移等情况,可能会有少数session未被释放,但将来unit再迁回后可复用。
while (session_pool->count() > 0) {
OX(session_pool->pop_session(tenant_id, session));
OX (session_pool->pop_session(tenant_id, session));
if (OB_NOT_NULL(session)) {
OX(op_reclaim_free(session));
OX(session = NULL);
OX (op_reclaim_free(session));
OX (session = NULL);
}
}
}
return ret;
}
ObSQLSessionInfo* ObSQLSessionMgr::ValueAlloc::alloc_value(uint64_t tenant_id)
ObSQLSessionInfo *ObSQLSessionMgr::ValueAlloc::alloc_value(uint64_t tenant_id)
{
int ret = OB_SUCCESS;
SessionPool* session_pool = NULL;
ObSQLSessionInfo* session = NULL;
SessionPool *session_pool = NULL;
ObSQLSessionInfo *session = NULL;
int64_t alloc_total_count = 0;
ObFLTControlInfoManager mgr(tenant_id);
// we use OX instead of OZ in operation of upper session pool, because we need acquire
// from lower session pool when not success, no matter which errno we get here.
if (is_valid_tenant_id(tenant_id)) {
OX(session_pool_map_.get_session_pool(tenant_id, session_pool));
OX(alloc_total_count = ATOMIC_FAA(&alloc_total_count_, 1));
OX (session_pool_map_.get_session_pool(tenant_id, session_pool));
OX (alloc_total_count = ATOMIC_FAA(&alloc_total_count_, 1));
}
if (OB_NOT_NULL(session_pool)) {
OX(session_pool->pop_session(tenant_id, session));
OX (session_pool->pop_session(tenant_id, session));
}
if (OB_ISNULL(session)) {
OX(session = op_reclaim_alloc(ObSQLSessionInfo));
OX (session = op_reclaim_alloc(ObSQLSessionInfo));
} else if (OB_FAIL(mgr.init())) {
LOG_WARN("failed to init full link control info", K(ret));
} else {
OX(ATOMIC_FAA(&alloc_from_pool_count_, 1));
if (mgr.is_valid_tenant_config()) {
session->set_flt_control_info(mgr.get_control_info());
}
OX (ATOMIC_FAA(&alloc_from_pool_count_, 1));
}
OV(OB_NOT_NULL(session));
OX(session->set_valid(true));
OX(session->set_shadow(true));
OV (OB_NOT_NULL(session));
OX (session->set_valid(true));
OX (session->set_shadow(true));
if (OB_SUCC(ret)) {
if (OB_FAIL(GCTX.session_mgr_->get_sess_hold_map()
.set_refactored(reinterpret_cast<uint64_t>(session), session))) {
LOG_WARN("fail to set session", K(ret), KP(session));
}
}
if (alloc_total_count > 0 && alloc_total_count % 10000 == 0) {
LOG_INFO("alloc_session_count", K(alloc_total_count), K_(alloc_from_pool_count));
}
return session;
}
void ObSQLSessionMgr::ValueAlloc::free_value(ObSQLSessionInfo* session)
void ObSQLSessionMgr::ValueAlloc::free_value(ObSQLSessionInfo *session)
{
if (OB_NOT_NULL(session)) {
int ret = OB_SUCCESS;
uint64_t tenant_id = session->get_login_tenant_id();
SessionPool* session_pool = NULL;
SessionPool *session_pool = NULL;
int64_t free_total_count = 0;
// delete from hold map, ingore error
int tmp_ret = OB_SUCCESS;
if (OB_SUCCESS != (tmp_ret = GCTX.session_mgr_->get_sess_hold_map().erase_refactored(
reinterpret_cast<uint64_t>(session)))) {
LOG_WARN("fail to erase session", K(session->get_sessid()), K(tmp_ret), KP(session));
}
if (is_valid_tenant_id(tenant_id) && session->can_release_to_pool()) {
if (session->is_use_inner_allocator() && !session->is_tenant_killed()) {
OX(session_pool_map_.get_session_pool(tenant_id, session_pool));
OX (session_pool_map_.get_session_pool(tenant_id, session_pool));
}
OX(free_total_count = ATOMIC_FAA(&free_total_count_, 1));
OX (free_total_count = ATOMIC_FAA(&free_total_count_, 1));
}
if (OB_NOT_NULL(session_pool)) {
OX(session->destroy(true));
OX(session->set_acquire_from_pool(true));
OX(session_pool->push_session(tenant_id, session));
OX (session->destroy(true));
OX (session->set_acquire_from_pool(true));
OX (session_pool->push_session(tenant_id, session));
}
if (OB_NOT_NULL(session)) {
OX(op_reclaim_free(session));
OX(session = NULL);
OX (op_reclaim_free(session));
OX (session = NULL);
} else {
OX(ATOMIC_FAA(&free_to_pool_count_, 1));
OX (ATOMIC_FAA(&free_to_pool_count_, 1));
}
if (free_total_count > 0 && free_total_count % 10000 == 0) {
LOG_INFO("free_session_count", K(free_total_count), K_(free_to_pool_count));
}
ObActiveSessionGuard::setup_default_ash();
}
}
bool ObSQLSessionMgr::ValueAlloc::is_valid_tenant_id(uint64_t tenant_id) const
{
return ::is_valid_tenant_id(tenant_id) && tenant_id != OB_INVALID_ID && tenant_id != OB_SYS_TENANT_ID;
return ::is_valid_tenant_id(tenant_id) &&
tenant_id != OB_INVALID_ID &&
tenant_id != OB_SYS_TENANT_ID;
}
int ObSQLSessionMgr::init()
@ -245,6 +272,10 @@ int ObSQLSessionMgr::init()
LOG_WARN("fail to init session map", K(ret));
} else if (OB_FAIL(sessid_sequence_.init(MAX_LOCAL_SEQ))) {
LOG_WARN("init sessid sequence failed", K(ret));
} else if (OB_FAIL(sess_hold_map_.create(BUCKET_COUNT,
"SessHoldMapBuck",
"SessHoldMapNode"))) {
LOG_WARN("failed to init sess_hold_map", K(ret));
}
for (uint32_t i = 1; OB_SUCC(ret) && i <= MAX_LOCAL_SEQ; ++i) {
if (OB_FAIL(sessid_sequence_.push(reinterpret_cast<void*>(i)))) {
@ -260,15 +291,14 @@ uint64_t ObSQLSessionMgr::extract_server_id(uint32_t sessid)
return server_id & MAX_SERVER_ID;
}
int ObSQLSessionMgr::inc_session_ref(const ObSQLSessionInfo* my_session)
int ObSQLSessionMgr::inc_session_ref(const ObSQLSessionInfo *my_session)
{
int ret = OB_SUCCESS;
if (OB_NOT_NULL(my_session)) {
ObSQLSessionInfo* tmp_session = NULL;
uint32_t version = my_session->get_version();
ObSQLSessionInfo *tmp_session = NULL;
uint32_t sessid = my_session->get_sessid();
if (OB_FAIL(get_session(version, sessid, tmp_session))) {
LOG_WARN("fail to get session", K(version), K(sessid), K(ret));
if (OB_FAIL(get_session(sessid, tmp_session))) {
LOG_WARN("fail to get session", K(sessid), K(ret));
}
UNUSED(tmp_session);
}
@ -282,9 +312,10 @@ int ObSQLSessionMgr::inc_session_ref(const ObSQLSessionInfo* my_session)
// |Mask| Server Id | Local Seq |
// +----+------------------------------+--------------------------------+
//
// MASK: 1 means session_id is generated by observer, 0 means in_mgr = false.
// Server Id: generated by root server, and unique in cluster.
// Local Seq: max session number in an observer.
//MASK: 1 表示是server自己生成connection id,
// 0 表示是proxy生成的connection id(已废弃,目前仅用于 in_mgr = false 的场景);
//Server Id: 集群中server的id由RS分配,集群内唯一;
//Local Seq: 一个server可用连接数,目前单台server最多有INT16_MAX个连接;
//
int ObSQLSessionMgr::create_sessid(uint32_t &sessid, bool in_mgr)
{
@ -293,7 +324,7 @@ int ObSQLSessionMgr::create_sessid(uint32_t &sessid, bool in_mgr)
sessid = 0;
const uint64_t server_id = GCTX.server_id_;
uint32_t local_seq = 0;
static uint32_t abnormal_seq = 0;
static uint32_t abnormal_seq = 0;//用于server_id == 0是的sessid分配
if (server_id > MAX_SERVER_ID) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("server id maybe invalid", K(ret), K(server_id));
@ -307,11 +338,10 @@ int ObSQLSessionMgr::create_sessid(uint32_t &sessid, bool in_mgr)
LOG_WARN("server is initiating", K(server_id), K(local_seq), K(max_local_seq), K(max_server_id));
} else if (OB_UNLIKELY(OB_SUCCESS != (ret = tmp_ret = get_avaiable_local_seq(local_seq)))) {
LOG_WARN("fail to get avaiable local_seq", K(local_seq));
} else { /*do nothing*/
}
} else {/*do nothing*/}
if (OB_SUCC(ret) && in_mgr) {
sessid = local_seq | SERVER_SESSID_TAG; // set observer sessid mark
sessid = local_seq | SERVER_SESSID_TAG;// set observer sessid mark
sessid |= static_cast<uint32_t>(server_id << LOCAL_SEQ_LEN); // set observer
// high bit is reserved for server id
sessid |= static_cast<uint32_t>(1ULL << (LOCAL_SEQ_LEN + SERVER_ID_LEN));
@ -319,120 +349,107 @@ int ObSQLSessionMgr::create_sessid(uint32_t &sessid, bool in_mgr)
return ret;
}
// if ret == OB_SUCCESS, sess_info must be not NULL, caller must call revert_session() later.
// if ret != OB_SUCCESS, sess_info must be NULL.
int ObSQLSessionMgr::create_session_by_version(
uint64_t tenant_id, uint32_t sessid, uint64_t proxy_sessid, ObSQLSessionInfo*& sess_info, uint32_t& out_version)
{
int ret = OB_SUCCESS;
int gt_ret = OB_SUCCESS;
int rt_ret = OB_SUCCESS;
sess_info = NULL;
out_version = 0;
uint32_t version = 0;
bool is_shadow = false;
ObSQLSessionInfo* tmp_sess = NULL;
do {
is_shadow = false;
if (OB_FAIL(sessinfo_map_.create(tenant_id, Key(version, sessid, proxy_sessid), tmp_sess))) {
if (OB_LIKELY(OB_ENTRY_EXIST == ret)) {
if (OB_UNLIKELY(OB_SUCCESS != (gt_ret = get_session(version, sessid, tmp_sess)))) {
if (OB_ENTRY_NOT_EXIST == gt_ret) {
LOG_DEBUG("session has been freed", K(gt_ret), K(version), K(sessid));
} else {
LOG_WARN("fail to get session", K(gt_ret), K(version), K(sessid));
}
} else {
is_shadow = tmp_sess->is_shadow();
if (OB_UNLIKELY(OB_SUCCESS != (rt_ret = revert_session(tmp_sess)))) {
LOG_ERROR("fail to revert session", K(rt_ret));
}
++version;
}
}
}
} while (OB_UNLIKELY(OB_ENTRY_EXIST == ret && ((OB_SUCCESS == gt_ret && is_shadow) || OB_ENTRY_NOT_EXIST == gt_ret) &&
version <= MAX_VERSION));
if (OB_SUCC(ret)) {
sess_info = tmp_sess;
out_version = version;
}
return ret;
}
// if ret == OB_SUCCESS, sess_info must be not NULL, caller must call revert_session() later.
// if ret != OB_SUCCESS, sess_info must be NULL.
int ObSQLSessionMgr::create_session(ObSMConnection* conn, ObSQLSessionInfo*& sess_info)
//ret == OB_SUCCESS时,保证sess_info != NULL, 需要在外面进行revert_session
//ret != OB_SUCCESS时,保证sess_info == NULL, 不需要在外面进行revert_session
int ObSQLSessionMgr::create_session(ObSMConnection *conn, ObSQLSessionInfo *&sess_info)
{
int ret = OB_SUCCESS;
sess_info = NULL;
if (OB_ISNULL(conn)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("conn is NULL", K(ret));
} else if (OB_FAIL(create_session(
conn->tenant_id_, conn->sessid_, conn->proxy_sessid_, conn->sess_create_time_, sess_info))) {
} else if (OB_FAIL(create_session(conn->tenant_id_,
conn->sessid_,
conn->proxy_sessid_,
conn->sess_create_time_,
sess_info))) {
LOG_WARN("create session failed", K(ret));
} else if (OB_ISNULL(sess_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL session returned", K(ret));
} else {
conn->version_ = sess_info->get_version();
}
return ret;
}
int ObSQLSessionMgr::create_session(const uint64_t tenant_id, const uint32_t sessid, const uint64_t proxy_sessid,
const int64_t create_time, ObSQLSessionInfo*& session_info)
int ObSQLSessionMgr::create_session(const uint64_t tenant_id,
const uint32_t sessid,
const uint64_t proxy_sessid,
const int64_t create_time,
ObSQLSessionInfo *&session_info)
{
int ret = OB_SUCCESS;
int err = OB_SUCCESS;
session_info = NULL;
uint32_t version = 0;
ObSQLSessionInfo* tmp_sess = NULL;
if (OB_FAIL(create_session_by_version(tenant_id, sessid, proxy_sessid, tmp_sess, version))) {
LOG_WARN("fail to create session by version", K(ret), K(sessid), K(version));
ObSQLSessionInfo *tmp_sess = NULL;
if (RL_IS_ENABLED) {
int64_t sess_count = 0;
if (OB_FAIL(get_session_count(sess_count))) {
LOG_WARN("fail to get session count", K(ret));
} else if (sess_count > RL_CONF.get_max_session_count()) {
ret = OB_RESOURCE_OUT;
LOG_WARN("too much sessions", K(ret), K(sess_count), K(RL_CONF.get_max_session_count()));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(sessinfo_map_.create(tenant_id, Key(sessid, proxy_sessid), tmp_sess))) {
LOG_WARN("fail to create session", K(ret), K(sessid));
if (OB_ENTRY_EXIST == ret) {
ret = OB_SESSION_ENTRY_EXIST;
}
} else if (OB_ISNULL(tmp_sess)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to alloc session info", K(ret), K(version), K(sessid), K(proxy_sessid));
} else if (OB_FAIL(tmp_sess->init(version, sessid, proxy_sessid, NULL, NULL, create_time, tenant_id))) {
LOG_WARN("fail to init session", K(ret), K(tmp_sess), K(version), K(sessid), K(proxy_sessid), K(create_time));
if (OB_SUCCESS != (err = revert_session(tmp_sess))) {
LOG_ERROR("fail to free session", K(err), K(version), K(sessid), K(proxy_sessid));
} else if (OB_SUCCESS != (err = sessinfo_map_.del(Key(version, sessid)))) {
LOG_ERROR("fail to free session", K(err), K(version), K(sessid), K(proxy_sessid));
LOG_WARN("fail to alloc session info", K(ret), K(sessid), K(proxy_sessid));
} else {
// create session contains a 'get_session' action implicitly
const bool v = GCONF._enable_trace_session_leak;
if (OB_UNLIKELY(v)) {
tmp_sess->on_get_session();
}
}
if (OB_FAIL(ret)) {
// pass
} else if (OB_FAIL(tmp_sess->init(sessid, proxy_sessid, NULL, NULL, create_time,
tenant_id))) {
LOG_WARN("fail to init session", K(ret), K(tmp_sess),
K(sessid), K(proxy_sessid), K(create_time));
if (FALSE_IT(revert_session(tmp_sess))) {
LOG_ERROR("fail to free session", K(err), K(sessid), K(proxy_sessid));
} else if (OB_SUCCESS != (err = sessinfo_map_.del(Key(sessid)))) {
LOG_ERROR("fail to free session", K(err), K(sessid), K(proxy_sessid));
} else {
LOG_DEBUG("free session successfully in create session", K(err), K(version), K(sessid), K(proxy_sessid));
LOG_DEBUG("free session successfully in create session", K(err),
K(sessid), K(proxy_sessid));
}
} else {
// set tenant info to session, if has.
ObFLTControlInfoManager mgr(tenant_id);
if (OB_FAIL(mgr.init())) {
LOG_WARN("failed to init full link control info", K(ret));
} else if (mgr.is_valid_tenant_config()) {
tmp_sess->set_flt_control_info(mgr.get_control_info());
}
tmp_sess->update_last_active_time();
session_info = tmp_sess;
}
return ret;
}
int ObSQLSessionMgr::free_session(const ObFreeSessionCtx& ctx)
int ObSQLSessionMgr::free_session(const ObFreeSessionCtx &ctx)
{
int ret = OB_SUCCESS;
uint32_t version = ctx.version_;
uint32_t sessid = ctx.sessid_;
uint64_t proxy_sessid = ctx.proxy_sessid_;
uint64_t tenant_id = ctx.tenant_id_;
bool has_inc = ctx.has_inc_active_num_;
ObSQLSessionInfo* sess_info = NULL;
sessinfo_map_.get(Key(version, sessid), sess_info);
ObSQLSessionInfo *sess_info = NULL;
sessinfo_map_.get(Key(sessid), sess_info);
if (NULL != sess_info) {
if (sess_info->has_got_conn_res()
&& OB_UNLIKELY(OB_SUCCESS != sess_info->on_user_disconnect())) {
LOG_ERROR("user disconnect failed", K(ret), K(sess_info->get_user_id()));
LOG_WARN("user disconnect failed", K(ret), K(sess_info->get_user_id()));
}
sessinfo_map_.revert(sess_info);
}
if (OB_FAIL(sessinfo_map_.del(Key(version, sessid)))) {
LOG_WARN("fail to remove session from session map", K(ret), K(version), K(sessid), K(proxy_sessid));
if (OB_FAIL(sessinfo_map_.del(Key(sessid)))) {
LOG_WARN("fail to remove session from session map", K(ret), K(sessid), K(proxy_sessid));
} else if (tenant_id != 0 && sessid != 0 && has_inc) {
ObTenantStatEstGuard guard(tenant_id);
EVENT_DEC(ACTIVE_SESSIONS);
@ -443,15 +460,39 @@ int ObSQLSessionMgr::free_session(const ObFreeSessionCtx& ctx)
void ObSQLSessionMgr::try_check_session()
{
int ret = OB_SUCCESS;
int64_t sess_count = 0;
CheckSessionFunctor check_timeout(this);
if (OB_FAIL(for_each_session(check_timeout))) {
LOG_WARN("fail to check time out", K(ret));
} else if (OB_FAIL(get_session_count(sess_count))) {
} else {
if (REACH_TIME_INTERVAL(60000000)) { // 60s
OZ (check_session_leak());
}
}
}
int ObSQLSessionMgr::check_session_leak()
{
int ret = OB_SUCCESS;
int64_t hold_session_count = sess_hold_map_.size();
int64_t used_session_count = 0;
if (OB_FAIL(get_session_count(used_session_count))) {
LOG_WARN("fail to get session count", K(ret));
} else {
LOG_DEBUG("get current session count", K(sess_count));
static const int32_t DEFAULT_SESSION_LEAK_COUNT_THRESHOLD = 100;
int64_t session_leak_count_threshold = - EVENT_CALL(EventTable::EN_SESSION_LEAK_COUNT_THRESHOLD);
session_leak_count_threshold = session_leak_count_threshold > 0
? session_leak_count_threshold
: DEFAULT_SESSION_LEAK_COUNT_THRESHOLD;
LOG_INFO("get current session count", K(used_session_count), K(hold_session_count),
K(session_leak_count_threshold));
if (hold_session_count - used_session_count >= session_leak_count_threshold) {
LOG_ERROR("session leak!!!", "leak_count", hold_session_count - used_session_count,
K(used_session_count), K(hold_session_count));
DumpHoldSession dump_session;
OZ(for_each_hold_session(dump_session));
}
}
return ret;
}
void ObSQLSessionMgr::runTimerTask()
@ -460,111 +501,114 @@ void ObSQLSessionMgr::runTimerTask()
}
// just a wrapper
int ObSQLSessionMgr::kill_query(ObSQLSessionInfo& session)
int ObSQLSessionMgr::kill_query(ObSQLSessionInfo &session)
{
return kill_query(session, partition_service_);
return kill_query(session, ObSQLSessionState::QUERY_KILLED);
}
int ObSQLSessionMgr::kill_query(ObSQLSessionInfo& session, storage::ObPartitionService* partition_service)
int ObSQLSessionMgr::set_query_deadlocked(ObSQLSessionInfo &session)
{
int tmp_ret = OB_SUCCESS;
// must call kill_query_session() to wakeup worker thread first,
// otherwise kill_query() may not work if worker is sleep.
if (OB_SUCCESS !=
(tmp_ret = ObSqlTransControl::kill_query_session(partition_service, session, ObSQLSessionState::QUERY_KILLED))) {
LOG_WARN("fail to kill query or session", "ret", tmp_ret, K(session));
}
return session.kill_query();
return kill_query(session, ObSQLSessionState::QUERY_DEADLOCKED);
}
// kill active transaction on this session
int ObSQLSessionMgr::kill_active_trx(ObSQLSessionInfo* session)
{
return ObSqlTransControl::kill_active_trx(partition_service_, session);
}
int ObSQLSessionMgr::kill_session(ObSQLSessionInfo& session)
int ObSQLSessionMgr::kill_query(ObSQLSessionInfo &session,
const ObSQLSessionState status)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
// must call kill_query_session() to wakeup worker thread first,
// otherwise kill_query() may not work if worker is sleep.
if (OB_SUCCESS != (tmp_ret = ObSqlTransControl::kill_query_session(
partition_service_, session, ObSQLSessionState::SESSION_KILLED))) {
//如果start_stmt/end_stmt卡住,此时需要先唤醒sql线程,然后再设置标记,否则kill session不起作用
if (OB_SUCCESS != (tmp_ret = ObSqlTransControl::kill_query_session(session, status))) {
LOG_WARN("fail to kill query or session", "ret", tmp_ret, K(session));
}
session.set_session_state(SESSION_KILLED);
// DO NOT change the order of the two guards below, otherwise it may cause deadlock.
ObSQLSessionInfo::LockGuard query_lock_guard(session.get_query_lock());
ObSQLSessionInfo::LockGuard data_lock_guard(session.get_thread_data_lock());
bool has_called_txs_end_trans = false;
session.set_query_start_time(ObTimeUtility::current_time());
if (OB_SUCCESS != (tmp_ret = ObSqlTransControl::end_trans(partition_service_, &session, has_called_txs_end_trans))) {
LOG_WARN("fail to rollback transaction",
K(session.get_sessid()),
"proxy_sessid",
session.get_proxy_sessid(),
K(tmp_ret),
"trans_id",
session.get_trans_desc().get_trans_id(),
"query_str",
session.get_current_query_string(),
K(has_called_txs_end_trans));
if (ObSQLSessionState::QUERY_KILLED == status) {
ret = session.kill_query();
} else if (ObSQLSessionState::QUERY_DEADLOCKED == status) {
ret = session.set_query_deadlocked();
} else {
LOG_WARN("unexpected status", K(status));
ret = OB_ERR_UNEXPECTED;
}
session.update_last_active_time();
easy_connection_t* c = session.get_conn();
if (OB_LIKELY(NULL != c)) {
// this function will trigger on_close(), and then free the session
easy_connection_destroy_dispatch(c);
session.set_conn(NULL); // the connection is invalid now
LOG_INFO("kill session successfully",
"proxy",
session.get_proxy_addr(),
"peer",
session.get_peer_addr(),
"real_client_ip",
session.get_client_ip(),
"sessid",
session.get_sessid(),
"proxy_sessid",
session.get_proxy_sessid(),
"trans_id",
session.get_trans_desc().get_trans_id(),
"is_trans_end",
session.get_trans_desc().is_trans_end(),
"query_str",
session.get_current_query_string());
} else {
LOG_WARN("get conn from session info is null",
K(session.get_sessid()),
K(session.get_version()),
"proxy_sessid",
session.get_proxy_sessid(),
K(session.get_magic_num()));
}
return ret;
}
int ObSQLSessionMgr::disconnect_session(ObSQLSessionInfo& session)
// kill idle timeout transaction on this session
int ObSQLSessionMgr::kill_idle_timeout_tx(ObSQLSessionInfo *session)
{
return ObSqlTransControl::kill_idle_timeout_tx(session);
}
// kill deadlock transaction on this session
int ObSQLSessionMgr::kill_deadlock_tx(ObSQLSessionInfo *session)
{
return ObSqlTransControl::kill_deadlock_tx(session);
}
int ObSQLSessionMgr::kill_session(ObSQLSessionInfo &session)
{
int ret = OB_SUCCESS;
// DO NOT change the order of the two guards below, otherwise it may cause deadlock.
int tmp_ret = OB_SUCCESS;
//如果start_stmt/end_stmt卡住,此时需要先唤醒sql线程,然后再设置标记,否则kill session不起作用
if (OB_SUCCESS != (tmp_ret = ObSqlTransControl::kill_query_session(
session, ObSQLSessionState::SESSION_KILLED))) {
LOG_WARN("fail to kill query or session", "ret", tmp_ret, K(session));
}
session.set_session_state(SESSION_KILLED);
// NOTE: 下面两个guard的顺序不可更换,否则有机会形成死锁
ObSQLSessionInfo::LockGuard query_lock_guard(session.get_query_lock());
ObSQLSessionInfo::LockGuard data_lock_guard(session.get_thread_data_lock());
bool has_called_txs_end_trans = false;
bool need_disconnect = false;
session.set_query_start_time(ObTimeUtility::current_time());
if (OB_FAIL(ObSqlTransControl::end_trans(partition_service_, &session, has_called_txs_end_trans))) {
LOG_WARN("fail to rollback transaction",
K(session.get_sessid()),
"proxy_sessid",
session.get_proxy_sessid(),
K(ret),
"trans_id",
session.get_trans_desc().get_trans_id(),
"query_str",
session.get_current_query_string(),
K(has_called_txs_end_trans));
if (session.is_in_transaction()) {
auto tx_desc = session.get_tx_desc();
if (OB_SUCCESS != (tmp_ret = ObSqlTransControl::kill_tx_on_session_killed(&session))) {
LOG_WARN("fail to rollback transaction", K(session.get_sessid()),
"proxy_sessid", session.get_proxy_sessid(),
K(tmp_ret), KPC(tx_desc),
"query_str", session.get_current_query_string(),
K(need_disconnect));
}
}
session.update_last_active_time();
rpc::ObSqlSockDesc &sock_desc = session.get_sock_desc();
if (OB_LIKELY(NULL != sock_desc.sock_desc_)) {
SQL_REQ_OP.disconnect_by_sql_sock_desc(sock_desc);
// this function will trigger on_close(), and then free the session
LOG_INFO("kill session successfully",
"proxy", session.get_proxy_addr(),
"peer", session.get_peer_addr(),
"real_client_ip", session.get_client_ip(),
"sessid", session.get_sessid(),
"proxy_sessid", session.get_proxy_sessid(),
"query_str", session.get_current_query_string());
} else {
LOG_WARN("get conn from session info is null", K(session.get_sessid()),
"proxy_sessid", session.get_proxy_sessid(), K(session.get_magic_num()));
}
return ret;
}
int ObSQLSessionMgr::disconnect_session(ObSQLSessionInfo &session)
{
int ret = OB_SUCCESS;
// NOTE: 下面两个guard的顺序不可更换,否则有机会形成死锁
ObSQLSessionInfo::LockGuard query_lock_guard(session.get_query_lock());
ObSQLSessionInfo::LockGuard data_lock_guard(session.get_thread_data_lock());
bool need_disconnect = false;
session.set_query_start_time(ObTimeUtility::current_time());
// 调用这个函数之前会在ObSMHandler::on_disconnect中调session.set_session_state(SESSION_KILLED),
if (session.is_in_transaction()) {
auto tx_desc = session.get_tx_desc();
if (OB_FAIL(ObSqlTransControl::kill_tx_on_session_disconnect(&session))) {
LOG_WARN("fail to rollback transaction", K(session.get_sessid()),
"proxy_sessid", session.get_proxy_sessid(), K(ret),
KPC(tx_desc),
"query_str", session.get_current_query_string(),
K(need_disconnect));
}
}
session.update_last_active_time();
return ret;
@ -574,13 +618,15 @@ int ObSQLSessionMgr::kill_tenant(const uint64_t tenant_id)
{
int ret = OB_SUCCESS;
KillTenant kt_func(this, tenant_id);
OZ(for_each_session(kt_func));
OZ(sessinfo_map_.clean_tenant(tenant_id));
OZ (for_each_session(kt_func));
OZ (sessinfo_map_.clean_tenant(tenant_id));
return ret;
}
int ObSQLSessionMgr::mark_sessid_used(uint32_t sess_id)
{
//这个接口是为了以前老版本解决proxy sessid复用添加的
//现在的版本(从2.0开始)里不会再有switch_sessid的需求,因此这里不用再提供
UNUSED(sess_id);
return OB_NOT_SUPPORTED;
}
@ -590,14 +636,19 @@ int ObSQLSessionMgr::mark_sessid_unused(uint32_t sess_id)
int ret = OB_SUCCESS;
uint64_t server_id = extract_server_id(sess_id);
if (server_id == 0) {
// see create_sessid(), sess_id with server_id 0 is not allocated from sessid_sequence_.
// 参考:create_sessid方法
// 由于server_id == 0时, 此时的local_seq,是由ATOMIC_FAA(&abnormal_seq, 1)产生,
// 使用ATOMIC_FAA的原因无从考证(原作者的信息描述无任何具体信息),采取保守修改策略
// local_seq未曾从sessid_sequence_队列中获取,所以不需要归还到队列,不然会导致队列溢出的bug
// bug详情: https://work.aone.alibaba-inc.com/issue/30648631
} else if (OB_FAIL(sessid_sequence_.push(reinterpret_cast<void*>(sess_id & MAX_LOCAL_SEQ)))) {
LOG_WARN("fail to push sessid to sessid_sequence_", K(sess_id), K(ret));
}
return ret;
}
bool ObSQLSessionMgr::CheckSessionFunctor::operator()(sql::ObSQLSessionMgr::Key key, ObSQLSessionInfo* sess_info)
bool ObSQLSessionMgr::CheckSessionFunctor::operator()(sql::ObSQLSessionMgr::Key key,
ObSQLSessionInfo *sess_info)
{
int ret = OB_SUCCESS;
UNUSED(key);
@ -609,7 +660,9 @@ bool ObSQLSessionMgr::CheckSessionFunctor::operator()(sql::ObSQLSessionMgr::Key
ret = OB_INVALID_ARGUMENT;
LOG_WARN("session info is not valid", K(ret));
} else {
// DO NOT change the order of the two locks below, otherwise it may cause deadlock.
int callback_retcode = OB_SUCCESS;
transaction::ObITxCallback *commit_cb = NULL;
// NOTE: 下面两个guard的顺序不可更换,否则有机会形成死锁
if (OB_FAIL(sess_info->try_lock_query())) {
if (OB_UNLIKELY(OB_EAGAIN != ret)) {
LOG_WARN("fail to try lock query", K(ret));
@ -630,30 +683,44 @@ bool ObSQLSessionMgr::CheckSessionFunctor::operator()(sql::ObSQLSessionMgr::Key
} else if (OB_FAIL(sess_info->is_timeout(is_timeout))) {
LOG_WARN("fail to check is timeout", K(ret));
} else if (true == is_timeout) {
LOG_INFO("session is timeout, kill this session", K(key.version_), K(key.sessid_));
LOG_INFO("session is timeout, kill this session", K(key.sessid_));
ret = sess_mgr_->kill_session(*sess_info);
} else {
//借助于session遍历的功能,尝试revert session上缓存的schema guard,
//避免长时间持有guard,导致schema mgr的槽位无法释放
sess_info->get_cached_schema_guard_info().try_revert_schema_guard();
// kill transaction which is idle more than configuration 'ob_trx_idle_timeout'
if (OB_FAIL(sess_info->is_trx_idle_timeout(is_timeout))) {
//定期更新租户级别的配置项,避免频繁获取租户级配置项给性能带来的开销
sess_info->refresh_tenant_config();
// send client commit result if txn commit timeout
if (OB_FAIL(sess_info->is_trx_commit_timeout(commit_cb, callback_retcode))) {
LOG_WARN("fail to check transaction commit timeout", K(ret));
} else if (commit_cb) {
LOG_INFO("transaction commit reach timeout", K(callback_retcode), K(key.sessid_));
} else if (OB_FAIL(sess_info->is_trx_idle_timeout(is_timeout))) {
// kill transaction which is idle more than configuration 'ob_trx_idle_timeout'
LOG_WARN("fail to check transaction idle timeout", K(ret));
} else if (true == is_timeout && !sess_info->is_xa_trans()) {
LOG_INFO("transaction is idle timeout, start to rollback", K(key.version_), K(key.sessid_));
} else if (true == is_timeout && !sess_info->associated_xa()) {
LOG_INFO("transaction is idle timeout, start to rollback", K(key.sessid_));
int tmp_ret;
if (OB_SUCCESS != (tmp_ret = sess_mgr_->kill_active_trx(sess_info))) {
LOG_WARN("fail to kill transaction", K(tmp_ret), K(key.version_), K(key.sessid_));
if (OB_SUCCESS != (tmp_ret = sess_mgr_->kill_idle_timeout_tx(sess_info))) {
LOG_WARN("fail to kill transaction", K(ret), K(key.sessid_));
}
}
}
(void)sess_info->unlock_thread_data();
}
(void)sess_info->unlock_query();
// NOTE: must execute callback after release query_lock
if (commit_cb) {
commit_cb->callback(callback_retcode);
}
}
}
return OB_SUCCESS == ret;
}
bool ObSQLSessionMgr::KillTenant::operator()(sql::ObSQLSessionMgr::Key, ObSQLSessionInfo* sess_info)
bool ObSQLSessionMgr::KillTenant::operator() (
sql::ObSQLSessionMgr::Key, ObSQLSessionInfo *sess_info)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(mgr_)) {
@ -670,11 +737,11 @@ bool ObSQLSessionMgr::KillTenant::operator()(sql::ObSQLSessionMgr::Key, ObSQLSes
return OB_SUCCESS == ret;
}
int ObSQLSessionMgr::get_avaiable_local_seq(uint32_t& local_seq)
int ObSQLSessionMgr::get_avaiable_local_seq(uint32_t &local_seq)
{
int ret = OB_SUCCESS;
local_seq = 0;
void* ptr = nullptr;
void *ptr = nullptr;
if (OB_FAIL(sessid_sequence_.pop(ptr))) {
LOG_WARN("fail to find and set first zero bit", K(ret));
} else {
@ -695,18 +762,55 @@ int ObSQLSessionMgr::get_avaiable_local_seq(uint32_t& local_seq)
return ret;
}
int ObSQLSessionMgr::is_need_clear_sessid(const ObSMConnection* conn, bool& is_need)
int ObSQLSessionMgr::is_need_clear_sessid(const ObSMConnection *conn, bool &is_need)
{
int ret = OB_SUCCESS;
is_need = false;
if (OB_ISNULL(conn)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected parameter", K(conn));
} else if (is_server_sessid(conn->sessid_) && ObSMConnection::INITIAL_SESSID != conn->sessid_ &&
0 != extract_server_id(conn->sessid_) && GCTX.server_id_ == extract_server_id(conn->sessid_) &&
conn->is_need_clear_sessid_) {
} else if (is_server_sessid(conn->sessid_)
&& ObSMConnection::INITIAL_SESSID != conn->sessid_
&& 0 != extract_server_id(conn->sessid_)
&& GCTX.server_id_ == extract_server_id(conn->sessid_)
&& conn->is_need_clear_sessid_) {
is_need = true;
} else { /*do nothing*/
} else {/*do nothing*/ }
return ret;
}
int ObSQLSessionMgr::DumpHoldSession::operator()(
common::hash::HashMapPair<uint64_t, ObSQLSessionInfo *> &entry)
{
int ret = common::OB_SUCCESS;
if (OB_ISNULL(entry.second)) {
LOG_INFO("session is null", "sess_ptr", entry.first);
} else {
LOG_INFO("dump session", "sid", entry.second->get_sessid(),
"ref_count", entry.second->get_sess_ref_cnt(),
"state",ObString::make_string(entry.second->get_session_state_str()),
KP(entry.second),
K(entry.first),
"lbt", entry.second->get_sess_bt());
}
return ret;
}
ObSessionGetterGuard::ObSessionGetterGuard(ObSQLSessionMgr &sess_mgr, uint32_t sessid)
: mgr_(sess_mgr), session_(NULL)
{
ret_ = mgr_.get_session(sessid, session_);
if (OB_SUCCESS != ret_) {
LOG_WARN("get session fail", K(ret_), K(sessid));
} else {
NG_TRACE_EXT(session, OB_ID(sid), session_->get_sessid(),
OB_ID(tenant_id), session_->get_priv_tenant_id());
}
}
ObSessionGetterGuard::~ObSessionGetterGuard()
{
if (session_) {
mgr_.revert_session(session_);
}
}