be/src/load/group_commit/group_commit_mgr.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 | | |
20 | | #include <gen_cpp/PaloInternalService_types.h> |
21 | | |
22 | | #include <atomic> |
23 | | #include <condition_variable> |
24 | | #include <cstdint> |
25 | | #include <future> |
26 | | #include <memory> |
27 | | #include <mutex> |
28 | | #include <set> |
29 | | #include <shared_mutex> |
30 | | #include <thread> |
31 | | #include <unordered_map> |
32 | | #include <utility> |
33 | | |
34 | | #include "common/status.h" |
35 | | #include "core/block/block.h" |
36 | | #include "exec/sink/writer/vwal_writer.h" |
37 | | #include "load/group_commit/wal/wal_manager.h" |
38 | | #include "runtime/exec_env.h" |
39 | | #include "util/threadpool.h" |
40 | | |
41 | | namespace doris { |
42 | | class ExecEnv; |
43 | | class GroupCommitMgr; |
44 | | class TUniqueId; |
45 | | class RuntimeState; |
46 | | |
47 | | class Dependency; |
48 | | |
49 | | struct BlockData { |
50 | 0 | BlockData(const std::shared_ptr<Block>& block) : block(block), block_bytes(block->bytes()) {}; |
51 | | std::shared_ptr<Block> block; |
52 | | size_t block_bytes; |
53 | | }; |
54 | | |
55 | | class LoadBlockQueue { |
56 | | public: |
57 | | LoadBlockQueue(const UniqueId& load_instance_id, std::string& label, int64_t txn_id, |
58 | | int64_t schema_version, int64_t index_size, |
59 | | std::shared_ptr<std::atomic_size_t> all_block_queues_bytes, |
60 | | bool wait_internal_group_commit_finish, int64_t group_commit_interval_ms, |
61 | | int64_t group_commit_data_bytes) |
62 | 0 | : load_instance_id(load_instance_id), |
63 | 0 | label(label), |
64 | 0 | txn_id(txn_id), |
65 | 0 | schema_version(schema_version), |
66 | 0 | index_size(index_size), |
67 | 0 | wait_internal_group_commit_finish(wait_internal_group_commit_finish), |
68 | 0 | _group_commit_interval_ms(group_commit_interval_ms), |
69 | 0 | _start_time(std::chrono::steady_clock::now()), |
70 | 0 | _last_print_time(_start_time), |
71 | 0 | _group_commit_data_bytes(group_commit_data_bytes), |
72 | 0 | _all_block_queues_bytes(all_block_queues_bytes) {}; |
73 | | |
74 | | Status add_block(RuntimeState* runtime_state, std::shared_ptr<Block> block, bool write_wal, |
75 | | UniqueId& load_id); |
76 | | Status get_block(RuntimeState* runtime_state, Block* block, bool* find_block, bool* eos, |
77 | | std::shared_ptr<Dependency> get_block_dep); |
78 | | bool contain_load_id(const UniqueId& load_id); |
79 | | Status add_load_id(const UniqueId& load_id, const std::shared_ptr<Dependency> put_block_dep); |
80 | | Status remove_load_id(const UniqueId& load_id); |
81 | | void cancel(const Status& st); |
82 | 0 | bool need_commit() const { return _need_commit.load(); } |
83 | | |
84 | | Status create_wal(int64_t db_id, int64_t tb_id, int64_t wal_id, const std::string& import_label, |
85 | | WalManager* wal_manager, std::vector<TSlotDescriptor>& slot_desc, |
86 | | int be_exe_version); |
87 | | Status close_wal(); |
88 | | bool has_enough_wal_disk_space(size_t estimated_wal_bytes); |
89 | | void append_dependency(std::shared_ptr<Dependency> finish_dep); |
90 | | void append_read_dependency(std::shared_ptr<Dependency> read_dep); |
91 | 0 | int64_t get_group_commit_interval_ms() { return _group_commit_interval_ms; }; |
92 | | |
93 | 0 | std::string debug_string() const { |
94 | 0 | fmt::memory_buffer debug_string_buffer; |
95 | 0 | fmt::format_to( |
96 | 0 | debug_string_buffer, |
97 | 0 | "load_instance_id={}, label={}, txn_id={}, " |
98 | 0 | "wait_internal_group_commit_finish={}, data_size_condition={}, " |
99 | 0 | "group_commit_load_count={}, process_finish={}, _need_commit={}, schema_version={}", |
100 | 0 | load_instance_id.to_string(), label, txn_id, wait_internal_group_commit_finish, |
101 | 0 | data_size_condition, group_commit_load_count, process_finish.load(), |
102 | 0 | _need_commit.load(), schema_version); |
103 | 0 | return fmt::to_string(debug_string_buffer); |
104 | 0 | } |
105 | | |
106 | | UniqueId load_instance_id; |
107 | | std::string label; |
108 | | int64_t txn_id; |
109 | | int64_t schema_version; |
110 | | int64_t index_size; |
111 | | bool wait_internal_group_commit_finish = false; |
112 | | bool data_size_condition = false; |
113 | | |
114 | | // counts of load in one group commit |
115 | | std::atomic_size_t group_commit_load_count = 0; |
116 | | |
117 | | // only used by fault injection (debug point) to reproduce that multiple loads |
118 | | // reuse one group commit plan and share a load_id |
119 | | std::atomic<int> _debug_add_block_seq = 0; |
120 | | |
121 | | // the execute status of this internal group commit |
122 | | std::mutex mutex; |
123 | | std::atomic<bool> process_finish = false; |
124 | | Status status = Status::OK(); |
125 | | std::vector<std::shared_ptr<Dependency>> dependencies; |
126 | | |
127 | | private: |
128 | | void _cancel_without_lock(const Status& st); |
129 | | std::string _get_load_ids(); |
130 | | |
131 | | // the set of load ids of all blocks in this queue |
132 | | std::map<UniqueId, std::shared_ptr<Dependency>> _load_ids_to_write_dep; |
133 | | std::vector<std::shared_ptr<Dependency>> _read_deps; |
134 | | std::list<BlockData> _block_queue; |
135 | | |
136 | | // wal |
137 | | std::string _wal_base_path; |
138 | | std::shared_ptr<VWalWriter> _v_wal_writer; |
139 | | |
140 | | // commit |
141 | | std::atomic<bool> _need_commit = false; |
142 | | // commit by time interval, can be changed by 'ALTER TABLE my_table SET ("group_commit_interval_ms"="1000");' |
143 | | int64_t _group_commit_interval_ms; |
144 | | std::chrono::steady_clock::time_point _start_time; |
145 | | std::chrono::steady_clock::time_point _last_print_time; |
146 | | // commit by data size |
147 | | int64_t _group_commit_data_bytes; |
148 | | int64_t _data_bytes = 0; |
149 | | |
150 | | // memory back pressure, memory consumption of all tables' load block queues |
151 | | std::shared_ptr<std::atomic_size_t> _all_block_queues_bytes; |
152 | | std::condition_variable _get_cond; |
153 | | }; |
154 | | |
155 | | class GroupCommitTable { |
156 | | public: |
157 | | GroupCommitTable(ExecEnv* exec_env, doris::ThreadPool* thread_pool, int64_t db_id, |
158 | | int64_t table_id, std::shared_ptr<std::atomic_size_t> all_block_queue_bytes, |
159 | | GroupCommitMgr* group_commit_mgr) |
160 | 0 | : _exec_env(exec_env), |
161 | 0 | _thread_pool(thread_pool), |
162 | 0 | _all_block_queues_bytes(all_block_queue_bytes), |
163 | 0 | _db_id(db_id), |
164 | 0 | _table_id(table_id), |
165 | 0 | _group_commit_mgr(group_commit_mgr) {}; |
166 | | Status get_first_block_load_queue(int64_t table_id, int64_t base_schema_version, |
167 | | int64_t index_size, const UniqueId& load_id, |
168 | | std::shared_ptr<LoadBlockQueue>& load_block_queue, |
169 | | int be_exe_version, |
170 | | std::shared_ptr<Dependency> create_plan_dep, |
171 | | std::shared_ptr<Dependency> put_block_dep); |
172 | | Status get_load_block_queue(const TUniqueId& instance_id, |
173 | | std::shared_ptr<LoadBlockQueue>& load_block_queue, |
174 | | std::shared_ptr<Dependency> get_block_dep); |
175 | | void remove_load_id(const UniqueId& load_id); |
176 | | Status submit_create_group_commit_load(); |
177 | | |
178 | | private: |
179 | | Status _submit_create_group_commit_load(); |
180 | | Status _create_group_commit_load(int be_exe_version, |
181 | | const std::shared_ptr<MemTrackerLimiter>& mem_tracker, |
182 | | std::shared_ptr<LoadBlockQueue>& created_load_block_queue); |
183 | | Status _exec_plan_fragment(int64_t db_id, int64_t table_id, const std::string& label, |
184 | | int64_t txn_id, const TPipelineFragmentParams& pipeline_params); |
185 | | Status _finish_group_commit_load(int64_t db_id, int64_t table_id, const std::string& label, |
186 | | int64_t txn_id, const TUniqueId& instance_id, Status& status, |
187 | | RuntimeState* state); |
188 | | |
189 | | ExecEnv* _exec_env = nullptr; |
190 | | ThreadPool* _thread_pool = nullptr; |
191 | | // memory consumption of all tables' load block queues, used for memory back pressure. |
192 | | std::shared_ptr<std::atomic_size_t> _all_block_queues_bytes; |
193 | | |
194 | | int64_t _db_id; |
195 | | int64_t _table_id; |
196 | | GroupCommitMgr* _group_commit_mgr = nullptr; |
197 | | |
198 | | std::mutex _lock; |
199 | | // fragment_instance_id to load_block_queue |
200 | | std::unordered_map<UniqueId, std::shared_ptr<LoadBlockQueue>> _load_block_queues; |
201 | | bool _is_creating_plan_fragment = false; |
202 | | // user_load_id -> <create_plan_dep, put_block_dep, base_schema_version, index_size> |
203 | | std::unordered_map<UniqueId, std::tuple<std::shared_ptr<Dependency>, |
204 | | std::shared_ptr<Dependency>, int64_t, int64_t>> |
205 | | _create_plan_deps; |
206 | | std::string _create_plan_failed_reason; |
207 | | int _create_plan_be_exe_version = 0; |
208 | | int64_t _create_plan_start_time_ms = 0; |
209 | | }; |
210 | | |
211 | | class GroupCommitMgr { |
212 | | public: |
213 | | GroupCommitMgr(ExecEnv* exec_env); |
214 | | virtual ~GroupCommitMgr(); |
215 | | |
216 | | void stop(); |
217 | | |
218 | | // used when init group_commit_scan_node |
219 | | Status get_load_block_queue(int64_t table_id, const TUniqueId& instance_id, |
220 | | std::shared_ptr<LoadBlockQueue>& load_block_queue, |
221 | | std::shared_ptr<Dependency> get_block_dep); |
222 | | Status get_first_block_load_queue(int64_t db_id, int64_t table_id, int64_t base_schema_version, |
223 | | int64_t index_size, const UniqueId& load_id, |
224 | | std::shared_ptr<LoadBlockQueue>& load_block_queue, |
225 | | int be_exe_version, |
226 | | std::shared_ptr<Dependency> create_plan_dep, |
227 | | std::shared_ptr<Dependency> put_block_dep); |
228 | | void remove_load_id(int64_t table_id, const UniqueId& load_id); |
229 | | std::promise<Status> debug_promise; |
230 | | std::future<Status> debug_future = debug_promise.get_future(); |
231 | | void add_need_create_plan_table(int64_t table_id); |
232 | 0 | std::shared_ptr<MemTrackerLimiter> group_commit_mem_tracker() { |
233 | 0 | return _group_commit_mem_tracker; |
234 | 0 | } |
235 | | |
236 | | private: |
237 | | void _create_plan_worker(); |
238 | | |
239 | | ExecEnv* _exec_env = nullptr; |
240 | | std::unique_ptr<doris::ThreadPool> _thread_pool; |
241 | | // memory consumption of all tables' load block queues, used for memory back pressure. |
242 | | std::shared_ptr<std::atomic_size_t> _all_block_queues_bytes; |
243 | | |
244 | | std::mutex _lock; |
245 | | // TODO remove table when unused |
246 | | std::unordered_map<int64_t, std::shared_ptr<GroupCommitTable>> _table_map; |
247 | | std::mutex _need_create_plan_lock; |
248 | | std::condition_variable _need_create_plan_cv; |
249 | | std::set<int64_t> _need_create_plan_tables; |
250 | | bool _stopped = false; |
251 | | std::thread _create_plan_thread; |
252 | | std::shared_ptr<MemTrackerLimiter> _group_commit_mem_tracker; |
253 | | }; |
254 | | |
255 | | } // namespace doris |