Coverage Report

Created: 2026-08-06 14:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/load/group_commit/group_commit_mgr.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 "load/group_commit/group_commit_mgr.h"
19
20
#include <gen_cpp/Types_types.h>
21
#include <glog/logging.h>
22
23
#include <chrono>
24
25
#include "cloud/config.h"
26
#include "common/compiler_util.h"
27
#include "common/config.h"
28
#include "common/status.h"
29
#include "exec/pipeline/dependency.h"
30
#include "runtime/cluster_info.h"
31
#include "runtime/exec_env.h"
32
#include "runtime/fragment_mgr.h"
33
#include "runtime/memory/mem_tracker_limiter.h"
34
#include "runtime/thread_context.h"
35
#include "service/backend_options.h"
36
#include "util/client_cache.h"
37
#include "util/debug_points.h"
38
#include "util/thrift_rpc_helper.h"
39
#include "util/time.h"
40
41
namespace doris {
42
43
bvar::Adder<uint64_t> group_commit_block_by_memory_counter("group_commit_block_by_memory_counter");
44
45
0
std::string LoadBlockQueue::_get_load_ids() {
46
0
    std::stringstream ss;
47
0
    ss << "[";
48
0
    for (auto& id : _load_ids_to_write_dep) {
49
0
        ss << id.first.to_string() << ", ";
50
0
    }
51
0
    ss << "]";
52
0
    return ss.str();
53
0
}
54
55
Status LoadBlockQueue::add_block(RuntimeState* runtime_state, std::shared_ptr<Block> block,
56
0
                                 bool write_wal, UniqueId& load_id) {
57
0
    DBUG_EXECUTE_IF("LoadBlockQueue.add_block.failed",
58
0
                    { return Status::InternalError("LoadBlockQueue.add_block.failed"); });
59
0
    DBUG_EXECUTE_IF("LoadBlockQueue.add_block.block_reuse_second", {
60
0
        int seq = _debug_add_block_seq.fetch_add(1);
61
0
        if (seq >= 1) {
62
0
            LOG(INFO) << "debug hold reuse 2nd+ add_block, label=" << label
63
0
                      << ", load_id=" << load_id.to_string();
64
0
            int64_t waited_ms = 0;
65
0
            while (waited_ms < 10000 && DebugPoints::instance()->is_enable(
66
0
                                                "LoadBlockQueue.add_block.block_reuse_second")) {
67
0
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
68
0
                waited_ms += 10;
69
0
            }
70
0
            LOG(INFO) << "debug release reuse 2nd+ add_block, label=" << label
71
0
                      << ", load_id=" << load_id.to_string() << ", waited_ms=" << waited_ms;
72
0
        }
73
0
    });
74
0
    std::unique_lock l(mutex);
75
0
    RETURN_IF_ERROR(status);
76
0
    if (UNLIKELY(runtime_state->is_cancelled())) {
77
0
        return runtime_state->cancel_reason();
78
0
    }
79
0
    RETURN_IF_ERROR(status);
80
0
    LOG(INFO) << "query_id: " << print_id(runtime_state->query_id())
81
0
              << ", add block rows=" << block->rows() << ", use group_commit label=" << label;
82
0
    DBUG_EXECUTE_IF("LoadBlockQueue.add_block.block", DBUG_BLOCK);
83
0
    if (block->rows() > 0) {
84
0
        if (!config::group_commit_wait_replay_wal_finish) {
85
0
            _block_queue.emplace_back(block);
86
0
            _data_bytes += block->bytes();
87
0
            size_t before_block_queues_bytes = _all_block_queues_bytes->load();
88
0
            _all_block_queues_bytes->fetch_add(block->bytes(), std::memory_order_relaxed);
89
0
            VLOG_DEBUG << "[Group Commit Debug] (LoadBlockQueue::add_block). "
90
0
                       << "Cur block rows=" << block->rows() << ", bytes=" << block->bytes()
91
0
                       << ". all block queues bytes from " << before_block_queues_bytes << " to  "
92
0
                       << _all_block_queues_bytes->load() << ", queue size=" << _block_queue.size()
93
0
                       << ". txn_id=" << txn_id << ", label=" << label
94
0
                       << ", instance_id=" << load_instance_id << ", load_ids=" << _get_load_ids();
95
0
        }
96
0
        if (write_wal || config::group_commit_wait_replay_wal_finish) {
97
0
            auto st = _v_wal_writer->write_wal(block.get());
98
0
            if (!st.ok()) {
99
0
                _cancel_without_lock(st);
100
0
                return st;
101
0
            }
102
0
        }
103
0
        if (!runtime_state->is_cancelled() && status.ok() &&
104
0
            _all_block_queues_bytes->load(std::memory_order_relaxed) >=
105
0
                    config::group_commit_queue_mem_limit) {
106
0
            group_commit_block_by_memory_counter << 1;
107
0
            auto dep_it = _load_ids_to_write_dep.find(load_id);
108
0
            DCHECK(dep_it != _load_ids_to_write_dep.end());
109
0
            if (dep_it != _load_ids_to_write_dep.end() && dep_it->second) {
110
0
                dep_it->second->block();
111
0
                VLOG_DEBUG << "block add_block for load_id=" << load_id << ", memory="
112
0
                           << _all_block_queues_bytes->load(std::memory_order_relaxed)
113
0
                           << ". inner load_id=" << load_instance_id << ", label=" << label;
114
0
            }
115
0
        }
116
0
    }
117
0
    if (!_need_commit.load()) {
118
0
        if (_data_bytes >= _group_commit_data_bytes) {
119
0
            VLOG_DEBUG << "group commit meets commit condition for data size, label=" << label
120
0
                       << ", instance_id=" << load_instance_id << ", data_bytes=" << _data_bytes;
121
0
            _need_commit.store(true);
122
0
            data_size_condition = true;
123
0
        }
124
0
        if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() -
125
0
                                                                  _start_time)
126
0
                    .count() >= _group_commit_interval_ms) {
127
0
            VLOG_DEBUG << "group commit meets commit condition for time interval, label=" << label
128
0
                       << ", instance_id=" << load_instance_id << ", data_bytes=" << _data_bytes;
129
0
            _need_commit.store(true);
130
0
        }
131
0
    }
132
0
    for (auto read_dep : _read_deps) {
133
0
        read_dep->set_ready();
134
0
        VLOG_DEBUG << "set ready for inner load_id=" << load_instance_id;
135
0
    }
