/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX SQL #include "sql/session/ob_sql_session_mgr.h" #include "lib/string/ob_sql_string.h" #include "lib/stat/ob_session_stat.h" #include "lib/mysqlclient/ob_mysql_proxy.h" #include "share/inner_table/ob_inner_table_schema_constants.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 "observer/ob_server_struct.h" using namespace oceanbase::common; using namespace oceanbase::sql; using namespace oceanbase::share; using namespace oceanbase::observer; ObSQLSessionMgr::SessionPool::SessionPool() : session_pool_() { MEMSET(session_array, 0, POOL_CAPACIPY * sizeof(ObSQLSessionInfo*)); } int ObSQLSessionMgr::SessionPool::init() { int ret = OB_SUCCESS; char* session_buf = reinterpret_cast(session_array); OZ(session_pool_.init(POOL_CAPACIPY, session_buf)); return ret; } 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())); } 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())); } } return ret; } 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())); } 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())); } } else { session = NULL; } } return ret; } 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 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; if (block_id < pool_blocks_.count()) { OX(pool_block = pool_blocks_.at(block_id)); } else { 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]))); if (OB_ISNULL(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 ret = OB_SUCCESS; void* buf = NULL; ObLockGuard 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(buf)), 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 ret = OB_SUCCESS; void* buf = NULL; OV(slot_id < SLOT_PER_BLOCK); ObLockGuard 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)); } return ret; } uint64_t ObSQLSessionMgr::SessionPoolMap::get_block_id(uint64_t tenant_id) const { return tenant_id >> BLOCK_ID_SHIFT; } uint64_t ObSQLSessionMgr::SessionPoolMap::get_slot_id(uint64_t tenant_id) const { return tenant_id & SLOT_ID_MASK; } int ObSQLSessionMgr::ValueAlloc::clean_tenant(uint64_t tenant_id) { int ret = OB_SUCCESS; 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)); } 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. while (session_pool->count() > 0) { OX(session_pool->pop_session(tenant_id, session)); if (OB_NOT_NULL(session)) { OX(op_reclaim_free(session)); OX(session = NULL); } } } return ret; } ObSQLSessionInfo* ObSQLSessionMgr::ValueAlloc::alloc_value(uint64_t tenant_id) { int ret = OB_SUCCESS; SessionPool* session_pool = NULL; ObSQLSessionInfo* session = NULL; int64_t alloc_total_count = 0; // 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)); } if (OB_NOT_NULL(session_pool)) { OX(session_pool->pop_session(tenant_id, session)); } if (OB_ISNULL(session)) { OX(session = op_reclaim_alloc(ObSQLSessionInfo)); } else { OX(ATOMIC_FAA(&alloc_from_pool_count_, 1)); } OV(OB_NOT_NULL(session)); OX(session->set_valid(true)); OX(session->set_shadow(true)); 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) { if (OB_NOT_NULL(session)) { int ret = OB_SUCCESS; uint64_t tenant_id = session->get_login_tenant_id(); SessionPool* session_pool = NULL; int64_t free_total_count = 0; 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(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)); } if (OB_NOT_NULL(session)) { OX(op_reclaim_free(session)); OX(session = NULL); } else { 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)); } } } 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; } int ObSQLSessionMgr::init() { int ret = OB_SUCCESS; if (OB_FAIL(sessinfo_map_.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)); } for (uint32_t i = 1; OB_SUCC(ret) && i <= MAX_LOCAL_SEQ; ++i) { if (OB_FAIL(sessid_sequence_.push(reinterpret_cast(i)))) { LOG_WARN("store sessid sequence failed", K(ret), K(i)); } } return ret; } uint64_t ObSQLSessionMgr::extract_server_id(uint32_t sessid) { uint64_t server_id = sessid >> LOCAL_SEQ_LEN; return server_id & MAX_SERVER_ID; } 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(); 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)); } UNUSED(tmp_session); } return ret; } // |<---------------------------------32bit---------------------------->| // 0b 1b 15b 16b // +----+------------------------------+--------------------------------+ // |Mask| Server Id | Local Seq | // +----+------------------------------+--------------------------------+ // // MASK: 1 means session_id is generated by observer, 0 means by proxy. // Server Id: generated by root server, and unique in cluster. // Local Seq: max session number in an observer. // int ObSQLSessionMgr::create_sessid(uint32_t& sessid) { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; sessid = 0; const uint64_t server_id = GCTX.server_id_; uint32_t local_seq = 0; static uint32_t abnormal_seq = 0; if (server_id > MAX_SERVER_ID) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("server id maybe invalid", K(ret), K(server_id)); } else if (0 == server_id) { local_seq = (ATOMIC_FAA(&abnormal_seq, 1) & MAX_LOCAL_SEQ); uint32_t max_local_seq = MAX_LOCAL_SEQ; uint32_t max_server_id = MAX_SERVER_ID; 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*/ } if (OB_SUCC(ret)) { sessid = local_seq | SERVER_SESSID_TAG; // set observer sessid mark sessid |= static_cast(server_id << LOCAL_SEQ_LEN); // set observer // high bit is reserved for server id sessid |= static_cast(1ULL << (LOCAL_SEQ_LEN + SERVER_ID_LEN)); } 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) { 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))) { 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 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)); 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)); } else { LOG_DEBUG("free session successfully in create session", K(err), K(version), K(sessid), K(proxy_sessid)); } } else { tmp_sess->update_last_active_time(); session_info = tmp_sess; } return ret; } 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); if (NULL != sess_info) { 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)); } else if (tenant_id != 0 && sessid != 0 && has_inc) { ObTenantStatEstGuard guard(tenant_id); EVENT_DEC(ACTIVE_SESSIONS); } return ret; } 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))) { LOG_WARN("fail to get session count", K(ret)); } else { LOG_DEBUG("get current session count", K(sess_count)); } } void ObSQLSessionMgr::runTimerTask() { try_check_session(); } // just a wrapper int ObSQLSessionMgr::kill_query(ObSQLSessionInfo& session) { return kill_query(session, partition_service_); } int ObSQLSessionMgr::kill_query(ObSQLSessionInfo& session, storage::ObPartitionService* partition_service) { 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(); } // 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 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))) { 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)); } 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) { int ret = OB_SUCCESS; // 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_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)); } session.update_last_active_time(); return ret; } 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)); return ret; } int ObSQLSessionMgr::mark_sessid_used(uint32_t sess_id) { UNUSED(sess_id); return OB_NOT_SUPPORTED; } 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_. } else if (OB_FAIL(sessid_sequence_.push(reinterpret_cast(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) { int ret = OB_SUCCESS; UNUSED(key); bool is_timeout = false; if (OB_ISNULL(sess_info)) { ret = OB_NOT_INIT; LOG_WARN("session info is NULL"); } else if (false == sess_info->is_valid()) { 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. if (OB_FAIL(sess_info->try_lock_query())) { if (OB_UNLIKELY(OB_EAGAIN != ret)) { LOG_WARN("fail to try lock query", K(ret)); } else { ret = OB_SUCCESS; } } else { if (OB_FAIL(sess_info->try_lock_thread_data())) { if (OB_UNLIKELY(OB_EAGAIN != ret)) { LOG_WARN("fail to try lock thread data", K(ret)); } else { ret = OB_SUCCESS; } } else { if (OB_ISNULL(sess_mgr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session manager point is NULL"); } 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_)); ret = sess_mgr_->kill_session(*sess_info); } else { 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))) { LOG_WARN("fail to check transaction idle timeout", K(ret)); } else if (true == is_timeout) { LOG_INFO("transaction is idle timeout, start to rollback", K(key.version_), 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_)); } } } (void)sess_info->unlock_thread_data(); } (void)sess_info->unlock_query(); } } return OB_SUCCESS == ret; } bool ObSQLSessionMgr::KillTenant::operator()(sql::ObSQLSessionMgr::Key, ObSQLSessionInfo* sess_info) { int ret = OB_SUCCESS; if (OB_ISNULL(mgr_)) { ret = OB_NOT_INIT; LOG_WARN("session mgr_ is NULL", K(mgr_)); } else if (OB_ISNULL(sess_info)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sess info is NULL", K(sess_info)); } else { if (sess_info->get_priv_tenant_id() == tenant_id_) { ret = mgr_->kill_session(*sess_info); } } return OB_SUCCESS == ret; } int ObSQLSessionMgr::get_avaiable_local_seq(uint32_t& local_seq) { int ret = OB_SUCCESS; local_seq = 0; void* ptr = nullptr; if (OB_FAIL(sessid_sequence_.pop(ptr))) { LOG_WARN("fail to find and set first zero bit", K(ret)); } else { int64_t value = reinterpret_cast(ptr); if (value > MAX_LOCAL_SEQ) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected value from bitset", K(ret), K(value), K(ptr)); } else { local_seq = static_cast(value); } } if (OB_ENTRY_NOT_EXIST == ret) { ret = OB_ERR_CON_COUNT_ERROR; int64_t sess_count = 0; (void)get_session_count(sess_count); LOG_WARN("too many connection", "connection_count", sess_count, K(ret)); } return ret; } 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_) { is_need = true; } else { /*do nothing*/ } return ret; }