diff --git a/src/storage/high_availability/ob_transfer_handler.cpp b/src/storage/high_availability/ob_transfer_handler.cpp index 1f5c516d92..e7a506acbe 100644 --- a/src/storage/high_availability/ob_transfer_handler.cpp +++ b/src/storage/high_availability/ob_transfer_handler.cpp @@ -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, diff --git a/src/storage/tablelock/ob_lock_memtable.cpp b/src/storage/tablelock/ob_lock_memtable.cpp index bb5da796af..6859543e79 100644 --- a/src/storage/tablelock/ob_lock_memtable.cpp +++ b/src/storage/tablelock/ob_lock_memtable.cpp @@ -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(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(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 diff --git a/src/storage/tablelock/ob_lock_memtable.h b/src/storage/tablelock/ob_lock_memtable.h index 6ac1341456..cc57a55e42 100644 --- a/src/storage/tablelock/ob_lock_memtable.h +++ b/src/storage/tablelock/ob_lock_memtable.h @@ -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