-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[opt](segment) Ignore not-found segments in query and load paths #61844
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 3 commits
03410a6
c3371a0
152eff1
9d46c42
47f2191
779e021
0edbb33
9f587cb
93578cd
60bb3c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -251,7 +251,14 @@ Status BetaRowset::load_segments(int64_t seg_id_begin, int64_t seg_id_end, | |
| int64_t seg_id = seg_id_begin; | ||
| while (seg_id < seg_id_end) { | ||
| std::shared_ptr<segment_v2::Segment> segment; | ||
| RETURN_IF_ERROR(load_segment(seg_id, nullptr, &segment)); | ||
| auto st = load_segment(seg_id, nullptr, &segment); | ||
| if (st.is<ErrorCode::NOT_FOUND>() && config::ignore_not_found_segment) { | ||
| LOG(WARNING) << "segment not found, skip it. rowset_id=" << rowset_id() | ||
| << ", seg_id=" << seg_id; | ||
| seg_id++; | ||
| continue; | ||
|
||
| } | ||
| RETURN_IF_ERROR(st); | ||
| segments->push_back(std::move(segment)); | ||
| seg_id++; | ||
| } | ||
|
|
@@ -260,6 +267,9 @@ Status BetaRowset::load_segments(int64_t seg_id_begin, int64_t seg_id_end, | |
|
|
||
| Status BetaRowset::load_segment(int64_t seg_id, OlapReaderStatistics* stats, | ||
| segment_v2::SegmentSharedPtr* segment) { | ||
| DBUG_EXECUTE_IF("BetaRowset::load_segment.return_not_found", { | ||
| return Status::Error<ErrorCode::NOT_FOUND>("injected segment not found, seg_id={}", seg_id); | ||
| }); | ||
| auto fs = _rowset_meta->fs(); | ||
| if (!fs) { | ||
| return Status::Error<INIT_FAILED>("get fs failed"); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,8 +40,15 @@ Status LazyInitSegmentIterator::init(const StorageReadOptions& opts) { | |
| std::shared_ptr<Segment> segment; | ||
| { | ||
| SegmentCacheHandle segment_cache_handle; | ||
| RETURN_IF_ERROR(SegmentLoader::instance()->load_segment( | ||
| _rowset, _segment_id, &segment_cache_handle, _should_use_cache, false, opts.stats)); | ||
| auto st = SegmentLoader::instance()->load_segment( | ||
| _rowset, _segment_id, &segment_cache_handle, _should_use_cache, false, opts.stats); | ||
| if (st.is<ErrorCode::NOT_FOUND>() && config::ignore_not_found_segment) { | ||
| LOG(WARNING) << "segment not found, skip it. rowset_id=" << _rowset->rowset_id() | ||
| << ", seg_id=" << _segment_id; | ||
| // _inner_iterator remains nullptr, next_batch() will return EOF | ||
| return Status::OK(); | ||
| } | ||
| RETURN_IF_ERROR(st); | ||
|
Comment on lines
+44
to
+53
|
||
| const auto& tmp_segments = segment_cache_handle.get_segments(); | ||
| segment = tmp_segments[0]; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -91,8 +91,14 @@ Status SegmentLoader::load_segments(const BetaRowsetSharedPtr& rowset, | |||||||||||
| return Status::OK(); | ||||||||||||
| } | ||||||||||||
| for (int64_t i = 0; i < rowset->num_segments(); i++) { | ||||||||||||
| RETURN_IF_ERROR(load_segment(rowset, i, cache_handle, use_cache, need_load_pk_index_and_bf, | ||||||||||||
| index_load_stats)); | ||||||||||||
| auto st = load_segment(rowset, i, cache_handle, use_cache, need_load_pk_index_and_bf, | ||||||||||||
| index_load_stats); | ||||||||||||
| if (st.is<ErrorCode::NOT_FOUND>() && config::ignore_not_found_segment) { | ||||||||||||
| LOG(WARNING) << "segment not found, skip it. rowset_id=" << rowset->rowset_id() | ||||||||||||
| << ", seg_id=" << i; | ||||||||||||
| continue; | ||||||||||||
|
||||||||||||
| } | ||||||||||||
|
||||||||||||
| if (st.is<ErrorCode::NOT_FOUND>() && config::ignore_not_found_segment) { | |
| LOG(WARNING) << "segment not found, skip it. rowset_id=" << rowset->rowset_id() | |
| << ", seg_id=" << i; | |
| continue; | |
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,244 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // 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 <gtest/gtest.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <memory> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "common/config.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "common/status.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "json2pb/json_to_pb.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "runtime/exec_env.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "storage/rowset/beta_rowset.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "storage/segment/lazy_init_segment_iterator.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "storage/segment/segment_loader.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "util/debug_points.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace doris { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| class IgnoreNotFoundSegmentTest : public testing::Test { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| protected: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| void SetUp() override { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| _saved_ignore = config::ignore_not_found_segment; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| _saved_debug_points = config::enable_debug_points; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| config::enable_debug_points = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Set up a SegmentLoader for LazyInitSegmentIterator tests | ||||||||||||||||||||||||||||||||||||||||||||||||||
| _saved_segment_loader = ExecEnv::GetInstance()->segment_loader(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| _segment_loader = new SegmentLoader(1024 * 1024, 100); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ExecEnv::GetInstance()->set_segment_loader(_segment_loader); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| void TearDown() override { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| DebugPoints::instance()->remove("BetaRowset::load_segment.return_not_found"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| config::ignore_not_found_segment = _saved_ignore; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| config::enable_debug_points = _saved_debug_points; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| ExecEnv::GetInstance()->set_segment_loader(_saved_segment_loader); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| delete _segment_loader; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| _segment_loader = nullptr; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+46
to
+54
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| BetaRowsetSharedPtr create_rowset(int num_segments) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto schema = std::make_shared<TabletSchema>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| TabletColumn col; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| col.set_name("c1"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| col.set_unique_id(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| col.set_type(FieldType::OLAP_FIELD_TYPE_INT); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| col.set_length(4); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| col.set_is_key(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| col.set_is_nullable(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| schema->append_column(col); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| schema->_keys_type = DUP_KEYS; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| auto rsm = std::make_shared<RowsetMeta>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| std::string json = R"({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "rowset_id": 540081, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "tablet_id": 10001, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "partition_id": 10000, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "tablet_schema_hash": 567997577, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "rowset_type": "BETA_ROWSET", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "rowset_state": "VISIBLE", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "empty": false | ||||||||||||||||||||||||||||||||||||||||||||||||||
| })"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| RowsetMetaPB pb; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| EXPECT_TRUE(json2pb::JsonToProtoMessage(json, &pb)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| pb.set_start_version(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| pb.set_end_version(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| pb.set_num_segments(num_segments); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| rsm->init_from_pb(pb); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+79
to
+84
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| rsm->set_tablet_schema(schema); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return std::make_shared<BetaRowset>(schema, rsm, ""); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| bool _saved_ignore = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| bool _saved_debug_points = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| SegmentLoader* _saved_segment_loader = nullptr; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| SegmentLoader* _segment_loader = nullptr; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Test: BetaRowset::load_segments skips NOT_FOUND segments when config enabled | ||||||||||||||||||||||||||||||||||||||||||||||||||
| TEST_F(IgnoreNotFoundSegmentTest, BetaRowsetLoadSegmentsSkipsNotFound) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| config::ignore_not_found_segment = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto rowset = create_rowset(3); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| DebugPoints::instance()->add("BetaRowset::load_segment.return_not_found"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| std::vector<segment_v2::SegmentSharedPtr> segments; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto st = rowset->load_segments(&segments); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // All segments are "not found" but should be skipped, resulting in OK with empty segments | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(st.ok()) << st; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_EQ(0, segments.size()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Test: BetaRowset::load_segments fails on NOT_FOUND when config disabled | ||||||||||||||||||||||||||||||||||||||||||||||||||
| TEST_F(IgnoreNotFoundSegmentTest, BetaRowsetLoadSegmentsFailsWhenConfigDisabled) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| config::ignore_not_found_segment = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto rowset = create_rowset(3); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| DebugPoints::instance()->add("BetaRowset::load_segment.return_not_found"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| std::vector<segment_v2::SegmentSharedPtr> segments; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto st = rowset->load_segments(&segments); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(st.is<ErrorCode::NOT_FOUND>()) << st; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_EQ(0, segments.size()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Test: BetaRowset::load_segments with range skips NOT_FOUND | ||||||||||||||||||||||||||||||||||||||||||||||||||
| TEST_F(IgnoreNotFoundSegmentTest, BetaRowsetLoadSegmentsRangeSkipsNotFound) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| config::ignore_not_found_segment = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto rowset = create_rowset(5); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| DebugPoints::instance()->add("BetaRowset::load_segment.return_not_found"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| std::vector<segment_v2::SegmentSharedPtr> segments; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto st = rowset->load_segments(1, 4, &segments); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(st.ok()) << st; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_EQ(0, segments.size()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Test: SegmentLoader::load_segments skips NOT_FOUND segments when config enabled | ||||||||||||||||||||||||||||||||||||||||||||||||||
| TEST_F(IgnoreNotFoundSegmentTest, SegmentLoaderLoadSegmentsSkipsNotFound) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| config::ignore_not_found_segment = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto rowset = create_rowset(3); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| DebugPoints::instance()->add("BetaRowset::load_segment.return_not_found"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Create a SegmentLoader with a small cache | ||||||||||||||||||||||||||||||||||||||||||||||||||
| SegmentLoader loader(1024 * 1024, 100); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| SegmentCacheHandle handle; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto st = loader.load_segments(rowset, &handle, false); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(st.ok()) << st; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_EQ(0, handle.get_segments().size()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(handle.is_inited()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Regression test: validate that SegmentCacheHandle::get_segments() can be indexed by seg_id | |
| // after a successful SegmentLoader::load_segments() call. This mimics real callers that do | |
| // `segments[seg_id]` and relies on the seg_id -> vector-index contract. | |
| TEST_F(IgnoreNotFoundSegmentTest, SegmentLoaderSegmentsIndexableBySegId) { | |
| config::ignore_not_found_segment = true; | |
| auto rowset = create_rowset(3); | |
| // Do not inject NOT_FOUND for this test; we want all segments to load successfully | |
| SegmentLoader loader(1024 * 1024, 100); | |
| SegmentCacheHandle handle; | |
| auto st = loader.load_segments(rowset, &handle, false); | |
| ASSERT_TRUE(st.ok()) << st; | |
| ASSERT_TRUE(handle.is_inited()); | |
| const auto& segments = handle.get_segments(); | |
| // Expect that we can index by seg_id in [0, 3) | |
| ASSERT_GE(segments.size(), 3); | |
| for (int seg_id = 0; seg_id < 3; ++seg_id) { | |
| // Real callers rely on segments[seg_id] being valid for each seg_id | |
| ASSERT_NE(nullptr, segments[seg_id]); | |
| } | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| -- This file is automatically generated. You should know what you did if you want to edit this | ||
| -- !baseline -- | ||
| 6 | ||
|
|
||
| -- !ignore_enabled -- | ||
| 0 | ||
|
|
||
| -- !recovery -- | ||
| 6 | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new config name
ignore_not_found_segmentis misleading because the behavior (and comment) also includesIO_ERROR, not just missing segments. Since this is a newly introduced config, consider renaming it to something likeignore_segment_io_errors(or otherwise aligning the name strictly to NOT_FOUND-only behavior) to avoid operator confusion when toggling at runtime.