Skip to content

Commit 2b7475f

Browse files
authored
[fix](orc) handle cancellation during condition cache seek (#67141)
### What problem does this PR solve? Issue Number: DORIS-28199 Problem Summary: Condition-cache granule skipping can call ORC seekToRow before the existing nextBatch exception boundary. When a query is cancelled during that I/O, the ORC input stream throws a stop exception that escapes get_block and may terminate the BE process. ### Release note Fix BE process termination when an ORC scan is cancelled during condition-cache seeking. ### Check List (For Author) - Test - [x] Regression test - [x] Unit Test - [ ] Manual test - [ ] No need to test or manual test. Verification: NewOrcReaderTest.* passed 163/163 under ASAN_UT. Clang-format 16 passed for both affected C++ files. - Behavior changed: - [ ] No. - [x] Yes. Cancellation during a condition-cache seek now returns clean EOF instead of allowing the ORC stop exception to escape. - Does this need documentation? - [x] No. - [ ] Yes. ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label
1 parent 6b5c53f commit 2b7475f

2 files changed

Lines changed: 56 additions & 4 deletions

File tree

be/src/format_v2/orc/orc_reader.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,8 @@ void OrcReader::_skip_condition_cache_false_granules(size_t* rows, bool* eof) {
17511751
}
17521752
if (target_row > _state->condition_cache_next_row) {
17531753
DORIS_CHECK(target_row <= file_total_rows);
1754+
DBUG_EXECUTE_IF("OrcReader._skip_condition_cache_false_granules.before_seek_to_row",
1755+
DBUG_RUN_CALLBACK());
17541756
_state->row_reader->seekToRow(target_row);
17551757
if (_io_ctx != nullptr) {
17561758
_io_ctx->condition_cache_filtered_rows += target_row - _state->condition_cache_next_row;
@@ -1939,11 +1941,13 @@ Status OrcReader::get_block(Block* file_block, size_t* rows, bool* eof) {
19391941

19401942
bool has_next = false;
19411943
while (true) {
1942-
_skip_condition_cache_false_granules(rows, eof);
1943-
if (*eof) {
1944-
return Status::OK();
1945-
}
19461944
try {
1945+
// Condition-cache seeks can perform I/O, so keep them in the same cancellation
1946+
// boundary as next().
1947+
_skip_condition_cache_false_granules(rows, eof);
1948+
if (*eof) {
1949+
return Status::OK();
1950+
}
19471951
_state->orc_lazy_selection_valid = false;
19481952
_state->orc_lazy_selected_rows.clear();
19491953
_state->orc_lazy_input_rows = 0;

be/test/format_v2/orc/orc_reader_test.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6133,6 +6133,54 @@ TEST_F(NewOrcReaderTest, ConditionCacheHitSkipsFalseGranulesBeforeColumnRead) {
61336133
EXPECT_EQ(rows, 0);
61346134
}
61356135

6136+
TEST_F(NewOrcReaderTest, ConditionCacheSeekReturnsCleanEofWhenCancelled) {
6137+
constexpr int64_t row_count = ConditionCacheContext::GRANULE_SIZE * 2;
6138+
const auto file_path = (_test_dir / "condition_cache_cancelled_seek.orc").string();
6139+
write_large_orc_int_file(file_path, row_count);
6140+
6141+
auto io_ctx = std::make_shared<io::IOContext>();
6142+
auto reader = create_reader_for_path(file_path, nullptr, io_ctx);
6143+
RuntimeState state {TQueryOptions(), TQueryGlobals()};
6144+
ASSERT_TRUE(reader->init(&state).ok());
6145+
6146+
std::vector<format::ColumnDefinition> schema;
6147+
ASSERT_TRUE(reader->get_schema(&schema).ok());
6148+
ASSERT_EQ(schema.size(), 1);
6149+
6150+
auto request = std::make_shared<format::FileScanRequest>();
6151+
request->predicate_columns = {field_projection(0)};
6152+
request->non_predicate_columns = {field_projection(0)};
6153+
request->local_positions.emplace(format::LocalColumnId(0), format::LocalIndex(0));
6154+
request->conjuncts.push_back(
6155+
VExprContext::create_shared(std::make_shared<NullableInt32GreaterThanExpr>(
6156+
0, ConditionCacheContext::GRANULE_SIZE)));
6157+
ASSERT_TRUE(reader->open(request).ok());
6158+
6159+
auto ctx = std::make_shared<ConditionCacheContext>();
6160+
ctx->is_hit = true;
6161+
ctx->filter_result =
6162+
std::make_shared<std::vector<bool>>(std::vector<bool> {false, true, false});
6163+
reader->set_condition_cache_context(ctx);
6164+
6165+
int injection_count = 0;
6166+
ScopedDebugPoint debug_point(
6167+
"OrcReader._skip_condition_cache_false_granules.before_seek_to_row", [&]() {
6168+
++injection_count;
6169+
io_ctx->should_stop = true;
6170+
throw ::orc::ParseError("stop");
6171+
});
6172+
6173+
Block block = build_file_block(schema);
6174+
size_t rows = 123;
6175+
bool eof = false;
6176+
auto status = reader->get_block(&block, &rows, &eof);
6177+
EXPECT_EQ(injection_count, 1);
6178+
ASSERT_TRUE(status.ok()) << status;
6179+
EXPECT_TRUE(eof);
6180+
EXPECT_EQ(rows, 0);
6181+
EXPECT_EQ(block.rows(), 0);
6182+
}
6183+
61366184
TEST_F(NewOrcReaderTest, ConditionCacheHitHandlesSplitWithoutSelectedStripe) {
61376185
const auto multi_stripe_file_path = (_test_dir / "condition_cache_empty_split.orc").string();
61386186
write_multi_stripe_orc_int_file(multi_stripe_file_path);

0 commit comments

Comments
 (0)