/** * 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. */ #define USING_LOG_PREFIX STORAGE #include "storage/ob_super_block_struct.h" #include "storage/blocksstable/ob_block_sstable_struct.h" namespace oceanbase { namespace storage { using namespace oceanbase::common; using namespace oceanbase::blocksstable; using namespace oceanbase::share; const MacroBlockId ObServerSuperBlock::EMPTY_LIST_ENTRY_BLOCK(0, MacroBlockId::EMPTY_ENTRY_BLOCK_INDEX, 0); // ========================== ObServerSuperBlock ============================== ObServerSuperBlockHeader::ObServerSuperBlockHeader() { reset(); } bool ObServerSuperBlockHeader::is_valid() const { return version_ == SERVER_SUPER_BLOCK_VERSION && magic_ == SERVER_SUPER_BLOCK_MAGIC && body_size_ > 0; } void ObServerSuperBlockHeader::reset() { version_ = 0; magic_ = 0; body_size_ = 0; body_crc_ = 0; } DEFINE_SERIALIZE(ObServerSuperBlockHeader) { int ret = OB_SUCCESS; if (NULL == buf || buf_len - pos < sizeof(ObServerSuperBlockHeader)) { ret = OB_BUF_NOT_ENOUGH; LOG_WARN("serialize superblock failed.", K(ret), KP(buf), K(buf_len), K(pos), "header_size", sizeof(ObServerSuperBlockHeader)); } else { MEMCPY(buf + pos, this, sizeof(ObServerSuperBlockHeader)); pos += sizeof(ObServerSuperBlockHeader); } return ret; } DEFINE_DESERIALIZE(ObServerSuperBlockHeader) { int ret = OB_SUCCESS; if (NULL == buf || data_len - pos < sizeof(ObServerSuperBlockHeader)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments.", K(ret), KP(buf), K(data_len), K(pos), "header_size", sizeof(ObServerSuperBlockHeader)); } else { MEMCPY(this, buf + pos, sizeof(ObServerSuperBlockHeader)); pos += sizeof(ObServerSuperBlockHeader); } if (OB_SUCC(ret)) { if (OB_UNLIKELY(SERVER_SUPER_BLOCK_VERSION != version_ || SERVER_SUPER_BLOCK_MAGIC != magic_)) { ret = OB_ERR_SYS; LOG_ERROR("version or magic not match", K(ret), K(*this)); } } return ret; } DEFINE_GET_SERIALIZE_SIZE(ObServerSuperBlockHeader) { return sizeof(ObServerSuperBlockHeader); } ServerSuperBlockBody::ServerSuperBlockBody() { reset(); } bool ServerSuperBlockBody::is_valid() const { return create_timestamp_ > 0 && modify_timestamp_ >= create_timestamp_ && macro_block_size_ > 0 && total_macro_block_count_ > 0 && total_file_size_ >= macro_block_size_ && replay_start_point_.is_valid() && tenant_meta_entry_.is_valid(); } void ServerSuperBlockBody::reset() { create_timestamp_ = 0; modify_timestamp_ = 0; macro_block_size_ = 0; total_macro_block_count_ = 0; total_file_size_ = 0; replay_start_point_.reset(); tenant_meta_entry_.reset(); } OB_SERIALIZE_MEMBER(ServerSuperBlockBody, create_timestamp_, modify_timestamp_, macro_block_size_, total_macro_block_count_, total_file_size_, replay_start_point_, tenant_meta_entry_); ObServerSuperBlock::ObServerSuperBlock() : header_(), body_() {} bool ObServerSuperBlock::is_valid() const { return header_.is_valid() && body_.is_valid(); } int64_t ObServerSuperBlock::get_serialize_size() const { return header_.get_serialize_size() + body_.get_serialize_size(); } int ObServerSuperBlock::serialize(char *buf, const int64_t buf_size, int64_t &pos) const { int ret = OB_SUCCESS; int64_t new_pos = pos; if (OB_ISNULL(buf) || buf_size <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid args", K(ret), KP(buf), K(buf_size)); } else if (!is_valid()) { ret = OB_ERR_SYS; LOG_WARN("cannot write invalid super block", K(ret), K(*this)); } else { MEMSET(buf + pos, 0, buf_size - pos); if (OB_FAIL(header_.serialize(buf, buf_size, new_pos))) { LOG_WARN("failed to encode super block header", K(ret), K(buf_size), K(new_pos), K(*this)); } else if (OB_FAIL(body_.serialize(buf, buf_size, new_pos))) { LOG_WARN("failed to encode super block content", K(ret), K(buf_size), K(new_pos), K(*this)); } else { pos = new_pos; LOG_INFO("succeed to serialize super block buf", K(buf_size), K(pos), K(*this)); } } return ret; } int ObServerSuperBlock::deserialize(const char *buf, const int64_t buf_size, int64_t &pos) { int ret = OB_SUCCESS; int32_t calc_crc = 0; if (OB_ISNULL(buf) || buf_size <= 0 || pos < 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid args", K(ret), KP(buf), K(buf_size)); } else if (is_valid()) { ret = OB_INIT_TWICE; LOG_ERROR("cannot read super block twice", K(ret), K(*this)); } else if (OB_FAIL(header_.deserialize(buf, buf_size, pos))) { LOG_WARN("failed to decode header", K(ret), KP(buf), K(buf_size), K(pos)); } else if (OB_UNLIKELY(header_.body_crc_ != (calc_crc = static_cast(ob_crc64(buf + pos, header_.body_size_))))) { ret = OB_PHYSIC_CHECKSUM_ERROR; LOG_DBA_ERROR(OB_PHYSIC_CHECKSUM_ERROR, "msg", "failed to check crc", K(ret), KP(buf), K(buf_size), K(pos), K_(header), K(calc_crc)); } else if (OB_FAIL(body_.deserialize(buf, buf_size, pos))) { LOG_WARN("failed to decode body", K(ret), KP(buf), K(buf_size), K(pos)); } else if (OB_UNLIKELY(!is_valid())) { ret = OB_INVALID_DATA; LOG_WARN("invalid data, ", K(ret), K(*this)); } else { LOG_INFO("load server superblock success.", K(buf_size), K(pos), K(*this)); } return ret; } void ObServerSuperBlock::reset() { header_.reset(); body_.reset(); } int ObServerSuperBlock::construct_header() { int ret = OB_SUCCESS; if (OB_UNLIKELY(!body_.is_valid())) { ret = OB_INVALID_DATA; LOG_WARN("super block body invalid", K(ret), K_(body)); } else { // calculate crc of content serialized buffer int64_t pos = 0; int64_t body_buf_len = body_.get_serialize_size(); char *body_buf = static_cast(ob_malloc(body_buf_len, "SuperBlock")); if (OB_ISNULL(body_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate memory for body", K(ret)); } else if (OB_FAIL(body_.serialize(body_buf, body_buf_len, pos))) { LOG_WARN("fail to serialize super block body", K(ret)); } else { header_.version_ = ObServerSuperBlockHeader::SERVER_SUPER_BLOCK_VERSION; header_.magic_ = SERVER_SUPER_BLOCK_MAGIC; header_.body_size_ = body_buf_len; header_.body_crc_ = static_cast(ob_crc64(body_buf, body_buf_len)); ob_free(body_buf); } } return ret; } int ObServerSuperBlock::format_startup_super_block( const int64_t macro_block_size, const int64_t data_file_size) { int ret = OB_SUCCESS; if (macro_block_size <= 0 || data_file_size <= 0 || data_file_size < macro_block_size) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(macro_block_size), K(data_file_size)); } else { reset(); body_.create_timestamp_ = ObTimeUtility::current_time(); body_.modify_timestamp_ = body_.create_timestamp_; body_.macro_block_size_ = macro_block_size; body_.total_macro_block_count_ = data_file_size / macro_block_size; body_.total_file_size_ = lower_align(data_file_size, macro_block_size); body_.tenant_meta_entry_ = ObServerSuperBlock::EMPTY_LIST_ENTRY_BLOCK; body_.replay_start_point_.file_id_ = 1; body_.replay_start_point_.log_id_ = 1; // Due to the design of slog, the log_id_'s initial value must be 1 body_.replay_start_point_.offset_ = 0; if (OB_FAIL(construct_header())) { LOG_WARN("fail to construct super block header", K(ret), K_(body)); } else { LOG_INFO("success to format super block", K(*this)); } } return ret; } // ========================== ObTenantSnapshotMetaMeta ============================== int ObTenantSnapshotMeta::serialize(char *buf, const int64_t buf_len, int64_t &pos) const { int ret = OB_SUCCESS; LST_DO_CODE(OB_UNIS_ENCODE, ls_meta_entry_, snapshot_id_); return ret; } int ObTenantSnapshotMeta::deserialize(const char *buf, const int64_t data_len, int64_t &pos) { int ret = OB_SUCCESS; LST_DO_CODE(OB_UNIS_DECODE, ls_meta_entry_, snapshot_id_); return ret; } int64_t ObTenantSnapshotMeta::get_serialize_size() const { int64_t len = 0; LST_DO_CODE(OB_UNIS_ADD_LEN, ls_meta_entry_, snapshot_id_); return len; } bool ObTenantSnapshotMeta::is_valid() const { return ls_meta_entry_.is_valid() && snapshot_id_.is_valid(); } void ObTenantSnapshotMeta::reset() { ls_meta_entry_ = ObServerSuperBlock::EMPTY_LIST_ENTRY_BLOCK; snapshot_id_.reset(); } // ========================== ObTenantSuperBlock ============================== ObTenantSuperBlock::ObTenantSuperBlock() { reset(); } ObTenantSuperBlock::ObTenantSuperBlock(const uint64_t tenant_id, const bool is_hidden) : tenant_id_(tenant_id), is_hidden_(is_hidden), version_(TENANT_SUPER_BLOCK_VERSION), snapshot_cnt_(0) { replay_start_point_.file_id_ = 1; replay_start_point_.log_id_ = 1; // // Due to the design of slog, the log_id_'s initial value must be 1 replay_start_point_.offset_ = 0; tablet_meta_entry_ = ObServerSuperBlock::EMPTY_LIST_ENTRY_BLOCK; ls_meta_entry_ = ObServerSuperBlock::EMPTY_LIST_ENTRY_BLOCK; for (int64_t i = 0; i < MAX_SNAPSHOT_NUM; i++) { tenant_snapshots_[i].reset(); } } ObTenantSuperBlock::ObTenantSuperBlock(const ObTenantSuperBlock &other) { *this = other; } ObTenantSuperBlock &ObTenantSuperBlock::operator=(const ObTenantSuperBlock &other) { if (this != &other) { reset(); tenant_id_ = other.tenant_id_; replay_start_point_ = other.replay_start_point_; ls_meta_entry_ = other.ls_meta_entry_; tablet_meta_entry_ = other.tablet_meta_entry_; is_hidden_ = other.is_hidden_; version_ = other.version_; snapshot_cnt_ = other.snapshot_cnt_; for (int64_t i = 0; i < snapshot_cnt_; i++) { tenant_snapshots_[i] = other.tenant_snapshots_[i]; } } return *this; } void ObTenantSuperBlock::reset() { tenant_id_ = OB_INVALID_TENANT_ID; replay_start_point_.reset(); ls_meta_entry_.reset(); tablet_meta_entry_.reset(); is_hidden_= false; version_ = TENANT_SUPER_BLOCK_VERSION; for (int64_t i = 0; i < MAX_SNAPSHOT_NUM; i++) { tenant_snapshots_[i].reset(); } snapshot_cnt_ = 0; } void ObTenantSuperBlock::copy_snapshots_from(const ObTenantSuperBlock &other) { snapshot_cnt_ = other.snapshot_cnt_; for (int64_t i = 0; i < snapshot_cnt_; i++) { tenant_snapshots_[i] = other.tenant_snapshots_[i]; } } bool ObTenantSuperBlock::is_valid() const { bool is_valid = OB_INVALID_TENANT_ID != tenant_id_ && replay_start_point_.is_valid() && ls_meta_entry_.is_valid() && tablet_meta_entry_.is_valid() && version_ > MIN_SUPER_BLOCK_VERSION && (is_old_version() || IS_EMPTY_BLOCK_LIST(tablet_meta_entry_)) && snapshot_cnt_ >= 0; return is_valid; } int ObTenantSuperBlock::get_snapshot(const ObTenantSnapshotID &snapshot_id, ObTenantSnapshotMeta &snapshot) const { int ret = OB_SUCCESS; bool found = false; for (int64_t i = 0; OB_SUCC(ret) && !found && i < snapshot_cnt_; i++) { if (snapshot_id == tenant_snapshots_[i].snapshot_id_) { if (OB_UNLIKELY(!tenant_snapshots_[i].is_valid())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("snapshot is invalid", K(ret), K(tenant_snapshots_[i])); } else { snapshot = tenant_snapshots_[i]; found = true; } } } if (OB_SUCC(ret) && OB_UNLIKELY(!found)) { ret = OB_ENTRY_NOT_EXIST; LOG_WARN("snapshot doesn't exist", K(ret), K(snapshot_id)); } return ret; } int ObTenantSuperBlock::add_snapshot(const ObTenantSnapshotMeta &snapshot) { int ret = OB_SUCCESS; if (OB_FAIL(check_new_snapshot(snapshot.snapshot_id_))) { LOG_WARN("fail to check new snapshot", K(ret), K(snapshot)); } else { tenant_snapshots_[snapshot_cnt_] = snapshot; snapshot_cnt_++; } return ret; } int ObTenantSuperBlock::check_new_snapshot(const ObTenantSnapshotID &snapshot_id) const { int ret = OB_SUCCESS; if (snapshot_cnt_ >= MAX_SNAPSHOT_NUM) { ret = OB_ERR_UNEXPECTED; LOG_WARN("num of snapshots has reached the limit", K(ret), K(snapshot_cnt_)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < snapshot_cnt_; i++) { if (snapshot_id == tenant_snapshots_[i].snapshot_id_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("repeated snapshot id", K(ret), K(snapshot_id)); } } } return ret; } int ObTenantSuperBlock::delete_snapshot(const ObTenantSnapshotID &snapshot_id) { int ret = OB_SUCCESS; int64_t index = -1; for (int64_t i = 0; -1 == index && i < snapshot_cnt_; i++) { if (tenant_snapshots_[i].snapshot_id_ == snapshot_id) { index = i; } } if (OB_UNLIKELY(index < 0)) { ret = OB_ENTRY_NOT_EXIST; LOG_WARN("target snapshot desn't exist", K(ret), K(snapshot_id), K(index)); } else { for (int64_t i = index; i < snapshot_cnt_ - 1; i++) { tenant_snapshots_[i] = tenant_snapshots_[i + 1]; } snapshot_cnt_--; } return ret; } int ObTenantSuperBlock::serialize(char *buf, const int64_t buf_len, int64_t &pos) const { int ret = OB_SUCCESS; OB_UNIS_ENCODE(UNIS_VERSION); if (OB_SUCC(ret)) { int64_t size_nbytes = NS_::OB_SERIALIZE_SIZE_NEED_BYTES; int64_t pos_bak = (pos += size_nbytes); if (OB_SUCC(ret)) { if (OB_FAIL(serialize_(buf, buf_len, pos))) { LOG_WARN("fail to serialize", K(ret), KP(buf), K(buf_len), K(pos)); } } int64_t serial_size = pos - pos_bak; int64_t tmp_pos = 0; int64_t expect_size = get_serialize_size_(); assert(expect_size >= serial_size); if (OB_SUCC(ret)) { ret = common::serialization::encode_fixed_bytes_i64(buf + pos_bak - size_nbytes, size_nbytes, tmp_pos, serial_size); } } return ret; } int ObTenantSuperBlock::serialize_(char *buf, const int64_t buf_len, int64_t &pos) const { int ret = OB_SUCCESS; LST_DO_CODE(OB_UNIS_ENCODE, tenant_id_, replay_start_point_, ls_meta_entry_, tablet_meta_entry_, is_hidden_, tenant_snapshots_, snapshot_cnt_); return ret; } int ObTenantSuperBlock::deserialize(const char *buf, const int64_t data_len, int64_t &pos) { int ret = OB_SUCCESS; int64_t len = 0; OB_UNIS_DECODE(version_); OB_UNIS_DECODE(len); if (OB_SUCC(ret)) { if (UNIS_VERSION < version_) { ret = ::oceanbase::common::OB_NOT_SUPPORTED; LOG_WARN("ObTenantSuperBlock object version mismatch", K(ret), K_(version)); } else if (len < 0) { ret = ::oceanbase::common::OB_ERR_UNEXPECTED; LOG_WARN("can't decode object with negative length", K(ret), K(len)); } else if (data_len < len + pos) { ret = ::oceanbase::common::OB_DESERIALIZE_ERROR; LOG_WARN("buf length not enough", K(ret), K(len), K(pos), K(data_len)); } else { int64_t pos_orig = pos; pos = 0; if (OB_FAIL(deserialize_(buf + pos_orig, len, pos))) { LOG_WARN("fail to de-serialize", K(ret), "len", len, K(pos)); } pos = pos_orig + len; } } return ret; } int ObTenantSuperBlock::deserialize_(const char *buf, const int64_t data_len, int64_t &pos) { int ret = OB_SUCCESS; LST_DO_CODE(OB_UNIS_DECODE, tenant_id_, replay_start_point_, ls_meta_entry_, tablet_meta_entry_, is_hidden_, tenant_snapshots_, snapshot_cnt_); return ret; } int64_t ObTenantSuperBlock::get_serialize_size(void) const { int64_t len = get_serialize_size_(); SERIALIZE_SIZE_HEADER(UNIS_VERSION); return len; } int64_t ObTenantSuperBlock::get_serialize_size_(void) const { int64_t len = 0; LST_DO_CODE(OB_UNIS_ADD_LEN, tenant_id_, replay_start_point_, ls_meta_entry_, tablet_meta_entry_, is_hidden_, tenant_snapshots_, snapshot_cnt_); return len; } } // end namespace storage } // end namespace oceanbase