[FOREIGN KEY] fix the bug about meet invalid conflict during checking child table which without index
This commit is contained in:
parent
098c6384d4
commit
f00019cb7c
@ -54,8 +54,10 @@ public:
|
|||||||
jump_read_group_id_(-1),
|
jump_read_group_id_(-1),
|
||||||
flags_(0)
|
flags_(0)
|
||||||
{
|
{
|
||||||
|
is_fk_cascading_ = 0;
|
||||||
need_check_server_ = 1;
|
need_check_server_ = 1;
|
||||||
same_server_ = 1;
|
same_server_ = 1;
|
||||||
|
iter_uncommitted_row_ = 0;
|
||||||
}
|
}
|
||||||
~ObDASCtx()
|
~ObDASCtx()
|
||||||
{
|
{
|
||||||
@ -139,10 +141,10 @@ public:
|
|||||||
uint64_t is_fk_cascading_ : 1; //fk starts to trigger nested sql
|
uint64_t is_fk_cascading_ : 1; //fk starts to trigger nested sql
|
||||||
uint64_t need_check_server_ : 1; //need to check if partitions hit the same server
|
uint64_t need_check_server_ : 1; //need to check if partitions hit the same server
|
||||||
uint64_t same_server_ : 1; //if partitions hit the same server, could be local or remote
|
uint64_t same_server_ : 1; //if partitions hit the same server, could be local or remote
|
||||||
uint64_t reserved_ : 62;
|
uint64_t iter_uncommitted_row_ : 1; //iter uncommitted row in fk_checker
|
||||||
|
uint64_t reserved_ : 60;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
} // namespace sql
|
} // namespace sql
|
||||||
} // namespace oceanbase
|
} // namespace oceanbase
|
||||||
|
@ -44,7 +44,8 @@ OB_DEF_SERIALIZE(ObDASDMLBaseRtDef)
|
|||||||
timeout_ts_,
|
timeout_ts_,
|
||||||
sql_mode_,
|
sql_mode_,
|
||||||
prelock_,
|
prelock_,
|
||||||
tenant_schema_version_);
|
tenant_schema_version_,
|
||||||
|
is_for_foreign_key_check_);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +56,8 @@ OB_DEF_DESERIALIZE(ObDASDMLBaseRtDef)
|
|||||||
timeout_ts_,
|
timeout_ts_,
|
||||||
sql_mode_,
|
sql_mode_,
|
||||||
prelock_,
|
prelock_,
|
||||||
tenant_schema_version_);
|
tenant_schema_version_,
|
||||||
|
is_for_foreign_key_check_);
|
||||||
if (OB_SUCC(ret)) {
|
if (OB_SUCC(ret)) {
|
||||||
(void)ObSQLUtils::adjust_time_by_ntp_offset(timeout_ts_);
|
(void)ObSQLUtils::adjust_time_by_ntp_offset(timeout_ts_);
|
||||||
}
|
}
|
||||||
@ -69,7 +71,8 @@ OB_DEF_SERIALIZE_SIZE(ObDASDMLBaseRtDef)
|
|||||||
timeout_ts_,
|
timeout_ts_,
|
||||||
sql_mode_,
|
sql_mode_,
|
||||||
prelock_,
|
prelock_,
|
||||||
tenant_schema_version_);
|
tenant_schema_version_,
|
||||||
|
is_for_foreign_key_check_);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,11 +108,13 @@ public:
|
|||||||
K_(sql_mode),
|
K_(sql_mode),
|
||||||
K_(prelock),
|
K_(prelock),
|
||||||
K_(tenant_schema_version),
|
K_(tenant_schema_version),
|
||||||
|
K_(is_for_foreign_key_check),
|
||||||
K_(affected_rows));
|
K_(affected_rows));
|
||||||
int64_t timeout_ts_;
|
int64_t timeout_ts_;
|
||||||
ObSQLMode sql_mode_;
|
ObSQLMode sql_mode_;
|
||||||
bool prelock_;
|
bool prelock_;
|
||||||
int64_t tenant_schema_version_;
|
int64_t tenant_schema_version_;
|
||||||
|
bool is_for_foreign_key_check_;
|
||||||
int64_t affected_rows_;
|
int64_t affected_rows_;
|
||||||
const DASDMLCtDefArray *related_ctdefs_;
|
const DASDMLCtDefArray *related_ctdefs_;
|
||||||
DASDMLRtDefArray *related_rtdefs_;
|
DASDMLRtDefArray *related_rtdefs_;
|
||||||
@ -123,6 +125,7 @@ protected:
|
|||||||
sql_mode_(DEFAULT_OCEANBASE_MODE),
|
sql_mode_(DEFAULT_OCEANBASE_MODE),
|
||||||
prelock_(false),
|
prelock_(false),
|
||||||
tenant_schema_version_(0),
|
tenant_schema_version_(0),
|
||||||
|
is_for_foreign_key_check_(false),
|
||||||
affected_rows_(0),
|
affected_rows_(0),
|
||||||
related_ctdefs_(nullptr),
|
related_ctdefs_(nullptr),
|
||||||
related_rtdefs_(nullptr)
|
related_rtdefs_(nullptr)
|
||||||
|
@ -1156,6 +1156,9 @@ int ObDMLService::init_dml_param(const ObDASDMLBaseCtDef &base_ctdef,
|
|||||||
&& !dml_param.table_param_->get_data_table().can_read_index()) {
|
&& !dml_param.table_param_->get_data_table().can_read_index()) {
|
||||||
dml_param.write_flag_.set_is_write_only_index();
|
dml_param.write_flag_.set_is_write_only_index();
|
||||||
}
|
}
|
||||||
|
if (base_rtdef.is_for_foreign_key_check_) {
|
||||||
|
dml_param.write_flag_.set_check_row_locked();
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1185,7 +1188,9 @@ int ObDMLService::init_das_dml_rtdef(ObDMLRtCtx &dml_rtctx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ObSQLUtils::is_fk_nested_sql(&dml_rtctx.get_exec_ctx())) {
|
||||||
|
das_rtdef.is_for_foreign_key_check_ = true;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,8 @@ int ForeignKeyHandle::do_handle(ObTableModifyOp &op,
|
|||||||
LOG_WARN("is_self_ref_row failed", K(ret), K(old_row), K(fk_arg));
|
LOG_WARN("is_self_ref_row failed", K(ret), K(old_row), K(fk_arg));
|
||||||
} else if (new_row.empty() && is_self_ref && op.is_fk_nested_session()) {
|
} else if (new_row.empty() && is_self_ref && op.is_fk_nested_session()) {
|
||||||
// delete self refercnced row should not cascade delete.
|
// delete self refercnced row should not cascade delete.
|
||||||
|
} else if (OB_FAIL(check_exist_inner_sql(op, fk_arg, old_row, true, true))) {
|
||||||
|
LOG_WARN("check exist before cascade failed", K(ret), K(fk_arg), K(old_row));
|
||||||
} else if (OB_FAIL(cascade(op, fk_arg, old_row, new_row))) {
|
} else if (OB_FAIL(cascade(op, fk_arg, old_row, new_row))) {
|
||||||
LOG_WARN("failed to cascade", K(ret), K(fk_arg), K(old_row), K(new_row));
|
LOG_WARN("failed to cascade", K(ret), K(fk_arg), K(old_row), K(new_row));
|
||||||
} else if (!new_row.empty() && is_self_ref) {
|
} else if (!new_row.empty() && is_self_ref) {
|
||||||
@ -114,7 +116,9 @@ int ForeignKeyHandle::do_handle(ObTableModifyOp &op,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ACTION_SET_NULL == fk_arg.ref_action_) {
|
} else if (ACTION_SET_NULL == fk_arg.ref_action_) {
|
||||||
if (OB_FAIL(set_null(op, fk_arg, old_row))) {
|
if (OB_FAIL(check_exist_inner_sql(op, fk_arg, old_row, true, true))) {
|
||||||
|
LOG_WARN("check exist before cascade failed", K(ret), K(fk_arg), K(old_row));
|
||||||
|
} else if (OB_FAIL(set_null(op, fk_arg, old_row))) {
|
||||||
LOG_WARN("failed to perform set null for foreign key", K(ret));
|
LOG_WARN("failed to perform set null for foreign key", K(ret));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,20 +163,24 @@ int ForeignKeyHandle::check_exist(ObTableModifyOp &modify_op, const ObForeignKey
|
|||||||
const ObExprPtrIArray &row, ObForeignKeyChecker *fk_checker, bool expect_zero)
|
const ObExprPtrIArray &row, ObForeignKeyChecker *fk_checker, bool expect_zero)
|
||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
|
DEBUG_SYNC(BEFORE_FOREIGN_KEY_CONSTRAINT_CHECK);
|
||||||
if (!expect_zero) {
|
if (!expect_zero) {
|
||||||
ret = check_exist_scan_task(modify_op, fk_arg, row, fk_checker, expect_zero);
|
ret = check_exist_scan_task(modify_op, fk_arg, row, fk_checker);
|
||||||
} else {
|
} else {
|
||||||
ret = check_exist_inner_sql(modify_op, fk_arg, row, expect_zero);
|
if (OB_FAIL(check_exist_inner_sql(modify_op, fk_arg, row, expect_zero, true))) {
|
||||||
|
LOG_WARN("check exist and iter uncommmited row meet failed", K(ret));
|
||||||
|
} else if (OB_FAIL(check_exist_inner_sql(modify_op, fk_arg, row, expect_zero, false))) {
|
||||||
|
LOG_WARN("check exist and iter commmited row meet failed", K(ret));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ForeignKeyHandle::check_exist_scan_task(ObTableModifyOp &modify_op, const ObForeignKeyArg &fk_arg,
|
int ForeignKeyHandle::check_exist_scan_task(ObTableModifyOp &modify_op, const ObForeignKeyArg &fk_arg,
|
||||||
const ObExprPtrIArray &row, ObForeignKeyChecker *fk_checker, bool expect_zero)
|
const ObExprPtrIArray &row, ObForeignKeyChecker *fk_checker)
|
||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
bool has_result = false;
|
bool has_result = false;
|
||||||
DEBUG_SYNC(BEFORE_FOREIGN_KEY_CONSTRAINT_CHECK);
|
|
||||||
if (OB_ISNULL(fk_checker)) {
|
if (OB_ISNULL(fk_checker)) {
|
||||||
ret = OB_ERR_UNEXPECTED;
|
ret = OB_ERR_UNEXPECTED;
|
||||||
LOG_WARN("foreign key checker is nullptr", K(ret));
|
LOG_WARN("foreign key checker is nullptr", K(ret));
|
||||||
@ -189,16 +197,16 @@ int ForeignKeyHandle::check_exist_scan_task(ObTableModifyOp &modify_op, const Ob
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ForeignKeyHandle::check_exist_inner_sql(ObTableModifyOp &op,
|
int ForeignKeyHandle::check_exist_inner_sql(ObTableModifyOp &op,
|
||||||
const ObForeignKeyArg &fk_arg,
|
const ObForeignKeyArg &fk_arg,
|
||||||
const ObExprPtrIArray &row,
|
const ObExprPtrIArray &row,
|
||||||
bool expect_zero)
|
bool expect_zero,
|
||||||
|
bool iter_uncommitted_row)
|
||||||
{
|
{
|
||||||
DEBUG_SYNC(BEFORE_FOREIGN_KEY_CONSTRAINT_CHECK);
|
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
static const char *SELECT_FMT_MYSQL =
|
static const char *SELECT_FMT_MYSQL =
|
||||||
"select /*+ no_parallel */ 1 from `%.*s`.`%.*s` where %.*s limit 2";
|
"select /*+ no_parallel */ 1 from `%.*s`.`%.*s` where %.*s limit 2 for update";
|
||||||
static const char *SELECT_FMT_ORACLE =
|
static const char *SELECT_FMT_ORACLE =
|
||||||
"select /*+ no_parallel */ 1 from \"%.*s\".\"%.*s\" where %.*s and rownum <= 2";
|
"select /*+ no_parallel */ 1 from \"%.*s\".\"%.*s\" where %.*s and rownum <= 2 for update";
|
||||||
const char *select_fmt = lib::is_mysql_mode() ? SELECT_FMT_MYSQL : SELECT_FMT_ORACLE;
|
const char *select_fmt = lib::is_mysql_mode() ? SELECT_FMT_MYSQL : SELECT_FMT_ORACLE;
|
||||||
ObArenaAllocator alloc(ObModIds::OB_MODULE_PAGE_ALLOCATOR,
|
ObArenaAllocator alloc(ObModIds::OB_MODULE_PAGE_ALLOCATOR,
|
||||||
OB_MALLOC_NORMAL_BLOCK_SIZE,
|
OB_MALLOC_NORMAL_BLOCK_SIZE,
|
||||||
@ -232,6 +240,9 @@ int ForeignKeyHandle::check_exist_inner_sql(ObTableModifyOp &op,
|
|||||||
stmt_buf[stmt_pos++] = 0;
|
stmt_buf[stmt_pos++] = 0;
|
||||||
}
|
}
|
||||||
if (OB_SUCC(ret) && stmt_pos > 0) {
|
if (OB_SUCC(ret) && stmt_pos > 0) {
|
||||||
|
if (iter_uncommitted_row) {
|
||||||
|
op.get_exec_ctx().get_das_ctx().iter_uncommitted_row_ = true;
|
||||||
|
}
|
||||||
LOG_DEBUG("foreign_key_check_exist", "stmt", stmt_buf, K(row), K(fk_arg));
|
LOG_DEBUG("foreign_key_check_exist", "stmt", stmt_buf, K(row), K(fk_arg));
|
||||||
SMART_VAR(ObMySQLProxy::MySQLResult, res) {
|
SMART_VAR(ObMySQLProxy::MySQLResult, res) {
|
||||||
if (OB_FAIL(op.begin_nested_session(fk_arg.is_self_ref_))) {
|
if (OB_FAIL(op.begin_nested_session(fk_arg.is_self_ref_))) {
|
||||||
@ -282,14 +293,16 @@ int ForeignKeyHandle::check_exist_inner_sql(ObTableModifyOp &op,
|
|||||||
* is true, then is_zero is false, need to exclude the case of self reference and
|
* is true, then is_zero is false, need to exclude the case of self reference and
|
||||||
* only affect one row. other cases return OB_ERR_ROW_IS_REFERENCED.
|
* only affect one row. other cases return OB_ERR_ROW_IS_REFERENCED.
|
||||||
*/
|
*/
|
||||||
if (OB_FAIL(is_self_ref_row(op.get_eval_ctx(), row, fk_arg, is_self_ref))) {
|
if (!iter_uncommitted_row) {
|
||||||
LOG_WARN("is_self_ref_row failed", K(ret), K(row), K(fk_arg));
|
if (OB_FAIL(is_self_ref_row(op.get_eval_ctx(), row, fk_arg, is_self_ref))) {
|
||||||
} else if (is_zero && !is_self_ref) {
|
LOG_WARN("is_self_ref_row failed", K(ret), K(row), K(fk_arg));
|
||||||
ret = OB_ERR_NO_REFERENCED_ROW;
|
} else if (is_zero && !is_self_ref) {
|
||||||
LOG_WARN("parent row is not exist", K(ret), K(fk_arg), K(row));
|
ret = OB_ERR_NO_REFERENCED_ROW;
|
||||||
} else if (!is_zero) {
|
LOG_WARN("parent row is not exist", K(ret), K(fk_arg), K(row));
|
||||||
ret = OB_ERR_ROW_IS_REFERENCED;
|
} else if (!is_zero) {
|
||||||
LOG_WARN("child row is exist", K(ret), K(fk_arg), K(row));
|
ret = OB_ERR_ROW_IS_REFERENCED;
|
||||||
|
LOG_WARN("child row is exist", K(ret), K(fk_arg), K(row));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,6 +331,8 @@ int ForeignKeyHandle::check_exist_inner_sql(ObTableModifyOp &op,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
op.get_exec_ctx().get_das_ctx().iter_uncommitted_row_ = false;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1293,6 +1308,7 @@ int ObTableModifyOp::inner_get_next_row()
|
|||||||
|
|
||||||
int ObTableModifyOp::perform_batch_fk_check()
|
int ObTableModifyOp::perform_batch_fk_check()
|
||||||
{
|
{
|
||||||
|
DEBUG_SYNC(BEFORE_FOREIGN_KEY_CONSTRAINT_CHECK);
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
for (int64_t i = 0; OB_SUCC(ret) && i < fk_checkers_.count(); ++i) {
|
for (int64_t i = 0; OB_SUCC(ret) && i < fk_checkers_.count(); ++i) {
|
||||||
bool all_has_result = false;
|
bool all_has_result = false;
|
||||||
|
@ -51,12 +51,12 @@ private:
|
|||||||
static int check_exist_inner_sql(ObTableModifyOp &modify_op,
|
static int check_exist_inner_sql(ObTableModifyOp &modify_op,
|
||||||
const ObForeignKeyArg &fk_arg,
|
const ObForeignKeyArg &fk_arg,
|
||||||
const ObExprPtrIArray &row,
|
const ObExprPtrIArray &row,
|
||||||
bool expect_zero);
|
bool expect_zero,
|
||||||
|
bool iter_uncommitted_row);
|
||||||
static int check_exist_scan_task(ObTableModifyOp &modify_op,
|
static int check_exist_scan_task(ObTableModifyOp &modify_op,
|
||||||
const ObForeignKeyArg &fk_arg,
|
const ObForeignKeyArg &fk_arg,
|
||||||
const ObExprPtrIArray &row,
|
const ObExprPtrIArray &row,
|
||||||
ObForeignKeyChecker *fk_checker,
|
ObForeignKeyChecker *fk_checker);
|
||||||
bool expect_zero);
|
|
||||||
static int cascade(ObTableModifyOp &modify_op, const ObForeignKeyArg &fk_arg,
|
static int cascade(ObTableModifyOp &modify_op, const ObForeignKeyArg &fk_arg,
|
||||||
const ObExprPtrIArray &old_row, const ObExprPtrIArray &new_row);
|
const ObExprPtrIArray &old_row, const ObExprPtrIArray &new_row);
|
||||||
|
|
||||||
|
@ -890,7 +890,9 @@ OB_INLINE int ObTableScanOp::init_das_scan_rtdef(const ObDASScanCtDef &das_ctdef
|
|||||||
das_rtdef.scan_flag_.is_show_seed_ = plan_ctx->get_show_seed();
|
das_rtdef.scan_flag_.is_show_seed_ = plan_ctx->get_show_seed();
|
||||||
if(is_foreign_check_nested_session()) {
|
if(is_foreign_check_nested_session()) {
|
||||||
das_rtdef.is_for_foreign_check_ = true;
|
das_rtdef.is_for_foreign_check_ = true;
|
||||||
das_rtdef.scan_flag_.set_for_foreign_key_check();
|
if (plan_ctx->get_phy_plan()->has_for_update() && ObSQLUtils::is_iter_uncommitted_row(&ctx_)) {
|
||||||
|
das_rtdef.scan_flag_.set_iter_uncommitted_row();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (MY_SPEC.batch_scan_flag_ || is_lookup) {
|
if (MY_SPEC.batch_scan_flag_ || is_lookup) {
|
||||||
das_rtdef.scan_flag_.scan_order_ = ObQueryFlag::KeepOrder;
|
das_rtdef.scan_flag_.scan_order_ = ObQueryFlag::KeepOrder;
|
||||||
|
@ -4437,6 +4437,17 @@ bool ObSQLUtils::is_fk_nested_sql(ObExecContext *cur_ctx)
|
|||||||
return bret;
|
return bret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ObSQLUtils::is_iter_uncommitted_row(ObExecContext *cur_ctx)
|
||||||
|
{
|
||||||
|
bool bret = false;
|
||||||
|
if (cur_ctx != nullptr &&
|
||||||
|
cur_ctx->get_parent_ctx() != nullptr &&
|
||||||
|
cur_ctx->get_parent_ctx()->get_das_ctx().iter_uncommitted_row_) {
|
||||||
|
bret = true;
|
||||||
|
}
|
||||||
|
return bret;
|
||||||
|
}
|
||||||
|
|
||||||
//notice: if a SQL is triggered by a PL defined as an autonomous transaction,
|
//notice: if a SQL is triggered by a PL defined as an autonomous transaction,
|
||||||
//then it is not nested sql, nor is it restricted by the constraints of nested sql
|
//then it is not nested sql, nor is it restricted by the constraints of nested sql
|
||||||
bool ObSQLUtils::is_nested_sql(ObExecContext *cur_ctx)
|
bool ObSQLUtils::is_nested_sql(ObExecContext *cur_ctx)
|
||||||
|
@ -577,6 +577,7 @@ public:
|
|||||||
static bool is_support_batch_exec(ObItemType type);
|
static bool is_support_batch_exec(ObItemType type);
|
||||||
static bool is_pl_nested_sql(ObExecContext *cur_ctx);
|
static bool is_pl_nested_sql(ObExecContext *cur_ctx);
|
||||||
static bool is_fk_nested_sql(ObExecContext *cur_ctx);
|
static bool is_fk_nested_sql(ObExecContext *cur_ctx);
|
||||||
|
static bool is_iter_uncommitted_row(ObExecContext *cur_ctx);
|
||||||
static bool is_nested_sql(ObExecContext *cur_ctx);
|
static bool is_nested_sql(ObExecContext *cur_ctx);
|
||||||
static bool is_select_from_dual(ObExecContext &ctx);
|
static bool is_select_from_dual(ObExecContext &ctx);
|
||||||
|
|
||||||
|
@ -3486,6 +3486,9 @@ int ObLSTabletService::need_check_old_row_legitimacy(ObDMLRunningCtx &run_ctx,
|
|||||||
//index can not be read during building index, so does not check old index row
|
//index can not be read during building index, so does not check old index row
|
||||||
need_check = false;
|
need_check = false;
|
||||||
}
|
}
|
||||||
|
if (ObDmlFlag::DF_LOCK == run_ctx.dml_flag_) {
|
||||||
|
need_check = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ int ObMvccEngine::get(ObMvccAccessCtx &ctx,
|
|||||||
TRANS_LOG(WARN, "fail to try to compact row", K(tmp_ret));
|
TRANS_LOG(WARN, "fail to try to compact row", K(tmp_ret));
|
||||||
}
|
}
|
||||||
} else if (query_flag.is_for_foreign_key_check()) {
|
} else if (query_flag.is_for_foreign_key_check()) {
|
||||||
ret = ObRowConflictHandler::check_foreign_key_constraint_for_memtable(&ctx, value, lock_state);
|
ret = ObRowConflictHandler::check_foreign_key_constraint_for_memtable(ctx, value, lock_state);
|
||||||
} else {
|
} else {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
@ -56,15 +56,13 @@ int ObMvccValueIterator::init(ObMvccAccessCtx &ctx,
|
|||||||
is_inited_ = true;
|
is_inited_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TRANS_LOG(TRACE, "value_iter.init", K(ret),
|
TRANS_LOG(TRACE, "value_iter.init", K(ret),
|
||||||
KPC(value),
|
KPC(value),
|
||||||
KPC_(version_iter),
|
KPC_(version_iter),
|
||||||
K(query_flag.is_read_latest()),
|
K(query_flag.is_read_latest()),
|
||||||
KPC(key),
|
KPC(key),
|
||||||
K(ctx),
|
K(ctx),
|
||||||
K(lbt()));
|
K(lbt()));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,7 +418,7 @@ int ObMvccRowIterator::get_next_row(
|
|||||||
TRANS_LOG(ERROR, "unexpected value null pointer", "ctx", *ctx_);
|
TRANS_LOG(ERROR, "unexpected value null pointer", "ctx", *ctx_);
|
||||||
ret = OB_ERR_UNEXPECTED;
|
ret = OB_ERR_UNEXPECTED;
|
||||||
} else if (query_flag_.is_for_foreign_key_check()) {
|
} else if (query_flag_.is_for_foreign_key_check()) {
|
||||||
if (OB_FAIL(ObRowConflictHandler::check_foreign_key_constraint_for_memtable(ctx_, value, lock_state))) {
|
if (OB_FAIL(ObRowConflictHandler::check_foreign_key_constraint_for_memtable(*ctx_, value, lock_state))) {
|
||||||
// we will throw error code if it's failed here, but we need to
|
// we will throw error code if it's failed here, but we need to
|
||||||
// post lock with key outside, so we have to set it here.
|
// post lock with key outside, so we have to set it here.
|
||||||
key = tmp_key;
|
key = tmp_key;
|
||||||
@ -498,4 +496,3 @@ int ObMvccRowIterator::try_purge(const ObTxSnapshot &snapshot_info,
|
|||||||
|
|
||||||
} // namespace memtable
|
} // namespace memtable
|
||||||
} // namespace oceanbase
|
} // namespace oceanbase
|
||||||
|
|
||||||
|
@ -30,7 +30,8 @@ struct ObWriteFlag
|
|||||||
#define OBWF_BIT_DML_BATCH_OPT 1
|
#define OBWF_BIT_DML_BATCH_OPT 1
|
||||||
#define OBWF_BIT_INSERT_UP 1
|
#define OBWF_BIT_INSERT_UP 1
|
||||||
#define OBWF_BIT_WRITE_ONLY_INDEX 1
|
#define OBWF_BIT_WRITE_ONLY_INDEX 1
|
||||||
#define OBWF_BIT_RESERVED 61
|
#define OBWF_BIT_CHECK_ROW_LOCKED 1
|
||||||
|
#define OBWF_BIT_RESERVED 57
|
||||||
|
|
||||||
static const uint64_t OBWF_MASK_TABLE_API = (0x1UL << OBWF_BIT_TABLE_API) - 1;
|
static const uint64_t OBWF_MASK_TABLE_API = (0x1UL << OBWF_BIT_TABLE_API) - 1;
|
||||||
static const uint64_t OBWF_MASK_TABLE_LOCK = (0x1UL << OBWF_BIT_TABLE_LOCK) - 1;
|
static const uint64_t OBWF_MASK_TABLE_LOCK = (0x1UL << OBWF_BIT_TABLE_LOCK) - 1;
|
||||||
@ -38,6 +39,7 @@ struct ObWriteFlag
|
|||||||
static const uint64_t OBWF_MASK_DML_BATCH_OPT = (0x1UL << OBWF_BIT_DML_BATCH_OPT) - 1;
|
static const uint64_t OBWF_MASK_DML_BATCH_OPT = (0x1UL << OBWF_BIT_DML_BATCH_OPT) - 1;
|
||||||
static const uint64_t OBWF_MASK_INSERT_UP = (0x1UL << OBWF_BIT_INSERT_UP) - 1;
|
static const uint64_t OBWF_MASK_INSERT_UP = (0x1UL << OBWF_BIT_INSERT_UP) - 1;
|
||||||
static const uint64_t OBWF_MASK_WRITE_ONLY_INDEX = (0x1UL << OBWF_BIT_WRITE_ONLY_INDEX) - 1;
|
static const uint64_t OBWF_MASK_WRITE_ONLY_INDEX = (0x1UL << OBWF_BIT_WRITE_ONLY_INDEX) - 1;
|
||||||
|
static const uint64_t OBWF_MASK_CHECK_ROW_LOCKED = (0x1UL << OBWF_BIT_CHECK_ROW_LOCKED) - 1;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@ -50,6 +52,7 @@ struct ObWriteFlag
|
|||||||
uint64_t is_dml_batch_opt_ : OBWF_BIT_DML_BATCH_OPT; // 0: false(default), 1: true
|
uint64_t is_dml_batch_opt_ : OBWF_BIT_DML_BATCH_OPT; // 0: false(default), 1: true
|
||||||
uint64_t is_insert_up_ : OBWF_BIT_INSERT_UP; // 0: false(default), 1: true
|
uint64_t is_insert_up_ : OBWF_BIT_INSERT_UP; // 0: false(default), 1: true
|
||||||
uint64_t is_write_only_index_ : OBWF_BIT_WRITE_ONLY_INDEX; // 0: false(default), 1: true
|
uint64_t is_write_only_index_ : OBWF_BIT_WRITE_ONLY_INDEX; // 0: false(default), 1: true
|
||||||
|
uint64_t is_check_row_locked_ : OBWF_BIT_CHECK_ROW_LOCKED; // 0: false(default), 1: true
|
||||||
uint64_t reserved_ : OBWF_BIT_RESERVED;
|
uint64_t reserved_ : OBWF_BIT_RESERVED;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -68,13 +71,16 @@ struct ObWriteFlag
|
|||||||
inline void set_is_insert_up() { is_insert_up_ = true; }
|
inline void set_is_insert_up() { is_insert_up_ = true; }
|
||||||
inline bool is_write_only_index() const { return is_write_only_index_; }
|
inline bool is_write_only_index() const { return is_write_only_index_; }
|
||||||
inline void set_is_write_only_index() { is_write_only_index_ = true; }
|
inline void set_is_write_only_index() { is_write_only_index_ = true; }
|
||||||
|
inline bool is_check_row_locked() const { return is_check_row_locked_; }
|
||||||
|
inline void set_check_row_locked() { is_check_row_locked_ = true; }
|
||||||
|
|
||||||
TO_STRING_KV("is_table_api", is_table_api_,
|
TO_STRING_KV("is_table_api", is_table_api_,
|
||||||
"is_table_lock", is_table_lock_,
|
"is_table_lock", is_table_lock_,
|
||||||
"is_mds", is_mds_,
|
"is_mds", is_mds_,
|
||||||
"is_dml_batch_opt", is_dml_batch_opt_,
|
"is_dml_batch_opt", is_dml_batch_opt_,
|
||||||
"is_insert_up", is_insert_up_,
|
"is_insert_up", is_insert_up_,
|
||||||
"is_write_only_index", is_write_only_index_);
|
"is_write_only_index", is_write_only_index_,
|
||||||
|
"is_check_row_locked", is_check_row_locked_);
|
||||||
|
|
||||||
OB_UNIS_VERSION(1);
|
OB_UNIS_VERSION(1);
|
||||||
};
|
};
|
||||||
|
@ -464,94 +464,6 @@ int ObMemtable::lock(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ObMemtable::check_row_locked_by_myself(
|
|
||||||
const storage::ObTableIterParam ¶m,
|
|
||||||
storage::ObTableAccessContext &context,
|
|
||||||
const blocksstable::ObDatumRowkey &rowkey,
|
|
||||||
bool &locked)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
ObMemtableKey mtk;
|
|
||||||
ObMvccWriteGuard guard;
|
|
||||||
ObStoreCtx *ctx = context.store_ctx_;
|
|
||||||
|
|
||||||
if (IS_NOT_INIT) {
|
|
||||||
TRANS_LOG(WARN, "not init", K(*this));
|
|
||||||
ret = OB_NOT_INIT;
|
|
||||||
} else if (!ctx->mvcc_acc_ctx_.is_write() || !rowkey.is_memtable_valid()) {
|
|
||||||
ret = OB_INVALID_ARGUMENT;
|
|
||||||
TRANS_LOG(WARN, "invalid param", K(ret), KP(ctx), K(rowkey));
|
|
||||||
} else if (OB_ISNULL(ctx->table_iter_)) {
|
|
||||||
ret = OB_ERR_UNEXPECTED;
|
|
||||||
TRANS_LOG(ERROR, "tables handle or iterator in context is null", K(ret), K(ctx));
|
|
||||||
} else if (OB_FAIL(guard.write_auth(*ctx))) {
|
|
||||||
TRANS_LOG(WARN, "not allow to write", KP(ctx));
|
|
||||||
} else if (OB_FAIL(mtk.encode(param.get_read_info()->get_columns_desc(), &rowkey.get_store_rowkey()))) {
|
|
||||||
TRANS_LOG(WARN, "mtk encode fail", "ret", ret);
|
|
||||||
} else {
|
|
||||||
bool is_locked = false;
|
|
||||||
bool tmp_is_locked = false;
|
|
||||||
ObStoreRowLockState lock_state;
|
|
||||||
const ObIArray<ObITable *> *stores = nullptr;
|
|
||||||
common::ObSEArray<ObITable *, 4> iter_tables;
|
|
||||||
ctx->table_iter_->resume();
|
|
||||||
ObTransID my_tx_id = ctx->mvcc_acc_ctx_.get_tx_id();
|
|
||||||
while (OB_SUCC(ret)) {
|
|
||||||
ObITable *table_ptr = nullptr;
|
|
||||||
if (OB_FAIL(ctx->table_iter_->get_next(table_ptr))) {
|
|
||||||
if (OB_ITER_END != ret) {
|
|
||||||
TRANS_LOG(WARN, "failed to get next tables", K(ret));
|
|
||||||
}
|
|
||||||
} else if (OB_ISNULL(table_ptr)) {
|
|
||||||
ret = OB_ERR_UNEXPECTED;
|
|
||||||
TRANS_LOG(WARN, "table must not be null", K(ret), KPC(ctx->table_iter_));
|
|
||||||
} else if (OB_FAIL(iter_tables.push_back(table_ptr))) {
|
|
||||||
TRANS_LOG(WARN, "rowkey_exists check::", K(ret), KPC(table_ptr));
|
|
||||||
}
|
|
||||||
} // end while
|
|
||||||
if (OB_ITER_END == ret) {
|
|
||||||
ret = OB_SUCCESS;
|
|
||||||
}
|
|
||||||
if (OB_SUCC(ret)) {
|
|
||||||
stores = &iter_tables;
|
|
||||||
for (int64_t i = stores->count() - 1; OB_SUCC(ret) && !is_locked && i >= 0; i--) {
|
|
||||||
lock_state.reset();
|
|
||||||
if (NULL == stores->at(i)) {
|
|
||||||
ret = OB_ERR_UNEXPECTED;
|
|
||||||
TRANS_LOG(WARN, "ObIStore is null", K(ret), K(i));
|
|
||||||
} else if (stores->at(i)->is_data_memtable()) {
|
|
||||||
ObMemtable *memtable = static_cast<ObMemtable *>(stores->at(i));
|
|
||||||
if (OB_FAIL(memtable->get_mvcc_engine().check_row_locked(ctx->mvcc_acc_ctx_,
|
|
||||||
&mtk,
|
|
||||||
lock_state))) {
|
|
||||||
TRANS_LOG(WARN, "mvcc engine check row lock fail", K(ret), K(mtk));
|
|
||||||
} else if (lock_state.is_locked_ && lock_state.lock_trans_id_ == my_tx_id) {
|
|
||||||
is_locked = true;
|
|
||||||
}
|
|
||||||
} else if (stores->at(i)->is_sstable()) {
|
|
||||||
ObSSTable *sstable = static_cast<ObSSTable *>(stores->at(i));
|
|
||||||
if (OB_FAIL(sstable->check_row_locked(param, context, rowkey, lock_state))) {
|
|
||||||
TRANS_LOG(WARN, "sstable check row lock fail", K(ret), K(rowkey));
|
|
||||||
} else if (lock_state.is_locked_ && lock_state.lock_trans_id_ == my_tx_id) {
|
|
||||||
is_locked = true;
|
|
||||||
}
|
|
||||||
TRANS_LOG(DEBUG, "check_row_locked meet sstable",
|
|
||||||
K(ret), K(rowkey), K(*sstable), K(is_locked));
|
|
||||||
} else {
|
|
||||||
ret = OB_ERR_UNEXPECTED;
|
|
||||||
TRANS_LOG(ERROR, "unknown store type", K(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (OB_SUCC(ret)) {
|
|
||||||
locked = is_locked;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
void ObMemtable::get_begin(ObMvccAccessCtx &ctx)
|
void ObMemtable::get_begin(ObMvccAccessCtx &ctx)
|
||||||
{
|
{
|
||||||
@ -1115,13 +1027,12 @@ int ObMemtable::replay_row(ObStoreCtx &ctx,
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int ObMemtable::lock_row_on_frozen_stores_(
|
int ObMemtable::lock_row_on_frozen_stores_(const storage::ObTableIterParam ¶m,
|
||||||
const storage::ObTableIterParam ¶m,
|
const ObTxNodeArg &arg,
|
||||||
const ObTxNodeArg &arg,
|
storage::ObTableAccessContext &context,
|
||||||
storage::ObTableAccessContext &context,
|
const ObMemtableKey *key,
|
||||||
const ObMemtableKey *key,
|
ObMvccRow *value,
|
||||||
ObMvccRow *value,
|
ObMvccWriteResult &res)
|
||||||
ObMvccWriteResult &res)
|
|
||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
ObStoreRowLockState &lock_state = res.lock_state_;
|
ObStoreRowLockState &lock_state = res.lock_state_;
|
||||||
@ -2732,7 +2643,6 @@ int ObMemtable::set_(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ObMemtable::lock_(
|
int ObMemtable::lock_(
|
||||||
const storage::ObTableIterParam ¶m,
|
const storage::ObTableIterParam ¶m,
|
||||||
storage::ObTableAccessContext &context,
|
storage::ObTableAccessContext &context,
|
||||||
@ -2751,24 +2661,26 @@ int ObMemtable::lock_(
|
|||||||
TRANS_LOG(WARN, "Failed to writer rowkey", K(ret), K(rowkey));
|
TRANS_LOG(WARN, "Failed to writer rowkey", K(ret), K(rowkey));
|
||||||
} else {
|
} else {
|
||||||
ObMemtableData mtd(blocksstable::ObDmlFlag::DF_LOCK, len, buf);
|
ObMemtableData mtd(blocksstable::ObDmlFlag::DF_LOCK, len, buf);
|
||||||
ObTxNodeArg arg(&mtd, /*memtable_data*/
|
ObTxNodeArg arg(&mtd, /*memtable_data*/
|
||||||
NULL, /*old_data*/
|
NULL, /*old_data*/
|
||||||
timestamp_, /*memstore_version*/
|
timestamp_, /*memstore_version*/
|
||||||
context.store_ctx_->mvcc_acc_ctx_.tx_scn_, /*seq_no*/
|
context.store_ctx_->mvcc_acc_ctx_.tx_scn_, /*seq_no*/
|
||||||
rowkey.get_obj_cnt() /*column_cnt*/);
|
rowkey.get_obj_cnt()); /*column_cnt*/
|
||||||
if (OB_FAIL(mvcc_write_(param, context, &mtk, arg, is_new_locked))) {
|
if (context.store_ctx_->mvcc_acc_ctx_.write_flag_.is_check_row_locked()) {
|
||||||
} else if (OB_UNLIKELY(!is_new_locked)) {
|
if (OB_FAIL(ObRowConflictHandler::check_foreign_key_constraint(param, context, rowkey))) {
|
||||||
TRANS_LOG(DEBUG, "lock twice, no need to store lock trans node");
|
if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_TRANSACTION_SET_VIOLATION != ret) {
|
||||||
}
|
TRANS_LOG(WARN, "meet unexpected return code in check_row_locked", K(ret), K(context), K(mtk));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (OB_FAIL(mvcc_write_(param, context, &mtk, arg, is_new_locked))) {
|
||||||
|
} else if (OB_UNLIKELY(!is_new_locked)) {
|
||||||
|
TRANS_LOG(DEBUG, "lock twice, no need to store lock trans node");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int ObMemtable::mvcc_replay_(storage::ObStoreCtx &ctx,
|
int ObMemtable::mvcc_replay_(storage::ObStoreCtx &ctx,
|
||||||
const ObMemtableKey *key,
|
const ObMemtableKey *key,
|
||||||
const ObTxNodeArg &arg)
|
const ObTxNodeArg &arg)
|
||||||
|
@ -290,18 +290,6 @@ public:
|
|||||||
virtual int replay_schema_version_change_log(
|
virtual int replay_schema_version_change_log(
|
||||||
const int64_t schema_version);
|
const int64_t schema_version);
|
||||||
|
|
||||||
// check_row_locked_by_myself check whether lock is locked by myself
|
|
||||||
// ctx is the locker tx's context, we need the tx_id for check
|
|
||||||
// tablet_id is necessary for the query_engine's key engine(NB: do we need it now?)
|
|
||||||
// columns is the schema of the new_row, it contains the row key
|
|
||||||
// rowkey is the row key used for lock
|
|
||||||
// locked returns whether lock is locked by myself
|
|
||||||
int check_row_locked_by_myself(
|
|
||||||
const storage::ObTableIterParam ¶m,
|
|
||||||
storage::ObTableAccessContext &context,
|
|
||||||
const blocksstable::ObDatumRowkey &rowkey,
|
|
||||||
bool &locked);
|
|
||||||
|
|
||||||
// // TODO: ==================== Memtable Other Interface ==================
|
// // TODO: ==================== Memtable Other Interface ==================
|
||||||
int set_freezer(storage::ObFreezer *handler);
|
int set_freezer(storage::ObFreezer *handler);
|
||||||
storage::ObFreezer *get_freezer() { return freezer_; }
|
storage::ObFreezer *get_freezer() { return freezer_; }
|
||||||
@ -509,7 +497,6 @@ private:
|
|||||||
int mvcc_replay_(storage::ObStoreCtx &ctx,
|
int mvcc_replay_(storage::ObStoreCtx &ctx,
|
||||||
const ObMemtableKey *key,
|
const ObMemtableKey *key,
|
||||||
const ObTxNodeArg &arg);
|
const ObTxNodeArg &arg);
|
||||||
|
|
||||||
int lock_row_on_frozen_stores_(
|
int lock_row_on_frozen_stores_(
|
||||||
const storage::ObTableIterParam ¶m,
|
const storage::ObTableIterParam ¶m,
|
||||||
const ObTxNodeArg &arg,
|
const ObTxNodeArg &arg,
|
||||||
@ -542,8 +529,6 @@ private:
|
|||||||
storage::ObTableAccessContext &context,
|
storage::ObTableAccessContext &context,
|
||||||
const common::ObStoreRowkey &rowkey);
|
const common::ObStoreRowkey &rowkey);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int post_row_write_conflict_(ObMvccAccessCtx &acc_ctx,
|
int post_row_write_conflict_(ObMvccAccessCtx &acc_ctx,
|
||||||
const ObMemtableKey &row_key,
|
const ObMemtableKey &row_key,
|
||||||
storage::ObStoreRowLockState &lock_state,
|
storage::ObStoreRowLockState &lock_state,
|
||||||
|
@ -1439,7 +1439,8 @@ OB_INLINE int ObReadRow::iterate_row_value_(
|
|||||||
const ObTransID reader_tx_id = value_iter.get_reader_tx_id();
|
const ObTransID reader_tx_id = value_iter.get_reader_tx_id();
|
||||||
share::SCN row_version = tx_node->trans_version_;
|
share::SCN row_version = tx_node->trans_version_;
|
||||||
row_scn = row_version.get_val_for_tx();
|
row_scn = row_version.get_val_for_tx();
|
||||||
if (!value_iter.get_mvcc_acc_ctx()->is_standby_read_
|
if (!row.is_have_uncommited_row() &&
|
||||||
|
!value_iter.get_mvcc_acc_ctx()->is_standby_read_
|
||||||
&& !(snapshot_tx_id == tx_node->get_tx_id() || reader_tx_id == tx_node->get_tx_id())
|
&& !(snapshot_tx_id == tx_node->get_tx_id() || reader_tx_id == tx_node->get_tx_id())
|
||||||
&& row_version.is_max()) {
|
&& row_version.is_max()) {
|
||||||
TRANS_LOG(ERROR, "meet row scn with undecided value", KPC(tx_node),
|
TRANS_LOG(ERROR, "meet row scn with undecided value", KPC(tx_node),
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
*/
|
*/
|
||||||
#define USING_LOG_PREFIX TRANS
|
#define USING_LOG_PREFIX TRANS
|
||||||
#include "ob_row_conflict_handler.h"
|
#include "ob_row_conflict_handler.h"
|
||||||
|
#include "storage/memtable/ob_memtable.h"
|
||||||
|
#include "storage/blocksstable/ob_sstable.h"
|
||||||
#include "storage/memtable/mvcc/ob_mvcc_iterator.h"
|
#include "storage/memtable/mvcc/ob_mvcc_iterator.h"
|
||||||
#include "storage/memtable/ob_lock_wait_mgr.h"
|
#include "storage/memtable/ob_lock_wait_mgr.h"
|
||||||
#include "storage/tx_table/ob_tx_table_guards.h"
|
#include "storage/tx_table/ob_tx_table_guards.h"
|
||||||
@ -20,19 +22,166 @@ using namespace common;
|
|||||||
using namespace memtable;
|
using namespace memtable;
|
||||||
using namespace transaction;
|
using namespace transaction;
|
||||||
namespace storage {
|
namespace storage {
|
||||||
int ObRowConflictHandler::check_foreign_key_constraint_for_memtable(ObMvccAccessCtx *ctx,
|
int ObRowConflictHandler::check_row_locked(const storage::ObTableIterParam ¶m,
|
||||||
ObMvccRow *row,
|
storage::ObTableAccessContext &context,
|
||||||
|
const blocksstable::ObDatumRowkey &rowkey,
|
||||||
|
const bool by_myself,
|
||||||
|
const bool post_lock)
|
||||||
|
{
|
||||||
|
int ret = OB_SUCCESS;
|
||||||
|
ObStoreRowLockState lock_state;
|
||||||
|
ObMvccAccessCtx acc_ctx = context.store_ctx_->mvcc_acc_ctx_;
|
||||||
|
share::SCN max_trans_version = share::SCN::min_scn();
|
||||||
|
const ObTransID my_tx_id = acc_ctx.get_tx_id();
|
||||||
|
const share::SCN snapshot_version = acc_ctx.get_snapshot_version();
|
||||||
|
|
||||||
|
if (OB_FAIL(check_row_locked(param, context, rowkey, lock_state, max_trans_version))) {
|
||||||
|
LOG_WARN("check row locked failed", K(ret), K(context), K(rowkey));
|
||||||
|
} else {
|
||||||
|
if (lock_state.is_locked_) {
|
||||||
|
if ((by_myself && lock_state.lock_trans_id_ == my_tx_id)
|
||||||
|
|| (!by_myself && lock_state.lock_trans_id_ != my_tx_id)) {
|
||||||
|
ret = OB_TRY_LOCK_ROW_CONFLICT;
|
||||||
|
if (post_lock) {
|
||||||
|
post_row_read_conflict(acc_ctx,
|
||||||
|
rowkey.get_store_rowkey(),
|
||||||
|
lock_state,
|
||||||
|
context.tablet_id_,
|
||||||
|
context.ls_id_,
|
||||||
|
0,
|
||||||
|
0, /* these two params get from mvcc_row, and for statistics, so we ignore them */
|
||||||
|
lock_state.trans_scn_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (max_trans_version > snapshot_version) {
|
||||||
|
ret = OB_TRANSACTION_SET_VIOLATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ObRowConflictHandler::check_row_locked(const storage::ObTableIterParam ¶m,
|
||||||
|
storage::ObTableAccessContext &context,
|
||||||
|
const blocksstable::ObDatumRowkey &rowkey,
|
||||||
|
ObStoreRowLockState &lock_state,
|
||||||
|
share::SCN &max_trans_version)
|
||||||
|
{
|
||||||
|
int ret = OB_SUCCESS;
|
||||||
|
ObMemtableKey mtk;
|
||||||
|
ObMvccWriteGuard guard;
|
||||||
|
ObStoreCtx *ctx = context.store_ctx_;
|
||||||
|
|
||||||
|
if (!ctx->mvcc_acc_ctx_.is_write() || !rowkey.is_memtable_valid()) {
|
||||||
|
ret = OB_INVALID_ARGUMENT;
|
||||||
|
TRANS_LOG(WARN, "invalid param", K(ret), KP(ctx), K(rowkey));
|
||||||
|
} else if (OB_ISNULL(ctx->table_iter_)) {
|
||||||
|
ret = OB_ERR_UNEXPECTED;
|
||||||
|
TRANS_LOG(ERROR, "tables handle or iterator in context is null", K(ret), K(ctx));
|
||||||
|
} else if (OB_FAIL(guard.write_auth(*ctx))) {
|
||||||
|
TRANS_LOG(WARN, "not allow to write", KP(ctx));
|
||||||
|
} else if (OB_FAIL(mtk.encode(param.get_read_info()->get_columns_desc(), &rowkey.get_store_rowkey()))) {
|
||||||
|
TRANS_LOG(WARN, "mtk encode fail", "ret", ret);
|
||||||
|
} else {
|
||||||
|
const ObIArray<ObITable *> *stores = nullptr;
|
||||||
|
common::ObSEArray<ObITable *, 4> iter_tables;
|
||||||
|
ctx->table_iter_->resume();
|
||||||
|
while (OB_SUCC(ret)) {
|
||||||
|
ObITable *table_ptr = nullptr;
|
||||||
|
if (OB_FAIL(ctx->table_iter_->get_next(table_ptr))) {
|
||||||
|
if (OB_ITER_END != ret) {
|
||||||
|
TRANS_LOG(WARN, "failed to get next tables", K(ret));
|
||||||
|
}
|
||||||
|
} else if (OB_ISNULL(table_ptr)) {
|
||||||
|
ret = OB_ERR_UNEXPECTED;
|
||||||
|
TRANS_LOG(WARN, "table must not be null", K(ret), KPC(ctx->table_iter_));
|
||||||
|
} else if (OB_FAIL(iter_tables.push_back(table_ptr))) {
|
||||||
|
TRANS_LOG(WARN, "rowkey_exists check::", K(ret), KPC(table_ptr));
|
||||||
|
}
|
||||||
|
} // end while
|
||||||
|
if (OB_ITER_END == ret) {
|
||||||
|
ret = OB_SUCCESS;
|
||||||
|
}
|
||||||
|
if (OB_SUCC(ret)) {
|
||||||
|
share::SCN snapshot_version = ctx->mvcc_acc_ctx_.get_snapshot_version();
|
||||||
|
stores = &iter_tables;
|
||||||
|
for (int64_t i = stores->count() - 1; OB_SUCC(ret) && i >= 0; i--) {
|
||||||
|
lock_state.reset();
|
||||||
|
if (NULL == stores->at(i)) {
|
||||||
|
ret = OB_ERR_UNEXPECTED;
|
||||||
|
TRANS_LOG(WARN, "ObIStore is null", K(ret), K(i));
|
||||||
|
} else if (stores->at(i)->is_data_memtable()) {
|
||||||
|
ObMemtable *memtable = static_cast<ObMemtable *>(stores->at(i));
|
||||||
|
if (OB_FAIL(memtable->get_mvcc_engine().check_row_locked(ctx->mvcc_acc_ctx_, &mtk, lock_state))) {
|
||||||
|
TRANS_LOG(WARN, "mvcc engine check row lock fail", K(ret), K(mtk));
|
||||||
|
}
|
||||||
|
} else if (stores->at(i)->is_sstable()) {
|
||||||
|
blocksstable::ObSSTable *sstable = static_cast<blocksstable::ObSSTable *>(stores->at(i));
|
||||||
|
if (OB_FAIL(sstable->check_row_locked(param, context, rowkey, lock_state))) {
|
||||||
|
TRANS_LOG(WARN, "sstable check row lock fail", K(ret), K(rowkey));
|
||||||
|
}
|
||||||
|
TRANS_LOG(DEBUG, "check_row_locked meet sstable", K(ret), K(rowkey), K(*sstable));
|
||||||
|
} else {
|
||||||
|
ret = OB_ERR_UNEXPECTED;
|
||||||
|
TRANS_LOG(ERROR, "unknown store type", K(ret));
|
||||||
|
}
|
||||||
|
if (OB_SUCC(ret)) {
|
||||||
|
if (lock_state.is_locked_) {
|
||||||
|
break;
|
||||||
|
} else if (max_trans_version < lock_state.trans_version_) {
|
||||||
|
max_trans_version = lock_state.trans_version_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ObRowConflictHandler::check_foreign_key_constraint(const storage::ObTableIterParam ¶m,
|
||||||
|
storage::ObTableAccessContext &context,
|
||||||
|
const common::ObStoreRowkey &rowkey)
|
||||||
|
{
|
||||||
|
int ret = OB_SUCCESS;
|
||||||
|
ObMvccAccessCtx acc_ctx = context.store_ctx_->mvcc_acc_ctx_;
|
||||||
|
blocksstable::ObDatumRowkeyHelper rowkey_converter;
|
||||||
|
blocksstable::ObDatumRowkey datum_rowkey;
|
||||||
|
if (OB_FAIL(rowkey_converter.convert_datum_rowkey(rowkey.get_rowkey(), datum_rowkey))) {
|
||||||
|
STORAGE_LOG(WARN, "Failed to convert datum rowkey", K(ret), K(rowkey));
|
||||||
|
} else if (OB_FAIL(check_row_locked(param, context, datum_rowkey, false /* by_myself */, true /* post_lock */))) {
|
||||||
|
if (OB_TRY_LOCK_ROW_CONFLICT == ret) {
|
||||||
|
if (REACH_TIME_INTERVAL(1000 * 1000)) {
|
||||||
|
TRANS_LOG(
|
||||||
|
WARN, "meet lock conflict during check foreign key constraint", K(ret), K(acc_ctx.get_tx_id()), K(rowkey));
|
||||||
|
}
|
||||||
|
} else if (OB_TRANSACTION_SET_VIOLATION == ret) {
|
||||||
|
if (REACH_TIME_INTERVAL(1000 * 1000)) {
|
||||||
|
TRANS_LOG(WARN,
|
||||||
|
"meet tsc during check foreign key constraint",
|
||||||
|
K(ret),
|
||||||
|
K(acc_ctx.get_tx_id()),
|
||||||
|
K(acc_ctx.get_snapshot_version()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TRANS_LOG(WARN, "check row locked failed", K(param), K(context), K(rowkey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ObRowConflictHandler::check_foreign_key_constraint_for_memtable(ObMvccAccessCtx &ctx,
|
||||||
|
ObMvccRow *value,
|
||||||
ObStoreRowLockState &lock_state)
|
ObStoreRowLockState &lock_state)
|
||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
if (OB_ISNULL(row)) {
|
if (OB_ISNULL(value)) {
|
||||||
ret = OB_BAD_NULL_ERROR;
|
ret = OB_BAD_NULL_ERROR;
|
||||||
TRANS_LOG(ERROR, "the ObMvccValueIterator is null", K(ret));
|
TRANS_LOG(ERROR, "the ObMvccValueIterator is null", K(ret));
|
||||||
} else if (OB_FAIL(row->check_row_locked(*ctx, lock_state))) {
|
} else if (OB_FAIL(value->check_row_locked(ctx, lock_state))) {
|
||||||
TRANS_LOG(WARN, "check row locked fail", K(ret), K(lock_state));
|
TRANS_LOG(WARN, "check row locked fail", K(ret), K(lock_state));
|
||||||
} else {
|
} else {
|
||||||
const ObTransID my_tx_id = ctx->get_tx_id();
|
const ObTransID my_tx_id = ctx.get_tx_id();
|
||||||
const share::SCN snapshot_version = ctx->get_snapshot_version();
|
const share::SCN snapshot_version = ctx.get_snapshot_version();
|
||||||
if (lock_state.is_locked_ && my_tx_id != lock_state.lock_trans_id_) {
|
if (lock_state.is_locked_ && my_tx_id != lock_state.lock_trans_id_) {
|
||||||
ret = OB_TRY_LOCK_ROW_CONFLICT;
|
ret = OB_TRY_LOCK_ROW_CONFLICT;
|
||||||
if (REACH_TIME_INTERVAL(1000 * 1000)) {
|
if (REACH_TIME_INTERVAL(1000 * 1000)) {
|
||||||
@ -169,6 +318,5 @@ int ObRowConflictHandler::post_row_read_conflict(ObMvccAccessCtx &acc_ctx,
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
} // namespace storage
|
||||||
}
|
} // namespace oceanbase
|
||||||
}
|
|
||||||
|
@ -16,8 +16,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
namespace oceanbase {
|
namespace oceanbase {
|
||||||
namespace memtable {
|
namespace memtable {
|
||||||
|
class ObMvccRow;
|
||||||
class ObMvccAccessCtx;
|
class ObMvccAccessCtx;
|
||||||
class ObMvccRow;
|
class ObMvccRow;
|
||||||
|
class ObMvccValueIterator;
|
||||||
}
|
}
|
||||||
namespace transaction {
|
namespace transaction {
|
||||||
class ObTransID;
|
class ObTransID;
|
||||||
@ -32,12 +34,28 @@ namespace share {
|
|||||||
class ObLSID;
|
class ObLSID;
|
||||||
class SCN;
|
class SCN;
|
||||||
}
|
}
|
||||||
namespace storage {
|
namespace blocksstable {
|
||||||
|
class ObDatumRowkey;
|
||||||
|
}
|
||||||
|
namespace storage
|
||||||
|
{
|
||||||
|
class ObTableIterParam;
|
||||||
|
class ObTableAccessContext;
|
||||||
class ObStoreRowLockState;
|
class ObStoreRowLockState;
|
||||||
class ObTxTableGuards;
|
class ObTxTableGuards;
|
||||||
|
|
||||||
class ObRowConflictHandler {
|
class ObRowConflictHandler {
|
||||||
public:
|
public:
|
||||||
|
static int check_row_locked(const storage::ObTableIterParam ¶m,
|
||||||
|
storage::ObTableAccessContext &context,
|
||||||
|
const blocksstable::ObDatumRowkey &rowkey,
|
||||||
|
const bool by_myself = false,
|
||||||
|
const bool post_lock = false);
|
||||||
|
static int check_row_locked(const storage::ObTableIterParam ¶m,
|
||||||
|
storage::ObTableAccessContext &context,
|
||||||
|
const blocksstable::ObDatumRowkey &rowkey,
|
||||||
|
ObStoreRowLockState &lock_state,
|
||||||
|
share::SCN &max_trans_veresion);
|
||||||
// There are 2 cases that can lead to row conflict in foreign key constraint check:
|
// There are 2 cases that can lead to row conflict in foreign key constraint check:
|
||||||
// Case 1: the row is locked, mainly beacuse there's an uncommitted transaction on it.
|
// Case 1: the row is locked, mainly beacuse there's an uncommitted transaction on it.
|
||||||
// If the check meet this case, we should call post_row_read_conflict to put it into
|
// If the check meet this case, we should call post_row_read_conflict to put it into
|
||||||
@ -47,8 +65,11 @@ public:
|
|||||||
// snapshot_version of current transaction, it will cause tsc.
|
// snapshot_version of current transaction, it will cause tsc.
|
||||||
// If the check meet this case, we should return error code to sql layer, and it will
|
// If the check meet this case, we should return error code to sql layer, and it will
|
||||||
// choose to retry or throw an exception according to the isolation level.
|
// choose to retry or throw an exception according to the isolation level.
|
||||||
static int check_foreign_key_constraint_for_memtable(memtable::ObMvccAccessCtx *ctx,
|
static int check_foreign_key_constraint(const storage::ObTableIterParam ¶m,
|
||||||
memtable::ObMvccRow *row,
|
storage::ObTableAccessContext &context,
|
||||||
|
const common::ObStoreRowkey &rowkey);
|
||||||
|
static int check_foreign_key_constraint_for_memtable(memtable::ObMvccAccessCtx &acc_ctx,
|
||||||
|
memtable::ObMvccRow *value,
|
||||||
storage::ObStoreRowLockState &lock_state);
|
storage::ObStoreRowLockState &lock_state);
|
||||||
static int check_foreign_key_constraint_for_sstable(storage::ObTxTableGuards &tx_table_guards,
|
static int check_foreign_key_constraint_for_sstable(storage::ObTxTableGuards &tx_table_guards,
|
||||||
const transaction::ObTransID &read_trans_id,
|
const transaction::ObTransID &read_trans_id,
|
||||||
@ -71,6 +92,6 @@ public:
|
|||||||
const int64_t total_trans_node_cnt,
|
const int64_t total_trans_node_cnt,
|
||||||
const share::SCN &trans_scn);
|
const share::SCN &trans_scn);
|
||||||
};
|
};
|
||||||
}
|
} // namespace storage
|
||||||
}
|
} // namespace oceanbase
|
||||||
#endif
|
#endif
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
#include "storage/tx/ob_trans_service.h"
|
#include "storage/tx/ob_trans_service.h"
|
||||||
#include "storage/tx_storage/ob_ls_service.h"
|
#include "storage/tx_storage/ob_ls_service.h"
|
||||||
#include "storage/compaction/ob_medium_list_checker.h"
|
#include "storage/compaction/ob_medium_list_checker.h"
|
||||||
|
#include "storage/memtable/ob_row_conflict_handler.h"
|
||||||
|
|
||||||
namespace oceanbase
|
namespace oceanbase
|
||||||
{
|
{
|
||||||
@ -2382,19 +2383,25 @@ int ObTablet::check_row_locked_by_myself(
|
|||||||
bool &locked)
|
bool &locked)
|
||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
|
int tmp_ret = OB_SUCCESS;
|
||||||
ObArenaAllocator allocator(common::ObMemAttr(MTL_ID(), ObModIds::OB_STORE_ROW_LOCK_CHECKER));
|
ObArenaAllocator allocator(common::ObMemAttr(MTL_ID(), ObModIds::OB_STORE_ROW_LOCK_CHECKER));
|
||||||
ObMemtable *write_memtable = nullptr;
|
ObMemtable *write_memtable = nullptr;
|
||||||
ObTableIterParam param;
|
ObTableIterParam param;
|
||||||
ObTableAccessContext context;
|
ObTableAccessContext context;
|
||||||
|
locked = false;
|
||||||
|
|
||||||
if (OB_FAIL(prepare_memtable(relative_table, store_ctx, write_memtable))) {
|
if (OB_FAIL(prepare_memtable(relative_table, store_ctx, write_memtable))) {
|
||||||
LOG_WARN("prepare write memtable fail", K(ret), K(relative_table));
|
LOG_WARN("prepare write memtable fail", K(ret), K(relative_table));
|
||||||
} else if (OB_FAIL(prepare_param_ctx(allocator, relative_table, store_ctx, param, context))) {
|
} else if (OB_FAIL(prepare_param_ctx(allocator, relative_table, store_ctx, param, context))) {
|
||||||
LOG_WARN("prepare param context fail, ", K(ret), K(rowkey));
|
LOG_WARN("prepare param context fail, ", K(ret), K(rowkey));
|
||||||
} else if (OB_FAIL(write_memtable->check_row_locked_by_myself(param, context, rowkey, locked))) {
|
} else if (OB_TMP_FAIL(ObRowConflictHandler::check_row_locked(param, context, rowkey, true /* by_myself */))) {
|
||||||
LOG_WARN("failed to lock write memtable", K(ret), K(rowkey));
|
if (OB_TRY_LOCK_ROW_CONFLICT == tmp_ret) {
|
||||||
|
locked = true;
|
||||||
|
} else if (OB_TRANSACTION_SET_VIOLATION != tmp_ret) {
|
||||||
|
ret = tmp_ret;
|
||||||
|
LOG_WARN("failed to check row locked by myself", K(tmp_ret), K(rowkey));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user