Files
oceanbase/src/archive/ob_start_archive_helper.cpp
oceanbase-admin cea7de1475 init push
2021-05-31 22:56:52 +08:00

925 lines
35 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_start_archive_helper.h"
#include "share/backup/ob_backup_info_mgr.h" // ObBackupInfo
#include "ob_archive_io.h" // ObArchiveIO
#include "ob_archive_log_wrapper.h" // ObArchiveLogWrapper
#include "ob_archive_destination_mgr.h" // ObArchiveDestination
#include "ob_archive_path.h" // ObArchivePathUtil
#include "ob_archive_entry_iterator.h" // ObArchiveEntryIterator
#include "ob_archive_log_file_store.h" // ObArchiveLogFileStore
#include "observer/ob_server_struct.h" // GCTX
#include "ob_archive_mgr.h"
#include "storage/ob_saved_storage_info_v2.h"
#include "ob_archive_file_utils.h"
namespace oceanbase {
namespace archive {
using namespace oceanbase::common;
using namespace oceanbase::clog;
using namespace oceanbase::share;
void ObMaxArchivedLogInfo::reset()
{
max_log_id_archived_ = 0;
max_checkpoint_ts_archived_ = OB_INVALID_TIMESTAMP;
max_log_submit_ts_archived_ = OB_INVALID_TIMESTAMP;
clog_epoch_id_ = OB_INVALID_TIMESTAMP;
accum_checksum_ = 0;
}
StartArchiveHelper::StartArchiveHelper(const ObPGKey& pg_key, const int64_t timestamp, const int64_t incarnation,
const int64_t archive_round, const int64_t epoch, const int64_t takeover_ts, const bool compatible,
const int64_t start_archive_ts, ObString& uri, ObString& storage_info, ObArchiveLogWrapper& log_wrapper,
ObArchiveMgr& archive_mgr)
: success_(false),
pg_key_(pg_key),
need_kickoff_log_(false),
is_mandatory_(false),
incarnation_(incarnation),
archive_round_(archive_round),
epoch_(epoch),
takeover_ts_(takeover_ts),
create_timestamp_(timestamp),
round_start_info_(),
start_log_id_(OB_INVALID_ID),
start_ilog_file_id_(OB_INVALID_FILE_ID),
max_archived_log_info_(),
min_index_file_id_(0),
max_index_file_id_(0),
index_file_exist_(false),
index_record_exist_(false),
max_archived_index_info_(),
min_data_file_id_(0),
max_data_file_id_(0),
data_file_exist_unrecorded_(false),
unrecorded_data_file_valid_(false),
min_log_id_unrecorded_(0),
min_log_ts_unrecorded_(-1),
max_log_id_unrecorded_(0),
max_checkpoint_ts_unrecorded_(OB_INVALID_TIMESTAMP),
max_log_submit_ts_unrecorded_(-1),
next_data_file_id_(0),
next_index_file_id_(0),
exist_log_(false),
compatible_(compatible),
server_start_ts_(start_archive_ts),
tenant_archive_checkpoint_ts_(OB_INVALID_TIMESTAMP),
archive_status_(share::ObLogArchiveStatus::STATUS::INVALID),
rs_start_ts_(OB_INVALID_TIMESTAMP),
uri_(uri),
storage_info_(storage_info),
log_wrapper_(log_wrapper),
archive_mgr_(archive_mgr)
{}
StartArchiveHelper::~StartArchiveHelper()
{}
bool StartArchiveHelper::is_valid()
{
bool bret = true;
if (OB_UNLIKELY(!success_) || OB_UNLIKELY(OB_INVALID_ID == start_log_id_) || OB_UNLIKELY(0 == start_ilog_file_id_) ||
OB_UNLIKELY(0 == next_index_file_id_) || OB_UNLIKELY(0 == next_data_file_id_) ||
OB_UNLIKELY(!round_start_info_.is_valid())) {
bret = false;
ARCHIVE_LOG(ERROR, "StartArchiveHelper is invalid", KPC(this));
}
return bret;
}
int StartArchiveHelper::handle()
{
int ret = OB_SUCCESS;
const int64_t start_ts = ObTimeUtility::current_time();
if (OB_UNLIKELY(!pg_key_.is_valid())) {
ARCHIVE_LOG(WARN, "invalid pg_key", K(pg_key_));
ret = OB_ERR_UNEXPECTED;
} else if (OB_FAIL(handle_pg_start_archive_())) {
ARCHIVE_LOG(WARN, "handle_pg_start_archive_ fail", KPC(this));
} else {
const int64_t cost_ts = ObTimeUtility::current_time() - start_ts;
ARCHIVE_LOG(INFO,
"handle_pg_start_archive_ succ",
K(cost_ts),
KPC(this),
K(need_kickoff_log_),
K(next_data_file_id_),
K(next_index_file_id_),
K(unrecorded_data_file_valid_),
K(success_),
K(is_mandatory_),
K(incarnation_),
K(archive_round_),
K(epoch_),
K(server_start_ts_),
K(archive_status_),
K(rs_start_ts_),
K(uri_));
}
return ret;
}
// start archive progress with reading archive files:
//
// 1. query max archived index file
// 2. get max archived index info
// 3. calculate max archived data file
// 4. read max arhived data file, get max archived log info
// 5. locate start ilog file id
// 6. decide need write kickoff log or not
// 7. make pg archive directory
int StartArchiveHelper::handle_pg_start_archive_()
{
int ret = OB_SUCCESS;
if (OB_FAIL(query_max_file_remote_())) {
ARCHIVE_LOG(WARN, "query_max_file_remote_ fail", KR(ret), KPC(this));
} else if (OB_FAIL(decide_pg_next_start_file_id_())) {
ARCHIVE_LOG(WARN, "decide_pg_next_start_file_id_ fail", KR(ret), KPC(this));
} else if (OB_FAIL(decide_pg_start_archive_log_id_())) {
ARCHIVE_LOG(WARN, "decide_pg_start_archive_log_id_ fail", KR(ret), KPC(this));
} else if (OB_FAIL(locate_pg_start_ilog_id_())) {
ARCHIVE_LOG(WARN, "locate_pg_start_ilog_id_ fail", KR(ret), K(pg_key_));
} else if (OB_FAIL(decide_need_archive_first_record_())) {
ARCHIVE_LOG(WARN, "decide_need_archive_first_record_ fail", KR(ret), KPC(this));
} else if (OB_FAIL(check_and_make_pg_archive_directory_())) {
ARCHIVE_LOG(WARN, "check_and_make_pg_archive_directory_ fail", KR(ret), KPC(this));
} else {
success_ = true;
}
return ret;
}
int StartArchiveHelper::decide_pg_start_archive_log_id_locally_()
{
int ret = OB_SUCCESS;
if (is_archive_status_doing_()) {
if (OB_FAIL(decide_start_log_id_on_doing_())) {
ARCHIVE_LOG(WARN, "decide_start_log_id_on_doing_ fail", KR(ret), KPC(this));
}
} else if (is_archive_status_beginning_()) {
if (OB_FAIL(decide_start_log_id_on_beginning_())) {
ARCHIVE_LOG(WARN, "decide_start_log_id_on_beginning_ fail", KR(ret), KPC(this));
}
} else {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR, "invalid archive status", KR(ret), KPC(this));
}
return ret;
}
int StartArchiveHelper::get_cluster_archive_status_()
{
int ret = OB_SUCCESS;
ObLogArchiveBackupInfo info;
if (OB_FAIL(ObBackupInfoMgr::get_instance().get_log_archive_backup_info(info))) {
ARCHIVE_LOG(WARN, "get_log_archive_backup_info fail", KR(ret), KPC(this));
} else if (OB_UNLIKELY(!info.is_valid())) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR, "ObLogArchiveBackupInfo is not valid", KR(ret), K(info));
} else if (share::ObLogArchiveStatus::STATUS::BEGINNING != info.status_.status_ &&
share::ObLogArchiveStatus::STATUS::DOING != info.status_.status_) {
ret = OB_EAGAIN;
ARCHIVE_LOG(WARN, "invalid archive status", KR(ret), K(info));
} else {
archive_status_ = info.status_.status_;
rs_start_ts_ = info.status_.start_ts_;
}
return ret;
}
int StartArchiveHelper::get_tenant_archive_status_()
{
int ret = OB_SUCCESS;
ObLogArchiveInfoMgr::ObLogArchiveSimpleInfo info;
// get archive progress with pg_key, takeover_ts_
if (OB_FAIL(
ObLogArchiveInfoMgr::get_instance().get_log_archive_status(pg_key_.get_tenant_id(), takeover_ts_, info)) &&
OB_ENTRY_NOT_EXIST != ret) {
ARCHIVE_LOG(WARN, "get_log_archive_status fail", KR(ret));
} else if (OB_ENTRY_NOT_EXIST == ret) {
ARCHIVE_LOG(WARN, "tenant log archive info not exist yet", KR(ret), KPC(this));
ret = OB_SUCCESS;
tenant_archive_checkpoint_ts_ = 0;
} else if (OB_UNLIKELY(!info.is_valid())) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR, "ObLogArchiveSimpleInfo is not valid", KR(ret), K(info));
} else if (share::ObLogArchiveStatus::STATUS::BEGINNING != info.status_ &&
share::ObLogArchiveStatus::STATUS::DOING != info.status_) {
ret = OB_EAGAIN;
ARCHIVE_LOG(WARN, "no doing archive status, retry later", KR(ret), K(info));
} else {
tenant_archive_checkpoint_ts_ = info.checkpoint_ts_;
}
return ret;
}
bool StartArchiveHelper::is_archive_status_beginning_()
{
return share::ObLogArchiveStatus::STATUS::BEGINNING == archive_status_;
}
bool StartArchiveHelper::is_archive_status_doing_()
{
return share::ObLogArchiveStatus::STATUS::DOING == archive_status_;
}
int StartArchiveHelper::decide_start_log_id_on_beginning_()
{
int ret = OB_SUCCESS;
bool is_from_restore = false;
if (OB_FAIL(log_wrapper_.check_is_from_restore(pg_key_, is_from_restore))) {
ARCHIVE_LOG(WARN, "failed to check_is_from_restore", KR(ret), K(pg_key_));
} else if (server_start_ts_ <= create_timestamp_ && (!is_from_restore)) {
// fake a safe progress for pg whose start log id is 0
int64_t first_log_submit_ts = OB_INVALID_TIMESTAMP;
if (OB_FAIL(log_wrapper_.get_pg_first_log_submit_ts(pg_key_, first_log_submit_ts))) {
ARCHIVE_LOG(ERROR, "get_pg_first_log_submit_ts fail", KR(ret), K(pg_key_));
archive_mgr_.mark_encounter_fatal_err(pg_key_, incarnation_, archive_round_);
} else {
max_archived_log_info_.max_log_id_archived_ = 0;
start_log_id_ = max_archived_log_info_.max_log_id_archived_ + 1;
// set round_start_log_ts 1, to avoid push up the global start_ts in doing
round_start_info_.start_ts_ = 1;
round_start_info_.start_log_id_ = start_log_id_;
round_start_info_.log_submit_ts_ = first_log_submit_ts - 1;
round_start_info_.snapshot_version_ = 0;
round_start_info_.clog_epoch_id_ = 1;
round_start_info_.accum_checksum_ = 0;
max_archived_log_info_.max_checkpoint_ts_archived_ = first_log_submit_ts - 1;
max_archived_log_info_.max_log_submit_ts_archived_ = first_log_submit_ts - 1;
max_archived_log_info_.clog_epoch_id_ = 1; // fake_clog_epoch_id
max_archived_log_info_.accum_checksum_ = 0;
}
} else {
ObSavedStorageInfoV2 info;
if (OB_FAIL(log_wrapper_.get_all_saved_info(pg_key_, info))) {
ARCHIVE_LOG(WARN, "failed to get_saved_clog_info", KR(ret), K(pg_key_));
} else {
const ObBaseStorageInfo& clog_info = info.get_clog_info();
if (OB_UNLIKELY(OB_INVALID_ID == clog_info.get_last_replay_log_id() ||
OB_INVALID_TIMESTAMP == clog_info.get_submit_timestamp() || 0 > clog_info.get_epoch_id())) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(WARN, "invalid info", KR(ret), K(pg_key_), K(info));
} else {
max_archived_log_info_.max_log_id_archived_ = clog_info.get_last_replay_log_id();
start_log_id_ = max_archived_log_info_.max_log_id_archived_ + 1;
round_start_info_.start_ts_ = clog_info.get_submit_timestamp();
round_start_info_.start_log_id_ = start_log_id_;
round_start_info_.log_submit_ts_ = clog_info.get_submit_timestamp();
round_start_info_.snapshot_version_ = info.get_data_info().get_publish_version();
round_start_info_.clog_epoch_id_ = clog_info.get_epoch_id();
round_start_info_.accum_checksum_ = clog_info.get_accumulate_checksum();
max_archived_log_info_.max_checkpoint_ts_archived_ = 0;
max_archived_log_info_.max_log_submit_ts_archived_ = clog_info.get_submit_timestamp();
max_archived_log_info_.clog_epoch_id_ = clog_info.get_epoch_id();
max_archived_log_info_.accum_checksum_ = clog_info.get_accumulate_checksum();
}
}
}
return ret;
}
int StartArchiveHelper::decide_start_log_id_on_doing_()
{
int ret = OB_SUCCESS;
bool is_from_restore = false;
if (OB_FAIL(log_wrapper_.check_is_from_restore(pg_key_, is_from_restore))) {
ARCHIVE_LOG(WARN, "failed to check_is_from_restore", KR(ret), K(pg_key_));
} else if (server_start_ts_ < create_timestamp_ && (!is_from_restore)) {
// fake a safe progress for pg whose start log id is 0
int64_t first_log_submit_ts = OB_INVALID_TIMESTAMP;
if (OB_FAIL(log_wrapper_.get_pg_first_log_submit_ts(pg_key_, first_log_submit_ts))) {
ARCHIVE_LOG(ERROR, "get_pg_first_log_submit_ts fail", KR(ret), K(pg_key_));
archive_mgr_.mark_encounter_fatal_err(pg_key_, incarnation_, archive_round_);
} else {
max_archived_log_info_.max_log_id_archived_ = 0;
start_log_id_ = max_archived_log_info_.max_log_id_archived_ + 1;
// set round_start_log_ts 1, to avoid push up the global start_ts in doing
round_start_info_.start_ts_ = 1;
round_start_info_.start_log_id_ = start_log_id_;
round_start_info_.log_submit_ts_ = first_log_submit_ts - 1;
round_start_info_.snapshot_version_ = 0;
round_start_info_.clog_epoch_id_ = 1;
round_start_info_.accum_checksum_ = 0;
max_archived_log_info_.max_checkpoint_ts_archived_ = first_log_submit_ts - 1;
max_archived_log_info_.max_log_submit_ts_archived_ = first_log_submit_ts - 1;
max_archived_log_info_.clog_epoch_id_ = 1; // fake_clog_epoch_id
max_archived_log_info_.accum_checksum_ = 0;
}
} else {
// restore tenant come into this case
ObSavedStorageInfoV2 info;
if (OB_FAIL(log_wrapper_.get_all_saved_info(pg_key_, info))) {
ARCHIVE_LOG(WARN, "failed to get_save_clog_info", KR(ret), K(pg_key_));
} else {
const ObBaseStorageInfo& clog_info = info.get_clog_info();
max_archived_log_info_.max_log_id_archived_ = clog_info.get_last_replay_log_id();
start_log_id_ = max_archived_log_info_.max_log_id_archived_ + 1;
round_start_info_.start_ts_ = clog_info.get_submit_timestamp();
round_start_info_.start_log_id_ = start_log_id_;
round_start_info_.log_submit_ts_ = clog_info.get_submit_timestamp();
round_start_info_.snapshot_version_ = info.get_data_info().get_publish_version();
round_start_info_.clog_epoch_id_ = clog_info.get_epoch_id();
round_start_info_.accum_checksum_ = clog_info.get_accumulate_checksum();
max_archived_log_info_.max_checkpoint_ts_archived_ = 0;
max_archived_log_info_.max_log_submit_ts_archived_ = clog_info.get_submit_timestamp();
max_archived_log_info_.clog_epoch_id_ = clog_info.get_epoch_id();
max_archived_log_info_.accum_checksum_ = clog_info.get_accumulate_checksum();
}
}
return ret;
}
int StartArchiveHelper::locate_pg_start_ilog_id_()
{
int ret = OB_SUCCESS;
file_id_t ilog_id = OB_INVALID_FILE_ID;
uint64_t max_log_id_in_ilog_file = OB_INVALID_ID;
bool ilog_file_exist = false;
if (OB_FAIL(log_wrapper_.locate_ilog_by_log_id(
pg_key_, start_log_id_, max_log_id_in_ilog_file, ilog_file_exist, ilog_id))) {
ARCHIVE_LOG(WARN, "locate_ilog_by_log_id fail", KR(ret));
} else {
start_ilog_file_id_ = ilog_id;
}
return ret;
}
int StartArchiveHelper::check_and_make_pg_archive_directory_()
{
int ret = OB_SUCCESS;
ObArchiveIO archive_io(storage_info_);
char index_file_prefix_path[MAX_FILE_PATH];
char data_file_prefix_path[MAX_FILE_PATH];
ObArchivePathUtil util;
if (uri_.prefix_match(OB_OSS_PREFIX)) {
// skip it
} else if (OB_FAIL(util.build_archive_file_prefix(pg_key_,
LOG_ARCHIVE_FILE_TYPE_INDEX,
incarnation_,
archive_round_,
MAX_FILE_PATH,
index_file_prefix_path))) {
ARCHIVE_LOG(WARN, "build_archive_file_prefix fail", KR(ret), K(pg_key_));
} else if (OB_FAIL(util.build_archive_file_prefix(pg_key_,
LOG_ARCHIVE_FILE_TYPE_DATA,
incarnation_,
archive_round_,
MAX_FILE_PATH,
data_file_prefix_path))) {
ARCHIVE_LOG(WARN, "build_archive_file_prefix fail", KR(ret), K(pg_key_));
} else {
ObString index_uri(index_file_prefix_path);
ObString data_uri(data_file_prefix_path);
if (OB_FAIL(archive_io.check_and_make_dir(pg_key_, index_uri))) {
ARCHIVE_LOG(WARN, "failed to generate index_dir", KR(ret), K(pg_key_), K(index_uri));
} else if (OB_FAIL(archive_io.check_and_make_dir(pg_key_, data_uri))) {
ARCHIVE_LOG(WARN, "failed to generate data_dir", KR(ret), K(pg_key_), K(data_uri));
} else {
}
}
return ret;
}
int StartArchiveHelper::query_max_file_remote_()
{
int ret = OB_SUCCESS;
if (OB_FAIL(get_max_exist_index_file_id_())) {
ARCHIVE_LOG(WARN, "get_max_exist_index_file_id_ fail", K(ret), K(pg_key_));
} else if (OB_FAIL(get_max_archived_index_info_())) {
ARCHIVE_LOG(WARN, "get_max_archived_index_info_ fail", KR(ret), KPC(this));
} else if (OB_FAIL(get_max_exist_data_file_id_())) {
ARCHIVE_LOG(WARN, "get_max_exist_data_file_id_ fail", K(ret), K(pg_key_));
} else {
// succ
}
return ret;
}
// get max index file
int StartArchiveHelper::get_max_exist_index_file_id_()
{
int ret = OB_SUCCESS;
uint64_t min_index_file_id = 0;
uint64_t max_index_file_id = 0;
ObArchiveIO archive_io(storage_info_);
if (OB_FAIL(archive_io.get_index_file_range(
pg_key_, incarnation_, archive_round_, min_index_file_id, max_index_file_id))) {
if (OB_ENTRY_NOT_EXIST != ret) {
ARCHIVE_LOG(WARN, "get_index_file_range fail", KR(ret), K(pg_key_), K(uri_));
} else {
ARCHIVE_LOG(DEBUG, "no index file exist", K(pg_key_));
ret = OB_SUCCESS;
}
} else {
min_index_file_id_ = min_index_file_id;
max_index_file_id_ = max_index_file_id;
index_file_exist_ = true;
ARCHIVE_LOG(DEBUG,
"get_max_exist_index_file_id_ succ",
K(pg_key_),
K(min_index_file_id_),
K(max_index_file_id_),
K(index_file_exist_));
}
return ret;
}
// get max data file
int StartArchiveHelper::get_max_exist_data_file_id_()
{
int ret = OB_SUCCESS;
ObArchiveIO archive_io(storage_info_);
uint64_t base_data_file_id = 0;
if (index_record_exist_ && max_archived_index_info_.data_file_collect_) {
base_data_file_id = max_archived_index_info_.max_record_data_file_id_;
max_data_file_id_ = base_data_file_id;
if (OB_FAIL(check_if_exist_data_file_not_record_(base_data_file_id + 1))) {
ARCHIVE_LOG(WARN, "check_if_exist_data_file_not_record_ fail", KR(ret), K(base_data_file_id));
} else if (data_file_exist_unrecorded_ && OB_FAIL(reconfirm_unrecord_data_file_())) {
ARCHIVE_LOG(WARN, "reconfirm_unrecord_data_file_ fail", KR(ret), K(pg_key_));
}
} else if (OB_FAIL(list_and_check_data_file_with_no_index_file_())) {
ARCHIVE_LOG(WARN, "list_and_check_data_file_with_no_index_file_ fail", KR(ret), KPC(this));
}
return ret;
}
// get max index info from index files
int StartArchiveHelper::get_max_archived_index_info_()
{
int ret = OB_SUCCESS;
ObArchiveIO archive_io(storage_info_);
if (!index_file_exist_) {
// skip
} else if (OB_FAIL(archive_io.get_max_archived_index_info(pg_key_,
incarnation_,
archive_round_,
min_index_file_id_,
max_index_file_id_,
max_archived_index_info_))) {
ARCHIVE_LOG(WARN, "get_max_archived_index_info fail", KR(ret), KPC(this));
} else if (max_archived_index_info_.data_file_collect_ || max_archived_index_info_.archived_log_collect_) {
index_record_exist_ = true;
}
return ret;
}
int StartArchiveHelper::list_and_check_data_file_with_no_index_file_()
{
int ret = OB_SUCCESS;
uint64_t min_data_file_id = 0;
uint64_t max_data_file_id = 0;
ObArchiveIO archive_io(storage_info_);
if (OB_FAIL(
archive_io.get_data_file_range(pg_key_, incarnation_, archive_round_, min_data_file_id, max_data_file_id))) {
if (OB_ENTRY_NOT_EXIST != ret) {
ARCHIVE_LOG(WARN, "get_max_data_file_id fail", KR(ret), K(pg_key_));
} else {
ARCHIVE_LOG(DEBUG, "no data file exist", K(pg_key_));
ret = OB_SUCCESS;
}
} else if (min_data_file_id != max_data_file_id) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR,
"data file more than one, and no data file recorded in index file",
KR(ret),
K(min_data_file_id),
K(max_data_file_id),
KPC(this));
} else {
data_file_exist_unrecorded_ = true;
min_data_file_id_ = min_data_file_id;
max_data_file_id_ = max_data_file_id;
ARCHIVE_LOG(DEBUG,
"list_and_check_data_file_with_no_index_file_ succ",
K(min_data_file_id_),
K(max_data_file_id_),
K(pg_key_));
}
return ret;
}
// max_data_file_id_ + 1 not exist
int StartArchiveHelper::reconfirm_unrecord_data_file_()
{
int ret = OB_SUCCESS;
char data_file_path[MAX_FILE_PATH];
bool file_exist = false;
uint64_t file_id = max_data_file_id_ + 1;
ObArchiveIO archive_io(storage_info_);
ObArchivePathUtil util;
if (OB_FAIL(util.build_archive_file_path(
pg_key_, LOG_ARCHIVE_FILE_TYPE_DATA, file_id, incarnation_, archive_round_, MAX_FILE_PATH, data_file_path))) {
ARCHIVE_LOG(WARN, "build_archive_file_path fail", KR(ret), K(pg_key_));
} else if (OB_FAIL(archive_io.check_file_exist(pg_key_, data_file_path, file_exist))) {
ARCHIVE_LOG(WARN, "check_file_exist fail", KR(ret), KPC(this));
} else if (file_exist) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR, "exist too many data file not recorded", K(file_id), K(pg_key_));
}
return ret;
}
int StartArchiveHelper::check_if_exist_data_file_not_record_(const uint64_t file_id)
{
int ret = OB_SUCCESS;
char data_file_path[MAX_FILE_PATH];
bool file_exist = false;
ObArchiveIO archive_io(storage_info_);
ObArchivePathUtil util;
if (OB_FAIL(util.build_archive_file_path(
pg_key_, LOG_ARCHIVE_FILE_TYPE_DATA, file_id, incarnation_, archive_round_, MAX_FILE_PATH, data_file_path))) {
ARCHIVE_LOG(WARN, "build_archive_file_path fail", KR(ret), K(pg_key_));
} else if (OB_FAIL(archive_io.check_file_exist(pg_key_, data_file_path, file_exist))) {
ARCHIVE_LOG(WARN, "check_file_exist fail", KR(ret), K(file_id), KPC(this));
} else if (!file_exist) {
ARCHIVE_LOG(DEBUG, "NO data file exist not record in index file", K(file_id), K(data_file_path), K(pg_key_));
} else {
data_file_exist_unrecorded_ = true;
max_data_file_id_ = file_id;
ARCHIVE_LOG(DEBUG, "check_if_exist_data_file_not_record_ succ", K(pg_key_), K(max_data_file_id_));
}
return ret;
}
// 1. index/data file not exist
// 2. index not exist, data file exist
// 3. index/data both exist
int StartArchiveHelper::decide_pg_next_start_file_id_()
{
int ret = OB_SUCCESS;
next_index_file_id_ = max_index_file_id_ + 1;
next_data_file_id_ = max_data_file_id_ + 1;
return ret;
}
int StartArchiveHelper::decide_pg_start_archive_log_id_remote_()
{
int ret = OB_SUCCESS;
// get start log info and max recorded log info from index info
if (index_record_exist_ && max_archived_index_info_.archived_log_collect_) {
get_log_info_from_index_info_();
}
// get max log info from unrecorded data file
// if no index info exist, start archive info also included in the unrecorded data file
if (data_file_exist_unrecorded_) {
if (OB_FAIL(extract_archive_log_from_data_file_())) {
ARCHIVE_LOG(WARN, "extract_archive_log_from_data_file_ fail", KR(ret), KPC(this));
}
}
if (OB_SUCC(ret) && exist_log_) {
start_log_id_ = max_archived_log_info_.max_log_id_archived_ + 1;
}
return ret;
}
int StartArchiveHelper::extract_archive_log_from_data_file_()
{
int ret = OB_SUCCESS;
if (OB_SUCC(quick_extract_archive_log_from_data_file_())) {
ARCHIVE_LOG(INFO, "quick_extract_archive_log_from_data_file_ succ", KPC(this));
} else if (OB_SUCC(iterate_archive_log_from_data_file_())) {
ARCHIVE_LOG(INFO, "iterate_archive_log_from_data_file_ succ", KPC(this));
} else {
ARCHIVE_LOG(WARN, "extract_archive_log_from_data_file_ fail", KPC(this));
}
return ret;
}
int StartArchiveHelper::quick_extract_archive_log_from_data_file_()
{
int ret = OB_SUCCESS;
char path[MAX_FILE_PATH] = {0};
ObArchivePathUtil path_util;
ObArchiveBlockMeta block_meta;
clog::ObLogEntry log_entry;
ObLogArchiveInnerLog inner_log;
bool is_kickoff = false;
ObArchiveLogFileStore file_store;
const uint64_t tenant_id = pg_key_.get_tenant_id();
const char* cluster_name = GCTX.config_->cluster;
const int64_t cluster_id = GCTX.config_->cluster_id;
if (OB_UNLIKELY(!data_file_exist_unrecorded_ || 0 == max_data_file_id_)) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR, "invalid data file id", KR(ret), K(data_file_exist_unrecorded_), K(max_data_file_id_));
} else if (OB_FAIL(file_store.init(
uri_.ptr(), storage_info_.ptr(), cluster_name, cluster_id, tenant_id, incarnation_, archive_round_))) {
ARCHIVE_LOG(WARN, "init file_store fail", KR(ret), KPC(this), K(cluster_name), K(cluster_id));
} else if (OB_FAIL(path_util.build_archive_file_path(pg_key_,
LOG_ARCHIVE_FILE_TYPE_DATA,
max_data_file_id_,
incarnation_,
archive_round_,
MAX_FILE_PATH,
path))) {
ARCHIVE_LOG(WARN, "build_archive_file_path fail", KR(ret), K(pg_key_), K(max_data_file_id_));
} else {
ObString uri(path);
ObArchiveFileUtils utils;
if (OB_FAIL(utils.extract_last_log_in_data_file(
pg_key_, max_data_file_id_, &file_store, uri, storage_info_, block_meta, log_entry, inner_log))) {
ARCHIVE_LOG(WARN, "extract_last_log_in_data_file fail", KR(ret), K(pg_key_), K(uri));
} else {
exist_log_ = true;
rebuild_archive_progress_from_block_meta_(block_meta);
const ObLogEntryHeader& log_header = log_entry.get_header();
is_kickoff = is_archive_kickoff_log(log_header.get_log_type());
if (is_kickoff) {
if (OB_FAIL(rebuild_start_archive_info_from_kickoff_log_(block_meta, log_header, inner_log))) {
ARCHIVE_LOG(WARN, "rebuild_start_archive_info_from_kickoff_log_", K(pg_key_));
}
}
unrecorded_data_file_valid_ = true;
}
// if start archive info still not be found,
// kickoff log must be the first block in the file
if (OB_SUCC(ret) && !round_start_info_.is_valid() && !is_kickoff) {
ObArchiveBlockMeta first_block_meta;
clog::ObLogEntry first_log_entry;
ObLogArchiveInnerLog first_inner_log;
if (OB_FAIL(utils.extract_first_log_in_data_file(
pg_key_, max_data_file_id_, &file_store, first_block_meta, first_log_entry, first_inner_log))) {
ARCHIVE_LOG(WARN, "extract_first_log_in_data_file fail", KR(ret), K(pg_key_));
} else if (OB_FAIL(rebuild_start_archive_info_from_kickoff_log_(
first_block_meta, first_log_entry.get_header(), first_inner_log))) {
ARCHIVE_LOG(WARN,
"rebuild_start_archive_info_from_kickoff_log_ fail",
KR(ret),
K(pg_key_),
K(first_block_meta),
K(first_log_entry),
K(first_inner_log),
KPC(this));
}
}
}
return ret;
}
int StartArchiveHelper::iterate_archive_log_from_data_file_()
{
int ret = OB_SUCCESS;
const int64_t TIMEOUT = 60 * 1000 * 1000L;
const uint64_t tenant_id = pg_key_.get_tenant_id();
const char* cluster_name = GCTX.config_->cluster;
const int64_t cluster_id = GCTX.config_->cluster_id;
ObArchiveEntryIterator iter;
ObArchiveLogFileStore file_store;
const bool need_limit_bandwidth = false;
if (OB_UNLIKELY(!data_file_exist_unrecorded_ || 0 == max_data_file_id_)) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR, "invalid data file id", KR(ret), K(data_file_exist_unrecorded_), K(max_data_file_id_));
} else if (OB_FAIL(file_store.init(
uri_.ptr(), storage_info_.ptr(), cluster_name, cluster_id, tenant_id, incarnation_, archive_round_))) {
ARCHIVE_LOG(WARN, "init file_store fail", KR(ret), KPC(this), K(cluster_name), K(cluster_id));
} else if (OB_FAIL(iter.init(&file_store, pg_key_, max_data_file_id_, 0, TIMEOUT, need_limit_bandwidth))) {
ARCHIVE_LOG(WARN, "ObArchiveEntryIterator init fail", KR(ret), K(pg_key_));
} else {
clog::ObLogEntry log_entry;
bool has_valid_block = false;
while (OB_SUCC(ret) && OB_SUCCESS == (ret = iter.next_entry(log_entry))) {
exist_log_ = true;
has_valid_block = true;
const ObLogEntryHeader& log_header = log_entry.get_header();
const uint64_t log_id = log_header.get_log_id();
clog::ObLogType log_type = log_header.get_log_type();
const int64_t data_len = log_entry.get_header().get_data_len();
if (is_archive_kickoff_log(log_type)) {
ObLogArchiveInnerLog inner_log;
int64_t pos = 0;
if (OB_FAIL(inner_log.deserialize(log_entry.get_buf(), data_len, pos))) {
ARCHIVE_LOG(WARN, "failed to deserialize inner_log", KR(ret), K(log_entry), K(pg_key_));
} else {
const ObArchiveBlockMeta& block_meta = iter.get_last_block_meta();
if (OB_UNLIKELY(block_meta.max_log_id_ != log_id - 1)) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR,
"block meta is not consistent with log data",
KR(ret),
K(pg_key_),
K(block_meta),
K(log_entry),
K(inner_log),
KPC(this));
} else if (OB_FAIL(rebuild_start_archive_info_from_kickoff_log_(block_meta, log_header, inner_log))) {
ARCHIVE_LOG(
WARN, "rebuild_start_archive_info_from_kickoff_log_ fail", KPC(this), K(block_meta), K(log_header));
}
}
}
unrecorded_data_file_valid_ = true;
}
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
}
if (OB_SUCC(ret) && has_valid_block) {
const ObArchiveBlockMeta& block_meta = iter.get_last_block_meta();
const uint64_t log_entry_log_id = log_entry.get_header().get_log_id();
// last archived log id = log_id of kickoff - 1
const uint64_t last_archived_log_id =
is_archive_kickoff_log(log_entry.get_header().get_log_type()) ? (log_entry_log_id - 1) : log_entry_log_id;
if (OB_UNLIKELY(block_meta.max_log_id_ != last_archived_log_id)) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR,
"block meta is not consistent with log data",
KR(ret),
K(pg_key_),
K(block_meta),
K(log_entry),
KPC(this));
} else {
rebuild_archive_progress_from_block_meta_(block_meta);
ret = OB_SUCCESS;
}
}
}
return ret;
}
int StartArchiveHelper::rebuild_start_archive_info_from_kickoff_log_(
const ObArchiveBlockMeta& block_meta, const ObLogEntryHeader& log_header, ObLogArchiveInnerLog& inner_log)
{
int ret = OB_SUCCESS;
clog::ObLogType log_type = log_header.get_log_type();
if (OB_UNLIKELY(!is_archive_kickoff_log(log_type))) {
ret = OB_ERR_UNEXPECTED;
ARCHIVE_LOG(ERROR, "not kickoff log", KR(ret), K(log_header), K(block_meta));
} else {
round_start_info_.start_log_id_ = log_header.get_log_id();
;
round_start_info_.log_submit_ts_ = log_header.get_submit_timestamp();
round_start_info_.start_ts_ = inner_log.get_round_start_ts();
round_start_info_.snapshot_version_ = inner_log.get_round_snapshot_version();
round_start_info_.clog_epoch_id_ = block_meta.clog_epoch_id_;
round_start_info_.accum_checksum_ = block_meta.accum_checksum_;
}
return ret;
}
void StartArchiveHelper::rebuild_archive_progress_from_block_meta_(const ObArchiveBlockMeta& block_meta)
{
min_log_id_unrecorded_ = block_meta.min_log_id_in_file_;
min_log_ts_unrecorded_ = block_meta.min_log_ts_in_file_;
max_log_id_unrecorded_ = block_meta.max_log_id_;
max_checkpoint_ts_unrecorded_ = block_meta.max_checkpoint_ts_;
max_log_submit_ts_unrecorded_ = block_meta.max_log_submit_ts_;
max_archived_log_info_.max_log_id_archived_ = block_meta.max_log_id_;
max_archived_log_info_.max_checkpoint_ts_archived_ = block_meta.max_checkpoint_ts_;
max_archived_log_info_.max_log_submit_ts_archived_ = block_meta.max_log_submit_ts_;
max_archived_log_info_.clog_epoch_id_ = block_meta.clog_epoch_id_;
max_archived_log_info_.accum_checksum_ = block_meta.accum_checksum_;
}
void StartArchiveHelper::get_log_info_from_index_info_()
{
round_start_info_ = max_archived_index_info_.round_start_info_;
max_archived_log_info_.max_log_id_archived_ = max_archived_index_info_.max_record_log_id_;
max_archived_log_info_.max_checkpoint_ts_archived_ = max_archived_index_info_.max_record_checkpoint_ts_;
max_archived_log_info_.max_log_submit_ts_archived_ = max_archived_index_info_.max_record_log_submit_ts_;
max_archived_log_info_.clog_epoch_id_ = max_archived_index_info_.clog_epoch_id_;
max_archived_log_info_.accum_checksum_ = max_archived_index_info_.accum_checksum_;
exist_log_ = true;
}
// at least on file exist to guarantee archive progress can be obtained
int StartArchiveHelper::decide_pg_start_archive_log_id_()
{
int ret = OB_SUCCESS;
if (OB_FAIL(decide_pg_start_archive_log_id_remote_())) {
ARCHIVE_LOG(WARN, "decide_pg_start_archive_log_id_remote_ fail", KR(ret), KPC(this));
} else if (OB_FAIL(get_cluster_archive_status_())) {
ARCHIVE_LOG(WARN, "get_cluster_archive_status_ fail", KR(ret));
} else if (OB_FAIL(get_tenant_archive_status_())) {
ARCHIVE_LOG(WARN, "get_tenant_archive_status_ fail", KR(ret));
}
if (OB_SUCC(ret)) {
// If no data exist in backup destiantion, the start archive info will be decided in local.
if (!exist_log_) {
if (OB_FAIL(decide_pg_start_archive_log_id_locally_())) {
ARCHIVE_LOG(WARN, "decide_pg_start_archive_log_id_locally_ fail", KR(ret), KPC(this));
}
}
// If log exist in backup dest, the archive progress will be decided by backup dest/rs/local cache chekcpoint ts.
else {
int64_t cur_checkpoint_ts = 0;
if (OB_FAIL(get_cur_pg_log_archive_checkpoint_ts_(cur_checkpoint_ts))) {
ARCHIVE_LOG(WARN, "get_cur_pg_log_archive_checkpoint_ts_ fail", KR(ret), K(pg_key_));
} else {
max_archived_log_info_.max_checkpoint_ts_archived_ = std::max(cur_checkpoint_ts,
std::max(max_archived_log_info_.max_checkpoint_ts_archived_, tenant_archive_checkpoint_ts_));
}
}
}
return ret;
}
int StartArchiveHelper::get_cur_pg_log_archive_checkpoint_ts_(int64_t& cur_checkpoint_ts)
{
int ret = OB_SUCCESS;
ObPGLogArchiveStatus status;
cur_checkpoint_ts = 0;
if (OB_FAIL(log_wrapper_.get_pg_log_archive_status(pg_key_, status))) {
ARCHIVE_LOG(WARN, "get_pg_log_archive_status fail", KR(ret), K(pg_key_));
} else if (status.archive_incarnation_ != incarnation_ || status.log_archive_round_ != archive_round_) {
// skip it
} else {
ARCHIVE_LOG(INFO, "get_log_archive_status succ", K(status), K(pg_key_));
cur_checkpoint_ts = status.last_archived_checkpoint_ts_;
}
return ret;
}
int StartArchiveHelper::decide_need_archive_first_record_()
{
int ret = OB_SUCCESS;
if (exist_log_) {
need_kickoff_log_ = false;
} else {
need_kickoff_log_ = true;
}
return ret;
}
} // namespace archive
} // namespace oceanbase