add double check for lock table during register table lock callback

This commit is contained in:
Handora
2024-10-21 13:43:18 +00:00
committed by ob-robot
parent 4d4bca0ba5
commit 2ffeca1e71
3 changed files with 51 additions and 9 deletions

View File

@ -1191,8 +1191,10 @@ int ObTransferHandler::wait_tablet_write_end_(
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ls->get_lock_table()->enable_check_tablet_status(true))) {
LOG_WARN("failed to enable check tablet status", KR(ret), K(task_info));
} else if (OB_FAIL(ls->wait_tx_write_end(timeout_ctx))) {
LOG_WARN("failed to wait tx_write end", KR(ret), K(task_info));
// Instead of wait table lock write end, we choose to use double check
// during table lock callback register
// } else if (OB_FAIL(ls->wait_tx_write_end(timeout_ctx))) {
// LOG_WARN("failed to wait tx_write end", KR(ret), K(task_info));
} else if (OB_FAIL(ls->get_tx_svr()->traverse_trans_to_submit_redo_log(failed_tx_id))) {
LOG_WARN("failed to submit tx log", KR(ret), K(task_info));
} else if (OB_FAIL(ls->tablet_freeze(checkpoint::INVALID_TRACE_ID,

View File

@ -206,6 +206,7 @@ ObLockMemtable::ObLockMemtable()
max_committed_scn_(),
is_frozen_(false),
need_check_tablet_status_(false),
transfer_counter_(0),
freezer_(nullptr),
flush_lock_(common::ObLatchIds::CLOG_CKPT_LOCK)
{}
@ -259,6 +260,7 @@ void ObLockMemtable::reset()
flushed_scn_.set_min();
is_frozen_ = false;
need_check_tablet_status_ = false;
transfer_counter_ = 0;
freezer_ = nullptr;
is_inited_ = false;
reset_trace_id();
@ -279,6 +281,8 @@ int ObLockMemtable::lock_(
ObLockStep succ_step = STEP_BEGIN;
bool register_to_deadlock = false;
ObTxIDSet conflict_tx_set;
int64_t input_transfer_counter = -1;
int64_t output_transfer_counter = -1;
// 1. record lock myself(check conflict).
// 2. record lock at memtable ctx.
@ -294,7 +298,9 @@ int ObLockMemtable::lock_(
ObMvccWriteGuard guard;
if (OB_FAIL(guard.write_auth(ctx))) {
LOG_WARN("not allow lock table.", K(ret), K(ctx));
} else if (OB_FAIL(check_tablet_write_allow_(lock_op))) {
} else if (OB_FAIL(check_tablet_write_allow_(lock_op,
input_transfer_counter,
output_transfer_counter))) {
LOG_WARN("check tablet write allow failed", K(ret), K(lock_op));
} else {
mem_ctx = static_cast<ObMemtableCtx *>(ctx.mvcc_acc_ctx_.mem_ctx_);
@ -326,6 +332,11 @@ int ObLockMemtable::lock_(
need_retry = true;
}
LOG_WARN("record lock at mem_ctx failed.", K(ret), K(lock_op));
} else {
input_transfer_counter = output_transfer_counter;
ret = check_tablet_write_allow_(lock_op,
input_transfer_counter,
output_transfer_counter);
}
}
if (OB_FAIL(ret) && succ_step == STEP_IN_LOCK_MGR) {
@ -427,7 +438,9 @@ int ObLockMemtable::lock_(
return ret;
}
int ObLockMemtable::check_tablet_write_allow_(const ObTableLockOp &lock_op)
int ObLockMemtable::check_tablet_write_allow_(const ObTableLockOp &lock_op,
const int64_t input_transfer_counter,
int64_t &output_transfer_counter)
{
int ret = OB_SUCCESS;
ObTabletID tablet_id;
@ -436,7 +449,14 @@ int ObLockMemtable::check_tablet_write_allow_(const ObTableLockOp &lock_op)
ObTabletHandle tablet_handle;
ObTabletCreateDeleteMdsUserData data;
bool is_commited = false;
if (!need_check_tablet_status_) {
// the order must be ensured
bool need_check_tablet_status = ATOMIC_LOAD(&need_check_tablet_status_);
output_transfer_counter = ATOMIC_LOAD(&transfer_counter_);
if (!need_check_tablet_status // transfer is not on going
&& (input_transfer_counter < 0 // no transfer is between two check_tablet_write_allow
|| input_transfer_counter == output_transfer_counter)) {
} else if (!lock_op.lock_id_.is_tablet_lock()) {
} else if (OB_FAIL(lock_op.lock_id_.convert_to(tablet_id))) {
LOG_WARN("convert lock id to tablet_id failed", K(ret), K(lock_op));
@ -479,6 +499,8 @@ int ObLockMemtable::unlock_(
bool need_retry = false;
uint64_t unused_lock_mode_cnt_in_same_trans[TABLE_LOCK_MODE_COUNT] = {0, 0, 0, 0, 0};
ObLockStep succ_step = STEP_BEGIN;
int64_t input_transfer_counter = -1;
int64_t output_transfer_counter = -1;
// 1. record unlock op myself(check conflict).
// 2. record unlock op at memtable ctx.
@ -497,7 +519,9 @@ int ObLockMemtable::unlock_(
LOG_WARN("unlock timeout", K(ret), K(unlock_op), K(expired_time));
} else if (OB_FAIL(guard.write_auth(ctx))) {
LOG_WARN("not allow unlock table.", K(ret), K(ctx));
} else if (OB_FAIL(check_tablet_write_allow_(unlock_op))) {
} else if (OB_FAIL(check_tablet_write_allow_(unlock_op,
input_transfer_counter,
output_transfer_counter))) {
LOG_WARN("check tablet write allow failed", K(ret), K(unlock_op));
} else if (FALSE_IT(mem_ctx = static_cast<ObMemtableCtx *>(ctx.mvcc_acc_ctx_.mem_ctx_))) {
// check whether the unlock op exist already
@ -520,6 +544,11 @@ int ObLockMemtable::unlock_(
need_retry = true;
}
LOG_WARN("record lock at mem_ctx failed.", K(ret), K(unlock_op));
} else {
input_transfer_counter = output_transfer_counter;
ret = check_tablet_write_allow_(unlock_op,
input_transfer_counter,
output_transfer_counter);
}
if (OB_FAIL(ret) && succ_step == STEP_IN_LOCK_MGR) {
obj_lock_map_.remove_lock_record(unlock_op);
@ -1546,6 +1575,13 @@ int ObLockMemtable::check_and_set_tx_lock_timeout_(const ObMvccAccessCtx &acc_ct
return ret;
}
void ObLockMemtable::enable_check_tablet_status(const bool need_check)
{
// the order must be ensured
ATOMIC_INC(&transfer_counter_);
ATOMIC_STORE(&need_check_tablet_status_, need_check);
}
} // tablelock
} // transaction
} // oceanbase

View File

@ -287,7 +287,7 @@ public:
void set_flushed_scn(const share::SCN &flushed_scn) { flushed_scn_ = flushed_scn; }
void enable_check_tablet_status(const bool need_check) { ATOMIC_STORE(&need_check_tablet_status_, need_check); }
void enable_check_tablet_status(const bool need_check);
INHERIT_TO_STRING_KV("ObITable", ObITable, KP(this), K_(snapshot_version), K_(ls_id));
private:
@ -338,7 +338,9 @@ private:
const ObTableLockOp &lock_op);
int unregister_from_deadlock_detector_(const ObTableLockOp &lock_op);
int check_tablet_write_allow_(const ObTableLockOp &lock_op);
int check_tablet_write_allow_(const ObTableLockOp &lock_op,
const int64_t input_transfer_counter,
int64_t &output_transfer_counter);
int get_lock_wait_expire_ts_(const int64_t lock_wait_start_ts);
int check_and_set_tx_lock_timeout_(const memtable::ObMvccAccessCtx &acc_ctx);
private:
@ -360,8 +362,10 @@ private:
share::SCN pre_rec_scn_;
share::SCN max_committed_scn_;
bool is_frozen_;
// for tablet transfer enable check tablet status
// for transfer to enable tablet status check
bool need_check_tablet_status_;
// for detect the transfer between the table lock operation
int64_t transfer_counter_;
storage::ObFreezer *freezer_;
RWLock flush_lock_; // lock before change ts