Files
oceanbase/src/storage/compaction/ob_partition_merge_fuser.cpp
2024-03-18 06:15:59 +00:00

419 lines
14 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.
*/
#define USING_LOG_PREFIX STORAGE_COMPACTION
#include "ob_partition_merge_fuser.h"
#include "ob_tablet_merge_ctx.h"
#include "sql/ob_sql_utils.h"
#include "storage/column_store/ob_column_oriented_merge_fuser.h"
namespace oceanbase
{
using namespace share::schema;
using namespace common;
using namespace memtable;
using namespace storage;
using namespace blocksstable;
namespace compaction
{
/*
*ObMergeFuser
*/
int ObMergeFuser::base_init(const bool is_fuse_row_flag)
{
int ret = OB_SUCCESS;
is_fuse_row_flag_ = is_fuse_row_flag;
if (OB_FAIL(result_row_.init(allocator_, column_cnt_))) {
STORAGE_LOG(WARN, "Failed to init datum row", K(ret));
} else if (OB_FAIL(nop_pos_.init(allocator_, column_cnt_))) {
STORAGE_LOG(WARN, "Failed to init nop pos", K(ret), K(column_cnt_));
}
return ret;
}
void ObMergeFuser::clean_nop_pos_and_result_row()
{
nop_pos_.reset();
result_row_.row_flag_.reset();
result_row_.row_flag_.set_flag(ObDmlFlag::DF_NOT_EXIST);
result_row_.trans_id_.reset();
result_row_.mvcc_row_flag_.reset();
for (int64_t i = 0; i < result_row_.count_; i++) {
result_row_.storage_datums_[i].set_nop();
}
}
int ObMergeFuser::add_fuse_row(const blocksstable::ObDatumRow &row, bool &final_result)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(!is_inited_)) {
ret = OB_NOT_INIT;
STORAGE_LOG(WARN, "ObMergeFuser is not inited", K(ret), K(is_inited_));
} else if (OB_FAIL(storage::ObRowFuse::fuse_row(row, result_row_, nop_pos_, final_result))) {
STORAGE_LOG(WARN, "Failed to fuse row", K(ret));
} else if (result_row_.count_ != column_cnt_) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "row count is not valid", K(ret), K(row), K(result_row_), K(column_cnt_));
} else if (is_fuse_row_flag_) {
result_row_.row_flag_.fuse_flag(row.row_flag_);
}
return ret;
}
int ObMergeFuser::preprocess_fuse_row(const blocksstable::ObDatumRow &row, bool &is_need_fuse)
{
UNUSED(row);
int ret = OB_SUCCESS;
clean_nop_pos_and_result_row();
is_need_fuse = true;
return ret;
}
int ObMergeFuser::end_fuse_row(const storage::ObNopPos &nop_pos, blocksstable::ObDatumRow &result_row)
{
if (result_row.row_flag_.is_exist_without_delete()) {
result_row.row_flag_.reset();
result_row.row_flag_.set_flag(ObDmlFlag::DF_INSERT);
}
return OB_SUCCESS;
}
int ObMergeFuser::set_multi_version_flag(const ObMultiVersionRowFlag &row_flag)
{
int ret = OB_SUCCESS;
if (IS_NOT_INIT) {
ret = OB_NOT_INIT;
STORAGE_LOG(WARN, "ObMergeFuser is not inited", K(ret));
} else {
result_row_.set_multi_version_flag(row_flag);
}
return ret;
}
int ObMergeFuser::fuse_row(MERGE_ITER_ARRAY &macro_row_iters)
{
int ret = OB_SUCCESS;
bool is_need_fuse = false;
const int64_t macro_row_iters_cnt = macro_row_iters.count();
if (OB_UNLIKELY(!is_inited())) {
ret = OB_NOT_INIT;
STORAGE_LOG(WARN, "ObMergeFuser not init", K(ret));
} else if (OB_UNLIKELY(macro_row_iters_cnt <= 0)) {
ret = OB_INVALID_ARGUMENT;
STORAGE_LOG(WARN, "Invalid macro row iters to fuse row", K(ret), K(macro_row_iters));
} else if (OB_ISNULL(macro_row_iters.at(0)) || OB_ISNULL(macro_row_iters.at(0)->get_curr_row())) {
ret = OB_INVALID_ARGUMENT;
STORAGE_LOG(WARN, "Invalid macro row iters to fuse row", K(ret), K(macro_row_iters));
} else if (OB_FAIL(preprocess_fuse_row(*macro_row_iters.at(0)->get_curr_row(), is_need_fuse))) {
STORAGE_LOG(WARN, "failed to preprocess_fuse_row", K(ret));
} else if (!is_need_fuse && macro_row_iters.at(0)->get_curr_row()->row_flag_.is_delete()) {
result_row_.row_flag_.reset();
result_row_.row_flag_ = macro_row_iters.at(0)->get_curr_row()->row_flag_;
for (int64_t i = 1; i < macro_row_iters_cnt; ++i) {
result_row_.row_flag_.fuse_flag(macro_row_iters.at(i)->get_curr_row()->row_flag_);
}
} else {
bool final_result = false;
for (int64_t i = 0; OB_SUCC(ret) && !final_result && i < macro_row_iters_cnt; ++i) {
if (OB_FAIL(add_fuse_row(*macro_row_iters.at(i)->get_curr_row(), final_result))) {
STORAGE_LOG(WARN, "Failed to fuse row", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(end_fuse_row(nop_pos_, result_row_))) {
STORAGE_LOG(WARN, "failed to end fuse row", K(ret), KPC(this));
}
}
return ret;
}
// fuse delete row
int ObMergeFuser::fuse_delete_row(
const blocksstable::ObDatumRow &del_row,
const int64_t rowkey_column_cnt)
{
int ret = OB_SUCCESS;
if (!del_row.row_flag_.is_delete()) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "Unexpected row flag", K(ret));
} else {
int64_t copy_cnt = rowkey_column_cnt;
if (del_row.is_uncommitted_row()){
copy_cnt = result_row_.count_;
}
for (int64_t i = 0; i < copy_cnt; ++i) {
result_row_.storage_datums_[i] = del_row.storage_datums_[i];
}
for (int64_t i = copy_cnt; i < result_row_.count_; ++i) {
result_row_.storage_datums_[i].set_nop();
}
if (OB_SUCC(ret)) {
result_row_.row_flag_.set_flag(ObDmlFlag::DF_DELETE);
result_row_.mvcc_row_flag_ = del_row.mvcc_row_flag_;
result_row_.set_compacted_multi_version_row();
STORAGE_LOG(DEBUG, "fuse delete row", K(ret), K(del_row), K(result_row_));
}
}
return ret;
}
bool ObMergeFuser::is_valid() const
{
return (is_inited_ && column_cnt_ > 0);
}
/*
*ObIPartitionMergeFuser
*/
bool ObIPartitionMergeFuser::is_valid() const
{
return ObMergeFuser::is_valid();
}
int ObIPartitionMergeFuser::init(const ObMergeParameter &merge_param, const bool is_fuse_row_flag)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(is_inited())) {
ret = OB_INIT_TWICE;
STORAGE_LOG(WARN, "ObIPartitionMergeFuser init twice", K(ret));
} else if (OB_UNLIKELY(!merge_param.is_valid())) {
ret = OB_INVALID_ARGUMENT;
STORAGE_LOG(WARN, "Invalid argument to init ObIPartitionMergeFuser", K(merge_param), K(ret));
} else if (OB_FAIL(inner_init(merge_param))) {
STORAGE_LOG(WARN, "Failed to inner init", K(ret), K(*this));
} else if (OB_FAIL(base_init(is_fuse_row_flag))){
STORAGE_LOG(WARN, "failed to init ObMergeFuser", K(ret), K(merge_param));
} else {
is_inited_ = true;
STORAGE_LOG(INFO, "Succ to init partition fuser", K(ret), K(*this));
}
return ret;
}
/*
*ObDefaultMergeFuser
*/
int ObDefaultMergeFuser::init(const int64_t column_count)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(is_inited_)) {
ret = OB_INIT_TWICE;
STORAGE_LOG(WARN, "ObMergeFuser init twice", K(ret));
} else if (FALSE_IT(column_cnt_ = column_count)) {
} else if (OB_FAIL(base_init())) {
STORAGE_LOG(WARN, "Failed to init datum row", K(ret));
} else {
is_inited_ = true;
}
return ret;
}
/*
*ObMajorPartitionMergeFuser
*/
ObMajorPartitionMergeFuser::~ObMajorPartitionMergeFuser()
{
default_row_.reset();
generated_cols_.reset();
}
int ObMajorPartitionMergeFuser::inner_init(const ObMergeParameter &merge_param)
{
int ret = OB_SUCCESS;
const common::ObIArray<share::schema::ObColDesc> &multi_version_column_ids = merge_param.static_param_.multi_version_column_descs_;
const ObStorageSchema *schema = merge_param.get_schema();
column_cnt_ = multi_version_column_ids.count();
const bool need_trim_default_row = cluster_version_ >= DATA_VERSION_4_3_1_0 || cluster_version_ < DATA_VERSION_4_3_0_0;
if (OB_FAIL(default_row_.init(allocator_, column_cnt_))) {
STORAGE_LOG(WARN, "Failed to init datum row", K(ret), K_(column_cnt));
} else if (OB_FAIL(schema->get_orig_default_row(multi_version_column_ids, need_trim_default_row, default_row_))) {
STORAGE_LOG(WARN, "Failed to get default row from table schema", K(ret), K(multi_version_column_ids));
} else if (OB_FAIL(ObLobManager::fill_lob_header(allocator_, multi_version_column_ids, default_row_))) {
STORAGE_LOG(WARN, "fail to fill lob header for default row", K(ret), K(multi_version_column_ids));
} else if (FALSE_IT(default_row_.row_flag_.set_flag(ObDmlFlag::DF_UPDATE))) {
} else if (OB_FAIL(generated_cols_.init(column_cnt_))) {
LOG_WARN("Fail to init generated_cols", K(ret), K_(column_cnt));
} else {
const ObColumnSchemaV2 *column_schema = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < column_cnt_; ++i) {
if (OB_HIDDEN_TRANS_VERSION_COLUMN_ID == multi_version_column_ids.at(i).col_id_ ||
OB_HIDDEN_SQL_SEQUENCE_COLUMN_ID == multi_version_column_ids.at(i).col_id_) {
// continue;
} else{
const ObStorageColumnSchema *column_schema = NULL;
if (OB_ISNULL(column_schema = schema->get_column_schema(
multi_version_column_ids.at(i).col_id_))) {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "The column schema is NULL", K(ret), K(i), K(multi_version_column_ids.at(i)));
} else if (column_schema->is_generated_column()
&& !schema->is_storage_index_table()) {
// the generated columns in index are always filled before insert
if (OB_FAIL(generated_cols_.push_back(i))) {
LOG_WARN("Fail to push_back generated_cols", K(ret));
}
}
}
}
}
return ret;
}
int ObMajorPartitionMergeFuser::end_fuse_row(const storage::ObNopPos &nop_pos, blocksstable::ObDatumRow &result_row)
{
int ret = OB_SUCCESS;
if (nop_pos.count() > 0 && result_row.row_flag_.is_exist_without_delete()) {
if (generated_cols_.count() > 0) {
// add defense for generated exprs
int64_t idx = -1;
for (int64_t i = 0; OB_SUCC(ret) && i < nop_pos.count(); i++) {
if (OB_FAIL(nop_pos.get_nop_pos(i, idx))) {
LOG_WARN("Failed to get nop pos", K(i), K(ret));
} else {
for (int64_t j = 0; OB_SUCC(ret) && j < generated_cols_.count(); j++) {
if (idx == generated_cols_.at(j)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Found nop generated columns in major fuser", K(ret), K(i), K(idx),
K(nop_pos), K_(generated_cols), K(result_row));
}
}
}
}
}
if (OB_SUCC(ret)) {
bool final_result = false;
if (OB_FAIL(add_fuse_row(default_row_, final_result))) {
STORAGE_LOG(WARN, "Failed to fuse default row", K(ret));
}
}
}
if (OB_SUCC(ret) && result_row.row_flag_.is_exist_without_delete()) {
result_row.row_flag_.reset();
result_row.row_flag_.set_flag(ObDmlFlag::DF_INSERT);
}
return ret;
}
/*
*ObMinorPartitionMergeFuser
*/
bool ObMinorPartitionMergeFuser::is_valid() const
{
return ObIPartitionMergeFuser::is_valid() && multi_version_rowkey_column_cnt_ > 0;
}
int ObMinorPartitionMergeFuser::inner_init(const ObMergeParameter &merge_param)
{
int ret = OB_SUCCESS;
int64_t column_cnt = 0;
if (OB_UNLIKELY(is_inited_)) {
ret = OB_INIT_TWICE;
STORAGE_LOG(WARN, "ObIPartitionMergeFuser init twice", K(ret));
} else if (OB_FAIL(merge_param.get_schema()->get_store_column_count(column_cnt, true/*full_col*/))) {
STORAGE_LOG(WARN, "failed to get store column count", K(ret), K(merge_param.get_schema()));
} else {
column_cnt_ = column_cnt + storage::ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt();
multi_version_rowkey_column_cnt_ = merge_param.static_param_.multi_version_column_descs_.count();
}
return ret;
}
int ObMinorPartitionMergeFuser::end_fuse_row(const storage::ObNopPos &nop_pos, blocksstable::ObDatumRow &result_row)
{
int ret = OB_SUCCESS;
if (result_row.row_flag_.is_delete() || nop_pos.count_ == 0) {
result_row.set_compacted_multi_version_row();
}
return ret;
}
int ObMinorPartitionMergeFuser::preprocess_fuse_row(const blocksstable::ObDatumRow &row, bool &is_need_fuse)
{
int ret = OB_SUCCESS;
is_need_fuse = true;
clean_nop_pos_and_result_row();
if (row.trans_id_.is_valid()) {
if (!row.mvcc_row_flag_.is_uncommitted_row()) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("uncommitted row is not valid",K(ret), K(row), K(row.trans_id_));
} else {
set_trans_id(row.trans_id_);
}
}
if (OB_FAIL(ret)) {
} else if (row.row_flag_.is_delete()) {
if (OB_FAIL(fuse_delete_row(row, multi_version_rowkey_column_cnt_))) {
STORAGE_LOG(WARN, "failed to fuse_delete_row", K(ret), K(row), K(multi_version_rowkey_column_cnt_));
} else {
is_need_fuse = false;
}
}
return ret;
}
int ObMergeFuserBuilder::build(const ObMergeParameter &merge_param,
const int64_t cluster_version,
ObIAllocator &allocator,
ObIPartitionMergeFuser *&partition_fuser)
{
int ret = OB_SUCCESS;
bool is_fuse_row_flag = true;
partition_fuser = nullptr;
if (OB_UNLIKELY(!merge_param.is_valid())) {
ret = OB_INVALID_ARGUMENT;
STORAGE_LOG(WARN, "Invalid argument to build MergeFuser", K(merge_param), K(ret));
} else {
const ObMergeType merge_type = merge_param.static_param_.get_merge_type();
if (is_major_merge_type(merge_type) && !merge_param.get_schema()->is_row_store()) {
partition_fuser = alloc_helper<ObCOMinorSSTableFuser>(allocator, allocator);
} else if (is_major_or_meta_merge_type(merge_type)) {
is_fuse_row_flag = false;
partition_fuser = alloc_helper<ObMajorPartitionMergeFuser>(allocator, allocator, cluster_version);
} else {
partition_fuser = alloc_helper<ObMinorPartitionMergeFuser>(allocator, allocator);
}
if (OB_ISNULL(partition_fuser)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
STORAGE_LOG(WARN, "Failed to allocate memory for partition fuser", K(ret), K(merge_param));
} else if (OB_FAIL(partition_fuser->init(merge_param, is_fuse_row_flag))) {
STORAGE_LOG(WARN, "Failed to init partition fuser", K(ret));
}
if (OB_FAIL(ret)) {
if (OB_NOT_NULL(partition_fuser)) {
partition_fuser->~ObIPartitionMergeFuser();
allocator.free(partition_fuser);
partition_fuser = nullptr;
}
}
}
return ret;
}
} //compaction
} //oceanbase