/** * 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 #include "storage/ob_saved_storage_info_v2.h" #include "common/ob_partition_key.h" #include "share/backup/ob_backup_info_mgr.h" #include "storage/ob_partition_service.h" #include "storage/ob_saved_storage_info.h" namespace oceanbase { using namespace common; using namespace share; namespace storage { OB_DEF_SERIALIZE(ObSavedStorageInfoV2) { int ret = OB_SUCCESS; LST_DO_CODE(OB_UNIS_ENCODE, STORAGE_INFO_VERSION_V3, clog_info_, data_info_, pg_file_id_); return ret; } OB_DEF_SERIALIZE_SIZE(ObSavedStorageInfoV2) { int64_t len = 0; LST_DO_CODE(OB_UNIS_ADD_LEN, STORAGE_INFO_VERSION_V3, clog_info_, data_info_, pg_file_id_); return len; } OB_DEF_DESERIALIZE(ObSavedStorageInfoV2) { int ret = OB_SUCCESS; int64_t tmp_pos = pos; int16_t version = 0; if (OB_ISNULL(buf) || data_len <= 0 || pos < 0 || pos >= data_len) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(buf), K(data_len), K(pos), K(ret)); } else if (OB_FAIL(serialization::decode(buf, data_len, tmp_pos, version))) { STORAGE_LOG(WARN, "deserialize version failed.", K(ret)); } else if (STORAGE_INFO_VERSION_V1 == version) { ret = OB_NOT_SUPPORTED; } else if (STORAGE_INFO_VERSION_V2 == version) { ObRecoverVec tmp_recover_vec; bool tmp_from_14x = false; ObVersion tmp_version(STORAGE_INFO_VERSION_V3, 0); LST_DO_CODE( OB_UNIS_DECODE, version_, clog_info_, data_info_, tmp_from_14x, tmp_version, tmp_recover_vec, pg_file_id_); } else if (STORAGE_INFO_VERSION_V3 == version) { LST_DO_CODE(OB_UNIS_DECODE, version_, clog_info_, data_info_, pg_file_id_); } else { ret = OB_DESERIALIZE_ERROR; STORAGE_LOG(ERROR, "version not recognized", K(ret), K(version)); } return ret; } int ObSavedStorageInfoV2::deep_copy(const ObSavedStorageInfoV2& save_storage_info) { int ret = OB_SUCCESS; if (!save_storage_info.is_valid()) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(save_storage_info)); } else if (OB_FAIL(set_clog_info(save_storage_info.clog_info_))) { STORAGE_LOG(WARN, "base storage info copy failed", K(ret)); } else if (OB_FAIL(set_data_info(save_storage_info.data_info_))) { STORAGE_LOG(WARN, "data storage info copy failed", K(ret)); } if (OB_INVALID_DATA_FILE_ID == pg_file_id_) { pg_file_id_ = save_storage_info.pg_file_id_; } return ret; } int ObSavedStorageInfoV2::convert(const ObSavedStorageInfo& save_storage_info) { int ret = OB_SUCCESS; if (!save_storage_info.is_valid()) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(save_storage_info)); } else if (OB_FAIL(set_clog_info(save_storage_info))) { STORAGE_LOG(WARN, "base storage info copy failed", K(ret)); } else { ObDataStorageInfo tmp_info; tmp_info.set_last_replay_log_id(save_storage_info.get_last_replay_log_id()); tmp_info.set_publish_version(save_storage_info.get_publish_version()); tmp_info.set_schema_version(save_storage_info.get_schema_version()); if (OB_FAIL(set_data_info(tmp_info))) { STORAGE_LOG(WARN, "data storage info copy failed", K(ret)); } } return ret; } int ObSavedStorageInfoV2::deep_copy(const ObSavedStorageInfo& save_storage_info) { int ret = OB_SUCCESS; if (OB_FAIL(convert(save_storage_info))) { STORAGE_LOG(WARN, "fail to convert V1 storage info", K(ret)); } return ret; } void ObSavedStorageInfoV2::reset() { version_ = STORAGE_INFO_VERSION_V3; clog_info_.reset(); data_info_.reset(); pg_file_id_ = OB_INVALID_DATA_FILE_ID; } int ObSavedStorageInfoV2::set_data_info(const ObDataStorageInfo& data_storage_info) { int ret = OB_SUCCESS; if (!data_storage_info.is_valid()) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(data_storage_info)); } else { data_info_ = data_storage_info; } return ret; } int ObSavedStorageInfoV2::query_log_info_with_log_id(const ObPartitionKey& pkey, const int64_t log_id, const int64_t timeout, int64_t& accum_checksum, int64_t& submit_timestamp, int64_t& epoch_id) { int ret = OB_SUCCESS; const int64_t start_ts = ObTimeUtility::current_time(); if (OB_FAIL(ObPartitionService::get_instance().query_log_info_with_log_id( pkey, log_id, timeout, accum_checksum, submit_timestamp, epoch_id))) { STORAGE_LOG(WARN, "failed to query log info", K(ret), K(pkey), K(log_id)); } const int64_t cost_ts = ObTimeUtility::current_time() - start_ts; if (cost_ts > 1000 * 1000 /*1s*/) { STORAGE_LOG(WARN, "query_log_info_with_log_id cost too much time", K(pkey), K(log_id), K(cost_ts)); } else { STORAGE_LOG(INFO, "query_log_info_with_log_id cost time", K(pkey), K(log_id), K(cost_ts)); } return ret; } int ObSavedStorageInfoV2::get_last_replay_log_info_( const ObPartitionKey& pkey, const int64_t timeout, ObRecoverPoint& point) { int ret = OB_SUCCESS; int64_t submit_timestamp = 0; int64_t epoch_id = 0; int64_t checksum = 0; if (0 == data_info_.get_last_replay_log_id()) { checksum = 0; } else if (data_info_.get_last_replay_log_id() < clog_info_.get_last_replay_log_id()) { ret = OB_ERR_UNEXPECTED; TRANS_LOG(ERROR, "filter log id is smaller than last replay log id", K(*this), K(ret)); } else if (data_info_.get_last_replay_log_id() == clog_info_.get_last_replay_log_id()) { checksum = clog_info_.get_accumulate_checksum(); } else if (OB_FAIL(query_log_info_with_log_id( pkey, data_info_.get_last_replay_log_id(), timeout, checksum, submit_timestamp, epoch_id))) { STORAGE_LOG(WARN, "failed to query accum checksum", K(ret), K(pkey), K(*this)); } else { point.set( data_info_.get_publish_version(), data_info_.get_last_replay_log_id(), checksum, epoch_id, submit_timestamp); } return ret; } int ObSavedStorageInfoV2::update_last_replay_log_info_(const ObPartitionKey& pkey, const bool replica_with_data, const ObBaseStorageInfo& old_clog_info, const int64_t timeout, const bool log_info_usable) { int ret = OB_SUCCESS; int64_t accum_checksum = 0; int64_t submit_timestamp = 0; int64_t epoch_id = 0; bool can_skip_query = log_info_usable; if (replica_with_data && data_info_.get_last_replay_log_id() < clog_info_.get_last_replay_log_id()) { clog_info_.set_last_replay_log_id(data_info_.get_last_replay_log_id()); can_skip_query = false; } if (can_skip_query) { STORAGE_LOG(INFO, "clog info unchanged", K(clog_info_)); } else if (clog_info_.get_last_replay_log_id() <= old_clog_info.get_last_replay_log_id()) { // For the case that the log id clog info may be recycled, the clog info of memtable dump // point is used. In addition, it should be guaranteed that the last_replay_log_id of clog info // is smaller than data info. if (replica_with_data && data_info_.get_last_replay_log_id() < old_clog_info.get_last_replay_log_id()) { ret = OB_EAGAIN; STORAGE_LOG(WARN, "data info too old, try again", K(ret), K(pkey), K(old_clog_info), K(*this)); } else { STORAGE_LOG(INFO, "use saved clog info", K(clog_info_), K(old_clog_info)); if (OB_FAIL(set_clog_info(old_clog_info))) { STORAGE_LOG(WARN, "base storage info copy failed", K(ret)); } } } else if (OB_FAIL(query_log_info_with_log_id( pkey, clog_info_.get_last_replay_log_id(), timeout, accum_checksum, submit_timestamp, epoch_id))) { STORAGE_LOG(WARN, "failed to query accum checksum", K(ret), K(pkey), K(*this)); } else { clog_info_.set_accumulate_checksum(accum_checksum); clog_info_.set_submit_timestamp(submit_timestamp); clog_info_.set_epoch_id(epoch_id); } return ret; } int ObSavedStorageInfoV2::update_last_replay_log_info(const ObPartitionKey& pkey, const bool replica_with_data, const ObBaseStorageInfo& old_clog_info, const int64_t timeout, const bool log_info_usable) { return update_last_replay_log_info_(pkey, replica_with_data, old_clog_info, timeout, log_info_usable); } int ObSavedStorageInfoV2::update_and_fetch_log_info(const ObPartitionKey& pkey, const bool replica_with_data, const ObBaseStorageInfo& old_clog_info, const int64_t timeout, const bool log_info_usable) { int ret = OB_SUCCESS; if (OB_FAIL(update_last_replay_log_info_(pkey, replica_with_data, old_clog_info, timeout, log_info_usable))) { STORAGE_LOG(WARN, "failed to update log info", K(ret), K(pkey), K(old_clog_info)); } return ret; } int ObSavedStorageInfoV2::clear_recover_points_for_physical_flashback(const int64_t, const ObRecoverPoint&) { return OB_NOT_IMPLEMENT; } OB_SERIALIZE_MEMBER(ObRecoverPoint, snapshot_version_, recover_log_id_, checksum_, epoch_id_, submit_timestamp_); OB_SERIALIZE_MEMBER(ObRecoverVec, recover_vec_); int ObRecoverVec::add_recover_point_(const ObRecoverPoint& point) { int ret = OB_SUCCESS; if (recover_vec_.count() > 0 && point.snapshot_version_ <= recover_vec_[recover_vec_.count() - 1].snapshot_version_) { STORAGE_LOG(INFO, "add recover point with lower recover point", K(ret), K(point), K(recover_vec_)); ret = OB_SUCCESS; } else if (OB_FAIL(recover_vec_.push_back(point))) { STORAGE_LOG(WARN, "push back to vec failed", K(ret), K(point)); } return ret; } int ObRecoverVec::add_recover_point(const ObRecoverPoint& point) { ObLockGuard lock_guard(lock_); return add_recover_point_(point); } int ObRecoverVec::reboot_recover_point(const ObRecoverPoint& point) { int ret = OB_SUCCESS; ObLockGuard lock_guard(lock_); if (0 == recover_vec_.count() && OB_FAIL(add_recover_point_(point))) { STORAGE_LOG(WARN, "reboot recover point failed", K(point), K(ret), K(*this)); } return ret; } int ObRecoverVec::gc_recover_points(const int64_t gc_snapshot_version, const int64_t kept_backup_version, bool& changed) { int ret = OB_SUCCESS; changed = false; ObLockGuard lock_guard(lock_); while (OB_SUCC(ret) && can_gc_recover_point_(gc_snapshot_version, kept_backup_version)) { ObRecoverPoint point = recover_vec_[0]; if (OB_FAIL(recover_vec_.remove(0))) { STORAGE_LOG(WARN, "gc recover points fail", K(ret), K(gc_snapshot_version), K(recover_vec_), K(kept_backup_version), K(point)); } else { STORAGE_LOG(INFO, "gc recover points succeed", K(ret), K(gc_snapshot_version), K(recover_vec_), K(kept_backup_version), K(point)); changed = true; } } return ret; } int ObRecoverVec::clear_recover_points_for_physical_flashback(const int64_t version, const ObRecoverPoint& point) { int ret = OB_SUCCESS; int size = 0; ObLockGuard lock_guard(lock_); size = recover_vec_.count(); for (int64_t i = size - 1; i >= 0 && OB_SUCC(ret) && recover_vec_[i].snapshot_version_ > version; i--) { if (OB_FAIL(recover_vec_.remove(i))) { STORAGE_LOG(ERROR, "remove recover points failed", K(ret), K(version), K(recover_vec_), K(point)); } } if (0 == recover_vec_.count() && OB_FAIL(add_recover_point_(point))) { STORAGE_LOG(ERROR, "remove recover points failed", K(ret), K(version), K(recover_vec_), K(point)); } return ret; } bool ObRecoverVec::can_gc_recover_point_(const int64_t gc_snapshot_version, const int64_t kept_backup_version) { // There must be at least one recovery point in the vector. return recover_vec_.count() > 1 && // If the snapshot_version of recover point is not greater than gc point. recover_vec_[0].snapshot_version_ <= gc_snapshot_version && // There must be at least one recovery point's snapshot_version is not greater than backup. (kept_backup_version == 0 || recover_vec_[1].snapshot_version_ <= kept_backup_version); } int ObRecoverVec::get_lower_bound_point(const int64_t snapshot_version, ObRecoverPoint& point) { int ret = OB_SUCCESS; int64_t id = 0; ObLockGuard lock_guard(lock_); if (OB_FAIL(get_lower_bound_point_(snapshot_version, id))) { if (OB_ENTRY_NOT_EXIST != ret) { STORAGE_LOG(ERROR, "get lower bound point error", K(snapshot_version)); } else { STORAGE_LOG(INFO, "get lower bound point not exist", K(snapshot_version)); } } else { point = recover_vec_[id]; } return ret; } int ObRecoverVec::get_lower_bound_point_(const int64_t snapshot_version, int64_t& id) { int ret = OB_SUCCESS; ObRecoverPoint tmp_point(snapshot_version, 0, 0, 0, 0); RecoverIter iter; if (recover_vec_.count() == 0) { ret = OB_ENTRY_NOT_EXIST; } else if (recover_vec_.end() == (iter = std::lower_bound(recover_vec_.begin(), recover_vec_.end(), tmp_point))) { id = recover_vec_.count() - 1; } else if (iter->snapshot_version_ == snapshot_version) { id = iter - recover_vec_.begin(); } else if (recover_vec_.begin() == iter) { ret = OB_ENTRY_NOT_EXIST; } else { id = iter - recover_vec_.begin() - 1; } return ret; } int ObRecoverVec::record_major_recover_point(const int64_t prev_version, const int64_t version, bool& changed) { int ret = OB_SUCCESS; int64_t id = 0; changed = false; ObLockGuard lock_guard(lock_); if (OB_FAIL(get_lower_bound_point_(version, id))) { if (OB_ENTRY_NOT_EXIST != ret) { STORAGE_LOG(ERROR, "get lower bound point error", K(version)); } else { STORAGE_LOG(INFO, "get lower bound point not exist", K(version)); } } else { for (int64_t i = id - 1; i >= 0 && OB_SUCC(ret) && recover_vec_[i].snapshot_version_ > prev_version; i--) { if (OB_FAIL(recover_vec_.remove(i))) { STORAGE_LOG(WARN, "gc recover points failed", K(ret), K(prev_version), K(version), K(recover_vec_)); } else { changed = true; } } if (OB_FAIL(ret)) { STORAGE_LOG(WARN, "record major recover point failed", K(ret), K(prev_version), K(version), K(recover_vec_)); } else { if (changed) { STORAGE_LOG(INFO, "record major recover point success", K(prev_version), K(version), K(recover_vec_)); } } } return ret; } int ObRecoverVec::assign_recover_points(const ObRecoverVec& vec) { int ret = OB_SUCCESS; ObLockGuard lock_guard(lock_); recover_vec_.reset(); if (OB_FAIL(recover_vec_.assign(vec.recover_vec_))) { STORAGE_LOG(WARN, "assign vec failed", K(recover_vec_), K(vec)); } return ret; } } // namespace storage } // namespace oceanbase