Coverage Report

Created: 2026-03-17 11:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/operator/data_queue.cpp
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
#include "exec/operator/data_queue.h"
19
20
#include <glog/logging.h>
21
22
#include <algorithm>
23
#include <mutex>
24
#include <utility>
25
26
#include "core/block/block.h"
27
#include "exec/pipeline/dependency.h"
28
29
namespace doris {
30
#include "common/compile_check_begin.h"
31
DataQueue::DataQueue(int child_count)
32
3.35k
        : _queue_blocks_lock(child_count),
33
3.35k
          _queue_blocks(child_count),
34
3.35k
          _free_blocks_lock(child_count),
35
3.35k
          _free_blocks(child_count),
36
3.35k
          _child_count(child_count),
37
3.35k
          _is_finished(child_count),
38
3.35k
          _is_canceled(child_count),
39
3.35k
          _cur_bytes_in_queue(child_count),
40
3.35k
          _cur_blocks_nums_in_queue(child_count),
41
3.35k
          _flag_queue_idx(0) {
42
10.0k
    for (int i = 0; i < child_count; ++i) {
43
6.69k
        _queue_blocks_lock[i].reset(new std::mutex());
44
6.69k
        _free_blocks_lock[i].reset(new std::mutex());
45
6.69k
        _is_finished[i] = false;
46
6.69k
        _is_canceled[i] = false;
47
6.69k
        _cur_bytes_in_queue[i] = 0;
48
6.69k
        _cur_blocks_nums_in_queue[i] = 0;
49
6.69k
    }
50
3.35k
    _un_finished_counter = child_count;
51
3.35k
    _sink_dependencies.resize(child_count, nullptr);
52
3.35k
}
53
54
6.34k
std::unique_ptr<Block> DataQueue::get_free_block(int child_idx) {
55
6.34k
    {
56
6.34k
        INJECT_MOCK_SLEEP(std::lock_guard<std::mutex> l(*_free_blocks_lock[child_idx]));
57
6.34k
        if (!_free_blocks[child_idx].empty()) {
58
4
            auto block = std::move(_free_blocks[child_idx].front());
59
4
            _free_blocks[child_idx].pop_front();
60
4
            return block;
61
4
        }
62
6.34k
    }
63
64
6.34k
    return Block::create_unique();
65
6.34k
}
66
67
6.34k
void DataQueue::push_free_block(std::unique_ptr<Block> block, int child_idx) {
68
6.34k
    DCHECK(block->rows() == 0);
69
70
6.34k
    if (!_is_low_memory_mode) {
71
6.34k
        INJECT_MOCK_SLEEP(std::lock_guard<std::mutex> l(*_free_blocks_lock[child_idx]));
72
6.34k
        _free_blocks[child_idx].emplace_back(std::move(block));
73
6.34k
    }
74
6.34k
}
75
76
2.98k
void DataQueue::clear_free_blocks() {
77
9.33k
    for (size_t child_idx = 0; child_idx < _free_blocks.size(); ++child_idx) {
78
6.35k
        std::lock_guard<std::mutex> l(*_free_blocks_lock[child_idx]);
79
6.35k
        std::deque<std::unique_ptr<Block>> tmp_queue;
80
6.35k
        _free_blocks[child_idx].swap(tmp_queue);
81
6.35k
    }
82
2.98k
}
83
84
2.98k
void DataQueue::terminate() {
85
9.33k
    for (int i = 0; i < _queue_blocks.size(); i++) {
86
6.34k
        set_finish(i);
87
6.34k
        INJECT_MOCK_SLEEP(std::lock_guard<std::mutex> l(*_queue_blocks_lock[i]));
88
6.34k
        if (_cur_blocks_nums_in_queue[i] > 0) {
89
3
            _queue_blocks[i].clear();
90
3
            _cur_bytes_in_queue[i] = 0;
91
3
            _cur_blocks_nums_in_queue[i] = 0;
92
3
            _sink_dependencies[i]->set_always_ready();
93
3
        }
94
6.34k
    }
95
2.98k
    clear_free_blocks();
96
2.98k
}
97
98
//check which queue have data, and save the idx in _flag_queue_idx,
99
//so next loop, will check the record idx + 1 first
100
//maybe it's useful with many queue, others maybe always 0
101
29.5k
bool DataQueue::remaining_has_data() {
102
29.5k
    int count = _child_count;
103
80.7k
    while (--count >= 0) {
104
57.6k
        _flag_queue_idx++;
105
57.6k
        if (_flag_queue_idx == _child_count) {
106
26.3k
            _flag_queue_idx = 0;
107
26.3k
        }
108
57.6k
        if (_cur_blocks_nums_in_queue[_flag_queue_idx] > 0) {
109
6.50k
            return true;
110
6.50k
        }
111
57.6k
    }
112
23.0k
    return false;
113
29.5k
}
114
115
//the _flag_queue_idx indicate which queue has data, and in check can_read
116
//will be set idx in remaining_has_data function
117
23.5k
Status DataQueue::get_block_from_queue(std::unique_ptr<Block>* output_block, int* child_idx) {
118
23.5k
    if (_is_canceled[_flag_queue_idx]) {
119
0
        return Status::InternalError("Current queue of idx {} have beed canceled: ",
120
0
                                     _flag_queue_idx);
121
0
    }
122
123
23.5k
    {
124
23.5k
        INJECT_MOCK_SLEEP(std::lock_guard<std::mutex> l(*_queue_blocks_lock[_flag_queue_idx]));
125
23.5k
        if (_cur_blocks_nums_in_queue[_flag_queue_idx] > 0) {
126
6.52k
            *output_block = std::move(_queue_blocks[_flag_queue_idx].front());
127
6.52k
            _queue_blocks[_flag_queue_idx].pop_front();
128
6.52k
            if (child_idx) {
129
6.51k
                *child_idx = _flag_queue_idx;
130
6.51k
            }
131
6.52k
            _cur_bytes_in_queue[_flag_queue_idx] -= (*output_block)->allocated_bytes();
132
6.52k
            _cur_blocks_nums_in_queue[_flag_queue_idx] -= 1;
133
6.52k
            if (_cur_blocks_nums_in_queue[_flag_queue_idx] == 0) {
134
6.44k
                _sink_dependencies[_flag_queue_idx]->set_ready();
135
6.44k
            }
136
6.52k
            auto old_value = _cur_blocks_total_nums.fetch_sub(1);
137
6.52k
            if (old_value == 1 && _source_dependency) {
138
6.04k
                set_source_block();
139
6.04k
            }
140
6.52k
        }
141
23.5k
    }
142
23.5k
    return Status::OK();
143
23.5k
}
144
145
6.49k
Status DataQueue::push_block(std::unique_ptr<Block> block, int child_idx) {
146
6.49k
    if (!block) {
147
0
        return Status::OK();
148
0
    }
149
6.49k
    {
150
6.49k
        INJECT_MOCK_SLEEP(std::lock_guard<std::mutex> l(*_queue_blocks_lock[child_idx]));
151
6.49k
        if (_is_finished[child_idx]) {
152
0
            return Status::EndOfFile("Already finish");
153
0
        }
154
6.49k
        _cur_bytes_in_queue[child_idx] += block->allocated_bytes();
155
6.49k
        _queue_blocks[child_idx].emplace_back(std::move(block));
156
6.49k
        _cur_blocks_nums_in_queue[child_idx] += 1;
157
158
6.49k
        if (_cur_blocks_nums_in_queue[child_idx] > _max_blocks_in_sub_queue) {
159
80
            _sink_dependencies[child_idx]->block();
160
80
        }
161
6.49k
        _cur_blocks_total_nums++;
162
163
6.49k
        set_source_ready();
164
6.49k
    }
165
0
    return Status::OK();
166
6.49k
}
167
168
13.0k
void DataQueue::set_finish(int child_idx) {
169
13.0k
    INJECT_MOCK_SLEEP(std::lock_guard<std::mutex> l(*_queue_blocks_lock[child_idx]));
170
13.0k
    if (_is_finished[child_idx]) {
171
6.34k
        return;
172
6.34k
    }
173
6.70k
    _is_finished[child_idx] = true;
174
6.70k
    if (_un_finished_counter.fetch_sub(1) == 1) {
175
3.36k
        _is_all_finished = true;
176
3.36k
    }
177
6.70k
    set_source_ready();
178
6.70k
}
179
180
0
void DataQueue::set_canceled(int child_idx) {
181
0
    INJECT_MOCK_SLEEP(std::lock_guard<std::mutex> l(*_queue_blocks_lock[child_idx]));
182
0
    DCHECK(!_is_finished[child_idx]);
183
0
    _is_canceled[child_idx] = true;
184
0
    _is_finished[child_idx] = true;
185
0
    if (_un_finished_counter.fetch_sub(1) == 1) {
186
0
        _is_all_finished = true;
187
0
    }
188
0
    set_source_ready();
189
0
}
190
191
3
bool DataQueue::is_finish(int child_idx) {
192
3
    return _is_finished[child_idx];
193
3
}
194
195
29.2k
bool DataQueue::is_all_finish() {
196
29.2k
    return _is_all_finished;
197
29.2k
}
198
199
13.2k
void DataQueue::set_source_ready() {
200
13.2k
    if (_source_dependency) {
201
13.2k
        std::unique_lock lc(_source_lock);
202
13.2k
        _source_dependency->set_ready();
203
13.2k
    }
204
13.2k
}
205
206
6.04k
void DataQueue::set_source_block() {
207
6.04k
    if (_cur_blocks_total_nums == 0 && !is_all_finish()) {
208
3.04k
        std::unique_lock lc(_source_lock);
209
        // Performing the judgment twice, attempting to avoid blocking the source as much as possible.
210
3.04k
        if (_cur_blocks_total_nums == 0 && !is_all_finish()) {
211
3.04k
            _source_dependency->block();
212
3.04k
        }
213
3.04k
    }
214
6.04k
}
215
216
} // namespace doris