add double check for lock table during register table lock callback
This commit is contained in:
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user