BUGFIX: tablelock release memctx lock before retry

This commit is contained in:
obdev
2023-08-30 09:10:38 +00:00
committed by ob-robot
parent 2e0c56b797
commit b27045e417
6 changed files with 461 additions and 184 deletions

View File

@ -971,6 +971,332 @@ TEST_F(TestLockMemtable, out_trans_multi_source)
// ASSERT_EQ(OB_OBJ_LOCK_NOT_EXIST, ret); // ASSERT_EQ(OB_OBJ_LOCK_NOT_EXIST, ret);
} }
TEST_F(TestLockMemtable, test_lock_retry)
{
LOG_INFO("TestLockMemtable::test_lock_retry");
// 1. LOCK PART CTX
// 2. DO OBJ LOCK
// 3. CHECK:
// the lock at map;
// the lock at lock mem ctx;
// the lock at part ctx;
// 4. UNLOCK PART CTX
// 5. DO OBJ LOCK AGAIN
// 6. CHECK
// ctx.lock_.lock()
// CtxLockGuard guard(lock_, need_lock);
int ret = OB_SUCCESS;
bool is_try_lock = true;
int64_t expired_time = ObClockGenerator::getClock() + 1 * 1000 * 1000;
ObLockParam param;
ObOBJLock *obj_lock = NULL;
ObMemtableCtx *mem_ctx = NULL;
bool lock_exist = false;
share::SCN min_commited_scn;
share::SCN flushed_scn;
unsigned char lock_mode_in_same_trans = 0x0;
ObTableLockOp lock_op = DEFAULT_OUT_TRANS_LOCK_OP;
min_commited_scn.set_min();
flushed_scn.set_min();
MyTxCtx default_ctx;
ObStoreCtx store_ctx;
ObStoreCtx unlock_store_ctx;
// 1. lock part ctx.
start_tx(DEFAULT_TRANS_ID, default_ctx);
get_store_ctx(default_ctx, store_ctx);
default_ctx.tx_ctx_.change_to_leader();
default_ctx.tx_ctx_.lock_.lock();
// 2. do obj lock
LOG_INFO("TestLockMemtable::test_lock_retry 2 do obj lock");
param.is_try_lock_ = is_try_lock;
param.expired_time_ = expired_time;
ret = memtable_.lock(param,
store_ctx,
lock_op);
ASSERT_EQ(OB_TIMEOUT, ret);
// 3. check
// 3.1 check lock at map
LOG_INFO("TestLockMemtable::test_lock_retry 3.1 check lock at map");
ret = memtable_.obj_lock_map_.get_obj_lock_with_ref_(DEFAULT_TABLE_LOCK_ID,
obj_lock);
ASSERT_EQ(OB_SUCCESS, ret);
ASSERT_EQ(0, obj_lock->size_without_lock());
// 3.2 check lock at mem ctx
LOG_INFO("TestLockMemtable::test_lock_retry 3.2 check lock at mem ctx");
mem_ctx = store_ctx.mvcc_acc_ctx_.mem_ctx_;
ret = mem_ctx->check_lock_exist(DEFAULT_OUT_TRANS_LOCK_OP.lock_id_,
DEFAULT_OUT_TRANS_LOCK_OP.owner_id_,
DEFAULT_OUT_TRANS_LOCK_OP.lock_mode_,
DEFAULT_OUT_TRANS_LOCK_OP.op_type_,
lock_exist,
lock_mode_in_same_trans);
ASSERT_EQ(lock_exist, false);
// 3.3 check lock at part ctx
LOG_INFO("TestLockMemtable::test_lock_retry 3.3 check lock at part ctx");
ASSERT_EQ(default_ctx.tx_ctx_.mds_cache_.mds_list_.empty(), true);
// 4. unlock part ctx
default_ctx.tx_ctx_.lock_.unlock();
// 5. do obj lock again.
LOG_INFO("TestLockMemtable::test_lock_retry 5 do lock again");
param.is_try_lock_ = is_try_lock;
param.expired_time_ = ObClockGenerator::getClock() + 1 * 1000 * 1000;
ret = memtable_.lock(param,
store_ctx,
lock_op);
ASSERT_EQ(OB_SUCCESS, ret);
// 6. check
// 6.1 check lock at map
LOG_INFO("TestLockMemtable::test_lock_retry 6.1 check lock at map");
ret = memtable_.obj_lock_map_.get_obj_lock_with_ref_(DEFAULT_TABLE_LOCK_ID,
obj_lock);
ASSERT_EQ(OB_SUCCESS, ret);
ASSERT_EQ(1, obj_lock->size_without_lock());
obj_lock->print();
// 6.2 check lock at mem ctx
LOG_INFO("TestLockMemtable::test_lock_retry 6.2 check lock at mem ctx");
mem_ctx = store_ctx.mvcc_acc_ctx_.mem_ctx_;
ret = mem_ctx->check_lock_exist(DEFAULT_OUT_TRANS_LOCK_OP.lock_id_,
DEFAULT_OUT_TRANS_LOCK_OP.owner_id_,
DEFAULT_OUT_TRANS_LOCK_OP.lock_mode_,
DEFAULT_OUT_TRANS_LOCK_OP.op_type_,
lock_exist,
lock_mode_in_same_trans);
ASSERT_EQ(lock_exist, true);
// 6.3 check lock at part ctx
LOG_INFO("TestLockMemtable::test_lock_retry 6.3 check lock at part ctx");
ASSERT_EQ(default_ctx.tx_ctx_.mds_cache_.mds_list_.empty(), false);
// 7. clean
// 7.1 commit out trans lock
LOG_INFO("TestLockMemtable::test_lock_retry 7.1");
share::SCN commit_version;
share::SCN commit_scn;
commit_version.set_base();
commit_scn.set_base();
ret = memtable_.update_lock_status(DEFAULT_OUT_TRANS_LOCK_OP,
commit_version,
commit_scn,
COMMIT_LOCK_OP_STATUS);
ASSERT_EQ(OB_SUCCESS, ret);
min_commited_scn = memtable_.obj_lock_map_.get_min_ddl_committed_scn(flushed_scn);
ASSERT_EQ(min_commited_scn, commit_scn);
memtable_.obj_lock_map_.print();
// 7.2 unlock complete lock
MyTxCtx ctx2;
start_tx(TRANS_ID2, ctx2);
get_store_ctx(ctx2, unlock_store_ctx);
ctx2.tx_ctx_.change_to_leader();
LOG_INFO("TestLockMemtable::test_lock_retry 7.2");
expired_time = ObClockGenerator::getClock() + 1 * 1000 * 1000;
ret = memtable_.unlock(unlock_store_ctx,
DEFAULT_OUT_TRANS_UNLOCK_OP,
is_try_lock,
expired_time);
ASSERT_EQ(OB_SUCCESS, ret);
memtable_.obj_lock_map_.print();
// 7.3 unlock commit
LOG_INFO("TestLockMemtable::test_lock_retry 7.3");
ret = memtable_.update_lock_status(DEFAULT_OUT_TRANS_UNLOCK_OP,
commit_version,
commit_scn,
COMMIT_LOCK_OP_STATUS);
ASSERT_EQ(OB_SUCCESS, ret);
memtable_.obj_lock_map_.print();
min_commited_scn = memtable_.obj_lock_map_.get_min_ddl_committed_scn(flushed_scn);
ASSERT_EQ(min_commited_scn, share::SCN::max_scn());
// 7.4 check
LOG_INFO("TestLockMemtable::test_lock_retry 7.4");
MyTxCtx ctx3;
ObStoreCtx unlock_store_ctx3;
start_tx(TRANS_ID3, ctx3);
get_store_ctx(ctx3, unlock_store_ctx3);
ctx3.tx_ctx_.change_to_leader();
expired_time = ObClockGenerator::getClock() + 1 * 1000 * 1000;
ret = memtable_.unlock(unlock_store_ctx3,
DEFAULT_OUT_TRANS_UNLOCK_OP,
is_try_lock,
expired_time);
ASSERT_EQ(OB_OBJ_LOCK_NOT_EXIST, ret);
}
TEST_F(TestLockMemtable, test_lock_retry_lock_conflict)
{
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict");
// 1. LOCK
// 2. LOCK AGAIN
// 3. UNLOCK
// 4. LOCK AGAIN
// 5. CHECK:
// the lock at map;
// the lock at lock mem ctx;
// the lock at part ctx;
// 6. CLEAN
int ret = OB_SUCCESS;
bool is_try_lock = false;
int64_t expired_time = ObClockGenerator::getClock() + 1 * 1000 * 1000;
ObLockParam param;
ObOBJLock *obj_lock = NULL;
ObMemtableCtx *mem_ctx = NULL;
bool lock_exist = false;
share::SCN min_commited_scn;
share::SCN flushed_scn;
unsigned char lock_mode_in_same_trans = 0x0;
ObTableLockOp lock_first = DEFAULT_OUT_TRANS_LOCK_OP; // RX, owner 0
ObTableLockOp lock_second = DEFAULT_OUT_TRANS_LOCK_OP;
lock_second.lock_mode_ = DEFAULT_COFLICT_LOCK_MODE; // X
lock_second.owner_id_ = CONFLICT_OWNER_ID; // owner 1
MyTxCtx default_ctx;
ObStoreCtx store_ctx;
MyTxCtx ctx2;
ObStoreCtx store_ctx2;
MyTxCtx ctx3;
ObStoreCtx unlock_store_ctx;
// 1. lock first.
start_tx(DEFAULT_TRANS_ID, default_ctx);
get_store_ctx(default_ctx, store_ctx);
default_ctx.tx_ctx_.change_to_leader();
start_tx(TRANS_ID2, ctx2);
get_store_ctx(ctx2, store_ctx2);
ctx2.tx_ctx_.change_to_leader();
start_tx(TRANS_ID3, ctx3);
get_store_ctx(ctx3, unlock_store_ctx);
ctx3.tx_ctx_.change_to_leader();
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 1 lock first");
param.is_try_lock_ = is_try_lock;
param.expired_time_ = expired_time;
ret = memtable_.lock(param,
store_ctx,
lock_first);
ASSERT_EQ(OB_SUCCESS, ret);
// 2. lock second, must conflict and retry until timeout
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 2 lock second");
ret = memtable_.lock(param,
store_ctx2,
lock_second);
ASSERT_EQ(OB_ERR_EXCLUSIVE_LOCK_CONFLICT, ret);
// 3. unlock
// 3.1 commit out trans lock
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 3.1");
share::SCN commit_version;
share::SCN commit_scn;
commit_version.set_base();
commit_scn.set_base();
ret = memtable_.update_lock_status(DEFAULT_OUT_TRANS_LOCK_OP,
commit_version,
commit_scn,
COMMIT_LOCK_OP_STATUS);
ASSERT_EQ(OB_SUCCESS, ret);
min_commited_scn = memtable_.obj_lock_map_.get_min_ddl_committed_scn(flushed_scn);
ASSERT_EQ(min_commited_scn, commit_scn);
memtable_.obj_lock_map_.print();
// 3.2 unlock complete lock
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 3.2");
expired_time = ObClockGenerator::getClock() + 1 * 1000 * 1000;
ret = memtable_.unlock(unlock_store_ctx,
DEFAULT_OUT_TRANS_UNLOCK_OP,
is_try_lock,
expired_time);
ASSERT_EQ(OB_SUCCESS, ret);
memtable_.obj_lock_map_.print();
// 3.3 unlock commit
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 3.3");
ret = memtable_.update_lock_status(DEFAULT_OUT_TRANS_UNLOCK_OP,
commit_version,
commit_scn,
COMMIT_LOCK_OP_STATUS);
ASSERT_EQ(OB_SUCCESS, ret);
memtable_.obj_lock_map_.print();
min_commited_scn = memtable_.obj_lock_map_.get_min_ddl_committed_scn(flushed_scn);
ASSERT_EQ(min_commited_scn, share::SCN::max_scn());
// 4. lock again
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 4 lock again");
param.expired_time_ = ObClockGenerator::getClock() + 1 * 1000 * 1000;
ret = memtable_.lock(param,
store_ctx2,
lock_second);
ASSERT_EQ(OB_SUCCESS, ret);
// 5. check
// 5.1 check lock at map
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 5.1 check lock at map");
ret = memtable_.obj_lock_map_.get_obj_lock_with_ref_(DEFAULT_TABLE_LOCK_ID,
obj_lock);
ASSERT_EQ(OB_SUCCESS, ret);
ASSERT_EQ(1, obj_lock->size_without_lock());
// 5.2 check lock at mem ctx
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 5.2 check lock at mem ctx");
mem_ctx = store_ctx2.mvcc_acc_ctx_.mem_ctx_;
ret = mem_ctx->check_lock_exist(lock_second.lock_id_,
lock_second.owner_id_,
lock_second.lock_mode_,
lock_second.op_type_,
lock_exist,
lock_mode_in_same_trans);
ASSERT_EQ(lock_exist, true);
// 6. clean
// 6.1 commit out trans lock
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 6.1");
commit_version.set_base();
commit_scn.set_base();
ret = memtable_.update_lock_status(lock_second,
commit_version,
commit_scn,
COMMIT_LOCK_OP_STATUS);
ASSERT_EQ(OB_SUCCESS, ret);
min_commited_scn = memtable_.obj_lock_map_.get_min_ddl_committed_scn(flushed_scn);
ASSERT_EQ(min_commited_scn, commit_scn);
memtable_.obj_lock_map_.print();
// 6.2 unlock complete lock
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 6.2");
expired_time = ObClockGenerator::getClock() + 1 * 1000 * 1000;
ObTableLockOp unlock_op = DEFAULT_OUT_TRANS_UNLOCK_OP;
unlock_op.owner_id_ = lock_second.owner_id_;
unlock_op.lock_mode_ = lock_second.lock_mode_;
ret = memtable_.unlock(unlock_store_ctx,
unlock_op,
is_try_lock,
expired_time);
ASSERT_EQ(OB_SUCCESS, ret);
memtable_.obj_lock_map_.print();
// 6.3 unlock commit
LOG_INFO("TestLockMemtable::test_lock_retry_lock_conflict 6.3");
ret = memtable_.update_lock_status(unlock_op,
commit_version,
commit_scn,
COMMIT_LOCK_OP_STATUS);
ASSERT_EQ(OB_SUCCESS, ret);
memtable_.obj_lock_map_.print();
min_commited_scn = memtable_.obj_lock_map_.get_min_ddl_committed_scn(flushed_scn);
ASSERT_EQ(min_commited_scn, share::SCN::max_scn());
}
} // tablelock } // tablelock
} // transaction } // transaction
} // oceanbase } // oceanbase

