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 (StarRocks#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(StarRocks#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 authored Mar 28, 2023
1 parent 92f67c8 commit b8208f4
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 @@ -549,15 +549,25 @@ 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);
}
if (sc_params.sc_directly) {
status = new_tablet->updates()->convert_from(base_tablet, request.alter_version,
sc_params.chunk_changer.get());
} else if (sc_params.sc_sorting) {
status = new_tablet->updates()->reorder_from(base_tablet, request.alter_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.alter_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 @@ -2794,7 +2794,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 @@ -2823,6 +2824,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
_last_compaction_time_ms = UnixMillis();
Expand Down Expand Up @@ -2898,8 +2900,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 @@ -180,7 +180,8 @@ class TabletUpdates {
Status convert_from(const std::shared_ptr<Tablet>& base_tablet, int64_t request_version,
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 @@ -1962,13 +1962,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 @@ -327,6 +327,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 b8208f4

Please sign in to comment.