1339 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1339 lines
		
	
	
		
			50 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_info_block_handler.h"
 | 
						|
#include "share/backup/ob_backup_info_mgr.h"
 | 
						|
#include "storage/ob_partition_service.h"
 | 
						|
#include "storage/ob_pg_storage.h"
 | 
						|
#include "ob_log_define.h"
 | 
						|
#include "ob_partition_log_service.h"
 | 
						|
 | 
						|
namespace oceanbase {
 | 
						|
using namespace common;
 | 
						|
using namespace share;
 | 
						|
using namespace storage;
 | 
						|
namespace clog {
 | 
						|
ObIInfoBlockHandler::ObIInfoBlockHandler()
 | 
						|
{
 | 
						|
  freeze_version_ = ObVersion(1, 0);
 | 
						|
  have_info_hash_v2_ = false;
 | 
						|
  info_hash_v2_.reset();
 | 
						|
  max_submit_timestamp_ = OB_INVALID_TIMESTAMP;
 | 
						|
}
 | 
						|
 | 
						|
bool ObIndexInfoBlockHandler::InfoEntryLoader::operator()(
 | 
						|
    const common::ObPartitionKey& partition_key, const InfoEntry& info_entry)
 | 
						|
{
 | 
						|
  int tmp_ret = OB_SUCCESS;
 | 
						|
  bool bool_ret = false;
 | 
						|
 | 
						|
  IndexInfoBlockEntry entry;
 | 
						|
 | 
						|
  // based on InfoEntry, init entry
 | 
						|
  entry.min_log_id_ = info_entry.min_log_id_;
 | 
						|
  entry.min_log_timestamp_ = info_entry.min_log_timestamp_;
 | 
						|
  entry.max_log_timestamp_ = info_entry.max_log_timestamp_;
 | 
						|
 | 
						|
  // insert entry into map
 | 
						|
  if (OB_SUCCESS != (tmp_ret = map_.insert(partition_key, entry))) {
 | 
						|
    CLOG_LOG(ERROR, "insert index info block map failed", K(tmp_ret), K(partition_key), K(info_entry), K(entry));
 | 
						|
  } else {
 | 
						|
    bool_ret = true;
 | 
						|
  }
 | 
						|
  return bool_ret;
 | 
						|
}
 | 
						|
 | 
						|
bool ObIndexInfoBlockHandler::InfoEntryV2Loader::operator()(
 | 
						|
    const common::ObPartitionKey& partition_key, const InfoEntryV2& info_entry_v2)
 | 
						|
{
 | 
						|
  bool bool_ret = false;
 | 
						|
  int tmp_ret = OB_SUCCESS;
 | 
						|
  IndexInfoBlockEntry entry;
 | 
						|
 | 
						|
  // the corresponding log must already exists.
 | 
						|
  if (OB_SUCCESS != (tmp_ret = map_.get(partition_key, entry))) {
 | 
						|
    CLOG_LOG(ERROR, "get IndexInfoBlockEntry from map fail", K(tmp_ret), K(partition_key));
 | 
						|
  } else {
 | 
						|
    // update max_log_id
 | 
						|
    entry.max_log_id_ = info_entry_v2.max_log_id_;
 | 
						|
 | 
						|
    // updat map
 | 
						|
    if (OB_SUCCESS != (tmp_ret = map_.update(partition_key, entry))) {
 | 
						|
      CLOG_LOG(ERROR, "update IndexInfoBlockEntry fail", K(tmp_ret), K(partition_key));
 | 
						|
    } else {
 | 
						|
      bool_ret = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return bool_ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::get_all_entry(IndexInfoBlockMap& map)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  int64_t capacity = (CLOG_INFO_BLOCK_SIZE_LIMIT) / map.item_size();
 | 
						|
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObIndexInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else if (OB_FAIL(map.init(ObModIds::OB_CLOG_INFO_BLK_HNDLR, capacity))) {
 | 
						|
    CLOG_LOG(ERROR, "index info block map init failed", K(ret), K(capacity));
 | 
						|
  } else {
 | 
						|
    InfoEntryLoader info_entry_loader(map);
 | 
						|
    InfoEntryV2Loader info_entry_v2_loader(map);
 | 
						|
 | 
						|
    // load InfoEntry
 | 
						|
    if (OB_FAIL(info_hash_.for_each(info_entry_loader))) {
 | 
						|
      CLOG_LOG(WARN, "for_each info hash fail", K(ret));
 | 
						|
    }
 | 
						|
    // load InfoEntryV2
 | 
						|
    else if (OB_FAIL(info_hash_v2_.for_each(info_entry_v2_loader))) {
 | 
						|
      CLOG_LOG(WARN, "for_each info hash v2 fail", K(ret));
 | 
						|
    } else {
 | 
						|
      // success
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
ObIndexInfoBlockHandler::AppendMinLogIdInfoFunctor::AppendMinLogIdInfoFunctor(MinLogIdInfo& min_log_id_info)
 | 
						|
    : min_log_id_info_(min_log_id_info)
 | 
						|
{}
 | 
						|
 | 
						|
bool ObIndexInfoBlockHandler::AppendMinLogIdInfoFunctor::operator()(
 | 
						|
    const common::ObPartitionKey& partition_key, const InfoEntry& info_entry)
 | 
						|
{
 | 
						|
  int tmp_ret = OB_SUCCESS;
 | 
						|
  bool bool_ret = false;
 | 
						|
  if (OB_SUCCESS != (tmp_ret = min_log_id_info_.insert(partition_key, info_entry.min_log_id_))) {
 | 
						|
    CLOG_LOG(ERROR, "insert failed", K(partition_key), K(info_entry));
 | 
						|
  } else {
 | 
						|
    bool_ret = true;
 | 
						|
  }
 | 
						|
  return bool_ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::get_all_min_log_id_info(MinLogIdInfo& min_log_id_info)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObIndexInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else if (OB_FAIL(min_log_id_info.init(
 | 
						|
                 ObModIds::OB_CLOG_INFO_BLK_HNDLR, (CLOG_INFO_BLOCK_SIZE_LIMIT) / min_log_id_info.item_size()))) {
 | 
						|
    CLOG_LOG(ERROR, "min_log_id_info init failed", K(ret));
 | 
						|
  } else {
 | 
						|
    AppendMinLogIdInfoFunctor functor(min_log_id_info);
 | 
						|
    ret = info_hash_.for_each(functor);
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
ObIndexInfoBlockHandler::InfoEntrySerializeFunctor::InfoEntrySerializeFunctor(
 | 
						|
    char* buf, const int64_t buf_len, int64_t& pos, TstampArray& max_log_tstamp_array)
 | 
						|
    : buf_(buf), buf_len_(buf_len), pos_(pos), max_log_tstamp_array_(max_log_tstamp_array)
 | 
						|
{}
 | 
						|
 | 
						|
bool ObIndexInfoBlockHandler::InfoEntrySerializeFunctor::operator()(
 | 
						|
    const common::ObPartitionKey& partition_key, const InfoEntry& info_entry)
 | 
						|
{
 | 
						|
  int tmp_ret = OB_SUCCESS;
 | 
						|
  bool bool_ret = false;
 | 
						|
 | 
						|
  // to be compatible with older versions, only serialize min_log_id and min_log_ts
 | 
						|
  // the max_log_ts serialize separately.
 | 
						|
  if (OB_SUCCESS != (tmp_ret = partition_key.serialize(buf_, buf_len_, pos_))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(tmp_ret));
 | 
						|
  } else if (OB_SUCCESS != (tmp_ret = serialization::encode_i64(buf_, buf_len_, pos_, info_entry.min_log_id_))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(tmp_ret));
 | 
						|
  } else if (OB_SUCCESS != (tmp_ret = serialization::encode_i64(buf_, buf_len_, pos_, info_entry.min_log_timestamp_))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(tmp_ret));
 | 
						|
  } else if (OB_SUCCESS != (tmp_ret = max_log_tstamp_array_.push_back(info_entry.max_log_timestamp_))) {
 | 
						|
    CLOG_LOG(ERROR, "push back max log timestamp fail", K(tmp_ret), K(info_entry), K(max_log_tstamp_array_));
 | 
						|
  } else {
 | 
						|
    bool_ret = true;
 | 
						|
  }
 | 
						|
  return bool_ret;
 | 
						|
}
 | 
						|
 | 
						|
ObIInfoBlockHandler::InfoEntrySerializeFunctorV2::InfoEntrySerializeFunctorV2(
 | 
						|
    char* buf, const int64_t buf_len, int64_t& pos)
 | 
						|
    : buf_(buf), buf_len_(buf_len), pos_(pos)
 | 
						|
{}
 | 
						|
 | 
						|
bool ObIInfoBlockHandler::InfoEntrySerializeFunctorV2::operator()(
 | 
						|
    const common::ObPartitionKey& partition_key, const InfoEntryV2& info_entry_v2)
 | 
						|
{
 | 
						|
  int tmp_ret = OB_SUCCESS;
 | 
						|
  bool bool_ret = false;
 | 
						|
  if (OB_SUCCESS != (tmp_ret = partition_key.serialize(buf_, buf_len_, pos_))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(tmp_ret));
 | 
						|
  } else if (OB_SUCCESS != (tmp_ret = serialization::encode_i64(buf_, buf_len_, pos_, info_entry_v2.max_log_id_))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(tmp_ret));
 | 
						|
  } else {
 | 
						|
    bool_ret = true;
 | 
						|
  }
 | 
						|
  return bool_ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::get_max_log_id(const common::ObPartitionKey& partition_key, uint64_t& max_log_id)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  max_log_id = OB_INVALID_ID;
 | 
						|
  if (have_info_hash_v2_) {
 | 
						|
    InfoEntryV2 entry_v2;
 | 
						|
    entry_v2.reset();
 | 
						|
    if (OB_SUCC(info_hash_v2_.get(partition_key, entry_v2))) {
 | 
						|
      max_log_id = entry_v2.max_log_id_;
 | 
						|
    }
 | 
						|
    if (OB_SUCCESS != ret && OB_ENTRY_NOT_EXIST != ret) {
 | 
						|
      CLOG_LOG(ERROR, "info_hash_v2 get failed", K(partition_key), K(ret));
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    ret = OB_ENTRY_NOT_EXIST;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::update_info_hash_v2_(const common::ObPartitionKey& partition_key, const uint64_t log_id)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  InfoEntryV2 entry_v2;
 | 
						|
 | 
						|
  if (OB_SUCC(info_hash_v2_.get(partition_key, entry_v2))) {
 | 
						|
    if (log_id > entry_v2.max_log_id_) {
 | 
						|
      entry_v2.max_log_id_ = log_id;
 | 
						|
    }
 | 
						|
    if (OB_FAIL(info_hash_v2_.update(partition_key, entry_v2))) {
 | 
						|
      CLOG_LOG(WARN, "info_hash_v2_ update failed", K(ret), K(partition_key), K(entry_v2));
 | 
						|
    }
 | 
						|
  } else if (OB_ENTRY_NOT_EXIST == ret) {
 | 
						|
    entry_v2.max_log_id_ = log_id;
 | 
						|
    if (OB_FAIL(info_hash_v2_.insert(partition_key, entry_v2))) {
 | 
						|
      CLOG_LOG(WARN, "info_hash_v2.insert failed", K(ret), K(partition_key), K(entry_v2));
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    CLOG_LOG(WARN, "info_hash_v2 get failed", K(ret), K(partition_key), K(entry_v2));
 | 
						|
  }
 | 
						|
 | 
						|
  // init have_info_hash_v2_
 | 
						|
  if (OB_SUCCESS == ret && !have_info_hash_v2_) {
 | 
						|
    have_info_hash_v2_ = true;
 | 
						|
  }
 | 
						|
 | 
						|
  CLOG_LOG(TRACE, "update_info_hash_v2_", K(ret), K(partition_key), K(log_id), K(entry_v2), K(have_info_hash_v2_));
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::resolve_info_hash_v2_(
 | 
						|
    const char* buf, const int64_t buf_len, int64_t& pos, const int64_t expected_magic_number)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  int64_t magic_num = 0;
 | 
						|
  uint64_t partition_num = 0;
 | 
						|
  int64_t new_pos = pos;
 | 
						|
 | 
						|
  if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, &magic_num))) {
 | 
						|
    CLOG_LOG(WARN, "deserialization failed", K(ret), K(buf), K(buf_len), K(new_pos));
 | 
						|
  } else if (magic_num != expected_magic_number) {
 | 
						|
    ret = OB_INVALID_DATA;
 | 
						|
    CLOG_LOG(INFO, "magic number not match", K(magic_num), K(expected_magic_number));
 | 
						|
  } else if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, reinterpret_cast<int64_t*>(&partition_num)))) {
 | 
						|
    CLOG_LOG(WARN, "deserialization failed", K(ret), K(buf), K(buf_len), K(new_pos));
 | 
						|
  } else if (OB_FAIL(info_hash_v2_.shrink_size(partition_num + 1))) {
 | 
						|
    CLOG_LOG(WARN, "info_hash_v2 shrink failed", K(ret), K(partition_num));
 | 
						|
  } else {
 | 
						|
    common::ObPartitionKey partition_key;
 | 
						|
    InfoEntryV2 entry_v2;
 | 
						|
    for (uint64_t i = 0; i < partition_num && OB_SUCC(ret); ++i) {
 | 
						|
      uint64_t max_log_id = 0;
 | 
						|
      partition_key.reset();
 | 
						|
      if (OB_FAIL(partition_key.deserialize(buf, buf_len, new_pos))) {
 | 
						|
        CLOG_LOG(WARN, "deserialization failed", K(ret));
 | 
						|
      } else if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, reinterpret_cast<int64_t*>(&max_log_id)))) {
 | 
						|
        CLOG_LOG(WARN, "deserialization failed", K(ret));
 | 
						|
      } else {
 | 
						|
        entry_v2.reset();
 | 
						|
        entry_v2.max_log_id_ = max_log_id;
 | 
						|
        if (OB_FAIL(info_hash_v2_.insert(partition_key, entry_v2))) {
 | 
						|
          CLOG_LOG(WARN, "info_hash_v2_ insert failed", K(ret), K(partition_key), K(entry_v2));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (OB_SUCC(ret)) {
 | 
						|
    have_info_hash_v2_ = true;
 | 
						|
  }
 | 
						|
  pos = new_pos;
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
ObCommitInfoBlockHandler::ObCommitInfoBlockHandler() : is_inited_(false)
 | 
						|
{}
 | 
						|
 | 
						|
int ObCommitInfoBlockHandler::init()
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (is_inited_) {
 | 
						|
    ret = OB_INIT_TWICE;
 | 
						|
  } else if (OB_FAIL(info_hash_v2_.init(
 | 
						|
                 ObModIds::OB_CLOG_INFO_BLK_HNDLR, (CLOG_INFO_BLOCK_SIZE_LIMIT) / info_hash_v2_.item_size()))) {
 | 
						|
    CLOG_LOG(ERROR, "info_hash_v2_ init failed", K(ret));
 | 
						|
  } else {
 | 
						|
    freeze_version_ = ObVersion(1, 0);
 | 
						|
    is_inited_ = true;
 | 
						|
  }
 | 
						|
  if (!is_inited_) {
 | 
						|
    destroy();
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
void ObCommitInfoBlockHandler::destroy()
 | 
						|
{
 | 
						|
  info_hash_v2_.destroy();
 | 
						|
  have_info_hash_v2_ = false;
 | 
						|
  is_inited_ = false;
 | 
						|
}
 | 
						|
 | 
						|
int ObCommitInfoBlockHandler::build_info_block(char* buf, const int64_t buf_len, int64_t& pos)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  int64_t new_pos = pos;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObCommitInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else if (NULL == buf || buf_len < 0 || pos < 0 || pos > buf_len) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
  } else if (OB_FAIL(serialization::encode_i16(buf, buf_len, new_pos, CLOG_INFO_BLOCK_VERSION))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
  } else if (OB_FAIL(freeze_version_.serialize(buf, buf_len, new_pos))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
  } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, MAGIC_NUMBER))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
  } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, info_hash_v2_.size()))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
  } else {
 | 
						|
    InfoEntrySerializeFunctorV2 functor_v2(buf, buf_len, new_pos);
 | 
						|
    ret = info_hash_v2_.for_each(functor_v2);
 | 
						|
  }
 | 
						|
  if (OB_SUCC(ret)) {
 | 
						|
    if (OB_FAIL(build_max_submit_timestamp_(buf, buf_len, new_pos))) {
 | 
						|
      CLOG_LOG(ERROR, "build_max_submit_timestamp_ failed", K(ret));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (OB_SUCC(ret)) {
 | 
						|
    if (OB_FAIL(reset())) {
 | 
						|
      CLOG_LOG(ERROR, "switch file failed", K(ret));
 | 
						|
    } else {
 | 
						|
      pos = new_pos;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  CLOG_LOG(INFO, "clog info block version", K(ret), K(freeze_version_));
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObCommitInfoBlockHandler::resolve_info_block(const char* buf, const int64_t buf_len, int64_t& pos)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  int64_t new_pos = pos;
 | 
						|
  int16_t clog_info_block_version = 0;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObCommitInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else if (NULL == buf || buf_len < 0 || pos < 0) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
  } else if (OB_FAIL(serialization::decode_i16(buf, buf_len, new_pos, &clog_info_block_version))) {
 | 
						|
    CLOG_LOG(ERROR, "deserialization failed", K(ret));
 | 
						|
  } else if (clog_info_block_version != CLOG_INFO_BLOCK_VERSION) {
 | 
						|
    CLOG_LOG(ERROR, "invalid version", K(clog_info_block_version), K(CLOG_INFO_BLOCK_VERSION));
 | 
						|
    ret = OB_VERSION_NOT_MATCH;
 | 
						|
  } else if (OB_FAIL(freeze_version_.deserialize(buf, buf_len, new_pos))) {
 | 
						|
    CLOG_LOG(ERROR, "deserialization failed", K(ret));
 | 
						|
  } else {
 | 
						|
    int tmp_ret = OB_SUCCESS;
 | 
						|
    if (OB_SUCCESS != (tmp_ret = resolve_info_hash_v2_(buf, buf_len, new_pos, MAGIC_NUMBER))) {
 | 
						|
      CLOG_LOG(INFO, "resolve_info_hash_v2_ failed", K(tmp_ret));
 | 
						|
    } else if (OB_SUCCESS != (tmp_ret = resolve_max_submit_timestamp_(buf, buf_len, new_pos))) {
 | 
						|
      CLOG_LOG(INFO, "resolve_max_submit_timestamp_ failed", K(tmp_ret));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  pos = new_pos;
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObCommitInfoBlockHandler::reset()
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObCommitInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else {
 | 
						|
    have_info_hash_v2_ = false;
 | 
						|
    info_hash_v2_.reset();
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObCommitInfoBlockHandler::update_info(const int64_t max_submit_timestamp)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObCommitInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else if (OB_INVALID_TIMESTAMP == max_submit_timestamp) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR, "invalid argument", K(ret), K(max_submit_timestamp));
 | 
						|
  } else if (max_submit_timestamp > max_submit_timestamp_) {
 | 
						|
    max_submit_timestamp_ = max_submit_timestamp;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObCommitInfoBlockHandler::update_info(
 | 
						|
    const common::ObPartitionKey& partition_key, const uint64_t log_id, const int64_t submit_timestamp)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObCommitInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else if (!partition_key.is_valid() || OB_INVALID_ID == log_id || OB_INVALID_TIMESTAMP == submit_timestamp ||
 | 
						|
             0 == submit_timestamp) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR, "invalid argument", K(ret), K(partition_key), K(log_id), K(submit_timestamp));
 | 
						|
  } else {
 | 
						|
    if (submit_timestamp > max_submit_timestamp_) {
 | 
						|
      max_submit_timestamp_ = submit_timestamp;
 | 
						|
    }
 | 
						|
    ret = update_info_hash_v2_(partition_key, log_id);
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
ObIndexInfoBlockHandler::ObIndexInfoBlockHandler() : is_inited_(false)
 | 
						|
{}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::init(void)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (is_inited_) {
 | 
						|
    ret = OB_INIT_TWICE;
 | 
						|
  } else if (OB_FAIL(info_hash_.init(
 | 
						|
                 ObModIds::OB_CLOG_INFO_BLK_HNDLR, (CLOG_INFO_BLOCK_SIZE_LIMIT) / info_hash_.item_size()))) {
 | 
						|
    CLOG_LOG(ERROR, "info_hash init failed", K(ret));
 | 
						|
  } else if (OB_FAIL(info_hash_v2_.init(
 | 
						|
                 ObModIds::OB_CLOG_INFO_BLK_HNDLR, (CLOG_INFO_BLOCK_SIZE_LIMIT) / info_hash_v2_.item_size()))) {
 | 
						|
    CLOG_LOG(ERROR, "info_hash_v2 init failed", K(ret));
 | 
						|
  } else {
 | 
						|
    freeze_version_ = ObVersion(1, 0);
 | 
						|
    is_inited_ = true;
 | 
						|
  }
 | 
						|
  if (!is_inited_) {
 | 
						|
    destroy();
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
void ObIndexInfoBlockHandler::destroy()
 | 
						|
{
 | 
						|
  info_hash_.destroy();
 | 
						|
  info_hash_v2_.destroy();
 | 
						|
  have_info_hash_v2_ = false;
 | 
						|
  is_inited_ = false;
 | 
						|
}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::build_info_block(char* buf, const int64_t buf_len, int64_t& pos)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  TstampArray max_log_tstamp_array;
 | 
						|
 | 
						|
  if (!is_inited_) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObIndexInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else {
 | 
						|
    int64_t new_pos = pos;
 | 
						|
    if (NULL == buf || buf_len < 0 || pos < 0 || pos > buf_len) {
 | 
						|
      ret = OB_INVALID_ARGUMENT;
 | 
						|
    } else if (OB_FAIL(serialization::encode_i16(buf, buf_len, new_pos, INDEX_LOG_INFO_BLOCK_VERSION))) {
 | 
						|
      CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
    } else if (OB_FAIL(freeze_version_.serialize(buf, buf_len, new_pos))) {
 | 
						|
      CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
    } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, info_hash_.size()))) {
 | 
						|
      CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
    } else {
 | 
						|
      InfoEntrySerializeFunctor functor(buf, buf_len, new_pos, max_log_tstamp_array);
 | 
						|
      ret = info_hash_.for_each(functor);
 | 
						|
    }
 | 
						|
    if (OB_SUCC(ret)) {
 | 
						|
      if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, MAGIC_NUMBER))) {
 | 
						|
        CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
      } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, info_hash_v2_.size()))) {
 | 
						|
        CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
      } else {
 | 
						|
        InfoEntrySerializeFunctorV2 functor_v2(buf, buf_len, new_pos);
 | 
						|
        ret = info_hash_v2_.for_each(functor_v2);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // serialize max_log_timestamp
 | 
						|
    if (OB_SUCC(ret)) {
 | 
						|
      int64_t part_number = info_hash_.size();
 | 
						|
      int64_t magic_number_for_max_log_tstamp = MAGIC_NUMBER_FOR_MAX_LOG_TIMESTAMP;
 | 
						|
 | 
						|
      if (OB_UNLIKELY(part_number != max_log_tstamp_array.count())) {
 | 
						|
        CLOG_LOG(WARN,
 | 
						|
            "error unexpected, part_number does not equals to max_log_timestamp array size",
 | 
						|
            K(part_number),
 | 
						|
            K(max_log_tstamp_array.count()));
 | 
						|
        ret = OB_ERR_UNEXPECTED;
 | 
						|
      }
 | 
						|
      // encode magic number
 | 
						|
      else if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, magic_number_for_max_log_tstamp))) {
 | 
						|
        CLOG_LOG(
 | 
						|
            ERROR, "encode magic number failed", K(ret), K(buf_len), K(new_pos), K(magic_number_for_max_log_tstamp));
 | 
						|
      }
 | 
						|
      // encode the number of partition
 | 
						|
      else if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, part_number))) {
 | 
						|
        CLOG_LOG(ERROR, "encode partition number failed", K(ret), K(part_number), K(new_pos), K(buf_len));
 | 
						|
      } else {
 | 
						|
        // encode max_log_timestamp
 | 
						|
        // NOTE: required same order with above
 | 
						|
        for (int64_t index = 0; OB_SUCC(ret) && index < max_log_tstamp_array.count(); index++) {
 | 
						|
          int64_t max_log_timestamp = max_log_tstamp_array.at(index);
 | 
						|
 | 
						|
          if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, max_log_timestamp))) {
 | 
						|
            CLOG_LOG(
 | 
						|
                ERROR, "encode max log timestamp fail", K(ret), K(max_log_timestamp), K(buf), K(buf_len), K(new_pos));
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (OB_SUCC(ret)) {
 | 
						|
      if (OB_FAIL(build_max_submit_timestamp_(buf, buf_len, new_pos))) {
 | 
						|
        CLOG_LOG(ERROR, "build_max_submit_timestamp_ failed", K(ret));
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (OB_SUCC(ret)) {
 | 
						|
      if (OB_FAIL(reset())) {
 | 
						|
        CLOG_LOG(ERROR, "reset failed", K(ret));
 | 
						|
      } else {
 | 
						|
        pos = new_pos;
 | 
						|
      }
 | 
						|
    } else if (OB_EAGAIN == ret) {
 | 
						|
      ret = OB_ERR_UNEXPECTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  CLOG_LOG(INFO, "ilog info block version", K(ret), K(freeze_version_));
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::resolve_info_block(const char* buf, const int64_t buf_len, int64_t& pos)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObPartitionKey* part_array = NULL;
 | 
						|
  int64_t partition_num = 0;
 | 
						|
 | 
						|
  if (!is_inited_) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObIndexInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else {
 | 
						|
    int64_t new_pos = pos;
 | 
						|
    int16_t index_log_info_block_version = 0;
 | 
						|
    if (NULL == buf || buf_len < 0 || pos < 0 || pos > buf_len) {
 | 
						|
      ret = OB_INVALID_ARGUMENT;
 | 
						|
    } else if (OB_FAIL(serialization::decode_i16(buf, buf_len, new_pos, &index_log_info_block_version))) {
 | 
						|
      CLOG_LOG(ERROR, "deserialization failed", K(ret));
 | 
						|
    } else if (index_log_info_block_version != INDEX_LOG_INFO_BLOCK_VERSION) {
 | 
						|
      ret = OB_VERSION_NOT_MATCH;
 | 
						|
      CLOG_LOG(ERROR, "invalid version", K(ret), K(index_log_info_block_version), K(INDEX_LOG_INFO_BLOCK_VERSION));
 | 
						|
    } else if (OB_FAIL(freeze_version_.deserialize(buf, buf_len, new_pos))) {
 | 
						|
      CLOG_LOG(ERROR, "deserialization failed", K(ret), K(buf), K(buf_len), K(new_pos));
 | 
						|
    } else if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, &partition_num))) {
 | 
						|
      CLOG_LOG(ERROR, "deserialization failed", K(ret));
 | 
						|
    } else if (OB_FAIL(info_hash_.shrink_size(partition_num + 1))) {
 | 
						|
      CLOG_LOG(ERROR, "info_hash shrink fail", K(ret), K(partition_num));
 | 
						|
    } else {
 | 
						|
      InfoEntry entry;
 | 
						|
      int64_t part_array_size = (sizeof(ObPartitionKey) * partition_num);
 | 
						|
 | 
						|
      // alloc a partition array, used to save partition_key during serialization
 | 
						|
      if (partition_num > 0) {
 | 
						|
        ObMemAttr mem_attr(OB_SERVER_TENANT_ID, ObModIds::OB_CLOG_INFO_BLK_HNDLR);
 | 
						|
        part_array = static_cast<ObPartitionKey*>(ob_malloc(part_array_size, mem_attr));
 | 
						|
        if (OB_ISNULL(part_array)) {
 | 
						|
          CLOG_LOG(WARN, "allocate partition array fail", K(partition_num), K(part_array_size));
 | 
						|
          ret = OB_ALLOCATE_MEMORY_FAILED;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
 | 
						|
        uint64_t min_log_id = 0;
 | 
						|
        int64_t min_log_timestamp = 0;
 | 
						|
 | 
						|
        ObPartitionKey* pkey = new (part_array + i) ObPartitionKey();
 | 
						|
 | 
						|
        if (OB_FAIL(pkey->deserialize(buf, buf_len, new_pos))) {
 | 
						|
          CLOG_LOG(ERROR, "deserialization failed", K(ret));
 | 
						|
        } else if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, reinterpret_cast<int64_t*>(&min_log_id)))) {
 | 
						|
          CLOG_LOG(ERROR, "deserialization failed", K(ret));
 | 
						|
        } else if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, &min_log_timestamp))) {
 | 
						|
          CLOG_LOG(ERROR, "deserialization failed", K(ret));
 | 
						|
        } else {
 | 
						|
          entry.reset();
 | 
						|
          entry.min_log_id_ = min_log_id;
 | 
						|
          entry.min_log_timestamp_ = min_log_timestamp;
 | 
						|
          ret = info_hash_.insert(*pkey, entry);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (OB_SUCC(ret)) {
 | 
						|
      int tmp_ret = OB_SUCCESS;
 | 
						|
      // decode max_log_id
 | 
						|
      tmp_ret = resolve_info_hash_v2_(buf, buf_len, new_pos, MAGIC_NUMBER);
 | 
						|
      if (OB_SUCCESS != tmp_ret) {
 | 
						|
        CLOG_LOG(INFO, "resolve_info_hash_v2_ failed", K(tmp_ret));
 | 
						|
      } else {
 | 
						|
        // decode max_log_timestamp
 | 
						|
        // ignore failure
 | 
						|
        tmp_ret = resolve_max_log_timestamp_(buf, buf_len, new_pos, part_array, partition_num);
 | 
						|
 | 
						|
        if (OB_SUCCESS != tmp_ret) {
 | 
						|
          CLOG_LOG(WARN, "resolve ilog info block max log timestamp fail", K(tmp_ret), K(buf), K(buf_len), K(new_pos));
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (OB_SUCCESS == tmp_ret) {
 | 
						|
        if (OB_SUCCESS != (tmp_ret = resolve_max_submit_timestamp_(buf, buf_len, new_pos))) {
 | 
						|
          CLOG_LOG(INFO, "resolve_max_submit_timestamp_ failed", K(tmp_ret));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    pos = new_pos;
 | 
						|
  }
 | 
						|
 | 
						|
  // reclaime memory
 | 
						|
  if (OB_NOT_NULL(part_array)) {
 | 
						|
    ob_free(part_array);
 | 
						|
    part_array = NULL;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
// if the number of partition is zero, part_array can be empty
 | 
						|
int ObIndexInfoBlockHandler::resolve_max_log_timestamp_(const char* buf, const int64_t buf_len, int64_t& pos,
 | 
						|
    const common::ObPartitionKey* part_array, const int64_t part_number)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  int64_t magic_num = 0;
 | 
						|
  int64_t new_partition_num = 0;
 | 
						|
  int64_t new_pos = pos;
 | 
						|
  const int64_t expect_magic_num = MAGIC_NUMBER_FOR_MAX_LOG_TIMESTAMP;
 | 
						|
 | 
						|
  if (OB_UNLIKELY(part_number > 0 && NULL == part_array)) {
 | 
						|
    CLOG_LOG(WARN, "invalid argument", K(part_number), K(part_array));
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
  } else if (new_pos >= buf_len) {
 | 
						|
    CLOG_LOG(WARN, "max log timestamp is not recorded in ilog info block", K(buf_len), K(pos), K(buf));
 | 
						|
    ret = OB_SUCCESS;
 | 
						|
  } else if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, &magic_num))) {
 | 
						|
    CLOG_LOG(WARN, "decode magic number fail", K(ret), K(buf), K(buf_len), K(new_pos));
 | 
						|
  }
 | 
						|
  // check magic number
 | 
						|
  else if (OB_UNLIKELY(magic_num != expect_magic_num)) {
 | 
						|
    CLOG_LOG(INFO, "magic number not match", K(magic_num), K(expect_magic_num));
 | 
						|
    ret = OB_INVALID_DATA;
 | 
						|
  } else if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, &new_partition_num))) {
 | 
						|
    CLOG_LOG(WARN, "decode partition number failed", K(ret), K(buf), K(buf_len), K(new_pos));
 | 
						|
  }
 | 
						|
  // check the number of partition
 | 
						|
  else if (OB_UNLIKELY(new_partition_num != part_number)) {
 | 
						|
    CLOG_LOG(WARN, "partition number does not match", K(ret), K(new_partition_num), K(part_number));
 | 
						|
    ret = OB_INVALID_DATA;
 | 
						|
  } else {
 | 
						|
    // decode max log timestamp
 | 
						|
    for (int64_t i = 0; i < new_partition_num && OB_SUCC(ret); ++i) {
 | 
						|
      int64_t max_log_timestamp = 0;
 | 
						|
      InfoEntry entry;
 | 
						|
      const ObPartitionKey& pkey = part_array[i];
 | 
						|
 | 
						|
      if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, &max_log_timestamp))) {
 | 
						|
        CLOG_LOG(WARN, "decode max log timestamp fail", K(ret), K(i), K(new_partition_num), K(buf_len), K(new_pos));
 | 
						|
      } else if (OB_FAIL(info_hash_.get(pkey, entry))) {
 | 
						|
        CLOG_LOG(WARN, "get info entry from info hash fail", K(ret), K(pkey));
 | 
						|
      } else {
 | 
						|
        // update max log timestamp
 | 
						|
        entry.max_log_timestamp_ = max_log_timestamp;
 | 
						|
 | 
						|
        if (OB_FAIL(info_hash_.update(pkey, entry))) {
 | 
						|
          CLOG_LOG(WARN, "update info entry fail", K(ret), K(pkey), K(entry));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  pos = new_pos;
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::reset()
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (!is_inited_) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObIndexInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else {
 | 
						|
    have_info_hash_v2_ = false;
 | 
						|
    info_hash_.reset();
 | 
						|
    info_hash_v2_.reset();
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::update_info(
 | 
						|
    const common::ObPartitionKey& partition_key, const uint64_t log_id, const int64_t submit_timestamp)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObIndexInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else if (OB_UNLIKELY(!partition_key.is_valid()) || OB_UNLIKELY(OB_INVALID_ID == log_id) ||
 | 
						|
             OB_UNLIKELY(OB_INVALID_TIMESTAMP == submit_timestamp) || OB_UNLIKELY(0 == submit_timestamp)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR, "invalid argument", K(ret), K(partition_key), K(log_id), K(submit_timestamp));
 | 
						|
  } else {
 | 
						|
    InfoEntry entry;
 | 
						|
 | 
						|
    if (OB_SUCC(info_hash_.get(partition_key, entry))) {
 | 
						|
      if (log_id <= entry.min_log_id_) {
 | 
						|
        ret = OB_ERR_UNEXPECTED;
 | 
						|
        CLOG_LOG(WARN, "update ilog info block with smaller log id", K(partition_key), K(log_id), K(entry.min_log_id_));
 | 
						|
      } else if (OB_INVALID_TIMESTAMP == entry.max_log_timestamp_ || entry.max_log_timestamp_ < submit_timestamp) {
 | 
						|
        // update max log timestamp
 | 
						|
        entry.max_log_timestamp_ = submit_timestamp;
 | 
						|
 | 
						|
        // update info_hash
 | 
						|
        if (OB_FAIL(info_hash_.update(partition_key, entry))) {
 | 
						|
          CLOG_LOG(WARN, "update info hash fail", K(ret), K(partition_key), K(entry));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else if (OB_ENTRY_NOT_EXIST == ret) {
 | 
						|
      ret = OB_SUCCESS;
 | 
						|
      entry.min_log_id_ = log_id;
 | 
						|
      entry.min_log_timestamp_ = submit_timestamp;
 | 
						|
      entry.max_log_timestamp_ = submit_timestamp;
 | 
						|
      if (OB_FAIL(info_hash_.insert(partition_key, entry))) {
 | 
						|
        CLOG_LOG(WARN, "info_hash_.insert fail", K(ret), K(partition_key), K(entry));
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      CLOG_LOG(WARN, "info_hash get fail", K(ret), K(partition_key), K(entry));
 | 
						|
    }
 | 
						|
 | 
						|
    CLOG_LOG(TRACE, "update ilog info block", K(ret), K(partition_key), K(log_id), K(submit_timestamp), K(entry));
 | 
						|
 | 
						|
    if (OB_SUCC(ret)) {
 | 
						|
      ret = update_info_hash_v2_(partition_key, log_id);
 | 
						|
    }
 | 
						|
    if (submit_timestamp > max_submit_timestamp_) {
 | 
						|
      max_submit_timestamp_ = submit_timestamp;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (OB_FAIL(ret)) {
 | 
						|
    CLOG_LOG(ERROR, "update_info failed", K(ret), K(partition_key), K(log_id), K(submit_timestamp));
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::update_info(const int64_t max_submit_timestamp)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObIndexInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else if (OB_INVALID_TIMESTAMP == max_submit_timestamp) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR, "invalid argument", K(ret), K(max_submit_timestamp));
 | 
						|
  } else if (max_submit_timestamp > max_submit_timestamp_) {
 | 
						|
    max_submit_timestamp_ = max_submit_timestamp;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::get_min_log_id(const common::ObPartitionKey& partition_key, uint64_t& min_log_id)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  min_log_id = OB_INVALID_ID;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObIndexInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else {
 | 
						|
    int64_t submit_timestamp = OB_INVALID_TIMESTAMP;
 | 
						|
    if (OB_FAIL(get_min_log_id(partition_key, min_log_id, submit_timestamp)) && OB_ENTRY_NOT_EXIST != ret) {
 | 
						|
      CLOG_LOG(WARN, "get_min_log_id failed", K(ret), K(partition_key), K(min_log_id));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIndexInfoBlockHandler::get_min_log_id(
 | 
						|
    const common::ObPartitionKey& partition_key, uint64_t& min_log_id, int64_t& submit_timestamp)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  min_log_id = OB_INVALID_ID;
 | 
						|
  submit_timestamp = OB_INVALID_TIMESTAMP;
 | 
						|
  if (IS_NOT_INIT) {
 | 
						|
    ret = OB_NOT_INIT;
 | 
						|
    CLOG_LOG(ERROR, "ObIndexInfoBlockHandler is not inited", K(ret));
 | 
						|
  } else {
 | 
						|
    InfoEntry entry;
 | 
						|
    entry.reset();
 | 
						|
    if (OB_SUCC(info_hash_.get(partition_key, entry))) {
 | 
						|
      min_log_id = entry.min_log_id_;
 | 
						|
      submit_timestamp = entry.min_log_timestamp_;
 | 
						|
    }
 | 
						|
    if (OB_SUCCESS != ret && OB_ENTRY_NOT_EXIST != ret) {
 | 
						|
      CLOG_LOG(ERROR, "info_hash get failed", K(partition_key), K(ret));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::can_skip_based_on_submit_timestamp(const int64_t min_submit_timestamp, bool& can_skip)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
 | 
						|
  if (OB_INVALID_TIMESTAMP == min_submit_timestamp) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR, "invalid argument", K(ret), K(min_submit_timestamp));
 | 
						|
  } else if (OB_INVALID_TIMESTAMP == max_submit_timestamp_) {
 | 
						|
    can_skip = false;
 | 
						|
    ret = OB_SUCCESS;
 | 
						|
    CLOG_LOG(INFO,
 | 
						|
        "invalid max_submit_timestamp, cannot skip this file",
 | 
						|
        K(ret),
 | 
						|
        K(min_submit_timestamp),
 | 
						|
        K(max_submit_timestamp_));
 | 
						|
  } else {
 | 
						|
    can_skip = (min_submit_timestamp > max_submit_timestamp_);
 | 
						|
  }
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::record_need_freeze_partition(
 | 
						|
    NeedFreezePartitionArray& partition_array, const common::ObPartitionKey& partition_key, const uint64_t log_id)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (!partition_key.is_valid() || OB_INVALID_ID == log_id) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(WARN, "invalid arguments", K(ret), K(partition_key), K(log_id));
 | 
						|
  } else {
 | 
						|
    NeedFreezePartition partition;
 | 
						|
    partition.set_partition_key(partition_key);
 | 
						|
    partition.set_log_id(log_id);
 | 
						|
    if (OB_FAIL(partition_array.push_back(partition))) {
 | 
						|
      CLOG_LOG(WARN, "partition_array push_back failed", K(ret), K(partition_key), K(log_id));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::get_min_submit_timestamp(
 | 
						|
    storage::ObPartitionService* partition_service, int64_t& min_submit_timestamp)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObIPartitionGroup* partition = NULL;
 | 
						|
  ObIPartitionGroupIterator* partition_iter = NULL;
 | 
						|
  ObPartitionKey partition_key;
 | 
						|
 | 
						|
  if (OB_ISNULL(partition_service)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR, "invalid argument", K(partition_service));
 | 
						|
  } else if (NULL == (partition_iter = partition_service->alloc_pg_iter())) {
 | 
						|
    ret = OB_ALLOCATE_MEMORY_FAILED;
 | 
						|
    CLOG_LOG(WARN, "partition mgr alloc scan iter failed");
 | 
						|
  }
 | 
						|
  int64_t min_ts = INT64_MAX;
 | 
						|
  while (OB_SUCC(ret)) {
 | 
						|
    if (OB_FAIL(partition_iter->get_next(partition)) || NULL == partition) {
 | 
						|
      // do nothing
 | 
						|
      if (OB_ITER_END != ret) {
 | 
						|
        CLOG_LOG(WARN, "partition_iter get_next failed", K(ret), K(partition));
 | 
						|
      }
 | 
						|
    } else if (!partition->is_valid()) {
 | 
						|
      CLOG_LOG(WARN,
 | 
						|
          "partition is invalid while scanning",
 | 
						|
          "partition key",
 | 
						|
          partition->get_partition_key(),
 | 
						|
          "is_valid",
 | 
						|
          partition->is_valid(),
 | 
						|
          "state",
 | 
						|
          partition->get_partition_state());
 | 
						|
    } else {
 | 
						|
      uint64_t unused = 0;
 | 
						|
      int64_t submit_timestamp = OB_INVALID_TIMESTAMP;
 | 
						|
      partition_key = partition->get_partition_key();
 | 
						|
      if (OB_FAIL(partition->get_saved_last_log_info(unused, submit_timestamp))) {
 | 
						|
        CLOG_LOG(WARN, "partition get static submit_timestamp error", K(ret), K(partition_key));
 | 
						|
      } else if (OB_INVALID_TIMESTAMP == submit_timestamp) {
 | 
						|
        ret = OB_ERR_UNEXPECTED;
 | 
						|
        CLOG_LOG(ERROR, "partition last submit timestamp is invalid", K(ret), K(partition_key), K(submit_timestamp));
 | 
						|
      } else if (min_ts > submit_timestamp) {
 | 
						|
        min_ts = submit_timestamp;
 | 
						|
        if (REACH_TIME_INTERVAL(10 * 1000 * 1000)) {
 | 
						|
          CLOG_LOG(INFO, "get_sstore_submit_timestamp", K(partition_key), K(ret), K(submit_timestamp), K(min_ts));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (NULL != partition_iter) {
 | 
						|
    partition_service->revert_pg_iter(partition_iter);
 | 
						|
  }
 | 
						|
  if (OB_ITER_END == ret) {
 | 
						|
    min_submit_timestamp = min_ts;
 | 
						|
    ret = OB_SUCCESS;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::get_max_submit_timestamp(int64_t& max_submit_timestamp) const
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  max_submit_timestamp = max_submit_timestamp_;
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::build_max_submit_timestamp_(char* buf, const int64_t buf_len, int64_t& pos)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  int64_t new_pos = pos;
 | 
						|
  if (NULL == buf || buf_len < 0 || pos < 0 || pos > buf_len) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
  } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, MAGIC_NUMBER_FOR_MAX_SUBMIT_TIMESTAMP))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
  } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, new_pos, max_submit_timestamp_))) {
 | 
						|
    CLOG_LOG(ERROR, "serialization failed", K(ret));
 | 
						|
  }
 | 
						|
  if (OB_SUCC(ret)) {
 | 
						|
    pos = new_pos;
 | 
						|
  }
 | 
						|
  CLOG_LOG(TRACE, "build_max_submit_timestamp_ finished", K(ret), K(max_submit_timestamp_));
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::resolve_max_submit_timestamp_(const char* buf, const int64_t buf_len, int64_t& pos)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  int64_t new_pos = pos;
 | 
						|
  int64_t magic_num = 0;
 | 
						|
  int64_t submit_timestamp = 0;
 | 
						|
  const int64_t expected_magic_number = MAGIC_NUMBER_FOR_MAX_SUBMIT_TIMESTAMP;
 | 
						|
 | 
						|
  if (NULL == buf || buf_len < 0 || pos < 0 || pos > buf_len) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
  } else if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, &magic_num))) {
 | 
						|
    CLOG_LOG(WARN, "deserialization failed", K(ret), K(buf), K(buf_len), K(new_pos));
 | 
						|
  } else if (magic_num != expected_magic_number) {
 | 
						|
    ret = OB_INVALID_DATA;
 | 
						|
    CLOG_LOG(INFO, "magic number not match", K(magic_num), "expected_magic_number", expected_magic_number);
 | 
						|
  } else if (OB_FAIL(serialization::decode_i64(buf, buf_len, new_pos, &submit_timestamp))) {
 | 
						|
    CLOG_LOG(WARN, "deserialization failed", K(ret), K(buf), K(buf_len), K(new_pos));
 | 
						|
  } else {
 | 
						|
    max_submit_timestamp_ = submit_timestamp;
 | 
						|
    pos = new_pos;
 | 
						|
  }
 | 
						|
  CLOG_LOG(TRACE, "resolve_max_submit_timestamp_ finished", K(ret), K(max_submit_timestamp_));
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
ObIInfoBlockHandler::CheckFileCanBeSkippedFunctor::CheckFileCanBeSkippedFunctor(
 | 
						|
    storage::ObPartitionService* partition_service)
 | 
						|
    : partition_service_(partition_service),
 | 
						|
      check_partition_not_exist_time_(OB_INVALID_TIMESTAMP),
 | 
						|
      can_skip_(false),
 | 
						|
      ret_code_(OB_SUCCESS)
 | 
						|
{}
 | 
						|
 | 
						|
bool ObIInfoBlockHandler::CheckFileCanBeSkippedFunctor::operator()(
 | 
						|
    const common::ObPartitionKey& partition_key, const InfoEntryV2& entry_v2)
 | 
						|
{
 | 
						|
  int ret = OB_ERR_UNEXPECTED;
 | 
						|
  uint64_t last_replay_log_id = OB_INVALID_ID;
 | 
						|
  int64_t unused = 0;
 | 
						|
  ObIPartitionGroupGuard partition_guard;
 | 
						|
  ObIPartitionGroup* partition = NULL;
 | 
						|
  ObIPartitionLogService* pls = NULL;
 | 
						|
  if (!partition_key.is_valid()) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(WARN, "partitio_key is invalid", K(ret), K(partition_key));
 | 
						|
  } else if (OB_ISNULL(partition_service_)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(WARN, "partition_service_ is nullptr", K(ret), K(partition_key));
 | 
						|
  } else if (OB_FAIL(partition_service_->get_partition(partition_key, partition_guard))) {
 | 
						|
    // partition has been garbage collect, but the corresponding file still exists
 | 
						|
    if (ret != OB_PARTITION_NOT_EXIST) {
 | 
						|
      CLOG_LOG(WARN, "get_partition failed", K(ret), K(partition_key));
 | 
						|
    } else {
 | 
						|
      ret = OB_SUCCESS;
 | 
						|
      if (partition_reach_time_interval(10 * 1000, check_partition_not_exist_time_)) {
 | 
						|
        CLOG_LOG(INFO, "partition may be gc, but clog file still exist", K(ret), K(partition_key));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else if (OB_ISNULL(partition = partition_guard.get_partition_group())) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    CLOG_LOG(WARN, "get_partition_group failed", K(ret), K(partition_key));
 | 
						|
  } else if (OB_ISNULL(pls = partition->get_log_service())) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    CLOG_LOG(WARN, "get_log_service failed", K(ret), K(partition_key), K(pls));
 | 
						|
  } else if (OB_FAIL(partition->get_saved_last_log_info(last_replay_log_id, unused))) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    CLOG_LOG(WARN, "partition get_last_replay_log_id failed", K(ret), K(partition_key));
 | 
						|
  } else if (OB_INVALID_ID == last_replay_log_id) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(WARN, "last_replay_log_id is invalid", K(ret), K(partition_key), K(last_replay_log_id));
 | 
						|
  } else {
 | 
						|
    ret = OB_SUCCESS;
 | 
						|
    if (last_replay_log_id >= entry_v2.max_log_id_) {
 | 
						|
      can_skip_ = true;
 | 
						|
    } else {
 | 
						|
      can_skip_ = false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  ret_code_ = ret;
 | 
						|
  // when any partition does not meet the criteria, exit the loop
 | 
						|
  return OB_SUCCESS == ret && can_skip_ == true;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::can_skip_based_on_log_id(storage::ObPartitionService* partition_service, bool& can_skip)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (false == have_info_hash_v2_) {
 | 
						|
    can_skip = false;
 | 
						|
  } else {
 | 
						|
    if (OB_ISNULL(partition_service)) {
 | 
						|
      ret = OB_INVALID_ARGUMENT;
 | 
						|
      CLOG_LOG(WARN, "invalid partition_service", K(ret), K(partition_service));
 | 
						|
    } else {
 | 
						|
      CheckFileCanBeSkippedFunctor functor(partition_service);
 | 
						|
      if (OB_FAIL(info_hash_v2_.for_each(functor))) {
 | 
						|
        // get real error code
 | 
						|
        ret = functor.get_ret_code();
 | 
						|
        CLOG_LOG(WARN, "traverse info_hash_v2_ failed", K(ret));
 | 
						|
      } else {
 | 
						|
        can_skip = functor.can_skip();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::can_skip_based_on_log_id(storage::ObPartitionService* partition_service,
 | 
						|
    NeedFreezePartitionArray& partition_array, const bool need_record, bool& can_skip)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  bool is_strict_recycle_mode = false;
 | 
						|
  is_strict_recycle_mode = ObServerConfig::get_instance()._ob_enable_log_replica_strict_recycle_mode;
 | 
						|
  if (false == have_info_hash_v2_) {
 | 
						|
    can_skip = false;
 | 
						|
  } else {
 | 
						|
    if (OB_ISNULL(partition_service)) {
 | 
						|
      ret = OB_INVALID_ARGUMENT;
 | 
						|
    } else {
 | 
						|
      CheckPartitionNeedFreezeFunctor functor(partition_service, partition_array, need_record, is_strict_recycle_mode);
 | 
						|
      if (OB_FAIL(info_hash_v2_.for_each(functor))) {
 | 
						|
        // get real error code
 | 
						|
        ret = functor.get_ret_code();
 | 
						|
        CLOG_LOG(ERROR, "traverse info_hash_v2_ failed", K(ret));
 | 
						|
      } else {
 | 
						|
        can_skip = functor.can_skip();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
ObIInfoBlockHandler::CheckPartitionNeedFreezeFunctor::CheckPartitionNeedFreezeFunctor(
 | 
						|
    ObPartitionService* partition_service, NeedFreezePartitionArray& partition_array, const bool need_record,
 | 
						|
    const bool is_strict_recycle_mode)
 | 
						|
    : partition_service_(partition_service),
 | 
						|
      partition_array_(partition_array),
 | 
						|
      check_partition_not_exist_time_(OB_INVALID_TIMESTAMP),
 | 
						|
      ret_code_(OB_SUCCESS),
 | 
						|
      need_record_(need_record),
 | 
						|
      is_strict_recycle_mode_(is_strict_recycle_mode),
 | 
						|
      can_skip_(true),
 | 
						|
      is_log_print_(false)
 | 
						|
{}
 | 
						|
 | 
						|
bool ObIInfoBlockHandler::CheckPartitionNeedFreezeFunctor::operator()(
 | 
						|
    const common::ObPartitionKey& partition_key, const InfoEntryV2& entry_v2)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  uint64_t last_replay_log_id = OB_INVALID_ID;
 | 
						|
  int64_t unused = 0;
 | 
						|
  ObIPartitionGroupGuard partition_guard;
 | 
						|
  ObIPartitionGroup* partition = NULL;
 | 
						|
  ObIPartitionLogService* pls = NULL;
 | 
						|
  ObReplicaType replica_type = REPLICA_TYPE_MAX;
 | 
						|
  if (!partition_key.is_valid()) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(WARN, "partitio_key is invalid", K(ret), K(partition_key));
 | 
						|
  } else if (OB_ISNULL(partition_service_)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(WARN, "partition_service_ is nullptr", K(ret), K(partition_key));
 | 
						|
  } else if (OB_FAIL(partition_service_->get_partition(partition_key, partition_guard))) {
 | 
						|
    // partition has been garbage collect, but the corresponding file still exists.
 | 
						|
    if (ret != OB_PARTITION_NOT_EXIST) {
 | 
						|
      CLOG_LOG(WARN, "get_partition failed", K(ret), K(partition_key));
 | 
						|
    } else {
 | 
						|
      ret = OB_SUCCESS;
 | 
						|
      if (partition_reach_time_interval(10 * 1000, check_partition_not_exist_time_)) {
 | 
						|
        CLOG_LOG(INFO, "partition may be gc, but clog file still exist", K(ret), K(partition_key));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else if (OB_ISNULL(partition = partition_guard.get_partition_group())) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    CLOG_LOG(ERROR, "get_partition_group failed", K(ret), K(partition_key));
 | 
						|
  } else if (!partition->is_valid() || OB_ISNULL(pls = partition->get_log_service())) {
 | 
						|
    CLOG_LOG(WARN,
 | 
						|
        "get_log_service failed",
 | 
						|
        K(ret),
 | 
						|
        K(partition_key),
 | 
						|
        "is_valid",
 | 
						|
        partition->is_valid(),
 | 
						|
        "state",
 | 
						|
        partition->get_partition_state());
 | 
						|
  } else if (REPLICA_TYPE_MAX == (replica_type = pls->get_replica_type())) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR, "invalid replica_type", K(ret), K(partition_key), K(pls));
 | 
						|
  } else if (OB_FAIL(partition->get_saved_last_log_info(last_replay_log_id, unused))) {
 | 
						|
    CLOG_LOG(ERROR, "partition get_last_replay_log_id failed", K(ret), K(partition_key));
 | 
						|
  } else if (OB_INVALID_ID == last_replay_log_id) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR, "last_replay_log_id is invalid", K(ret), K(last_replay_log_id));
 | 
						|
  } else if (OB_FAIL(do_check_partition_need_freeze_(
 | 
						|
                 partition, pls, partition_key, replica_type, last_replay_log_id, entry_v2.max_log_id_))) {
 | 
						|
    CLOG_LOG(ERROR,
 | 
						|
        "do_check_partition_need_freeze_ failed",
 | 
						|
        K(ret),
 | 
						|
        K(partition_key),
 | 
						|
        K(replica_type),
 | 
						|
        K(last_replay_log_id),
 | 
						|
        K(entry_v2.max_log_id_));
 | 
						|
  }
 | 
						|
  ret_code_ = ret;
 | 
						|
  return ret == OB_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::CheckPartitionNeedFreezeFunctor::do_check_partition_need_freeze_(
 | 
						|
    storage::ObIPartitionGroup* partition, ObIPartitionLogService* pls, const common::ObPartitionKey& partition_key,
 | 
						|
    const ObReplicaType replica_type, const int64_t last_replay_log_id, const int64_t max_log_id)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (!partition->is_valid() || OB_ISNULL(pls)) {
 | 
						|
    CLOG_LOG(WARN,
 | 
						|
        "do_can_skip_based_on_log_id_ invalid argument",
 | 
						|
        K(ret),
 | 
						|
        K(partition->is_valid()),
 | 
						|
        K(pls),
 | 
						|
        K(partition_key),
 | 
						|
        K(last_replay_log_id),
 | 
						|
        K(max_log_id));
 | 
						|
  } else if (last_replay_log_id == OB_INVALID_ID || max_log_id == OB_INVALID_ID) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    CLOG_LOG(ERROR,
 | 
						|
        "last_replay_log_id or max_log_id is invalid",
 | 
						|
        K(ret),
 | 
						|
        K(partition_key),
 | 
						|
        K(last_replay_log_id),
 | 
						|
        K(max_log_id));
 | 
						|
  } else if (REPLICA_TYPE_LOGONLY != replica_type) {
 | 
						|
    if (last_replay_log_id < max_log_id) {
 | 
						|
      can_skip_ = false;
 | 
						|
      if (!is_log_print_) {
 | 
						|
        CLOG_LOG(INFO,
 | 
						|
            "can_skip_based_on_log_id failed because of last_replay_log_id",
 | 
						|
            K(partition_key),
 | 
						|
            K(last_replay_log_id),
 | 
						|
            K(max_log_id),
 | 
						|
            K(replica_type),
 | 
						|
            K(need_record_));
 | 
						|
        is_log_print_ = true;
 | 
						|
      }
 | 
						|
      if (need_record_) {
 | 
						|
        (void)record_need_freeze_partition(partition_array_, partition_key, max_log_id);
 | 
						|
      }
 | 
						|
    } else if (REPLICA_TYPE_FULL == replica_type) {
 | 
						|
      if (OB_FAIL(
 | 
						|
              do_check_full_partition_need_freeze_(partition, pls, partition_key, last_replay_log_id, max_log_id)) &&
 | 
						|
          OB_EAGAIN != ret) {
 | 
						|
        CLOG_LOG(ERROR,
 | 
						|
            "do_check_full_partition_need_freeze_ failed",
 | 
						|
            K(ret),
 | 
						|
            K(partition_key),
 | 
						|
            K(last_replay_log_id),
 | 
						|
            K(max_log_id));
 | 
						|
      } else {
 | 
						|
        ret = OB_SUCCESS;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
    }
 | 
						|
  } else if (REPLICA_TYPE_LOGONLY == replica_type) {
 | 
						|
    if (OB_FAIL(do_check_log_only_partition_need_freeze_(pls, partition_key, last_replay_log_id, max_log_id))) {
 | 
						|
      CLOG_LOG(ERROR,
 | 
						|
          "do_check_log_only_partition_need_freeze_ failed",
 | 
						|
          K(ret),
 | 
						|
          K(partition_key),
 | 
						|
          K(last_replay_log_id),
 | 
						|
          K(max_log_id));
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    CLOG_LOG(WARN, "invalid replica type", K(ret), K(partition_key), K(replica_type));
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObIInfoBlockHandler::CheckPartitionNeedFreezeFunctor::do_check_full_partition_need_freeze_(
 | 
						|
    storage::ObIPartitionGroup* partition, ObIPartitionLogService* pls, const common::ObPartitionKey& partition_key,
 | 
						|
    const int64_t last_replay_log_id, const int64_t max_log_id)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (!partition->is_valid() || OB_ISNULL(pls) || !partition_key.is_valid() || OB_INVALID_ID == last_replay_log_id) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR,
 | 
						|
        "do_check_full_partition_need_freeze_ invalid argument",
 | 
						|
        K(ret),
 | 
						|
        K(pls),
 | 
						|
        K(partition_key),
 | 
						|
        K(last_replay_log_id),
 | 
						|
        K(max_log_id));
 | 
						|
  } else if ((OB_SYS_TENANT_ID != partition_key.get_tenant_id()) && ObServerConfig::get_instance().enable_log_archive &&
 | 
						|
             ObServerConfig::get_instance().backup_log_archive_option.is_mandatory() &&
 | 
						|
             (!partition->get_pg_storage().is_restore())) {
 | 
						|
    // TODO: only limit log collect for full replica, the case of read only replica revert
 | 
						|
    // to full replica, and then do it together
 | 
						|
    ObLogArchiveBackupInfo info;
 | 
						|
    uint64_t last_archived_log_id = OB_INVALID_ID;
 | 
						|
    if (OB_FAIL(ObBackupInfoMgr::get_instance().get_log_archive_backup_info(info))) {
 | 
						|
      CLOG_LOG(WARN, "failed to get_log_archive_backup_info", K(partition_key), KR(ret));
 | 
						|
      // five states of archive
 | 
						|
      // 1. BEGINING and DOING, means that archive has started, log file can be reclaimed need limit by
 | 
						|
      // last_archived_log_id
 | 
						|
      // 2. INVALID, means that archive may be had started or stopped, cann't reclaime the log file, need
 | 
						|
      // wati next round
 | 
						|
      // 3. STOPING and STOPED, means that archive has stopped
 | 
						|
    } else if (ObLogArchiveStatus::STATUS::BEGINNING == info.status_.status_ ||
 | 
						|
               ObLogArchiveStatus::STATUS::DOING == info.status_.status_) {
 | 
						|
      if (OB_FAIL(
 | 
						|
              pls->get_last_archived_log_id(info.status_.incarnation_, info.status_.round_, last_archived_log_id))) {
 | 
						|
        CLOG_LOG(WARN, "failed to get_log_archive_backup_info", K(partition_key), K(info), KR(ret));
 | 
						|
      } else if (OB_INVALID_ID == last_archived_log_id || last_archived_log_id < max_log_id) {
 | 
						|
        can_skip_ = false;
 | 
						|
        if (!is_log_print_) {
 | 
						|
          CLOG_LOG(INFO,
 | 
						|
              "can_skip_based_on_log_id failed because of last_archive_log_id",
 | 
						|
              K(partition_key),
 | 
						|
              K(last_replay_log_id),
 | 
						|
              K(last_archived_log_id),
 | 
						|
              K(info),
 | 
						|
              K(max_log_id),
 | 
						|
              K(need_record_));
 | 
						|
          is_log_print_ = true;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
      }
 | 
						|
    } else if (ObLogArchiveStatus::STATUS::INVALID == info.status_.status_) {
 | 
						|
      // if can't get ObLogArchiveStatus, closing archive by set configuration can
 | 
						|
      // solve the problem of log file can't be reclaimed.
 | 
						|
      can_skip_ = false;
 | 
						|
      CLOG_LOG(INFO, "archive has enabled, may acquire stale inner table info", K(partition_key));
 | 
						|
    } else {
 | 
						|
    }
 | 
						|
    if (OB_FAIL(ret)) {
 | 
						|
      can_skip_ = false;
 | 
						|
      CLOG_LOG(INFO,
 | 
						|
          "can_skip_based_on_log_id failed because of last_archive_log_id",
 | 
						|
          KR(ret),
 | 
						|
          K(partition_key),
 | 
						|
          K(last_replay_log_id),
 | 
						|
          K(last_archived_log_id),
 | 
						|
          K(max_log_id),
 | 
						|
          K(need_record_));
 | 
						|
      is_log_print_ = true;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
// description: for log only replica, can't reclaime log file when last_replay_log_id is greater than
 | 
						|
//              max_log_id.
 | 
						|
//
 | 
						|
// reasons: log only replica doesn't have baseline data, when change 3f+2l to 1f+2l, data may be loose.
 | 
						|
// assume ABC are full replicas, DE are log only replicas, ABDE set last_replay_log_id as 100, however,
 | 
						|
// C's last_replay_log_id is 50. meanwhile, AB offline, DE's log have been recalimed, C becomes leader,
 | 
						|
// logs between 50-100 will lose.
 | 
						|
//
 | 
						|
// solution: limit log collection for log replicas. when need reclaime logs on log only replica, should
 | 
						|
// determine whether the min_confirmed_log_id of majority full replicas, is greater than or equal to
 | 
						|
// max_log_id in the log file which need to be reclaimed.
 | 
						|
int ObIInfoBlockHandler::CheckPartitionNeedFreezeFunctor::do_check_log_only_partition_need_freeze_(
 | 
						|
    ObIPartitionLogService* pls, const common::ObPartitionKey& partition_key, const int64_t last_replay_log_id,
 | 
						|
    const int64_t max_log_id)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  uint64_t recycable_log_id = 0;
 | 
						|
  bool is_offline = false;
 | 
						|
  if (OB_ISNULL(pls) || !partition_key.is_valid() || OB_INVALID_ID == last_replay_log_id) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    CLOG_LOG(ERROR,
 | 
						|
        "do_check_log_only_partition_need_freeze_ invalid argument",
 | 
						|
        K(ret),
 | 
						|
        K(pls),
 | 
						|
        K(partition_key),
 | 
						|
        K(last_replay_log_id),
 | 
						|
        K(max_log_id));
 | 
						|
  } else if (OB_FAIL(pls->is_offline(is_offline))) {
 | 
						|
    CLOG_LOG(ERROR, "is_offline failed", K(ret));
 | 
						|
  } else if (OB_FAIL(pls->get_recyclable_log_id(recycable_log_id))) {
 | 
						|
    CLOG_LOG(ERROR, "get_recyclable_log_id failed", K(ret), K(partition_key), K(last_replay_log_id), K(max_log_id));
 | 
						|
  } else if (last_replay_log_id >= max_log_id &&
 | 
						|
             (is_offline || !is_strict_recycle_mode_ || recycable_log_id >= max_log_id)) {
 | 
						|
    // do nothing
 | 
						|
  } else {
 | 
						|
    can_skip_ = false;
 | 
						|
    if (!is_log_print_) {
 | 
						|
      CLOG_LOG(INFO,
 | 
						|
          "do_check_log_only_partition_need_freeze_ false",
 | 
						|
          K(partition_key),
 | 
						|
          K(last_replay_log_id),
 | 
						|
          K(max_log_id),
 | 
						|
          K(recycable_log_id),
 | 
						|
          K(need_record_));
 | 
						|
      is_log_print_ = true;
 | 
						|
    }
 | 
						|
    if (last_replay_log_id < max_log_id && need_record_) {
 | 
						|
      (void)record_need_freeze_partition(partition_array_, partition_key, max_log_id);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace clog
 | 
						|
}  // namespace oceanbase
 |