Files
oceanbase/src/storage/ob_garbage_collector.cpp

1398 lines
54 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 "ob_garbage_collector.h"
#include "common/ob_clock_generator.h"
#include "lib/mysqlclient/ob_mysql_proxy.h"
#include "lib/mysqlclient/ob_mysql_result.h"
#include "lib/thread/ob_thread_name.h"
#include "observer/ob_server_event_history_table_operator.h"
#include "share/ob_cluster_version.h"
#include "share/ob_srv_rpc_proxy.h"
#include "share/schema/ob_multi_version_schema_service.h"
#include "share/schema/ob_schema_getter_guard.h"
#include "share/ob_upgrade_utils.h"
#include "share/ob_multi_cluster_util.h"
#include "share/backup/ob_backup_info_mgr.h"
#include "storage/transaction/ob_trans_service.h"
#include "storage/transaction/ob_gc_partition_adapter.h"
#include "storage/ob_pg_storage.h"
#include "storage/ob_partition_service.h"
#include "storage/blocksstable/ob_tmp_file.h"
#include "storage/ob_file_system_util.h"
#include "rootserver/ob_rs_job_table_operator.h"
namespace oceanbase {
using namespace common;
using namespace share;
using namespace share::schema;
namespace storage {
class ObGarbageCollector::InsertPGFunctor {
public:
explicit InsertPGFunctor(const common::ObPGKey& pg_key) : pg_key_(pg_key), ret_value_(common::OB_SUCCESS)
{}
~InsertPGFunctor()
{}
public:
bool operator()(const common::ObAddr& leader, common::ObPartitionArray& pg_array)
{
if (OB_SUCCESS != (ret_value_ = pg_array.push_back(pg_key_))) {
STORAGE_LOG(WARN, "pg_array push_back failed", K(ret_value_), K(pg_key_), K(leader));
}
return common::OB_SUCCESS == ret_value_;
}
int get_ret_value() const
{
return ret_value_;
}
private:
common::ObPGKey pg_key_;
int ret_value_;
private:
DISALLOW_COPY_AND_ASSIGN(InsertPGFunctor);
};
class ObGarbageCollector::QueryPGIsValidMemberFunctor {
public:
QueryPGIsValidMemberFunctor(obrpc::ObSrvRpcProxy* rpc_proxy, ObPartitionService* partition_service,
const common::ObAddr& self_addr, const int64_t gc_seq, ObGCCandidateArray& gc_candidates)
: rpc_proxy_(rpc_proxy),
partition_service_(partition_service),
self_addr_(self_addr),
gc_seq_(gc_seq),
gc_candidates_(gc_candidates),
ret_value_(common::OB_SUCCESS)
{}
~QueryPGIsValidMemberFunctor()
{}
public:
bool operator()(const common::ObAddr& leader, common::ObPartitionArray& pg_array)
{
if (OB_SUCCESS != (ret_value_ = handle_pg_array_(leader, pg_array))) {
STORAGE_LOG(WARN, "handle_pg_array_ failed", K(ret_value_), K(pg_array), K(leader));
}
return common::OB_SUCCESS == ret_value_;
}
int get_ret_value() const
{
return ret_value_;
}
private:
int handle_pg_array_(const common::ObAddr& leader, const common::ObPartitionArray& pg_array);
int handle_rpc_response_(const common::ObAddr& leader, const obrpc::ObQueryIsValidMemberResponse& response);
bool is_normal_readonly_replica_(ObIPartitionGroup* pg) const;
int try_renew_location_(const common::ObPartitionArray& pg_array);
private:
obrpc::ObSrvRpcProxy* rpc_proxy_;
ObPartitionService* partition_service_;
common::ObAddr self_addr_;
int64_t gc_seq_;
ObGCCandidateArray& gc_candidates_;
int ret_value_;
private:
DISALLOW_COPY_AND_ASSIGN(QueryPGIsValidMemberFunctor);
};
class ObGarbageCollector::QueryPGFlushedIlogIDFunctor {
public:
QueryPGFlushedIlogIDFunctor(
obrpc::ObSrvRpcProxy* rpc_proxy, PGOfflineIlogFlushedInfoMap& pg_offline_ilog_flushed_info_map)
: rpc_proxy_(rpc_proxy),
pg_offline_ilog_flushed_info_map_(pg_offline_ilog_flushed_info_map),
ret_value_(common::OB_SUCCESS)
{}
~QueryPGFlushedIlogIDFunctor()
{}
public:
bool operator()(const common::ObAddr& leader, common::ObPartitionArray& pg_array)
{
if (OB_SUCCESS != (ret_value_ = handle_pg_array_(leader, pg_array))) {
STORAGE_LOG(WARN, "handle_pg_array_ failed", K(ret_value_), K(pg_array));
}
return common::OB_SUCCESS == ret_value_;
}
int get_ret_value() const
{
return ret_value_;
}
private:
int handle_pg_array_(const common::ObAddr& leader, const common::ObPartitionArray& pg_array);
int handle_rpc_response_(const common::ObAddr& server, const obrpc::ObQueryMaxFlushedILogIdResponse& response);
private:
obrpc::ObSrvRpcProxy* rpc_proxy_;
PGOfflineIlogFlushedInfoMap& pg_offline_ilog_flushed_info_map_;
int ret_value_;
private:
DISALLOW_COPY_AND_ASSIGN(QueryPGFlushedIlogIDFunctor);
};
class ObGarbageCollector::ExecuteSchemaDropFunctor {
public:
ExecuteSchemaDropFunctor(common::ObMySQLProxy* sql_proxy, ObPartitionService* partition_service)
: sql_proxy_(sql_proxy), partition_service_(partition_service), ret_value_(common::OB_SUCCESS)
{}
~ExecuteSchemaDropFunctor()
{}
public:
bool operator()(const common::ObPGKey& pg_key, const PGOfflineIlogFlushedInfo& info)
{
if (OB_SUCCESS != (ret_value_ = handle_each_pg_(pg_key, info))) {
STORAGE_LOG(WARN, "handle_each_pg_ failed", K(ret_value_), K(info));
}
return common::OB_SUCCESS == ret_value_;
}
int get_ret_value() const
{
return ret_value_;
}
private:
int handle_each_pg_(const common::ObPGKey& pg_key, const PGOfflineIlogFlushedInfo& info);
int delete_tenant_gc_partition_info_(const common::ObPGKey& pg_key);
private:
common::ObMySQLProxy* sql_proxy_;
ObPartitionService* partition_service_;
int ret_value_;
private:
DISALLOW_COPY_AND_ASSIGN(ExecuteSchemaDropFunctor);
};
ObGarbageCollector::ObGarbageCollector()
: is_inited_(false),
partition_service_(NULL),
trans_service_(NULL),
schema_service_(NULL),
rpc_proxy_(NULL),
sql_proxy_(NULL),
self_addr_(),
seq_(1)
{}
ObGarbageCollector::~ObGarbageCollector()
{
destroy();
}
int ObGarbageCollector::init(ObPartitionService* partition_service, transaction::ObTransService* trans_service,
share::schema::ObMultiVersionSchemaService* schema_service, obrpc::ObSrvRpcProxy* rpc_proxy,
common::ObMySQLProxy* sql_proxy, const common::ObAddr& self_addr)
{
int ret = OB_SUCCESS;
if (is_inited_) {
ret = OB_INIT_TWICE;
STORAGE_LOG(WARN, "ObGarbageCollector is inited twice");
} else if (OB_ISNULL(partition_service) || OB_ISNULL(trans_service) || OB_ISNULL(schema_service) ||
OB_ISNULL(rpc_proxy) || OB_ISNULL(sql_proxy) || !self_addr.is_valid()) {
ret = OB_INVALID_ARGUMENT;
STORAGE_LOG(WARN,
"invalid arguments",
K(ret),
KP(partition_service),
KP(trans_service),
KP(schema_service),
KP(rpc_proxy),
KP(sql_proxy),
K(self_addr));
} else {
partition_service_ = partition_service;
trans_service_ = trans_service;
schema_service_ = schema_service;
rpc_proxy_ = rpc_proxy;
sql_proxy_ = sql_proxy;
self_addr_ = self_addr;
seq_ = 1;
is_inited_ = true;
}
STORAGE_LOG(INFO, "ObGarbageCollector is inited", K(ret), K(self_addr_));
return ret;
}
int ObGarbageCollector::start()
{
int ret = OB_SUCCESS;
if (IS_NOT_INIT) {
ret = OB_NOT_INIT;
STORAGE_LOG(WARN, "ObGarbageCollector is not inited", K(ret));
} else if (OB_FAIL(ObThreadPool::start())) {
STORAGE_LOG(ERROR, "ObGarbageCollector thread failed to start", K(ret));
} else {
// do nothing
}
return ret;
}
void ObGarbageCollector::stop()
{
ObThreadPool::stop();
STORAGE_LOG(INFO, "ObGarbageCollector stop");
}
void ObGarbageCollector::wait()
{
ObThreadPool::wait();
STORAGE_LOG(INFO, "ObGarbageCollector wait");
}
void ObGarbageCollector::destroy()
{
stop();
wait();
is_inited_ = false;
partition_service_ = NULL;
trans_service_ = NULL;
schema_service_ = NULL;
rpc_proxy_ = NULL;
sql_proxy_ = NULL;
self_addr_.reset();
}
void ObGarbageCollector::run1()
{
STORAGE_LOG(INFO, "Garbage Collector start to run");
lib::set_thread_name("GCCollector");
while (!has_set_stop()) {
DEBUG_SYNC(BLOCK_GARBAGE_COLLECTOR);
int ret = OB_SUCCESS;
TenantSet gc_tenant_set;
ObGCCandidateArray gc_candidates;
int64_t gc_interval = GC_INTERVAL;
#ifdef ERRSIM
gc_interval = std::min(gc_interval, (int64_t)ObServerConfig::get_instance().schema_drop_gc_delay_time);
#endif
STORAGE_LOG(INFO, "Garbage Collector is running", K(seq_), K(gc_interval));
if (OB_FAIL(gc_tenant_set.create(241))) { // 241 means HASH_BUCKET_NUM
STORAGE_LOG(ERROR, "gc_tenant_set create failed", K(ret));
} else if (check_gc_condition_()) {
gc_candidates.reset();
(void)gc_check_member_list_(gc_candidates);
(void)execute_gc_except_leader_schema_drop_(gc_candidates);
gc_candidates.reset();
(void)gc_check_schema_(gc_candidates, gc_tenant_set);
(void)execute_gc_except_leader_schema_drop_(gc_candidates);
(void)execute_gc_for_leader_schema_drop_(gc_candidates);
(void)execute_gc_tenant_tmp_file_();
}
usleep(gc_interval);
seq_++;
}
return;
}
bool ObGarbageCollector::check_gc_condition_() const
{
bool bool_ret = true;
if (!schema_service_->is_sys_full_schema()) {
bool_ret = false;
STORAGE_LOG(INFO, "no full-updated schema, skip gc");
} else if (!partition_service_->is_scan_disk_finished()) {
bool_ret = false;
STORAGE_LOG(INFO, "in rebooting, skip gc");
} else {
// do nothing
}
return bool_ret;
}
bool ObGarbageCollector::is_gc_reason_leader_schema_drop_(const NeedGCReason& gc_reason)
{
return (LEADER_PENDDING_SCHEMA_DROP == gc_reason) || (LEADER_PHYSICAL_SCHEMA_DROP == gc_reason);
}
int ObGarbageCollector::execute_gc_except_leader_schema_drop_(const ObGCCandidateArray& gc_candidates)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
const int64_t begin_time = ObTimeUtility::current_time();
for (int64_t index = 0; OB_SUCC(ret) && index < gc_candidates.count(); index++) {
const common::ObPGKey& pg_key = gc_candidates[index].pg_key_;
const NeedGCReason& gc_reason = gc_candidates[index].gc_reason_;
if (is_gc_reason_leader_schema_drop_(gc_reason)) {
// skip it
} else if (OB_SUCCESS != (tmp_ret = partition_service_->remove_partition(pg_key))) {
STORAGE_LOG(WARN, "remove_partition failed", K(tmp_ret), K(pg_key));
} else {
STORAGE_LOG(INFO, "GC remove_partition success", K(tmp_ret), K(pg_key));
SERVER_EVENT_ADD("gc", "clearup_replica", "partition_group", pg_key);
}
}
STORAGE_LOG(INFO,
"execute_gc_except_leader_schema_drop_ cost time",
K(ret),
K(seq_),
"time",
ObTimeUtility::current_time() - begin_time);
return ret;
}
int ObGarbageCollector::execute_gc_for_leader_schema_drop_(const ObGCCandidateArray& gc_candidates)
{
int ret = OB_SUCCESS;
const int64_t begin_time = ObTimeUtility::current_time();
ObGCCandidateArray leader_schema_drop_gc_candidates;
if (OB_FAIL(extract_leader_schema_drop_gc_candidates_(gc_candidates, leader_schema_drop_gc_candidates))) {
STORAGE_LOG(WARN, "extract_leader_schema_drop_gc_candidates_ failed", K(ret));
} else if (OB_FAIL(handle_leader_schema_drop_gc_candidates_(leader_schema_drop_gc_candidates))) {
STORAGE_LOG(WARN, "handle_leader_schema_drop_gc_candidates_ failed", K(ret));
}
STORAGE_LOG(INFO,
"execute_gc_for_leader_schema_drop_ cost time",
K(ret),
K(seq_),
"time",
ObTimeUtility::current_time() - begin_time);
return ret;
}
int ObGarbageCollector::extract_leader_schema_drop_gc_candidates_(
const ObGCCandidateArray& gc_candidates, ObGCCandidateArray& leader_schema_drop_gc_candidates)
{
int ret = OB_SUCCESS;
for (int64_t index = 0; OB_SUCC(ret) && index < gc_candidates.count(); index++) {
const GCCandidate& candidate = gc_candidates[index];
if (is_gc_reason_leader_schema_drop_(candidate.gc_reason_) &&
OB_FAIL(leader_schema_drop_gc_candidates.push_back(candidate))) {
STORAGE_LOG(WARN, "leader_schema_drop_gc_candidates push_back failed", K(ret), K(candidate));
}
}
return ret;
}
int ObGarbageCollector::handle_leader_schema_drop_gc_candidates_(const ObGCCandidateArray& gc_candidates)
{
int ret = OB_SUCCESS;
ServerPGMap server_pg_map;
PGOfflineIlogFlushedInfoMap pg_offline_ilog_flushed_info_map;
if (OB_FAIL(server_pg_map.init(ObModIds::OB_HASH_BUCKET_SERVER_PARTITION_MAP))) {
STORAGE_LOG(WARN, "server_pg_map init failed", K(ret));
} else if (OB_FAIL(pg_offline_ilog_flushed_info_map.init(
ObModIds::OB_HASH_BUCKET_SERVER_PARTITION_MAP, gc_candidates.count()))) {
STORAGE_LOG(WARN, "pg_offline_ilog_flushed_info_map failed", K(ret));
} else if (OB_FAIL(construct_server_pg_map_for_leader_schema_drop_(
gc_candidates, server_pg_map, pg_offline_ilog_flushed_info_map))) {
STORAGE_LOG(WARN, "construct_server_pg_map_for_leader_schema_drop_ failed", K(ret));
} else if (OB_FAIL(handle_each_pg_for_leader_schema_drop_(server_pg_map, pg_offline_ilog_flushed_info_map))) {
STORAGE_LOG(WARN, "handle_each_pg_for_leader_schema_drop_ failed", K(ret));
}
return ret;
}
int ObGarbageCollector::construct_server_pg_map_for_leader_schema_drop_(const ObGCCandidateArray& gc_candidates,
ServerPGMap& server_pg_map, PGOfflineIlogFlushedInfoMap& pg_offline_ilog_flushed_info_map)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
for (int64_t index = 0; OB_SUCC(ret) && index < gc_candidates.count(); index++) {
storage::ObIPartitionGroupGuard guard;
clog::ObIPartitionLogService* log_service = NULL;
common::ObMemberList leader_member_list;
int64_t replica_num = 0;
common::ObAddr server;
const common::ObPGKey& pg_key = gc_candidates[index].pg_key_;
const NeedGCReason& gc_reason = gc_candidates[index].gc_reason_;
PGOfflineIlogFlushedInfo ilog_flushed_info;
ilog_flushed_info.offline_ilog_flushed_replica_num_ = 0;
ilog_flushed_info.gc_reason_ = gc_reason;
if (OB_SUCCESS != (tmp_ret = partition_service_->get_partition(pg_key, guard)) ||
NULL == guard.get_partition_group() || NULL == (log_service = guard.get_partition_group()->get_log_service())) {
tmp_ret = OB_PARTITION_NOT_EXIST;
STORAGE_LOG(WARN, "partition not exist", K(tmp_ret), K(pg_key));
} else if (!guard.get_partition_group()->is_valid()) {
tmp_ret = OB_INVALID_PARTITION;
STORAGE_LOG(WARN, "invalid partition", K(tmp_ret), K(pg_key));
} else if (OB_SUCCESS != (tmp_ret = log_service->get_leader_curr_member_list(leader_member_list))) {
STORAGE_LOG(WARN, "get_leader_curr_member_list failed", K(tmp_ret), K(pg_key));
} else if (OB_SUCCESS != (tmp_ret = log_service->get_replica_num(replica_num))) {
STORAGE_LOG(WARN, "get_replica_num failed", K(tmp_ret), K(pg_key));
} else if (OB_FALSE_IT(ilog_flushed_info.replica_num_ = replica_num)) {
// skip it
} else if (OB_FALSE_IT(ilog_flushed_info.offline_log_id_ = guard.get_partition_group()->get_offline_log_id())) {
// skip it
} else if (OB_FAIL(pg_offline_ilog_flushed_info_map.insert(pg_key, ilog_flushed_info))) {
STORAGE_LOG(WARN, "pg_offline_ilog_flushed_info_map insert failed", K(ret), K(pg_key));
} else {
for (int64_t index = 0; OB_SUCC(ret) && index < leader_member_list.get_member_number(); index++) {
if (OB_FAIL(leader_member_list.get_server_by_index(index, server))) {
STORAGE_LOG(WARN, "leader_member_list get_server_by_index failed", K(ret), K(pg_key), K(leader_member_list));
} else if (OB_FAIL(construct_server_pg_map_(server_pg_map, server, pg_key))) {
STORAGE_LOG(WARN, "construct_server_pg_map_ failed", K(ret), K(pg_key), K(server));
}
}
}
}
return ret;
}
int ObGarbageCollector::handle_each_pg_for_leader_schema_drop_(
ServerPGMap& server_pg_map, PGOfflineIlogFlushedInfoMap& pg_offline_ilog_flushed_info_map)
{
int ret = OB_SUCCESS;
QueryPGFlushedIlogIDFunctor functor(rpc_proxy_, pg_offline_ilog_flushed_info_map);
if (OB_SUCCESS != server_pg_map.for_each(functor)) {
ret = functor.get_ret_value();
STORAGE_LOG(WARN, "for_each server_pg_map failed", K(ret));
}
if (OB_SUCC(ret) && OB_FAIL(handle_pg_offline_ilog_flushed_info_map_(pg_offline_ilog_flushed_info_map))) {
STORAGE_LOG(WARN, "handle_pg_offline_ilog_flushed_info_map_ failed", K(ret));
}
return ret;
}
int ObGarbageCollector::handle_pg_offline_ilog_flushed_info_map_(
PGOfflineIlogFlushedInfoMap& pg_offline_ilog_flushed_info_map)
{
int ret = OB_SUCCESS;
ExecuteSchemaDropFunctor functor(sql_proxy_, partition_service_);
if (OB_SUCCESS != pg_offline_ilog_flushed_info_map.for_each(functor)) {
ret = functor.get_ret_value();
STORAGE_LOG(WARN, "for_each pg_offline_ilog_flushed_info_map failed", K(ret));
}
return ret;
}
int ObGarbageCollector::execute_gc_tenant_tmp_file_()
{
int ret = OB_SUCCESS;
ObSEArray<uint64_t, 16> tenant_ids;
ObSchemaGetterGuard schema_guard;
const int64_t begin_time = ObTimeUtility::current_time();
if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.get_all_tenant_id(tenant_ids))) {
STORAGE_LOG(WARN, "fail to get all tenant ids", K(ret));
} else if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) {
STORAGE_LOG(WARN, "fail to get schema guard", K(ret));
} else if (OB_FAIL(schema_guard.check_formal_guard())) {
STORAGE_LOG(WARN, "schema_guard is not formal", K(ret));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < tenant_ids.count(); i++) {
const uint64_t tenant_id = tenant_ids.at(i);
bool tenant_has_been_dropped = false;
if (OB_FAIL(schema_guard.check_if_tenant_has_been_dropped(tenant_id, tenant_has_been_dropped))) {
STORAGE_LOG(WARN, "fail to check if tenant hash been dropped", K(ret), K(tenant_id));
} else if (!tenant_has_been_dropped) {
continue;// do nothing, just skip.
} else if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.remove_tenant_file(tenant_id))) {
STORAGE_LOG(WARN, "remove tenant tmp file failed", K(ret), K(tenant_id));
} else {
STORAGE_LOG(INFO, "remove tenant tmp file success", K(ret), K(tenant_id));
}
}
}
STORAGE_LOG(INFO,
"execute_gc_tenant_tmp_file_ cost time",
K(ret),
K(seq_),
"time",
ObTimeUtility::current_time() - begin_time);
return ret;
}
int ObGarbageCollector::gc_check_member_list_(ObGCCandidateArray& gc_candidates)
{
int ret = OB_SUCCESS;
const int64_t begin_time = ObTimeUtility::current_time();
ServerPGMap server_pg_map;
if (OB_FAIL(server_pg_map.init(ObModIds::OB_HASH_BUCKET_SERVER_PARTITION_MAP))) {
STORAGE_LOG(WARN, "server_pg_map init failed", K(ret));
} else if (OB_FAIL(construct_server_pg_map_for_member_list_(server_pg_map))) {
STORAGE_LOG(WARN, "construct_server_pg_map_for_member_list_ failed", K(ret));
} else if (OB_FAIL(handle_each_pg_for_member_list_(server_pg_map, gc_candidates))) {
STORAGE_LOG(WARN, "handle_each_pg_for_member_list_ failed", K(ret));
}
STORAGE_LOG(
INFO, "gc_check_member_list_ cost time", K(ret), K(seq_), "time", ObTimeUtility::current_time() - begin_time);
return ret;
}
int ObGarbageCollector::construct_server_pg_map_for_member_list_(ServerPGMap& server_pg_map) const
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
storage::ObIPartitionGroupIterator* partition_iter = NULL;
if (NULL == (partition_iter = partition_service_->alloc_pg_iter())) {
ret = OB_ALLOCATE_MEMORY_FAILED;
STORAGE_LOG(ERROR, "partition_service alloc_pg_iter failed", K(ret));
} else {
while (OB_SUCC(ret)) {
storage::ObIPartitionGroup* pg = NULL;
clog::ObIPartitionLogService* log_service = NULL;
common::ObPGKey pg_key;
common::ObAddr leader;
bool allow_gc = false;
if (OB_FAIL(partition_iter->get_next(pg))) {
if (OB_ITER_END != ret) {
STORAGE_LOG(WARN, "partition_iter->get_next failed", K(ret));
}
} else if (NULL == pg || NULL == (log_service = pg->get_log_service()) ||
OB_FALSE_IT(pg_key = pg->get_partition_key())) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(ERROR, "unexpected error, pg is NULL", K(ret));
} else if (OB_SUCCESS != (tmp_ret = pg->get_leader(leader))) {
STORAGE_LOG(WARN, "get_leader failed", K(tmp_ret), K(pg_key));
} else if (leader == self_addr_) {
STORAGE_LOG(TRACE, "self is leader, skip it", K(pg_key));
} else if (!leader.is_valid()) {
STORAGE_LOG(TRACE, "leader is invalid, need renew location cache", K(pg_key));
if (OB_SUCCESS != (tmp_ret = log_service->try_update_leader_from_loc_cache())) {
STORAGE_LOG(WARN, "try_update_leader_from_loc_cache failed", K(tmp_ret), K(pg_key));
}
} else if (OB_SUCCESS != (tmp_ret = pg->allow_gc(allow_gc))) {
STORAGE_LOG(WARN, "allow gc failed", K(tmp_ret), K(pg_key));
} else if (!allow_gc) {
STORAGE_LOG(INFO, "this pg is not allowed to gc", K(pg_key));
} else if (OB_SUCCESS != (tmp_ret = construct_server_pg_map_(server_pg_map, leader, pg_key))) {
STORAGE_LOG(WARN, "construct_server_pg_map_ failed", K(tmp_ret), K(pg_key), K(leader));
}
}
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
}
}
if (NULL != partition_iter) {
partition_service_->revert_pg_iter(partition_iter);
partition_iter = NULL;
}
return ret;
}
int ObGarbageCollector::construct_server_pg_map_(
ServerPGMap& server_pg_map, const common::ObAddr& server, const common::ObPGKey& pg_key) const
{
int ret = OB_SUCCESS;
InsertPGFunctor functor(pg_key);
if (!server.is_valid() || !pg_key.is_valid()) {
ret = OB_INVALID_ARGUMENT;
STORAGE_LOG(ERROR, "invalid arguments", K(ret), K(pg_key), K(server));
} else if (OB_SUCCESS == (ret = server_pg_map.operate(server, functor))) {
// do nothing
} else if (OB_ENTRY_NOT_EXIST == ret) {
common::ObPartitionArray tmp_pg_array;
if (OB_FAIL(server_pg_map.insert(server, tmp_pg_array))) {
STORAGE_LOG(WARN, "server_pg_map insert failed", K(ret), K(pg_key), K(server));
} else if (OB_SUCCESS != server_pg_map.operate(server, functor)) {
ret = functor.get_ret_value();
STORAGE_LOG(WARN, "insert pg functor operate failed", K(ret), K(pg_key), K(server));
}
} else {
ret = functor.get_ret_value();
STORAGE_LOG(WARN, "insert pg functor operate failed", K(ret), K(pg_key), K(server));
}
return ret;
}
int ObGarbageCollector::handle_each_pg_for_member_list_(ServerPGMap& server_pg_map, ObGCCandidateArray& gc_candidates)
{
int ret = OB_SUCCESS;
QueryPGIsValidMemberFunctor functor(rpc_proxy_, partition_service_, self_addr_, seq_, gc_candidates);
if (OB_SUCCESS != server_pg_map.for_each(functor)) {
ret = functor.get_ret_value();
STORAGE_LOG(WARN, "for_each server_pg_map failed", K(ret));
}
return ret;
}
int ObGarbageCollector::QueryPGIsValidMemberFunctor::handle_pg_array_(
const common::ObAddr& leader, const common::ObPartitionArray& pg_array)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
const int64_t TIMEOUT = 10 * 1000 * 1000;
const int64_t MAX_PARTITION_CNT = 10000;
obrpc::ObQueryIsValidMemberRequest request;
obrpc::ObQueryIsValidMemberResponse response;
for (int64_t index = 0; OB_SUCC(ret) && index < pg_array.count(); index++) {
request.self_addr_ = self_addr_;
if (OB_FAIL(request.partition_array_.push_back(pg_array[index]))) {
STORAGE_LOG(WARN, "request pg_array push_back failed", K(ret), K(leader));
} else if ((index + 1) % MAX_PARTITION_CNT == 0 || index == pg_array.count() - 1) {
if (OB_SUCCESS != (tmp_ret = rpc_proxy_->to(leader).timeout(TIMEOUT).query_is_valid_member(request, response)) ||
(OB_SUCCESS != (tmp_ret = response.ret_value_))) {
STORAGE_LOG(WARN, "query_is_valid_member failed", K(tmp_ret), K(leader));
if (OB_SUCCESS != (tmp_ret = try_renew_location_(pg_array))) {
STORAGE_LOG(WARN, "try_renew_location_ failed", K(tmp_ret), K(pg_array));
}
} else if (OB_SUCCESS != (tmp_ret = handle_rpc_response_(leader, response))) {
STORAGE_LOG(WARN, "handle_rpc_response failed", K(ret), K(leader));
} else {
request.reset();
response.reset();
}
}
}
return ret;
}
bool ObGarbageCollector::QueryPGIsValidMemberFunctor::is_normal_readonly_replica_(ObIPartitionGroup* pg) const
{
bool bool_ret = false;
int tmp_ret = OB_SUCCESS;
bool is_offline = false;
const common::ObPGKey& pg_key = pg->get_partition_key();
if (ObReplicaTypeCheck::is_readonly_replica(pg->get_replica_type())) {
if (OB_SUCCESS != (tmp_ret = pg->is_replica_need_gc(is_offline))) {
STORAGE_LOG(WARN, "is_replica_need_gc failed", K(tmp_ret), K(pg_key));
} else if (!is_offline) {
bool_ret = true;
} else {
STORAGE_LOG(INFO, "is_replica_need_gc return true", K(tmp_ret), K(pg_key));
}
}
return bool_ret;
}
int ObGarbageCollector::QueryPGIsValidMemberFunctor::try_renew_location_(const common::ObPartitionArray& pg_array)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
for (int64_t index = 0; OB_SUCC(ret) && index < pg_array.count(); index++) {
const common::ObPGKey& pg_key = pg_array[index];
storage::ObIPartitionGroupGuard guard;
storage::ObIPartitionGroup* pg = NULL;
clog::ObIPartitionLogService* log_service = NULL;
if (OB_SUCCESS != (tmp_ret = partition_service_->get_partition(pg_key, guard))) {
STORAGE_LOG(WARN, "get_partition failed", K(tmp_ret), K(pg_key));
} else if (NULL == (pg = guard.get_partition_group()) || !pg->is_valid() ||
OB_ISNULL(log_service = pg->get_log_service())) {
STORAGE_LOG(WARN, "invalid pg", K(pg_key));
} else if (OB_SUCCESS != (tmp_ret = log_service->try_update_leader_from_loc_cache())) {
STORAGE_LOG(WARN, "try_update_leader_from_loc_cache failed", K(tmp_ret), K(pg_key));
}
}
return ret;
}
int ObGarbageCollector::QueryPGIsValidMemberFunctor::handle_rpc_response_(
const common::ObAddr& leader, const obrpc::ObQueryIsValidMemberResponse& response)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
const common::ObPartitionArray& pg_array = response.partition_array_;
const common::ObSEArray<bool, 16>& candidates_status = response.candidates_status_;
const common::ObSEArray<int, 16>& ret_array = response.ret_array_;
if (pg_array.count() != candidates_status.count()) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(ERROR, "response count not match, unexpected", K(ret), K(leader));
} else {
for (int64_t index = 0; OB_SUCC(ret) && index < pg_array.count(); index++) {
storage::ObIPartitionGroupGuard guard;
storage::ObIPartitionGroup* pg = NULL;
clog::ObIPartitionLogService* log_service = NULL;
bool allow_gc = false;
const common::ObPGKey& pg_key = pg_array[index];
const bool is_valid_member = candidates_status[index];
if (OB_SUCCESS != (tmp_ret = partition_service_->get_partition(pg_key, guard))) {
STORAGE_LOG(WARN, "get_partition failed", K(tmp_ret), K(pg_key));
} else if (NULL == (pg = guard.get_partition_group()) || !pg->is_valid() ||
OB_ISNULL(log_service = pg->get_log_service())) {
STORAGE_LOG(WARN, "invalid pg", K(pg_key));
} else if (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_3100 && ret_array.count() == pg_array.count() &&
OB_SUCCESS != ret_array[index]) {
STORAGE_LOG(INFO,
"remote_ret_code is not success, need renew location",
K(pg_key),
K(leader),
"remote_ret_code",
ret_array[index]);
if (OB_SUCCESS != (tmp_ret = log_service->try_update_leader_from_loc_cache())) {
STORAGE_LOG(WARN, "try_update_leader_from_loc_cache failed", K(tmp_ret), K(pg_key), K(leader));
}
} else if (is_normal_readonly_replica_(pg)) {
// do nothing
} else if (OB_SUCCESS != (tmp_ret = pg->gc_check_valid_member(is_valid_member, gc_seq_, allow_gc))) {
STORAGE_LOG(WARN,
"gc_check_valid_member failed",
K(tmp_ret),
K(pg_key),
K(leader),
K(is_valid_member),
K(gc_seq_),
K(allow_gc));
} else if (allow_gc) {
GCCandidate candidate;
candidate.pg_key_ = pg_key;
candidate.gc_reason_ = NOT_IN_LEADER_MEMBER_LIST;
if (OB_FAIL(gc_candidates_.push_back(candidate))) {
STORAGE_LOG(WARN, "gc_candidates push_back failed", K(ret), K(pg_key), K(leader));
} else {
STORAGE_LOG(
INFO, "gc_candidates push_back pg success", K(ret), K(pg_key), "gc_reason", NOT_IN_LEADER_MEMBER_LIST);
SERVER_EVENT_ADD("gc", "gc_candidates", "partition_group", pg_key, "reason", "not in leader member list");
}
}
}
}
return ret;
}
int ObGarbageCollector::QueryPGFlushedIlogIDFunctor::handle_pg_array_(
const common::ObAddr& server, const common::ObPartitionArray& pg_array)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
const int64_t TIMEOUT = 10 * 1000 * 1000;
const int64_t MAX_PARTITION_CNT = 10000;
obrpc::ObQueryMaxFlushedILogIdRequest request;
obrpc::ObQueryMaxFlushedILogIdResponse response;
for (int64_t index = 0; OB_SUCC(ret) && index < pg_array.count(); index++) {
if (OB_FAIL(request.partition_array_.push_back(pg_array[index]))) {
STORAGE_LOG(WARN, "request pg_array push_back failed", K(ret), K(server));
} else if ((index + 1) % MAX_PARTITION_CNT == 0 || index == pg_array.count() - 1) {
if (OB_SUCCESS !=
(tmp_ret = rpc_proxy_->to(server).timeout(TIMEOUT).query_max_flushed_ilog_id(request, response)) ||
OB_SUCCESS != (tmp_ret = response.err_code_)) {
STORAGE_LOG(WARN, "query_max_flushed_ilog_id failed", K(tmp_ret), K(server));
} else if (OB_SUCCESS != (tmp_ret = handle_rpc_response_(server, response))) {
STORAGE_LOG(WARN, "handle_rpc_response_ failed", K(tmp_ret), K(server));
} else {
request.reset();
response.reset();
}
}
}
return ret;
}
int ObGarbageCollector::QueryPGFlushedIlogIDFunctor::handle_rpc_response_(
const common::ObAddr& server, const obrpc::ObQueryMaxFlushedILogIdResponse& response)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
const common::ObPartitionArray& pg_array = response.partition_array_;
const common::ObSEArray<uint64_t, 16>& max_flushed_ilog_ids = response.max_flushed_ilog_ids_;
if (pg_array.count() != max_flushed_ilog_ids.count()) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(ERROR, "response count not match, unexpected", K(ret), K(server));
} else {
for (int64_t index = 0; OB_SUCC(ret) && index < pg_array.count(); index++) {
const common::ObPGKey& pg_key = pg_array[index];
const uint64_t max_flushed_ilog_id = max_flushed_ilog_ids[index];
PGOfflineIlogFlushedInfo pg_offline_ilog_flushed_info;
if (OB_SUCCESS != (tmp_ret = pg_offline_ilog_flushed_info_map_.get(pg_key, pg_offline_ilog_flushed_info))) {
STORAGE_LOG(WARN, "pg_offline_ilog_flushed_info_map_ get failed", K(ret), K(pg_key), K(server));
} else if (OB_INVALID_ID != max_flushed_ilog_id &&
max_flushed_ilog_id >= pg_offline_ilog_flushed_info.offline_log_id_) {
pg_offline_ilog_flushed_info.offline_ilog_flushed_replica_num_++;
if (OB_SUCCESS != (tmp_ret = pg_offline_ilog_flushed_info_map_.update(pg_key, pg_offline_ilog_flushed_info))) {
STORAGE_LOG(WARN, "pg_offline_ilog_flushed_info_map_ update failed", K(ret), K(pg_key), K(server));
}
}
}
}
return ret;
}
int ObGarbageCollector::ExecuteSchemaDropFunctor::handle_each_pg_(
const common::ObPGKey& pg_key, const PGOfflineIlogFlushedInfo& info)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
if (info.offline_ilog_flushed_replica_num_ < info.replica_num_ / 2 + 1) {
STORAGE_LOG(INFO, "offline_ilog_flushed_replica_num is not majority, skip this pg", K(pg_key), K(info));
} else if (OB_SUCCESS != (tmp_ret = delete_tenant_gc_partition_info_(pg_key))) {
STORAGE_LOG(WARN, "delete_tenant_gc_partition_info_ failed", K(ret), K(pg_key), K(info));
} else if (LEADER_PHYSICAL_SCHEMA_DROP == info.gc_reason_) {
if (OB_SUCCESS != (tmp_ret = partition_service_->remove_partition(pg_key))) {
STORAGE_LOG(WARN, "remove_partition failed", K(tmp_ret), K(pg_key), K(info));
} else {
STORAGE_LOG(INFO, "GC remove_partition success", K(tmp_ret), K(pg_key), K(info));
SERVER_EVENT_ADD("gc", "clearup_replica", "partition_group", pg_key);
}
} else {
STORAGE_LOG(INFO, "this pg is in pennding schema drop, wait to gc", K(ret), K(pg_key), K(info));
}
return ret;
}
int ObGarbageCollector::ExecuteSchemaDropFunctor::delete_tenant_gc_partition_info_(const common::ObPGKey& pg_key)
{
int ret = OB_SUCCESS;
const uint64_t tenant_id = pg_key.get_tenant_id();
const uint64_t table_id = pg_key.get_table_id();
const int64_t partition_id = pg_key.get_partition_id();
ObSqlString sql;
int64_t affected_rows = 0;
if (OB_ISNULL(sql_proxy_)) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "sql proxy is NULL", K(ret));
} else if (OB_FAIL(sql.append_fmt("DELETE FROM %s WHERE (tenant_id = %lu and table_id = %lu and partition_id = %ld)",
OB_ALL_TENANT_GC_PARTITION_INFO_TNAME,
ObSchemaUtils::get_extract_tenant_id(tenant_id, tenant_id),
ObSchemaUtils::get_extract_schema_id(tenant_id, table_id),
partition_id))) {
STORAGE_LOG(WARN, "append sql failed", K(ret));
} else if (OB_FAIL(sql.append_fmt(" or (tenant_id = %lu and table_id = %lu and partition_id = %ld)",
OB_INVALID_TENANT_ID,
extract_pure_id(table_id),
partition_id))) {
STORAGE_LOG(WARN, "append sql failed", K(ret));
} else if (OB_FAIL(sql_proxy_->write(tenant_id, sql.ptr(), affected_rows))) {
STORAGE_LOG(WARN, "execute sql failed", K(ret), K(sql));
} else if (1 != affected_rows && 0 != affected_rows) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(ERROR, "affected_rows should be not greator than 1", K(ret), K(affected_rows));
} else {
// do nothing
}
STORAGE_LOG(INFO, "delete_tenant_gc_partition_info", K(ret), K(pg_key), K(sql));
return ret;
}
int ObGarbageCollector::gc_check_schema_(ObGCCandidateArray& gc_candidates, TenantSet& gc_tenant_set)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
const int64_t begin_time = ObTimeUtility::current_time();
storage::ObIPartitionGroupIterator* partition_iter = NULL;
ObSchemaGetterGuard schema_guard;
if (NULL == (partition_iter = partition_service_->alloc_pg_iter())) {
ret = OB_ALLOCATE_MEMORY_FAILED;
STORAGE_LOG(ERROR, "partition_service alloc_pg_iter failed", K(ret));
} else if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) {
STORAGE_LOG(WARN, "fail to get schema guard", K(ret));
} else if (OB_FAIL(schema_guard.check_formal_guard())) {
STORAGE_LOG(WARN, "schema_guard is not formal", K(ret));
} else {
while (OB_SUCC(ret)) {
storage::ObIPartitionGroup* pg = NULL;
ObPGKey pg_key;
NeedGCReason gc_reason = NO_NEED_TO_GC;
bool allow_gc = false;
if (OB_FAIL(partition_iter->get_next(pg))) {
if (OB_ITER_END != ret) {
STORAGE_LOG(WARN, "partition_iter->get_next failed", K(ret));
}
} else if (NULL == pg || OB_FALSE_IT(pg_key = pg->get_partition_key())) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(ERROR, "unexpected error, pg is NULL", K(ret));
} else if (OB_SUCCESS != (tmp_ret = gc_check_schema_(pg, schema_guard, gc_tenant_set, gc_reason))) {
STORAGE_LOG(WARN, "gc_check_schema_ failed", K(tmp_ret), K(pg_key));
} else if (NO_NEED_TO_GC == gc_reason) {
// skip it
} else if (OB_SUCCESS != (tmp_ret = pg->allow_gc(allow_gc))) {
STORAGE_LOG(WARN, "allow gc failed", K(tmp_ret), K(pg_key));
} else if (!allow_gc) {
(void)pg->set_need_gc();
STORAGE_LOG(INFO, "this pg is needed to gc, but is not allowed to gc, set need_gc flag", K(pg_key));
} else {
GCCandidate candidate;
candidate.pg_key_ = pg_key;
candidate.gc_reason_ = gc_reason;
if (OB_FAIL(gc_candidates.push_back(candidate))) {
STORAGE_LOG(WARN, "gc_candidates push_back failed", K(ret), K(pg_key));
} else {
STORAGE_LOG(INFO, "gc_candidates push_back pg success", K(ret), K(pg_key), K(gc_reason));
}
}
}
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
}
}
if (NULL != partition_iter) {
partition_service_->revert_pg_iter(partition_iter);
partition_iter = NULL;
}
STORAGE_LOG(INFO, "gc_check_schema_ cost time", K(ret), K(seq_), "time", ObTimeUtility::current_time() - begin_time);
return ret;
}
int ObGarbageCollector::gc_check_schema_(storage::ObIPartitionGroup* pg,
share::schema::ObSchemaGetterGuard& schema_guard, TenantSet& gc_tenant_set, NeedGCReason& gc_reason)
{
int ret = OB_SUCCESS;
const common::ObPGKey& pg_key = pg->get_partition_key();
const uint64_t tenant_id = pg_key.get_tenant_id();
const uint64_t tenant_id_for_get_schema =
is_inner_table(pg_key.get_table_id()) ? OB_SYS_TENANT_ID : pg_key.get_tenant_id();
int64_t local_schema_version = OB_INVALID_VERSION;
int64_t pg_create_schema_version = OB_INVALID_VERSION;
bool tenant_has_been_dropped = false;
bool tenant_created_success = true;
if (OB_FAIL(schema_guard.check_if_tenant_has_been_dropped(tenant_id, tenant_has_been_dropped))) {
STORAGE_LOG(WARN, "fail to check if tenant has been dropped", K(ret), K(tenant_id));
} else if (tenant_has_been_dropped) {
if (OB_FAIL(gc_tenant_set.set_refactored(tenant_id, 1 /*overwrite*/))) {
STORAGE_LOG(WARN, "gc_tenant_set set failed", K(ret), K(tenant_id));
} else {
gc_reason = TENANT_SCHEMA_DROP;
SERVER_EVENT_ADD("gc", "gc_candidates", "partition_group", pg_key, "reason", "tenant schema drop");
}
} else if (OB_FAIL(pg->get_pg_storage().get_create_schema_version(pg_create_schema_version))) {
if (OB_EAGAIN != ret) {
STORAGE_LOG(WARN, "fail to get create schema version for pg", K(ret), K(pg_key));
} else {
ret = OB_SUCCESS;
}
} else if (OB_FAIL(schema_guard.get_schema_version(tenant_id_for_get_schema, local_schema_version))) {
STORAGE_LOG(WARN, "fail to get schema version", K(ret), K(pg_key), K(tenant_id_for_get_schema));
} else if (pg_create_schema_version > local_schema_version ||
!share::schema::ObSchemaService::is_formal_version(local_schema_version)) {
STORAGE_LOG(INFO,
"new partition group, schema is not flushed, skip it",
K(pg_key),
K(tenant_id_for_get_schema),
K(local_schema_version),
K(pg_create_schema_version));
} else if (OB_FAIL(schema_guard.check_tenant_exist(tenant_id, tenant_created_success))) {
STORAGE_LOG(WARN, "failed to check tenant exist", K(ret), K(pg_key), K(tenant_id));
} else if (!tenant_created_success) {
gc_reason = TENANT_FAIL_TO_CREATE;
SERVER_EVENT_ADD("gc",
"gc_candidates",
"partition_group",
pg_key,
"reason",
"tenant is failed to create",
"local_schema_version",
local_schema_version);
} else if (OB_FAIL(gc_check_pg_schema_(pg, schema_guard, gc_reason))) {
STORAGE_LOG(WARN, "gc_check_pg_schema_ failed", K(ret), K(pg_key));
} else if (pg->is_pg()) {
ObPartitionArray pkey_array;
if (OB_FAIL(pg->get_all_pg_partition_keys(pkey_array))) {
STORAGE_LOG(WARN, "get all pg partition keys failed", K(ret), K(pg_key));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < pkey_array.count(); ++i) {
const ObPartitionKey& partition_key = pkey_array.at(i);
if (OB_FAIL(gc_check_partition_schema_(pg, schema_guard, partition_key))) {
STORAGE_LOG(WARN, "gc_check_partition_schema_ failed", K(ret), K(pg_key), K(partition_key));
}
}
}
}
return ret;
}
int ObGarbageCollector::gc_check_pg_schema_(
storage::ObIPartitionGroup* pg, share::schema::ObSchemaGetterGuard& schema_guard, NeedGCReason& gc_reason)
{
int ret = OB_SUCCESS;
bool can_remove = false;
bool is_physical_removed = false;
const common::ObPGKey& pg_key = pg->get_partition_key();
if (OB_FAIL(schema_guard.check_partition_can_remove(pg_key.get_table_id(),
pg_key.get_partition_id(),
false, /* delay dropped schema is not visble */
can_remove))) {
STORAGE_LOG(WARN, "check_partition_can_remove failed", K(ret), K(pg_key));
} else if (!can_remove) {
STORAGE_LOG(TRACE, "pg can not gc, skip it", K(ret), K(pg_key));
} else if (OB_FAIL(schema_guard.check_partition_can_remove(pg_key.get_table_id(),
pg_key.get_partition_id(),
true, /* delay dropped schema is visble */
is_physical_removed))) {
STORAGE_LOG(WARN, "check_partition_can_remove failed", K(ret), K(pg_key));
} else if (OB_FAIL(handle_schema_drop_pg_(pg, is_physical_removed, gc_reason))) {
STORAGE_LOG(WARN, "handle_schema_drop_pg_ failed", K(ret), K(pg_key));
} else if (NO_NEED_TO_GC != gc_reason) {
STORAGE_LOG(INFO, "this pg need to gc", K(pg_key), K(gc_reason));
}
return ret;
}
int ObGarbageCollector::handle_schema_drop_pg_(
storage::ObIPartitionGroup* pg, const bool is_physical_removed, NeedGCReason& gc_reason)
{
int ret = OB_SUCCESS;
ObRole role;
const common::ObPGKey& pg_key = pg->get_partition_key();
if (OB_FAIL(pg->get_role(role))) {
STORAGE_LOG(WARN, "fail to get_role", K(ret), K(pg_key));
} else if (is_strong_leader(role)) {
if (OB_FAIL(leader_handle_schema_drop_pg_(pg, is_physical_removed, gc_reason))) {
STORAGE_LOG(WARN, "leader_handle_schema_drop_pg_ failed", K(ret), K(pg_key), K(is_physical_removed));
}
} else if (!is_physical_removed) {
STORAGE_LOG(TRACE, "follower should gc after schema is physical removed", K(ret), K(pg_key));
} else if (OB_FAIL(follower_handle_schema_drop_pg_(pg, gc_reason))) {
STORAGE_LOG(WARN, "follower_handle_schema_drop_pg_ failed", K(ret), K(pg_key));
}
return ret;
}
int ObGarbageCollector::leader_handle_schema_drop_pg_(
storage::ObIPartitionGroup* pg, const bool is_physical_removed, NeedGCReason& gc_reason)
{
int ret = OB_SUCCESS;
int64_t max_decided_trans_version = OB_INVALID_TIMESTAMP;
bool is_all_trans_clear = false;
const int64_t MAX_DECIDED_RESERVED_TIME = 20 * 1000 * 1000;
int64_t gc_schema_drop_delay = GC_SCHEMA_DROP_DELAY;
if (!GCONF.enable_one_phase_commit) {
gc_schema_drop_delay = MAX_DECIDED_RESERVED_TIME;
}
#ifdef ERRSIM
gc_schema_drop_delay = ObServerConfig::get_instance().schema_drop_gc_delay_time;
#endif
const common::ObPGKey& pg_key = pg->get_partition_key();
if (OB_FAIL(partition_service_->get_global_max_decided_trans_version(max_decided_trans_version))) {
STORAGE_LOG(ERROR, "get_global_max_decided_trans_version failed", K(ret));
} else if (!pg->check_pg_partition_offline(pg_key)) {
if (OB_FAIL(trans_service_->block_partition(pg_key, is_all_trans_clear))) {
if (OB_PARTITION_NOT_EXIST != ret && OB_ENTRY_NOT_EXIST != ret) {
STORAGE_LOG(WARN, "block_partition failed", K(ret), K(pg_key));
}
}
if ((OB_SUCCESS == ret && is_all_trans_clear) || OB_PARTITION_NOT_EXIST == ret || OB_ENTRY_NOT_EXIST == ret) {
if (OB_FAIL(pg->offline_itself(is_physical_removed))) {
STORAGE_LOG(WARN, "offline itself failed", K(ret), K(pg_key));
}
} else if (REACH_TIME_INTERVAL(60 * 1000 * 1000)) {
STORAGE_LOG(
WARN, "trans_service_ block_partition failed, please attention", K(ret), K(pg_key), K(is_all_trans_clear));
}
} else if (ObTimeUtility::current_time() - pg->get_gc_schema_drop_ts() <= gc_schema_drop_delay &&
pg->get_gc_schema_drop_ts() + MAX_DECIDED_RESERVED_TIME > max_decided_trans_version) {
if (REACH_TIME_INTERVAL(60 * 1000 * 1000)) {
STORAGE_LOG(INFO,
"leader schema drop pg, wait to gc",
K(pg_key),
"gc_schema_drop_ts",
pg->get_gc_schema_drop_ts(),
K(max_decided_trans_version));
}
} else if (OB_FAIL(gc_check_log_archive_(pg, is_physical_removed, gc_reason))) {
STORAGE_LOG(WARN, "gc_check_log_archive_ failed", K(ret), K(pg_key), K(is_physical_removed));
} else {
// do nothing
}
return ret;
}
int ObGarbageCollector::follower_handle_schema_drop_pg_(storage::ObIPartitionGroup* pg, NeedGCReason& gc_reason)
{
int ret = OB_SUCCESS;
bool exist = true;
const common::ObPGKey& pg_key = pg->get_partition_key();
if (OB_FAIL(GC_PARTITION_ADAPTER.check_partition_exist(pg_key, exist))) {
STORAGE_LOG(WARN, "check_partition_exist failed", K(ret), K(pg_key));
} else if (!exist) {
gc_reason = FOLLOWER_SCHEMA_DROP;
SERVER_EVENT_ADD("gc", "gc_candidates", "partition_group", pg_key, "reason", "follower pg schema drop");
}
STORAGE_LOG(INFO, "follower_handle_schema_drop_pg_", K(ret), K(pg_key), K(gc_reason));
return ret;
}
int ObGarbageCollector::gc_check_log_archive_(
storage::ObIPartitionGroup* pg, const bool is_physical_removed, NeedGCReason& gc_reason)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
const common::ObPGKey& pg_key = pg->get_partition_key();
const bool enable_log_archive = ObServerConfig::get_instance().enable_log_archive;
const bool is_mandatory = ObServerConfig::get_instance().backup_log_archive_option.is_mandatory();
const bool is_restore = pg->get_pg_storage().is_restore();
const bool is_sys_tenant = (OB_SYS_TENANT_ID == pg_key.get_tenant_id());
ObLogArchiveBackupInfo backup_info;
bool has_archived = false;
bool need_gc = false;
int64_t delay_interval = LOG_ARCHIVE_DROP_DELAY;
#ifdef ERRSIM
// delay_interval = std::min(LOG_ARCHIVE_DROP_DELAY, (int64_t)ObServerConfig::get_instance().schema_drop_gc_delay_time);
#endif
if (enable_log_archive && !is_restore && !is_sys_tenant) {
if (OB_SUCCESS != (tmp_ret = ObBackupInfoMgr::get_instance().get_log_archive_backup_info(backup_info))) {
if (REACH_TIME_INTERVAL(10 * 1000 * 1000)) {
STORAGE_LOG(INFO,
"leader schema drop pg, wait to gc because of get_log_archive_backup_info failed",
K(tmp_ret),
K(pg_key));
}
} else if (ObLogArchiveStatus::STATUS::BEGINNING != backup_info.status_.status_ &&
ObLogArchiveStatus::STATUS::DOING != backup_info.status_.status_) {
need_gc = true;
} else if (OB_SUCCESS ==
(tmp_ret = pg->check_offline_log_archived(
pg_key, backup_info.status_.incarnation_, backup_info.status_.round_, has_archived)) &&
has_archived) {
need_gc = true;
} else if (is_mandatory) {
STORAGE_LOG(INFO,
"leader schema drop pg, wait to gc because offline log has not been archived in mandatory mode",
K(pg_key));
} else if (GCONF.gc_wait_archive) {
// In optional mode, GC wait util archive offline log successfully if parameter gc_wait_archive is true
STORAGE_LOG(INFO, "leader schema drop pg, wait to gc because gc_wait_archive is true", K(pg_key));
} else if (ObTimeUtility::current_time() - pg->get_gc_schema_drop_ts() <= delay_interval) {
STORAGE_LOG(INFO,
"leader schema drop pg, wait to gc because offline log has not been archived in optional mode",
K(pg_key),
K(delay_interval),
"gc_schema_drop_ts",
pg->get_gc_schema_drop_ts());
} else if (OB_SUCCESS != (tmp_ret = partition_service_->mark_log_archive_encount_fatal_error(
pg_key, backup_info.status_.incarnation_, backup_info.status_.round_))) {
STORAGE_LOG(INFO,
"leader schema drop pg, wait to mark_log_archive_interrupted in optional mode",
K(tmp_ret),
K(pg_key),
K(backup_info));
} else {
STORAGE_LOG(ERROR,
"LOG_ARCHIVE: pg is forced to gc when offline log has not been archived in optional mode",
K(pg_key),
K(backup_info));
}
} else {
need_gc = true;
}
if (need_gc && is_physical_removed) {
gc_reason = LEADER_PHYSICAL_SCHEMA_DROP;
SERVER_EVENT_ADD("gc", "gc_candidates", "partition_group", pg_key, "reason", "leader physical schema drop");
} else if (need_gc) {
gc_reason = LEADER_PENDDING_SCHEMA_DROP;
SERVER_EVENT_ADD("gc", "gc_candidates", "partition_group", pg_key, "reason", "leader pendding schema drop");
}
return ret;
}
int ObGarbageCollector::gc_check_partition_schema_(storage::ObIPartitionGroup* pg,
share::schema::ObSchemaGetterGuard& schema_guard, const common::ObPartitionKey& partition_key)
{
int ret = OB_SUCCESS;
const uint64_t tenant_id_for_get_schema =
is_inner_table(partition_key.get_table_id()) ? OB_SYS_TENANT_ID : partition_key.get_tenant_id();
int64_t local_schema_version = OB_INVALID_VERSION;
int64_t partition_create_schema_version = OB_INVALID_VERSION;
const common::ObPGKey& pg_key = pg->get_partition_key();
bool can_remove = false;
bool is_physical_removed = false;
if (OB_FAIL(pg->get_pg_storage().get_create_schema_version(partition_key, partition_create_schema_version))) {
if (OB_EAGAIN != ret) {
STORAGE_LOG(WARN, "fail to get create schema version for partition", K(ret), K(partition_key));
} else {
ret = OB_SUCCESS;
}
} else if (OB_FAIL(schema_guard.get_schema_version(tenant_id_for_get_schema, local_schema_version))) {
STORAGE_LOG(WARN, "fail to get schema version", K(ret), K(pg_key), K(partition_key), K(tenant_id_for_get_schema));
} else if (partition_create_schema_version > local_schema_version ||
!share::schema::ObSchemaService::is_formal_version(local_schema_version)) {
STORAGE_LOG(INFO,
"new partition, schema is not flushed, skip it",
K(pg_key),
K(partition_key),
K(tenant_id_for_get_schema),
K(local_schema_version),
K(partition_create_schema_version));
} else if (OB_FAIL(schema_guard.check_partition_can_remove(partition_key.get_table_id(),
partition_key.get_partition_id(),
false, /* delay dropped schema is not visble */
can_remove))) {
STORAGE_LOG(WARN, "check_partition_can_remove failed", K(ret), K(pg_key), K(partition_key));
} else if (!can_remove) {
STORAGE_LOG(TRACE, "partition can not gc, skip it", K(ret), K(pg_key), K(partition_key));
} else if (OB_FAIL(schema_guard.check_partition_can_remove(partition_key.get_table_id(),
partition_key.get_partition_id(),
true, /* delay dropped schema is visble */
is_physical_removed))) {
STORAGE_LOG(WARN, "check_partition_can_remove failed", K(ret), K(pg_key), K(partition_key));
} else if (is_physical_removed && OB_FAIL(handle_schema_drop_partition_(pg, partition_key))) {
STORAGE_LOG(WARN, "handle_schema_drop_partition_ failed", K(ret), K(pg_key), K(partition_key));
} else {
// do nothing
}
return ret;
}
int ObGarbageCollector::handle_schema_drop_partition_(
storage::ObIPartitionGroup* pg, const common::ObPartitionKey& partition_key)
{
int ret = OB_SUCCESS;
ObRole role;
const common::ObPGKey& pg_key = pg->get_partition_key();
if (OB_FAIL(pg->get_role(role))) {
STORAGE_LOG(WARN, "fail to get role", K(ret), K(pg_key), K(partition_key));
} else if (is_strong_leader(role)) {
if (OB_FAIL(leader_handle_schema_drop_partition_(pg, partition_key))) {
STORAGE_LOG(WARN, "leader_handle_schema_drop_partition_ failed", K(ret), K(pg_key), K(partition_key));
}
} else if (OB_FAIL(follower_handle_schema_drop_partition_(pg, partition_key))) {
STORAGE_LOG(WARN, "follower_handle_schema_drop_partition_ failed", K(ret), K(pg_key), K(partition_key));
}
return ret;
}
int ObGarbageCollector::leader_handle_schema_drop_partition_(
storage::ObIPartitionGroup* pg, const common::ObPartitionKey& partition_key)
{
int ret = OB_SUCCESS;
int64_t gc_start_ts = 0;
ObPGPartitionGuard pg_partition_guard;
const common::ObPGKey& pg_key = pg->get_partition_key();
bool is_all_trans_clear = false;
const uint64_t UNUSED = 100;
const bool for_replay = false;
if (OB_FAIL(pg->get_pg_partition(partition_key, pg_partition_guard))) {
STORAGE_LOG(WARN, "get pg partition failed", K(ret), K(pg_key), K(partition_key));
} else if (OB_ISNULL(pg_partition_guard.get_pg_partition())) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "pg partition is null", K(ret), K(pg_key), K(partition_key));
} else if (OB_FAIL(pg_partition_guard.get_pg_partition()->set_gc_starting())) {
STORAGE_LOG(WARN, "pg partition set_gc_starting failed", K(ret), K(pg_key), K(partition_key));
} else if (OB_FAIL(pg_partition_guard.get_pg_partition()->get_gc_start_ts(gc_start_ts))) {
STORAGE_LOG(WARN, "get gc start ts failed", K(ret), K(pg_key), K(partition_key));
} else if (gc_start_ts <= 0) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(ERROR, "unexpected gc start ts", K(ret), K(pg_key), K(partition_key), K(gc_start_ts));
} else if (OB_FAIL(trans_service_->check_ctx_create_timestamp_elapsed(pg_key, gc_start_ts))) {
if (OB_PARTITION_NOT_EXIST != ret && OB_ENTRY_NOT_EXIST != ret) {
STORAGE_LOG(WARN, "check_ctx_create_timestamp_elapsed failed", K(ret), K(pg_key), K(partition_key));
}
} else {
is_all_trans_clear = true;
}
if ((OB_SUCCESS == ret && is_all_trans_clear) || OB_PARTITION_NOT_EXIST == ret || OB_ENTRY_NOT_EXIST == ret) {
if (OB_FAIL(partition_service_->remove_partition_from_pg(for_replay, pg_key, partition_key, UNUSED))) {
STORAGE_LOG(WARN, "follower remove_partition_from_pg failed", K(ret), K(pg_key), K(partition_key));
} else {
SERVER_EVENT_ADD("gc", "clearup_partition", "partition", partition_key, "reason", "partition leader schema drop");
}
}
return ret;
}
int ObGarbageCollector::follower_handle_schema_drop_partition_(
storage::ObIPartitionGroup* pg, const common::ObPartitionKey& partition_key)
{
int ret = OB_SUCCESS;
const uint64_t UNUSED = 100;
const bool for_replay = true;
const common::ObPGKey& pg_key = pg->get_partition_key();
if (OB_FAIL(partition_service_->remove_partition_from_pg(for_replay, pg_key, partition_key, UNUSED))) {
STORAGE_LOG(WARN, "follower remove_partition_from_pg failed", K(ret), K(pg_key), K(partition_key));
} else {
SERVER_EVENT_ADD("gc", "clearup_partition", "partition", partition_key, "reason", "partition follower schema drop");
}
return ret;
}
} // namespace storage
} // namespace oceanbase