View File

@ -29,19 +29,6 @@ namespace transaction
{ {
namespace tablelock namespace tablelock
{ {
int ObOBJLock::register_into_deadlock_detector_(const ObStoreCtx &ctx,
const ObTableLockOp &lock_op)
{
UNUSEDx(ctx, lock_op);
return OB_SUCCESS;
}
int ObOBJLock::unregister_from_deadlock_detector_(const ObTableLockOp &lock_op)
{
UNUSED(lock_op);
return OB_SUCCESS;
}
class TestObjLock : public MockTxEnv, class TestObjLock : public MockTxEnv,
public ::testing::Test public ::testing::Test
{ {
@ -572,9 +559,9 @@ TEST_F(TestObjLock, lock_conflict_in_in)
ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, ret); ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, ret);
} else { } else {
// deadlock detect will kill the trans // deadlock detect will kill the trans
// ASSERT_EQ(OB_ERR_EXCLUSIVE_LOCK_CONFLICT, ret); // ASSERT_EQ(OB_TRY_LOCK_ROW_CONFLICT, ret);
// ASSERT_EQ(OB_TRANS_KILLED, ret); // ASSERT_EQ(OB_TRANS_KILLED, ret);
ASSERT_EQ((ret == OB_TRANS_KILLED || ret == OB_ERR_EXCLUSIVE_LOCK_CONFLICT), true); ASSERT_EQ((ret == OB_TRANS_KILLED || ret == OB_TRY_LOCK_ROW_CONFLICT), true);
} }
// 1.3 clean. // 1.3 clean.

View File

@ -25,6 +25,7 @@
#include "storage/memtable/ob_memtable_context.h" // ObMemtableCtx #include "storage/memtable/ob_memtable_context.h" // ObMemtableCtx
#include "storage/tablelock/ob_mem_ctx_table_lock.h" #include "storage/tablelock/ob_mem_ctx_table_lock.h"
#include "storage/tablelock/ob_table_lock_common.h" #include "storage/tablelock/ob_table_lock_common.h"
#include "storage/tablelock/ob_table_lock_deadlock.h"
#include "storage/tablelock/ob_table_lock_rpc_struct.h" #include "storage/tablelock/ob_table_lock_rpc_struct.h"
#include "storage/tx/ob_trans_define.h" #include "storage/tx/ob_trans_define.h"
#include "storage/tx/ob_trans_part_ctx.h" #include "storage/tx/ob_trans_part_ctx.h"
@ -135,6 +136,7 @@ int ObLockMemtable::lock_(
ObTableLockMode lock_mode_in_same_trans = 0x0; ObTableLockMode lock_mode_in_same_trans = 0x0;
bool lock_exist = false; bool lock_exist = false;
ObLockStep succ_step = STEP_BEGIN; ObLockStep succ_step = STEP_BEGIN;
bool register_to_deadlock = false;
ObTxIDSet conflict_tx_set; ObTxIDSet conflict_tx_set;
// 1. record lock myself(check conflict). // 1. record lock myself(check conflict).
@ -150,8 +152,8 @@ int ObLockMemtable::lock_(
conflict_tx_set.reset(); conflict_tx_set.reset();
ObMvccWriteGuard guard(true); ObMvccWriteGuard guard(true);
if (ObClockGenerator::getClock() >= param.expired_time_) { if (ObClockGenerator::getClock() >= param.expired_time_) {
ret = OB_TIMEOUT; ret = (ret == OB_TRY_LOCK_ROW_CONFLICT ? OB_ERR_EXCLUSIVE_LOCK_CONFLICT : OB_TIMEOUT);
LOG_WARN("lock timeout", K(ret), K(param)); LOG_WARN("lock timeout", K(ret), K(lock_op), K(param));
} else if (OB_FAIL(guard.write_auth(ctx))) { } else if (OB_FAIL(guard.write_auth(ctx))) {
LOG_WARN("not allow lock table.", K(ret), K(ctx)); LOG_WARN("not allow lock table.", K(ret), K(ctx));
} else if (FALSE_IT(mem_ctx = static_cast<ObMemtableCtx *>(ctx.mvcc_acc_ctx_.mem_ctx_))) { } else if (FALSE_IT(mem_ctx = static_cast<ObMemtableCtx *>(ctx.mvcc_acc_ctx_.mem_ctx_))) {
@ -181,14 +183,41 @@ int ObLockMemtable::lock_(
} }
LOG_WARN("record lock at mem_ctx failed.", K(ret), K(lock_op)); LOG_WARN("record lock at mem_ctx failed.", K(ret), K(lock_op));
} }
if (OB_FAIL(ret) && succ_step == STEP_IN_LOCK_MGR) { if (OB_FAIL(ret) && succ_step == STEP_IN_LOCK_MGR) {
obj_lock_map_.remove_lock_record(lock_op); obj_lock_map_.remove_lock_record(lock_op);
} }
if (!need_retry &&
ret == OB_TRY_LOCK_ROW_CONFLICT) {
if (param.is_try_lock_) {
} else if (ctx.mvcc_acc_ctx_.tx_ctx_->is_table_lock_killed()) {
// trans is killed by deadlock detect or abort because of
// something else.
ret = OB_TRANS_KILLED;
} else if (lock_op.is_dml_lock_op() /* only dml lock will wait at lock wait mgr */) {
// wait at lock wait mgr but not retry at here.
} else {
// register to deadlock detector.
need_retry = true;
if (!lock_op.is_dml_lock_op() && !register_to_deadlock) {
if (OB_TMP_FAIL(register_into_deadlock_detector_(ctx, lock_op))) {
LOG_WARN("register to deadlock detector failed", K(ret), K(lock_op));
} else {
register_to_deadlock = true;
}
}
}
}
} }
if (need_retry) { if (need_retry) {
ob_usleep(USLEEP_TIME); ob_usleep(USLEEP_TIME);
} }
} while (need_retry); } while (need_retry);
if (OB_UNLIKELY(register_to_deadlock)) {
if (OB_TMP_FAIL(unregister_from_deadlock_detector_(lock_op))) {
LOG_WARN("unregister from deadlock detector failed", K(tmp_ret), K(lock_op));
}
}
// return success if lock twice. // return success if lock twice.
if (ret == OB_OBJ_LOCK_EXIST) { if (ret == OB_OBJ_LOCK_EXIST) {
ret = OB_SUCCESS; ret = OB_SUCCESS;
@ -287,6 +316,11 @@ int ObLockMemtable::unlock_(
if (OB_FAIL(ret) && succ_step == STEP_IN_LOCK_MGR) { if (OB_FAIL(ret) && succ_step == STEP_IN_LOCK_MGR) {
obj_lock_map_.remove_lock_record(unlock_op); obj_lock_map_.remove_lock_record(unlock_op);
} }
if (!need_retry &&
is_need_retry_unlock_error(ret) &&
!is_try_lock) {
need_retry = true;
}
} }
if (need_retry) { if (need_retry) {
ob_usleep(USLEEP_TIME); ob_usleep(USLEEP_TIME);
@ -948,6 +982,62 @@ int ObLockMemtable::replay_lock(
return ret; return ret;
} }
int ObLockMemtable::register_into_deadlock_detector_(
const ObStoreCtx &ctx,
const ObTableLockOp &lock_op)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
ObTransLockPartID tx_lock_part_id;
ObAddr parent_addr;
const ObLSID &ls_id = ctx.ls_id_;
const int64_t priority = ~(ctx.mvcc_acc_ctx_.tx_desc_->get_active_ts());
tx_lock_part_id.lock_id_ = lock_op.lock_id_;
tx_lock_part_id.trans_id_ = lock_op.create_trans_id_;
if (OB_FAIL(ObTableLockDeadlockDetectorHelper::register_trans_lock_part(
tx_lock_part_id, ls_id, priority))) {
LOG_WARN("register trans lock part failed", K(ret), K(tx_lock_part_id),
K(ls_id));
} else if (OB_FAIL(ObTransDeadlockDetectorAdapter::get_trans_scheduler_info_on_participant(
tx_lock_part_id.trans_id_, ls_id, parent_addr))) {
LOG_WARN("get scheduler address failed", K(tx_lock_part_id), K(ls_id));
} else if (OB_FAIL(ObTableLockDeadlockDetectorHelper::add_parent(
tx_lock_part_id, parent_addr, lock_op.create_trans_id_))) {
LOG_WARN("add parent failed", K(ret), K(tx_lock_part_id));
} else if (OB_FAIL(ObTableLockDeadlockDetectorHelper::block(tx_lock_part_id,
ls_id,
lock_op))) {
LOG_WARN("add dependency failed", K(ret), K(tx_lock_part_id));
} else {
LOG_DEBUG("succeed register to the dead lock detector");
}
if (OB_FAIL(ret)) {
if (OB_SUCCESS != (tmp_ret = ObTableLockDeadlockDetectorHelper::
unregister_trans_lock_part(tx_lock_part_id))) {
if (tmp_ret != OB_ENTRY_NOT_EXIST) {
LOG_WARN("unregister from deadlock detector failed", K(ret),
K(tx_lock_part_id));
}
}
}
return ret;
}
int ObLockMemtable::unregister_from_deadlock_detector_(const ObTableLockOp &lock_op)
{
int ret = OB_SUCCESS;
ObTransLockPartID tx_lock_part_id;
tx_lock_part_id.lock_id_ = lock_op.lock_id_;
tx_lock_part_id.trans_id_ = lock_op.create_trans_id_;
if (OB_FAIL(ObTableLockDeadlockDetectorHelper::unregister_trans_lock_part(
tx_lock_part_id))) {
LOG_WARN("unregister trans lock part failed", K(ret), K(tx_lock_part_id));
} else {
// do nothing
}
return ret;
}
} // tablelock } // tablelock
} // transaction } // transaction
} // oceanbase } // oceanbase

