198 lines
7.5 KiB
C++
198 lines
7.5 KiB
C++
/**
|
|
* Copyright (c) 2021 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 "role_coordinator_handler.h"
|
|
#include "lib/container/ob_fixed_array.h"
|
|
#include "lib/lock/ob_spin_lock.h"
|
|
#include "lib/ob_define.h"
|
|
#include "share/ob_errno.h"
|
|
namespace oceanbase
|
|
{
|
|
using namespace common;
|
|
using namespace logservice;
|
|
namespace palfcluster
|
|
{
|
|
|
|
ObRoleChangeHandler::ObRoleChangeHandler(): lock_(common::ObLatchIds::RCS_LOCK),
|
|
sub_role_change_handler_arr_()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
ObRoleChangeHandler::~ObRoleChangeHandler()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
void ObRoleChangeHandler::reset()
|
|
{
|
|
for (int i = 0; i < ObLogBaseType::MAX_LOG_BASE_TYPE; i++) {
|
|
sub_role_change_handler_arr_[i] = NULL;
|
|
}
|
|
}
|
|
|
|
int ObRoleChangeHandler::register_handler(const ObLogBaseType &type,
|
|
ObIRoleChangeSubHandler *role_change_handler)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSpinLockGuard guard(lock_);
|
|
if (false == is_valid_log_base_type(type)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
sub_role_change_handler_arr_[type] = role_change_handler;
|
|
CLOG_LOG(INFO, "register_handler success", K(ret), K(type), KP(role_change_handler));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ObRoleChangeHandler::unregister_handler(const ObLogBaseType &type)
|
|
{
|
|
ObSpinLockGuard guard(lock_);
|
|
if (true == is_valid_log_base_type(type)) {
|
|
sub_role_change_handler_arr_[type] = NULL;
|
|
CLOG_LOG(INFO, "unregister_handler success", K(type));
|
|
}
|
|
}
|
|
|
|
void ObRoleChangeHandler::switch_to_follower_forcedly()
|
|
{
|
|
ObSpinLockGuard guard(lock_);
|
|
for (int i = 0; i < ObLogBaseType::MAX_LOG_BASE_TYPE; i++) {
|
|
ObIRoleChangeSubHandler *handler = sub_role_change_handler_arr_[i];
|
|
char sub_role_change_handler_str[OB_LOG_BASE_TYPE_STR_MAX_LEN] = {'\0'};
|
|
ObLogBaseType base_type = static_cast<ObLogBaseType>(i);
|
|
bool has_defined_to_string = false;
|
|
if (OB_SUCCESS == log_base_type_to_string(base_type, sub_role_change_handler_str,
|
|
OB_LOG_BASE_TYPE_STR_MAX_LEN)) {
|
|
has_defined_to_string = true;
|
|
}
|
|
if (NULL != handler) {
|
|
handler->switch_to_follower_forcedly();
|
|
CLOG_LOG(INFO, "leader to follower forcedly, current role change handler is",
|
|
"cursor", i, "name", has_defined_to_string ? sub_role_change_handler_str : "hasn't define to string");
|
|
}
|
|
}
|
|
}
|
|
|
|
int ObRoleChangeHandler::switch_to_leader()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSpinLockGuard guard(lock_);
|
|
for (int i = 0; i < ObLogBaseType::MAX_LOG_BASE_TYPE && OB_SUCC(ret); i++) {
|
|
ObIRoleChangeSubHandler *handler = sub_role_change_handler_arr_[i];
|
|
char sub_role_change_handler_str[OB_LOG_BASE_TYPE_STR_MAX_LEN] = {'\0'};
|
|
ObLogBaseType base_type = static_cast<ObLogBaseType>(i);
|
|
bool has_defined_to_string = false;
|
|
if (OB_SUCCESS == log_base_type_to_string(base_type, sub_role_change_handler_str,
|
|
OB_LOG_BASE_TYPE_STR_MAX_LEN)) {
|
|
has_defined_to_string = true;
|
|
}
|
|
if (NULL == handler) {
|
|
} else if (OB_FAIL(handler->switch_to_leader())) {
|
|
CLOG_LOG(WARN, "switch_to_leader failed", K(ret), KP(handler), K(i),
|
|
"cursor", i, "name", has_defined_to_string ? sub_role_change_handler_str : "hasn't define to string");
|
|
} else {
|
|
CLOG_LOG(INFO, "follower to leader, current role change handler is",
|
|
"cursor", i, "name", has_defined_to_string ? sub_role_change_handler_str : "hasn't define to string");
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObRoleChangeHandler::switch_to_follower_gracefully()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSpinLockGuard guard(lock_);
|
|
int64_t cursor = 0;
|
|
const int64_t count = ObLogBaseType::MAX_LOG_BASE_TYPE;
|
|
while (cursor < count && OB_SUCC(ret)) {
|
|
char sub_role_change_handler_str[OB_LOG_BASE_TYPE_STR_MAX_LEN] = {'\0'};
|
|
ObLogBaseType base_type = static_cast<ObLogBaseType>(cursor);
|
|
bool has_defined_to_string = false;
|
|
if (OB_SUCCESS == log_base_type_to_string(base_type, sub_role_change_handler_str,
|
|
OB_LOG_BASE_TYPE_STR_MAX_LEN)) {
|
|
has_defined_to_string = true;
|
|
}
|
|
ObIRoleChangeSubHandler *handler = sub_role_change_handler_arr_[cursor];
|
|
if (NULL == handler) {
|
|
cursor++;
|
|
} else if (OB_FAIL(handler->switch_to_follower_gracefully()) && OB_LS_NEED_REVOKE != ret) {
|
|
CLOG_LOG(WARN, "switch_to_follower_gracefully failed, need resume other sub modules", K(ret),
|
|
KP(handler), K(cursor),
|
|
"cursor", cursor, "name", has_defined_to_string ? sub_role_change_handler_str : "hasn't define to string");
|
|
// NB: resume_leader failed, need revoke leader.
|
|
} else if (OB_LS_NEED_REVOKE == ret) {
|
|
CLOG_LOG(WARN, "ObIRoleChangeSubHandler resume leader failed", K(ret), K(cursor));
|
|
} else {
|
|
CLOG_LOG(INFO, "leader to follower gracefully, current role change handler is",
|
|
"cursor", cursor, "name", has_defined_to_string ? sub_role_change_handler_str : "hasn't define to string");
|
|
cursor++;
|
|
}
|
|
}
|
|
// if any sub role handler switch_to_follower_gracefully failed, and no need to revoke leader,
|
|
// we should resume other sub role handler, meanwhile, we should overrite 'ret' only if
|
|
// resume_leader_when_switch_failure_ failed.
|
|
if (OB_FAIL(ret) && OB_LS_NEED_REVOKE != ret) {
|
|
int tmp_ret = OB_SUCCESS;
|
|
if (OB_SUCCESS != (tmp_ret = resume_leader_when_switch_failure_(cursor))) {
|
|
CLOG_LOG(WARN, "resume_leader_when_switch_failure_ failed", K(tmp_ret), K(cursor));
|
|
ret = tmp_ret;
|
|
} else {
|
|
CLOG_LOG(WARN, "resume_leader_when_switch_failure_ success, no need to excut follower to leader gracefully",
|
|
K(ret), K(tmp_ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObRoleChangeHandler::resume_to_leader()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int cursor = ObLogBaseType::MAX_LOG_BASE_TYPE;
|
|
if (OB_FAIL(resume_leader_when_switch_failure_(cursor))) {
|
|
CLOG_LOG(WARN, "resume_leader_when_switch_failure_ failed");
|
|
} else {
|
|
CLOG_LOG(INFO, "resume_to_leader success");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObRoleChangeHandler::resume_leader_when_switch_failure_(const int64_t cursor)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
for (int64_t i = cursor - 1; i >= 0 && OB_SUCC(ret); i--) {
|
|
ObIRoleChangeSubHandler *handler = sub_role_change_handler_arr_[i];
|
|
ObLogBaseType base_type = static_cast<ObLogBaseType>(i);
|
|
char sub_role_change_handler_str[OB_LOG_BASE_TYPE_STR_MAX_LEN] = {'\0'};
|
|
bool has_defined_to_string = false;
|
|
if (OB_SUCCESS == log_base_type_to_string(base_type, sub_role_change_handler_str,
|
|
OB_LOG_BASE_TYPE_STR_MAX_LEN)) {
|
|
has_defined_to_string = true;
|
|
}
|
|
if (NULL == handler){
|
|
CLOG_LOG(INFO, "not register into role change service", K(ret), K(i));
|
|
} else if (OB_FAIL(handler->resume_leader())) {
|
|
CLOG_LOG(WARN, "resume_leader failed", K(ret), K(i), KP(handler),
|
|
"cursor", i, "name", has_defined_to_string ? sub_role_change_handler_str : "hasn't define to string");
|
|
} else {
|
|
CLOG_LOG(INFO, "resume_leader success", K(ret), K(i), KP(handler),
|
|
"cursor", i, "name", has_defined_to_string ? sub_role_change_handler_str : "hasn't define to string");
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
ret = OB_LS_NEED_REVOKE;
|
|
}
|
|
return ret;
|
|
}
|
|
} // end namespace logservice
|
|
} // end namespace oceanbase
|