136
0
    return Status::OK();
137
0
}
138
139
Status LoadBlockQueue::get_block(RuntimeState* runtime_state, Block* block, bool* find_block,
140
0
                                 bool* eos, std::shared_ptr<Dependency> get_block_dep) {
141
0
    *find_block = false;
142
0
    *eos = false;
143
0
    std::unique_lock l(mutex);
144
0
    if (runtime_state->is_cancelled() || !status.ok()) {
145
0
        auto st = runtime_state->cancel_reason();
146
0
        _cancel_without_lock(st);
147
0
        return status;
148
0
    }
149
0
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
150
0
                            std::chrono::steady_clock::now() - _start_time)
151
0
                            .count();
152
0
    if (!_need_commit.load() && duration >= _group_commit_interval_ms) {
153
0
        _need_commit.store(true);
154
0
    }
155
0
    if (_block_queue.empty()) {
156
0
        if (_need_commit.load() && duration >= 10 * _group_commit_interval_ms) {
157
0
            auto last_print_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
158
0
                                               std::chrono::steady_clock::now() - _last_print_time)
159
0
                                               .count();
160
0
            if (last_print_duration >= 10000) {
161
0
                _last_print_time = std::chrono::steady_clock::now();
162
0
                LOG(INFO) << "find one group_commit need to commit, txn_id=" << txn_id
163
0
                          << ", label=" << label << ", instance_id=" << load_instance_id
164
0
                          << ", duration=" << duration << ", load_ids=" << _get_load_ids();
165
0
            }
166
0
        }
167
0
        VLOG_DEBUG << "get_block for inner load_id=" << load_instance_id << ", but queue is empty";
168
0
        if (!_need_commit.load()) {
169
0
            get_block_dep->block();
170
0
            VLOG_DEBUG << "block get_block for inner load_id=" << load_instance_id;
171
0
        }
172
0
    } else {
173
0
        const BlockData block_data = _block_queue.front();
174
0
        block->swap(*block_data.block);
175
0
        *find_block = true;
176
0
        _block_queue.pop_front();
177
0
        size_t before_block_queues_bytes = _all_block_queues_bytes->load();
178
0
        _all_block_queues_bytes->fetch_sub(block_data.block_bytes, std::memory_order_relaxed);
179
0
        VLOG_DEBUG << "[Group Commit Debug] (LoadBlockQueue::get_block). "
180
0
                   << "Cur block rows=" << block->rows() << ", bytes=" << block->bytes()
181
0
                   << ". all block queues bytes from " << before_block_queues_bytes << " to  "
182
0
                   << _all_block_queues_bytes->load() << ", queue size=" << _block_queue.size()
183
0
                   << ". txn_id=" << txn_id << ", label=" << label
184
0
                   << ", instance_id=" << load_instance_id << ", load_ids=" << _get_load_ids();
185
0
    }
186
0
    if (_block_queue.empty() && _need_commit.load() && _load_ids_to_write_dep.empty()) {
187
0
        *eos = true;
188
0
    } else {
189
0
        *eos = false;
190
0
    }
191
0
    if (_all_block_queues_bytes->load(std::memory_order_relaxed) <
192
0
        config::group_commit_queue_mem_limit) {
193
0
        for (auto& id : _load_ids_to_write_dep) {
194
0
            id.second->set_ready();
195
0
        }
196
0
        VLOG_DEBUG << "set ready for load_ids=" << _get_load_ids()
197
0
                   << ". inner load_id=" << load_instance_id << ", label=" << label;
198
0
    }
199
0
    return Status::OK();
