This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.0 by this push:
new 8af45166949 branch-4.0: [Bug](cloud restore) refresh index id in
rowset schema #57074 (#58660)
8af45166949 is described below
commit 8af4516694913e303831ba07eb9f879d591218f9
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Dec 3 22:23:52 2025 +0800
branch-4.0: [Bug](cloud restore) refresh index id in rowset schema #57074
(#58660)
Cherry-picked from #57074
Co-authored-by: xy720 <[email protected]>
---
be/src/cloud/cloud_snapshot_mgr.cpp | 35 +++
be/src/cloud/cloud_snapshot_mgr.h | 3 +
be/src/olap/snapshot_manager.cpp | 44 +++
be/src/olap/snapshot_manager.h | 4 +
be/src/olap/tablet_schema.cpp | 12 +
be/src/olap/tablet_schema.h | 2 +
be/test/cloud/cloud_snapshot_mgr_test.cpp | 106 ++++++++
be/test/olap/snapshot_manager_test.cpp | 296 +++++++++++++++++++++
be/test/olap/tablet_schema_test.cpp | 92 ++++++-
.../test_backup_restore_reset_index_id.groovy | 161 +++++++++++
10 files changed, 754 insertions(+), 1 deletion(-)
diff --git a/be/src/cloud/cloud_snapshot_mgr.cpp
b/be/src/cloud/cloud_snapshot_mgr.cpp
index a3f3c5dc213..2d471d80975 100644
--- a/be/src/cloud/cloud_snapshot_mgr.cpp
+++ b/be/src/cloud/cloud_snapshot_mgr.cpp
@@ -145,6 +145,9 @@ Status CloudSnapshotMgr::convert_rowsets(
cooldown_meta_id->set_hi(0);
cooldown_meta_id->set_lo(0);
+ TabletSchemaSPtr target_tablet_schema = std::make_shared<TabletSchema>();
+ target_tablet_schema->copy_from(*target_tablet->tablet_schema());
+
TabletSchemaSPtr tablet_schema = std::make_shared<TabletSchema>();
tablet_schema->init_from_pb(in.schema());
@@ -155,10 +158,19 @@ Status CloudSnapshotMgr::convert_rowsets(
RETURN_IF_ERROR(_create_rowset_meta(new_rowset_meta_pb,
rowset_meta_pb, tablet_id,
target_tablet, storage_resource,
tablet_schema,
file_mapping, rowset_id_mapping));
+ if (new_rowset_meta_pb->has_tablet_schema() &&
+ new_rowset_meta_pb->tablet_schema().index_size() > 0) {
+
RETURN_IF_ERROR(_rename_index_ids(*new_rowset_meta_pb->mutable_tablet_schema(),
+ target_tablet_schema));
+ }
Version rowset_version = {rowset_meta_pb.start_version(),
rowset_meta_pb.end_version()};
rs_version_map[rowset_version] = new_rowset_meta_pb;
}
+ if (out->schema().index_size() > 0) {
+ RETURN_IF_ERROR(_rename_index_ids(*out->mutable_schema(),
target_tablet_schema));
+ }
+
if (!rowset_id_mapping.empty() && in.has_delete_bitmap()) {
const auto& old_del_bitmap_pb = in.delete_bitmap();
DeleteBitmapPB* new_del_bitmap_pb = out->mutable_delete_bitmap();
@@ -178,6 +190,7 @@ Status CloudSnapshotMgr::convert_rowsets(
new_del_bitmap_pb->set_rowset_ids(cast_set<int>(i),
it->second.to_string());
}
}
+
return Status::OK();
}
@@ -271,5 +284,27 @@ Status CloudSnapshotMgr::_create_rowset_meta(
return Status::OK();
}
+Status CloudSnapshotMgr::_rename_index_ids(TabletSchemaPB& schema_pb,
+ const TabletSchemaSPtr&
tablet_schema) const {
+ if (tablet_schema == nullptr) {
+ return Status::OK();
+ }
+
+ for (int i = 0; i < schema_pb.index_size(); ++i) {
+ TabletIndexPB* index_pb = schema_pb.mutable_index(i);
+ for (int32_t col_unique_id : index_pb->col_unique_id()) {
+ auto local_index = tablet_schema->get_index(col_unique_id,
index_pb->index_type(),
+
index_pb->index_suffix_name());
+ if (local_index) {
+ if (index_pb->index_id() != local_index->index_id()) {
+ index_pb->set_index_id(local_index->index_id());
+ }
+ break;
+ }
+ }
+ }
+ return Status::OK();
+}
+
#include "common/compile_check_end.h"
} // namespace doris
diff --git a/be/src/cloud/cloud_snapshot_mgr.h
b/be/src/cloud/cloud_snapshot_mgr.h
index e1888ac412e..e249e3e4865 100644
--- a/be/src/cloud/cloud_snapshot_mgr.h
+++ b/be/src/cloud/cloud_snapshot_mgr.h
@@ -90,6 +90,9 @@ private:
std::unordered_map<std::string, std::string>&
file_mapping,
std::unordered_map<RowsetId, RowsetId>&
rowset_id_mapping);
+ Status _rename_index_ids(TabletSchemaPB& schema_pb,
+ const TabletSchemaSPtr& tablet_schema) const;
+
private:
CloudStorageEngine& _engine;
std::atomic<uint64_t> _snapshot_base_id {0};
diff --git a/be/src/olap/snapshot_manager.cpp b/be/src/olap/snapshot_manager.cpp
index 899a4bef265..684a93b150a 100644
--- a/be/src/olap/snapshot_manager.cpp
+++ b/be/src/olap/snapshot_manager.cpp
@@ -183,6 +183,13 @@ Result<std::vector<PendingRowsetGuard>>
SnapshotManager::convert_rowset_ids(
"clone dir not existed when convert rowsetids. clone_dir={}",
clone_dir));
}
+ TabletSharedPtr target_tablet =
_engine.tablet_manager()->get_tablet(tablet_id);
+ TabletSchemaSPtr target_tablet_schema = nullptr;
+ if (target_tablet != nullptr) {
+ target_tablet_schema = std::make_shared<TabletSchema>();
+ target_tablet_schema->copy_from(*target_tablet->tablet_schema());
+ }
+
// load original tablet meta
auto cloned_meta_file = fmt::format("{}/{}.hdr", clone_dir, tablet_id);
TabletMetaPB cloned_tablet_meta_pb;
@@ -241,6 +248,11 @@ Result<std::vector<PendingRowsetGuard>>
SnapshotManager::convert_rowset_ids(
rowset_meta->set_partition_id(partition_id);
}
+ if (rowset_meta->has_tablet_schema() &&
rowset_meta->tablet_schema().index_size() > 0) {
+ RETURN_IF_ERROR_RESULT(
+ _rename_index_ids(*rowset_meta->mutable_tablet_schema(),
target_tablet_schema));
+ }
+
Version rowset_version = {visible_rowset.start_version(),
visible_rowset.end_version()};
rs_version_map[rowset_version] = rowset_meta;
}
@@ -277,6 +289,16 @@ Result<std::vector<PendingRowsetGuard>>
SnapshotManager::convert_rowset_ids(
if (partition_id != -1) {
rowset_meta->set_partition_id(partition_id);
}
+
+ if (rowset_meta->has_tablet_schema() &&
rowset_meta->tablet_schema().index_size() > 0) {
+ RETURN_IF_ERROR_RESULT(
+ _rename_index_ids(*rowset_meta->mutable_tablet_schema(),
target_tablet_schema));
+ }
+ }
+
+ if (new_tablet_meta_pb.schema().index_size() > 0) {
+ RETURN_IF_ERROR_RESULT(
+ _rename_index_ids(*new_tablet_meta_pb.mutable_schema(),
target_tablet_schema));
}
if (!rowset_id_mapping.empty() &&
cloned_tablet_meta_pb.has_delete_bitmap()) {
@@ -346,6 +368,28 @@ Status SnapshotManager::_rename_rowset_id(const
RowsetMetaPB& rs_meta_pb,
return Status::OK();
}
+Status SnapshotManager::_rename_index_ids(TabletSchemaPB& schema_pb,
+ const TabletSchemaSPtr&
tablet_schema) const {
+ if (tablet_schema == nullptr) {
+ return Status::OK();
+ }
+
+ for (int i = 0; i < schema_pb.index_size(); ++i) {
+ TabletIndexPB* index_pb = schema_pb.mutable_index(i);
+ for (int32_t col_unique_id : index_pb->col_unique_id()) {
+ auto local_index = tablet_schema->get_index(col_unique_id,
index_pb->index_type(),
+
index_pb->index_suffix_name());
+ if (local_index) {
+ if (index_pb->index_id() != local_index->index_id()) {
+ index_pb->set_index_id(local_index->index_id());
+ }
+ break;
+ }
+ }
+ }
+ return Status::OK();
+}
+
// get snapshot path: curtime.seq.timeout
// eg: 20190819221234.3.86400
Status SnapshotManager::_calc_snapshot_id_path(const TabletSharedPtr& tablet,
int64_t timeout_s,
diff --git a/be/src/olap/snapshot_manager.h b/be/src/olap/snapshot_manager.h
index 668bb860e1b..01303dac4f2 100644
--- a/be/src/olap/snapshot_manager.h
+++ b/be/src/olap/snapshot_manager.h
@@ -30,6 +30,7 @@
namespace doris {
class RowsetMetaPB;
+class TabletSchemaPB;
class TSnapshotRequest;
struct RowsetId;
class StorageEngine;
@@ -133,6 +134,9 @@ private:
TabletSchemaSPtr tablet_schema, const RowsetId&
next_id,
RowsetMetaPB* new_rs_meta_pb);
+ Status _rename_index_ids(TabletSchemaPB& schema_pb,
+ const TabletSchemaSPtr& tablet_schema) const;
+
StorageEngine& _engine;
std::atomic<uint64_t> _snapshot_base_id {0};
diff --git a/be/src/olap/tablet_schema.cpp b/be/src/olap/tablet_schema.cpp
index b3331cdfb18..0408800d0d0 100644
--- a/be/src/olap/tablet_schema.cpp
+++ b/be/src/olap/tablet_schema.cpp
@@ -1673,6 +1673,18 @@ const TabletIndex*
TabletSchema::get_ngram_bf_index(int32_t col_unique_id) const
return nullptr;
}
+const TabletIndex* TabletSchema::get_index(int32_t col_unique_id, IndexType
index_type,
+ const std::string& suffix_path)
const {
+ IndexKey index_key(index_type, col_unique_id, suffix_path);
+ auto it = _col_id_suffix_to_index.find(index_key);
+ if (it != _col_id_suffix_to_index.end()) {
+ if (!it->second.empty() && it->second[0] < _indexes.size()) {
+ return _indexes[it->second[0]].get();
+ }
+ }
+ return nullptr;
+}
+
vectorized::Block TabletSchema::create_block(
const std::vector<uint32_t>& return_columns,
const std::unordered_set<uint32_t>* tablet_columns_need_convert_null)
const {
diff --git a/be/src/olap/tablet_schema.h b/be/src/olap/tablet_schema.h
index 429e102c9a2..9d76424acbe 100644
--- a/be/src/olap/tablet_schema.h
+++ b/be/src/olap/tablet_schema.h
@@ -545,6 +545,8 @@ public:
bool has_ngram_bf_index(int32_t col_unique_id) const;
const TabletIndex* get_ngram_bf_index(int32_t col_unique_id) const;
+ const TabletIndex* get_index(int32_t col_unique_id, IndexType index_type,
+ const std::string& suffix_path) const;
void update_indexes_from_thrift(const std::vector<doris::TOlapTableIndex>&
indexes);
// If schema version is not set, it should be -1
int32_t schema_version() const { return _schema_version; }
diff --git a/be/test/cloud/cloud_snapshot_mgr_test.cpp
b/be/test/cloud/cloud_snapshot_mgr_test.cpp
index 3ca72cd7eb8..5b097be04d4 100644
--- a/be/test/cloud/cloud_snapshot_mgr_test.cpp
+++ b/be/test/cloud/cloud_snapshot_mgr_test.cpp
@@ -61,6 +61,38 @@ TEST_F(CloudSnapshotMgrTest, TestConvertRowsets) {
input_meta_pb.set_schema_hash(123456);
*input_meta_pb.mutable_tablet_uid() = TabletUid::gen_uid().to_proto();
+ TabletSchemaPB* input_schema = input_meta_pb.mutable_schema();
+ input_schema->set_keys_type(KeysType::DUP_KEYS);
+ input_schema->set_num_short_key_columns(1);
+ input_schema->set_num_rows_per_row_block(1024);
+ input_schema->set_compress_kind(COMPRESS_LZ4);
+
+ ColumnPB* col1 = input_schema->add_column();
+ col1->set_unique_id(1);
+ col1->set_name("col1");
+ col1->set_type("INT");
+ col1->set_is_key(true);
+ col1->set_aggregation("NONE");
+
+ ColumnPB* col2 = input_schema->add_column();
+ col2->set_unique_id(2);
+ col2->set_name("col2");
+ col2->set_type("VARCHAR");
+ col2->set_is_key(false);
+ col2->set_aggregation("REPLACE");
+
+ doris::TabletIndexPB* index1 = input_schema->add_index();
+ index1->set_index_id(1001);
+ index1->set_index_name("test_index1");
+ index1->set_index_type(IndexType::BITMAP);
+ index1->add_col_unique_id(2);
+
+ doris::TabletIndexPB* index2 = input_schema->add_index();
+ index2->set_index_id(1002);
+ index2->set_index_name("test_index2");
+ index2->set_index_type(IndexType::INVERTED);
+ index2->add_col_unique_id(2);
+
RowsetMetaPB* rowset_meta = input_meta_pb.add_rs_metas();
RowsetId rowset_id;
rowset_id.init(10000);
@@ -78,8 +110,21 @@ TEST_F(CloudSnapshotMgrTest, TestConvertRowsets) {
rowset_meta->set_rowset_state(RowsetStatePB::VISIBLE);
rowset_meta->set_newest_write_timestamp(1678901234567890);
+ TabletSchemaPB* rowset_schema = rowset_meta->mutable_tablet_schema();
+ rowset_schema->CopyFrom(*input_schema);
+
auto tablet_meta = std::make_shared<TabletMeta>();
tablet_meta->init_from_pb(input_meta_pb);
+
+ TabletSchemaSPtr local_tablet_schema = std::make_shared<TabletSchema>();
+ local_tablet_schema->init_from_pb(input_meta_pb.schema());
+
+ // reset the index id
+ input_schema->mutable_index(0)->set_index_id(2001);
+ input_schema->mutable_index(1)->set_index_id(2002);
+ rowset_meta->mutable_tablet_schema()->mutable_index(0)->set_index_id(2001);
+ rowset_meta->mutable_tablet_schema()->mutable_index(1)->set_index_id(2002);
+
CloudTabletSPtr target_tablet = std::make_shared<CloudTablet>(*_engine,
tablet_meta);
StorageResource storage_resource {_fs};
std::unordered_map<std::string, std::string> file_mapping;
@@ -92,6 +137,16 @@ TEST_F(CloudSnapshotMgrTest, TestConvertRowsets) {
EXPECT_EQ(output_meta_pb.rs_metas(0).tablet_id(), 3000);
EXPECT_EQ(output_meta_pb.rs_metas(0).rowset_id(), 0);
EXPECT_NE(output_meta_pb.rs_metas(0).rowset_id_v2(),
rowset_id.to_string());
+ EXPECT_TRUE(output_meta_pb.has_schema());
+ EXPECT_EQ(output_meta_pb.schema().index_size(), 2);
+ EXPECT_EQ(output_meta_pb.schema().index(0).index_id(), 1001);
+ EXPECT_EQ(output_meta_pb.schema().index(0).index_name(), "test_index1");
+ EXPECT_EQ(output_meta_pb.schema().index(1).index_id(), 1002);
+ EXPECT_EQ(output_meta_pb.schema().index(1).index_name(), "test_index2");
+ EXPECT_TRUE(output_meta_pb.rs_metas(0).has_tablet_schema());
+ EXPECT_EQ(output_meta_pb.rs_metas(0).tablet_schema().index_size(), 2);
+ EXPECT_EQ(output_meta_pb.rs_metas(0).tablet_schema().index(0).index_id(),
1001);
+ EXPECT_EQ(output_meta_pb.rs_metas(0).tablet_schema().index(1).index_id(),
1002);
EXPECT_EQ(output_meta_pb.rs_metas(0).num_segments(), 3);
EXPECT_EQ(output_meta_pb.rs_metas(0).num_rows(), 100);
EXPECT_EQ(output_meta_pb.rs_metas(0).start_version(), 100);
@@ -105,4 +160,55 @@ TEST_F(CloudSnapshotMgrTest, TestConvertRowsets) {
EXPECT_TRUE(status.ok());
}
+TEST_F(CloudSnapshotMgrTest, TestRenameIndexIds) {
+ TabletSchemaPB source_schema_pb;
+ source_schema_pb.set_keys_type(KeysType::DUP_KEYS);
+ source_schema_pb.set_num_short_key_columns(1);
+ source_schema_pb.set_num_rows_per_row_block(1024);
+ source_schema_pb.set_compress_kind(COMPRESS_LZ4);
+
+ ColumnPB* col1 = source_schema_pb.add_column();
+ col1->set_unique_id(1);
+ col1->set_name("col1");
+ col1->set_type("INT");
+ col1->set_is_key(true);
+ col1->set_aggregation("NONE");
+
+ ColumnPB* col2 = source_schema_pb.add_column();
+ col2->set_unique_id(2);
+ col2->set_name("col2");
+ col2->set_type("VARCHAR");
+ col2->set_is_key(false);
+ col2->set_aggregation("REPLACE");
+
+ doris::TabletIndexPB* index1 = source_schema_pb.add_index();
+ index1->set_index_id(1001);
+ index1->set_index_name("test_index1");
+ index1->set_index_type(IndexType::BITMAP);
+ index1->add_col_unique_id(2);
+
+ doris::TabletIndexPB* index2 = source_schema_pb.add_index();
+ index2->set_index_id(1002);
+ index2->set_index_name("test_index2");
+ index2->set_index_type(IndexType::INVERTED);
+ index2->add_col_unique_id(2);
+
+ TabletSchemaSPtr local_tablet_schema = std::make_shared<TabletSchema>();
+ local_tablet_schema->init_from_pb(source_schema_pb);
+
+ // reset the index id
+ source_schema_pb.mutable_index(0)->set_index_id(2001);
+ source_schema_pb.mutable_index(1)->set_index_id(2002);
+
+ Status status = _snapshot_mgr->_rename_index_ids(source_schema_pb,
local_tablet_schema);
+ EXPECT_TRUE(status.ok());
+ EXPECT_EQ(source_schema_pb.index_size(), 2);
+ EXPECT_EQ(source_schema_pb.index(0).index_id(), 1001);
+ EXPECT_EQ(source_schema_pb.index(0).index_name(), "test_index1");
+ EXPECT_EQ(source_schema_pb.index(0).index_type(), IndexType::BITMAP);
+ EXPECT_EQ(source_schema_pb.index(1).index_id(), 1002);
+ EXPECT_EQ(source_schema_pb.index(1).index_name(), "test_index2");
+ EXPECT_EQ(source_schema_pb.index(1).index_type(), IndexType::INVERTED);
+}
+
} // namespace doris
diff --git a/be/test/olap/snapshot_manager_test.cpp
b/be/test/olap/snapshot_manager_test.cpp
new file mode 100644
index 00000000000..d7ea196b655
--- /dev/null
+++ b/be/test/olap/snapshot_manager_test.cpp
@@ -0,0 +1,296 @@
+// 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/snapshot_manager.h"
+
+#include <gen_cpp/AgentService_types.h>
+#include <gtest/gtest-message.h>
+#include <gtest/gtest-test-part.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "common/status.h"
+#include "gtest/gtest_pred_impl.h"
+#include "io/fs/local_file_system.h"
+#include "olap/data_dir.h"
+#include "olap/olap_common.h"
+#include "olap/olap_define.h"
+#include "olap/options.h"
+#include "olap/storage_engine.h"
+#include "olap/tablet.h"
+#include "olap/tablet_manager.h"
+#include "olap/tablet_meta.h"
+#include "runtime/exec_env.h"
+#include "util/uid_util.h"
+
+namespace doris {
+class SnapshotManagerTest : public testing::Test {
+public:
+ virtual void SetUp() {
+ _engine_data_path = "./be/test/olap/test_data/converter_test_data/tmp";
+ auto st =
io::global_local_filesystem()->delete_directory(_engine_data_path);
+ ASSERT_TRUE(st.ok()) << st;
+ st =
io::global_local_filesystem()->create_directory(_engine_data_path);
+ ASSERT_TRUE(st.ok()) << st;
+ EXPECT_TRUE(
+
io::global_local_filesystem()->create_directory(_engine_data_path +
"/meta").ok());
+
+ config::tablet_map_shard_size = 1;
+ config::txn_map_shard_size = 1;
+ config::txn_shard_size = 1;
+ EngineOptions options;
+ options.backend_uid = UniqueId::gen_uid();
+ auto engine = std::make_unique<StorageEngine>(options);
+ ExecEnv::GetInstance()->set_storage_engine(std::move(engine));
+ _engine = &ExecEnv::GetInstance()->storage_engine().to_local();
+ _data_dir = new DataDir(*_engine, _engine_data_path, 1000000000);
+ static_cast<void>(_data_dir->init());
+ }
+
+ virtual void TearDown() {
+ SAFE_DELETE(_data_dir);
+
EXPECT_TRUE(io::global_local_filesystem()->delete_directory(_engine_data_path).ok());
+ ExecEnv::GetInstance()->set_storage_engine(nullptr);
+ _engine = nullptr;
+ }
+
+protected:
+ StorageEngine* _engine = nullptr;
+ DataDir* _data_dir = nullptr;
+ std::string _engine_data_path;
+};
+
+TEST_F(SnapshotManagerTest, TestMakeSnapshotInvalidParameters) {
+ TSnapshotRequest request;
+ request.tablet_id = 10001;
+ request.schema_hash = 12345;
+
+ std::string* null_snapshot_path = nullptr;
+ bool allow_incremental_clone = false;
+
+ Status status = _engine->snapshot_mgr()->make_snapshot(request,
null_snapshot_path,
+
&allow_incremental_clone);
+ EXPECT_FALSE(status.ok());
+ EXPECT_EQ(status.code(), ErrorCode::INVALID_ARGUMENT);
+}
+
+TEST_F(SnapshotManagerTest, TestReleaseSnapshotInvalidPath) {
+ std::string invalid_path = "/invalid/snapshot/path";
+
+ Status status = _engine->snapshot_mgr()->release_snapshot(invalid_path);
+ EXPECT_FALSE(status.ok());
+ EXPECT_EQ(status.code(), ErrorCode::CE_CMD_PARAMS_ERROR);
+}
+
+TEST_F(SnapshotManagerTest, TestConvertRowsetIdsInvalidDir) {
+ std::string non_existent_dir = "/non/existent/dir";
+ int64_t tablet_id = 10003;
+ int64_t replica_id = 1;
+ int64_t table_id = 1000;
+ int64_t partition_id = 100;
+ int32_t schema_hash = 54321;
+
+ auto result = _engine->snapshot_mgr()->convert_rowset_ids(
+ non_existent_dir, tablet_id, replica_id, table_id, partition_id,
schema_hash);
+ EXPECT_FALSE(result.has_value());
+ EXPECT_EQ(result.error().code(), ErrorCode::DIR_NOT_EXIST);
+}
+
+TEST_F(SnapshotManagerTest, TestConvertRowsetIdsNormal) {
+ std::string clone_dir = _engine_data_path + "/clone_dir_local";
+
EXPECT_TRUE(io::global_local_filesystem()->create_directory(clone_dir).ok());
+
+ TabletMetaPB tablet_meta_pb;
+ tablet_meta_pb.set_tablet_id(10006);
+ tablet_meta_pb.set_schema_hash(12346);
+ tablet_meta_pb.set_replica_id(1);
+ tablet_meta_pb.set_table_id(1000);
+ tablet_meta_pb.set_partition_id(100);
+
+ TabletSchemaPB* schema_pb = tablet_meta_pb.mutable_schema();
+ schema_pb->set_num_short_key_columns(1);
+ schema_pb->set_num_rows_per_row_block(1024);
+ schema_pb->set_compress_kind(COMPRESS_LZ4);
+
+ // column 0
+ ColumnPB* column = schema_pb->add_column();
+ column->set_unique_id(0);
+ column->set_name("k1");
+ column->set_type("INT");
+ column->set_is_key(true);
+ column->set_is_nullable(false);
+ column->set_length(4);
+ column->set_index_length(4);
+ column->set_precision(0);
+ column->set_frac(0);
+
+ // column 1
+ column = schema_pb->add_column();
+ column->set_unique_id(1);
+ column->set_name("v1");
+ column->set_type("INT");
+ column->set_is_key(false);
+ column->set_is_nullable(true);
+ column->set_length(4);
+ column->set_index_length(4);
+ column->set_precision(0);
+ column->set_frac(0);
+
+ // index 0
+ TabletIndexPB* index_pb = schema_pb->add_index();
+ index_pb->set_index_id(1001);
+ index_pb->set_index_name("test_index");
+ index_pb->set_index_type(IndexType::BITMAP);
+ index_pb->add_col_unique_id(0);
+
+ // rowset meta 0
+ RowsetMetaPB* rowset_meta = tablet_meta_pb.add_rs_metas();
+ rowset_meta->set_rowset_id(10001);
+ rowset_meta->set_rowset_id_v2("02000000000000010001");
+ rowset_meta->set_tablet_id(10006);
+ rowset_meta->set_tablet_schema_hash(12346);
+ rowset_meta->set_rowset_type(BETA_ROWSET);
+ rowset_meta->set_rowset_state(VISIBLE);
+ rowset_meta->set_start_version(0);
+ rowset_meta->set_end_version(1);
+ rowset_meta->set_num_rows(100);
+ rowset_meta->set_total_disk_size(1024);
+ rowset_meta->set_data_disk_size(1000);
+ rowset_meta->set_index_disk_size(24);
+ rowset_meta->set_empty(false);
+
+ TabletSchemaPB* rowset_schema = rowset_meta->mutable_tablet_schema();
+ rowset_schema->CopyFrom(*schema_pb);
+
+ // new ids
+ int64_t tablet_id = 20006;
+ int64_t replica_id = 2;
+ int64_t table_id = 2000;
+ int64_t partition_id = 200;
+ int32_t schema_hash = 65432;
+
+ // save the meta file
+ std::string meta_file = clone_dir + "/" + std::to_string(tablet_id) +
".hdr";
+ EXPECT_TRUE(TabletMeta::save(meta_file, tablet_meta_pb).ok());
+
+ TCreateTabletReq create_tablet_req;
+ create_tablet_req.__set_tablet_id(tablet_id);
+ create_tablet_req.__set_replica_id(replica_id);
+ create_tablet_req.__set_table_id(table_id);
+ create_tablet_req.__set_partition_id(partition_id);
+ create_tablet_req.__set_version(1);
+
+ TTabletSchema tablet_schema;
+ tablet_schema.__set_schema_hash(schema_hash);
+
tablet_schema.__set_short_key_column_count(schema_pb->num_short_key_columns());
+ tablet_schema.__set_keys_type(TKeysType::AGG_KEYS);
+ tablet_schema.__set_storage_type(TStorageType::COLUMN);
+
+ std::vector<TColumn> columns;
+ for (int i = 0; i < schema_pb->column_size(); i++) {
+ const ColumnPB& column_pb = schema_pb->column(i);
+ TColumn tcolumn;
+ tcolumn.__set_column_name(column_pb.name());
+ tcolumn.__set_is_key(column_pb.is_key());
+ TColumnType col_type;
+ col_type.__set_type(TPrimitiveType::INT);
+ tcolumn.__set_column_type(col_type);
+ tcolumn.__set_is_allow_null(column_pb.is_nullable());
+ if (!column_pb.is_key()) {
+ tcolumn.__set_aggregation_type(TAggregationType::SUM);
+ }
+ columns.push_back(tcolumn);
+ }
+ tablet_schema.__set_columns(columns);
+
+ std::vector<TOlapTableIndex> indexes;
+ for (int i = 0; i < schema_pb->index_size(); i++) {
+ TOlapTableIndex tindex;
+ tindex.__set_index_id(2001 + i);
+ tindex.__set_index_name("test_index");
+ tindex.__set_index_type(TIndexType::BITMAP);
+ tindex.__set_columns({"k1"});
+ tindex.__set_column_unique_ids({0});
+ indexes.push_back(tindex);
+ }
+ tablet_schema.__set_indexes(indexes);
+
+ create_tablet_req.__set_tablet_schema(tablet_schema);
+ std::vector<DataDir*> stores;
+ stores.push_back(_data_dir);
+ RuntimeProfile profile("CreateTablet");
+
+ Status status =
_engine->tablet_manager()->create_tablet(create_tablet_req, stores, &profile);
+ EXPECT_TRUE(status.ok()) << "Failed to create tablet: " << status;
+
+ auto result = _engine->snapshot_mgr()->convert_rowset_ids(clone_dir,
tablet_id, replica_id,
+ table_id,
partition_id, schema_hash);
+ EXPECT_TRUE(result.has_value());
+
+ TabletMetaPB converted_meta_pb;
+ EXPECT_TRUE(TabletMeta::load_from_file(meta_file,
&converted_meta_pb).ok());
+
+ EXPECT_EQ(converted_meta_pb.tablet_id(), tablet_id);
+ EXPECT_EQ(converted_meta_pb.schema_hash(), schema_hash);
+ EXPECT_EQ(converted_meta_pb.replica_id(), replica_id);
+ EXPECT_EQ(converted_meta_pb.table_id(), table_id);
+ EXPECT_EQ(converted_meta_pb.partition_id(), partition_id);
+
+ // verify schema
+ EXPECT_EQ(converted_meta_pb.schema().num_short_key_columns(), 1);
+ EXPECT_EQ(converted_meta_pb.schema().column_size(), 2);
+
+ // verify index
+ EXPECT_EQ(converted_meta_pb.schema().index_size(), 1);
+ const TabletIndexPB& converted_index = converted_meta_pb.schema().index(0);
+ EXPECT_EQ(converted_index.index_id(), 2001);
+ EXPECT_EQ(converted_index.index_name(), "test_index");
+ EXPECT_EQ(converted_index.index_type(), IndexType::BITMAP);
+ EXPECT_EQ(converted_index.col_unique_id_size(), 1);
+ EXPECT_EQ(converted_index.col_unique_id(0), 0);
+
+ // verify rowset meta
+ EXPECT_EQ(converted_meta_pb.rs_metas_size(), 1);
+ const RowsetMetaPB& converted_rowset_meta = converted_meta_pb.rs_metas(0);
+ EXPECT_NE(converted_rowset_meta.rowset_id(), 10001);
+ EXPECT_NE(converted_rowset_meta.rowset_id_v2(), "02000000000000010001");
+ EXPECT_EQ(converted_rowset_meta.tablet_id(), tablet_id);
+ EXPECT_EQ(converted_rowset_meta.rowset_type(), BETA_ROWSET);
+ EXPECT_EQ(converted_rowset_meta.rowset_state(), VISIBLE);
+ EXPECT_EQ(converted_rowset_meta.start_version(), 0);
+ EXPECT_EQ(converted_rowset_meta.end_version(), 1);
+ EXPECT_EQ(converted_rowset_meta.num_rows(), 100);
+ EXPECT_EQ(converted_rowset_meta.total_disk_size(), 1024);
+ EXPECT_TRUE(converted_rowset_meta.has_tablet_schema());
+
+ // verify rowset schema
+ const TabletSchemaPB& converted_rowset_schema =
converted_rowset_meta.tablet_schema();
+ EXPECT_EQ(converted_rowset_schema.num_short_key_columns(), 1);
+ EXPECT_EQ(converted_rowset_schema.column_size(), 2);
+ EXPECT_EQ(converted_rowset_schema.index_size(), 1);
+
+ // verify rowset index
+ const TabletIndexPB& converted_rowset_index =
converted_rowset_schema.index(0);
+ EXPECT_EQ(converted_rowset_index.index_id(), 2001);
+ EXPECT_EQ(converted_rowset_index.index_name(), "test_index");
+ EXPECT_EQ(converted_rowset_index.index_type(), IndexType::BITMAP);
+ EXPECT_EQ(converted_rowset_index.col_unique_id_size(), 1);
+ EXPECT_EQ(converted_rowset_index.col_unique_id(0), 0);
+}
+} // namespace doris
diff --git a/be/test/olap/tablet_schema_test.cpp
b/be/test/olap/tablet_schema_test.cpp
index 6b9665d780a..b421e059f27 100644
--- a/be/test/olap/tablet_schema_test.cpp
+++ b/be/test/olap/tablet_schema_test.cpp
@@ -803,4 +803,94 @@ TEST_F(TabletSchemaTest,
test_tablet_schema_need_record_variant_extended_schema)
EXPECT_FALSE(schema_multiple_variants.need_record_variant_extended_schema());
}
-} // namespace doris
\ No newline at end of file
+TEST_F(TabletSchemaTest, test_tablet_schema_get_index) {
+ TabletSchema schema;
+
+ TabletColumn col1;
+ col1.set_unique_id(14001);
+ col1.set_name("test_col1");
+ col1.set_type(FieldType::OLAP_FIELD_TYPE_STRING);
+ schema.append_column(col1);
+
+ TabletColumn col2;
+ col2.set_unique_id(14002);
+ col2.set_name("test_col2");
+ col2.set_type(FieldType::OLAP_FIELD_TYPE_VARCHAR);
+ schema.append_column(col2);
+
+ TabletIndex inverted_index;
+ TabletIndexPB inverted_index_pb;
+ inverted_index_pb.set_index_id(5001);
+ inverted_index_pb.set_index_name("inverted_idx");
+ inverted_index_pb.set_index_type(IndexType::INVERTED);
+ inverted_index_pb.add_col_unique_id(14001);
+ inverted_index.init_from_pb(inverted_index_pb);
+
+ TabletIndex bitmap_index;
+ TabletIndexPB bitmap_index_pb;
+ bitmap_index_pb.set_index_id(5002);
+ bitmap_index_pb.set_index_name("bitmap_idx");
+ bitmap_index_pb.set_index_type(IndexType::BITMAP);
+ bitmap_index_pb.add_col_unique_id(14001);
+ bitmap_index.init_from_pb(bitmap_index_pb);
+
+ TabletIndex ann_index;
+ TabletIndexPB ann_index_pb;
+ ann_index_pb.set_index_id(5003);
+ ann_index_pb.set_index_name("ann_idx");
+ ann_index_pb.set_index_type(IndexType::ANN);
+ ann_index_pb.add_col_unique_id(14002);
+ ann_index.init_from_pb(ann_index_pb);
+
+ TabletIndex ngram_bf_index;
+ TabletIndexPB ngram_bf_index_pb;
+ ngram_bf_index_pb.set_index_id(5004);
+ ngram_bf_index_pb.set_index_name("ngram_bf_idx");
+ ngram_bf_index_pb.set_index_type(IndexType::NGRAM_BF);
+ ngram_bf_index_pb.add_col_unique_id(14002);
+ ngram_bf_index.init_from_pb(ngram_bf_index_pb);
+
+ schema.append_index(std::move(inverted_index));
+ schema.append_index(std::move(bitmap_index));
+ schema.append_index(std::move(ann_index));
+ schema.append_index(std::move(ngram_bf_index));
+
+ const TabletIndex* found_inverted = schema.get_index(14001,
IndexType::INVERTED, "");
+ EXPECT_NE(nullptr, found_inverted);
+ EXPECT_EQ("inverted_idx", found_inverted->index_name());
+ EXPECT_EQ(5001, found_inverted->index_id());
+ const TabletIndex* found_bitmap = schema.get_index(14001,
IndexType::BITMAP, "");
+ EXPECT_NE(nullptr, found_bitmap);
+ EXPECT_EQ("bitmap_idx", found_bitmap->index_name());
+ EXPECT_EQ(5002, found_bitmap->index_id());
+ const TabletIndex* found_ann = schema.get_index(14002, IndexType::ANN, "");
+ EXPECT_NE(nullptr, found_ann);
+ EXPECT_EQ("ann_idx", found_ann->index_name());
+ EXPECT_EQ(5003, found_ann->index_id());
+ const TabletIndex* found_ngram_bf = schema.get_index(14002,
IndexType::NGRAM_BF, "");
+ EXPECT_NE(nullptr, found_ngram_bf);
+ EXPECT_EQ("ngram_bf_idx", found_ngram_bf->index_name());
+ EXPECT_EQ(5004, found_ngram_bf->index_id());
+ const TabletIndex* not_found = schema.get_index(99999,
IndexType::INVERTED, "");
+ EXPECT_EQ(nullptr, not_found);
+ const TabletIndex* empty_suffix = schema.get_index(14001,
IndexType::INVERTED, "");
+ EXPECT_NE(nullptr, empty_suffix);
+ EXPECT_EQ("inverted_idx", empty_suffix->index_name());
+ const TabletIndex* with_suffix = schema.get_index(14001,
IndexType::INVERTED, "test_suffix");
+ EXPECT_EQ(nullptr, with_suffix);
+
+ EXPECT_TRUE(found_inverted->is_inverted_index());
+ EXPECT_EQ(IndexType::INVERTED, found_inverted->index_type());
+ EXPECT_EQ(IndexType::BITMAP, found_bitmap->index_type());
+ EXPECT_EQ(IndexType::ANN, found_ann->index_type());
+ EXPECT_EQ(IndexType::NGRAM_BF, found_ngram_bf->index_type());
+
+ const auto& inverted_col_ids = found_inverted->col_unique_ids();
+ EXPECT_EQ(1, inverted_col_ids.size());
+ EXPECT_EQ(14001, inverted_col_ids[0]);
+ const auto& ann_col_ids = found_ann->col_unique_ids();
+ EXPECT_EQ(1, ann_col_ids.size());
+ EXPECT_EQ(14002, ann_col_ids[0]);
+}
+
+} // namespace doris
diff --git
a/regression-test/suites/backup_restore/test_backup_restore_reset_index_id.groovy
b/regression-test/suites/backup_restore/test_backup_restore_reset_index_id.groovy
new file mode 100644
index 00000000000..6c4fd8c4c01
--- /dev/null
+++
b/regression-test/suites/backup_restore/test_backup_restore_reset_index_id.groovy
@@ -0,0 +1,161 @@
+// 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.
+
+suite("test_backup_restore_reset_index_id", "backup_restore") {
+ String suiteName = "test_backup_restore_reset_index_id"
+ String dbName = "${suiteName}_db"
+ String repoName = "${suiteName}_repo_" +
UUID.randomUUID().toString().replace("-", "")
+ String snapshotName = "${suiteName}_snapshot"
+ String tableName = "${suiteName}_table"
+
+ def syncer = getSyncer()
+ syncer.createS3Repository(repoName)
+ sql "CREATE DATABASE IF NOT EXISTS ${dbName}"
+
+ sql "DROP TABLE IF EXISTS ${dbName}.${tableName}"
+ sql """
+ CREATE TABLE if NOT EXISTS ${dbName}.${tableName}
+ (
+ `test` INT,
+ `id` INT,
+ `username` varchar(32) NULL DEFAULT "",
+ `extra` varchar(32) NULL DEFAULT "",
+ INDEX idx_ngrambf (`username`) USING NGRAM_BF PROPERTIES("bf_size"
= "256", "gram_size" = "3"),
+ INDEX idx_extra_ngram (`extra`) USING NGRAM_BF
PROPERTIES("bf_size" = "256", "gram_size" = "3"),
+ INDEX idx_extra_inverted (`extra`) USING INVERTED
+ )
+ ENGINE=OLAP
+ DUPLICATE KEY(`test`, `id`)
+ DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES (
+ "replication_allocation" = "tag.location.default: 1"
+ )
+ """
+ List<String> values = []
+ int numRows = 10;
+ for (int j = 0; j <= numRows; ++j) {
+ values.add("(${j}, ${j}1, \"${j} ${j*10}\", \"index_test\")")
+ }
+ sql "INSERT INTO ${dbName}.${tableName} VALUES ${values.join(",")}"
+
+ def indexes = sql_return_maparray "SHOW INDEX FROM ${dbName}.${tableName}"
+ logger.info("current indexes: ${indexes}")
+
+ def query_table_index_id = { indexName ->
+ def res = sql_return_maparray "SHOW TABLETS FROM
${dbName}.${tableName}"
+ def tabletId = res[0].TabletId
+ res = sql_return_maparray "SHOW TABLET ${tabletId}"
+ def dbId = res[0].DbId
+ def tableId = res[0].TableId
+ res = sql_return_maparray """ SHOW PROC
"/dbs/${dbId}/${tableId}/indexes" """
+ for (def record in res) {
+ if (record.KeyName == indexName) {
+ return record.IndexId
+ }
+ }
+ throw new Exception("index ${indexName} is not exists")
+ }
+
+ def query_tablet_schema_index_id = { indexName ->
+ def metaUrl = sql_return_maparray("SHOW TABLETS FROM
${dbName}.${tableName}").get(0).MetaUrl
+ def (code, out, err) = curl("GET", metaUrl)
+ assertEquals(code, 0)
+ def jsonMeta = parseJson(out.trim())
+
+ for (def index : jsonMeta.schema.index) {
+ if (index.index_name == indexName) {
+ return index.index_id
+ }
+ }
+ throw new Exception("index ${indexName} is not exists")
+ }
+
+ def query_rowset_schema_index_id = { indexName ->
+ def metaUrl = sql_return_maparray("SHOW TABLETS FROM
${dbName}.${tableName}").get(0).MetaUrl
+ def (code, out, err) = curl("GET", metaUrl)
+ assertEquals(code, 0)
+ def jsonMeta = parseJson(out.trim())
+ assertTrue(jsonMeta.rs_metas.size() > 0)
+
+ for (def meta : jsonMeta.rs_metas) {
+ for (def index : meta.tablet_schema.index) {
+ if (index.index_name == indexName) {
+ return index.index_id
+ }
+ }
+ }
+ throw new Exception("index ${indexName} is not exists")
+ }
+
+ try {
+ sql """ ADMIN SET FRONTEND CONFIG ("restore_reset_index_id" = "true")
"""
+ sql """
+ BACKUP SNAPSHOT ${dbName}.${snapshotName}
+ TO `${repoName}`
+ ON (`${tableName}`)
+ """
+
+ syncer.waitSnapshotFinish(dbName)
+
+ def snapshot = syncer.getSnapshotTimestamp(repoName, snapshotName)
+ assertTrue(snapshot != null)
+
+ def oldIndexNgramBfId = query_table_index_id("idx_ngrambf")
+ def oldIndexExtraNgram = query_table_index_id("idx_extra_ngram")
+ logger.info("the exists index id of idx_ngrambf is
${oldIndexNgramBfId}")
+ logger.info("the exists index id of idx_ngrambf is
${oldIndexExtraNgram}")
+
+ sql "DROP TABLE ${dbName}.${tableName}"
+
+ sql """
+ RESTORE SNAPSHOT ${dbName}.${snapshotName}
+ FROM `${repoName}`
+ ON (`${tableName}`)
+ PROPERTIES
+ (
+ "backup_timestamp" = "${snapshot}",
+ "reserve_replica" = "true"
+ )
+ """
+
+ syncer.waitAllRestoreFinish(dbName)
+
+ indexes = sql_return_maparray "SHOW INDEX FROM ${dbName}.${tableName}"
+ logger.info("current indexes: ${indexes}")
+
+ def newIndexNgramBfId = query_table_index_id("idx_ngrambf")
+ def newIndexExtraNgram = query_table_index_id("idx_extra_ngram")
+ assertTrue(oldIndexNgramBfId != newIndexNgramBfId, "old index id
${oldIndexNgramBfId}, new index id ${newIndexNgramBfId}")
+ assertTrue(oldIndexExtraNgram != newIndexExtraNgram, "old index id
${oldIndexExtraNgram}, new index id ${newIndexExtraNgram}")
+
+ def indexNgramBfId = query_tablet_schema_index_id("idx_ngrambf")
+ def indexExtraNgram = query_tablet_schema_index_id("idx_extra_ngram")
+ assertEquals(indexNgramBfId, newIndexNgramBfId.toLong(), "tablet index
id ${indexNgramBfId}, new index id ${newIndexNgramBfId}")
+ assertEquals(indexExtraNgram, newIndexExtraNgram.toLong(), "tablet
index id ${indexExtraNgram}, new index id ${newIndexExtraNgram}")
+
+ indexNgramBfId = query_rowset_schema_index_id("idx_ngrambf")
+ indexExtraNgram = query_rowset_schema_index_id("idx_extra_ngram")
+ assertEquals(indexNgramBfId, newIndexNgramBfId.toLong(), "tablet index
id ${indexNgramBfId}, new index id ${newIndexNgramBfId}")
+ assertEquals(indexExtraNgram, newIndexExtraNgram.toLong(), "tablet
index id ${indexExtraNgram}, new index id ${newIndexExtraNgram}")
+ } finally {
+ sql """ ADMIN SET FRONTEND CONFIG ("restore_reset_index_id" = "false")
"""
+ }
+
+ sql "DROP TABLE ${dbName}.${tableName} FORCE"
+ sql "DROP DATABASE ${dbName} FORCE"
+ sql "DROP REPOSITORY `${repoName}`"
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]