Coverage Report

Created: 2026-08-07 21:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/sink/writer/async_result_writer.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
#include <concurrentqueue.h>
20
21
#include <condition_variable>
22
#include <queue> // IWYU pragma: keep
23
24
#include "exec/sink/writer/async_writer_queue_admission.h"
25
#include "exec/sink/writer/result_writer.h"
26
#include "exprs/vexpr_fwd.h"
27
#include "runtime/memory/thread_mem_tracker_mgr.h"
28
#include "runtime/runtime_profile.h"
29
30
namespace doris {
31
class ObjectPool;
32
class RowDescriptor;
33
class RuntimeState;
34
class TDataSink;
35
class TExpr;
36
37
class Dependency;
38
class PipelineTask;
39
40
class Block;
41
42
/*
43
 *  In the pipeline execution engine, there are usually a large number of io operations on the sink side that
44
 *  will block the limited execution threads of the pipeline execution engine, resulting in a sharp performance
45
 *  degradation of the pipeline execution engine when there are import tasks.
46
 *
47
 *  So all ResultWriter in Sink should use AsyncResultWriter to do the real IO task in thread pool to keep the
48
 *  pipeline execution engine performance.
49
 *
50
 *  The Sub class of AsyncResultWriter need to impl two virtual function
51
 *     * Status open() the first time IO work like: create file/ connect network
52
 *     * Status write() do the real IO work for block 
53
 */
54
class AsyncResultWriter : public ResultWriter {
55
public:
56
    AsyncResultWriter(const VExprContextSPtrs& output_expr_ctxs, std::shared_ptr<Dependency> dep,
57
                      std::shared_ptr<Dependency> fin_dep);
58
59
    void force_close(Status s);
60
61
0
    Status init(RuntimeState* state) override { return Status::OK(); }
62
63
    virtual Status open(RuntimeState* state, RuntimeProfile* operator_profile) = 0;
64
65
    // sink the block data to data queue, it is async
66
    Status sink(Block* block, bool eos);
67
68
    // Add the IO thread task process block() to thread pool to dispose the IO
69
    Status start_writer(RuntimeState* state, RuntimeProfile* operator_profile);
70
71
1
    Status get_writer_status() { return _writer_status.status(); }
72
73
    void set_low_memory_mode();
74
75
0
    void wait_for_processing_before_next_sink() {
76
0
        _queue_admission.wait_for_processing_before_next_sink();
77
0
    }
78
79
protected:
80
    Status _projection_block(Block& input_block, Block* output_block);
81
    const VExprContextSPtrs& _vec_output_expr_ctxs;
82
    RuntimeProfile* _operator_profile = nullptr; // not owned, set when open
83
84
    std::unique_ptr<Block> _get_free_block(Block*, size_t rows);
85
86
private:
87
    struct QueuedBlock {
88
        std::unique_ptr<Block> block;
89
        ReservedMemoryToken reservation;
90
        bool eos = false;
91
    };
92
93
    void process_block(RuntimeState* state, RuntimeProfile* operator_profile);
94
5
    [[nodiscard]] bool _data_queue_is_available() const {
95
5
        return _queue_admission.is_available(_data_queue.size());
96
5
    }
97
4
    [[nodiscard]] bool _is_finished() const { return !_writer_status.ok() || _eos; }
98
    void _set_ready_to_finish();
99
100
    void _return_free_block(std::unique_ptr<Block>);
101
    QueuedBlock _get_block_from_queue();
102
    void _notify_block_processed();
103
104
    std::mutex _m;
105
    std::condition_variable _cv;
106
    std::deque<QueuedBlock> _data_queue;
107
    // Default value is ok
108
    AtomicStatus _writer_status;
109
    bool _eos = false;
110
    AsyncWriterQueueAdmission _queue_admission;
111
    std::atomic_bool _low_memory_mode = false;
112
113
    std::shared_ptr<Dependency> _dependency;
114
    std::shared_ptr<Dependency> _finish_dependency;
115
116
    moodycamel::ConcurrentQueue<std::unique_ptr<Block>> _free_blocks;
117
    RuntimeProfile::Counter* _memory_used_counter = nullptr;
118
};
119
120
} // namespace doris