[MDS] fix thread deadlock between DAG and tablet and mds_table
This commit is contained in:
2
deps/oblib/src/lib/stat/ob_latch_define.cpp
vendored
2
deps/oblib/src/lib/stat/ob_latch_define.cpp
vendored
@ -22,7 +22,7 @@ const ObLatchDesc OB_LATCHES[] = {
|
|||||||
#undef LATCH_DEF
|
#undef LATCH_DEF
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(ARRAYSIZEOF(OB_LATCHES) == 312, "DO NOT delete latch defination");
|
static_assert(ARRAYSIZEOF(OB_LATCHES) == 313, "DO NOT delete latch defination");
|
||||||
static_assert(ObLatchIds::LATCH_END == ARRAYSIZEOF(OB_LATCHES) - 1, "update id of LATCH_END before adding your defination");
|
static_assert(ObLatchIds::LATCH_END == ARRAYSIZEOF(OB_LATCHES) - 1, "update id of LATCH_END before adding your defination");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
4
deps/oblib/src/lib/stat/ob_latch_define.h
vendored
4
deps/oblib/src/lib/stat/ob_latch_define.h
vendored
@ -324,8 +324,8 @@ LATCH_DEF(LOG_EXTERNAL_STORAGE_HANDLER_RW_LOCK, 308, "log external storage handl
|
|||||||
LATCH_DEF(LOG_EXTERNAL_STORAGE_HANDLER_LOCK, 309, "log external storage handler spin lock", LATCH_FIFO, 2000, 0, LOG_EXTERNAL_STORAGE_HANDLER_WAIT, "log external storage handler spin lock")
|
LATCH_DEF(LOG_EXTERNAL_STORAGE_HANDLER_LOCK, 309, "log external storage handler spin lock", LATCH_FIFO, 2000, 0, LOG_EXTERNAL_STORAGE_HANDLER_WAIT, "log external storage handler spin lock")
|
||||||
|
|
||||||
LATCH_DEF(PL_DEBUG_RUNTIMEINFO_LOCK, 310, "PL DEBUG RuntimeInfo lock", LATCH_FIFO, 2000, 0, PL_DEBUG_RUNTIME_INFO_WAIT, "PL DEBUG RuntimeInfo lock")
|
LATCH_DEF(PL_DEBUG_RUNTIMEINFO_LOCK, 310, "PL DEBUG RuntimeInfo lock", LATCH_FIFO, 2000, 0, PL_DEBUG_RUNTIME_INFO_WAIT, "PL DEBUG RuntimeInfo lock")
|
||||||
|
LATCH_DEF(MDS_TABLE_HANDLER_LOCK, 311, "mds table handler lock", LATCH_READ_PREFER, 2000, 0, MDS_TABLE_HANDLER_WAIT, "mds table handler lock")
|
||||||
LATCH_DEF(LATCH_END, 311, "latch end", LATCH_FIFO, 2000, 0, WAIT_EVENT_END, "latch end")
|
LATCH_DEF(LATCH_END, 312, "latch end", LATCH_FIFO, 2000, 0, WAIT_EVENT_END, "latch end")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OB_LATCH_DEFINE_H_
|
#ifndef OB_LATCH_DEFINE_H_
|
||||||
|
|||||||
@ -368,6 +368,7 @@ WAIT_EVENT_DEF(GC_HANDLER_WAIT, 16054, "gc handler lock wait", "", "", "", CONCU
|
|||||||
WAIT_EVENT_DEF(FREEZE_THREAD_POOL_WAIT, 16055, "freeze thread pool wait", "", "", "", CONCURRENCY, "FREEZE_THREAD_POOL_WAIT", true)
|
WAIT_EVENT_DEF(FREEZE_THREAD_POOL_WAIT, 16055, "freeze thread pool wait", "", "", "", CONCURRENCY, "FREEZE_THREAD_POOL_WAIT", true)
|
||||||
WAIT_EVENT_DEF(DDL_EXECUTE_LOCK_WAIT, 16056, "ddl execute lock wait", "", "", "", CONCURRENCY, "DDL_EXECUTE_LOCK_WAIT", true)
|
WAIT_EVENT_DEF(DDL_EXECUTE_LOCK_WAIT, 16056, "ddl execute lock wait", "", "", "", CONCURRENCY, "DDL_EXECUTE_LOCK_WAIT", true)
|
||||||
WAIT_EVENT_DEF(DUP_TABLET_LOCK_WAIT, 16057, "dup tablet lock wait", "", "", "", CONCURRENCY, "DUP_TABLET_LOCK_WAIT", true)
|
WAIT_EVENT_DEF(DUP_TABLET_LOCK_WAIT, 16057, "dup tablet lock wait", "", "", "", CONCURRENCY, "DUP_TABLET_LOCK_WAIT", true)
|
||||||
|
WAIT_EVENT_DEF(MDS_TABLE_HANDLER_WAIT, 16058, "mds table handler wait", "", "", "", CONCURRENCY, "MDS_TABLE_HANDLER_WAIT", true)
|
||||||
|
|
||||||
// WAIT_EVENT_DEF(TENANT_MGR_TENANT_BUCKET_LOCK_WAIT, 16056, "tenant mgr tenant bucket lock wait", "", "", "", CONCURRENCY, "TENANT_MGR_TENANT_BUCKET_LOCK_WAIT", true)
|
// WAIT_EVENT_DEF(TENANT_MGR_TENANT_BUCKET_LOCK_WAIT, 16056, "tenant mgr tenant bucket lock wait", "", "", "", CONCURRENCY, "TENANT_MGR_TENANT_BUCKET_LOCK_WAIT", true)
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ int BufferCtxNode::serialize(char *buf, const int64_t buf_len, int64_t &pos) con
|
|||||||
MDS_TG(10_ms);
|
MDS_TG(10_ms);
|
||||||
if (OB_NOT_NULL(ctx_)) {
|
if (OB_NOT_NULL(ctx_)) {
|
||||||
// 序列化时,如果ctx不为空,那么其类型必须是有效的,这里防御一下,否则反序列化的报错会增加排查难度
|
// 序列化时,如果ctx不为空,那么其类型必须是有效的,这里防御一下,否则反序列化的报错会增加排查难度
|
||||||
OB_ASSERT(ctx_->get_binding_type_id() != INVALID_VALUE);
|
MDS_ASSERT(ctx_->get_binding_type_id() != INVALID_VALUE);
|
||||||
int64_t type_id = ctx_->get_binding_type_id();
|
int64_t type_id = ctx_->get_binding_type_id();
|
||||||
if (MDS_FAIL(serialization::encode(buf, buf_len, pos, type_id))) {
|
if (MDS_FAIL(serialization::encode(buf, buf_len, pos, type_id))) {
|
||||||
MDS_LOG(ERROR, "serialize buffer ctx id failed", KR(ret), K(type_id));
|
MDS_LOG(ERROR, "serialize buffer ctx id failed", KR(ret), K(type_id));
|
||||||
|
|||||||
@ -63,7 +63,7 @@ class BufferCtxNode
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BufferCtxNode() : ctx_(nullptr) {}
|
BufferCtxNode() : ctx_(nullptr) {}
|
||||||
void set_ctx(BufferCtx *ctx) { OB_ASSERT(ctx_ == nullptr); ctx_ = ctx; }// 预期不应该出现覆盖的情况
|
void set_ctx(BufferCtx *ctx) { MDS_ASSERT(ctx_ == nullptr); ctx_ = ctx; }// 预期不应该出现覆盖的情况
|
||||||
const BufferCtx *get_ctx() const { return ctx_; }
|
const BufferCtx *get_ctx() const { return ctx_; }
|
||||||
void destroy_ctx();
|
void destroy_ctx();
|
||||||
void on_redo(const share::SCN &redo_scn) { ctx_->on_redo(redo_scn); }
|
void on_redo(const share::SCN &redo_scn) { ctx_->on_redo(redo_scn); }
|
||||||
|
|||||||
@ -35,7 +35,7 @@ MdsCtx::~MdsCtx()
|
|||||||
MdsWLockGuard lg(lock_);
|
MdsWLockGuard lg(lock_);
|
||||||
list_empty = write_list_.empty();
|
list_empty = write_list_.empty();
|
||||||
if (!list_empty) {
|
if (!list_empty) {
|
||||||
OB_ASSERT(state_ != TwoPhaseCommitState::ON_COMMIT);// if decided, list is empty
|
MDS_ASSERT(state_ != TwoPhaseCommitState::ON_COMMIT);// if decided, list is empty
|
||||||
MDS_LOG_RET(INFO, OB_SUCCESS, "nodes not commit or abort when mds ctx destroyed", K(*this));
|
MDS_LOG_RET(INFO, OB_SUCCESS, "nodes not commit or abort when mds ctx destroyed", K(*this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ void MdsCtx::record_written_node(ListNode<MdsNode> *node)
|
|||||||
|
|
||||||
void MdsCtx::on_redo(const share::SCN &redo_scn)
|
void MdsCtx::on_redo(const share::SCN &redo_scn)
|
||||||
{
|
{
|
||||||
OB_ASSERT(writer_.writer_type_ == WriterType::TRANSACTION);// can only called by TRANS, or must call single_log_commit()
|
MDS_ASSERT(writer_.writer_type_ == WriterType::TRANSACTION);// can only called by TRANS, or must call single_log_commit()
|
||||||
do_while_retry_with_lock_until_success_for_all_([this, redo_scn]() {// if failed on any node, will release lock and try from first node again
|
do_while_retry_with_lock_until_success_for_all_([this, redo_scn]() {// if failed on any node, will release lock and try from first node again
|
||||||
return for_each_node_try_([redo_scn](MdsNode &node) {// the operation tried on each node
|
return for_each_node_try_([redo_scn](MdsNode &node) {// the operation tried on each node
|
||||||
bool try_success = true;
|
bool try_success = true;
|
||||||
@ -93,11 +93,13 @@ void MdsCtx::on_redo(const share::SCN &redo_scn)
|
|||||||
|
|
||||||
void MdsCtx::before_prepare()
|
void MdsCtx::before_prepare()
|
||||||
{
|
{
|
||||||
OB_ASSERT(writer_.writer_type_ == WriterType::TRANSACTION);// can only called by TRANS, or must call single_log_commit()
|
MDS_ASSERT(writer_.writer_type_ == WriterType::TRANSACTION);// can only called by TRANS, or must call single_log_commit()
|
||||||
do_while_retry_with_lock_until_success_for_all_([this]() {// if failed on any node, will release lock and try from first node again
|
do_while_retry_with_lock_until_success_for_all_([this]() {// if failed on any node, will release lock and try from first node again
|
||||||
return for_each_node_try_([](MdsNode &node) {// the operation tried on each node
|
return for_each_node_try_([](MdsNode &node) {// the operation tried on each node
|
||||||
bool try_success = true;
|
bool try_success = true;
|
||||||
if (node.status_.get_state() < TwoPhaseCommitState::BEFORE_PREPARE) {// avoid try lock
|
if (node.status_.get_state() == TwoPhaseCommitState::ON_PREPARE) {// due to force majeure
|
||||||
|
// do nothing, just accept it
|
||||||
|
} else if (node.status_.get_state() < TwoPhaseCommitState::BEFORE_PREPARE) {// avoid try lock
|
||||||
try_success = node.try_before_prepare();
|
try_success = node.try_before_prepare();
|
||||||
}
|
}
|
||||||
return try_success;
|
return try_success;
|
||||||
@ -107,7 +109,7 @@ void MdsCtx::before_prepare()
|
|||||||
|
|
||||||
void MdsCtx::on_prepare(const share::SCN &prepare_version)
|
void MdsCtx::on_prepare(const share::SCN &prepare_version)
|
||||||
{
|
{
|
||||||
OB_ASSERT(writer_.writer_type_ == WriterType::TRANSACTION);// can only called by TRANS, or must call single_log_commit()
|
MDS_ASSERT(writer_.writer_type_ == WriterType::TRANSACTION);// can only called by TRANS, or must call single_log_commit()
|
||||||
do_while_retry_with_lock_until_success_for_all_([this, prepare_version]() {// if failed on any node, will release lock and try from first node again
|
do_while_retry_with_lock_until_success_for_all_([this, prepare_version]() {// if failed on any node, will release lock and try from first node again
|
||||||
return for_each_node_try_([prepare_version](MdsNode &node) {// the operation tried on each node
|
return for_each_node_try_([prepare_version](MdsNode &node) {// the operation tried on each node
|
||||||
bool try_success = true;
|
bool try_success = true;
|
||||||
@ -121,7 +123,7 @@ void MdsCtx::on_prepare(const share::SCN &prepare_version)
|
|||||||
|
|
||||||
void MdsCtx::on_commit(const share::SCN &commit_version, const share::SCN &commit_scn)
|
void MdsCtx::on_commit(const share::SCN &commit_version, const share::SCN &commit_scn)
|
||||||
{
|
{
|
||||||
OB_ASSERT(writer_.writer_type_ == WriterType::TRANSACTION);// can only called by TRANS, or must call single_log_commit()
|
MDS_ASSERT(writer_.writer_type_ == WriterType::TRANSACTION);// can only called by TRANS, or must call single_log_commit()
|
||||||
do_while_retry_with_lock_until_success_for_all_([this, commit_version, commit_scn]() {// if failed on any node, will release lock and try from first node again
|
do_while_retry_with_lock_until_success_for_all_([this, commit_version, commit_scn]() {// if failed on any node, will release lock and try from first node again
|
||||||
return for_each_node_fetch_to_try_([commit_version, commit_scn](MdsNode &node) {// the operation tried on each node, if failed, the fetched node will be insert to head again to rollback
|
return for_each_node_fetch_to_try_([commit_version, commit_scn](MdsNode &node) {// the operation tried on each node, if failed, the fetched node will be insert to head again to rollback
|
||||||
bool try_success = true;
|
bool try_success = true;
|
||||||
@ -161,7 +163,7 @@ void MdsCtx::single_log_commit(const share::SCN commit_version, const share::SCN
|
|||||||
|
|
||||||
void MdsCtx::single_log_abort()
|
void MdsCtx::single_log_abort()
|
||||||
{
|
{
|
||||||
OB_ASSERT(writer_.writer_type_ != WriterType::TRANSACTION);// TRANSACTION use two-phase-commit
|
MDS_ASSERT(writer_.writer_type_ != WriterType::TRANSACTION);// TRANSACTION use two-phase-commit
|
||||||
do_while_retry_with_lock_until_success_for_all_([this]() {// if failed on any node, will release lock and try from first node again
|
do_while_retry_with_lock_until_success_for_all_([this]() {// if failed on any node, will release lock and try from first node again
|
||||||
return for_each_node_fetch_to_try_([](MdsNode &node) {// the operation tried on each node, if failed, the fetched node will be insert to head again to rollback
|
return for_each_node_fetch_to_try_([](MdsNode &node) {// the operation tried on each node, if failed, the fetched node will be insert to head again to rollback
|
||||||
bool try_success = true;
|
bool try_success = true;
|
||||||
|
|||||||
@ -70,6 +70,10 @@ private:
|
|||||||
int64_t try_times = 0;
|
int64_t try_times = 0;
|
||||||
do {
|
do {
|
||||||
MdsWLockGuard lg(lock_);
|
MdsWLockGuard lg(lock_);
|
||||||
|
if (state_ == TwoPhaseCommitState::ON_PREPARE && new_state == TwoPhaseCommitState::BEFORE_PREPARE) {// due to force majeure
|
||||||
|
// do nothing, just accept it
|
||||||
|
operate_all_nodes_succeed = true;
|
||||||
|
} else {
|
||||||
operate_all_nodes_succeed = op();
|
operate_all_nodes_succeed = op();
|
||||||
if (OB_LIKELY(operate_all_nodes_succeed)) {
|
if (OB_LIKELY(operate_all_nodes_succeed)) {
|
||||||
if (new_state != TwoPhaseCommitState::STATE_END) {
|
if (new_state != TwoPhaseCommitState::STATE_END) {
|
||||||
@ -78,6 +82,7 @@ private:
|
|||||||
} else if (OB_UNLIKELY((++try_times % 10000) == 0)) {
|
} else if (OB_UNLIKELY((++try_times % 10000) == 0)) {
|
||||||
MDS_LOG_RET(WARN, OB_ERR_TOO_MUCH_TIME, "do-while retry too much times", K(try_times), K(*this));
|
MDS_LOG_RET(WARN, OB_ERR_TOO_MUCH_TIME, "do-while retry too much times", K(try_times), K(*this));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} while (!operate_all_nodes_succeed && ({PAUSE(); true;}));// keep trying lock until success, while-try is for avoid thread deadlock
|
} while (!operate_all_nodes_succeed && ({PAUSE(); true;}));// keep trying lock until success, while-try is for avoid thread deadlock
|
||||||
}
|
}
|
||||||
template <typename OP, ENABLE_IF_LIKE_FUNCTION(OP, bool(MdsNode &node))>
|
template <typename OP, ENABLE_IF_LIKE_FUNCTION(OP, bool(MdsNode &node))>
|
||||||
|
|||||||
@ -63,10 +63,10 @@ void MdsNodeStatus::advance(TwoPhaseCommitState new_stat)// ATOMIC
|
|||||||
MdsNodeStatus old_node_status, new_node_status;
|
MdsNodeStatus old_node_status, new_node_status;
|
||||||
do {
|
do {
|
||||||
old_node_status.union_.value_ = ATOMIC_LOAD(&union_.value_);
|
old_node_status.union_.value_ = ATOMIC_LOAD(&union_.value_);
|
||||||
OB_ASSERT(new_stat >= old_node_status.union_.field_.state_ &&
|
MDS_ASSERT(new_stat >= old_node_status.union_.field_.state_ &&
|
||||||
new_stat < TwoPhaseCommitState::STATE_END &&
|
new_stat < TwoPhaseCommitState::STATE_END &&
|
||||||
new_stat > TwoPhaseCommitState::STATE_INIT);
|
new_stat > TwoPhaseCommitState::STATE_INIT);
|
||||||
OB_ASSERT(STATE_CHECK_ALLOWED_MAP[(int)old_node_status.union_.field_.state_][(int)new_stat] == true);
|
MDS_ASSERT(STATE_CHECK_ALLOWED_MAP[(int)old_node_status.union_.field_.state_][(int)new_stat] == true);
|
||||||
new_node_status.union_.value_ = old_node_status.union_.value_;
|
new_node_status.union_.value_ = old_node_status.union_.value_;
|
||||||
new_node_status.union_.field_.state_ = new_stat;
|
new_node_status.union_.field_.state_ = new_stat;
|
||||||
} while (!ATOMIC_BCAS(&union_.value_, old_node_status.union_.value_, new_node_status.union_.value_));
|
} while (!ATOMIC_BCAS(&union_.value_, old_node_status.union_.value_, new_node_status.union_.value_));
|
||||||
|
|||||||
@ -167,7 +167,7 @@ template <typename K, typename V>
|
|||||||
void UserMdsNode<K, V>::before_prepare_()
|
void UserMdsNode<K, V>::before_prepare_()
|
||||||
{
|
{
|
||||||
if (status_.union_.field_.state_ == TwoPhaseCommitState::BEFORE_PREPARE) {// reentrant
|
if (status_.union_.field_.state_ == TwoPhaseCommitState::BEFORE_PREPARE) {// reentrant
|
||||||
OB_ASSERT(trans_version_.is_min());
|
MDS_ASSERT(trans_version_.is_min());
|
||||||
} else {
|
} else {
|
||||||
status_.advance(TwoPhaseCommitState::BEFORE_PREPARE);
|
status_.advance(TwoPhaseCommitState::BEFORE_PREPARE);
|
||||||
trans_version_.set_min();// block all read operation
|
trans_version_.set_min();// block all read operation
|
||||||
@ -192,7 +192,7 @@ void UserMdsNode<K, V>::on_prepare_(const share::SCN &prepare_version)
|
|||||||
{
|
{
|
||||||
if (status_.union_.field_.state_ == TwoPhaseCommitState::ON_PREPARE) {// reentrant
|
if (status_.union_.field_.state_ == TwoPhaseCommitState::ON_PREPARE) {// reentrant
|
||||||
if (is_valid_scn_(prepare_version)) {
|
if (is_valid_scn_(prepare_version)) {
|
||||||
OB_ASSERT(trans_version_ == prepare_version);
|
MDS_ASSERT(trans_version_ == prepare_version);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status_.advance(TwoPhaseCommitState::ON_PREPARE);
|
status_.advance(TwoPhaseCommitState::ON_PREPARE);
|
||||||
@ -226,8 +226,8 @@ void UserMdsNode<K, V>::on_commit_(const share::SCN &commit_version,
|
|||||||
K(*this), K(commit_version), K(commit_scn));
|
K(*this), K(commit_version), K(commit_scn));
|
||||||
} else {
|
} else {
|
||||||
if (status_.union_.field_.state_ == TwoPhaseCommitState::ON_COMMIT) {// reentrant
|
if (status_.union_.field_.state_ == TwoPhaseCommitState::ON_COMMIT) {// reentrant
|
||||||
OB_ASSERT(trans_version_ == commit_version);
|
MDS_ASSERT(trans_version_ == commit_version);
|
||||||
OB_ASSERT(end_scn_ == commit_scn);
|
MDS_ASSERT(end_scn_ == commit_scn);
|
||||||
} else {
|
} else {
|
||||||
status_.advance(TwoPhaseCommitState::ON_COMMIT);
|
status_.advance(TwoPhaseCommitState::ON_COMMIT);
|
||||||
trans_version_ = commit_version;
|
trans_version_ = commit_version;
|
||||||
|
|||||||
@ -396,7 +396,7 @@ int MdsRow<K, V>::get_with_read_wrapper_(READ_OP &&read_operation,
|
|||||||
};
|
};
|
||||||
for_each_node_([&](const UserMdsNode<K, V> &node) {
|
for_each_node_([&](const UserMdsNode<K, V> &node) {
|
||||||
bool can_read = false;
|
bool can_read = false;
|
||||||
OB_ASSERT(!node.is_aborted_());// should not meet aborted node, cause aborted node deleted immediately
|
MDS_ASSERT(!node.is_aborted_());// should not meet aborted node, cause aborted node deleted immediately
|
||||||
if (OB_FAIL(check_node_op(node, can_read))) {
|
if (OB_FAIL(check_node_op(node, can_read))) {
|
||||||
MDS_LOG_GET(WARN, "check node can read meet failed");
|
MDS_LOG_GET(WARN, "check node can read meet failed");
|
||||||
} else if (can_read) {
|
} else if (can_read) {
|
||||||
@ -537,19 +537,19 @@ int MdsRow<K, V>::scan_dump_node_from_tail_to_head(DUMP_OP &&op,
|
|||||||
[this, &op, &ret, &dump_kv, flush_scn, for_flush, mds_table_id, mds_unit_id, &has_meet_undump_node](const UserMdsNode<K, V> &node) {
|
[this, &op, &ret, &dump_kv, flush_scn, for_flush, mds_table_id, mds_unit_id, &has_meet_undump_node](const UserMdsNode<K, V> &node) {
|
||||||
bool need_break = false;
|
bool need_break = false;
|
||||||
MDS_TG(5_ms);
|
MDS_TG(5_ms);
|
||||||
OB_ASSERT(!node.is_aborted_());// should not see aborted node, cause it is deleted immediatly
|
MDS_ASSERT(!node.is_aborted_());// should not see aborted node, cause it is deleted immediatly
|
||||||
if (!node.is_dumped_()) {
|
if (!node.is_dumped_()) {
|
||||||
has_meet_undump_node = true;// this is a barrier, mark it to defense
|
has_meet_undump_node = true;// this is a barrier, mark it to defense
|
||||||
}
|
}
|
||||||
if (!node.is_committed_()) {
|
if (!node.is_committed_()) {
|
||||||
if (node.redo_scn_.is_valid() && !flush_scn.is_max()) {
|
if (node.redo_scn_.is_valid() && !flush_scn.is_max()) {
|
||||||
OB_ASSERT(node.redo_scn_ > flush_scn);// defense
|
MDS_ASSERT(node.redo_scn_ > flush_scn);// defense
|
||||||
}
|
}
|
||||||
need_break = true;
|
need_break = true;
|
||||||
} else if (node.is_dumped_() && for_flush) {// just skip it
|
} else if (node.is_dumped_() && for_flush) {// just skip it
|
||||||
// all nodes before first undumped node should be dumped status,(reverse scan order)
|
// all nodes before first undumped node should be dumped status,(reverse scan order)
|
||||||
// and all nodes after first undumped node should be undemped status(reverse scan order)
|
// and all nodes after first undumped node should be undemped status(reverse scan order)
|
||||||
OB_ASSERT(has_meet_undump_node == false);// defense
|
MDS_ASSERT(has_meet_undump_node == false);// defense
|
||||||
} else if (!check_node_scn_beflow_flush(node, flush_scn)) {
|
} else if (!check_node_scn_beflow_flush(node, flush_scn)) {
|
||||||
need_break = true;
|
need_break = true;
|
||||||
} else if (MDS_FAIL(dump_kv.v_.init(mds_table_id,
|
} else if (MDS_FAIL(dump_kv.v_.init(mds_table_id,
|
||||||
@ -602,7 +602,7 @@ void MdsRow<K, V>::node_abort_callback_(ListNodeBase *node)
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
OB_ASSERT(has_meet_input_arg_node);
|
MDS_ASSERT(has_meet_input_arg_node);
|
||||||
}
|
}
|
||||||
#undef PRINT_WRAPPER
|
#undef PRINT_WRAPPER
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,8 +90,12 @@ int MdsTableBase::register_to_mds_table_mgr()
|
|||||||
|
|
||||||
void MdsTableBase::mark_removed_from_t3m(ObTabletPointer *pointer)
|
void MdsTableBase::mark_removed_from_t3m(ObTabletPointer *pointer)
|
||||||
{
|
{
|
||||||
|
MDS_TG(1_ms);
|
||||||
|
int ret = OB_SUCCESS;
|
||||||
if (ATOMIC_LOAD(&debug_info_.remove_ts_) != 0) {
|
if (ATOMIC_LOAD(&debug_info_.remove_ts_) != 0) {
|
||||||
MDS_LOG_RET(WARN, OB_ERR_UNEXPECTED, "this MdsTable has been marked removed", K(*this));
|
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 {
|
} else {
|
||||||
debug_info_.do_remove_tablet_pointer_ = pointer;
|
debug_info_.do_remove_tablet_pointer_ = pointer;
|
||||||
debug_info_.remove_trace_id_ = *ObCurTraceId::get_trace_id();
|
debug_info_.remove_trace_id_ = *ObCurTraceId::get_trace_id();
|
||||||
@ -133,7 +137,20 @@ int MdsTableBase::unregister_from_mds_table_mgr()
|
|||||||
MDS_LOG(INFO, "no need unregister from mds_table_mgr cause invalid id", KR(ret), K(*this));
|
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))) {
|
} 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));
|
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 {
|
} else {
|
||||||
|
mgr_handle_.get_mds_table_mgr()->unregister_from_removed_mds_table_recorder(this);
|
||||||
mgr_handle_.reset();
|
mgr_handle_.reset();
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@ -159,7 +159,7 @@ public:
|
|||||||
share::ObLSID get_ls_id() const;
|
share::ObLSID get_ls_id() const;
|
||||||
int64_t get_node_cnt() const;
|
int64_t get_node_cnt() const;
|
||||||
virtual share::SCN get_rec_scn();
|
virtual share::SCN get_rec_scn();
|
||||||
virtual int dump_status() const = 0;
|
virtual int operate(const ObFunction<int(MdsTableBase &)> &operation) = 0;
|
||||||
virtual int flush(share::SCN need_advanced_rec_scn_lower_limit) = 0;
|
virtual int flush(share::SCN need_advanced_rec_scn_lower_limit) = 0;
|
||||||
virtual ObTabletID get_tablet_id() const;
|
virtual ObTabletID get_tablet_id() const;
|
||||||
virtual bool is_flushing() const;
|
virtual bool is_flushing() const;
|
||||||
@ -178,7 +178,8 @@ protected:
|
|||||||
void try_decline_rec_scn(const share::SCN scn);
|
void try_decline_rec_scn(const share::SCN scn);
|
||||||
int get_ls_max_consequent_callbacked_scn_(share::SCN &max_consequent_callbacked_scn) const;
|
int get_ls_max_consequent_callbacked_scn_(share::SCN &max_consequent_callbacked_scn) const;
|
||||||
int register_to_mds_table_mgr();
|
int register_to_mds_table_mgr();
|
||||||
int unregister_from_mds_table_mgr();
|
int unregister_from_mds_table_mgr();// call when marked deleted or released directly
|
||||||
|
int unregister_from_removed_recorder();// call when marked deleted
|
||||||
int merge(const int64_t construct_sequence, const share::SCN &flushing_scn);
|
int merge(const int64_t construct_sequence, const share::SCN &flushing_scn);
|
||||||
template <int N>
|
template <int N>
|
||||||
void report_rec_scn_event_(const char (&event_str)[N],
|
void report_rec_scn_event_(const char (&event_str)[N],
|
||||||
|
|||||||
@ -110,7 +110,6 @@ public:
|
|||||||
int get_ref_cnt(int64_t &ref_cnt) const;
|
int get_ref_cnt(int64_t &ref_cnt) const;
|
||||||
int get_node_cnt(int64_t &valid_cnt) const;
|
int get_node_cnt(int64_t &valid_cnt) const;
|
||||||
int get_rec_scn(share::SCN &rec_scn) const;
|
int get_rec_scn(share::SCN &rec_scn) const;
|
||||||
int dump_status() const;
|
|
||||||
bool is_valid() const;
|
bool is_valid() const;
|
||||||
void reset();
|
void reset();
|
||||||
MdsTableBase *get_mds_table_ptr() { return p_mds_table_base_.ptr(); }
|
MdsTableBase *get_mds_table_ptr() { return p_mds_table_base_.ptr(); }
|
||||||
|
|||||||
@ -549,14 +549,6 @@ inline int MdsTableHandle::get_rec_scn(share::SCN &rec_scn) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int MdsTableHandle::dump_status() const
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
CHECK_MDS_TABLE_INIT();
|
|
||||||
p_mds_table_base_->dump_status();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int MdsTableHandle::get_node_cnt(int64_t &valid_cnt) const
|
inline int MdsTableHandle::get_node_cnt(int64_t &valid_cnt) const
|
||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
|
|||||||
@ -141,7 +141,7 @@ int ObMdsTableHandler::try_release_nodes_below(const share::SCN &scn)
|
|||||||
MDS_TG(5_ms);
|
MDS_TG(5_ms);
|
||||||
MdsTableHandle mds_table_handle;
|
MdsTableHandle mds_table_handle;
|
||||||
{
|
{
|
||||||
MdsWLockGuard guard(lock_);
|
MdsRLockGuard guard(lock_);
|
||||||
CLICK();
|
CLICK();
|
||||||
mds_table_handle = mds_table_handle_;
|
mds_table_handle = mds_table_handle_;
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ ObMdsTableHandler &ObMdsTableHandler::operator=(const ObMdsTableHandler &rhs)//
|
|||||||
void ObMdsTableHandler::mark_removed_from_t3m(ObTabletPointer *pointer)
|
void ObMdsTableHandler::mark_removed_from_t3m(ObTabletPointer *pointer)
|
||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
MdsWLockGuard guard(lock_);
|
MdsRLockGuard guard(lock_);
|
||||||
if (mds_table_handle_.is_valid()) {
|
if (mds_table_handle_.is_valid()) {
|
||||||
if (OB_FAIL(mds_table_handle_.mark_removed_from_t3m(pointer))) {
|
if (OB_FAIL(mds_table_handle_.mark_removed_from_t3m(pointer))) {
|
||||||
MDS_LOG(WARN, "fail to unregister_from_mds_table_mgr", K(*this));
|
MDS_LOG(WARN, "fail to unregister_from_mds_table_mgr", K(*this));
|
||||||
|
|||||||
@ -15,7 +15,9 @@ namespace mds
|
|||||||
class ObMdsTableHandler
|
class ObMdsTableHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ObMdsTableHandler() : is_written_(false) {}
|
ObMdsTableHandler()
|
||||||
|
: is_written_(false),
|
||||||
|
lock_(common::ObLatchIds::MDS_TABLE_HANDLER_LOCK) {}
|
||||||
~ObMdsTableHandler();
|
~ObMdsTableHandler();
|
||||||
ObMdsTableHandler(const ObMdsTableHandler &) = delete;
|
ObMdsTableHandler(const ObMdsTableHandler &) = delete;
|
||||||
ObMdsTableHandler &operator=(const ObMdsTableHandler &);// value sematic for tablet ponter deep copy
|
ObMdsTableHandler &operator=(const ObMdsTableHandler &);// value sematic for tablet ponter deep copy
|
||||||
@ -36,6 +38,19 @@ private:
|
|||||||
MdsTableHandle mds_table_handle_;// primary handle, all other handles are copied from this one
|
MdsTableHandle mds_table_handle_;// primary handle, all other handles are copied from this one
|
||||||
bool is_written_;
|
bool is_written_;
|
||||||
mutable MdsLock lock_;
|
mutable MdsLock lock_;
|
||||||
|
// lock_ is defined as read prefered lock, this is necessary because if this lock is write prefered, can not avoid thread deadlock:
|
||||||
|
// thread A is doing flush, access to MdsTableMgr's Bucket Lock first, then create DAG, the DAG create action will read tablet_status, and will lock mds_table_handler with RLockGuard.
|
||||||
|
// thread B is doing mark_removed_from_t3m action, which will lock mds_table_handler with RLockGuard, then access to MdsTableMgr's Bucket to remove mds_table.
|
||||||
|
// so far so good, cause both A and B lock mds_table_handler with RLockGuard, no wait relationship between A and B.
|
||||||
|
// now, just consider if there is a another thread C, locking mds_table_handler with WLockGuard, and this lock operation is just happend after B before A, and lock_ is write prefered defined.
|
||||||
|
// this is what may happened:
|
||||||
|
// 1. thread A holding MdsTableMgr's Bucket Lock, trying to lock mds_table_handler with RLockGuard, hung there though, cause lock_ is write prefered, and thread C is trying to lock it with WLockGuard.
|
||||||
|
// 2. thread B holding mds_table_handler's RLock, trying to lock MdsTableMgr's Bucket Lock, hung there obviously, cause thread A is holding it.
|
||||||
|
// 3. thread C is trying lock mds_table_handler with WLockGuard, it will never got it, cause read count on lock_ will never decline to 0.
|
||||||
|
|
||||||
|
// So, lock_ must be read predered, if you don't understand it, just keep it in your mind.
|
||||||
|
// I know you just wonder why it's so complicated, the reason is complicated also, i can't explain it to you in a simple way.
|
||||||
|
// Better not refact this in an "elegant way", i strongly suggest you just accept it.
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -139,7 +139,7 @@ public:
|
|||||||
ObFunction<int(const MdsDumpKV&)> &for_each_op,
|
ObFunction<int(const MdsDumpKV&)> &for_each_op,
|
||||||
const int64_t mds_construct_sequence,
|
const int64_t mds_construct_sequence,
|
||||||
const bool for_flush) const override;
|
const bool for_flush) const override;
|
||||||
virtual int dump_status() const override;
|
virtual int operate(const ObFunction<int(MdsTableBase &)> &operation) override;
|
||||||
int calculate_flush_scn_and_need_dumped_nodes_cnt_(share::SCN need_advanced_rec_scn_lower_limit,
|
int calculate_flush_scn_and_need_dumped_nodes_cnt_(share::SCN need_advanced_rec_scn_lower_limit,
|
||||||
share::SCN &flush_scn,
|
share::SCN &flush_scn,
|
||||||
int64_t &need_dumped_nodes_cnt);
|
int64_t &need_dumped_nodes_cnt);
|
||||||
|
|||||||
@ -65,8 +65,14 @@ MdsTableImpl<MdsTableType>::MdsTableImpl() : MdsTableBase::MdsTableBase()
|
|||||||
template <typename MdsTableType>
|
template <typename MdsTableType>
|
||||||
MdsTableImpl<MdsTableType>::~MdsTableImpl() {
|
MdsTableImpl<MdsTableType>::~MdsTableImpl() {
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
|
if (!is_removed_from_t3m()) {
|
||||||
if (OB_FAIL(unregister_from_mds_table_mgr())) {
|
if (OB_FAIL(unregister_from_mds_table_mgr())) {
|
||||||
MDS_LOG(ERROR, "fail to unregister from mds table mgr", K(*this));
|
MDS_LOG(ERROR, "fail to unregister from mds table mgr", K(*this));
|
||||||
|
ret = OB_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (OB_FAIL(unregister_from_removed_recorder())) {
|
||||||
|
MDS_LOG(ERROR, "fail to unregister from removed_recorder", K(*this));
|
||||||
}
|
}
|
||||||
MDS_LOG(INFO, "mds table destructed", K(*this));
|
MDS_LOG(INFO, "mds table destructed", K(*this));
|
||||||
}
|
}
|
||||||
@ -1209,7 +1215,7 @@ template <typename T>
|
|||||||
int MdsTableImpl<MdsTableType>::is_locked_by_others(bool &is_locked, const MdsWriter &self) const
|
int MdsTableImpl<MdsTableType>::is_locked_by_others(bool &is_locked, const MdsWriter &self) const
|
||||||
{
|
{
|
||||||
auto read_op_wrapper = [&is_locked, &self](const UserMdsNode<DummyKey, T> &node) -> int {
|
auto read_op_wrapper = [&is_locked, &self](const UserMdsNode<DummyKey, T> &node) -> int {
|
||||||
OB_ASSERT(node.status_.union_.field_.state_ != TwoPhaseCommitState::ON_ABORT);
|
MDS_ASSERT(node.status_.union_.field_.state_ != TwoPhaseCommitState::ON_ABORT);
|
||||||
if (node.status_.union_.field_.state_ == TwoPhaseCommitState::ON_COMMIT) {// no lock on decided node
|
if (node.status_.union_.field_.state_ == TwoPhaseCommitState::ON_COMMIT) {// no lock on decided node
|
||||||
is_locked = false;
|
is_locked = false;
|
||||||
} else if (node.status_.union_.field_.writer_type_ == self.writer_type_ &&
|
} else if (node.status_.union_.field_.writer_type_ == self.writer_type_ &&
|
||||||
@ -1328,7 +1334,7 @@ int MdsTableImpl<MdsTableType>::is_locked_by_others(const Key &key,
|
|||||||
const MdsWriter &self) const
|
const MdsWriter &self) const
|
||||||
{
|
{
|
||||||
auto read_op_wrapper = [&is_locked, &self](const UserMdsNode<Key, Value> &node) -> int {
|
auto read_op_wrapper = [&is_locked, &self](const UserMdsNode<Key, Value> &node) -> int {
|
||||||
OB_ASSERT(node.status_.union_.field_.state_ != TwoPhaseCommitState::ON_ABORT);
|
MDS_ASSERT(node.status_.union_.field_.state_ != TwoPhaseCommitState::ON_ABORT);
|
||||||
if (node.status_.union_.field_.state_ == TwoPhaseCommitState::ON_COMMIT) {
|
if (node.status_.union_.field_.state_ == TwoPhaseCommitState::ON_COMMIT) {
|
||||||
is_locked = false;
|
is_locked = false;
|
||||||
} else if (node.status_.union_.field_.writer_type_ == self.writer_type_ &&
|
} else if (node.status_.union_.field_.writer_type_ == self.writer_type_ &&
|
||||||
@ -1369,7 +1375,7 @@ struct RecycleNodeOp
|
|||||||
MDS_TG(1_ms);
|
MDS_TG(1_ms);
|
||||||
{
|
{
|
||||||
CLICK();
|
CLICK();
|
||||||
OB_ASSERT(!mds_node.is_aborted_());// should not see aborted node cause cause it is deleted immediatly
|
MDS_ASSERT(!mds_node.is_aborted_());// should not see aborted node cause cause it is deleted immediatly
|
||||||
if (mds_node.is_committed_()) {
|
if (mds_node.is_committed_()) {
|
||||||
if (mds_node.end_scn_ == share::SCN::max_scn()) {// must has an associated valid end LOG to commit/abort
|
if (mds_node.end_scn_ == share::SCN::max_scn()) {// must has an associated valid end LOG to commit/abort
|
||||||
ret = OB_ERR_UNEXPECTED;
|
ret = OB_ERR_UNEXPECTED;
|
||||||
@ -1471,13 +1477,16 @@ int MdsTableImpl<MdsTableType>::forcely_reset_mds_table(const char *reason)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename MdsTableType>
|
template <typename MdsTableType>
|
||||||
inline int MdsTableImpl<MdsTableType>::dump_status() const
|
inline int MdsTableImpl<MdsTableType>::operate(const ObFunction<int(MdsTableBase &)> &operation)
|
||||||
{
|
{
|
||||||
#define PRINT_WRAPPER K(*this)
|
#define PRINT_WRAPPER KR(ret), K(*this)
|
||||||
|
int ret = OB_SUCCESS;
|
||||||
MDS_TG(10_ms);
|
MDS_TG(10_ms);
|
||||||
MdsWLockGuard lg(lock_);
|
MdsWLockGuard lg(lock_);
|
||||||
MDS_LOG_NONE(INFO, "dump mds table status");
|
if (OB_FAIL(operation(*this))) {
|
||||||
return OB_SUCCESS;
|
MDS_LOG_NONE(INFO, "fail to apply upper layer operation");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
#undef PRINT_WRAPPER
|
#undef PRINT_WRAPPER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,18 @@ using namespace share;
|
|||||||
namespace storage {
|
namespace storage {
|
||||||
namespace mds {
|
namespace mds {
|
||||||
|
|
||||||
|
void RemovedMdsTableRecorder::record(MdsTableBase *mds_table)
|
||||||
|
{
|
||||||
|
SpinWLockGuard guard(lock_);
|
||||||
|
removed_mds_table_list_.append(mds_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemovedMdsTableRecorder::del(MdsTableBase *mds_table)
|
||||||
|
{
|
||||||
|
SpinWLockGuard guard(lock_);
|
||||||
|
removed_mds_table_list_.del(mds_table);
|
||||||
|
}
|
||||||
|
|
||||||
int ObMdsTableMgr::init(ObLS *ls)
|
int ObMdsTableMgr::init(ObLS *ls)
|
||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
@ -79,56 +91,11 @@ int ObMdsTableMgr::register_to_mds_table_mgr(MdsTableBase *p_mds_table)
|
|||||||
ret = OB_INVALID_ARGUMENT;
|
ret = OB_INVALID_ARGUMENT;
|
||||||
MDS_LOG(ERROR, "invalid mdstable handle", KR(ret), KP(p_mds_table));
|
MDS_LOG(ERROR, "invalid mdstable handle", KR(ret), KP(p_mds_table));
|
||||||
} else if (FALSE_IT(tablet_id = p_mds_table->get_tablet_id())) {
|
} else if (FALSE_IT(tablet_id = p_mds_table->get_tablet_id())) {
|
||||||
|
} else if (OB_FAIL(mds_table_map_.insert(tablet_id, p_mds_table))) {
|
||||||
|
MDS_LOG(ERROR, "fail to insert mds table to map", KR(ret), KPC(p_mds_table));
|
||||||
} else {
|
} else {
|
||||||
int op_result = OB_SUCCESS;
|
|
||||||
auto op = [p_mds_table, &op_result](const ObTabletID &id, List<MdsTableBase> &list) {// with map's bucket lock protected
|
|
||||||
if (list.empty()) {
|
|
||||||
list.insert_into_head(p_mds_table);
|
|
||||||
} else {
|
|
||||||
MdsTableBase *head_mds_table = static_cast<MdsTableBase *>(list.list_head_);
|
|
||||||
if (!head_mds_table->is_removed_from_t3m()) {
|
|
||||||
op_result = OB_ENTRY_EXIST;
|
|
||||||
MDS_LOG_RET(INFO, op_result, "register meet conflct", K(id), K(list), KPC(p_mds_table));
|
|
||||||
} else {
|
|
||||||
list.insert_into_head(p_mds_table);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
bool need_break = false;
|
|
||||||
List<MdsTableBase> tmp_list;
|
|
||||||
tmp_list.append(p_mds_table);
|
|
||||||
while (!need_break) {
|
|
||||||
if (OB_FAIL(mds_table_map_.insert(tablet_id, tmp_list))) {
|
|
||||||
if (OB_ENTRY_EXIST == ret) {
|
|
||||||
ret = OB_SUCCESS;
|
|
||||||
if (OB_FAIL(mds_table_map_.operate(tablet_id, op))) {
|
|
||||||
if (OB_ENTRY_NOT_EXIST == ret) {// meet concurrent erase
|
|
||||||
ret = OB_SUCCESS;
|
|
||||||
} else {// meet errors can't handle, no need retry
|
|
||||||
need_break = true;
|
|
||||||
MDS_LOG(WARN, "operate list failed and ret is not ENTRY_NOT_EXIST", KR(ret), K(tablet_id));
|
|
||||||
}
|
|
||||||
} else {// insert to existing list success, no need retry
|
|
||||||
need_break = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
need_break = true;// meet errors can't handle, no need retry
|
|
||||||
MDS_LOG(WARN, "insert list failed and ret is not ENTRY_EXIST", KR(ret), K(tablet_id));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
need_break = true;// insert new list success, no need retry
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (OB_FAIL(ret)) {
|
|
||||||
// do nothing
|
|
||||||
} else {
|
|
||||||
ret = op_result;
|
|
||||||
if (OB_SUCC(ret)) {
|
|
||||||
MDS_LOG(INFO, "register success", KR(ret), KPC(p_mds_table));
|
MDS_LOG(INFO, "register success", KR(ret), KPC(p_mds_table));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,31 +103,32 @@ int ObMdsTableMgr::unregister_from_mds_table_mgr(MdsTableBase *p_mds_table)
|
|||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
common::ObTabletID tablet_id;
|
common::ObTabletID tablet_id;
|
||||||
auto op = [p_mds_table](const ObTabletID &id, List<MdsTableBase> &list) {// with map's bucket lock protected
|
auto op = [p_mds_table, this](const ObTabletID &id, MdsTableBase *&p_mds_table_in_map) {// with map's bucket ock protected
|
||||||
if (list.check_node_exist(p_mds_table)) {
|
if (p_mds_table != p_mds_table_in_map) {
|
||||||
list.del(p_mds_table);
|
MDS_LOG_RET(ERROR, OB_ERR_UNEXPECTED,
|
||||||
} else {
|
"erased mds table is not same with mds table in map, but shared same tablet id",
|
||||||
MDS_LOG_RET(ERROR, OB_ERR_UNEXPECTED, "mds table not in list", KPC(p_mds_table), K(id), K(list));
|
K(id), KPC(p_mds_table), KPC(p_mds_table_in_map));
|
||||||
ob_abort();
|
|
||||||
}
|
}
|
||||||
return list.empty();
|
removed_mds_table_recorder_.record(p_mds_table);
|
||||||
|
return true;// always erase it
|
||||||
};
|
};
|
||||||
if (OB_ISNULL(p_mds_table)) {
|
if (OB_ISNULL(p_mds_table)) {
|
||||||
ret = OB_INVALID_ARGUMENT;
|
ret = OB_INVALID_ARGUMENT;
|
||||||
MDS_LOG(ERROR, "invalid mdstable handle", KR(ret), KP(p_mds_table));
|
MDS_LOG(ERROR, "invalid mdstable handle", KR(ret), KP(p_mds_table));
|
||||||
} else if (FALSE_IT(tablet_id = p_mds_table->get_tablet_id())) {
|
} else if (FALSE_IT(tablet_id = p_mds_table->get_tablet_id())) {
|
||||||
} else if (OB_FAIL(mds_table_map_.erase_if(tablet_id, op))) {
|
} else if (OB_FAIL(mds_table_map_.erase_if(tablet_id, op))) {
|
||||||
if (OB_EAGAIN == ret) {
|
|
||||||
ret = OB_SUCCESS;
|
|
||||||
} else {
|
|
||||||
MDS_LOG(WARN, "fail to erase kv", KR(ret), K(tablet_id));
|
MDS_LOG(WARN, "fail to erase kv", KR(ret), K(tablet_id));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
MDS_LOG(INFO, "unregister success", KR(ret), KPC(p_mds_table));
|
MDS_LOG(INFO, "unregister success", KR(ret), KPC(p_mds_table));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObMdsTableMgr::unregister_from_removed_mds_table_recorder(MdsTableBase *p_mds_table)
|
||||||
|
{
|
||||||
|
removed_mds_table_recorder_.del(p_mds_table);
|
||||||
|
}
|
||||||
|
|
||||||
int ObMdsTableMgr::first_scan_to_get_min_rec_scn_(share::SCN &min_rec_scn)
|
int ObMdsTableMgr::first_scan_to_get_min_rec_scn_(share::SCN &min_rec_scn)
|
||||||
{
|
{
|
||||||
MDS_TG(10_s);
|
MDS_TG(10_s);
|
||||||
@ -184,7 +152,14 @@ int ObMdsTableMgr::first_scan_to_get_min_rec_scn_(share::SCN &min_rec_scn)
|
|||||||
// true means iterating the next mds table
|
// true means iterating the next mds table
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if (OB_FAIL(mds_table_map_.for_each(get_max_min_rec_scn_op))) {
|
auto get_min_rec_scn_op =
|
||||||
|
[&min_rec_scn, &scan_cnt](const common::ObTabletID &, MdsTableBase *&mds_table) {
|
||||||
|
share::SCN rec_scn = mds_table->get_rec_scn();
|
||||||
|
min_rec_scn = std::min(rec_scn, min_rec_scn);
|
||||||
|
++scan_cnt;
|
||||||
|
return true;// true means iterating the next mds table
|
||||||
|
};
|
||||||
|
if (OB_FAIL(mds_table_map_.for_each(get_min_rec_scn_op))) {
|
||||||
MDS_LOG(WARN, "fail to do map for_each", KR(ret), K(*this), K(scan_cnt), K(min_rec_scn));
|
MDS_LOG(WARN, "fail to do map for_each", KR(ret), K(*this), K(scan_cnt), K(min_rec_scn));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -196,22 +171,14 @@ int ObMdsTableMgr::second_scan_to_do_flush_(share::SCN do_flush_limit_scn)
|
|||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
int64_t scan_mds_table_cnt = 0;
|
int64_t scan_mds_table_cnt = 0;
|
||||||
auto flush_op = [do_flush_limit_scn, &scan_mds_table_cnt](const common::ObTabletID &tablet_id,
|
auto flush_op = [do_flush_limit_scn, &scan_mds_table_cnt](const common::ObTabletID &tablet_id,
|
||||||
List<MdsTableBase> &mds_table_list) {
|
MdsTableBase *&mds_table) {
|
||||||
int tmp_ret = OB_SUCCESS;
|
int tmp_ret = OB_SUCCESS;
|
||||||
if (mds_table_list.empty()) {
|
if (OB_TMP_FAIL(mds_table->flush(do_flush_limit_scn))) {
|
||||||
MDS_LOG_RET(ERROR, OB_ERR_UNEXPECTED, "meet empty mds table list", K(tablet_id), K(scan_mds_table_cnt));
|
|
||||||
} else {
|
|
||||||
MdsTableBase *mds_table = static_cast<MdsTableBase *>(mds_table_list.list_head_);
|
|
||||||
if (mds_table->is_removed_from_t3m()) {
|
|
||||||
// jsut skip it
|
|
||||||
} else if (OB_TMP_FAIL(mds_table->flush(do_flush_limit_scn))) {
|
|
||||||
MDS_LOG_RET(WARN, ret, "flush mds table failed", KR(tmp_ret), K(tablet_id), K(scan_mds_table_cnt));
|
MDS_LOG_RET(WARN, ret, "flush mds table failed", KR(tmp_ret), K(tablet_id), K(scan_mds_table_cnt));
|
||||||
} else {
|
} else {
|
||||||
++scan_mds_table_cnt;
|
++scan_mds_table_cnt;
|
||||||
}
|
}
|
||||||
}
|
return true;// true means iterating the next mds table
|
||||||
// true means iterating the next mds table
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
if (OB_FAIL(mds_table_map_.for_each(flush_op))) {
|
if (OB_FAIL(mds_table_map_.for_each(flush_op))) {
|
||||||
MDS_LOG(WARN, "fail to do map for_each", KR(ret), K(*this), K(scan_mds_table_cnt), K(do_flush_limit_scn));
|
MDS_LOG(WARN, "fail to do map for_each", KR(ret), K(*this), K(scan_mds_table_cnt), K(do_flush_limit_scn));
|
||||||
@ -258,6 +225,10 @@ int ObMdsTableMgr::flush(SCN recycle_scn, bool need_freeze)
|
|||||||
freezing_scn_.atomic_store(recycle_scn);
|
freezing_scn_.atomic_store(recycle_scn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (freezing_scn_ > max_consequent_callbacked_scn) {
|
||||||
|
freezing_scn_ = max_consequent_callbacked_scn;
|
||||||
|
MDS_LOG_FREEZE(INFO, "freezing_scn decline to max_consequent_callbacked_scn");
|
||||||
|
}
|
||||||
if (min_rec_scn <= freezing_scn_) {
|
if (min_rec_scn <= freezing_scn_) {
|
||||||
if (MDS_FAIL(second_scan_to_do_flush_(freezing_scn_))) {
|
if (MDS_FAIL(second_scan_to_do_flush_(freezing_scn_))) {
|
||||||
MDS_LOG_FREEZE(WARN, "fail to do flush");
|
MDS_LOG_FREEZE(WARN, "fail to do flush");
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#ifndef SHARE_STORAGE_MULTI_DATA_SOURCE_MDS_TABLE_MGR_H
|
#ifndef SHARE_STORAGE_MULTI_DATA_SOURCE_MDS_TABLE_MGR_H
|
||||||
#define SHARE_STORAGE_MULTI_DATA_SOURCE_MDS_TABLE_MGR_H
|
#define SHARE_STORAGE_MULTI_DATA_SOURCE_MDS_TABLE_MGR_H
|
||||||
|
|
||||||
|
#include "lib/lock/ob_small_spin_lock.h"
|
||||||
#include "lib/lock/ob_tc_rwlock.h"
|
#include "lib/lock/ob_tc_rwlock.h"
|
||||||
#include "meta_programming/ob_type_traits.h"
|
#include "meta_programming/ob_type_traits.h"
|
||||||
#include "storage/checkpoint/ob_common_checkpoint.h"
|
#include "storage/checkpoint/ob_common_checkpoint.h"
|
||||||
@ -26,9 +27,26 @@ class ObTabletHandle;
|
|||||||
namespace mds {
|
namespace mds {
|
||||||
class MdsTableFreezeGuard;
|
class MdsTableFreezeGuard;
|
||||||
class MdsTableBase;
|
class MdsTableBase;
|
||||||
|
|
||||||
|
class RemovedMdsTableRecorder// tablet leak will resulting mds table leak, we must prove it
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RemovedMdsTableRecorder() = default;
|
||||||
|
void record(MdsTableBase *mds_table);
|
||||||
|
void del(MdsTableBase *mds_table);
|
||||||
|
template <typename OP>
|
||||||
|
void for_each(OP &&op) {
|
||||||
|
SpinRLockGuard guard(lock_);
|
||||||
|
removed_mds_table_list_.for_each_node_from_head_to_tail_until_true(op);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
SpinRWLock lock_;
|
||||||
|
mds::List<MdsTableBase> removed_mds_table_list_;// this list is for record those removed mds tables from t3m, but not destroed yet
|
||||||
|
};
|
||||||
|
|
||||||
class ObMdsTableMgr final : public checkpoint::ObCommonCheckpoint
|
class ObMdsTableMgr final : public checkpoint::ObCommonCheckpoint
|
||||||
{
|
{
|
||||||
using MdsTableMap = common::ObLinearHashMap<common::ObTabletID, List<MdsTableBase>>;
|
using MdsTableMap = common::ObLinearHashMap<common::ObTabletID, MdsTableBase*>;
|
||||||
friend MdsTableFreezeGuard;
|
friend MdsTableFreezeGuard;
|
||||||
public:
|
public:
|
||||||
ObMdsTableMgr()
|
ObMdsTableMgr()
|
||||||
@ -37,23 +55,44 @@ public:
|
|||||||
freezing_scn_(share::SCN::min_scn()),
|
freezing_scn_(share::SCN::min_scn()),
|
||||||
ref_cnt_(0),
|
ref_cnt_(0),
|
||||||
ls_(nullptr),
|
ls_(nullptr),
|
||||||
mds_table_map_() {}
|
mds_table_map_(),
|
||||||
|
removed_mds_table_recorder_() {}
|
||||||
~ObMdsTableMgr() { destroy(); }
|
~ObMdsTableMgr() { destroy(); }
|
||||||
|
|
||||||
int init(ObLS *ls);
|
int init(ObLS *ls);
|
||||||
int reset();
|
int reset();
|
||||||
void offline();
|
void offline();
|
||||||
void destroy();
|
void destroy();
|
||||||
int register_to_mds_table_mgr(MdsTableBase *p_mds_table);
|
int register_to_mds_table_mgr(MdsTableBase *p_mds_table);// call when create new mds table
|
||||||
int unregister_from_mds_table_mgr(MdsTableBase *p_mds_table);
|
int unregister_from_mds_table_mgr(MdsTableBase *p_mds_table);// call when remove tablet pointer from t3m map, record mds table in removed_mds_table_recorder
|
||||||
template <typename OP, ENABLE_IF_LIKE_FUNCTION(OP, bool(const ObTabletID &, List<MdsTableBase> &))>
|
void unregister_from_removed_mds_table_recorder(MdsTableBase *p_mds_table);// call when mds table released(tablet pointer released), del from removed_mds_table_recorder
|
||||||
int for_each_mds_table_list(OP &&op) {
|
template <typename OP, ENABLE_IF_LIKE_FUNCTION(OP, int(MdsTableBase &))>// if op return FAIL, break for-each
|
||||||
return mds_table_map_.for_each(op);
|
int for_each_removed_mds_table(OP &&op) {
|
||||||
|
int ret = OB_SUCCESS;
|
||||||
|
auto op_wrapper = [&op, &ret](const MdsTableBase &mds_table) -> bool {
|
||||||
|
bool break_flag = false;// means keep iterating next mds_table
|
||||||
|
if (OB_FAIL(op(const_cast<MdsTableBase &>(mds_table)))) {
|
||||||
|
break_flag = true;
|
||||||
|
}
|
||||||
|
return break_flag;
|
||||||
|
};
|
||||||
|
removed_mds_table_recorder_.for_each(op_wrapper);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
template <typename OP, ENABLE_IF_LIKE_FUNCTION(OP, int(MdsTableBase &))>// if op return FAIL, break for-each
|
||||||
|
int for_each_in_t3m_mds_table(OP &&op) {
|
||||||
|
auto op_wrapper = [&op](const common::ObTabletID &k, MdsTableBase* &v) -> bool {
|
||||||
|
bool keep_iterating = true;// means keep iterating next mds_table
|
||||||
|
int ret = OB_SUCCESS;
|
||||||
|
if (OB_FAIL(op(*v))) {
|
||||||
|
keep_iterating = false;
|
||||||
|
}
|
||||||
|
return keep_iterating;
|
||||||
|
};
|
||||||
|
return mds_table_map_.for_each(op_wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_TO_STRING;
|
DECLARE_TO_STRING;
|
||||||
|
|
||||||
|
|
||||||
public: // derived from ObCommonCheckpoint
|
public: // derived from ObCommonCheckpoint
|
||||||
share::SCN get_freezing_scn() const;
|
share::SCN get_freezing_scn() const;
|
||||||
virtual share::SCN get_rec_scn() override;
|
virtual share::SCN get_rec_scn() override;
|
||||||
@ -77,6 +116,7 @@ private:
|
|||||||
int64_t ref_cnt_;
|
int64_t ref_cnt_;
|
||||||
ObLS *ls_;
|
ObLS *ls_;
|
||||||
MdsTableMap mds_table_map_;
|
MdsTableMap mds_table_map_;
|
||||||
|
RemovedMdsTableRecorder removed_mds_table_recorder_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MdsTableFreezeGuard
|
class MdsTableFreezeGuard
|
||||||
|
|||||||
@ -9,6 +9,20 @@
|
|||||||
#include "src/share/scn.h"
|
#include "src/share/scn.h"
|
||||||
#include "src/share/ob_occam_time_guard.h"
|
#include "src/share/ob_occam_time_guard.h"
|
||||||
|
|
||||||
|
#ifdef OB_BUILD_RPM
|
||||||
|
#define MDS_ASSERT(x) (void)(x)
|
||||||
|
#else
|
||||||
|
#define MDS_ASSERT(x) \
|
||||||
|
do{ \
|
||||||
|
bool v=(x); \
|
||||||
|
if(OB_UNLIKELY(!(v))) { \
|
||||||
|
_OB_LOG_RET(ERROR, oceanbase::common::OB_ERROR, "assert fail, exp=%s", #x); \
|
||||||
|
BACKTRACE_RET(ERROR, oceanbase::common::OB_ERROR, 1, "assert fail"); \
|
||||||
|
ob_abort(); \
|
||||||
|
} \
|
||||||
|
} while(false)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace oceanbase
|
namespace oceanbase
|
||||||
{
|
{
|
||||||
namespace storage
|
namespace storage
|
||||||
@ -90,7 +104,7 @@ static constexpr bool STATE_CHECK_ALLOWED_MAP[static_cast<int>(TwoPhaseCommitSta
|
|||||||
|
|
||||||
static inline void check_and_advance_two_phase_commit(TwoPhaseCommitState &state, TwoPhaseCommitState new_state)
|
static inline void check_and_advance_two_phase_commit(TwoPhaseCommitState &state, TwoPhaseCommitState new_state)
|
||||||
{
|
{
|
||||||
OB_ASSERT(STATE_CHECK_ALLOWED_MAP[(int)state][(int)new_state] == true);
|
MDS_ASSERT(STATE_CHECK_ALLOWED_MAP[(int)state][(int)new_state] == true);
|
||||||
state = new_state;
|
state = new_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +182,7 @@ enum LogPhase
|
|||||||
FLUSH,
|
FLUSH,
|
||||||
GC,
|
GC,
|
||||||
FREEZE,
|
FREEZE,
|
||||||
|
NOTICE,
|
||||||
NONE
|
NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -212,6 +227,9 @@ do {\
|
|||||||
case mds::LogPhase::FREEZE:\
|
case mds::LogPhase::FREEZE:\
|
||||||
oceanbase::common::databuff_printf(joined_info, joined_length, pos, "[FREEZE]%s", info);\
|
oceanbase::common::databuff_printf(joined_info, joined_length, pos, "[FREEZE]%s", info);\
|
||||||
break;\
|
break;\
|
||||||
|
case mds::LogPhase::NOTICE:\
|
||||||
|
oceanbase::common::databuff_printf(joined_info, joined_length, pos, "[NOTICE]%s", info);\
|
||||||
|
break;\
|
||||||
case mds::LogPhase::NONE:\
|
case mds::LogPhase::NONE:\
|
||||||
oceanbase::common::databuff_printf(joined_info, joined_length, pos, "[NONE]%s", info);\
|
oceanbase::common::databuff_printf(joined_info, joined_length, pos, "[NONE]%s", info);\
|
||||||
break;\
|
break;\
|
||||||
@ -232,8 +250,9 @@ do {\
|
|||||||
#define MDS_LOG_SCAN(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::SCAN, info, ##args)
|
#define MDS_LOG_SCAN(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::SCAN, info, ##args)
|
||||||
#define MDS_LOG_FLUSH(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::FLUSH, info, ##args)
|
#define MDS_LOG_FLUSH(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::FLUSH, info, ##args)
|
||||||
#define MDS_LOG_GC(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::GC, info, ##args)
|
#define MDS_LOG_GC(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::GC, info, ##args)
|
||||||
#define MDS_LOG_NONE(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::NONE, info, ##args)
|
|
||||||
#define MDS_LOG_FREEZE(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::FREEZE, info, ##args)
|
#define MDS_LOG_FREEZE(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::FREEZE, info, ##args)
|
||||||
|
#define MDS_LOG_NOTICE(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::NOTICE, info, ##args)
|
||||||
|
#define MDS_LOG_NONE(level, info, args...) _MDS_LOG_PHASE(level, mds::LogPhase::NONE, info, ##args)
|
||||||
|
|
||||||
// flag is needed to rollback logic
|
// flag is needed to rollback logic
|
||||||
#define MDS_FAIL_FLAG(stmt, flag) (CLICK_FAIL(stmt) || FALSE_IT(flag = true))
|
#define MDS_FAIL_FLAG(stmt, flag) (CLICK_FAIL(stmt) || FALSE_IT(flag = true))
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "lib/ob_errno.h"
|
#include "lib/ob_errno.h"
|
||||||
#include "lib/utility/ob_macro_utils.h"
|
#include "lib/utility/ob_macro_utils.h"
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
|
#include "lib/utility/utility.h"
|
||||||
#include "src/share/ob_delegate.h"
|
#include "src/share/ob_delegate.h"
|
||||||
|
|
||||||
namespace oceanbase
|
namespace oceanbase
|
||||||
@ -58,26 +59,26 @@ struct ListBase// erase List Type
|
|||||||
void check_invariance_() const {
|
void check_invariance_() const {
|
||||||
#ifdef UNITTEST_DEBUG
|
#ifdef UNITTEST_DEBUG
|
||||||
if (OB_NOT_NULL(list_head_)) {
|
if (OB_NOT_NULL(list_head_)) {
|
||||||
OB_ASSERT(OB_NOT_NULL(list_tail_));
|
MDS_ASSERT(OB_NOT_NULL(list_tail_));
|
||||||
OB_ASSERT(OB_ISNULL(list_head_->prev_));
|
MDS_ASSERT(OB_ISNULL(list_head_->prev_));
|
||||||
OB_ASSERT(OB_ISNULL(list_tail_->next_));
|
MDS_ASSERT(OB_ISNULL(list_tail_->next_));
|
||||||
// can reach tail from head
|
// can reach tail from head
|
||||||
const ListNodeBase *iter = list_head_;
|
const ListNodeBase *iter = list_head_;
|
||||||
while (iter != list_tail_) {
|
while (iter != list_tail_) {
|
||||||
iter = iter->next_;
|
iter = iter->next_;
|
||||||
}
|
}
|
||||||
OB_ASSERT(iter == list_tail_);
|
MDS_ASSERT(iter == list_tail_);
|
||||||
}
|
}
|
||||||
if (OB_NOT_NULL(list_tail_)) {
|
if (OB_NOT_NULL(list_tail_)) {
|
||||||
OB_ASSERT(OB_NOT_NULL(list_tail_));
|
MDS_ASSERT(OB_NOT_NULL(list_tail_));
|
||||||
OB_ASSERT(OB_ISNULL(list_head_->prev_));
|
MDS_ASSERT(OB_ISNULL(list_head_->prev_));
|
||||||
OB_ASSERT(OB_ISNULL(list_tail_->next_));
|
MDS_ASSERT(OB_ISNULL(list_tail_->next_));
|
||||||
// can reach head from tail
|
// can reach head from tail
|
||||||
const ListNodeBase *iter = list_tail_;
|
const ListNodeBase *iter = list_tail_;
|
||||||
while (iter != list_head_) {
|
while (iter != list_head_) {
|
||||||
iter = iter->prev_;
|
iter = iter->prev_;
|
||||||
}
|
}
|
||||||
OB_ASSERT(iter == list_head_);
|
MDS_ASSERT(iter == list_head_);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -104,14 +105,14 @@ struct ListBase// erase List Type
|
|||||||
void append(ListNodeBase *new_node) {
|
void append(ListNodeBase *new_node) {
|
||||||
new_node->reset();
|
new_node->reset();
|
||||||
if (OB_ISNULL(list_head_)) {// insert into head
|
if (OB_ISNULL(list_head_)) {// insert into head
|
||||||
OB_ASSERT(OB_ISNULL(list_tail_));
|
MDS_ASSERT(OB_ISNULL(list_tail_));
|
||||||
list_head_ = new_node;
|
list_head_ = new_node;
|
||||||
list_tail_ = new_node;
|
list_tail_ = new_node;
|
||||||
} else {// insert after tail
|
} else {// insert after tail
|
||||||
OB_ASSERT(OB_ISNULL(list_tail_->next_));
|
MDS_ASSERT(OB_ISNULL(list_tail_->next_));
|
||||||
OB_ASSERT(OB_NOT_NULL(new_node));
|
MDS_ASSERT(OB_NOT_NULL(new_node));
|
||||||
OB_ASSERT(OB_ISNULL(new_node->prev_));
|
MDS_ASSERT(OB_ISNULL(new_node->prev_));
|
||||||
OB_ASSERT(OB_ISNULL(new_node->next_));
|
MDS_ASSERT(OB_ISNULL(new_node->next_));
|
||||||
list_tail_->next_ = new_node;
|
list_tail_->next_ = new_node;
|
||||||
new_node->prev_ = list_tail_;
|
new_node->prev_ = list_tail_;
|
||||||
new_node->next_ = nullptr;
|
new_node->next_ = nullptr;
|
||||||
@ -120,11 +121,11 @@ struct ListBase// erase List Type
|
|||||||
check_invariance_();
|
check_invariance_();
|
||||||
}
|
}
|
||||||
void del(ListNodeBase *list_node) {
|
void del(ListNodeBase *list_node) {
|
||||||
OB_ASSERT(OB_NOT_NULL(list_node));
|
MDS_ASSERT(OB_NOT_NULL(list_node));
|
||||||
ListNodeBase *before = list_node->prev_;
|
ListNodeBase *before = list_node->prev_;
|
||||||
ListNodeBase *after = list_node->next_;
|
ListNodeBase *after = list_node->next_;
|
||||||
if (OB_ISNULL(before)) {// the first node
|
if (OB_ISNULL(before)) {// the first node
|
||||||
OB_ASSERT(list_head_ == list_node);
|
MDS_ASSERT(list_head_ == list_node);
|
||||||
list_head_ = after;
|
list_head_ = after;
|
||||||
if (OB_NOT_NULL(list_head_)) {
|
if (OB_NOT_NULL(list_head_)) {
|
||||||
list_head_->prev_ = nullptr;
|
list_head_->prev_ = nullptr;
|
||||||
@ -133,7 +134,7 @@ struct ListBase// erase List Type
|
|||||||
before->next_ = list_node->next_;
|
before->next_ = list_node->next_;
|
||||||
}
|
}
|
||||||
if (OB_ISNULL(after)) {// the last node
|
if (OB_ISNULL(after)) {// the last node
|
||||||
OB_ASSERT(list_tail_ == list_node);
|
MDS_ASSERT(list_tail_ == list_node);
|
||||||
list_tail_ = before;
|
list_tail_ = before;
|
||||||
if (OB_NOT_NULL(list_tail_)) {
|
if (OB_NOT_NULL(list_tail_)) {
|
||||||
list_tail_->next_ = nullptr;
|
list_tail_->next_ = nullptr;
|
||||||
@ -207,16 +208,16 @@ public:
|
|||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
void insert_into_head(ListNode<T> *new_node) {
|
void insert_into_head(ListNode<T> *new_node) {
|
||||||
OB_ASSERT(OB_NOT_NULL(new_node));
|
MDS_ASSERT(OB_NOT_NULL(new_node));
|
||||||
new_node->reset();
|
new_node->reset();
|
||||||
if (OB_ISNULL(list_head_)) {// insert into head
|
if (OB_ISNULL(list_head_)) {// insert into head
|
||||||
OB_ASSERT(OB_ISNULL(list_tail_));
|
MDS_ASSERT(OB_ISNULL(list_tail_));
|
||||||
list_head_ = new_node;
|
list_head_ = new_node;
|
||||||
list_tail_ = new_node;
|
list_tail_ = new_node;
|
||||||
} else {// insert before head
|
} else {// insert before head
|
||||||
OB_ASSERT(OB_ISNULL(list_head_->prev_));
|
MDS_ASSERT(OB_ISNULL(list_head_->prev_));
|
||||||
OB_ASSERT(OB_ISNULL(new_node->prev_));
|
MDS_ASSERT(OB_ISNULL(new_node->prev_));
|
||||||
OB_ASSERT(OB_ISNULL(new_node->next_));
|
MDS_ASSERT(OB_ISNULL(new_node->next_));
|
||||||
list_head_->prev_ = new_node;
|
list_head_->prev_ = new_node;
|
||||||
new_node->next_ = list_head_;
|
new_node->next_ = list_head_;
|
||||||
new_node->prev_ = nullptr;
|
new_node->prev_ = nullptr;
|
||||||
@ -251,9 +252,9 @@ public:
|
|||||||
SortedList<T, SORT_TYPE> &operator=(const SortedList<T, SORT_TYPE> &) = delete;
|
SortedList<T, SORT_TYPE> &operator=(const SortedList<T, SORT_TYPE> &) = delete;
|
||||||
SortedList<T, SORT_TYPE> &operator=(SortedList<T, SORT_TYPE> &&) = delete;
|
SortedList<T, SORT_TYPE> &operator=(SortedList<T, SORT_TYPE> &&) = delete;
|
||||||
void insert(ListNode<T> *new_node) {
|
void insert(ListNode<T> *new_node) {
|
||||||
OB_ASSERT(OB_NOT_NULL(new_node));
|
MDS_ASSERT(OB_NOT_NULL(new_node));
|
||||||
OB_ASSERT(OB_ISNULL(new_node->next_));
|
MDS_ASSERT(OB_ISNULL(new_node->next_));
|
||||||
OB_ASSERT(OB_ISNULL(new_node->prev_));
|
MDS_ASSERT(OB_ISNULL(new_node->prev_));
|
||||||
if (ListBase::empty()) {
|
if (ListBase::empty()) {
|
||||||
ListBase::list_head_ = new_node;
|
ListBase::list_head_ = new_node;
|
||||||
ListBase::list_tail_ = new_node;
|
ListBase::list_tail_ = new_node;
|
||||||
@ -276,7 +277,7 @@ public:
|
|||||||
new_node->prev_ = ListBase::list_tail_;
|
new_node->prev_ = ListBase::list_tail_;
|
||||||
ListBase::list_tail_ = new_node;
|
ListBase::list_tail_ = new_node;
|
||||||
} else if (OB_ISNULL(next_node->prev_)) {// insert to head
|
} else if (OB_ISNULL(next_node->prev_)) {// insert to head
|
||||||
OB_ASSERT(ListBase::list_head_ == next_node);
|
MDS_ASSERT(ListBase::list_head_ == next_node);
|
||||||
ListBase::list_head_->prev_ = new_node;
|
ListBase::list_head_->prev_ = new_node;
|
||||||
new_node->next_ = ListBase::list_head_;
|
new_node->next_ = ListBase::list_head_;
|
||||||
ListBase::list_head_ = new_node;
|
ListBase::list_head_ = new_node;
|
||||||
@ -291,12 +292,12 @@ public:
|
|||||||
}
|
}
|
||||||
T &get_head() {
|
T &get_head() {
|
||||||
T *data = nullptr;
|
T *data = nullptr;
|
||||||
OB_ASSERT(OB_NOT_NULL(data = dynamic_cast<T*>(ListBase::list_head_)));
|
MDS_ASSERT(OB_NOT_NULL(data = dynamic_cast<T*>(ListBase::list_head_)));
|
||||||
return *data;
|
return *data;
|
||||||
}
|
}
|
||||||
T &get_tail() {
|
T &get_tail() {
|
||||||
T *data = nullptr;
|
T *data = nullptr;
|
||||||
OB_ASSERT(OB_NOT_NULL(data = dynamic_cast<T*>(ListBase::list_tail_)));
|
MDS_ASSERT(OB_NOT_NULL(data = dynamic_cast<T*>(ListBase::list_tail_)));
|
||||||
return *data;
|
return *data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -58,7 +58,7 @@ int deepcopy(const transaction::ObTransID &trans_id,
|
|||||||
using ImplType = GET_CTX_TYPE_BY_TUPLE_IDX(IDX);
|
using ImplType = GET_CTX_TYPE_BY_TUPLE_IDX(IDX);
|
||||||
ImplType *p_impl = nullptr;
|
ImplType *p_impl = nullptr;
|
||||||
const ImplType *p_old_impl_ctx = dynamic_cast<const ImplType *>(&old_ctx);
|
const ImplType *p_old_impl_ctx = dynamic_cast<const ImplType *>(&old_ctx);
|
||||||
OB_ASSERT(OB_NOT_NULL(p_old_impl_ctx));
|
MDS_ASSERT(OB_NOT_NULL(p_old_impl_ctx));
|
||||||
const ImplType &old_impl_ctx = *p_old_impl_ctx;
|
const ImplType &old_impl_ctx = *p_old_impl_ctx;
|
||||||
set_mds_mem_check_thread_local_info(MdsWriter(trans_id), typeid(ImplType).name(), alloc_file, alloc_func, line);
|
set_mds_mem_check_thread_local_info(MdsWriter(trans_id), typeid(ImplType).name(), alloc_file, alloc_func, line);
|
||||||
if (CLICK() &&
|
if (CLICK() &&
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
#include "lib/string/ob_string_holder.h"
|
#include "lib/string/ob_string_holder.h"
|
||||||
#include "lib/time/ob_time_utility.h"
|
#include "lib/time/ob_time_utility.h"
|
||||||
#include "lib/utility/utility.h"
|
#include "lib/utility/utility.h"
|
||||||
|
#include "ob_clock_generator.h"
|
||||||
#include "share/rc/ob_tenant_base.h"
|
#include "share/rc/ob_tenant_base.h"
|
||||||
#include "storage/meta_mem/ob_tablet_map_key.h"
|
#include "storage/meta_mem/ob_tablet_map_key.h"
|
||||||
#include "storage/meta_mem/ob_tenant_meta_mem_mgr.h"
|
#include "storage/meta_mem/ob_tenant_meta_mem_mgr.h"
|
||||||
@ -256,10 +257,10 @@ void ObTenantMdsTimer::try_recycle_mds_table_task()
|
|||||||
|
|
||||||
void ObTenantMdsTimer::dump_special_mds_table_status_task()
|
void ObTenantMdsTimer::dump_special_mds_table_status_task()
|
||||||
{
|
{
|
||||||
#define PRINT_WRAPPER KR(ret), KPC(this)
|
#define PRINT_WRAPPER KR(ret)
|
||||||
MDS_TG(1_s);
|
MDS_TG(1_s);
|
||||||
ObCurTraceId::init(GCONF.self_addr_);
|
ObCurTraceId::init(GCONF.self_addr_);
|
||||||
ObTenantMdsService::for_each_ls_in_tenant([this](ObLS &ls) -> int {
|
ObTenantMdsService::for_each_ls_in_tenant([](ObLS &ls) -> int {
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
MDS_TG(1_s);
|
MDS_TG(1_s);
|
||||||
MdsTableMgrHandle mds_table_mge_handle;
|
MdsTableMgrHandle mds_table_mge_handle;
|
||||||
@ -268,24 +269,25 @@ void ObTenantMdsTimer::dump_special_mds_table_status_task()
|
|||||||
MDS_LOG_NONE(WARN, "fail to get mds table mgr");
|
MDS_LOG_NONE(WARN, "fail to get mds table mgr");
|
||||||
} else if (FALSE_IT(ls_mds_freezing_scn = mds_table_mge_handle.get_mds_table_mgr()->get_freezing_scn())) {
|
} else if (FALSE_IT(ls_mds_freezing_scn = mds_table_mge_handle.get_mds_table_mgr()->get_freezing_scn())) {
|
||||||
} else {
|
} else {
|
||||||
ObTenantMdsService::for_each_mds_table_in_ls(ls, [this, ls_mds_freezing_scn](ObTablet &tablet) -> int {
|
(void)mds_table_mge_handle.get_mds_table_mgr()->for_each_in_t3m_mds_table([ls_mds_freezing_scn](MdsTableBase &mds_table) -> int {// with hash map bucket's lock protected
|
||||||
|
(void) mds_table.operate([ls_mds_freezing_scn](MdsTableBase &mds_table)-> int {// with MdsTable's lock protected
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
MDS_TG(1_s);
|
if (mds_table.get_rec_scn() <= ls_mds_freezing_scn) {
|
||||||
MdsTableHandle mds_table_handle;
|
MDS_LOG_NOTICE(WARN, "dump rec_scn lagging freeze_scn mds_table", K(ls_mds_freezing_scn), K(mds_table));
|
||||||
share::SCN rec_scn;
|
|
||||||
const ObTablet::ObTabletPointerHandle &pointer_handle = tablet.get_pointer_handle();
|
|
||||||
ObMetaPointer<oceanbase::storage::ObTablet> *resource_ptr = pointer_handle.get_resource_ptr();
|
|
||||||
ObTabletPointer *tablet_pointer = dynamic_cast<ObTabletPointer *>(resource_ptr);
|
|
||||||
if (OB_FAIL(tablet_pointer->get_mds_table(mds_table_handle))) {
|
|
||||||
if (OB_ENTRY_NOT_EXIST != ret) {
|
|
||||||
MDS_LOG_NONE(WARN, "fail to get mds table", K(tablet.get_tablet_meta().tablet_id_));
|
|
||||||
}
|
}
|
||||||
} else if (OB_FAIL(mds_table_handle.get_rec_scn(rec_scn))) {
|
return OB_SUCCESS;// keep iterating
|
||||||
MDS_LOG_NONE(WARN, "fail to get mds table rec_scn", K(tablet.get_tablet_meta().tablet_id_));
|
});
|
||||||
} else if (rec_scn <= ls_mds_freezing_scn) {
|
return OB_SUCCESS;// keep iterating
|
||||||
mds_table_handle.dump_status();
|
});
|
||||||
|
(void)mds_table_mge_handle.get_mds_table_mgr()->for_each_removed_mds_table([](MdsTableBase &mds_table) -> int {
|
||||||
|
(void) mds_table.operate([](MdsTableBase &mds_table)-> int {// with MdsTable's lock protected
|
||||||
|
int ret = OB_SUCCESS;
|
||||||
|
if (ObClockGenerator::getClock() - mds_table.get_removed_from_t3m_ts() > 1_min) {
|
||||||
|
MDS_LOG_NOTICE(WARN, "dump maybe leaked mds_table", K(mds_table));
|
||||||
}
|
}
|
||||||
return OB_SUCCESS;// keep doing ignore error
|
return OB_SUCCESS;// keep iterating
|
||||||
|
});
|
||||||
|
return OB_SUCCESS;// keep iterating
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return OB_SUCCESS;// keep doing ignore error
|
return OB_SUCCESS;// keep doing ignore error
|
||||||
@ -378,51 +380,18 @@ int ObTenantMdsService::for_each_mds_table_in_ls(ObLS &ls, const ObFunction<int(
|
|||||||
ObArray<ObTabletID> ids_in_t3m_array;
|
ObArray<ObTabletID> ids_in_t3m_array;
|
||||||
if (MDS_FAIL(ls.get_mds_table_mgr(mgr_handle))) {
|
if (MDS_FAIL(ls.get_mds_table_mgr(mgr_handle))) {
|
||||||
MDS_LOG_NONE(WARN, "fail to get mds table mgr");
|
MDS_LOG_NONE(WARN, "fail to get mds table mgr");
|
||||||
} else if (MDS_FAIL(mgr_handle.get_mds_table_mgr()->for_each_mds_table_list(
|
} else if (MDS_FAIL(mgr_handle.get_mds_table_mgr()->for_each_in_t3m_mds_table(
|
||||||
[&mds_table_total_num, &ids_in_t3m_array, &ls](const ObTabletID &tablet_id, List<MdsTableBase> &mds_table_list) -> bool {// with map's bucket lock protected
|
[&mds_table_total_num, &ids_in_t3m_array, &ls](MdsTableBase &mds_table) -> int {// with map's bucket lock protected
|
||||||
MDS_TG(1_s);
|
MDS_TG(1_s);
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
if (mds_table_list.empty()) {
|
if (MDS_FAIL(ids_in_t3m_array.push_back(mds_table.get_tablet_id()))) {
|
||||||
ret = OB_ERR_UNEXPECTED;
|
MDS_LOG_NONE(WARN, "fail to push array");
|
||||||
MDS_LOG_NONE(ERROR, "meet empty mds_table_list", K(tablet_id));
|
|
||||||
} else {
|
|
||||||
MdsTableBase *p_mds_table = static_cast<MdsTableBase *>(mds_table_list.list_head_);
|
|
||||||
if (!p_mds_table->is_removed_from_t3m()) {
|
|
||||||
MDS_LOG_NONE(TRACE, "process with mds_table", KPC(p_mds_table));
|
|
||||||
if (MDS_FAIL(ids_in_t3m_array.push_back(p_mds_table->get_tablet_id()))) {
|
|
||||||
MDS_LOG_NONE(WARN, "fail to push array", KPC(p_mds_table));
|
|
||||||
}
|
}
|
||||||
} else {
|
return ret;
|
||||||
MDS_LOG_NONE(WARN, "consider mds_table leaked if this log keep printing", KPC(p_mds_table));
|
|
||||||
}
|
|
||||||
++mds_table_total_num;
|
|
||||||
MdsTableBase *iter = static_cast<MdsTableBase *>(p_mds_table->next_);
|
|
||||||
while (OB_NOT_NULL(iter)) {
|
|
||||||
if (ObTimeUtility::fast_current_time() - iter->get_removed_from_t3m_ts() > 5_min) {
|
|
||||||
MDS_LOG_NONE(WARN, "consider mds_table leaked if this log keep printing", KPC(iter));
|
|
||||||
}
|
|
||||||
++mds_table_total_num;
|
|
||||||
iter = static_cast<MdsTableBase *>(iter->next_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;// keep iter
|
|
||||||
}
|
}
|
||||||
))) {
|
))) {
|
||||||
MDS_LOG_NONE(WARN, "fail to scan mds_table");
|
MDS_LOG_NONE(WARN, "fail to scan mds_table");
|
||||||
} else {
|
} else {
|
||||||
MDS_LOG_NONE(INFO, "succ to scan mds_table");
|
|
||||||
constexpr int64_t PRINT_SIZE = 128;
|
|
||||||
// print those in t3m array ids, and if ids too many, print random part of them
|
|
||||||
if (ids_in_t3m_array.count() < PRINT_SIZE) {
|
|
||||||
MDS_LOG_NONE(INFO, "dump tablet ids in t3m", K(ids_in_t3m_array));
|
|
||||||
} else {
|
|
||||||
int64_t random_start = rand() % ids_in_t3m_array.count();
|
|
||||||
ObSEArray<ObTabletID, PRINT_SIZE> print_array;
|
|
||||||
for (int64_t idx = 0; idx < PRINT_SIZE; ++idx) {
|
|
||||||
print_array.push_back(ids_in_t3m_array[(random_start + idx) % ids_in_t3m_array.count()]);
|
|
||||||
}
|
|
||||||
MDS_LOG_NONE(INFO, "dump random part tablet ids in t3m", K(print_array), K(ids_in_t3m_array.count()), K(PRINT_SIZE));
|
|
||||||
}
|
|
||||||
for (int64_t idx = 0; idx < ids_in_t3m_array.count(); ++idx) {// ignore ret
|
for (int64_t idx = 0; idx < ids_in_t3m_array.count(); ++idx) {// ignore ret
|
||||||
ObTabletHandle tablet_handle;
|
ObTabletHandle tablet_handle;
|
||||||
if (OB_FAIL(ls.get_tablet(ids_in_t3m_array[idx], tablet_handle, 1_s, ObMDSGetTabletMode::READ_WITHOUT_CHECK))) {
|
if (OB_FAIL(ls.get_tablet(ids_in_t3m_array[idx], tablet_handle, 1_s, ObMDSGetTabletMode::READ_WITHOUT_CHECK))) {
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "lib/utility/serialization.h"
|
#include "lib/utility/serialization.h"
|
||||||
#include "meta_programming/ob_meta_serialization.h"
|
#include "meta_programming/ob_meta_serialization.h"
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
|
|
||||||
namespace oceanbase {
|
namespace oceanbase {
|
||||||
namespace unittest {
|
namespace unittest {
|
||||||
struct ExampleUserKey {
|
struct ExampleUserKey {
|
||||||
|
|||||||
@ -95,7 +95,7 @@ void TestMdsDumpKV::test_dump_node_convert_and_serialize_and_compare()
|
|||||||
|
|
||||||
ObArenaAllocator allocator;
|
ObArenaAllocator allocator;
|
||||||
ASSERT_EQ(OB_SUCCESS, dump_node2.deserialize(allocator, buffer, buf_len, pos));
|
ASSERT_EQ(OB_SUCCESS, dump_node2.deserialize(allocator, buffer, buf_len, pos));
|
||||||
OB_ASSERT(dump_node2.crc_check_number_ == dump_node2.generate_hash());
|
MDS_ASSERT(dump_node2.crc_check_number_ == dump_node2.generate_hash());
|
||||||
ASSERT_EQ(dump_node2.generate_hash(), dump_node2.crc_check_number_);
|
ASSERT_EQ(dump_node2.generate_hash(), dump_node2.crc_check_number_);
|
||||||
ASSERT_EQ(dump_node2.crc_check_number_, dump_node.crc_check_number_);
|
ASSERT_EQ(dump_node2.crc_check_number_, dump_node.crc_check_number_);
|
||||||
UserMdsNode<DummyKey, ExampleUserData2> user_mds_node2;
|
UserMdsNode<DummyKey, ExampleUserData2> user_mds_node2;
|
||||||
|
|||||||
@ -139,7 +139,7 @@ void TestMdsTable::replay() {
|
|||||||
share::SCN recorde_scn = mock_scn(0);
|
share::SCN recorde_scn = mock_scn(0);
|
||||||
unit.single_row_.v_.sorted_list_.for_each_node_from_tail_to_head_until_true([&](const UserMdsNode<DummyKey, ExampleUserData1> &node) -> int {
|
unit.single_row_.v_.sorted_list_.for_each_node_from_tail_to_head_until_true([&](const UserMdsNode<DummyKey, ExampleUserData1> &node) -> int {
|
||||||
if (!node.is_aborted_()) {
|
if (!node.is_aborted_()) {
|
||||||
OB_ASSERT(node.redo_scn_ > recorde_scn);
|
MDS_ASSERT(node.redo_scn_ > recorde_scn);
|
||||||
recorde_scn = node.redo_scn_;
|
recorde_scn = node.redo_scn_;
|
||||||
}
|
}
|
||||||
return OB_SUCCESS;
|
return OB_SUCCESS;
|
||||||
@ -383,8 +383,8 @@ void TestMdsTable::test_flush() {
|
|||||||
ASSERT_EQ(mock_scn(199), mds_table_.p_mds_table_base_->flushing_scn_);// 2. 实际上以199为版本号进行flush动作
|
ASSERT_EQ(mock_scn(199), mds_table_.p_mds_table_base_->flushing_scn_);// 2. 实际上以199为版本号进行flush动作
|
||||||
ASSERT_EQ(OB_SUCCESS, mds_table_.for_each_unit_from_small_key_to_big_from_old_node_to_new_to_dump(
|
ASSERT_EQ(OB_SUCCESS, mds_table_.for_each_unit_from_small_key_to_big_from_old_node_to_new_to_dump(
|
||||||
[&idx](const MdsDumpKV &kv) -> int {// 2. 转储时扫描mds table
|
[&idx](const MdsDumpKV &kv) -> int {// 2. 转储时扫描mds table
|
||||||
OB_ASSERT(kv.v_.end_scn_ < mock_scn(199));// 扫描时看不到199版本以上的提交
|
MDS_ASSERT(kv.v_.end_scn_ < mock_scn(199));// 扫描时看不到199版本以上的提交
|
||||||
OB_ASSERT(idx < 10);
|
MDS_ASSERT(idx < 10);
|
||||||
MDS_LOG(INFO, "print dump node kv", K(kv));
|
MDS_LOG(INFO, "print dump node kv", K(kv));
|
||||||
return OB_SUCCESS;
|
return OB_SUCCESS;
|
||||||
}, 0, true)
|
}, 0, true)
|
||||||
|
|||||||
Reference in New Issue
Block a user