/** * Copyright (c) 2023 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #include "mds_table_base.h" #include "lib/lock/ob_small_spin_lock.h" #include "lib/ob_errno.h" #include "lib/profile/ob_trace_id.h" #include "ob_clock_generator.h" #include "share/scn.h" #include "storage/tx_storage/ob_ls_service.h" #include "storage/compaction/ob_schedule_dag_func.h" #include "storage/multi_data_source/ob_mds_table_merge_dag_param.h" #include "storage/tx/ob_multi_data_source.h" namespace oceanbase { namespace storage { namespace mds { TLOCAL(transaction::NotifyType, TLOCAL_MDS_TRANS_NOTIFY_TYPE) = transaction::NotifyType::UNKNOWN; int MdsTableBase::advance_state_to(State new_state) const { int ret = OB_SUCCESS; MDS_TG(1_ms); bool success = false; while (!success && OB_SUCC(ret)) { State old_state = ATOMIC_LOAD(&state_); if (new_state < old_state) {// no need advance break; } else if (!StateChecker[old_state][new_state]) { ret = OB_STATE_NOT_MATCH; MDS_LOG(WARN, "not allow switch mds table state", KR(ret), K(*this), K(state_to_string(old_state)), K(state_to_string(new_state))); } else { success = ATOMIC_BCAS(&state_, old_state, new_state); } } return ret; } int MdsTableBase::init(const ObTabletID tablet_id, const share::ObLSID ls_id, ObTabletPointer *pointer, ObMdsTableMgr *p_mgr) { int ret = OB_SUCCESS; MDS_TG(1_ms); if (!ls_id.is_valid() || !tablet_id.is_valid()) { ret = OB_INVALID_ARGUMENT; MDS_LOG(ERROR, "invalid argument", KR(ret), K(*this), K(ls_id), K(tablet_id)); } else if (MDS_FAIL(advance_state_to(State::INIT))) { MDS_LOG(ERROR, "mds table maybe init twice", KR(ret), K(*this), K(ls_id), K(tablet_id)); } else { tablet_id_ = tablet_id; ls_id_ = ls_id; if (OB_NOT_NULL(p_mgr)) { mgr_handle_.set_mds_table_mgr(p_mgr); debug_info_.do_init_tablet_pointer_ = pointer; debug_info_.init_trace_id_ = *ObCurTraceId::get_trace_id(); debug_info_.init_ts_ = ObClockGenerator::getClock(); if (MDS_FAIL(register_to_mds_table_mgr())) { MDS_LOG(WARN, "fail to register mds table", KR(ret), K(*this), K(ls_id), K(tablet_id)); } } MDS_LOG(INFO, "mds table inited", KR(ret), K(*this)); } return ret; } int MdsTableBase::register_to_mds_table_mgr() { int ret = OB_SUCCESS; MDS_TG(1_ms); if (OB_ISNULL(mgr_handle_.get_mds_table_mgr())) { ret = OB_BAD_NULL_ERROR; MDS_LOG(WARN, "mds_table_mgr ptr is null", KR(ret), K(*this)); } else if (MDS_FAIL(mgr_handle_.get_mds_table_mgr()->register_to_mds_table_mgr(this))) { MDS_LOG(WARN, "fail to register mds table", KR(ret), K(*this)); } return ret; } void MdsTableBase::mark_removed_from_t3m(ObTabletPointer *pointer) { MDS_TG(1_ms); int ret = OB_SUCCESS; if (ATOMIC_LOAD(&debug_info_.remove_ts_) != 0) { MDS_LOG_RET(WARN, OB_ERR_UNEXPECTED, "this MdsTable has been marked removed", K(*this)); } else if (MDS_FAIL(unregister_from_mds_table_mgr())) { MDS_LOG(WARN, "unregister from mds_table_mgr failed", KR(ret), K(*this)); } else { debug_info_.do_remove_tablet_pointer_ = pointer; debug_info_.remove_trace_id_ = *ObCurTraceId::get_trace_id(); ATOMIC_STORE(&debug_info_.remove_ts_, ObClockGenerator::getClock()); } } void MdsTableBase::mark_switched_to_empty_shell() { if (ATOMIC_LOAD(&debug_info_.switch_to_empty_shell_ts_) != 0) { MDS_LOG_RET(WARN, OB_ERR_UNEXPECTED, "this MdsTable has been marked switch to empty shell", K(*this)); } else { ATOMIC_STORE(&debug_info_.switch_to_empty_shell_ts_, ObClockGenerator::getClock()); } } bool MdsTableBase::is_switched_to_empty_shell() const { return ATOMIC_LOAD(&debug_info_.switch_to_empty_shell_ts_) != 0; } bool MdsTableBase::is_removed_from_t3m() const { return ATOMIC_LOAD(&debug_info_.remove_ts_) != 0; } int64_t MdsTableBase::get_removed_from_t3m_ts() const { return ATOMIC_LOAD(&debug_info_.remove_ts_); } int MdsTableBase::unregister_from_mds_table_mgr() { int ret = OB_SUCCESS; MDS_TG(1_ms); if (!mgr_handle_.is_valid()) { MDS_LOG(INFO, "no need unregister from mds_table_mgr cause invalid mds_table_mgr", KR(ret), K(*this)); } else if (!ls_id_.is_valid() || !tablet_id_.is_valid()) { MDS_LOG(INFO, "no need unregister from mds_table_mgr cause invalid id", KR(ret), K(*this)); } else if (MDS_FAIL(mgr_handle_.get_mds_table_mgr()->unregister_from_mds_table_mgr(this))) { MDS_LOG(ERROR, "fail to unregister mds table", K(*this)); } return ret; } int MdsTableBase::unregister_from_removed_recorder() { int ret = OB_SUCCESS; MDS_TG(1_ms); if (!mgr_handle_.is_valid()) { MDS_LOG(INFO, "no need unregister from mds_table_mgr cause invalid mds_table_mgr", KR(ret), K(*this)); } else if (!ls_id_.is_valid() || !tablet_id_.is_valid()) { MDS_LOG(INFO, "no need unregister from mds_table_mgr cause invalid id", KR(ret), K(*this)); } else { mgr_handle_.get_mds_table_mgr()->unregister_from_removed_mds_table_recorder(this); mgr_handle_.reset(); } return ret; } int MdsTableBase::get_ls_max_consequent_callbacked_scn_(share::SCN &max_consequent_callbacked_scn) const { int ret = OB_SUCCESS; ObLSService *ls_service = MTL(ObLSService *); ObLSHandle ls_handle; MDS_TG(1_ms); if (!ls_id_.is_valid()) { ret = OB_ERR_UNEXPECTED; MDS_LOG(WARN, "ls id not valid", KR(ret), K(*this)); } else if (OB_ISNULL(ls_service)) { ret = OB_BAD_NULL_ERROR; MDS_LOG(WARN, "ls tx service is null", KR(ret), K(*this)); } else if (MDS_FAIL(ls_service->get_ls(ls_id_, ls_handle, ObLSGetMod::MDS_TABLE_MOD))) { MDS_LOG(WARN, "fail to get ls handle", KR(ret), K(*this)); } else if (MDS_FAIL(ls_handle.get_ls()->get_freezer()->get_max_consequent_callbacked_scn(max_consequent_callbacked_scn))) { MDS_LOG(WARN, "fail to get max_consequent_callbacked_scn", KR(ret), K(*this)); } return ret; } int MdsTableBase::merge(const int64_t construct_sequence, const share::SCN &flushing_scn) { int ret = OB_SUCCESS; ObMdsTableMergeDagParam param; param.ls_id_ = ls_id_; param.tablet_id_ = tablet_id_; param.flush_scn_ = flushing_scn; param.mds_construct_sequence_ = construct_sequence; param.generate_ts_ = ObClockGenerator::getClock(); param.merge_type_ = compaction::ObMergeType::MDS_MINI_MERGE; param.merge_version_ = 0; if (OB_FAIL(compaction::ObScheduleDagFunc::schedule_mds_table_merge_dag(param))) { if (OB_EAGAIN != ret && OB_SIZE_OVERFLOW != ret) { MDS_LOG(WARN, "failed to schedule mds table merge dag", K(ret), K(param)); } } else { MDS_LOG(DEBUG, "succeeded to schedule mds table merge dag", K(ret), K(param)); } return ret; } int64_t MdsTableBase::get_node_cnt() const { int64_t total_cnt = ATOMIC_LOAD(&total_node_cnt_); if (total_cnt < 0) { MDS_LOG_RET(ERROR, OB_ERR_SYS, "total_valid_node_cnt_ is less than 0", KP(this), K(total_cnt)); } return total_cnt; } void MdsTableBase::inc_valid_node_cnt() { if (ATOMIC_AAF(&total_node_cnt_, 1) <= 0) { MDS_LOG_RET(ERROR, OB_ERR_SYS, "total_valid_node_cnt_ is less than 0", KP(this), K(total_node_cnt_)); } } void MdsTableBase::dec_valid_node_cnt() { if (ATOMIC_AAF(&total_node_cnt_, -1) < 0) { MDS_LOG_RET(ERROR, OB_ERR_SYS, "total_valid_node_cnt_ is less than 0", KP(this), K(total_node_cnt_)); } } void MdsTableBase::try_advance_rec_scn(const share::SCN scn) { bool success = false; while (!success) { share::SCN old_scn = rec_scn_; if (scn > old_scn) { success = rec_scn_.atomic_bcas(old_scn, scn); if (success) { report_rec_scn_event_("ADVANCE_REC_SCN", old_scn, scn); } } else { break; } } } void MdsTableBase::try_decline_rec_scn(const share::SCN scn) { bool success = false; while (!success) { share::SCN old_scn = rec_scn_; if (scn < old_scn) { success = rec_scn_.atomic_bcas(old_scn, scn); if (success) { report_rec_scn_event_("DECLINE_REC_SCN", old_scn, scn); } } else { break; } } } common::ObTabletID MdsTableBase::get_tablet_id() const { return tablet_id_; } share::ObLSID MdsTableBase::get_ls_id() const { return ls_id_; } share::SCN MdsTableBase::get_rec_scn() { return rec_scn_.atomic_get(); } bool MdsTableBase::is_flushing() const { MdsRLockGuard lg(lock_); return flushing_scn_.is_valid(); } bool check_node_scn_beflow_flush(const MdsNode &node, const share::SCN &flush_scn) { bool need_dump = false; if (node.end_scn_ <= flush_scn) {// change to redo_scn <= flush_scn after support dump uncommitted node need_dump = true; } return need_dump; } } // namespace mds } // namespace storage } // namespace oceanbase