Skip to content

Commit

Permalink
[Schema Change] support fast add/drop column (apache#49)
Browse files Browse the repository at this point in the history
* [feature](schema-change) support fast schema change. coauthor: yixiutt

* [schema change] Using columns desc from fe to read data. coauthor: Lchangliang

* [feature](schema change) schema change optimize for add/drop columns.

1.add uniqueId field for class column.
2.schema change for add/drop columns directly update schema meta

Co-authored-by: yixiutt <yixiu@selectdb.com>
Co-authored-by: SWJTU-ZhangLei <1091517373@qq.com>

[Feature](schema change) fix write and add regression test (apache#69)

Co-authored-by: yixiutt <yixiu@selectdb.com>

[schema change] be ssupport that delete use newest schema

add delete regression test

fix regression case (apache#107)

tmp

[feature](schema change) light schema change exclude rollup and agg/uniq/dup key type.

[feature](schema change) fe olapTable maxUniqueId write in disk.

[feature](schema change) add rpc iface for sc add column.

[feature](schema change) add columnsDesc to TPushReq for ligtht sc.

resolve the deadlock when schema change (apache#124)

fix columns from fe don't has bitmap_index flag (apache#134)

add update/delete case

construct MATERIALIZED schema from origin schema when insert

fix not vectorized compaction coredump

use segment cache

choose newest schema by schema version when compaction (apache#182)

[bugfix](schema change) fix ligth schema change problem.

[feature](schema change) light schema change add alter job. (#1)

fix be ut

[bug] (schema change) unique drop key column should not light schema
change

[feature](schema change) add schema change regression-test.

fix regression test

[bugfix](schema change) fix multi alter clauses for light schema change. (#2)

[bugfix](schema change) fix multi clauses calculate column unique id (#3)

modify PushTask process (apache#217)

[Bugfix](schema change) fix jobId replay cause bdbje exception.

[bug](schema change) fix max col unique id repeatitive. (apache#232)

[optimize](schema change) modify pendingMaxColUniqueId generate rule.

fix compaction error
* fix be ut

* fix snapshot load core

fix unique_id error (apache#278)

[refact](fe) remove redundant code for light schema change. (#4)

[refact](fe) remove redundant code for light schema change. (#4)

format fe core

format be core

fix be ut

modify fe meta version

fix rebase error
  • Loading branch information
Lchangliang committed Jul 6, 2022
1 parent c936abd commit 4b827eb
Show file tree
Hide file tree
Showing 98 changed files with 5,191 additions and 750 deletions.
28 changes: 20 additions & 8 deletions be/src/exec/olap_scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
#include "exprs/expr_context.h"
#include "gen_cpp/PaloInternalService_types.h"
#include "olap/decimal12.h"
#include "olap/field.h"
#include "olap/storage_engine.h"
#include "olap/tablet_schema.h"
#include "olap/uint24.h"
#include "olap_scan_node.h"
#include "olap_utils.h"
Expand Down Expand Up @@ -86,6 +88,14 @@ Status OlapScanner::prepare(
LOG(WARNING) << ss.str();
return Status::InternalError(ss.str());
}
_tablet_schema = _tablet->tablet_schema();
if (!_parent->_olap_scan_node.columns_desc.empty() &&
_parent->_olap_scan_node.columns_desc[0].col_unique_id >= 0) {
_tablet_schema.clear_columns();
for (const auto& column_desc : _parent->_olap_scan_node.columns_desc) {
_tablet_schema.append_column(TabletColumn(column_desc));
}
}
{
std::shared_lock rdlock(_tablet->get_header_lock());
const RowsetSharedPtr rowset = _tablet->rowset_with_max_version();
Expand Down Expand Up @@ -168,6 +178,7 @@ Status OlapScanner::_init_tablet_reader_params(
RETURN_IF_ERROR(_init_return_columns(!_tablet_reader_params.direct_mode));

_tablet_reader_params.tablet = _tablet;
_tablet_reader_params.tablet_schema = &_tablet_schema;
_tablet_reader_params.reader_type = READER_QUERY;
_tablet_reader_params.aggregation = _aggregation;
_tablet_reader_params.version = Version(0, _version);
Expand Down Expand Up @@ -208,7 +219,7 @@ Status OlapScanner::_init_tablet_reader_params(
_tablet_reader_params.return_columns.push_back(i);
}
for (auto index : _return_columns) {
if (_tablet->tablet_schema().column(index).is_key()) {
if (_tablet_schema.column(index).is_key()) {
continue;
} else {
_tablet_reader_params.return_columns.push_back(index);
Expand All @@ -217,13 +228,12 @@ Status OlapScanner::_init_tablet_reader_params(
}

// use _tablet_reader_params.return_columns, because reader use this to merge sort
Status res =
_read_row_cursor.init(_tablet->tablet_schema(), _tablet_reader_params.return_columns);
Status res = _read_row_cursor.init(_tablet_schema, _tablet_reader_params.return_columns);
if (!res.ok()) {
LOG(WARNING) << "fail to init row cursor.res = " << res;
return Status::InternalError("failed to initialize storage read row cursor");
}
_read_row_cursor.allocate_memory_for_string_type(_tablet->tablet_schema());
_read_row_cursor.allocate_memory_for_string_type(_tablet_schema);

// If a agg node is this scan node direct parent
// we will not call agg object finalize method in scan node,
Expand All @@ -242,15 +252,17 @@ Status OlapScanner::_init_return_columns(bool need_seq_col) {
if (!slot->is_materialized()) {
continue;
}
int32_t index = _tablet->field_index(slot->col_name());
int32_t index = slot->col_unique_id() >= 0
? _tablet_schema.field_index(slot->col_unique_id())
: _tablet_schema.field_index(slot->col_name());
if (index < 0) {
std::stringstream ss;
ss << "field name is invalid. field=" << slot->col_name();
LOG(WARNING) << ss.str();
return Status::InternalError(ss.str());
}
_return_columns.push_back(index);
if (slot->is_nullable() && !_tablet->tablet_schema().column(index).is_nullable())
if (slot->is_nullable() && !_tablet_schema.column(index).is_nullable())
_tablet_columns_convert_to_null_set.emplace(index);
_query_slots.push_back(slot);
}
Expand All @@ -259,13 +271,13 @@ Status OlapScanner::_init_return_columns(bool need_seq_col) {
if (_tablet->tablet_schema().has_sequence_col() && need_seq_col) {
bool has_replace_col = false;
for (auto col : _return_columns) {
if (_tablet->tablet_schema().column(col).aggregation() ==
if (_tablet_schema.column(col).aggregation() ==
FieldAggregationMethod::OLAP_FIELD_AGGREGATION_REPLACE) {
has_replace_col = true;
break;
}
}
if (auto sequence_col_idx = _tablet->tablet_schema().sequence_col_idx();
if (auto sequence_col_idx = _tablet_schema.sequence_col_idx();
has_replace_col && std::find(_return_columns.begin(), _return_columns.end(),
sequence_col_idx) == _return_columns.end()) {
_return_columns.push_back(sequence_col_idx);
Expand Down
2 changes: 2 additions & 0 deletions be/src/exec/olap_scanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ class OlapScanner {
MonotonicStopWatch _watcher;

std::shared_ptr<MemTracker> _mem_tracker;

TabletSchema _tablet_schema;
};

} // namespace doris
13 changes: 13 additions & 0 deletions be/src/exec/tablet_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ void OlapTableIndexSchema::to_protobuf(POlapTableIndexSchema* pindex) const {
for (auto slot : slots) {
pindex->add_columns(slot->col_name());
}
for (auto column : columns) {
column->to_schema_pb(pindex->add_columns_desc());
}
}

Status OlapTableSchemaParam::init(const POlapTableSchemaParam& pschema) {
Expand All @@ -57,6 +60,11 @@ Status OlapTableSchemaParam::init(const POlapTableSchemaParam& pschema) {
}
index->slots.emplace_back(it->second);
}
for (auto& pcolumn_desc : p_index.columns_desc()) {
TabletColumn* tc = _obj_pool.add(new TabletColumn());
tc->init_from_pb(pcolumn_desc);
index->columns.emplace_back(tc);
}
_indexes.emplace_back(index);
}

Expand Down Expand Up @@ -90,6 +98,11 @@ Status OlapTableSchemaParam::init(const TOlapTableSchemaParam& tschema) {
}
index->slots.emplace_back(it->second);
}
for (auto& tcolumn_desc : t_index.columns_desc) {
TabletColumn* tc = _obj_pool.add(new TabletColumn());
tc->init_from_thrift(tcolumn_desc);
index->columns.emplace_back(tc);
}
_indexes.emplace_back(index);
}

Expand Down
2 changes: 2 additions & 0 deletions be/src/exec/tablet_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "common/status.h"
#include "gen_cpp/Descriptors_types.h"
#include "gen_cpp/descriptors.pb.h"
#include "olap/tablet_schema.h"
#include "runtime/descriptors.h"
#include "runtime/raw_value.h"
#include "runtime/tuple.h"
Expand All @@ -41,6 +42,7 @@ struct OlapTableIndexSchema {
int64_t index_id;
std::vector<SlotDescriptor*> slots;
int32_t schema_hash;
std::vector<TabletColumn*> columns;

void to_protobuf(POlapTableIndexSchema* pindex) const;
};
Expand Down
2 changes: 1 addition & 1 deletion be/src/olap/base_tablet.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class BaseTablet : public std::enable_shared_from_this<BaseTablet> {
bool equal(int64_t tablet_id, int32_t schema_hash);

// properties encapsulated in TabletSchema
const TabletSchema& tablet_schema() const;
virtual const TabletSchema& tablet_schema() const;

protected:
void _gen_tablet_path();
Expand Down
8 changes: 4 additions & 4 deletions be/src/olap/collect_iterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ Status CollectIterator::add_child(RowsetReaderSharedPtr rs_reader) {
// then merged with the base rowset.
void CollectIterator::build_heap(const std::vector<RowsetReaderSharedPtr>& rs_readers) {
DCHECK(rs_readers.size() == _children.size());
_reverse = _reader->_tablet->tablet_schema().keys_type() == KeysType::UNIQUE_KEYS;
SortType sort_type = _reader->_tablet->tablet_schema().sort_type();
int sort_col_num = _reader->_tablet->tablet_schema().sort_col_num();
_reverse = _reader->_tablet_schema->keys_type() == KeysType::UNIQUE_KEYS;
SortType sort_type = _reader->_tablet_schema->sort_type();
int sort_col_num = _reader->_tablet_schema->sort_col_num();
if (_children.empty()) {
_inner_iter.reset(nullptr);
return;
Expand Down Expand Up @@ -200,7 +200,7 @@ CollectIterator::Level0Iterator::Level0Iterator(RowsetReaderSharedPtr rs_reader,
CollectIterator::Level0Iterator::~Level0Iterator() = default;

Status CollectIterator::Level0Iterator::init() {
RETURN_NOT_OK_LOG(_row_cursor.init(_reader->_tablet->tablet_schema(), _reader->_seek_columns),
RETURN_NOT_OK_LOG(_row_cursor.init(*_reader->_tablet_schema, _reader->_seek_columns),
"failed to init row cursor");
return (this->*_refresh_current_row)();
}
Expand Down
27 changes: 20 additions & 7 deletions be/src/olap/compaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,21 @@ Status Compaction::do_compaction_impl(int64_t permits) {

LOG(INFO) << "start " << merge_type << compaction_name() << ". tablet=" << _tablet->full_name()
<< ", output_version=" << _output_version << ", permits: " << permits;
const TabletSchema* cur_tablet_schema = nullptr;
if (_input_rowsets.front()->rowset_meta()->tablet_schema() == nullptr) {
cur_tablet_schema = &(_tablet->tablet_schema());
} else {
// get cur schema if rowset schema exist, rowset schema must be newer than tablet schema
auto max_version_rowset =
std::max_element(_input_rowsets.begin(), _input_rowsets.end(),
[](const RowsetSharedPtr& a, const RowsetSharedPtr& b) {
return a->rowset_meta()->tablet_schema()->schema_version() <
b->rowset_meta()->tablet_schema()->schema_version();
});
cur_tablet_schema = (*max_version_rowset)->rowset_meta()->tablet_schema();
}

RETURN_NOT_OK(construct_output_rowset_writer());
RETURN_NOT_OK(construct_output_rowset_writer(cur_tablet_schema));
RETURN_NOT_OK(construct_input_rowset_readers());
TRACE("prepare finished");

Expand All @@ -149,11 +162,11 @@ Status Compaction::do_compaction_impl(int64_t permits) {
Status res;

if (use_vectorized_compaction) {
res = Merger::vmerge_rowsets(_tablet, compaction_type(), _input_rs_readers,
_output_rs_writer.get(), &stats);
res = Merger::vmerge_rowsets(_tablet, compaction_type(), cur_tablet_schema,
_input_rs_readers, _output_rs_writer.get(), &stats);
} else {
res = Merger::merge_rowsets(_tablet, compaction_type(), _input_rs_readers,
_output_rs_writer.get(), &stats);
res = Merger::merge_rowsets(_tablet, compaction_type(), cur_tablet_schema,
_input_rs_readers, _output_rs_writer.get(), &stats);
}

if (!res.ok()) {
Expand Down Expand Up @@ -216,8 +229,8 @@ Status Compaction::do_compaction_impl(int64_t permits) {
return Status::OK();
}

Status Compaction::construct_output_rowset_writer() {
return _tablet->create_rowset_writer(_output_version, VISIBLE, NONOVERLAPPING,
Status Compaction::construct_output_rowset_writer(const TabletSchema* schema) {
return _tablet->create_rowset_writer(_output_version, VISIBLE, NONOVERLAPPING, schema,
&_output_rs_writer);
}

Expand Down
2 changes: 1 addition & 1 deletion be/src/olap/compaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class Compaction {
Status modify_rowsets();
void gc_output_rowset();

Status construct_output_rowset_writer();
Status construct_output_rowset_writer(const TabletSchema* schama);
Status construct_input_rowset_readers();

Status check_version_continuity(const std::vector<RowsetSharedPtr>& rowsets);
Expand Down
141 changes: 141 additions & 0 deletions be/src/olap/convert_rowset.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

#include "olap/convert_rowset.h"

namespace doris {

Status ConvertRowset::do_convert() {
if (!_tablet->init_succeeded()) {
return Status::OLAPInternalError(OLAP_ERR_INPUT_PARAMETER_ERROR);
}
std::unique_lock<std::mutex> base_compaction_lock(_tablet->get_base_compaction_lock(),
std::try_to_lock);
std::unique_lock<std::mutex> cumulative_compaction_lock(
_tablet->get_cumulative_compaction_lock(), std::try_to_lock);
if (!base_compaction_lock.owns_lock() || !cumulative_compaction_lock.owns_lock()) {
LOG(INFO) << "The tablet is under compaction. tablet=" << _tablet->full_name();
return Status::OLAPInternalError(OLAP_ERR_CE_TRY_CE_LOCK_ERROR);
}

std::vector<RowsetSharedPtr> alpah_rowsets;
_tablet->find_alpha_rowsets(&alpah_rowsets);

Merger::Statistics stats;
Status res;
const size_t max_convert_row_count = 20000000;
size_t row_count = 0;
for (size_t i = 0; i < alpah_rowsets.size(); ++i) {
Version output_version =
Version(alpah_rowsets[i]->start_version(), alpah_rowsets[i]->end_version());

RowsetReaderSharedPtr input_rs_reader;
RETURN_NOT_OK(alpah_rowsets[i]->create_reader(&input_rs_reader));

std::unique_ptr<RowsetWriter> output_rs_writer;
RETURN_NOT_OK(_tablet->create_rowset_writer(output_version, VISIBLE, NONOVERLAPPING,
&_tablet->tablet_schema(), &output_rs_writer));
res = Merger::merge_rowsets(_tablet, ReaderType::READER_BASE_COMPACTION,
&_tablet->tablet_schema(), {input_rs_reader},
output_rs_writer.get(), &stats);

if (!res.ok()) {
LOG(WARNING) << "fail to convert rowset. res=" << res
<< ", tablet=" << _tablet->full_name();
return res;
} else {
auto output_rowset = output_rs_writer->build();
if (output_rowset == nullptr) {
LOG(WARNING) << "rowset writer build failed"
<< ", tablet=" << _tablet->full_name();
return Status::OLAPInternalError(OLAP_ERR_MALLOC_ERROR);
}

RETURN_NOT_OK(check_correctness(alpah_rowsets[i], output_rowset, stats));

row_count += alpah_rowsets[i]->num_rows();

RETURN_NOT_OK(_modify_rowsets(alpah_rowsets[i], output_rowset));

LOG(INFO) << "succeed to convert rowset"
<< ". tablet=" << _tablet->full_name()
<< ", output_version=" << output_version
<< ", disk=" << _tablet->data_dir()->path();

if (row_count >= max_convert_row_count) {
break;
}
}
}
return Status::OK();
}

Status ConvertRowset::check_correctness(RowsetSharedPtr input_rowset, RowsetSharedPtr output_rowset,
const Merger::Statistics& stats) {
// 1. check row number
if (input_rowset->num_rows() !=
output_rowset->num_rows() + stats.merged_rows + stats.filtered_rows) {
LOG(WARNING) << "row_num does not match between input and output! "
<< "input_row_num=" << input_rowset->num_rows()
<< ", merged_row_num=" << stats.merged_rows
<< ", filtered_row_num=" << stats.filtered_rows
<< ", output_row_num=" << output_rowset->num_rows();

// ATTN(cmy): We found that the num_rows in some rowset meta may be set to the wrong value,
// but it is not known which version of the code has the problem. So when the convert
// result is inconsistent, we then try to verify by num_rows recorded in segment_groups.
// If the check passes, ignore the error and set the correct value in the output rowset meta
// to fix this problem.
// Only handle alpha rowset because we only find this bug in alpha rowset
int64_t num_rows = _get_input_num_rows_from_seg_grps(input_rowset);
if (num_rows == -1) {
return Status::OLAPInternalError(OLAP_ERR_CHECK_LINES_ERROR);
}
if (num_rows != output_rowset->num_rows() + stats.merged_rows + stats.filtered_rows) {
// If it is still incorrect, it may be another problem
LOG(WARNING) << "row_num got from seg groups does not match between cumulative input "
"and output! "
<< "input_row_num=" << num_rows << ", merged_row_num=" << stats.merged_rows
<< ", filtered_row_num=" << stats.filtered_rows
<< ", output_row_num=" << output_rowset->num_rows();

return Status::OLAPInternalError(OLAP_ERR_CHECK_LINES_ERROR);
}
}
return Status::OK();
}

int64_t ConvertRowset::_get_input_num_rows_from_seg_grps(RowsetSharedPtr rowset) {
int64_t num_rows = 0;
for (auto& seg_grp : rowset->rowset_meta()->alpha_rowset_extra_meta_pb().segment_groups()) {
num_rows += seg_grp.num_rows();
}
return num_rows;
}
Status ConvertRowset::_modify_rowsets(RowsetSharedPtr input_rowset, RowsetSharedPtr output_rowset) {
std::vector<RowsetSharedPtr> input_rowsets;
input_rowsets.push_back(input_rowset);

std::vector<RowsetSharedPtr> output_rowsets;
output_rowsets.push_back(output_rowset);

std::lock_guard<std::shared_mutex> wrlock(_tablet->get_header_lock());
RETURN_NOT_OK(_tablet->modify_rowsets(output_rowsets, input_rowsets, true));
_tablet->save_meta();
return Status::OK();
}
} // namespace doris
Loading

0 comments on commit 4b827eb

Please sign in to comment.