View File

@ -195,6 +195,9 @@ private:
const ObTableLockMode &lock_mode, const ObTableLockMode &lock_mode,
const ObTransID &conflict_tx_id, const ObTransID &conflict_tx_id,
ObFunction<int(bool &need_wait)> &recheck_f); ObFunction<int(bool &need_wait)> &recheck_f);
int register_into_deadlock_detector_(const ObStoreCtx &ctx,
const ObTableLockOp &lock_op);
int unregister_from_deadlock_detector_(const ObTableLockOp &lock_op);
private: private:
typedef common::SpinRWLock RWLock; typedef common::SpinRWLock RWLock;
typedef common::SpinRLockGuard RLockGuard; typedef common::SpinRLockGuard RLockGuard;

View File

@ -22,7 +22,6 @@
#include "storage/tablelock/ob_obj_lock.h" #include "storage/tablelock/ob_obj_lock.h"
#include "storage/tablelock/ob_table_lock_common.h" #include "storage/tablelock/ob_table_lock_common.h"
#include "storage/tablelock/ob_mem_ctx_table_lock.h" #include "storage/tablelock/ob_mem_ctx_table_lock.h"
#include "storage/tablelock/ob_table_lock_deadlock.h"
#include "storage/tablelock/ob_table_lock_iterator.h" #include "storage/tablelock/ob_table_lock_iterator.h"
#include "storage/tablelock/ob_table_lock_rpc_struct.h" #include "storage/tablelock/ob_table_lock_rpc_struct.h"
@ -170,7 +169,6 @@ int ObOBJLock::slow_lock(
const ObLockParam &param, const ObLockParam &param,
const ObTableLockOp &lock_op, const ObTableLockOp &lock_op,
const ObTableLockMode &lock_mode_in_same_trans, const ObTableLockMode &lock_mode_in_same_trans,
bool &need_retry,
ObMalloc &allocator, ObMalloc &allocator,
ObTxIDSet &conflict_tx_set) ObTxIDSet &conflict_tx_set)
{ {
@ -187,7 +185,6 @@ int ObOBJLock::slow_lock(
WRLockGuard guard(rwlock_); WRLockGuard guard(rwlock_);
if (is_deleted_) { if (is_deleted_) {
ret = OB_EAGAIN; ret = OB_EAGAIN;
need_retry = false;
} else if (OB_FAIL(check_allow_lock_(lock_op, } else if (OB_FAIL(check_allow_lock_(lock_op,
lock_mode_in_same_trans, lock_mode_in_same_trans,
conflict_tx_set, conflict_tx_set,
@ -222,17 +219,14 @@ int ObOBJLock::slow_lock(
op_list, allocator); op_list, allocator);
} }
// 1. need retry basic conditions // 1. need retry basic conditions
if (ret == OB_TRY_LOCK_ROW_CONFLICT && !param.is_try_lock_) { // lock conflict and it is not try lock.
need_retry = true;
}
// 2. need retry second conditions // 2. need retry second conditions
// out trans lock or in trans lock table lock should not retry if // out trans lock or in trans lock table lock should not retry if
// it is conflict with dml lock. // it is conflict with dml lock.
if (need_retry) { if (ret == OB_TRY_LOCK_ROW_CONFLICT && !param.is_try_lock_) {
if (!lock_op.is_dml_lock_op() && if (!lock_op.is_dml_lock_op() &&
conflict_with_dml_lock && conflict_with_dml_lock &&
param.is_deadlock_avoid_enabled_) { param.is_deadlock_avoid_enabled_) {
need_retry = false;
ret = OB_TRANS_KILLED; ret = OB_TRANS_KILLED;
} }
} }
@ -414,14 +408,12 @@ int ObOBJLock::update_lock_status(const ObTableLockOp &lock_op,
int ObOBJLock::try_fast_lock_( int ObOBJLock::try_fast_lock_(
const ObTableLockOp &lock_op, const ObTableLockOp &lock_op,
const ObTableLockMode &lock_mode_in_same_trans, const ObTableLockMode &lock_mode_in_same_trans,
bool &need_retry,
ObTxIDSet &conflict_tx_set) ObTxIDSet &conflict_tx_set)
{ {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
bool unused_conflict_with_dml_lock = false; bool unused_conflict_with_dml_lock = false;
if (is_deleted_) { if (is_deleted_) {
ret = OB_EAGAIN; ret = OB_EAGAIN;
need_retry = false;
} else if (OB_UNLIKELY(lock_op.need_record_lock_op())) { } else if (OB_UNLIKELY(lock_op.need_record_lock_op())) {
ret = OB_ERR_UNEXPECTED; ret = OB_ERR_UNEXPECTED;
LOG_WARN("this lock op should not do fast lock", KR(ret), K(lock_op)); LOG_WARN("this lock op should not do fast lock", KR(ret), K(lock_op));
@ -447,7 +439,6 @@ int ObOBJLock::fast_lock(
const ObLockParam &param, const ObLockParam &param,
const ObTableLockOp &lock_op, const ObTableLockOp &lock_op,
const ObTableLockMode &lock_mode_in_same_trans, const ObTableLockMode &lock_mode_in_same_trans,
bool &need_retry,
ObMalloc &allocator, ObMalloc &allocator,
ObTxIDSet &conflict_tx_set) ObTxIDSet &conflict_tx_set)
{ {
@ -458,7 +449,6 @@ int ObOBJLock::fast_lock(
RDLockGuard guard(rwlock_); RDLockGuard guard(rwlock_);
if (OB_FAIL(try_fast_lock_(lock_op, if (OB_FAIL(try_fast_lock_(lock_op,
lock_mode_in_same_trans, lock_mode_in_same_trans,
need_retry,
conflict_tx_set))) { conflict_tx_set))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_EAGAIN != ret) { if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_EAGAIN != ret) {
LOG_WARN("try fast lock failed", KR(ret), K(lock_op)); LOG_WARN("try fast lock failed", KR(ret), K(lock_op));
@ -467,10 +457,6 @@ int ObOBJLock::fast_lock(
LOG_DEBUG("succeed create lock ", K(lock_op)); LOG_DEBUG("succeed create lock ", K(lock_op));
} }
} }
// 1. need retry basic conditions
if (ret == OB_TRY_LOCK_ROW_CONFLICT && !param.is_try_lock_) {
need_retry = true;
}
return ret; return ret;
} }
@ -485,7 +471,6 @@ int ObOBJLock::lock(
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS;
int64_t USLEEP_TIME = 100; // 0.1 ms int64_t USLEEP_TIME = 100; // 0.1 ms
bool register_to_deadlock = false;
// 1. lock myself. // 1. lock myself.
// 2. try to lock. // 2. try to lock.
LOG_DEBUG("ObOBJLock::lock ", K(param), K(lock_op)); LOG_DEBUG("ObOBJLock::lock ", K(param), K(lock_op));
@ -493,73 +478,31 @@ int ObOBJLock::lock(
ret = OB_INVALID_ARGUMENT; ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument.", K(ret), K(lock_op)); LOG_WARN("invalid argument.", K(ret), K(lock_op));
} else { } else {
bool need_retry = false; if (OB_LIKELY(!lock_op.need_record_lock_op())) {
do { if (OB_FAIL(fast_lock(param,
need_retry = false; lock_op,
if (OB_LIKELY(!lock_op.need_record_lock_op())) { lock_mode_in_same_trans,
if (OB_FAIL(fast_lock(param, allocator,
lock_op, conflict_tx_set))) {
lock_mode_in_same_trans,
need_retry,
allocator,
conflict_tx_set))) {
if (ret != OB_TRY_LOCK_ROW_CONFLICT &&
ret != OB_EAGAIN) {
LOG_WARN("lock failed.", K(ret), K(lock_op));
}
}
} else if (OB_FAIL(slow_lock(param,
lock_op,
lock_mode_in_same_trans,
need_retry,
allocator,
conflict_tx_set))) {
if (ret != OB_TRY_LOCK_ROW_CONFLICT && if (ret != OB_TRY_LOCK_ROW_CONFLICT &&
ret != OB_EAGAIN) { ret != OB_EAGAIN) {
LOG_WARN("lock failed.", K(ret), K(lock_op)); LOG_WARN("lock failed.", K(ret), K(lock_op));
} }
} }
} else if (OB_FAIL(slow_lock(param,
lock_op,
lock_mode_in_same_trans,
allocator,
conflict_tx_set))) {
if (ret != OB_TRY_LOCK_ROW_CONFLICT &&
ret != OB_EAGAIN) {
LOG_WARN("lock failed.", K(ret), K(lock_op));
}
}
if (need_retry && if (OB_FAIL(ret) && REACH_TIME_INTERVAL(1 * 1000 * 1000)) {
ret == OB_TRY_LOCK_ROW_CONFLICT) { LOG_WARN("ObOBJLock::lock ", K(ret), K(param), K(lock_op));
need_retry = false; print();
if (param.is_try_lock_) {
} else if (OB_UNLIKELY(ObClockGenerator::getClock() >= param.expired_time_)) {
ret = OB_ERR_EXCLUSIVE_LOCK_CONFLICT; // TODO: specialize error code with different lock mode
LOG_WARN("lock is timeout", K(ret), K(lock_op), K(param));
} else if (ctx.mvcc_acc_ctx_.tx_ctx_->is_table_lock_killed()) {
// trans is killed by deadlock detect or abort because of
// something else.
need_retry = false;
ret = OB_TRANS_KILLED;
} else if (lock_op.is_dml_lock_op() /* only dml lock will wait at lock wait mgr */) {
// wait at lock wait mgr but not retry at here.
need_retry = false;
} else {
// register to deadlock detector.
need_retry = true;
if (!lock_op.is_dml_lock_op() &&
!register_to_deadlock) {
if (OB_FAIL(register_into_deadlock_detector_(ctx,
lock_op))) {
LOG_WARN("register to deadlock detector failed", K(ret),
K(lock_op));
} else {
register_to_deadlock = true;
}
}
ob_usleep(USLEEP_TIME);
}
}
if (OB_FAIL(ret) && REACH_TIME_INTERVAL(1 * 1000 * 1000)) {
LOG_WARN("ObOBJLock::lock ", K(ret), K(param), K(lock_op));
print();
}
} while (need_retry);
if (OB_UNLIKELY(register_to_deadlock)) {
if (OB_SUCCESS != (tmp_ret = unregister_from_deadlock_detector_(lock_op))) {
LOG_WARN("unregister from deadlock detector failed", K(tmp_ret), K(lock_op));
}
} }
} }
LOG_DEBUG("ObOBJLock::lock finish", K(ret), K(conflict_tx_set)); LOG_DEBUG("ObOBJLock::lock finish", K(ret), K(conflict_tx_set));
@ -585,35 +528,25 @@ int ObOBJLock::unlock(
ret = OB_ERR_UNEXPECTED; ret = OB_ERR_UNEXPECTED;
LOG_ERROR("should only slow lock op", K(ret), K(unlock_op)); LOG_ERROR("should only slow lock op", K(ret), K(unlock_op));
} else { } else {
bool need_retry = false; {
do { WRLockGuard guard(rwlock_);
need_retry = false; if (!is_try_lock && OB_UNLIKELY(ObClockGenerator::getClock() >= expired_time)) {
{ ret = (ret == OB_SUCCESS ? OB_TIMEOUT : ret);
WRLockGuard guard(rwlock_); LOG_WARN("unlock is timeout", K(ret), K(unlock_op));
if (!is_try_lock && OB_UNLIKELY(ObClockGenerator::getClock() >= expired_time)) { } else if (is_deleted_) {
ret = (ret == OB_SUCCESS ? OB_TIMEOUT : ret); // need retry from upper layer.
LOG_WARN("unlock is timeout", K(ret), K(unlock_op)); ret = OB_EAGAIN;
} else if (is_deleted_) { } else if (OB_FAIL(unlock_(unlock_op, allocator))) {
// need retry from upper layer. if (!is_need_retry_unlock_error(ret)) {
ret = OB_EAGAIN; LOG_WARN("unlock failed.", K(ret), K(unlock_op));
need_retry = false;
} else if (OB_FAIL(unlock_(unlock_op, allocator))) {
if (is_need_retry_unlock_error(ret) && !is_try_lock) {
need_retry = true;
} else {
LOG_WARN("unlock failed.", K(ret), K(unlock_op));
}
} }
} }
if (need_retry) { }
ob_usleep(USLEEP_TIME); if (OB_FAIL(ret) && REACH_TIME_INTERVAL(1 * 1000 * 1000)) {
} LOG_WARN("ObOBJLock::unlock ", K(ret), K(is_try_lock),
if (OB_FAIL(ret) && REACH_TIME_INTERVAL(1 * 1000 * 1000)) { K(expired_time), K(unlock_op));
LOG_WARN("ObOBJLock::unlock ", K(ret), K(is_try_lock), print();
K(expired_time), K(unlock_op)); }
print();
}
} while (need_retry);
} }
LOG_DEBUG("ObOBJLock::unlock finish.", K(ret)); LOG_DEBUG("ObOBJLock::unlock finish.", K(ret));
@ -1587,61 +1520,6 @@ int ObOBJLock::compact_tablelock_(ObMalloc &allocator,
return ret; return ret;
} }
int ObOBJLock::register_into_deadlock_detector_(const ObStoreCtx &ctx,
const ObTableLockOp &lock_op)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
ObTransLockPartID tx_lock_part_id;
ObAddr parent_addr;
const ObLSID &ls_id = ctx.ls_id_;
const int64_t priority = ~(ctx.mvcc_acc_ctx_.tx_desc_->get_active_ts());
tx_lock_part_id.lock_id_ = lock_op.lock_id_;
tx_lock_part_id.trans_id_ = lock_op.create_trans_id_;
if (OB_FAIL(ObTableLockDeadlockDetectorHelper::register_trans_lock_part(
tx_lock_part_id, ls_id, priority))) {
LOG_WARN("register trans lock part failed", K(ret), K(tx_lock_part_id),
K(ls_id));
} else if (OB_FAIL(ObTransDeadlockDetectorAdapter::get_trans_scheduler_info_on_participant(
tx_lock_part_id.trans_id_, ls_id, parent_addr))) {
LOG_WARN("get scheduler address failed", K(tx_lock_part_id), K(ls_id));
} else if (OB_FAIL(ObTableLockDeadlockDetectorHelper::add_parent(
tx_lock_part_id, parent_addr, lock_op.create_trans_id_))) {
LOG_WARN("add parent failed", K(ret), K(tx_lock_part_id));
} else if (OB_FAIL(ObTableLockDeadlockDetectorHelper::block(tx_lock_part_id,
ls_id,
lock_op))) {
LOG_WARN("add dependency failed", K(ret), K(tx_lock_part_id));
} else {
LOG_DEBUG("succeed register to the dead lock detector");
}
if (OB_FAIL(ret)) {
if (OB_SUCCESS != (tmp_ret = ObTableLockDeadlockDetectorHelper::
unregister_trans_lock_part(tx_lock_part_id))) {
if (tmp_ret != OB_ENTRY_NOT_EXIST) {
LOG_WARN("unregister from deadlock detector failed", K(ret),
K(tx_lock_part_id));
}
}
}
return ret;
}
int ObOBJLock::unregister_from_deadlock_detector_(const ObTableLockOp &lock_op)
{
int ret = OB_SUCCESS;
ObTransLockPartID tx_lock_part_id;
tx_lock_part_id.lock_id_ = lock_op.lock_id_;
tx_lock_part_id.trans_id_ = lock_op.create_trans_id_;
if (OB_FAIL(ObTableLockDeadlockDetectorHelper::unregister_trans_lock_part(
tx_lock_part_id))) {
LOG_WARN("unregister trans lock part failed", K(ret), K(tx_lock_part_id));
} else {
// do nothing
}
return ret;
}
int ObOBJLock::get_or_create_op_list(const ObTableLockMode mode, int ObOBJLock::get_or_create_op_list(const ObTableLockMode mode,
const uint64_t tenant_id, const uint64_t tenant_id,
ObMalloc &allocator, ObMalloc &allocator,

View File

@ -162,20 +162,17 @@ private:
const ObLockParam &param, const ObLockParam &param,
const ObTableLockOp &lock_op, const ObTableLockOp &lock_op,
const ObTableLockMode &lock_mode_in_same_trans, const ObTableLockMode &lock_mode_in_same_trans,
bool &need_retry,
ObMalloc &allocator, ObMalloc &allocator,
ObTxIDSet &conflict_tx_set); ObTxIDSet &conflict_tx_set);
int slow_lock( int slow_lock(
const ObLockParam &param, const ObLockParam &param,
const ObTableLockOp &lock_op, const ObTableLockOp &lock_op,
const ObTableLockMode &lock_mode_in_same_trans, const ObTableLockMode &lock_mode_in_same_trans,
bool &need_retry,
ObMalloc &allocator, ObMalloc &allocator,
ObTxIDSet &conflict_tx_set); ObTxIDSet &conflict_tx_set);
int try_fast_lock_( int try_fast_lock_(
const ObTableLockOp &lock_op, const ObTableLockOp &lock_op,
const ObTableLockMode &lock_mode_in_same_trans, const ObTableLockMode &lock_mode_in_same_trans,
bool &need_retry,
ObTxIDSet &conflict_tx_set); ObTxIDSet &conflict_tx_set);
int unlock_( int unlock_(
const ObTableLockOp &unlock_op, const ObTableLockOp &unlock_op,
@ -238,10 +235,6 @@ private:
ObMalloc &allocator, ObMalloc &allocator,
bool &is_compact, bool &is_compact,
const bool is_force = false); const bool is_force = false);
int register_into_deadlock_detector_(
const storage::ObStoreCtx &ctx,
const ObTableLockOp &lock_op);
int unregister_from_deadlock_detector_(const ObTableLockOp &lock_op);
private: private:
int get_index_by_lock_mode(ObTableLockMode mode); int get_index_by_lock_mode(ObTableLockMode mode);
int check_op_allow_lock_from_list_( int check_op_allow_lock_from_list_(