<gh_stars>0
/**
 * 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 <gtest/gtest.h>
#include "storage/blocksstable/ob_data_buffer.h"
#define protected public
#define private public
#include "storage/blocksstable/ob_macro_block_common_header.h"
#include "storage/blocksstable/ob_block_sstable_struct.h"
#include "./ob_macro_meta_generate.h"

namespace oceanbase {
using namespace common;
namespace blocksstable {

bool check_meta_entry(ObSuperBlockV2::MetaEntry& meta_entry, const int64_t block_idx, const int64_t log_seq,
    const int64_t file_id, const int64_t file_size)
{
  return meta_entry.block_index_ == block_idx && meta_entry.log_seq_ == log_seq && meta_entry.file_id_ == file_id &&
         meta_entry.file_size_ == file_size;
}

struct SuperBlock20 {
  SuperBlock20();
  static const int64_t MAX_BACKUP_META_COUNT = 2;
  static const int64_t SUPER_BLOCK_RESERVED_COUNT = 7;
  static const int64_t MAX_SUPER_BLOCK_SIZE = 1 << 12;

  int32_t header_size_;
  int32_t version_;
  int32_t magic_;  // magic number
  int32_t attr_;   // reserved, set 0

  int64_t create_timestamp_;  // create timestamp
  int64_t modify_timestamp_;  // last modified timestamp
  int64_t macro_block_size_;
  int64_t total_macro_block_count_;
  int64_t reserved_block_count_;
  int64_t free_macro_block_count_;
  int64_t first_macro_block_;
  int64_t first_free_block_index_;
  int64_t total_file_size_;

  int64_t backup_meta_count_;
  int64_t backup_meta_blocks_[MAX_BACKUP_META_COUNT];

  int64_t macro_block_meta_entry_block_index_;  // entry of macro block meta blocks.
  int64_t partition_meta_entry_block_index_;    // entry of partition meta blocks.
  common::ObLogCursor replay_start_point_;
  int64_t table_mgr_meta_entry_block_index_;  // entry of table mgr macro block meta blocks.
  int64_t partition_meta_log_seq_;            // log seq of partition meta in checkpoint
  int64_t table_mgr_meta_log_seq_;            // log seq of table mgr meta in checkpoint
  int64_t reserved_[SUPER_BLOCK_RESERVED_COUNT];

  bool is_valid() const;
  TO_STRING_KV(K_(header_size), K_(version), K_(magic), K_(attr), K_(create_timestamp), K_(modify_timestamp),
      K_(macro_block_size), K_(total_macro_block_count), K_(reserved_block_count), K_(free_macro_block_count),
      K_(first_macro_block), K_(first_free_block_index), K_(total_file_size), K_(backup_meta_count),
      "backup_meta_blocks_", common::ObArrayWrap<int64_t>(backup_meta_blocks_, backup_meta_count_),
      K_(macro_block_meta_entry_block_index), K_(partition_meta_entry_block_index),
      K_(table_mgr_meta_entry_block_index), K_(partition_meta_log_seq), K_(table_mgr_meta_log_seq),
      K_(replay_start_point));
  NEED_SERIALIZE_AND_DESERIALIZE;
};
//================================SuperBlock======================================
SuperBlock20::SuperBlock20()
    : header_size_(0),
      version_(0),
      magic_(0),
      attr_(0),
      create_timestamp_(0),
      modify_timestamp_(0),
      macro_block_size_(0),
      total_macro_block_count_(0),
      reserved_block_count_(0),
      free_macro_block_count_(0),
      first_macro_block_(0),
      first_free_block_index_(0),
      total_file_size_(0),
      backup_meta_count_(0),
      macro_block_meta_entry_block_index_(0),
      partition_meta_entry_block_index_(0),
      table_mgr_meta_entry_block_index_(0),
      partition_meta_log_seq_(0),
      table_mgr_meta_log_seq_(0)

{
  memset(backup_meta_blocks_, 0, sizeof(backup_meta_blocks_));
  memset(reserved_, 0, sizeof(reserved_));
}

bool SuperBlock20::is_valid() const
{
  return header_size_ > 0 && version_ >= 0 && SUPER_BLOCK_MAGIC == magic_ && attr_ >= 0 && create_timestamp_ > 0 &&
         modify_timestamp_ >= create_timestamp_ && macro_block_size_ > 0 && total_macro_block_count_ > 0 &&
         reserved_block_count_ >= 0 && free_macro_block_count_ >= 0 && first_macro_block_ >= 0 &&
         first_free_block_index_ > 0 && total_file_size_ >= macro_block_size_ && backup_meta_count_ > 0 &&
         macro_block_meta_entry_block_index_ >= -1 && partition_meta_entry_block_index_ >= -1 &&
         replay_start_point_.is_valid() && table_mgr_meta_entry_block_index_ >= -1 && partition_meta_log_seq_ >= 0 &&
         table_mgr_meta_log_seq_ >= 0;
}

DEFINE_SERIALIZE(SuperBlock20)
{
  int ret = OB_SUCCESS;
  if (NULL == buf || buf_len - pos < header_size_) {
    ret = OB_BUF_NOT_ENOUGH;
    STORAGE_LOG(WARN, "serialize superblock failed.", KP(buf), K(buf_len), K(pos), K(header_size_), K(ret));
  } else {
    MEMCPY(buf + pos, this, sizeof(SuperBlock20));
    pos += header_size_;
  }
  return ret;
}

DEFINE_DESERIALIZE(SuperBlock20)
{
  int ret = OB_SUCCESS;
  // read size first;
  if (NULL == buf || data_len - pos < static_cast<int64_t>(sizeof(int32_t))) {
    ret = OB_INVALID_ARGUMENT;
    STORAGE_LOG(WARN, "invalid arguments.", KP(buf), K(data_len), K(pos), K(header_size_), K(ret));
  } else {
    int32_t header_size = *(reinterpret_cast<const int32_t*>(buf));
    if (data_len - pos < header_size) {
      ret = OB_BUF_NOT_ENOUGH;
      STORAGE_LOG(ERROR, "data_len not enough for header size.", K(data_len), K(pos), K(header_size), K(ret));
    } else {
      MEMCPY(this, buf + pos, sizeof(SuperBlock20));
      pos += header_size;
    }
  }
  return ret;
}

DEFINE_GET_SERIALIZE_SIZE(SuperBlock20)
{
  return sizeof(SuperBlock20);
}

struct SuperBlock14 {
  SuperBlock14();
  static const int64_t MAX_BACKUP_META_COUNT = 2;
  static const int64_t SUPER_BLOCK_RESERVED_COUNT = 10;
  static const int64_t MAX_SUPER_BLOCK_SIZE = 1 << 12;

  int32_t header_size_;
  int32_t version_;
  int32_t magic_;  // magic number
  int32_t attr_;   // reserved, set 0

  int64_t create_timestamp_;  // create timestamp
  int64_t modify_timestamp_;  // last modified timestamp
  int64_t macro_block_size_;
  int64_t total_macro_block_count_;
  int64_t reserved_block_count_;
  int64_t free_macro_block_count_;
  int64_t first_macro_block_;
  int64_t first_free_block_index_;
  int64_t total_file_size_;

  int64_t backup_meta_count_;
  int64_t backup_meta_blocks_[MAX_BACKUP_META_COUNT];

  int64_t macro_block_meta_entry_block_index_;  // entry of macro block meta blocks.
  int64_t partition_meta_entry_block_index_;    // entry of partition meta blocks.
  common::ObLogCursor replay_start_point_;
  int64_t reserved_[SUPER_BLOCK_RESERVED_COUNT];

  bool is_valid() const;
  TO_STRING_KV(K_(header_size), K_(version), K_(magic), K_(attr), K_(create_timestamp), K_(modify_timestamp),
      K_(macro_block_size), K_(total_macro_block_count), K_(reserved_block_count), K_(free_macro_block_count),
      K_(first_macro_block), K_(first_free_block_index), K_(total_file_size), K_(backup_meta_count),
      "backup_meta_blocks_", common::ObArrayWrap<int64_t>(backup_meta_blocks_, backup_meta_count_),
      K_(macro_block_meta_entry_block_index), K_(partition_meta_entry_block_index), K_(replay_start_point));
  NEED_SERIALIZE_AND_DESERIALIZE;
};

//================================SuperBlock======================================
SuperBlock14::SuperBlock14()
    : header_size_(0),
      version_(0),
      magic_(0),
      attr_(0),
      create_timestamp_(0),
      modify_timestamp_(0),
      macro_block_size_(0),
      total_macro_block_count_(0),
      reserved_block_count_(0),
      free_macro_block_count_(0),
      first_macro_block_(0),
      first_free_block_index_(0),
      total_file_size_(0),
      backup_meta_count_(0),
      macro_block_meta_entry_block_index_(0),
      partition_meta_entry_block_index_(0)

{
  memset(backup_meta_blocks_, 0, sizeof(backup_meta_blocks_));
  memset(reserved_, 0, sizeof(reserved_));
}

bool SuperBlock14::is_valid() const
{
  return header_size_ > 0 && version_ >= 0 && SUPER_BLOCK_MAGIC == magic_ && attr_ >= 0 && create_timestamp_ > 0 &&
         modify_timestamp_ >= create_timestamp_ && macro_block_size_ > 0 && total_macro_block_count_ > 0 &&
         reserved_block_count_ >= 0 && free_macro_block_count_ >= 0 && first_macro_block_ >= 0 &&
         first_free_block_index_ > 0 && total_file_size_ >= macro_block_size_ && backup_meta_count_ > 0 &&
         macro_block_meta_entry_block_index_ >= -1 && partition_meta_entry_block_index_ >= -1 &&
         replay_start_point_.is_valid();
}

DEFINE_SERIALIZE(SuperBlock14)
{
  int ret = OB_SUCCESS;
  if (NULL == buf || buf_len - pos < header_size_) {
    ret = OB_BUF_NOT_ENOUGH;
    STORAGE_LOG(WARN, "serialize superblock failed.", KP(buf), K(buf_len), K(pos), K(header_size_), K(ret));
  } else {
    MEMCPY(buf + pos, this, sizeof(SuperBlock14));
    pos += header_size_;
  }
  return ret;
}

DEFINE_DESERIALIZE(SuperBlock14)
{
  int ret = OB_SUCCESS;
  // read size first;
  if (NULL == buf || data_len - pos < static_cast<int64_t>(sizeof(int32_t))) {
    ret = OB_INVALID_ARGUMENT;
    STORAGE_LOG(WARN, "invalid arguments.", KP(buf), K(data_len), K(pos), K(header_size_), K(ret));
  } else {
    int32_t header_size = *(reinterpret_cast<const int32_t*>(buf));
    if (data_len - pos < header_size) {
      ret = OB_BUF_NOT_ENOUGH;
      STORAGE_LOG(ERROR, "data_len not enough for header size.", K(data_len), K(pos), K(header_size), K(ret));
    } else {
      MEMCPY(this, buf + pos, sizeof(SuperBlock14));
      pos += header_size;
    }
  }
  return ret;
}

DEFINE_GET_SERIALIZE_SIZE(SuperBlock14)
{
  return sizeof(SuperBlock14);
}

TEST(ObCommitLogSpec, normal)
{
  // is_valid() test
  ObCommitLogSpec log_spec;
  log_spec.log_dir_ = "./";
  log_spec.max_log_size_ = 2L * 1024L;
  log_spec.log_sync_type_ = 0;
  ASSERT_TRUE(log_spec.is_valid());
  log_spec.log_dir_ = NULL;
  ASSERT_FALSE(log_spec.is_valid());
  // to_string() test
  const char* out = to_cstring(log_spec);
  ASSERT_STRNE(NULL, out);
}

TEST(ObStorageEnv, normal)
{
  // to_string() test
  ObStorageEnv env;
  const char* out = to_cstring(env);
  ASSERT_STRNE(NULL, out);
}

TEST(SuperBlock, normal)
{
  int ret = OB_SUCCESS;

  ObArenaAllocator allocator(ObModIds::TEST);
  int64_t buf_len = ObSuperBlockHeader::OB_MAX_SUPER_BLOCK_SIZE;
  char* buf = static_cast<char*>(allocator.alloc(buf_len));
  ASSERT_TRUE(NULL != buf);
  int64_t pos = 0;

  ObSuperBlockV2 sb1;
  ObSuperBlockV2 sb2;

  sb1.reset();
  sb1.header_.version_ = OB_SUPER_BLOCK_V2;
  sb1.header_.magic_ = SUPER_BLOCK_MAGIC_V2;
  sb1.header_.attr_ = 0;

  sb1.content_.create_timestamp_ = ObTimeUtility::current_time();
  sb1.content_.modify_timestamp_ = sb1.content_.create_timestamp_;
  sb1.content_.macro_block_size_ = common::OB_DEFAULT_MACRO_BLOCK_SIZE;
  sb1.content_.total_macro_block_count_ = 10;
  sb1.content_.free_macro_block_count_ = 0;
  sb1.content_.total_file_size_ = 10 * common::OB_DEFAULT_MACRO_BLOCK_SIZE;

  sb1.content_.macro_block_meta_.reset();
  sb1.content_.partition_meta_.reset();
  sb1.content_.table_mgr_meta_.reset();
  sb1.content_.replay_start_point_.file_id_ = 1;
  sb1.content_.replay_start_point_.log_id_ = 0;
  sb1.content_.replay_start_point_.offset_ = 0;
  sb1.header_.super_block_size_ = static_cast<int32_t>(sb1.get_serialize_size());

  // serialize and deserizlize success test
  pos = 0;
  ret = sb1.serialize(buf, buf_len, pos);
  ASSERT_EQ(OB_SUCCESS, ret);
  pos = 0;
  ret = sb2.deserialize(buf, buf_len, pos);
  ASSERT_EQ(OB_SUCCESS, ret);
  ASSERT_EQ(0, memcmp(&sb1, &sb2, sizeof(sb1)));

  // serialize boundary test
  pos = 0;
  ret = sb1.serialize(buf, 10, pos);
  ASSERT_NE(OB_SUCCESS, ret);
  // deserialize boundary test
  pos = 0;
  ret = sb2.deserialize(buf, 10, pos);
  ASSERT_NE(OB_SUCCESS, ret);
  // to_string() test
  const char* out = to_cstring(sb1);
  ASSERT_STRNE(NULL, out);
}

TEST(SuperBlock, upgrade_from_20)
{
  const int64_t buf_len = SuperBlock20::MAX_SUPER_BLOCK_SIZE;
  char buf[buf_len];
  SuperBlock20 super_block;
  ObSuperBlockV1 super_block_v1;
  ObSuperBlockV2 super_block_v2;
  const int64_t data_file_size = 100 * 1024 * 1024;
  int64_t pos = 0;

  ASSERT_GT(buf_len, sizeof(super_block_v1));
  ASSERT_EQ(sizeof(super_block_v1), sizeof(super_block));

  MEMSET(&super_block, 0, sizeof(SuperBlock20));
  super_block.header_size_ = sizeof(SuperBlock20);
  super_block.version_ = ObMacroBlockCommonHeader::MACRO_BLOCK_COMMON_HEADER_VERSION;
  super_block.magic_ = SUPER_BLOCK_MAGIC;
  super_block.attr_ = 0;

  // first two blocks are superblock.
  super_block.backup_meta_count_ = SuperBlock20::MAX_BACKUP_META_COUNT;
  super_block.backup_meta_blocks_[0] = 0;
  super_block.backup_meta_blocks_[1] = 1;

  super_block.create_timestamp_ = ObTimeUtility::current_time();
  super_block.modify_timestamp_ = super_block.create_timestamp_;
  super_block.macro_block_size_ = common::OB_DEFAULT_MACRO_BLOCK_SIZE;
  super_block.total_macro_block_count_ = data_file_size / common::OB_DEFAULT_MACRO_BLOCK_SIZE;
  super_block.reserved_block_count_ = super_block.backup_meta_count_;
  super_block.free_macro_block_count_ = 0;
  super_block.first_macro_block_ = super_block.backup_meta_blocks_[1] + 1;
  super_block.first_free_block_index_ = super_block.first_macro_block_;
  super_block.total_file_size_ = lower_align(data_file_size, common::OB_DEFAULT_MACRO_BLOCK_SIZE);

  super_block.macro_block_meta_entry_block_index_ = 10;
  super_block.partition_meta_entry_block_index_ = 20;
  super_block.table_mgr_meta_entry_block_index_ = 30;
  super_block.partition_meta_log_seq_ = 40;
  super_block.table_mgr_meta_log_seq_ = 50;
  super_block.replay_start_point_.file_id_ = 60;
  super_block.replay_start_point_.log_id_ = 70;
  super_block.replay_start_point_.offset_ = 80;

  ASSERT_EQ(OB_SUCCESS, serialization::encode_i64(buf, buf_len, pos, ob_crc64(&super_block, super_block.header_size_)));
  ASSERT_EQ(OB_SUCCESS, super_block.serialize(buf, buf_len, pos));
  ASSERT_EQ(sizeof(super_block) + serialization::encoded_length_i64(0), pos);
  STORAGE_LOG(INFO, "succeed to serialize super block", K(buf_len), K(pos), K(super_block));
  pos = 0;
  ASSERT_EQ(OB_SUCCESS, super_block_v1.read_super_block_buf(buf, buf_len, pos));
  STORAGE_LOG(INFO, "read super block v1", K(super_block), K(super_block_v1));
  ASSERT_EQ(0, memcmp(&super_block_v1, &super_block, sizeof(super_block)));
  ASSERT_EQ(OB_SUCCESS, super_block_v2.set_super_block(super_block_v1));
  STORAGE_LOG(INFO, "convert from v1", K(super_block_v1), K(super_block_v2));

  const int64_t super_block_size = super_block_v2.get_serialize_size();
  ASSERT_EQ(super_block_size, super_block_v2.header_.super_block_size_);
  ASSERT_EQ(OB_SUPER_BLOCK_V2, super_block_v2.header_.version_);
  ASSERT_EQ(SUPER_BLOCK_MAGIC_V2, super_block_v2.header_.magic_);
  ASSERT_EQ(0, super_block_v2.header_.attr_);
  ASSERT_EQ(super_block.create_timestamp_, super_block_v2.content_.create_timestamp_);
  ASSERT_EQ(super_block.modify_timestamp_, super_block_v2.content_.modify_timestamp_);
  ASSERT_EQ(super_block.macro_block_size_, super_block_v2.content_.macro_block_size_);
  ASSERT_EQ(super_block.total_macro_block_count_, super_block_v2.content_.total_macro_block_count_);
  ASSERT_EQ(super_block.free_macro_block_count_, super_block_v2.content_.free_macro_block_count_);
  ASSERT_EQ(super_block.total_file_size_, super_block_v2.content_.total_file_size_);
  ASSERT_EQ(super_block.replay_start_point_.file_id_, super_block_v2.content_.replay_start_point_.file_id_);
  ASSERT_EQ(super_block.replay_start_point_.log_id_, super_block_v2.content_.replay_start_point_.log_id_);
  ASSERT_EQ(super_block.replay_start_point_.offset_, super_block_v2.content_.replay_start_point_.offset_);
  ASSERT_TRUE(check_meta_entry(
      super_block_v2.content_.macro_block_meta_, super_block.macro_block_meta_entry_block_index_, 0, 0, 0));
  ASSERT_TRUE(check_meta_entry(super_block_v2.content_.partition_meta_,
      super_block.partition_meta_entry_block_index_,
      super_block.partition_meta_log_seq_,
      0,
      0));
  ASSERT_TRUE(check_meta_entry(super_block_v2.content_.table_mgr_meta_,
      super_block.table_mgr_meta_entry_block_index_,
      super_block.table_mgr_meta_log_seq_,
      0,
      0));
}

TEST(SuperBlock, upgrade_from_14)
{
  const int64_t buf_len = SuperBlock14::MAX_SUPER_BLOCK_SIZE;
  char buf[buf_len];
  SuperBlock14 super_block;
  ObSuperBlockV1 super_block_v1;
  ObSuperBlockV2 super_block_v2;
  const int64_t data_file_size = 100 * 1024 * 1024;
  int64_t pos = 0;

  ASSERT_GT(buf_len, sizeof(super_block_v1));
  ASSERT_EQ(sizeof(super_block_v1), sizeof(super_block));

  MEMSET(&super_block, 0, sizeof(SuperBlock14));
  super_block.header_size_ = sizeof(SuperBlock14);
  super_block.version_ = ObMacroBlockCommonHeader::MACRO_BLOCK_COMMON_HEADER_VERSION;
  super_block.magic_ = SUPER_BLOCK_MAGIC;
  super_block.attr_ = 0;

  // first two blocks are superblock.
  super_block.backup_meta_count_ = SuperBlock14::MAX_BACKUP_META_COUNT;
  super_block.backup_meta_blocks_[0] = 0;
  super_block.backup_meta_blocks_[1] = 1;

  super_block.create_timestamp_ = ObTimeUtility::current_time();
  super_block.modify_timestamp_ = super_block.create_timestamp_;
  super_block.macro_block_size_ = common::OB_DEFAULT_MACRO_BLOCK_SIZE;
  super_block.total_macro_block_count_ = data_file_size / common::OB_DEFAULT_MACRO_BLOCK_SIZE;
  super_block.reserved_block_count_ = super_block.backup_meta_count_;
  super_block.free_macro_block_count_ = 0;
  super_block.first_macro_block_ = super_block.backup_meta_blocks_[1] + 1;
  super_block.first_free_block_index_ = super_block.first_macro_block_;
  super_block.total_file_size_ = lower_align(data_file_size, common::OB_DEFAULT_MACRO_BLOCK_SIZE);

  super_block.macro_block_meta_entry_block_index_ = 10;
  super_block.partition_meta_entry_block_index_ = 20;
  super_block.replay_start_point_.file_id_ = 60;
  super_block.replay_start_point_.log_id_ = 70;
  super_block.replay_start_point_.offset_ = 80;

  ASSERT_EQ(OB_SUCCESS, serialization::encode_i64(buf, buf_len, pos, ob_crc64(&super_block, super_block.header_size_)));
  ASSERT_EQ(OB_SUCCESS, super_block.serialize(buf, buf_len, pos));
  ASSERT_EQ(sizeof(super_block) + serialization::encoded_length_i64(0), pos);
  pos = 0;
  ASSERT_EQ(OB_SUCCESS, super_block_v1.read_super_block_buf(buf, buf_len, pos));
  STORAGE_LOG(INFO, "read super block v1", K(super_block), K(super_block_v1));
  ASSERT_EQ(0, memcmp(&super_block_v1, &super_block, sizeof(super_block)));
  ASSERT_EQ(OB_SUCCESS, super_block_v2.set_super_block(super_block_v1));
  STORAGE_LOG(INFO, "convert from v1", K(super_block_v1), K(super_block_v2));

  ASSERT_EQ(super_block_v2.get_serialize_size(), super_block_v2.header_.super_block_size_);
  ASSERT_EQ(OB_SUPER_BLOCK_V2, super_block_v2.header_.version_);
  ASSERT_EQ(SUPER_BLOCK_MAGIC_V2, super_block_v2.header_.magic_);
  ASSERT_EQ(0, super_block_v2.header_.attr_);
  ASSERT_EQ(super_block.create_timestamp_, super_block_v2.content_.create_timestamp_);
  ASSERT_EQ(super_block.modify_timestamp_, super_block_v2.content_.modify_timestamp_);
  ASSERT_EQ(super_block.macro_block_size_, super_block_v2.content_.macro_block_size_);
  ASSERT_EQ(super_block.total_macro_block_count_, super_block_v2.content_.total_macro_block_count_);
  ASSERT_EQ(super_block.free_macro_block_count_, super_block_v2.content_.free_macro_block_count_);
  ASSERT_EQ(super_block.total_file_size_, super_block_v2.content_.total_file_size_);
  ASSERT_EQ(super_block.replay_start_point_.file_id_, super_block_v2.content_.replay_start_point_.file_id_);
  ASSERT_EQ(super_block.replay_start_point_.log_id_, super_block_v2.content_.replay_start_point_.log_id_);
  ASSERT_EQ(super_block.replay_start_point_.offset_, super_block_v2.content_.replay_start_point_.offset_);
  ASSERT_TRUE(check_meta_entry(
      super_block_v2.content_.macro_block_meta_, super_block.macro_block_meta_entry_block_index_, 0, 0, 0));
  ASSERT_TRUE(check_meta_entry(
      super_block_v2.content_.partition_meta_, super_block.partition_meta_entry_block_index_, 0, 0, 0));
  ASSERT_TRUE(check_meta_entry(super_block_v2.content_.table_mgr_meta_, 0, 0, 0, 0));
}

TEST(SuperBlock, set_super_block)
{
  int ret = OB_SUCCESS;
  const int64_t data_file_size = 100 * 1024 * 1024;
  ObSuperBlockV1 src_v1;
  ObSuperBlockV1 dst_v1;
  ObSuperBlockV2 sb_v2;
  MEMSET(&src_v1, 0, sizeof(src_v1));
  MEMSET(&dst_v1, 0, sizeof(dst_v1));
  MEMSET(&sb_v2, 0, sizeof(sb_v2));

  src_v1.header_.super_block_size_ = sizeof(src_v1);
  src_v1.header_.version_ = ObMacroBlockCommonHeader::MACRO_BLOCK_COMMON_HEADER_VERSION;
  src_v1.header_.magic_ = SUPER_BLOCK_MAGIC;
  src_v1.header_.attr_ = 0;

  src_v1.backup_meta_count_ = ObSuperBlockV1::MAX_BACKUP_META_COUNT;
  src_v1.backup_meta_blocks_[0] = 0;
  src_v1.backup_meta_blocks_[1] = 1;

  src_v1.create_timestamp_ = ObTimeUtility::current_time();
  src_v1.modify_timestamp_ = ObTimeUtility::current_time();
  src_v1.macro_block_size_ = common::OB_DEFAULT_MACRO_BLOCK_SIZE;
  src_v1.total_macro_block_count_ = data_file_size / common::OB_DEFAULT_MACRO_BLOCK_SIZE;
  src_v1.reserved_block_count_ = src_v1.backup_meta_count_;
  src_v1.free_macro_block_count_ = 100;
  src_v1.first_macro_block_ = src_v1.backup_meta_blocks_[1] + 1;
  src_v1.first_free_block_index_ = src_v1.first_macro_block_;
  src_v1.total_file_size_ = lower_align(data_file_size, common::OB_DEFAULT_MACRO_BLOCK_SIZE);

  src_v1.macro_block_meta_entry_block_index_ = 10;
  src_v1.partition_meta_entry_block_index_ = 20;
  src_v1.table_mgr_meta_entry_block_index_ = 30;
  src_v1.partition_meta_log_seq_ = 40;
  src_v1.table_mgr_meta_log_seq_ = 50;
  src_v1.replay_start_point_.file_id_ = 60;
  src_v1.replay_start_point_.log_id_ = 70;
  src_v1.replay_start_point_.offset_ = 80;

  ret = sb_v2.set_super_block(src_v1);
  ASSERT_EQ(OB_SUCCESS, ret);

  ret = dst_v1.set_super_block(sb_v2);
  ASSERT_EQ(OB_SUCCESS, ret);

  ASSERT_EQ(src_v1.header_.super_block_size_, dst_v1.header_.super_block_size_);
  ASSERT_EQ(src_v1.header_.version_, dst_v1.header_.version_);
  ASSERT_EQ(src_v1.header_.magic_, dst_v1.header_.magic_);
  ASSERT_EQ(src_v1.header_.attr_, dst_v1.header_.attr_);

  ASSERT_EQ(src_v1.backup_meta_count_, dst_v1.backup_meta_count_);
  ASSERT_EQ(src_v1.backup_meta_blocks_[0], dst_v1.backup_meta_blocks_[0]);
  ASSERT_EQ(src_v1.backup_meta_blocks_[1], dst_v1.backup_meta_blocks_[1]);

  ASSERT_EQ(src_v1.create_timestamp_, dst_v1.create_timestamp_);
  ASSERT_EQ(src_v1.modify_timestamp_, dst_v1.modify_timestamp_);
  ASSERT_EQ(src_v1.macro_block_size_, dst_v1.macro_block_size_);
  ASSERT_EQ(src_v1.total_macro_block_count_, dst_v1.total_macro_block_count_);
  ASSERT_EQ(src_v1.reserved_block_count_, dst_v1.reserved_block_count_);
  ASSERT_EQ(src_v1.free_macro_block_count_, dst_v1.free_macro_block_count_);
  ASSERT_EQ(src_v1.first_macro_block_, dst_v1.first_macro_block_);
  ASSERT_EQ(src_v1.first_free_block_index_, dst_v1.first_free_block_index_);
  ASSERT_EQ(src_v1.total_file_size_, dst_v1.total_file_size_);

  ASSERT_EQ(src_v1.macro_block_meta_entry_block_index_, dst_v1.macro_block_meta_entry_block_index_);
  ASSERT_EQ(src_v1.partition_meta_entry_block_index_, dst_v1.partition_meta_entry_block_index_);
  ASSERT_EQ(src_v1.table_mgr_meta_entry_block_index_, dst_v1.table_mgr_meta_entry_block_index_);
  ASSERT_EQ(src_v1.partition_meta_log_seq_, dst_v1.partition_meta_log_seq_);
  ASSERT_EQ(src_v1.table_mgr_meta_log_seq_, dst_v1.table_mgr_meta_log_seq_);
  ASSERT_EQ(src_v1.replay_start_point_.file_id_, dst_v1.replay_start_point_.file_id_);
  ASSERT_EQ(src_v1.replay_start_point_.log_id_, dst_v1.replay_start_point_.log_id_);
  ASSERT_EQ(src_v1.replay_start_point_.offset_, dst_v1.replay_start_point_.offset_);
}

TEST(ObLinkedMacroBlockHeader, normal)
{
  // check() test
  ObLinkedMacroBlockHeader link_header;
  link_header.version_ = 1;
  link_header.magic_ = 2;
  link_header.attr_ = 1;
  ASSERT_FALSE(link_header.is_valid());
  link_header.header_size_ = sizeof(link_header);
  link_header.version_ = LINKED_MACRO_BLOCK_HEADER_VERSION;
  link_header.magic_ = MACRO_META_HEADER_MAGIC;
  link_header.attr_ = ObMacroBlockCommonHeader::MacroMeta;
  ASSERT_TRUE(link_header.is_valid());
  // to_string() test
  const char* out = to_cstring(link_header);
  ASSERT_STRNE(NULL, out);
}

TEST(ObMicroBlockHeader, normal)
{
  // to_string() test
  ObMicroBlockHeader micro_header;
  const char* out = to_cstring(micro_header);
  ASSERT_STRNE(NULL, out);
}

TEST(ObMacroBlockCommonHeader, normal)
{
  // check() test
  ObMacroBlockCommonHeader common_header;
  common_header.set_attr(ObMacroBlockCommonHeader::PartitionMeta);
  ASSERT_TRUE(common_header.is_valid());
  common_header.set_previous_block_index(-2);
  ASSERT_FALSE(common_header.is_valid());
  // to_string() test
  const char* out = to_cstring(common_header);
  ASSERT_STRNE(NULL, out);
  // serialization length test
  ASSERT_EQ(common_header.header_size_, common_header.get_serialize_size());
}

TEST(ObSSTableMacroBlockHeader, normal)
{
  // to_string() test
  ObSSTableMacroBlockHeader sstable_header;
  const char* out = to_cstring(sstable_header);
  ASSERT_STRNE(NULL, out);
}

TEST(ObMacroBlockMeta, serialize)
{
  int ret = OB_SUCCESS;
  ObArenaAllocator allocator(ObModIds::TEST);
  int64_t buf_len = 0;
  int64_t pos = 0;
  char* buf = NULL;

  ObMacroBlockMeta meta1;
  ObMacroBlockMeta meta2;

  // serialize and deserialize success test
  ObMacroMetaGenerator::gen_meta(meta1, allocator);
  buf_len = meta1.get_serialize_size();
  buf = static_cast<char*>(allocator.alloc(buf_len));
  ASSERT_STRNE(NULL, buf);
  pos = 0;
  ret = meta1.serialize(buf, buf_len, pos);
  ASSERT_EQ(OB_SUCCESS, ret);

  ObObj out_endkey[128];
  meta2.endkey_ = out_endkey;
  pos = 0;
  ret = meta2.deserialize(buf, buf_len, pos);
  ASSERT_EQ(ret, OB_SUCCESS);
  ASSERT_TRUE(meta1 == meta2);

  // serialize boundary
  for (int64_t i = buf_len - 50; i < buf_len; ++i) {
    pos = i;
    ret = meta1.serialize(buf, buf_len, pos);
    ASSERT_NE(OB_SUCCESS, ret);
  }
}

TEST(ObMacroBlockMeta, deep_copy)
{
  int ret = OB_SUCCESS;
  int64_t column_num = 7;
  ObArenaAllocator allocator(ObModIds::TEST);
  ObMacroBlockMeta meta1;
  ObMacroBlockMeta* meta2 = NULL;
  ObMacroMetaGenerator::gen_meta(meta1, allocator);
  ObRowkey rowkey(meta1.endkey_, column_num);
  ObRowkey collation_free_rowkey;
  int64_t deep_copy_size = sizeof(ObMacroBlockMeta) + 5        // compressor_
                           + sizeof(uint16_t) * column_num     // column_id_array_
                           + sizeof(ObObjMeta) * column_num    // column_type_array
                           + sizeof(ObOrderType) * column_num  // column_order_array_
                           + sizeof(int64_t) * column_num      // column_checksum_
                           + sizeof(int64_t) * column_num      // empty_read_cnt_
                           + rowkey.get_deep_copy_size();      // endkey_
  int64_t get_deep_copy_size = 0;
  ASSERT_EQ(OB_SUCCESS, meta1.get_deep_copy_size(collation_free_rowkey, allocator, get_deep_copy_size));
  deep_copy_size += collation_free_rowkey.get_deep_copy_size();
  ASSERT_EQ(deep_copy_size, get_deep_copy_size);
  // copy success test
  ret = meta1.deep_copy(meta2, allocator);
  ASSERT_EQ(ret, OB_SUCCESS);
  ASSERT_TRUE(NULL != meta2);
  ASSERT_TRUE(meta1 == *meta2);

  // empty_read_cnt_ = NULL;
  ObMacroBlockMeta* meta3 = NULL;
  ASSERT_EQ(OB_SUCCESS, meta1.get_deep_copy_size(collation_free_rowkey, allocator, get_deep_copy_size));
  ASSERT_EQ(deep_copy_size, get_deep_copy_size);
  ret = meta1.deep_copy(meta3, allocator);
  ASSERT_EQ(OB_SUCCESS, ret);
  ASSERT_TRUE(NULL != meta3);
  ASSERT_TRUE(meta1 == *meta3);
}

TEST(ObMacroBlockMeta, misc)
{
  ObArenaAllocator allocator(ObModIds::TEST);
  ObMacroBlockMeta meta;
  ObMacroMetaGenerator::gen_meta(meta, allocator);
  // to_string() test
  const char* out = to_cstring(meta);
  ASSERT_STRNE(NULL, out);
}

TEST(ObSSTableMeta, normal)
{
  int ret = OB_SUCCESS;
  ObArenaAllocator allocator(ObModIds::TEST);
  int64_t buf_len = 0;
  int64_t pos = 0;
  char* buf = NULL;

  ObSSTableMeta smeta1(allocator);
  ObSSTableMeta smeta2(allocator);
  smeta1.index_id_ = 3001;
  smeta1.row_count_ = 2;
  smeta1.occupy_size_ = 2 * 1024 * 1024;
  smeta1.data_checksum_ = 12345;
  smeta1.row_checksum_ = 12345;
  smeta1.data_version_ = 1;
  smeta1.rowkey_column_count_ = 2;
  smeta1.table_type_ = 0;
  smeta1.index_type_ = 0;
  smeta1.available_version_ = 0;
  smeta1.macro_block_count_ = 1;
  smeta1.column_cnt_ = 10;
  smeta1.checksum_method_ = blocksstable::CCM_VALUE_ONLY;
  ObSSTableColumnMeta col_meta;
  ASSERT_EQ(OB_SUCCESS, smeta1.column_metas_.reserve(smeta1.column_cnt_));
  ASSERT_EQ(OB_SUCCESS, smeta1.new_column_metas_.reserve(smeta1.column_cnt_));
  for (int64_t i = 0; i < smeta1.column_cnt_; ++i) {
    col_meta.column_id_ = i + 1;
    col_meta.column_default_checksum_ = i;
    col_meta.column_checksum_ = i * 10;
    smeta1.column_metas_.push_back(col_meta);
  }
  for (int64_t i = 0; i < smeta1.column_cnt_; ++i) {
    col_meta.column_id_ = i + 1;
    col_meta.column_default_checksum_ = i;
    col_meta.column_checksum_ = i * 10;
    smeta1.new_column_metas_.push_back(col_meta);
  }
  MacroBlockId block_id(0, 0, 0, 2);
  ret = smeta1.macro_block_array_.push_back(block_id);
  ASSERT_EQ(ret, OB_SUCCESS);

  buf_len = smeta1.get_serialize_size();
  buf = static_cast<char*>(allocator.alloc(buf_len));
  ASSERT_STRNE(NULL, buf);

  // serizlize and deserialize success
  pos = 0;
  ret = smeta1.serialize(buf, buf_len, pos);
  ASSERT_EQ(OB_SUCCESS, ret);
  ASSERT_EQ(smeta1.get_serialize_size(), pos);

  pos = 0;
  ret = smeta2.deserialize(buf, buf_len, pos);
  ASSERT_EQ(ret, OB_SUCCESS);
  ASSERT_TRUE(smeta1 == smeta2);

  // serialize boundary test
  for (int64_t i = 1; i < buf_len; ++i) {
    pos = i;
    ret = smeta1.serialize(buf, buf_len, pos);
    ASSERT_NE(OB_SUCCESS, ret);
  }

  // deserialize boundary test
  for (int64_t i = 1; i < buf_len; ++i) {
    pos = i;
    ret = smeta2.deserialize(buf, buf_len, pos);
    ASSERT_NE(OB_SUCCESS, ret);
  }

  // to_string
  const char* out = to_cstring(smeta1);
  ASSERT_STRNE(NULL, out);
}

TEST(ObPartitionMeta, normal)
{
  int ret = OB_SUCCESS;
  ObArenaAllocator allocator(ObModIds::TEST);
  int64_t buf_len = 0;
  int64_t pos = 0;
  char* buf = NULL;

  ObPartitionMeta pmeta1;
  ObPartitionMeta pmeta2;
  memset(&pmeta1, 223, sizeof(pmeta1));
  pmeta1.log_info_.assign_ptr("hello", static_cast<ObString::obstr_size_t>(strlen("hello")));

  // serialize and deserialize boundary test
  buf_len = pmeta1.get_serialize_size();
  buf = static_cast<char*>(allocator.alloc(buf_len));
  ASSERT_STRNE(NULL, buf);
  for (int64_t i = 1; i < buf_len; ++i) {
    pos = i;
    ret = pmeta1.serialize(buf, buf_len, pos);
    ASSERT_NE(OB_SUCCESS, ret);
  }

  // serialize and deserialize success test
  pos = 0;
  ret = pmeta1.serialize(buf, buf_len, pos);
  ASSERT_EQ(ret, OB_SUCCESS);
  ASSERT_EQ(pos, pmeta1.get_serialize_size());

  pos = 0;
  ret = pmeta2.deserialize(buf, buf_len, pos);
  ASSERT_EQ(ret, OB_SUCCESS);
  ASSERT_TRUE(pmeta1 == pmeta2);

  pmeta2.reset();
  pos = 0;
  ret = pmeta2.deserialize(buf, buf_len, pos, allocator);
  ASSERT_EQ(OB_SUCCESS, ret);
  ASSERT_TRUE(pmeta1 == pmeta2);

  // to_string
  const char* out = to_cstring(pmeta1);
  ASSERT_STRNE(NULL, out);
}

TEST(ObSSTableMeta, to_string)
{
  int ret = OB_SUCCESS;
  ObArenaAllocator allocator(ObModIds::TEST);
  ObSSTableMeta sstable_meta(allocator);
  MacroBlockId block_id(1);
  const int64_t buf_len = 100;
  char buf[buf_len];
  int64_t pos = 0;

  for (int64_t i = 0; i < 10000; ++i) {
    sstable_meta.macro_block_count_++;
    ret = sstable_meta.macro_block_array_.push_back(block_id);
    ASSERT_EQ(OB_SUCCESS, ret);
  }

  pos = sstable_meta.to_string(buf, buf_len);
  ASSERT_TRUE(pos <= buf_len);
}

TEST(ObPartitionMeta, deserialize_error)
{
  ObArenaAllocator allocator(ObModIds::TEST);
  common::ObLfFIFOAllocator fifo_allocator;
  int64_t buf_len = 0;
  int64_t pos = 0;
  char* buf = NULL;

  ObPartitionMeta pmeta1;
  ObPartitionMeta pmeta2;
  memset(&pmeta1, 223, sizeof(pmeta1));
  pmeta1.log_info_.assign_ptr("hello", static_cast<ObString::obstr_size_t>(strlen("hello")));

  ASSERT_EQ(
      OB_SUCCESS, fifo_allocator.init(8 * 1024 * 1024, ObModIds::TEST, OB_SERVER_TENANT_ID, 1, 8 * 1024 * 1024 + 4096));
  void* used = fifo_allocator.alloc(8 * 1024 * 1024 - 17 /*sizeof(SliceHeader)*/ - 1);
  ASSERT_TRUE(NULL != used);
  buf_len = pmeta1.get_serialize_size();
  buf = static_cast<char*>(allocator.alloc(buf_len));
  ASSERT_TRUE(NULL != buf);
  pos = 0;
  ASSERT_EQ(OB_SUCCESS, pmeta1.serialize(buf, buf_len, pos));

  pos = 0;
  ASSERT_EQ(OB_ALLOCATE_MEMORY_FAILED, pmeta2.deserialize(buf, buf_len, pos, fifo_allocator));
  if (NULL != pmeta2.log_info_.ptr()) {
    fifo_allocator.free(pmeta2.log_info_.ptr());
  }
  fifo_allocator.free(used);
}

}  // namespace blocksstable
}  // namespace oceanbase

int main(int argc, char** argv)
{
  OB_LOGGER.set_log_level("INFO");
  testing::InitGoogleTest(&argc, argv);
  oceanbase::lib::set_memory_limit(40L << 30);
  return RUN_ALL_TESTS();
}