200
0
}
201
202
0
Status LoadBlockQueue::remove_load_id(const UniqueId& load_id) {
203
0
    std::unique_lock l(mutex);
204
0
    if (_load_ids_to_write_dep.find(load_id) != _load_ids_to_write_dep.end()) {
205
0
        _load_ids_to_write_dep[load_id]->set_always_ready();
206
0
        _load_ids_to_write_dep.erase(load_id);
207
0
        for (auto read_dep : _read_deps) {
208
0
            read_dep->set_ready();
209
0
        }
210
0
        VLOG_DEBUG << "set ready for load_id=" << load_id << ", inner load_id=" << load_instance_id;
211
0
        return Status::OK();
212
0
    }
213
0
    return Status::NotFound<false>("load_id=" + load_id.to_string() +
214
0
                                   " not in block queue, label=" + label);
215
0
}
216
217
0
bool LoadBlockQueue::contain_load_id(const UniqueId& load_id) {
218
0
    std::unique_lock l(mutex);
219
0
    return _load_ids_to_write_dep.find(load_id) != _load_ids_to_write_dep.end();
220
0
}
221
222
Status LoadBlockQueue::add_load_id(const UniqueId& load_id,
223
0
                                   const std::shared_ptr<Dependency> put_block_dep) {
224
0
    std::unique_lock l(mutex);
225
0
    if (_need_commit.load() || !status.ok() || process_finish.load()) {
226
0
        return Status::InternalError<false>(
227
0
                "block queue cannot add load id, id=" + load_instance_id.to_string() +
228
0
                ", need_commit=" + (_need_commit.load() ? "true" : "false") +
229
0
                ", process_finish=" + (process_finish.load() ? "true" : "false") +
230
0
                ", queue_status=" + status.to_string());
231
0
    }
232
0
    _load_ids_to_write_dep[load_id] = put_block_dep;
233
0
    group_commit_load_count.fetch_add(1);
234
0
    return Status::OK();
235
0
}
236
237
0
void LoadBlockQueue::cancel(const Status& st) {
238
0
    DCHECK(!st.ok());
239
0
    std::unique_lock l(mutex);
240
0
    _cancel_without_lock(st);
241
0
}
242
243
0
void LoadBlockQueue::_cancel_without_lock(const Status& st) {
244
0
    LOG(INFO) << "cancel group_commit, instance_id=" << load_instance_id << ", label=" << label
245
0
              << ", status=" << st.to_string();
246
0
    status =
247
0
            Status::Cancelled("cancel group_commit, label=" + label + ", status=" + st.to_string());
248
0
    size_t before_block_queues_bytes = _all_block_queues_bytes->load();
249
0
    while (!_block_queue.empty()) {
250
0
        const BlockData& block_data = _block_queue.front();
251
0
        _all_block_queues_bytes->fetch_sub(block_data.block_bytes, std::memory_order_relaxed);
252
0
        _block_queue.pop_front();
253
0
    }
254
0
    VLOG_DEBUG << "[Group Commit Debug] (LoadBlockQueue::_cancel_without_block). "
255
0
               << "all block queues bytes from " << before_block_queues_bytes << " to "
256
0
               << _all_block_queues_bytes->load() << ", queue size=" << _block_queue.size()
257
0
               << ", txn_id=" << txn_id << ", label=" << label
258
0
               << ", instance_id=" << load_instance_id << ", load_ids=" << _get_load_ids();
259
0
    for (auto& id : _load_ids_to_write_dep) {
260
0
        id.second->set_always_ready();
261
0
    }
262
0
    for (auto read_dep : _read_deps) {
263
0
        read_dep->set_ready();
264
0
    }
265
0
    VLOG_DEBUG << "set ready for load_ids=" << _get_load_ids()
266
0
               << ", inner load_id=" << load_instance_id;
267
0
}
268
269
Status GroupCommitTable::get_first_block_load_queue(
270
        int64_t table_id, int64_t base_schema_version, int64_t index_size, const UniqueId& load_id,
271
        std::shared_ptr<LoadBlockQueue>& load_block_queue, int be_exe_version,
272
        TGroupCommitMode::type group_commit_mode, std::shared_ptr<Dependency> create_plan_dep,
273
0
        std::shared_ptr<Dependency> put_block_dep) {
274
0
    DCHECK(table_id == _table_id);
275
0
    std::unique_lock l(_lock);
276
0
    auto try_to_get_matched_queue = [&](bool& need_create_plan) -> Status {
277
0
        need_create_plan = false;
278
0
        for (const auto& [_, inner_block_queue] : _load_block_queues) {
279
0
            if (inner_block_queue->contain_load_id(load_id)) {
280
0
                load_block_queue = inner_block_queue;
281
0
                return Status::OK();
282
0
            }
283
0
        }
284
0
        RETURN_IF_ERROR(_check_wal_backlog(group_commit_mode));
285
0
        for (const auto& [_, inner_block_queue] : _load_block_queues) {
286
0
            if (!inner_block_queue->need_commit()) {
287
0
                if (base_schema_version == inner_block_queue->schema_version &&
288
0
                    index_size == inner_block_queue->index_size) {
289
0
                    if (inner_block_queue->add_load_id(load_id, put_block_dep).ok()) {
290
0
                        load_block_queue = inner_block_queue;
291
0
                        return Status::OK();
292
0
                    }
293
0
                } else {
294
0
                    return Status::DataQualityError<false>(
295
0
                            "schema version not match, maybe a schema change is in process. "
296
0
                            "Please retry this load manually.");
297
0
                }
298
0
            }
299
0
        }
300
0
        need_create_plan = true;
301
0
        return Status::OK();
302
0
    };
303
304
0
    bool need_create_plan = false;
305
0
    RETURN_IF_ERROR(try_to_get_matched_queue(need_create_plan));
306
0
    if (!need_create_plan) {
307
0
        return Status::OK();
308
0
    }
309
0
    create_plan_dep->block();
310
0
    _create_plan_be_exe_version = be_exe_version;
311
0
    if (_create_plan_deps.empty()) {
312
0
        _create_plan_start_time_ms = MonotonicMillis();
313
0
    }
314
0
    _create_plan_deps.emplace(load_id, std::make_tuple(create_plan_dep, put_block_dep,
315
0
                                                       base_schema_version, index_size));
316
0
    [[maybe_unused]] auto submit_st = _submit_create_group_commit_load();
317
0
    RETURN_IF_ERROR(try_to_get_matched_queue(need_create_plan));
318
0
    if (need_create_plan) {
319
0
        return Status::InternalError<false>("can not get a block queue for table_id: " +
320
0
                                            std::to_string(_table_id) + _create_plan_failed_reason);
321
0
    }
322
0
    return Status::OK();
323
0
}
324
325
0
Status GroupCommitTable::_check_wal_backlog(TGroupCommitMode::type group_commit_mode) {
326
0
    int32_t max_wal_num = config::group_commit_max_wal_num_per_table;
327
0
    if (group_commit_mode != TGroupCommitMode::ASYNC_MODE || max_wal_num <= 0) {
328
0
        return Status::OK();
329
0
    }
330
0
    size_t wal_num = _exec_env->wal_mgr()->get_wal_queue_size(_table_id);
331
0
    if (wal_num < static_cast<size_t>(max_wal_num)) {
332
0
        return Status::OK();
333
0
    }
334
0
    std::string failed_reason = _exec_env->wal_mgr()->get_last_replay_wal_failed_reason(_table_id);
335
0
    if (failed_reason.empty()) {
336
0
        return Status::OK();
337
0
    }
338
0
    return Status::Error<ErrorCode::EXCEEDED_LIMIT>(
339
0
            "Too many group commit async WALs for table {} on be host {}. wal num={}, limit={}, "
340
0
            "last replay wal failed reason: {}",
341
0
            _table_id, BackendOptions::get_localhost(), wal_num, max_wal_num, failed_reason);
342
0
}
343
344
0
Status GroupCommitTable::submit_create_group_commit_load() {
345
0
    std::unique_lock l(_lock);
346
0
    if (_create_plan_deps.empty()) {
347
0
        return Status::OK();
348
0
    }
349
0
    return _submit_create_group_commit_load();
350
0
}
351
352
0
Status GroupCommitTable::_submit_create_group_commit_load() {
353
0
    if (_is_creating_plan_fragment) {
354
0
        return Status::OK();
355
0
    }
356
357
0
    int64_t timeout_ms = config::group_commit_create_plan_timeout_ms;
358
0
    if (timeout_ms > 0 && !_create_plan_deps.empty()) {
359
0
        int64_t now_ms = MonotonicMillis();
360
0
        if (_create_plan_start_time_ms > 0 && now_ms - _create_plan_start_time_ms > timeout_ms) {
361
0
            std::string last_create_plan_failed_reason = _create_plan_failed_reason;
362
0
            _create_plan_failed_reason =
363
0
                    ". group commit create plan timeout after " + std::to_string(timeout_ms) + "ms";
364
0
            if (!last_create_plan_failed_reason.empty()) {
365
0
                _create_plan_failed_reason +=
366
0
                        ", last create plan error: " + last_create_plan_failed_reason;
367
0
            }
368
0
            for (const auto& [id, load_info] : _create_plan_deps) {
369
0
                std::get<0>(load_info)->set_ready();
370
0
            }
371
0
            _create_plan_deps.clear();
372
0
            _create_plan_start_time_ms = 0;
373
0
            return Status::OK();
374
0
        }
375
0
    }
376
377
0
    auto mem_tracker = _group_commit_mgr->group_commit_mem_tracker();
378
0
    int be_exe_version = _create_plan_be_exe_version;
379
0
    _is_creating_plan_fragment = true;
380
0
    auto submit_st = _thread_pool->submit_func([&, be_exe_version, mem_tracker] {
381
0
        std::shared_ptr<LoadBlockQueue> created_load_block_queue;
382
0
        Status create_group_commit_st = Status::OK();
383
0
        std::string create_plan_failed_reason;
384
0
        Defer defer {[&]() {
385
0
            bool need_resubmit = !create_group_commit_st.ok();
386
0
            std::unique_lock l(_lock);
387
0
            _is_creating_plan_fragment = false;
388
0
            _create_plan_failed_reason = create_plan_failed_reason;
389
0
            if (created_load_block_queue && create_group_commit_st.ok() &&
390
0
                !created_load_block_queue->need_commit()) {
391
0
                std::vector<UniqueId> success_load_ids;
392
0
                for (const auto& [id, load_info] : _create_plan_deps) {
393
0
                    auto create_dep = std::get<0>(load_info);
394
0
                    auto put_dep = std::get<1>(load_info);
395
0
                    if (created_load_block_queue->schema_version == std::get<2>(load_info) &&
396
0
                        created_load_block_queue->index_size == std::get<3>(load_info)) {
397
0
                        auto st = created_load_block_queue->add_load_id(id, put_dep);
398
0
                        if (!st.ok()) {
399
0
                            LOG(WARNING) << "failed to add pending load_id into created "
400
0
                                            "group commit queue, load_id="
401
0
                                         << id << ", label=" << created_load_block_queue->label
402
0
                                         << ", status=" << st.to_string();
403
0
                            need_resubmit = true;
404
0
                        } else {
405
0
                            create_dep->set_ready();
406
0
                            success_load_ids.emplace_back(id);
407
0
                        }
408
0
                    } else if (created_load_block_queue->schema_version > std::get<2>(load_info) ||
409
0
                               (created_load_block_queue->schema_version ==
410
0
                                        std::get<2>(load_info) &&
411
0
                                created_load_block_queue->index_size != std::get<3>(load_info))) {
412
                        // schema version mismatch:
413
                        //   1. the schema version of created load block queue is newer than the load request
414
                        //   2. the index size is not equal
415
                        // set ready for the load request to let it fail
416
0
                        create_dep->set_ready();
417
0
                        success_load_ids.emplace_back(id);
418
0
                    }
419
0
                }
420
0
                for (const auto& id : success_load_ids) {
421
0
                    _create_plan_deps.erase(id);
422
0
                }
423
0
                if (_create_plan_deps.empty()) {
424
0
                    _create_plan_start_time_ms = 0;
425
0
                }
426
0
            }
427
0
            if (!_create_plan_deps.empty()) {
428
0
                need_resubmit = true;
429
0
            }
430
0
            if (need_resubmit && _group_commit_mgr) {
431
0
                LOG(INFO) << "resubmit create group commit load task for table: " << _table_id;
432
0
                _group_commit_mgr->add_need_create_plan_table(_table_id);
433
0
            }
434
0
        }};
435
0
        create_group_commit_st =
436
0
                _create_group_commit_load(be_exe_version, mem_tracker, created_load_block_queue);
437
0
        if (!create_group_commit_st.ok()) {
438
0
            LOG(WARNING) << "create group commit load error: "
439
0
                         << create_group_commit_st.to_string();
440
0
            create_plan_failed_reason = ". create group commit load error: " +
441
0
                                        create_group_commit_st.to_string().substr(0, 300);
442
0
        } else {
443
0
            create_plan_failed_reason = "";
444
0
        }
445
0
    });
446
0
    if (!submit_st.ok()) {
447
0
        _is_creating_plan_fragment = false;
448
0
        _create_plan_failed_reason =
449
0
                ". create group commit load error: submit create group commit load task failed: " +
450
0
                submit_st.to_string().substr(0, 300);
451
0
        for (const auto& [id, load_info] : _create_plan_deps) {
452
0
            std::get<0>(load_info)->set_ready();
453
0
        }
454
0
        _create_plan_deps.clear();
455
0
        LOG(WARNING) << "submit create group commit load task for table: " << _table_id
456
0
                     << ", error: " << submit_st.to_string();
457
0
    }
458
0
    return submit_st;
459
0
}
460
461
0
void GroupCommitTable::remove_load_id(const UniqueId& load_id) {
462
0
    std::unique_lock l(_lock);
463
0
    if (_create_plan_deps.find(load_id) != _create_plan_deps.end()) {
464
0
        _create_plan_deps.erase(load_id);
465
0
        return;
466
0
    }
467
0
    for (const auto& [_, inner_block_queue] : _load_block_queues) {
468
0
        if (inner_block_queue->remove_load_id(load_id).ok()) {
469
0
            return;
470
0
        }
471
0
    }
472
0
}
473
474
Status GroupCommitTable::_create_group_commit_load(
475
        int be_exe_version, const std::shared_ptr<MemTrackerLimiter>& mem_tracker,
476
0
        std::shared_ptr<LoadBlockQueue>& created_load_block_queue) {
477
0
    Status st = Status::OK();
478
0
    TStreamLoadPutResult result;
479
0
    std::string label;
480
0
    int64_t txn_id;
481
0
    TUniqueId instance_id;
482
0
    {
483
0
        SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER(mem_tracker);
484
0
        UniqueId load_id = UniqueId::gen_uid();
485
0
        TUniqueId tload_id;
486
0
        tload_id.__set_hi(load_id.hi);
487
0
        tload_id.__set_lo(load_id.lo);
488
0
        std::regex reg("-");
489
0
        label = "group_commit_" + std::regex_replace(load_id.to_string(), reg, "_");
490
0
        std::stringstream ss;
491
0
        ss << "insert into doris_internal_table_id(" << _table_id << ") WITH LABEL " << label
492
0
           << " select * from group_commit(\"table_id\"=\"" << _table_id << "\")";
493
0
        TStreamLoadPutRequest request;
494
0
        request.__set_load_sql(ss.str());
495
0
        request.__set_loadId(tload_id);
496
0
        request.__set_label(label);
497
0
        request.__set_token("group_commit"); // this is a fake, fe not check it now
498
0
        request.__set_max_filter_ratio(1.0);
499
0
        request.__set_strictMode(false);
500
0
        request.__set_partial_update(false);
501
        // this is an internal interface, use admin to pass the auth check
502
0
        request.__set_user("admin");
503
0
        if (_exec_env->cluster_info()->backend_id != 0) {
504
0
            request.__set_backend_id(_exec_env->cluster_info()->backend_id);
505
0
        } else {
506
0
            LOG(WARNING) << "_exec_env->cluster_info not set backend_id";
507
0
        }
508
0
        TNetworkAddress master_addr = _exec_env->cluster_info()->master_fe_addr;
509
0
        st = ThriftRpcHelper::rpc<FrontendServiceClient>(
510
0
                master_addr.hostname, master_addr.port,
511
0
                [&result, &request](FrontendServiceConnection& client) {
512
0
                    client->streamLoadPut(result, request);
513
0
                },
514
0
                10000L);
515
0
        if (!st.ok()) {
516
0
            LOG(WARNING) << "create group commit load rpc error, st=" << st.to_string();
517
0
            return st;
518
0
        }
519
0
        st = Status::create<false>(result.status);
520
0
        if (st.ok() && !result.__isset.pipeline_params) {
521
0
            st = Status::InternalError("Non-pipeline is disabled!");
522
0
        }
523
0
        if (!st.ok()) {
524
0
            LOG(WARNING) << "create group commit load error, st=" << st.to_string();
525
0
            return st;
526
0
        }
527
0
        auto& pipeline_params = result.pipeline_params;
528
0
        auto schema_version = pipeline_params.fragment.output_sink.olap_table_sink.schema.version;
529
0
        auto index_size =
530
0
                pipeline_params.fragment.output_sink.olap_table_sink.schema.indexes.size();
531
0
        DCHECK(pipeline_params.fragment.output_sink.olap_table_sink.db_id == _db_id);
532
0
        txn_id = pipeline_params.txn_conf.txn_id;
533
0
        DCHECK(pipeline_params.local_params.size() == 1);
534
0
        instance_id = pipeline_params.local_params[0].fragment_instance_id;
535
0
        VLOG_DEBUG << "create plan fragment, db_id=" << _db_id << ", table=" << _table_id
536
0
                   << ", schema version=" << schema_version << ", index size=" << index_size
537
0
                   << ", label=" << label << ", txn_id=" << txn_id
538
0
                   << ", instance_id=" << print_id(instance_id);
539
0
        {
540
0
            auto load_block_queue = std::make_shared<LoadBlockQueue>(
541
0
                    instance_id, label, txn_id, schema_version, index_size, _all_block_queues_bytes,
542
0
                    result.wait_internal_group_commit_finish, result.group_commit_interval_ms,
543
0
                    result.group_commit_data_bytes);
544
0
            RETURN_IF_ERROR(load_block_queue->create_wal(
545
0
                    _db_id, _table_id, txn_id, label, _exec_env->wal_mgr(),
546
0
                    pipeline_params.fragment.output_sink.olap_table_sink.schema.slot_descs,
547
0
                    be_exe_version));
548
0
            created_load_block_queue = load_block_queue;
549
550
0
            std::unique_lock l(_lock);
551
0
            _load_block_queues.emplace(instance_id, load_block_queue);
552
0
            std::vector<UniqueId> success_load_ids;
553
0
            for (const auto& [id, load_info] : _create_plan_deps) {
554
0
                auto create_dep = std::get<0>(load_info);
555
0
                auto put_dep = std::get<1>(load_info);
556
0
                if (load_block_queue->schema_version == std::get<2>(load_info) &&
557
0
                    load_block_queue->index_size == std::get<3>(load_info)) {
558
0
                    if (load_block_queue->add_load_id(id, put_dep).ok()) {
559
0
                        create_dep->set_ready();
560
0
                        success_load_ids.emplace_back(id);
561
0
                    }
562
0
                } else if (load_block_queue->schema_version > std::get<2>(load_info) ||
563
0
                           (load_block_queue->schema_version == std::get<2>(load_info) &&
564
0
                            load_block_queue->index_size != std::get<3>(load_info))) {
565
                    // schema version mismatch:
566
                    //   1. the schema version of created load block queue is newer than the load request
567
                    //   2. the index size is not equal
568
                    // set ready for the load request to let it fail
569
0
                    create_dep->set_ready();
570
0
                    success_load_ids.emplace_back(id);
571
0
                }
572
0
            }
573
0
            for (const auto& id : success_load_ids) {
574
0
                _create_plan_deps.erase(id);
575
0
            }
576
0
            if (_create_plan_deps.empty()) {
577
0
                _create_plan_start_time_ms = 0;
578
0
            }
579
0
        }
580
0
    }
581
0
    st = _exec_plan_fragment(_db_id, _table_id, label, txn_id, result.pipeline_params);
582
0
    if (!st.ok()) {
583
0
        SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER(mem_tracker);
584
0
        auto finish_st = _finish_group_commit_load(_db_id, _table_id, label, txn_id, instance_id,
585
0
                                                   st, nullptr);
586
0
        if (!finish_st.ok()) {
587
0
            LOG(WARNING) << "finish group commit error, label=" << label
588
0
                         << ", st=" << finish_st.to_string();
589
0
        }
590
0
    }
591
0
    return st;
592
0
}
593
594
Status GroupCommitTable::_finish_group_commit_load(int64_t db_id, int64_t table_id,
595
                                                   const std::string& label, int64_t txn_id,
596
                                                   const TUniqueId& instance_id, Status& status,
597
0
                                                   RuntimeState* state) {
598
0
    Status st;
599
0
    Status result_status;
600
0
    DBUG_EXECUTE_IF("LoadBlockQueue._finish_group_commit_load.err_status", {
601
0
        status = Status::InternalError("LoadBlockQueue._finish_group_commit_load.err_status");
602
0
    });
603
0
    DBUG_EXECUTE_IF("LoadBlockQueue._finish_group_commit_load.load_error",
604
0
                    { status = Status::InternalError("load_error"); });
605
0
    if (status.ok()) {
606
0
        DBUG_EXECUTE_IF("LoadBlockQueue._finish_group_commit_load.commit_error", {
607
0
            status = Status::InternalError("LoadBlockQueue._finish_group_commit_load.commit_error");
608
0
        });
609
        // commit txn
610
0
        TLoadTxnCommitRequest request;
611
        // deprecated and should be removed in 3.1, use token instead
612
0
        request.__set_auth_code(0);
613
0
        request.__set_token(_exec_env->cluster_info()->curr_auth_token);
614
0
        request.__set_db_id(db_id);
615
0
        request.__set_table_id(table_id);
616
0
        request.__set_txnId(txn_id);
617
0
        request.__set_thrift_rpc_timeout_ms(config::txn_commit_rpc_timeout_ms);
618
0
        request.__set_groupCommit(true);
619
0
        request.__set_receiveBytes(state->num_bytes_load_total());
620
0
        if (_exec_env->cluster_info()->backend_id != 0) {
621
0
            request.__set_backendId(_exec_env->cluster_info()->backend_id);
622
0
        } else {
623
0
            LOG(WARNING) << "_exec_env->cluster_info not set backend_id";
624
0
        }
625
0
        if (state) {
626
0
            request.__set_commitInfos(state->tablet_commit_infos());
627
0
        }
628
0
        TLoadTxnCommitResult result;
629
0
        TNetworkAddress master_addr = _exec_env->cluster_info()->master_fe_addr;
630
0
        int retry_times = 0;
631
0
        while (retry_times < config::mow_stream_load_commit_retry_times) {
632
0
            st = ThriftRpcHelper::rpc<FrontendServiceClient>(
633
0
                    master_addr.hostname, master_addr.port,
634
0
                    [&request, &result](FrontendServiceConnection& client) {
635
0
                        client->loadTxnCommit(result, request);
636
0
                    },
637
0
                    config::txn_commit_rpc_timeout_ms);
638
0
            if (st.ok()) {
639
0
                result_status = Status::create(result.status);
640
                // DELETE_BITMAP_LOCK_ERROR will be retried
641
0
                if (result_status.ok() ||
642
0
                    !result_status.is<ErrorCode::DELETE_BITMAP_LOCK_ERROR>()) {
643
0
                    break;
644
0
                }
645
0
                LOG_WARNING("Failed to commit txn on group commit")
646
0
                        .tag("label", label)
647
0
                        .tag("txn_id", txn_id)
648
0
                        .tag("retry_times", retry_times)
649
0
                        .error(result_status);
650
0
            } else {
651
0
                LOG_WARNING("Failed to commit txn on group commit")
652
0
                        .tag("label", label)
653
0
                        .tag("txn_id", txn_id)
654
0
                        .tag("retry_times", retry_times)
655
0
                        .error(st);
656
0
            }
657
0
            retry_times++;
658
0
        }
659
0
        DBUG_EXECUTE_IF("LoadBlockQueue._finish_group_commit_load.commit_success_and_rpc_error",
660
0
                        { result_status = Status::InternalError("commit_success_and_rpc_error"); });
661
0
    } else {
662
        // abort txn
663
0
        TLoadTxnRollbackRequest request;
664
        // deprecated and should be removed in 3.1, use token instead
665
0
        request.__set_auth_code(0);
666
0
        request.__set_token(_exec_env->cluster_info()->curr_auth_token);
667
0
        request.__set_db_id(db_id);
668
0
        request.__set_txnId(txn_id);
669
0
        request.__set_reason(status.to_string());
670
0
        TLoadTxnRollbackResult result;
671
0
        TNetworkAddress master_addr = _exec_env->cluster_info()->master_fe_addr;
672
0
        st = ThriftRpcHelper::rpc<FrontendServiceClient>(
673
0
                master_addr.hostname, master_addr.port,
674
0
                [&request, &result](FrontendServiceConnection& client) {
675
0
                    client->loadTxnRollback(result, request);
676
0
                });
677
0
        if (st.ok()) {
678
0
            result_status = Status::create<false>(result.status);
679
0
        }
680
0
        DBUG_EXECUTE_IF("LoadBlockQueue._finish_group_commit_load.err_status", {
681
0
            std ::string msg = "abort txn";
682
0
            LOG(INFO) << "debug promise set: " << msg;
683
0
            ExecEnv::GetInstance()->group_commit_mgr()->debug_promise.set_value(
684
0
                    Status ::InternalError(msg));
685
0
        });
686
0
    }
687
0
    std::shared_ptr<LoadBlockQueue> load_block_queue;
688
0
    {
689
0
        std::lock_guard<std::mutex> l(_lock);
690
0
        auto it = _load_block_queues.find(instance_id);
691
0
        if (it != _load_block_queues.end()) {
692
0
            load_block_queue = it->second;
693
0
            if (!status.ok()) {
694
0
                load_block_queue->cancel(status);
695
0
            }
696
            //close wal
697
0
            RETURN_IF_ERROR(load_block_queue->close_wal());
698
            // notify sync mode loads
699
0
            {
700
0
                std::unique_lock l2(load_block_queue->mutex);
701
0
                load_block_queue->process_finish = true;
702
0
                for (auto dep : load_block_queue->dependencies) {
703
0
                    dep->set_always_ready();
704
0
                }
705
0
            }
706
0
        }
707
0
        _load_block_queues.erase(instance_id);
708
0
    }
709
0
    if (!load_block_queue) {
710
0
        LOG(WARNING) << "finish group commit can not find load block queue, label=" << label
711
0
                     << ", txn_id=" << txn_id << ", instance_id=" << print_id(instance_id);
712
0
    }
713
    // status: exec_plan_fragment result
714
    // st: commit txn rpc status
715
    // result_status: commit txn result
716
0
    DBUG_EXECUTE_IF("LoadBlockQueue._finish_group_commit_load.err_st", {
717
0
        st = Status::InternalError("LoadBlockQueue._finish_group_commit_load.err_st");
718
0
    });
719
0
    if (status.ok() && st.ok() &&
720
0
        (result_status.ok() || result_status.is<ErrorCode::PUBLISH_TIMEOUT>())) {
721
0
        if (!config::group_commit_wait_replay_wal_finish) {
722
0
            auto delete_st = _exec_env->wal_mgr()->delete_wal(table_id, txn_id);
723
0
            if (!delete_st.ok()) {
724
0
                LOG(WARNING) << "fail to delete wal " << txn_id << ", st=" << delete_st.to_string();
725
0
            }
726
0
        }
727
0
    } else {
728
0
        std::string wal_path;
729
0
        RETURN_IF_ERROR(_exec_env->wal_mgr()->get_wal_path(txn_id, wal_path));
730
0
        RETURN_IF_ERROR(_exec_env->wal_mgr()->add_recover_wal(db_id, table_id, txn_id, wal_path));
731
0
    }
732
0
    std::stringstream ss;
733
0
    ss << "finish group commit, db_id=" << db_id << ", table_id=" << table_id << ", label=" << label
734
0
       << ", txn_id=" << txn_id << ", instance_id=" << print_id(instance_id)
735
0
       << ", exec_plan_fragment status=" << status.to_string()
736
0
       << ", commit/abort txn rpc status=" << st.to_string()
737
0
       << ", commit/abort txn status=" << result_status.to_string();
738
0
    if (load_block_queue) {
739
0
        ss << ", this group commit includes " << load_block_queue->group_commit_load_count
740
0
           << " loads, flush because meet "
741
0
           << (load_block_queue->data_size_condition ? "data size " : "time ") << "condition";
742
0
    } else {
743
0
        ss << ", load block queue is missing when finishing group commit";
744
0
    }
745
0
    ss << ", wal space info:" << ExecEnv::GetInstance()->wal_mgr()->get_wal_dirs_info_string();
746
0
    if (state) {
747
0
        if (!state->get_error_log_file_path().empty()) {
748
0
            ss << ", error_url=" << state->get_error_log_file_path();
749
0
        }
750
0
        if (!state->get_first_error_msg().empty()) {
751
0
            ss << ", first_error_msg=" << state->get_first_error_msg();
752
0
        }
753
0
        ss << ", rows=" << state->num_rows_load_success();
754
0
    }
755
0
    LOG(INFO) << ss.str();
756
0
    DBUG_EXECUTE_IF("LoadBlockQueue._finish_group_commit_load.get_wal_back_pressure_msg", {
757
0
        if (dp->param<int64_t>("table_id", -1) == table_id) {
758
0
            std ::string msg = _exec_env->wal_mgr()->get_wal_dirs_info_string();
759
0
            LOG(INFO) << "table_id" << std::to_string(table_id) << " set debug promise: " << msg;
760
0
            ExecEnv::GetInstance()->group_commit_mgr()->debug_promise.set_value(
761
0
                    Status ::InternalError(msg));
762
0
        }
763
0
    };);
764
0
    return st;
765
0
}
766
767
Status GroupCommitTable::_exec_plan_fragment(int64_t db_id, int64_t table_id,
768
                                             const std::string& label, int64_t txn_id,
769
0
                                             const TPipelineFragmentParams& pipeline_params) {
770
0
    auto finish_cb = [db_id, table_id, label, txn_id, this](RuntimeState* state, Status* status) {
771
0
        DCHECK(state);
772
0
        auto finish_st = _finish_group_commit_load(db_id, table_id, label, txn_id,
773
0
                                                   state->fragment_instance_id(), *status, state);
774
0
        if (!finish_st.ok()) {
775
0
            LOG(WARNING) << "finish group commit error, label=" << label
776
0
                         << ", st=" << finish_st.to_string();
777
0
        }
778
0
    };
779
780
0
    TPipelineFragmentParamsList mocked;
781
0
    return _exec_env->fragment_mgr()->exec_plan_fragment(
782
0
            pipeline_params, QuerySource::GROUP_COMMIT_LOAD, finish_cb, mocked);
783
0
}
784
785
Status GroupCommitTable::get_load_block_queue(const TUniqueId& instance_id,
786
                                              std::shared_ptr<LoadBlockQueue>& load_block_queue,
787
0
                                              std::shared_ptr<Dependency> get_block_dep) {
788
0
    std::unique_lock l(_lock);
789
0
    auto it = _load_block_queues.find(instance_id);
790
0
    if (it == _load_block_queues.end()) {
791
0
        return Status::InternalError("group commit load instance " + print_id(instance_id) +
792
0
                                     " not found");
793
0
    }
794
0
    load_block_queue = it->second;
795
0
    load_block_queue->append_read_dependency(get_block_dep);
796
0
    return Status::OK();
797
0
}
798
799
0
GroupCommitMgr::GroupCommitMgr(ExecEnv* exec_env) : _exec_env(exec_env) {
800
0
    static_cast<void>(ThreadPoolBuilder("GroupCommitThreadPool")
801
0
                              .set_min_threads(1)
802
0
                              .set_max_threads(config::group_commit_insert_threads)
803
0
                              .build(&_thread_pool));
804
0
    _all_block_queues_bytes = std::make_shared<std::atomic_size_t>(0);
805
0
    _group_commit_mem_tracker =
806
0
            MemTrackerLimiter::create_shared(MemTrackerLimiter::Type::LOAD, "GroupCommit");
807
0
    _create_plan_thread = std::thread(&GroupCommitMgr::_create_plan_worker, this);
808
0
}
809
810
0
GroupCommitMgr::~GroupCommitMgr() {
811
0
    stop();
812
0
    LOG(INFO) << "GroupCommitMgr is destoried";
813
0
}
814
815
0
void GroupCommitMgr::stop() {
816
0
    {
817
0
        std::lock_guard<std::mutex> l(_need_create_plan_lock);
818
0
        if (_stopped) {
819
0
            return;
820
0
        }
821
0
        _stopped = true;
822
0
    }
823
0
    _need_create_plan_cv.notify_all();
824
0
    if (_create_plan_thread.joinable()) {
825
0
        _create_plan_thread.join();
826
0
    }
827
0
    _thread_pool->shutdown();
828
0
    LOG(INFO) << "GroupCommitMgr is stopped";
829
0
}
830
831
0
void GroupCommitMgr::add_need_create_plan_table(int64_t table_id) {
832
0
    {
833
0
        std::lock_guard<std::mutex> l(_need_create_plan_lock);
834
0
        if (_stopped) {
835
0
            return;
836
0
        }
837
0
        _need_create_plan_tables.insert(table_id);
838
0
    }
839
0
    _need_create_plan_cv.notify_one();
840
0
}
841
842
0
void GroupCommitMgr::_create_plan_worker() {
843
0
    SCOPED_INIT_THREAD_CONTEXT();
844
0
    while (true) {
845
0
        std::set<int64_t> need_create_plan_tables;
846
0
        {
847
0
            std::unique_lock<std::mutex> l(_need_create_plan_lock);
848
0
            _need_create_plan_cv.wait(
849
0
                    l, [this] { return _stopped || !_need_create_plan_tables.empty(); });
850
0
            if (_stopped && _need_create_plan_tables.empty()) {
851
0
                return;
852
0
            }
853
0
            need_create_plan_tables.swap(_need_create_plan_tables);
854
0
        }
855
0
        for (const auto table_id : need_create_plan_tables) {
856
0
            std::shared_ptr<GroupCommitTable> group_commit_table;
857
0
            {
858
0
                std::lock_guard<std::mutex> l(_lock);
859
0
                auto it = _table_map.find(table_id);
860
0
                if (it == _table_map.end()) {
861
0
                    continue;
862
0
                }
863
0
                group_commit_table = it->second;
864
0
            }
865
0
            auto st = group_commit_table->submit_create_group_commit_load();
866
0
            if (!st.ok()) {
867
0
                LOG(WARNING) << "submit create group commit load task from worker for table: "
868
0
                             << table_id << ", error: " << st.to_string();
869
0
            }
870
0
        }
871
0
    }
872
0
}
873
874
Status GroupCommitMgr::get_first_block_load_queue(
875
        int64_t db_id, int64_t table_id, int64_t base_schema_version, int64_t index_size,
876
        const UniqueId& load_id, std::shared_ptr<LoadBlockQueue>& load_block_queue,
877
        int be_exe_version, TGroupCommitMode::type group_commit_mode,
878
0
        std::shared_ptr<Dependency> create_plan_dep, std::shared_ptr<Dependency> put_block_dep) {
879
0
    std::shared_ptr<GroupCommitTable> group_commit_table;
880
0
    {
881
0
        std::lock_guard wlock(_lock);
882
0
        if (_table_map.find(table_id) == _table_map.end()) {
883
0
            _table_map.emplace(table_id, std::make_shared<GroupCommitTable>(
884
0
                                                 _exec_env, _thread_pool.get(), db_id, table_id,
885
0
                                                 _all_block_queues_bytes, this));
886
0
        }
887
0
        group_commit_table = _table_map[table_id];
888
0
    }
889
0
    RETURN_IF_ERROR(group_commit_table->get_first_block_load_queue(
890
0
            table_id, base_schema_version, index_size, load_id, load_block_queue, be_exe_version,
891
0
            group_commit_mode, create_plan_dep, put_block_dep));
892
0
    return Status::OK();
893
0
}
894
895
Status GroupCommitMgr::get_load_block_queue(int64_t table_id, const TUniqueId& instance_id,
896
                                            std::shared_ptr<LoadBlockQueue>& load_block_queue,
897
0
                                            std::shared_ptr<Dependency> get_block_dep) {
898
0
    std::shared_ptr<GroupCommitTable> group_commit_table;
899
0
    {
900
0
        std::lock_guard<std::mutex> l(_lock);
901
0
        auto it = _table_map.find(table_id);
902
0
        if (it == _table_map.end()) {
903
0
            return Status::NotFound("table_id: " + std::to_string(table_id) +
904
0
                                    ", instance_id: " + print_id(instance_id) + " dose not exist");
905
0
        }
906
0
        group_commit_table = it->second;
907
0
    }
908
0
    return group_commit_table->get_load_block_queue(instance_id, load_block_queue, get_block_dep);
909
0
}
910
911
0
void GroupCommitMgr::remove_load_id(int64_t table_id, const UniqueId& load_id) {
912
0
    std::lock_guard wlock(_lock);
913
0
    if (_table_map.find(table_id) != _table_map.end()) {
914
0
        _table_map.find(table_id)->second->remove_load_id(load_id);
915
0
    }
916
0
}
917
918
Status LoadBlockQueue::create_wal(int64_t db_id, int64_t tb_id, int64_t wal_id,
919
                                  const std::string& import_label, WalManager* wal_manager,
920
0
                                  std::vector<TSlotDescriptor>& slot_desc, int be_exe_version) {
921
0
    std::string real_label = config::group_commit_wait_replay_wal_finish
922
0
                                     ? import_label + "_test_wait"
923
0
                                     : import_label;
924
0
    RETURN_IF_ERROR(ExecEnv::GetInstance()->wal_mgr()->create_wal_path(
925
0
            db_id, tb_id, wal_id, real_label, _wal_base_path, WAL_VERSION));
926
0
    _v_wal_writer = std::make_shared<VWalWriter>(db_id, tb_id, wal_id, real_label, wal_manager,
927
0
                                                 slot_desc, be_exe_version);
928
0
    return _v_wal_writer->init();
929
0
}
930
931
0
Status LoadBlockQueue::close_wal() {
932
0
    if (_v_wal_writer != nullptr) {
933
0
        RETURN_IF_ERROR(_v_wal_writer->close());
934
0
    }
935
0
    return Status::OK();
936
0
}
937
938
0
void LoadBlockQueue::append_dependency(std::shared_ptr<Dependency> finish_dep) {
939
0
    std::lock_guard<std::mutex> lock(mutex);
940
    // If not finished, dependencies should be blocked.
941
0
    if (!process_finish) {
942
0
        finish_dep->block();
943
0
        dependencies.push_back(finish_dep);
944
0
    }
945
0
}
946
947
0
void LoadBlockQueue::append_read_dependency(std::shared_ptr<Dependency> read_dep) {
948
0
    std::lock_guard<std::mutex> lock(mutex);
949
0
    _read_deps.push_back(read_dep);
950
0
}
951
952
0
bool LoadBlockQueue::has_enough_wal_disk_space(size_t estimated_wal_bytes) {
953
0
    DBUG_EXECUTE_IF("LoadBlockQueue.has_enough_wal_disk_space.low_space", { return false; });
954
0
    auto* wal_mgr = ExecEnv::GetInstance()->wal_mgr();
955
0
    size_t available_bytes = 0;
956
0
    {
957
0
        Status st = wal_mgr->get_wal_dir_available_size(_wal_base_path, &available_bytes);
958
0
        if (!st.ok()) {
959
0
            LOG(WARNING) << "get wal dir available size failed, st=" << st.to_string();
960
0
        }
961
0
    }
962
0
    if (estimated_wal_bytes < available_bytes) {
963
0
        Status st =
964
0
                wal_mgr->update_wal_dir_estimated_wal_bytes(_wal_base_path, estimated_wal_bytes, 0);
965
0
        if (!st.ok()) {
966
0
            LOG(WARNING) << "update wal dir estimated_wal_bytes failed, reason: " << st.to_string();
967
0
        }
968
0
        return true;
969
0
    } else {
970
0
        return false;
971
0
    }
972
0
}
973
974
} // namespace doris