Skip to content

Commit

Permalink
[BugFix] Be maybe crash when we do schema change for primary key tabl…
Browse files Browse the repository at this point in the history
…e with separate primary key and sort key (#20035)

If we create a primary key table with a separate primary key and sort key, BE maybe crash if we do a schema change in the table(add column/drop column)
The reason is that we use column id as the sort key index in the tablet, and we only support reordering the sort key in this pr(#13642) which assumes the number of columns in the origin tablet and new tablet during schema change is the same. However, if we add/drop a column, the sort key index in the new tablet will be different from the origin tablet and we will execute reorder which may cause BE crash.

Signed-off-by: zhangqiang <[email protected]>
  • Loading branch information
sevev committed Dec 7, 2023
1 parent 481964b commit 886638f
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 9 deletions.
16 changes: 13 additions & 3 deletions be/src/storage/schema_change.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -771,8 +771,17 @@ Status SchemaChangeHandler::_do_process_alter_tablet_v2(const TAlterTabletReqV2&
if (base_tablet->keys_type() == KeysType::PRIMARY_KEYS) {
const auto& base_sort_key_idxes = base_tablet->tablet_schema().sort_key_idxes();
const auto& new_sort_key_idxes = new_tablet->tablet_schema().sort_key_idxes();
if (std::mismatch(new_sort_key_idxes.begin(), new_sort_key_idxes.end(), base_sort_key_idxes.begin()).first !=
new_sort_key_idxes.end()) {
std::vector<int32_t> base_sort_key_unique_ids;
std::vector<int32_t> new_sort_key_unique_ids;
for (auto idx : base_sort_key_idxes) {
base_sort_key_unique_ids.emplace_back(base_tablet->tablet_schema().column(idx).unique_id());
}
for (auto idx : new_sort_key_idxes) {
new_sort_key_unique_ids.emplace_back(new_tablet->tablet_schema().column(idx).unique_id());
}
if (std::mismatch(new_sort_key_unique_ids.begin(), new_sort_key_unique_ids.end(),
base_sort_key_unique_ids.begin())
.first != new_sort_key_unique_ids.end()) {
sc_params.sc_directly = !(sc_params.sc_sorting = true);
}

Expand All @@ -788,7 +797,8 @@ Status SchemaChangeHandler::_do_process_alter_tablet_v2(const TAlterTabletReqV2&
if (sc_params.sc_directly) {
status = new_tablet->updates()->convert_from(base_tablet, request_version, sc_params.chunk_changer.get());
} else if (sc_params.sc_sorting) {
status = new_tablet->updates()->reorder_from(base_tablet, request_version);
status = new_tablet->updates()->reorder_from(base_tablet, request.alter_version,
sc_params.chunk_changer.get());
} else {
status = new_tablet->updates()->link_from(base_tablet.get(), request_version);
}
Expand Down
12 changes: 9 additions & 3 deletions be/src/storage/tablet_updates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3082,7 +3082,8 @@ Status TabletUpdates::_convert_from_base_rowset(const std::shared_ptr<Tablet>& b
return rowset_writer->flush();
}

Status TabletUpdates::reorder_from(const std::shared_ptr<Tablet>& base_tablet, int64_t request_version) {
Status TabletUpdates::reorder_from(const std::shared_ptr<Tablet>& base_tablet, int64_t request_version,
ChunkChanger* chunk_changer) {
OlapStopWatch watch;
DCHECK(_tablet.tablet_state() == TABLET_NOTREADY)
<< "tablet state is not TABLET_NOTREADY, reorder_from is not allowed"
Expand Down Expand Up @@ -3113,6 +3114,7 @@ Status TabletUpdates::reorder_from(const std::shared_ptr<Tablet>& base_tablet, i
<< " request_version:" << request_version << " reason:" << status;
return status;
}
std::unique_ptr<MemPool> mem_pool(new MemPool());

// disable compaction temporarily when tablet just loaded
int64_t prev_last_compaction_time_ms = _last_compaction_time_ms;
Expand Down Expand Up @@ -3189,8 +3191,12 @@ Status TabletUpdates::reorder_from(const std::shared_ptr<Tablet>& base_tablet, i
}
}

for (auto i = 0; i < base_chunk->num_columns(); ++i) {
base_chunk->get_column_by_index(i)->swap_column(*new_chunk->get_column_by_index(i));
if (!chunk_changer->change_chunk_v2(base_chunk, new_chunk, base_schema, new_schema, mem_pool.get())) {
std::string err_msg =
strings::Substitute("failed to convert chunk data. base tablet:$0, new tablet:$1",
base_tablet->tablet_id(), _tablet.tablet_id());
LOG(WARNING) << err_msg;
return Status::InternalError(err_msg);
}

total_bytes += static_cast<double>(new_chunk->memory_usage());
Expand Down
3 changes: 2 additions & 1 deletion be/src/storage/tablet_updates.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ class TabletUpdates {
Status convert_from(const std::shared_ptr<Tablet>& base_tablet, int64_t request_version,
vectorized::ChunkChanger* chunk_changer);

Status reorder_from(const std::shared_ptr<Tablet>& base_tablet, int64_t request_version);
Status reorder_from(const std::shared_ptr<Tablet>& base_tablet, int64_t request_version,
ChunkChanger* chunk_changer);

Status load_snapshot(const SnapshotMeta& snapshot_meta, bool restore_from_backup = false);

Expand Down
25 changes: 23 additions & 2 deletions be/test/storage/tablet_updates_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2315,13 +2315,34 @@ void TabletUpdatesTest::test_reorder_from(bool enable_persistent_index) {
ASSERT_TRUE(_tablet->rowset_commit(4, create_rowset_schema_change_sort_key(_tablet, keys)).ok());

tablet_with_sort_key1->set_tablet_state(TABLET_NOTREADY);
ASSERT_TRUE(tablet_with_sort_key1->updates()->reorder_from(_tablet, 4).ok());
auto chunk_changer = std::make_unique<ChunkChanger>(tablet_with_sort_key1->tablet_schema());
for (int i = 0; i < tablet_with_sort_key1->tablet_schema().num_columns(); ++i) {
const auto& new_column = tablet_with_sort_key1->tablet_schema().column(i);
int32_t column_index = _tablet->field_index(std::string{new_column.name()});
auto column_mapping = chunk_changer->get_mutable_column_mapping(i);
if (column_index >= 0) {
column_mapping->ref_column = column_index;
column_mapping->ref_base_reader_column_index = i;
}
}

ASSERT_TRUE(tablet_with_sort_key1->updates()->reorder_from(_tablet, 4, chunk_changer.get()).ok());

ASSERT_EQ(N, read_tablet_and_compare_schema_changed_sort_key1(tablet_with_sort_key1, 4, keys));

const auto& tablet_with_sort_key2 = create_tablet_with_sort_key(rand(), rand(), {2});
tablet_with_sort_key2->set_tablet_state(TABLET_NOTREADY);
ASSERT_TRUE(tablet_with_sort_key2->updates()->reorder_from(tablet_with_sort_key1, 4).ok());
chunk_changer = std::make_unique<ChunkChanger>(tablet_with_sort_key2->tablet_schema());
for (int i = 0; i < tablet_with_sort_key2->tablet_schema().num_columns(); ++i) {
const auto& new_column = tablet_with_sort_key2->tablet_schema().column(i);
int32_t column_index = _tablet->field_index(std::string{new_column.name()});
auto column_mapping = chunk_changer->get_mutable_column_mapping(i);
if (column_index >= 0) {
column_mapping->ref_column = column_index;
column_mapping->ref_base_reader_column_index = i;
}
}
ASSERT_TRUE(tablet_with_sort_key2->updates()->reorder_from(tablet_with_sort_key1, 4, chunk_changer.get()).ok());
ASSERT_EQ(N, read_tablet_and_compare_schema_changed_sort_key2(tablet_with_sort_key2, 4, keys));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ protected void runPendingJob() throws AlterCancelException {
}
if (sortKeyIdxes != null) {
copiedSortKeyIdxes = sortKeyIdxes;
} else if (copiedSortKeyIdxes != null && !copiedSortKeyIdxes.isEmpty()) {
sortKeyIdxes = copiedSortKeyIdxes;
}
for (Tablet shadowTablet : shadowIdx.getTablets()) {
long shadowTabletId = shadowTablet.getId();
Expand Down

0 comments on commit 886638f

Please sign in to comment.