1902 lines
80 KiB
C++
1902 lines
80 KiB
C++
/**
|
|
* 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_EXE
|
|
|
|
#include "share/ob_schema_status_proxy.h" // ObSchemaStatusProxy
|
|
#include "share/ob_encryption_util.h"
|
|
#include "sql/ob_sql_trans_control.h"
|
|
#include "sql/ob_sql_trans_hook.h"
|
|
#include "sql/engine/ob_physical_plan.h"
|
|
#include "sql/engine/ob_physical_plan_ctx.h"
|
|
#include "sql/parser/parse_malloc.h"
|
|
#include "sql/resolver/ob_stmt.h"
|
|
#include "sql/session/ob_sql_session_info.h"
|
|
#include "sql/ob_sql_trans_util.h"
|
|
#include "sql/ob_end_trans_callback.h"
|
|
#include "lib/oblog/ob_trace_log.h"
|
|
#include "storage/ob_partition_service.h"
|
|
#include "storage/transaction/ob_trans_define.h"
|
|
#include "common/ob_partition_key.h"
|
|
#include "sql/engine/ob_exec_context.h"
|
|
#include "sql/executor/ob_task_spliter.h"
|
|
#include "lib/profile/ob_perf_event.h"
|
|
#include "observer/ob_server_struct.h"
|
|
#include "observer/ob_server.h"
|
|
#include "storage/transaction/ob_weak_read_util.h" //ObWeakReadUtil
|
|
|
|
#if 0
|
|
#define DEBUG_AC_TRANS(exec_ctx) \
|
|
{ \
|
|
ObSQLSessionInfo* __my_session = GET_MY_SESSION(exec_ctx); \
|
|
OB_ASSERT(NULL != __my_session); \
|
|
bool ac = __my_session->get_autocommit(); \
|
|
bool in_trans = __my_session->get_in_transaction(); \
|
|
LOG_INFO("ac & in_trans", K(ac), K(in_trans)); \
|
|
}
|
|
#else
|
|
#define DEBUG_AC_TRANS(exec_ctx)
|
|
#endif
|
|
|
|
#if 0
|
|
#define DEBUG_TRANS_STAGE(stage) \
|
|
if (my_session->get_has_temp_table_flag()) { \
|
|
LOG_WARN("TMP_TABLE " stage, K(my_session->get_trans_desc())); \
|
|
}
|
|
#else
|
|
#define DEBUG_TRANS_STAGE(stage)
|
|
#endif
|
|
|
|
namespace oceanbase {
|
|
using namespace common;
|
|
using namespace transaction;
|
|
using namespace share;
|
|
using namespace share::schema;
|
|
namespace sql {
|
|
int ObSqlTransControl::on_plan_start(ObExecContext& exec_ctx, bool is_remote /* = false*/)
|
|
{
|
|
DEBUG_AC_TRANS(exec_ctx);
|
|
int ret = OB_SUCCESS;
|
|
bool ac = true;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
ObPhysicalPlanCtx* plan_ctx = GET_PHY_PLAN_CTX(exec_ctx);
|
|
if (OB_ISNULL(my_session) || OB_ISNULL(plan_ctx) || OB_ISNULL(plan_ctx->get_phy_plan())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("session ptr or plan ctx or plan_ctx->get_phy_plan is null", K(ret), K(my_session), K(plan_ctx));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(my_session->get_autocommit(ac))) {
|
|
LOG_WARN("fail to get autocommit", K(ret));
|
|
} else if (stmt::T_SELECT == plan_ctx->get_phy_plan()->get_stmt_type() &&
|
|
!plan_ctx->get_phy_plan()->has_for_update() &&
|
|
(!my_session->get_trans_desc().is_valid() || my_session->get_trans_desc().is_trans_end()) &&
|
|
my_session->is_support_external_consistent() && GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_2260 &&
|
|
!(my_session->is_in_transaction() && my_session->get_trans_desc().is_valid() &&
|
|
my_session->get_trans_desc().is_xa_local_trans()) &&
|
|
(share::is_oracle_mode() || my_session->get_local_autocommit())) {
|
|
OZ(start_standalone_stmt(exec_ctx, *my_session, *plan_ctx, is_remote));
|
|
} else {
|
|
bool in_trans = my_session->get_in_transaction();
|
|
if (ObSqlTransUtil::plan_can_start_trans(ac, in_trans)) {
|
|
ret = implicit_start_trans(exec_ctx, is_remote);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*int ObSqlTransControl::on_plan_end(ObExecContext &exec_ctx,
|
|
bool is_rollback,
|
|
ObExclusiveEndTransCallback &callback)
|
|
{
|
|
DEBUG_AC_TRANS(exec_ctx);
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo *my_session = GET_MY_SESSION(exec_ctx);
|
|
bool ac = true;
|
|
if (OB_ISNULL(my_session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("session ptr is null", K(ret));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
//session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed", K(ret), K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()), "proxy_sessid", my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(my_session->get_autocommit(ac))) {
|
|
LOG_WARN("fail to get autocommit", K(ret));
|
|
} else {
|
|
bool in_trans = my_session->get_in_transaction();
|
|
if (ObSqlTransUtil::plan_can_end_trans(ac, in_trans)) {
|
|
ret = implicit_end_trans(exec_ctx, is_rollback, callback);
|
|
}
|
|
}
|
|
return ret;
|
|
}*/
|
|
|
|
int ObSqlTransControl::explicit_start_trans(ObExecContext& ctx, const bool read_only)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObPhysicalPlanCtx* plan_ctx = GET_PHY_PLAN_CTX(ctx);
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(ctx);
|
|
ObTaskExecutorCtx& task_exec_ctx = ctx.get_task_exec_ctx();
|
|
if (OB_ISNULL(plan_ctx) || OB_ISNULL(my_session) || OB_UNLIKELY(!task_exec_ctx.min_cluster_version_is_valid())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("invalid param", K(ret), K(plan_ctx), K(my_session), K(task_exec_ctx.get_min_cluster_version()));
|
|
} else {
|
|
int32_t access_mode = read_only ? ObTransAccessMode::READ_ONLY : ObTransAccessMode::READ_WRITE;
|
|
int32_t tx_isolation = my_session->get_tx_isolation();
|
|
ObStartTransParam& start_trans_param = plan_ctx->get_start_trans_param();
|
|
start_trans_param.set_access_mode(access_mode);
|
|
start_trans_param.set_isolation(tx_isolation);
|
|
start_trans_param.set_type(my_session->get_trans_type());
|
|
start_trans_param.set_cluster_version(task_exec_ctx.get_min_cluster_version());
|
|
start_trans_param.set_inner_trans(my_session->is_inner());
|
|
NG_TRACE_EXT(start_trans, OB_ID(read_only), read_only, OB_ID(access_mode), access_mode);
|
|
if (OB_FAIL(ObSqlTransControl::explicit_start_trans(ctx, start_trans_param))) {
|
|
LOG_WARN("fail start trans", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::explicit_start_trans(ObExecContext& exec_ctx, transaction::ObStartTransParam& start_trans_param)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
if (OB_ISNULL(my_session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("session ptr is null", K(ret));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else {
|
|
if (false == my_session->get_in_transaction()) {
|
|
if (OB_FAIL(start_trans(exec_ctx, start_trans_param))) {
|
|
LOG_WARN("fail start explicit trans", K(ret));
|
|
} else {
|
|
bool is_read_only =
|
|
(start_trans_param.get_access_mode() == transaction::ObTransAccessMode::READ_ONLY) ? true : false;
|
|
my_session->set_tx_read_only(is_read_only);
|
|
my_session->set_in_transaction(true);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::implicit_start_trans(ObExecContext& exec_ctx, bool is_remote /* = false*/)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObPhysicalPlanCtx* plan_ctx = GET_PHY_PLAN_CTX(exec_ctx);
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
ObTaskExecutorCtx& task_exec_ctx = exec_ctx.get_task_exec_ctx();
|
|
bool ac = true;
|
|
if (OB_ISNULL(plan_ctx) || OB_ISNULL(my_session) || OB_ISNULL(plan_ctx->get_phy_plan())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("can't get plan_ctx or session or phy_plan", K(ret), K(plan_ctx), K(my_session));
|
|
} else if (OB_UNLIKELY(!is_remote && !task_exec_ctx.min_cluster_version_is_valid())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("is not remote start trans, but task_exec_ctx.get_min_cluster_version() is invalid",
|
|
K(ret),
|
|
K(task_exec_ctx.get_min_cluster_version()));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(my_session->get_autocommit(ac))) {
|
|
LOG_WARN("fail to get autocommit", K(ret));
|
|
} else {
|
|
bool in_trans = my_session->get_in_transaction();
|
|
bool tx_read_only = my_session->get_tx_read_only();
|
|
int32_t tx_isolation = my_session->get_tx_isolation();
|
|
transaction::ObStartTransParam& start_trans_param = plan_ctx->get_start_trans_param();
|
|
if (true == ac && false == in_trans && stmt::T_SELECT == plan_ctx->get_phy_plan()->get_stmt_type() &&
|
|
!plan_ctx->get_phy_plan()->has_for_update()) {
|
|
start_trans_param.set_access_mode(transaction::ObTransAccessMode::READ_ONLY);
|
|
} else if (true == tx_read_only) {
|
|
start_trans_param.set_access_mode(transaction::ObTransAccessMode::READ_ONLY);
|
|
} else {
|
|
start_trans_param.set_access_mode(transaction::ObTransAccessMode::READ_WRITE);
|
|
}
|
|
start_trans_param.set_type(my_session->get_trans_type());
|
|
start_trans_param.set_isolation(tx_isolation);
|
|
start_trans_param.set_autocommit(ac && !in_trans);
|
|
if (task_exec_ctx.min_cluster_version_is_valid()) {
|
|
start_trans_param.set_cluster_version(task_exec_ctx.get_min_cluster_version());
|
|
} else {
|
|
start_trans_param.set_cluster_version(GET_MIN_CLUSTER_VERSION());
|
|
}
|
|
start_trans_param.set_inner_trans(my_session->is_inner());
|
|
if (OB_FAIL(start_trans(exec_ctx, start_trans_param, is_remote))) {
|
|
LOG_WARN("fail start trans", K(ret));
|
|
}
|
|
if (OB_SUCC(ret) && false == ac) {
|
|
my_session->set_in_transaction(true);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::start_trans(
|
|
ObExecContext& exec_ctx, transaction::ObStartTransParam& start_trans_param, bool is_remote /* = false*/)
|
|
{
|
|
DEBUG_AC_TRANS(exec_ctx);
|
|
int ret = OB_SUCCESS;
|
|
int64_t org_cluster_id = OB_INVALID_ORG_CLUSTER_ID;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
ObPhysicalPlanCtx* plan_ctx = exec_ctx.get_physical_plan_ctx();
|
|
storage::ObPartitionService* ps = NULL;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(plan_ctx) ||
|
|
OB_ISNULL(ps = executor_ctx->get_partition_service())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("null ptr", K(ret), K(executor_ctx), K(my_session), K(plan_ctx), K(ps));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(my_session->get_ob_org_cluster_id(org_cluster_id))) {
|
|
if (OB_LIKELY(is_remote && OB_ENTRY_NOT_EXIST == ret)) {
|
|
LOG_WARN("start trans in remote, ob_org_cluster_id is not serilized to the remote server, "
|
|
"maybe server version is different, then ignore it, "
|
|
"use default cluster id and set ret to OB_SUCCESS");
|
|
ret = OB_SUCCESS;
|
|
org_cluster_id = ObServerConfig::get_instance().cluster_id;
|
|
} else {
|
|
LOG_WARN("fail to get ob_org_cluster_id", K(ret));
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else {
|
|
if (OB_INVALID_ORG_CLUSTER_ID == org_cluster_id || OB_INVALID_CLUSTER_ID == org_cluster_id) {
|
|
org_cluster_id = ObServerConfig::get_instance().cluster_id;
|
|
if (OB_UNLIKELY(org_cluster_id < OB_MIN_CLUSTER_ID || org_cluster_id > OB_MAX_CLUSTER_ID)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("org_cluster_id is set to cluster_id, but it is out of range",
|
|
K(ret),
|
|
K(org_cluster_id),
|
|
K(OB_MIN_CLUSTER_ID),
|
|
K(OB_MAX_CLUSTER_ID));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
my_session->get_trans_result().reset();
|
|
transaction::ObTransDesc& trans_desc = my_session->get_trans_desc();
|
|
const uint64_t tenant_id = my_session->get_effective_tenant_id();
|
|
int64_t trans_timeout_ts = 0;
|
|
if (OB_FAIL(get_trans_timeout_ts(*my_session, trans_timeout_ts))) {
|
|
LOG_ERROR("fail to get trans timeout ts", K(ret));
|
|
} else if (OB_FAIL(ps->start_trans(tenant_id,
|
|
static_cast<uint64_t>(org_cluster_id),
|
|
start_trans_param,
|
|
trans_timeout_ts,
|
|
my_session->get_sessid(),
|
|
my_session->get_proxy_sessid(),
|
|
trans_desc))) {
|
|
LOG_WARN("fail start trans", K(ret));
|
|
}
|
|
DEBUG_TRANS_STAGE("start_trans");
|
|
NG_TRACE_EXT(start_trans,
|
|
OB_ID(trans_id),
|
|
trans_desc.get_trans_id(),
|
|
OB_ID(timeout),
|
|
trans_timeout_ts,
|
|
OB_ID(start_time),
|
|
my_session->get_query_start_time());
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::implicit_end_trans(
|
|
ObExecContext& exec_ctx, const bool is_rollback, ObExclusiveEndTransCallback& callback)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const bool is_explicit = false;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
if (OB_ISNULL(my_session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("session ptr is null, won't call end trans!!!", K(ret));
|
|
} else if (OB_FAIL(end_trans(exec_ctx, is_rollback, is_explicit, callback))) {
|
|
LOG_WARN("fail to end trans", K(ret), K(is_rollback));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::explicit_end_trans(ObExecContext& exec_ctx, const bool is_rollback)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (exec_ctx.is_end_trans_async()) {
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
if (OB_ISNULL(my_session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("session ptr is null", K(ret));
|
|
} else {
|
|
ObEndTransAsyncCallback& call_back = my_session->get_end_trans_cb();
|
|
ret = explicit_end_trans(exec_ctx, is_rollback, call_back);
|
|
}
|
|
} else {
|
|
ObEndTransSyncCallback call_back;
|
|
ret = explicit_end_trans(exec_ctx, is_rollback, call_back);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::explicit_end_trans(
|
|
ObExecContext& exec_ctx, const bool is_rollback, ObEndTransSyncCallback& callback)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const bool is_explicit = true;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
if (OB_ISNULL(my_session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("session ptr is null", K(ret));
|
|
} else {
|
|
if (true == my_session->get_in_transaction()) {
|
|
if (OB_FAIL(callback.init(&(my_session->get_trans_desc()), my_session))) {
|
|
LOG_ERROR("fail init callback", K(ret), K(my_session->get_trans_desc()));
|
|
// implicit commit, no rollback
|
|
} else {
|
|
int wait_ret = OB_SUCCESS;
|
|
if (OB_FAIL(end_trans(exec_ctx, is_rollback, is_explicit, callback))) {
|
|
LOG_WARN("fail end explicit trans", K(is_rollback), K(ret));
|
|
}
|
|
if (OB_UNLIKELY(OB_SUCCESS != (wait_ret = callback.wait()))) {
|
|
LOG_WARN("sync end trans callback return an error!",
|
|
K(ret),
|
|
K(wait_ret),
|
|
K(is_rollback),
|
|
K(my_session->get_trans_desc()));
|
|
}
|
|
ret = OB_SUCCESS != ret ? ret : wait_ret;
|
|
}
|
|
} else {
|
|
my_session->reset_tx_variable();
|
|
my_session->set_early_lock_release(false);
|
|
exec_ctx.set_need_disconnect(false);
|
|
my_session->get_trans_desc().get_standalone_stmt_desc().reset();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::explicit_end_trans(
|
|
ObExecContext& exec_ctx, const bool is_rollback, ObEndTransAsyncCallback& callback)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const bool is_explicit = true;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
if (OB_ISNULL(my_session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("session is NULL, won't call end trans!!!", K(ret), KP(my_session));
|
|
} else {
|
|
if (true == my_session->get_in_transaction()) {
|
|
// other fields will be and should be (re)set correctly in call back routine.
|
|
if (OB_FAIL(end_trans(exec_ctx, is_rollback, is_explicit, callback))) {
|
|
LOG_WARN("fail end explicit trans", K(is_rollback), K(ret));
|
|
}
|
|
exec_ctx.get_trans_state().set_end_trans_executed(OB_SUCC(ret));
|
|
} else {
|
|
my_session->reset_first_stmt_type();
|
|
my_session->reset_tx_variable();
|
|
my_session->set_early_lock_release(false);
|
|
exec_ctx.set_need_disconnect(false);
|
|
my_session->get_trans_desc().get_standalone_stmt_desc().reset();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::kill_query_session(
|
|
storage::ObPartitionService* ps, ObSQLSessionInfo& session, const ObSQLSessionState& status)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (OB_ISNULL(ps)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_ERROR("invalid argument for point", K(ret), K(ps), K(session));
|
|
} else if (true == session.get_in_transaction()) {
|
|
const transaction::ObTransDesc& trans_desc = session.get_trans_desc();
|
|
if (OB_FAIL(ps->kill_query_session(trans_desc, status))) {
|
|
LOG_WARN("fail kill query or session error", K(ret), K(trans_desc));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// may concurrency with user-query, need blocking query:
|
|
// - acquire session.query_lock by caller
|
|
// - only rollback transaction in Transaction-Layer, don't touch SQL-Layer state
|
|
int ObSqlTransControl::kill_active_trx(storage::ObPartitionService* ps, ObSQLSessionInfo* session)
|
|
{
|
|
LOG_DEBUG("kill active trx start", "session_id", session->get_sessid(), K(*session));
|
|
int ret = OB_SUCCESS;
|
|
transaction::ObTransDesc& trans_desc = session->get_trans_desc();
|
|
if (trans_desc.is_valid() && !trans_desc.is_trans_end() && !trans_desc.is_trx_idle_timeout()) {
|
|
if (OB_FAIL(ps->internal_kill_trans(trans_desc))) {
|
|
LOG_WARN("kill active trx by end_trans fail.",
|
|
K(ret),
|
|
"session_id",
|
|
session->get_sessid(),
|
|
K(*session),
|
|
K(trans_desc));
|
|
} else {
|
|
LOG_INFO("kill active trx succeed, need user rollback in next stmt",
|
|
"session_id",
|
|
session->get_sessid(),
|
|
K(*session),
|
|
K(trans_desc));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::end_trans(
|
|
storage::ObPartitionService* ps, ObSQLSessionInfo* session, bool& has_called_txs_end_trans)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int wait_ret = OB_SUCCESS;
|
|
int hook_ret = OB_SUCCESS;
|
|
has_called_txs_end_trans = false;
|
|
if (OB_ISNULL(ps) || OB_ISNULL(session)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_ERROR("invalid argument for point", K(ret), K(ps), K(session));
|
|
} else if (true == session->get_in_transaction()) {
|
|
transaction::ObTransDesc& trans_desc = session->get_trans_desc();
|
|
int64_t timeout = 0;
|
|
ObEndTransSyncCallback callback;
|
|
if (OB_FAIL(get_stmt_timeout_ts(*session, timeout))) {
|
|
LOG_ERROR("fail to get stmt timeout ts", K(ret));
|
|
} else if (OB_FAIL(callback.init(&trans_desc, session))) {
|
|
LOG_ERROR("fail init callback", K(ret), K(trans_desc));
|
|
} else {
|
|
callback.set_is_need_rollback(true);
|
|
callback.set_end_trans_type(ObExclusiveEndTransCallback::END_TRANS_TYPE_IMPLICIT);
|
|
callback.handout();
|
|
if (OB_FAIL(ps->end_trans(true, trans_desc, callback, timeout))) {
|
|
LOG_WARN("fail end trans when session terminate", K(ret), K(trans_desc), K(timeout));
|
|
}
|
|
session->reset_first_stmt_type();
|
|
if (OB_UNLIKELY(OB_SUCCESS != (wait_ret = callback.wait()))) {
|
|
LOG_WARN("sync end trans callback return an error!", K(ret), K(wait_ret), K(trans_desc), K(timeout));
|
|
}
|
|
ret = OB_SUCCESS != ret ? ret : wait_ret;
|
|
|
|
if (callback.is_txs_end_trans_called()) {
|
|
has_called_txs_end_trans = true;
|
|
} else {
|
|
has_called_txs_end_trans = false;
|
|
LOG_WARN("fail before trans service end trans, may disconnct", K(ret), K(session->get_sessid()));
|
|
if (OB_UNLIKELY(OB_SUCCESS == ret)) {
|
|
LOG_ERROR("callback before trans service end trans, but ret is OB_SUCCESS, it is BUG!!!",
|
|
K(callback.is_txs_end_trans_called()));
|
|
}
|
|
}
|
|
|
|
session->reset_tx_variable();
|
|
session->set_early_lock_release(false);
|
|
}
|
|
} else {
|
|
session->reset_first_stmt_type();
|
|
has_called_txs_end_trans = true;
|
|
}
|
|
return (OB_SUCCESS != ret) ? ret : hook_ret;
|
|
}
|
|
|
|
int ObSqlTransControl::end_trans(
|
|
ObExecContext& exec_ctx, const bool is_rollback, const bool is_explicit, ObExclusiveEndTransCallback& callback)
|
|
{
|
|
DEBUG_AC_TRANS(exec_ctx);
|
|
int ret = OB_SUCCESS;
|
|
int hook_ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
ObPhysicalPlanCtx* plan_ctx = GET_PHY_PLAN_CTX(exec_ctx);
|
|
ObEndTransCallbackType callback_type = callback.get_callback_type();
|
|
storage::ObPartitionService* ps = NULL;
|
|
int32_t xa_trans_state = transaction::ObXATransState::NON_EXISTING;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(plan_ctx) ||
|
|
OB_ISNULL(ps = executor_ctx->get_partition_service())) {
|
|
LOG_ERROR("null ptr, won't call end trans!!!", K(executor_ctx), K(my_session), K(plan_ctx), K(ps));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else {
|
|
transaction::ObTransDesc& trans_desc = my_session->get_trans_desc();
|
|
if (trans_desc.is_xa_local_trans() && !is_explicit) {
|
|
if (OB_FAIL(ps->get_xa_trans_state(xa_trans_state, trans_desc))) {
|
|
LOG_WARN("failed get_xa_trans_state", K(ret));
|
|
} else if (transaction::ObXATransState::NON_EXISTING != xa_trans_state) {
|
|
ret = OB_TRANS_XA_RMFAIL;
|
|
// LOG_USER_ERROR(OB_TRANS_XA_RMFAIL, ObXATransState::to_string(xa_trans_state));
|
|
LOG_WARN("invalid xa state", K(ret), K(xa_trans_state));
|
|
callback.set_is_need_rollback(is_rollback);
|
|
callback.set_end_trans_type(ObExclusiveEndTransCallback::END_TRANS_TYPE_IMPLICIT);
|
|
callback.handout();
|
|
callback.callback(ret);
|
|
}
|
|
} else {
|
|
int64_t timeout = get_stmt_timeout_ts(*plan_ctx);
|
|
callback.set_is_need_rollback(is_rollback);
|
|
if (is_explicit) {
|
|
callback.set_end_trans_type(ObExclusiveEndTransCallback::END_TRANS_TYPE_EXPLICIT);
|
|
} else {
|
|
callback.set_end_trans_type(ObExclusiveEndTransCallback::END_TRANS_TYPE_IMPLICIT);
|
|
}
|
|
callback.handout();
|
|
if (ASYNC_CALLBACK_TYPE == callback_type && OB_FAIL(inc_session_ref(my_session))) {
|
|
LOG_WARN("fail to inc session ref", K(ret));
|
|
} else if (OB_FAIL(ps->end_trans(is_rollback, trans_desc, callback, timeout))) {
|
|
LOG_WARN("fail end trans", K(ret), K(callback_type));
|
|
}
|
|
DEBUG_TRANS_STAGE("end_trans");
|
|
my_session->reset_first_stmt_type();
|
|
if (callback.get_callback_type() != ASYNC_CALLBACK_TYPE) {
|
|
my_session->reset_tx_variable();
|
|
my_session->set_early_lock_release(false);
|
|
}
|
|
// my_session->get_trans_desc().reset();
|
|
DEBUG_AC_TRANS(exec_ctx);
|
|
if (ASYNC_CALLBACK_TYPE == callback_type) {
|
|
exec_ctx.set_need_disconnect(false);
|
|
} else if (!callback.is_txs_end_trans_called()) {
|
|
exec_ctx.set_need_disconnect(true);
|
|
LOG_WARN("fail before trans service end trans, disconnct", K(ret), K(my_session->get_sessid()));
|
|
if (OB_UNLIKELY(OB_SUCCESS == ret)) {
|
|
LOG_ERROR("callback before trans service end trans, but ret is OB_SUCCESS, it is BUG!!!",
|
|
K(is_explicit),
|
|
K(callback.is_txs_end_trans_called()));
|
|
}
|
|
} else {
|
|
bool is_need_disconnect = false;
|
|
ObSQLUtils::check_if_need_disconnect_after_end_trans(ret, is_rollback, is_explicit, is_need_disconnect);
|
|
exec_ctx.set_need_disconnect(is_need_disconnect);
|
|
}
|
|
}
|
|
}
|
|
return (OB_SUCCESS != ret) ? ret : hook_ret;
|
|
}
|
|
|
|
bool ObSqlTransControl::is_weak_consistency_level(const ObConsistencyLevel& consistency_level)
|
|
{
|
|
return (WEAK == consistency_level || FROZEN == consistency_level);
|
|
}
|
|
|
|
int ObSqlTransControl::decide_trans_read_interface_specs(const char* module, const ObSQLSessionInfo& session,
|
|
const stmt::StmtType& stmt_type, const stmt::StmtType& literal_stmt_type, const bool& is_contain_select_for_update,
|
|
const bool& is_contain_inner_table, const ObConsistencyLevel& sql_consistency_level,
|
|
const bool need_consistent_snapshot, int32_t& trans_consistency_level, int32_t& trans_consistency_type,
|
|
int32_t& read_snapshot_type)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const char* err_msg = "";
|
|
ObConsistencyLevelAdaptor consistency_level_adaptor(sql_consistency_level);
|
|
const bool is_standby_cluster = GCTX.is_standby_cluster();
|
|
const bool is_inner_sql = session.is_inner();
|
|
const bool is_from_show_stmt = (literal_stmt_type != stmt::T_NONE);
|
|
const bool is_build_index_stmt = (stmt::T_BUILD_INDEX_SSTABLE == stmt_type);
|
|
uint64_t tenant_id = session.get_effective_tenant_id();
|
|
const bool stmt_spec_snapshot_version_is_valid = session.has_valid_read_snapshot_version();
|
|
int32_t isolation = session.is_in_transaction() ? session.get_trans_desc().get_trans_param().get_isolation()
|
|
: session.get_tx_isolation();
|
|
const bool is_serializable_trans =
|
|
(ObTransIsolation::SERIALIZABLE == isolation || ObTransIsolation::REPEATABLE_READ == isolation);
|
|
|
|
trans_consistency_level = (int32_t)consistency_level_adaptor.get_consistency();
|
|
trans_consistency_type = ObTransConsistencyType::CURRENT_READ;
|
|
read_snapshot_type = ObTransReadSnapshotType::STATEMENT_SNAPSHOT;
|
|
|
|
if (OB_UNLIKELY(!ObTransConsistencyLevel::is_valid(trans_consistency_level))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
err_msg = "invalid trans consisntency level";
|
|
} else if (is_build_index_stmt) {
|
|
trans_consistency_level = ObTransConsistencyLevel::WEAK;
|
|
trans_consistency_type = ObTransConsistencyType::BOUNDED_STALENESS_READ;
|
|
} else if (is_from_show_stmt) {
|
|
if (!is_standby_cluster || OB_SYS_TENANT_ID == tenant_id) {
|
|
trans_consistency_level = ObTransConsistencyLevel::STRONG;
|
|
trans_consistency_type = ObTransConsistencyType::CURRENT_READ;
|
|
} else {
|
|
trans_consistency_level = ObTransConsistencyLevel::WEAK;
|
|
trans_consistency_type = ObTransConsistencyType::BOUNDED_STALENESS_READ;
|
|
}
|
|
} else if (stmt::T_SELECT != stmt_type || (stmt::T_SELECT == stmt_type && is_contain_select_for_update)) {
|
|
trans_consistency_level = ObTransConsistencyLevel::STRONG;
|
|
trans_consistency_type = ObTransConsistencyType::CURRENT_READ;
|
|
} else if (is_contain_inner_table) {
|
|
if (is_inner_sql) {
|
|
} else {
|
|
if (!is_standby_cluster || OB_SYS_TENANT_ID == tenant_id) {
|
|
trans_consistency_level = ObTransConsistencyLevel::STRONG;
|
|
} else {
|
|
}
|
|
}
|
|
if (ObTransConsistencyLevel::STRONG == trans_consistency_level) {
|
|
trans_consistency_type = ObTransConsistencyType::CURRENT_READ;
|
|
} else {
|
|
trans_consistency_type = ObTransConsistencyType::BOUNDED_STALENESS_READ;
|
|
}
|
|
} else {
|
|
int32_t cur_stmt_consistency_type = ObTransConsistencyType::UNKNOWN;
|
|
const int32_t first_stmt_consistency_type = session.get_trans_consistency_type();
|
|
|
|
if (ObTransConsistencyLevel::STRONG == trans_consistency_level) {
|
|
cur_stmt_consistency_type = ObTransConsistencyType::CURRENT_READ;
|
|
} else {
|
|
cur_stmt_consistency_type = ObTransConsistencyType::BOUNDED_STALENESS_READ;
|
|
}
|
|
|
|
if (ObTransConsistencyType::UNKNOWN == first_stmt_consistency_type) {
|
|
trans_consistency_type = cur_stmt_consistency_type;
|
|
} else {
|
|
trans_consistency_type = first_stmt_consistency_type;
|
|
if (OB_UNLIKELY(cur_stmt_consistency_type != first_stmt_consistency_type)) {
|
|
err_msg = "current statement consistency type is different from the first statement";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCCESS == ret) {
|
|
if (is_serializable_trans) {
|
|
read_snapshot_type = ObTransReadSnapshotType::TRANSACTION_SNAPSHOT;
|
|
} else {
|
|
if (is_contain_inner_table || !need_consistent_snapshot) {
|
|
read_snapshot_type = ObTransReadSnapshotType::PARTICIPANT_SNAPSHOT;
|
|
} else {
|
|
read_snapshot_type = ObTransReadSnapshotType::STATEMENT_SNAPSHOT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret) || OB_UNLIKELY(0 != STRCMP(err_msg, ""))) {
|
|
LOG_WARN(err_msg,
|
|
K(ret),
|
|
K(tenant_id),
|
|
K(module),
|
|
K(trans_consistency_type),
|
|
K(read_snapshot_type),
|
|
K(trans_consistency_level),
|
|
K(sql_consistency_level),
|
|
K(is_standby_cluster),
|
|
K(is_inner_sql),
|
|
K(is_from_show_stmt),
|
|
K(is_build_index_stmt),
|
|
K(is_serializable_trans),
|
|
K(is_contain_inner_table),
|
|
K(stmt_spec_snapshot_version_is_valid),
|
|
K(is_contain_select_for_update),
|
|
K(stmt_type),
|
|
K(literal_stmt_type),
|
|
K(session),
|
|
"trans_desc",
|
|
session.get_trans_desc());
|
|
} else {
|
|
LOG_DEBUG("decide_trans_read_interface_specs",
|
|
K(ret),
|
|
K(tenant_id),
|
|
K(module),
|
|
K(trans_consistency_type),
|
|
K(read_snapshot_type),
|
|
K(trans_consistency_level),
|
|
K(sql_consistency_level),
|
|
K(is_standby_cluster),
|
|
K(is_inner_sql),
|
|
K(is_from_show_stmt),
|
|
K(is_build_index_stmt),
|
|
K(is_serializable_trans),
|
|
K(is_contain_inner_table),
|
|
K(stmt_spec_snapshot_version_is_valid),
|
|
K(is_contain_select_for_update),
|
|
K(stmt_type),
|
|
K(literal_stmt_type),
|
|
K(session),
|
|
"trans_desc",
|
|
session.get_trans_desc());
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool ObSqlTransControl::check_fast_select_read_uncommited(
|
|
transaction::ObTransDesc& trans_desc, const common::ObPartitionLeaderArray& pla)
|
|
{
|
|
bool read_uncommited = false;
|
|
const common::ObPartitionArray& participants = trans_desc.get_participants();
|
|
for (int i = 0; !read_uncommited && i < pla.get_partitions().count(); ++i) {
|
|
const ObPartitionKey& pkey = pla.get_partitions().at(i);
|
|
for (int j = 0; j < participants.count(); ++j) {
|
|
if (pkey == participants.at(j)) {
|
|
read_uncommited = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return read_uncommited;
|
|
}
|
|
|
|
int ObSqlTransControl::update_safe_weak_read_snapshot(
|
|
bool is_bounded_staleness_read, ObSQLSessionInfo& session_info, int snapshot_type, int64_t snapshot_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (is_bounded_staleness_read) {
|
|
if (ObWeakReadUtil::enable_monotonic_weak_read(session_info.get_effective_tenant_id()) &&
|
|
!session_info.has_valid_read_snapshot_version() &&
|
|
ObTransReadSnapshotType::STATEMENT_SNAPSHOT == snapshot_type) {
|
|
int64_t cur_stmt_snapshot_version = snapshot_version;
|
|
if (OB_UNLIKELY(cur_stmt_snapshot_version <= 0)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
TRANS_LOG(WARN,
|
|
"statement snapshot version is invalid, unexpected error",
|
|
K(ret),
|
|
K(cur_stmt_snapshot_version),
|
|
K(session_info),
|
|
K(session_info.get_trans_desc()));
|
|
} else if (OB_FAIL(session_info.update_safe_weak_read_snapshot(session_info.get_effective_tenant_id(),
|
|
cur_stmt_snapshot_version,
|
|
ObBasicSessionInfo::LAST_STMT))) {
|
|
TRANS_LOG(WARN,
|
|
"update safe weak read snapshot version error",
|
|
K(ret),
|
|
K(snapshot_type),
|
|
K(snapshot_version),
|
|
K(session_info),
|
|
K(session_info.get_trans_desc()));
|
|
} else if (REACH_TIME_INTERVAL(10 * 1000 * 1000)) {
|
|
LOG_INFO("update safe weak read snapshot version success",
|
|
K(ret),
|
|
"snapshot_version",
|
|
snapshot_version,
|
|
"session",
|
|
session_info,
|
|
K(session_info.get_trans_desc()));
|
|
} else {
|
|
// do nothing
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::start_stmt(
|
|
ObExecContext& exec_ctx, const common::ObPartitionLeaderArray& pla, bool is_remote /* = false*/)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
const ObPhysicalPlanCtx* phy_plan_ctx = GET_PHY_PLAN_CTX(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
const ObPhysicalPlan* phy_plan = NULL;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(phy_plan_ctx) ||
|
|
OB_ISNULL(ps = executor_ctx->get_partition_service()) || OB_ISNULL(phy_plan = phy_plan_ctx->get_phy_plan())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("null ptr", K(ret), K(executor_ctx), K(my_session), K(phy_plan_ctx), K(ps), K(phy_plan));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(my_session->set_cur_stmt_tables(pla.get_partitions(), phy_plan->get_stmt_type()))) {
|
|
LOG_WARN("set cur stmt tables fail", K(ret));
|
|
} else if (/*my_session->reuse_cur_sql_no() ||*/ my_session->is_standalone_stmt()) {
|
|
// skip start_stmt.
|
|
} else if (my_session->is_nested_session()) {
|
|
ObTransDesc& trans_desc = my_session->get_trans_desc();
|
|
TransResult& trans_result = my_session->get_trans_result();
|
|
if (OB_FAIL(ps->start_nested_stmt(trans_desc))) {
|
|
LOG_WARN("start nested stmt fail", K(ret), K(trans_desc));
|
|
} else if (OB_FAIL(trans_result.set_max_sql_no(trans_desc.get_sql_no()))) {
|
|
LOG_WARN("refresh max sql no fail", K(ret), K(trans_result), K(trans_desc));
|
|
}
|
|
/*
|
|
int64_t nested_count = my_session->get_nested_count();
|
|
int64_t max_sql_no = trans_result.get_max_sql_no();
|
|
const ObString nested_stmt = my_session->get_current_query_string();
|
|
LOG_INFO("start_nested_stmt", K(nested_count), K(nested_stmt), K(max_sql_no));
|
|
*/
|
|
} else if (my_session->is_fast_select()) {
|
|
if (pla.count() > 0) {
|
|
ObPartitionLeaderArray out_pla;
|
|
OZ(change_pla_info_(executor_ctx->get_table_locations(), pla, out_pla));
|
|
OX(my_session->set_read_uncommited(check_fast_select_read_uncommited(my_session->get_trans_desc(), out_pla)));
|
|
}
|
|
} else if (OB_UNLIKELY(ObSQLSessionInfo::INVALID_TYPE == my_session->get_session_type())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("session type is not init", K(my_session), K(ret));
|
|
} else if (OB_UNLIKELY(INVALID_CONSISTENCY == phy_plan_ctx->get_consistency_level())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("sql consistency level is invalid", K(ret), K(phy_plan_ctx->get_consistency_level()));
|
|
} else {
|
|
ObStmtParam stmt_param;
|
|
ObPartitionArray unreachable_partitions;
|
|
const bool is_retry_sql = (executor_ctx->get_retry_times() > 0);
|
|
const uint64_t tenant_id = my_session->get_effective_tenant_id();
|
|
transaction::ObTransDesc& trans_desc = my_session->get_trans_desc();
|
|
transaction::ObStartTransParam& trans_param = trans_desc.get_trans_param();
|
|
transaction::ObStmtDesc& stmt_desc = trans_desc.get_cur_stmt_desc();
|
|
int32_t trans_consistency_level = ObTransConsistencyLevel::UNKNOWN;
|
|
const int64_t last_safe_weak_read_snapshot = my_session->get_safe_weak_read_snapshot();
|
|
const int64_t last_safe_weak_read_snapshot_source = my_session->get_safe_weak_read_snapshot_source();
|
|
int64_t auto_spec_snapshot_version = ObTransVersion::INVALID_TRANS_VERSION;
|
|
const bool is_trx_elr = my_session->get_early_lock_release();
|
|
|
|
my_session->get_trans_result().clear_stmt_result();
|
|
|
|
if (OB_FAIL(set_trans_param_(*my_session,
|
|
*phy_plan,
|
|
phy_plan_ctx->get_consistency_level(),
|
|
trans_consistency_level,
|
|
auto_spec_snapshot_version))) {
|
|
LOG_WARN("set trans param fail", K(ret), KPC(my_session));
|
|
} else if (OB_FAIL(stmt_param.init(tenant_id,
|
|
get_stmt_timeout_ts(*phy_plan_ctx),
|
|
is_retry_sql,
|
|
last_safe_weak_read_snapshot,
|
|
last_safe_weak_read_snapshot_source,
|
|
is_trx_elr))) {
|
|
LOG_WARN("ObStmtParam init error", K(ret), K(tenant_id), K(is_retry_sql), K(last_safe_weak_read_snapshot));
|
|
} else {
|
|
stmt_desc.phy_plan_type_ = phy_plan->has_nested_sql() ? OB_PHY_PLAN_UNCERTAIN : phy_plan->get_location_type();
|
|
stmt_desc.stmt_type_ = phy_plan->get_stmt_type();
|
|
stmt_desc.is_sfu_ = phy_plan->has_for_update();
|
|
stmt_desc.execution_id_ = my_session->get_current_execution_id();
|
|
stmt_desc.sql_id_.assign_strive(phy_plan->stat_.sql_id_);
|
|
stmt_desc.trace_id_adaptor_.set(ObCurTraceId::get());
|
|
const ObString& app_trace_id_str = my_session->get_app_trace_id();
|
|
stmt_desc.app_trace_id_str_.reset();
|
|
stmt_desc.app_trace_id_str_.assign_buffer(stmt_desc.buffer_, sizeof(stmt_desc.buffer_));
|
|
stmt_desc.app_trace_id_str_.write(app_trace_id_str.ptr(), app_trace_id_str.length());
|
|
stmt_desc.cur_query_start_time_ = my_session->get_query_start_time();
|
|
stmt_desc.stmt_tenant_id_ = my_session->get_effective_tenant_id();
|
|
stmt_desc.inner_sql_ = my_session->is_inner();
|
|
stmt_desc.consistency_level_ = trans_consistency_level;
|
|
stmt_desc.trx_lock_timeout_ = my_session->get_trx_lock_timeout();
|
|
|
|
if (my_session->has_valid_read_snapshot_version()) {
|
|
stmt_desc.cur_stmt_specified_snapshot_version_ = my_session->get_read_snapshot_version();
|
|
} else if (auto_spec_snapshot_version > 0) {
|
|
stmt_desc.cur_stmt_specified_snapshot_version_ = auto_spec_snapshot_version;
|
|
}
|
|
/*
|
|
const ObString root_stmt = my_session->get_current_query_string();
|
|
LOG_INFO("start_root_stmt", K(root_stmt));
|
|
*/
|
|
ObPartitionLeaderArray out_pla;
|
|
if (pla.count() > 0 && OB_FAIL(change_pla_info_(executor_ctx->get_table_locations(), pla, out_pla))) {
|
|
LOG_WARN("change pla info error", K(ret), K(stmt_param), K(trans_desc), K(pla));
|
|
} else if (OB_FAIL(ps->start_stmt(stmt_param, trans_desc, out_pla, unreachable_partitions))) {
|
|
LOG_WARN("fail start stmt",
|
|
K(ret),
|
|
K(trans_desc),
|
|
K(pla),
|
|
K(out_pla),
|
|
K(is_remote),
|
|
K(unreachable_partitions.count()));
|
|
if ((is_transaction_rpc_timeout_err(ret) || is_data_not_readable_err(ret) || is_partition_change_error(ret)) &&
|
|
!is_remote) {
|
|
ObAddr unreachable_server;
|
|
for (int64_t i = 0; i < unreachable_partitions.count(); ++i) {
|
|
unreachable_server.reset();
|
|
int tmp_ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(
|
|
OB_SUCCESS != (tmp_ret = out_pla.find_leader(unreachable_partitions.at(i), unreachable_server)))) {
|
|
LOG_ERROR("can not find unreachable server", K(ret), K(tmp_ret), K(i), K(unreachable_partitions.at(i)));
|
|
} else if (OB_UNLIKELY(OB_SUCCESS !=
|
|
(tmp_ret = my_session->get_retry_info_for_update().add_invalid_server_distinctly(
|
|
unreachable_server, true)))) {
|
|
LOG_WARN("fail to add invalid server distinctly",
|
|
K(ret),
|
|
K(tmp_ret),
|
|
K(unreachable_server),
|
|
K(my_session->get_retry_info()));
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
OZ(update_safe_weak_read_snapshot(trans_param.is_bounded_staleness_read(),
|
|
*my_session,
|
|
trans_param.get_read_snapshot_type(),
|
|
trans_desc.get_snapshot_version()));
|
|
OZ(my_session->set_start_stmt());
|
|
|
|
if (phy_plan->is_contain_oracle_trx_level_temporary_table()) {
|
|
trans_desc.set_trx_level_temporary_table_involved();
|
|
}
|
|
|
|
DEBUG_TRANS_STAGE("start_stmt");
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::specify_stmt_snapshot_version_for_slave_cluster_sql_(const ObSQLSessionInfo& session,
|
|
const stmt::StmtType& literal_stmt_type, const bool& is_contain_inner_table, const int32_t consistency_type,
|
|
const int32_t read_snapshot_type, int64_t& auto_spec_snapshot_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
share::ObSchemaStatusProxy* schema_status_proxy = GCTX.schema_status_proxy_;
|
|
share::schema::ObRefreshSchemaStatus slave_schema_status;
|
|
|
|
const uint64_t tenant_id = session.get_effective_tenant_id();
|
|
|
|
const bool is_standby_cluster = GCTX.is_standby_cluster();
|
|
const bool is_inner_sql = session.is_inner();
|
|
const bool is_from_show_stmt = (literal_stmt_type != stmt::T_NONE);
|
|
const bool stmt_spec_snapshot_version_is_valid = session.has_valid_read_snapshot_version();
|
|
|
|
if (is_standby_cluster && is_contain_inner_table && !is_inner_sql && OB_SYS_TENANT_ID != tenant_id &&
|
|
!stmt_spec_snapshot_version_is_valid && ObTransConsistencyType::BOUNDED_STALENESS_READ == consistency_type) {
|
|
if (OB_ISNULL(schema_status_proxy)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid schema_status_proxy", K(schema_status_proxy));
|
|
} else if (OB_FAIL(schema_status_proxy->nonblock_get(tenant_id, slave_schema_status))) {
|
|
LOG_WARN("get schema status on slave cluster fail",
|
|
K(ret),
|
|
K(tenant_id),
|
|
K(session),
|
|
K(is_standby_cluster),
|
|
K(is_from_show_stmt),
|
|
K(is_contain_inner_table),
|
|
K(consistency_type),
|
|
K(read_snapshot_type));
|
|
if (OB_ENTRY_NOT_EXIST == ret) {
|
|
ret = OB_REPLICA_NOT_READABLE;
|
|
}
|
|
} else if (OB_UNLIKELY(slave_schema_status.snapshot_timestamp_ <= 0)) {
|
|
ret = OB_REPLICA_NOT_READABLE;
|
|
LOG_WARN("tenant schema status is invalid on slave cluster",
|
|
K(ret),
|
|
K(tenant_id),
|
|
K(slave_schema_status),
|
|
K(session),
|
|
K(is_standby_cluster),
|
|
K(is_from_show_stmt),
|
|
K(is_contain_inner_table),
|
|
K(consistency_type),
|
|
K(read_snapshot_type));
|
|
} else {
|
|
auto_spec_snapshot_version = slave_schema_status.snapshot_timestamp_;
|
|
LOG_INFO("specify statement snapshot version for slave cluster SQL",
|
|
K(tenant_id),
|
|
K(slave_schema_status),
|
|
K(is_standby_cluster),
|
|
K(is_inner_sql),
|
|
K(is_from_show_stmt),
|
|
K(is_contain_inner_table),
|
|
K(consistency_type),
|
|
K(read_snapshot_type),
|
|
K(session));
|
|
}
|
|
|
|
if (OB_REPLICA_NOT_READABLE == ret) {
|
|
LOG_WARN("slave cluster inner table readable snapshot version still not ready, need retry",
|
|
K(ret),
|
|
K(tenant_id),
|
|
K(is_standby_cluster),
|
|
K(is_inner_sql),
|
|
K(is_from_show_stmt),
|
|
K(consistency_type),
|
|
K(read_snapshot_type),
|
|
K(is_contain_inner_table),
|
|
K(session));
|
|
}
|
|
} else {
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::trans_param_compat_with_cluster_before_2200_(ObTransDesc& trans_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (trans_desc.get_cluster_version() < CLUSTER_VERSION_2200) {
|
|
if (trans_desc.get_snapshot_version() == ObTransVersion::INVALID_TRANS_VERSION) {
|
|
trans_desc.set_snapshot_version(0);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::set_trans_param_(ObSQLSessionInfo& my_session, const ObPhysicalPlan& phy_plan,
|
|
const ObConsistencyLevel sql_consistency_level, int32_t& trans_consistency_level,
|
|
int64_t& auto_spec_snapshot_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
transaction::ObTransDesc& trans_desc = my_session.get_trans_desc();
|
|
int32_t trans_consistency_type = ObTransConsistencyType::UNKNOWN;
|
|
int32_t read_snapshot_type = ObTransReadSnapshotType::UNKNOWN;
|
|
|
|
if (OB_FAIL(decide_trans_read_interface_specs("ObSqlTransControl::start_stmt",
|
|
my_session,
|
|
phy_plan.get_stmt_type(),
|
|
phy_plan.get_literal_stmt_type(),
|
|
phy_plan.has_for_update(),
|
|
phy_plan.is_contain_inner_table(),
|
|
sql_consistency_level,
|
|
phy_plan.need_consistent_snapshot(),
|
|
trans_consistency_level,
|
|
trans_consistency_type,
|
|
read_snapshot_type))) {
|
|
LOG_WARN("fail to decide trans read interface specs",
|
|
K(ret),
|
|
K(phy_plan.get_stmt_type()),
|
|
K(phy_plan.get_literal_stmt_type()),
|
|
K(phy_plan.has_for_update()),
|
|
K(phy_plan.is_contain_inner_table()),
|
|
K(sql_consistency_level),
|
|
K(my_session));
|
|
} else if (GCTX.is_standby_cluster() && OB_FAIL(specify_stmt_snapshot_version_for_slave_cluster_sql_(my_session,
|
|
phy_plan.get_literal_stmt_type(),
|
|
phy_plan.is_contain_inner_table(),
|
|
trans_consistency_type,
|
|
read_snapshot_type,
|
|
auto_spec_snapshot_version))) {
|
|
LOG_WARN("specify statement snapshot version for slave cluster sql fail", K(ret), K(my_session));
|
|
} else if (OB_FAIL(trans_param_compat_with_cluster_before_2200_(trans_desc))) {
|
|
LOG_WARN("trans param compat with cluster before 2200 fail", K(ret), K(trans_desc));
|
|
} else {
|
|
trans_desc.get_trans_param().set_read_snapshot_type(read_snapshot_type);
|
|
|
|
if (ObTransConsistencyType::UNKNOWN == my_session.get_trans_consistency_type()) {
|
|
my_session.set_trans_consistency_type(trans_consistency_type);
|
|
trans_desc.get_trans_param().set_consistency_type(trans_consistency_type);
|
|
} else if (trans_desc.get_trans_param().get_consistency_type() != trans_consistency_type) {
|
|
ret = OB_NOT_SUPPORTED;
|
|
LOG_WARN("different consistency type in one transaction, unexpected error",
|
|
K(ret),
|
|
K(trans_consistency_type),
|
|
K(trans_desc));
|
|
LOG_USER_ERROR(OB_NOT_SUPPORTED, "different consistency type in one transaction");
|
|
}
|
|
|
|
if (OB_SUCCESS == ret) {
|
|
if (ObTransConsistencyType::BOUNDED_STALENESS_READ == trans_consistency_type) {
|
|
trans_desc.get_trans_param().set_access_mode(transaction::ObTransAccessMode::READ_ONLY);
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG_DEBUG("ObSqlTransControl::start_stmt::set_trans_param",
|
|
K(sql_consistency_level),
|
|
K(trans_consistency_type),
|
|
K(trans_consistency_level),
|
|
K(read_snapshot_type),
|
|
K(auto_spec_snapshot_version),
|
|
K(trans_desc),
|
|
K(my_session));
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::get_discard_participants(const ObPartitionArray& all_partitions,
|
|
const ObPartitionArray& response_partitions, ObPartitionArray& discard_partitions)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(all_partitions.count() > response_partitions.count())) {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < all_partitions.count(); ++i) {
|
|
if (OB_UNLIKELY(!has_exist_in_array(response_partitions, all_partitions.at(i)))) {
|
|
OZ(discard_partitions.push_back(all_partitions.at(i)), i, all_partitions.at(i));
|
|
}
|
|
}
|
|
LOG_DEBUG("get discard participants", K(ret), K(all_partitions), K(response_partitions), K(discard_partitions));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::create_savepoint(ObExecContext& exec_ctx, const ObString& sp_name)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(ps = executor_ctx->get_partition_service())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("null ptr", K(ret), K(executor_ctx), K(my_session), K(ps));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(ps->savepoint(my_session->get_trans_desc(), sp_name))) {
|
|
LOG_WARN("fail to create savepoint", K(ret), K(sp_name));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::rollback_savepoint(ObExecContext& exec_ctx, const ObString& sp_name)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
const ObPhysicalPlanCtx* phy_plan_ctx = GET_PHY_PLAN_CTX(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
transaction::ObStmtParam stmt_param;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(ps = executor_ctx->get_partition_service())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("null ptr", K(ret), K(executor_ctx), K(my_session), K(ps));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(
|
|
stmt_param.init(my_session->get_effective_tenant_id(), get_stmt_timeout_ts(*phy_plan_ctx), false))) {
|
|
LOG_WARN("ObStmtParam init error", K(ret), K(my_session));
|
|
} else if (OB_FAIL(ps->rollback_savepoint(my_session->get_trans_desc(), sp_name, stmt_param))) {
|
|
LOG_WARN("fail to rollback savepoint", K(ret), K(sp_name), K(stmt_param));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::release_savepoint(ObExecContext& exec_ctx, const ObString& sp_name)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(ps = executor_ctx->get_partition_service())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("null ptr", K(ret), K(executor_ctx), K(my_session), K(ps));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(ps->release_savepoint(my_session->get_trans_desc(), sp_name))) {
|
|
LOG_WARN("fail to release savepoint", K(ret), K(sp_name));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::xa_rollback_all_changes(ObExecContext& exec_ctx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
const ObPhysicalPlanCtx* phy_plan_ctx = GET_PHY_PLAN_CTX(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
transaction::ObStmtParam stmt_param;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(ps = executor_ctx->get_partition_service())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("null ptr", K(ret), K(executor_ctx), K(my_session), K(ps));
|
|
} else if (!my_session->is_in_transaction() || !my_session->get_trans_desc().is_xa_local_trans()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("called in wrong context", K(ret), K(my_session->get_trans_desc()));
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(
|
|
stmt_param.init(my_session->get_effective_tenant_id(), get_stmt_timeout_ts(*phy_plan_ctx), false))) {
|
|
LOG_WARN("ObStmtParam init error", K(ret), K(my_session));
|
|
} else if (OB_FAIL(ps->xa_rollback_all_changes(my_session->get_trans_desc(), stmt_param))) {
|
|
LOG_WARN("fail to rollback savepoint", K(ret), K(stmt_param), K(my_session->get_trans_desc()));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::end_stmt(ObExecContext& exec_ctx, const bool is_rollback)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
common::ObPartitionLeaderArray pla;
|
|
bool skip_end_stmt = false;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(ps = executor_ctx->get_partition_service())) {
|
|
LOG_WARN("can't get partition service or my_session", K(executor_ctx), K(my_session), K(ps));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else if (my_session->is_fast_select() || my_session->is_standalone_stmt()) {
|
|
skip_end_stmt = true;
|
|
} else if (FALSE_IT(skip_end_stmt = my_session->reuse_cur_sql_no())) {
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (OB_FAIL(get_participants(
|
|
executor_ctx->get_table_locations(), pla, my_session->get_is_in_retry_for_dup_tbl()))) {
|
|
LOG_WARN("get participants failed", K(ret), K(executor_ctx->get_table_locations()));
|
|
} else if (OB_FAIL(merge_stmt_partitions(exec_ctx, *my_session))) {
|
|
LOG_WARN("fail to merge stmt partitions", K(ret));
|
|
} else if (skip_end_stmt) {
|
|
// nesetd sql will not end_stmt().
|
|
LOG_DEBUG("skip end_stmt",
|
|
K(ret),
|
|
"cur_stmt",
|
|
my_session->get_current_query_string(),
|
|
"trans_result",
|
|
my_session->get_trans_result());
|
|
} else if (my_session->is_nested_session()) {
|
|
TransResult& trans_result = my_session->get_trans_result();
|
|
ObTransDesc& trans_desc = my_session->get_trans_desc();
|
|
ObPartitionArray cur_stmt_all_pgs;
|
|
if (trans_result.get_total_partitions().count() > 0 &&
|
|
OB_FAIL(change_pkeys_to_pgs_(
|
|
executor_ctx->get_table_locations(), trans_result.get_total_partitions(), cur_stmt_all_pgs))) {
|
|
LOG_WARN("change cur stmt pkeys to pgs error", K(ret), K(trans_result));
|
|
trans_desc.set_need_rollback();
|
|
} else if (OB_FAIL(ps->end_nested_stmt(trans_desc, cur_stmt_all_pgs, is_rollback))) {
|
|
LOG_WARN("end nested stmt fail", K(ret), K(trans_desc), K(cur_stmt_all_pgs), K(is_rollback));
|
|
}
|
|
/*
|
|
int64_t nested_count = my_session->get_nested_count();
|
|
const ObString nested_stmt = my_session->get_current_query_string();
|
|
LOG_INFO("end_nested_stmt", K(nested_count), K(nested_stmt), K(trans_result), K(is_rollback));
|
|
*/
|
|
} else {
|
|
transaction::ObTransDesc& trans_desc = my_session->get_trans_desc();
|
|
TransResult& trans_result = my_session->get_trans_result();
|
|
ObPartitionArray discard_partitions;
|
|
if (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_2100 && !is_rollback) {
|
|
// param discard_partitions is added in version 2.1
|
|
// in order to compatible with the old server below version 2.1
|
|
// only calculate the discard partition when all server are updated to version 2.1
|
|
OZ(get_discard_participants(
|
|
trans_result.get_total_partitions(), trans_result.get_response_partitions(), discard_partitions),
|
|
trans_result,
|
|
discard_partitions);
|
|
}
|
|
ObPartitionArray cur_stmt_all_pgs;
|
|
ObPartitionArray cur_stmt_discard_pgs;
|
|
ObPartitionLeaderArray cur_stmt_pla;
|
|
if (trans_result.get_total_partitions().count() > 0 &&
|
|
OB_FAIL(change_pkeys_to_pgs_(
|
|
executor_ctx->get_table_locations(), trans_result.get_total_partitions(), cur_stmt_all_pgs))) {
|
|
LOG_WARN("change cur stmt pkeys to pgs error", K(ret), K(trans_result), K(trans_desc));
|
|
trans_desc.set_need_rollback();
|
|
} else if (discard_partitions.count() > 0 &&
|
|
OB_FAIL(change_pkeys_to_pgs_(
|
|
executor_ctx->get_table_locations(), discard_partitions, cur_stmt_discard_pgs))) {
|
|
LOG_WARN("change cur stmt discard pkeys to pgs error", K(ret), K(trans_result), K(trans_desc));
|
|
trans_desc.set_need_rollback();
|
|
} else if (pla.count() > 0 && OB_FAIL(change_pla_info_(executor_ctx->get_table_locations(), pla, cur_stmt_pla))) {
|
|
LOG_WARN("change pla info error", K(ret), K(pla), K(cur_stmt_pla), K(trans_result), K(trans_desc));
|
|
trans_desc.set_need_rollback();
|
|
} else {
|
|
/*
|
|
const ObString root_stmt = my_session->get_current_query_string();
|
|
LOG_INFO("end_root_stmt", K(root_stmt), KP(&trans_desc),
|
|
"trans_desc_max_sql_no", trans_desc.get_max_sql_no(),
|
|
"trans_result_max_sql_no", trans_result.get_max_sql_no());
|
|
*/
|
|
OZ(ps->end_stmt(is_rollback,
|
|
trans_result.is_incomplete(),
|
|
cur_stmt_all_pgs,
|
|
trans_result.get_part_epoch_list(),
|
|
cur_stmt_discard_pgs,
|
|
cur_stmt_pla,
|
|
trans_desc),
|
|
trans_result,
|
|
discard_partitions,
|
|
trans_desc);
|
|
DEBUG_TRANS_STAGE("end_stmt");
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
LOG_WARN("call end_stmt",
|
|
K(ret),
|
|
K(trans_desc),
|
|
"cur_stmt",
|
|
my_session->get_current_query_string(),
|
|
K(cur_stmt_all_pgs),
|
|
K(cur_stmt_discard_pgs),
|
|
K(cur_stmt_pla),
|
|
K(discard_partitions),
|
|
K(trans_result));
|
|
}
|
|
}
|
|
if (OB_NOT_NULL(my_session) && !skip_end_stmt && !my_session->is_nested_session()) {
|
|
my_session->get_trans_result().clear_stmt_result();
|
|
int end_ret = my_session->set_end_stmt();
|
|
if (OB_SUCCESS != end_ret) {
|
|
LOG_ERROR("failed to set end stmt", K(end_ret));
|
|
if (OB_SUCCESS == ret) {
|
|
ret = end_ret;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::start_participant(
|
|
ObExecContext& exec_ctx, const common::ObPartitionArray& participants, bool is_remote /* = false*/)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
const ObPhysicalPlan* phy_plan = NULL;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(ps = executor_ctx->get_partition_service()) ||
|
|
OB_ISNULL(phy_plan = GET_PHY_PLAN_CTX(exec_ctx)->get_phy_plan())) {
|
|
LOG_WARN("can't get partition service or my_session", K(executor_ctx), K(my_session), K(ps));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (my_session->is_fast_select() || my_session->is_standalone_stmt()) {
|
|
// do nothing ...
|
|
} else {
|
|
transaction::ObTransDesc& trans_desc = my_session->get_trans_desc();
|
|
TransResult& trans_result = my_session->get_trans_result();
|
|
if (OB_FAIL(trans_result.merge_total_partitions(participants))) {
|
|
LOG_WARN("fail to merge partitions", K(ret), K(participants));
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
ObPartitionArray pgs;
|
|
ObPartitionEpochArray partition_epoch_arr;
|
|
const ObTransID& trans_id = trans_desc.get_trans_id();
|
|
int64_t sql_no = trans_desc.get_sql_no();
|
|
bool is_forbidden = false;
|
|
if (participants.count() > 0 &&
|
|
OB_FAIL(change_pkeys_to_pgs_(executor_ctx->get_table_locations(), participants, pgs))) {
|
|
LOG_WARN("change pkeys to pgs error", K(ret), K(participants), K(pgs), K(trans_desc));
|
|
} else if (OB_FAIL(ps->is_trans_forbidden_sql_no(trans_id, pgs, sql_no, is_forbidden))) {
|
|
LOG_WARN("get trans forbidden error", K(ret), K(participants), K(pgs), K(trans_desc));
|
|
} else if (is_forbidden) {
|
|
ret = OB_ERR_INTERRUPTED;
|
|
LOG_WARN("execution is interrupted", K(ret), K(participants), K(pgs), K(trans_desc));
|
|
} else if (OB_FAIL(ps->start_participant(trans_desc, pgs, partition_epoch_arr))) {
|
|
if (OB_NOT_MASTER != ret) {
|
|
LOG_WARN(
|
|
"fail start participants", K(ret), K(is_remote), K(participants), K(pgs), K(trans_result), K(trans_desc));
|
|
}
|
|
if (is_data_not_readable_err(ret) && !is_remote) {
|
|
int add_ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(
|
|
OB_SUCCESS != (add_ret = my_session->get_retry_info_for_update().add_invalid_server_distinctly(
|
|
exec_ctx.get_addr(), true)))) {
|
|
LOG_WARN("fail to add local addr to invalid servers distinctly",
|
|
K(ret),
|
|
K(add_ret),
|
|
K(exec_ctx.get_addr()),
|
|
K(my_session->get_retry_info()));
|
|
}
|
|
}
|
|
} else {
|
|
DEBUG_TRANS_STAGE("start_participant");
|
|
LOG_DEBUG("start participant", K(participants), K(trans_result));
|
|
OZ(trans_result.merge_response_partitions(participants), participants);
|
|
OZ(trans_result.merge_part_epoch_list(partition_epoch_arr), partition_epoch_arr);
|
|
}
|
|
NG_TRACE_EXT(start_part, OB_ID(ret), ret, OB_ID(trans_id), trans_desc.get_trans_id());
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::end_participant(
|
|
ObExecContext& exec_ctx, const bool is_rollback, const common::ObPartitionArray& participants)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
if (OB_ISNULL(executor_ctx) || OB_ISNULL(my_session) || OB_ISNULL(ps = executor_ctx->get_partition_service())) {
|
|
LOG_WARN("can't get partition service or my_session", K(executor_ctx), K(my_session), K(ps));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else if (OB_UNLIKELY(my_session->is_zombie())) {
|
|
// session has been killed some moment ago
|
|
ret = OB_ERR_SESSION_INTERRUPTED;
|
|
LOG_WARN("session has been killed",
|
|
K(ret),
|
|
K(my_session->get_session_state()),
|
|
K(my_session->get_sessid()),
|
|
"proxy_sessid",
|
|
my_session->get_proxy_sessid());
|
|
} else if (my_session->is_fast_select() || my_session->is_standalone_stmt()) {
|
|
// do nothing ...
|
|
} else {
|
|
transaction::ObTransDesc& trans_desc = my_session->get_trans_desc();
|
|
ObPartitionArray pgs;
|
|
if (participants.count() > 0 &&
|
|
OB_FAIL(change_pkeys_to_pgs_(executor_ctx->get_table_locations(), participants, pgs))) {
|
|
LOG_WARN("change pkeys to pgs error", K(ret), K(participants), K(pgs), K(trans_desc));
|
|
} else if (OB_FAIL(ps->end_participant(is_rollback, trans_desc, pgs))) {
|
|
LOG_WARN("fail end participant", K(ret), K(is_rollback), K(participants), K(pgs), K(trans_desc));
|
|
} else {
|
|
// do nothing
|
|
DEBUG_TRANS_STAGE("end_participant");
|
|
}
|
|
}
|
|
NG_TRACE_EXT(end_participant, OB_ID(ret), ret);
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::get_pg_key_(
|
|
const ObIArray<ObPhyTableLocation>& table_locations, const ObPartitionKey& pkey, ObPartitionKey& pg_key)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool hit = false;
|
|
for (int64_t i = 0; OB_SUCC(ret) && !hit && i < table_locations.count(); ++i) {
|
|
const ObPartitionReplicaLocationIArray& part_locations = table_locations.at(i).get_partition_location_list();
|
|
for (int64_t j = 0; OB_SUCC(ret) && j < part_locations.count(); ++j) {
|
|
ObPartitionKey tmp_pkey;
|
|
if (OB_FAIL(part_locations.at(j).get_partition_key(tmp_pkey))) {
|
|
LOG_WARN("get partition key error", K(ret), "location", part_locations.at(j));
|
|
} else if (pkey == tmp_pkey) {
|
|
pg_key = part_locations.at(j).get_pg_key();
|
|
hit = true;
|
|
break;
|
|
} else {
|
|
// do nothing
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (!hit || !pg_key.is_valid()) {
|
|
LOG_DEBUG("cannot find pg key", K(ret), K(table_locations), K(pkey), K(pg_key));
|
|
if (OB_FAIL(storage::ObPartitionService::get_instance().get_pg_key(pkey, pg_key))) {
|
|
LOG_WARN("get pg key error", K(ret), K(pkey), K(pg_key));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::change_pkeys_to_pgs_(
|
|
const ObIArray<ObPhyTableLocation>& table_locations, const ObPartitionArray& pkeys, ObPartitionArray& pg_keys)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (pkeys.count() <= 0) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret), K(pkeys), K(pg_keys), K(table_locations));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < pkeys.count(); ++i) {
|
|
ObPGKey pg_key;
|
|
if (table_locations.count() <= 0) {
|
|
if (OB_FAIL(storage::ObPartitionService::get_instance().get_pg_key(pkeys.at(i), pg_key))) {
|
|
LOG_WARN("get pg key error", K(ret), K(pkeys), K(pg_key));
|
|
}
|
|
} else if (OB_FAIL(get_pg_key_(table_locations, pkeys.at(i), pg_key))) {
|
|
LOG_WARN("get pg key error", K(ret), "key", pkeys.at(i));
|
|
} else {
|
|
// do nothing
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
int64_t j = 0;
|
|
for (; j < pg_keys.count(); ++j) {
|
|
if (pg_key == pg_keys.at(j)) {
|
|
break;
|
|
}
|
|
}
|
|
if (j == pg_keys.count()) {
|
|
if (OB_FAIL(pg_keys.push_back(pg_key))) {
|
|
LOG_WARN("pg keys push back error", K(ret), K(pg_key), K(pg_keys));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::change_pla_info_(const ObIArray<ObPhyTableLocation>& table_locations,
|
|
const ObPartitionLeaderArray& pla, ObPartitionLeaderArray& out_pla)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (pla.count() <= 0) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret), K(pla), K(table_locations));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < pla.count(); ++i) {
|
|
ObPGKey pg_key;
|
|
if (table_locations.count() <= 0) {
|
|
if (OB_FAIL(storage::ObPartitionService::get_instance().get_pg_key(pla.get_partitions().at(i), pg_key))) {
|
|
LOG_WARN("get pg key error", K(ret), K(table_locations), K(pla));
|
|
}
|
|
} else if (OB_FAIL(get_pg_key_(table_locations, pla.get_partitions().at(i), pg_key))) {
|
|
LOG_WARN("get pg key error", K(ret), K(table_locations), K(pla));
|
|
} else {
|
|
// do nothing
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
const ObAddr& addr = pla.get_leaders().at(i);
|
|
const common::ObPartitionType& type = pla.get_types().at(i);
|
|
int64_t j = 0;
|
|
for (; j < out_pla.count(); ++j) {
|
|
if (pg_key == out_pla.get_partitions().at(j) && addr == out_pla.get_leaders().at(j) &&
|
|
type == out_pla.get_types().at(j)) {
|
|
break;
|
|
}
|
|
}
|
|
if (j == out_pla.count()) {
|
|
if (OB_FAIL(out_pla.push(pg_key, addr, type))) {
|
|
LOG_WARN("out pla push back error", K(pg_key), K(addr), K(type));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::get_participants(
|
|
const ObIArray<ObPhyTableLocation>& table_locations, ObPartitionLeaderArray& pla, bool is_retry_for_dup_tbl)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
uint64_t N = table_locations.count();
|
|
ObPartitionKey key;
|
|
common::ObPartitionType type;
|
|
// SQL_LOG(DEBUG, "phy table location size:", K(N));
|
|
for (uint64_t i = 0; OB_SUCC(ret) && i < N; ++i) {
|
|
const ObPartitionReplicaLocationIArray& part_locations = table_locations.at(i).get_partition_location_list();
|
|
int64_t M = part_locations.count();
|
|
bool is_dup = table_locations.at(i).is_duplicate_table();
|
|
bool is_dup_not_dml = table_locations.at(i).is_duplicate_table_not_in_dml();
|
|
for (int64_t j = 0; OB_SUCC(ret) && j < M; ++j) {
|
|
if (is_dup) {
|
|
if (part_locations.at(j).get_replica_location().is_follower()) {
|
|
type = ObPartitionType::DUPLICATE_FOLLOWER_PARTITION;
|
|
} else if (is_dup_not_dml && false == is_retry_for_dup_tbl) {
|
|
type = ObPartitionType::DUPLICATE_FOLLOWER_PARTITION;
|
|
} else {
|
|
type = ObPartitionType::DUPLICATE_LEADER_PARTITION;
|
|
}
|
|
} else {
|
|
type = ObPartitionType::NORMAL_PARTITION;
|
|
}
|
|
// LOG_INFO("partition location", K(is_dup), K(type), K(is_dup_not_dml), K(part_locations.at(j)));
|
|
if (OB_FAIL(part_locations.at(j).get_partition_key(key))) {
|
|
LOG_WARN("failed to get partition key", K(ret));
|
|
} else if (OB_UNLIKELY(is_virtual_table(key.table_id_))) {
|
|
} else if (OB_FAIL(append_participant_to_array_distinctly(
|
|
pla, key, type, part_locations.at(j).get_replica_location().server_))) {
|
|
/*
|
|
* In the case of multiple alias table corresponding to the same physical table, the
|
|
* key we get could be duplicate. To avoid having same partition as participants more
|
|
* than once, we need to check if we have already added the key in the list.
|
|
*/
|
|
LOG_WARN("fail to push back participant", K(ret), K(i), K(key), K(is_dup));
|
|
}
|
|
} /* for */
|
|
} /* for */
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::get_participants(ObExecContext& exec_ctx, ObPartitionLeaderArray& pla)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx* task_exec_ctx = exec_ctx.get_task_executor_ctx();
|
|
ObSQLSessionInfo* my_session = GET_MY_SESSION(exec_ctx);
|
|
if (OB_ISNULL(task_exec_ctx) || OB_ISNULL(my_session)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("task executor ctx should not be NULL", K(my_session));
|
|
} else if (OB_FAIL(get_participants(
|
|
task_exec_ctx->get_table_locations(), pla, my_session->get_is_in_retry_for_dup_tbl()))) {
|
|
LOG_WARN("get participants failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::append_participant_to_array_distinctly(
|
|
ObPartitionLeaderArray& pla, const ObPartitionKey& key, const common::ObPartitionType type, const ObAddr& svr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool found = false;
|
|
// check if the key already exists
|
|
for (int64_t i = 0; !found && i < pla.count(); i++) {
|
|
if (pla.get_partitions().at(i) == key && pla.get_leaders().at(i) == svr) {
|
|
found = true;
|
|
}
|
|
}
|
|
// if not, add it
|
|
if (!found) {
|
|
ret = pla.push(key, svr, type);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::get_participants(ObExecContext& exec_ctx, common::ObPartitionArray& participants)
|
|
{
|
|
// DO NOT reset participants for init, see ObResultSet::merge_stmt_partitions().
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx& task_exec_ctx = exec_ctx.get_task_exec_ctx();
|
|
const ObIArray<ObPhyTableLocation>& table_locations = task_exec_ctx.get_table_locations();
|
|
uint64_t N = table_locations.count();
|
|
SQL_LOG(DEBUG, "phy table location size:", K(N));
|
|
for (uint64_t i = 0; OB_SUCC(ret) && i < N; ++i) {
|
|
const ObPartitionReplicaLocationIArray& part_locations = table_locations.at(i).get_partition_location_list();
|
|
int64_t M = part_locations.count();
|
|
for (int64_t j = 0; OB_SUCC(ret) && j < M; ++j) {
|
|
// LOG_INFO("partition location", K(part_locations.at(j)));
|
|
ObPartitionKey key;
|
|
if (OB_FAIL(part_locations.at(j).get_partition_key(key))) {
|
|
LOG_WARN("failed to get partition key", K(ret));
|
|
} else if (OB_UNLIKELY(is_virtual_table(key.table_id_))) {
|
|
} else if (OB_FAIL(append_participant_to_array_distinctly(participants, key))) {
|
|
/*
|
|
* In the case of multiple alias table corresponding to the same physical table, the
|
|
* key we get could be duplicate. To avoid having same partition as participants more
|
|
* than once, we need to check if we have already added the key in the list.
|
|
*/
|
|
LOG_WARN("fail to push back participant", K(ret), K(i), K(j), K(key));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::get_root_job_participants(
|
|
ObExecContext& exec_ctx, const ObPhyOperator& root_job_root_op, ObPartitionArray& participants)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx& task_exec_ctx = exec_ctx.get_task_exec_ctx();
|
|
ObSEArray<TableLocationKey, 2> table_location_keys;
|
|
OZ(ObTaskSpliter::find_all_table_location_keys(table_location_keys, root_job_root_op));
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < table_location_keys.count(); ++i) {
|
|
const TableLocationKey& table_location_key = table_location_keys.at(i);
|
|
const ObPhyTableLocation* table_loc = NULL;
|
|
OZ(ObTaskExecutorCtxUtil::get_phy_table_location(
|
|
task_exec_ctx, table_location_key.table_id_, table_location_key.ref_table_id_, table_loc));
|
|
CK(OB_NOT_NULL(table_loc));
|
|
OZ(append_participant_by_table_loc(participants, *table_loc));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::get_root_job_participants(
|
|
ObExecContext& exec_ctx, const ObOperator& root_job_root_op, ObPartitionArray& participants)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx& task_exec_ctx = exec_ctx.get_task_exec_ctx();
|
|
ObSEArray<TableLocationKey, 2> table_location_keys;
|
|
OZ(ObTaskSpliter::find_all_table_location_keys(table_location_keys, root_job_root_op.get_spec()));
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < table_location_keys.count(); ++i) {
|
|
const TableLocationKey& table_location_key = table_location_keys.at(i);
|
|
const ObPhyTableLocation* table_loc = NULL;
|
|
OZ(ObTaskExecutorCtxUtil::get_phy_table_location(
|
|
task_exec_ctx, table_location_key.table_id_, table_location_key.ref_table_id_, table_loc));
|
|
CK(OB_NOT_NULL(table_loc));
|
|
OZ(append_participant_by_table_loc(participants, *table_loc));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::append_participant_by_table_loc(
|
|
ObPartitionIArray& participants, const ObPhyTableLocation& table_loc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObPartitionReplicaLocationIArray& part_locations = table_loc.get_partition_location_list();
|
|
int64_t M = part_locations.count();
|
|
ObPartitionKey key;
|
|
for (int64_t j = 0; OB_SUCC(ret) && j < M; ++j) {
|
|
key.reset();
|
|
if (OB_FAIL(part_locations.at(j).get_partition_key(key))) {
|
|
LOG_WARN("failed to get partition key", K(ret));
|
|
} else if (OB_UNLIKELY(true == is_virtual_table(key.table_id_))) {
|
|
} else if (OB_FAIL(append_participant_to_array_distinctly(participants, key))) {
|
|
/*
|
|
* In the case of multiple alias table corresponding to the same physical table, the
|
|
* key we get could be duplicate. To avoid having same partition as participants more
|
|
* than once, we need to check if we have already added the key in the list.
|
|
*/
|
|
LOG_WARN("fail to push back participant", K(ret), K(j), K(key));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::append_participant_to_array_distinctly(
|
|
ObPartitionIArray& participants, const ObPartitionKey& key)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool found = false;
|
|
// check if the key already exists
|
|
for (int64_t i = 0; !found && i < participants.count(); i++) {
|
|
if (participants.at(i) == key) {
|
|
found = true;
|
|
}
|
|
}
|
|
// if not, add it
|
|
if (!found) {
|
|
ret = participants.push_back(key);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::inc_session_ref(const ObSQLSessionInfo* my_session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(GCTX.session_mgr_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid parameter", K(my_session), K(GCTX.session_mgr_), K(ret));
|
|
} else {
|
|
ret = GCTX.session_mgr_->inc_session_ref(my_session);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::merge_stmt_partitions(ObExecContext& exec_ctx, ObSQLSessionInfo& session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObPartitionArray total_partitions;
|
|
// ObSqlTransControl::get_participants() can merge partitions.
|
|
if (OB_FAIL(ObSqlTransControl::get_participants(exec_ctx, total_partitions))) {
|
|
LOG_WARN("get participants failed", K(ret));
|
|
} else if (OB_FAIL(session.get_trans_result().merge_total_partitions(total_partitions))) {
|
|
LOG_WARN("merge total participants failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::get_stmt_snapshot_info(
|
|
ObExecContext& exec_ctx, const bool is_cursor, transaction::ObTransDesc& trans_desc, ObTransSnapInfo& snap_info)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
transaction::ObTransService* txs = NULL;
|
|
CK(OB_NOT_NULL(executor_ctx));
|
|
CK(OB_NOT_NULL(ps = executor_ctx->get_partition_service()));
|
|
CK(OB_NOT_NULL(txs = ps->get_trans_service()));
|
|
OZ(txs->get_stmt_snapshot_info(is_cursor, trans_desc, snap_info));
|
|
return ret;
|
|
}
|
|
|
|
int ObSqlTransControl::start_standalone_stmt(
|
|
ObExecContext& exec_ctx, ObSQLSessionInfo& session_info, ObPhysicalPlanCtx& phy_plan_ctx, bool is_remote)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LOG_DEBUG("start_standalone_stmt", "session_id", session_info.get_sessid());
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
storage::ObPartitionService* ps = NULL;
|
|
transaction::ObTransService* txs = NULL;
|
|
bool is_local_single_partition_stmt = false;
|
|
const ObPhysicalPlan* phy_plan = phy_plan_ctx.get_phy_plan();
|
|
transaction::ObStandaloneStmtDesc& standalone_stmt_desc = session_info.get_trans_desc().get_standalone_stmt_desc();
|
|
|
|
int32_t consistency_level = ObTransConsistencyLevel::UNKNOWN;
|
|
int32_t consistency_type = ObTransConsistencyType::UNKNOWN;
|
|
int32_t read_snapshot_type = ObTransReadSnapshotType::UNKNOWN;
|
|
int64_t auto_spec_snapshot_version = ObTransVersion::INVALID_TRANS_VERSION;
|
|
CK(OB_NOT_NULL(executor_ctx));
|
|
CK(OB_NOT_NULL(ps = executor_ctx->get_partition_service()));
|
|
CK(OB_NOT_NULL(txs = ps->get_trans_service()));
|
|
CK(OB_NOT_NULL(phy_plan));
|
|
OZ(decide_trans_read_interface_specs("ObSqlTransControl::start_standalone_stmt",
|
|
session_info,
|
|
phy_plan_ctx.get_phy_plan()->get_stmt_type(),
|
|
phy_plan_ctx.get_phy_plan()->get_literal_stmt_type(),
|
|
phy_plan_ctx.get_phy_plan()->has_for_update(),
|
|
phy_plan_ctx.get_phy_plan()->is_contain_inner_table(),
|
|
phy_plan_ctx.get_consistency_level(),
|
|
phy_plan_ctx.get_phy_plan()->need_consistent_snapshot(),
|
|
consistency_level,
|
|
consistency_type,
|
|
read_snapshot_type));
|
|
if (GCTX.is_standby_cluster()) {
|
|
OZ(specify_stmt_snapshot_version_for_slave_cluster_sql_(session_info,
|
|
phy_plan_ctx.get_phy_plan()->get_literal_stmt_type(),
|
|
phy_plan_ctx.get_phy_plan()->is_contain_inner_table(),
|
|
consistency_type,
|
|
read_snapshot_type,
|
|
auto_spec_snapshot_version));
|
|
}
|
|
if (OB_SUCC(ret) && session_info.has_valid_read_snapshot_version()) {
|
|
auto_spec_snapshot_version = session_info.get_read_snapshot_version();
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
common::ObPartitionLeaderArray in_pla;
|
|
if (!(phy_plan->has_nested_sql() || OB_PHY_PLAN_UNCERTAIN == phy_plan->get_location_type())) {
|
|
OZ(ObSqlTransControl::get_participants(exec_ctx, in_pla));
|
|
if (OB_SUCC(ret)) {
|
|
is_local_single_partition_stmt = (in_pla.count() == 1 && in_pla.get_leaders().at(0) == MYADDR &&
|
|
read_snapshot_type == ObTransReadSnapshotType::STATEMENT_SNAPSHOT);
|
|
}
|
|
}
|
|
OZ(standalone_stmt_desc.init(txs->get_server(),
|
|
session_info.get_effective_tenant_id(),
|
|
get_stmt_timeout_ts(phy_plan_ctx),
|
|
session_info.get_trx_lock_timeout(),
|
|
is_local_single_partition_stmt,
|
|
consistency_type,
|
|
read_snapshot_type,
|
|
is_local_single_partition_stmt ? in_pla.get_partitions().at(0) : ObPartitionKey()));
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (standalone_stmt_desc.is_bounded_staleness_read() &&
|
|
!ObWeakReadUtil::enable_monotonic_weak_read(session_info.get_effective_tenant_id())) {
|
|
if (ObSqlTransUtil::plan_can_start_trans(session_info.get_local_autocommit(), session_info.get_in_transaction())) {
|
|
OZ(implicit_start_trans(exec_ctx, is_remote));
|
|
}
|
|
} else {
|
|
OZ(txs->get_stmt_snapshot_info(session_info.get_trans_desc(), auto_spec_snapshot_version));
|
|
if (standalone_stmt_desc.is_bounded_staleness_read()) {
|
|
OZ(update_safe_weak_read_snapshot(standalone_stmt_desc.is_bounded_staleness_read(),
|
|
session_info,
|
|
read_snapshot_type,
|
|
standalone_stmt_desc.get_snapshot_version()));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool ObSqlTransControl::is_isolation_RR_or_SE(int32_t isolation)
|
|
{
|
|
return (isolation == ObTransIsolation::REPEATABLE_READ || isolation == ObTransIsolation::SERIALIZABLE);
|
|
}
|
|
|
|
int ObSqlTransControl::start_cursor_stmt(ObExecContext& exec_ctx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx* executor_ctx = GET_TASK_EXECUTOR_CTX(exec_ctx);
|
|
storage::ObPartitionService* ps = nullptr;
|
|
transaction::ObTransService* txs = nullptr;
|
|
ObSQLSessionInfo* session = nullptr;
|
|
ObPhysicalPlanCtx* plan_ctx = nullptr;
|
|
CK(OB_NOT_NULL(executor_ctx));
|
|
CK(OB_NOT_NULL(ps = executor_ctx->get_partition_service()));
|
|
CK(OB_NOT_NULL(txs = ps->get_trans_service()));
|
|
CK(OB_NOT_NULL(session = exec_ctx.get_my_session()));
|
|
CK(OB_NOT_NULL(plan_ctx = GET_PHY_PLAN_CTX(exec_ctx)));
|
|
OZ(txs->start_cursor_stmt(session->get_trans_desc(), plan_ctx->get_trans_timeout_timestamp()));
|
|
return ret;
|
|
}
|
|
|
|
} // namespace sql
|
|
} // namespace oceanbase
|