diff --git a/src/sql/ob_result_set.cpp b/src/sql/ob_result_set.cpp index d8b6b638d1..6292d15860 100644 --- a/src/sql/ob_result_set.cpp +++ b/src/sql/ob_result_set.cpp @@ -1091,8 +1091,20 @@ OB_INLINE int ObResultSet::auto_end_plan_trans(ObPhysicalPlan& plan, if (is_rollback && !is_will_retry_() && is_tx_active && !in_trans) { ObTransStatistic::get_instance().add_rollback_trans_count(MTL_ID(), 1); } - // 对于UPDATE等异步提交的语句,如果需要重试,那么中途的rollback也走同步接口 - if (OB_LIKELY(false == is_end_trans_async()) || OB_LIKELY(false == is_user_sql_)) { + bool lock_conflict_skip_end_trans = false; + // if err is lock conflict retry, do not rollback transaction, but cleanup transaction + // state, keep transaction id unchanged, easy for deadlock detection and $OB_LOCKS view + if (is_rollback && ret == OB_TRY_LOCK_ROW_CONFLICT && is_will_retry_()) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(ObSqlTransControl::reset_trans_for_autocommit_lock_conflict(get_exec_context()))) { + LOG_WARN("cleanup trans state for lock conflict fail, fallback to end trans", K(tmp_ret)); + } else { + lock_conflict_skip_end_trans = true; + } + } + if (lock_conflict_skip_end_trans) { + } else if (OB_LIKELY(false == is_end_trans_async()) || OB_LIKELY(false == is_user_sql_)) { + // 对于UPDATE等异步提交的语句,如果需要重试,那么中途的rollback也走同步接口 // 如果没有设置end_trans_cb,就走同步接口。这个主要是为了InnerSQL提供的。 // 因为InnerSQL没有走Obmp_query接口,而是直接操作ResultSet int save_ret = ret; diff --git a/src/sql/ob_sql_trans_control.cpp b/src/sql/ob_sql_trans_control.cpp index bc66124a28..f45a68230a 100644 --- a/src/sql/ob_sql_trans_control.cpp +++ b/src/sql/ob_sql_trans_control.cpp @@ -1658,5 +1658,16 @@ int ObSqlTransControl::alloc_branch_id(ObExecContext &exec_ctx, const int64_t co return ret; } +int ObSqlTransControl::reset_trans_for_autocommit_lock_conflict(ObExecContext &exec_ctx) +{ + int ret = OB_SUCCESS; + ObSQLSessionInfo *session = GET_MY_SESSION(exec_ctx); + ObTxDesc *tx_desc = NULL; + CK (OB_NOT_NULL(session)); + CK (OB_NOT_NULL(tx_desc = session->get_tx_desc())); + OZ (tx_desc->clear_state_for_autocommit_retry()); + return ret; +} + }/* ns sql*/ }/* ns oceanbase */ diff --git a/src/sql/ob_sql_trans_control.h b/src/sql/ob_sql_trans_control.h index 98d8fbeb98..ff77fc85c6 100644 --- a/src/sql/ob_sql_trans_control.h +++ b/src/sql/ob_sql_trans_control.h @@ -310,6 +310,10 @@ public: // called when response client to decide whether need allow free route and whether state need to be returned static int calc_txn_free_route(ObSQLSessionInfo &session, transaction::ObTxnFreeRouteCtx &txn_free_route_ctx); static int check_free_route_tx_alive(ObSQLSessionInfo &session, transaction::ObTxnFreeRouteCtx &txn_free_rotue_ctx); + + // when lock conflict, stmt will do retry, we do not rollback current transaction + // but clean the transaction level snapshot it exist + static int reset_trans_for_autocommit_lock_conflict(ObExecContext &exec_ctx); }; inline int ObSqlTransControl::get_trans_expire_ts(const ObSQLSessionInfo &my_session, diff --git a/src/storage/tx/ob_trans_define_v4.cpp b/src/storage/tx/ob_trans_define_v4.cpp index db6b11d5d4..2f55ec49e3 100644 --- a/src/storage/tx/ob_trans_define_v4.cpp +++ b/src/storage/tx/ob_trans_define_v4.cpp @@ -1789,6 +1789,23 @@ int64_t ObTxDesc::get_coord_epoch() const return epoch; } +// 1. clear transaction level snapshot +// 2. clear savepoints +int ObTxDesc::clear_state_for_autocommit_retry() +{ + ObSpinLockGuard guard(lock_); + if (tx_id_.is_valid()) { + savepoints_.reset(); + if (isolation_ == ObTxIsolationLevel::RR || isolation_ == ObTxIsolationLevel::SERIAL) { + snapshot_version_.reset(); + snapshot_scn_.reset(); + snapshot_uncertain_bound_ = 0; + TRANS_LOG(TRACE, "", KPC(this)); + } + } + return OB_SUCCESS; +} + } // transaction } // oceanbase #undef USING_LOG_PREFIX diff --git a/src/storage/tx/ob_trans_define_v4.h b/src/storage/tx/ob_trans_define_v4.h index ab16b7dee2..d8f0462344 100644 --- a/src/storage/tx/ob_trans_define_v4.h +++ b/src/storage/tx/ob_trans_define_v4.h @@ -812,6 +812,7 @@ LST_DO(DEF_FREE_ROUTE_DECODE, (;), static, dynamic, parts, extra); ObTxSEQ inc_and_get_tx_seq(int16_t branch) const; ObTxSEQ get_tx_seq(int64_t seq_abs = 0) const; ObTxSEQ get_min_tx_seq() const; + int clear_state_for_autocommit_retry(); }; // Is used to store and travserse all TxScheduler's Stat information;