be/src/storage/rowset/segment_creator.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/internal_service.pb.h> |
21 | | #include <gen_cpp/olap_file.pb.h> |
22 | | |
23 | | #include <limits> |
24 | | #include <memory> |
25 | | #include <mutex> |
26 | | #include <utility> |
27 | | #include <vector> |
28 | | |
29 | | #include "common/status.h" |
30 | | #include "core/block/block.h" |
31 | | #include "io/fs/file_reader_writer_fwd.h" |
32 | | #include "storage/index/index_file_writer.h" |
33 | | #include "storage/rowset/rowset_writer_context.h" |
34 | | #include "storage/segment/segment_index_file_cache_loader.h" |
35 | | #include "storage/tablet/tablet_fwd.h" |
36 | | |
37 | | namespace doris { |
38 | | class Block; |
39 | | |
40 | | namespace segment_v2 { |
41 | | class SegmentWriter; |
42 | | class VerticalSegmentWriter; |
43 | | class DerivedColumnGenerator; |
44 | | // Matches block_transform.h: at most one derived column (the row-store column) |
45 | | // for each flush, held as a {cid, generator} pair; null generator means none. |
46 | | using DerivedColumn = std::pair<uint32_t, std::shared_ptr<const DerivedColumnGenerator>>; |
47 | | } // namespace segment_v2 |
48 | | |
49 | | struct SegmentStatistics; |
50 | | class BetaRowsetWriter; |
51 | | class SegmentFileCollection; |
52 | | class InvertedIndexFileCollection; |
53 | | |
54 | | class FileWriterCreator { |
55 | | public: |
56 | 1.45k | virtual ~FileWriterCreator() = default; |
57 | | |
58 | | virtual Status create(uint32_t segment_id, io::FileWriterPtr& file_writer, |
59 | | FileType file_type = FileType::SEGMENT_FILE) = 0; |
60 | | |
61 | | virtual Status create(uint32_t segment_id, IndexFileWriterPtr* file_writer) = 0; |
62 | | }; |
63 | | |
64 | | template <class T> |
65 | | requires std::is_base_of_v<RowsetWriter, T> |
66 | | class FileWriterCreatorT : public FileWriterCreator { |
67 | | public: |
68 | 1.27k | explicit FileWriterCreatorT(T* t) : _t(t) {}_ZN5doris18FileWriterCreatorTINS_20BaseBetaRowsetWriterEEC2EPS1_ Line | Count | Source | 68 | 1.27k | explicit FileWriterCreatorT(T* t) : _t(t) {} |
_ZN5doris18FileWriterCreatorTINS_18BetaRowsetWriterV2EEC2EPS1_ Line | Count | Source | 68 | 1 | explicit FileWriterCreatorT(T* t) : _t(t) {} |
|
69 | | |
70 | | Status create(uint32_t segment_id, io::FileWriterPtr& file_writer, |
71 | 2.05k | FileType file_type = FileType::SEGMENT_FILE) override { |
72 | 2.05k | return _t->create_file_writer(segment_id, file_writer, file_type); |
73 | 2.05k | } _ZN5doris18FileWriterCreatorTINS_20BaseBetaRowsetWriterEE6createEjRSt10unique_ptrINS_2io10FileWriterESt14default_deleteIS5_EENS_8FileTypeE Line | Count | Source | 71 | 2.05k | FileType file_type = FileType::SEGMENT_FILE) override { | 72 | 2.05k | return _t->create_file_writer(segment_id, file_writer, file_type); | 73 | 2.05k | } |
Unexecuted instantiation: _ZN5doris18FileWriterCreatorTINS_18BetaRowsetWriterV2EE6createEjRSt10unique_ptrINS_2io10FileWriterESt14default_deleteIS5_EENS_8FileTypeE |
74 | | |
75 | 294 | Status create(uint32_t segment_id, IndexFileWriterPtr* file_writer) override { |
76 | 294 | return _t->create_index_file_writer(segment_id, file_writer); |
77 | 294 | } _ZN5doris18FileWriterCreatorTINS_20BaseBetaRowsetWriterEE6createEjPSt10unique_ptrINS_10segment_v215IndexFileWriterESt14default_deleteIS5_EE Line | Count | Source | 75 | 294 | Status create(uint32_t segment_id, IndexFileWriterPtr* file_writer) override { | 76 | 294 | return _t->create_index_file_writer(segment_id, file_writer); | 77 | 294 | } |
Unexecuted instantiation: _ZN5doris18FileWriterCreatorTINS_18BetaRowsetWriterV2EE6createEjPSt10unique_ptrINS_10segment_v215IndexFileWriterESt14default_deleteIS5_EE |
78 | | |
79 | | private: |
80 | | T* _t = nullptr; |
81 | | }; |
82 | | |
83 | | class SegmentCollector { |
84 | | public: |
85 | 1.45k | virtual ~SegmentCollector() = default; |
86 | | |
87 | | virtual Status add(uint32_t segment_id, SegmentStatistics& segstat) = 0; |
88 | | }; |
89 | | |
90 | | template <class T> |
91 | | requires std::is_base_of_v<RowsetWriter, T> |
92 | | class SegmentCollectorT : public SegmentCollector { |
93 | | public: |
94 | 1.27k | explicit SegmentCollectorT(T* t) : _t(t) {}_ZN5doris17SegmentCollectorTINS_20BaseBetaRowsetWriterEEC2EPS1_ Line | Count | Source | 94 | 1.27k | explicit SegmentCollectorT(T* t) : _t(t) {} |
_ZN5doris17SegmentCollectorTINS_18BetaRowsetWriterV2EEC2EPS1_ Line | Count | Source | 94 | 1 | explicit SegmentCollectorT(T* t) : _t(t) {} |
|
95 | | |
96 | 2.05k | Status add(uint32_t segment_id, SegmentStatistics& segstat) override { |
97 | 2.05k | return _t->add_segment(segment_id, segstat); |
98 | 2.05k | } _ZN5doris17SegmentCollectorTINS_20BaseBetaRowsetWriterEE3addEjRNS_17SegmentStatisticsE Line | Count | Source | 96 | 2.05k | Status add(uint32_t segment_id, SegmentStatistics& segstat) override { | 97 | 2.05k | return _t->add_segment(segment_id, segstat); | 98 | 2.05k | } |
Unexecuted instantiation: _ZN5doris17SegmentCollectorTINS_18BetaRowsetWriterV2EE3addEjRNS_17SegmentStatisticsE |
99 | | |
100 | | private: |
101 | | T* _t = nullptr; |
102 | | }; |
103 | | |
104 | | class SegmentFlusher { |
105 | | public: |
106 | | SegmentFlusher(RowsetWriterContext& context, SegmentFileCollection& seg_files, |
107 | | InvertedIndexFileCollection& idx_files); |
108 | | |
109 | | ~SegmentFlusher(); |
110 | | |
111 | | // Runs the block transform chain on `block` and hands back the derived (row-store) |
112 | | // column for the caller to feed into its writer. |
113 | | Status transform_block(Block* block, int32_t segment_id, |
114 | | segment_v2::DerivedColumn* derived_column); |
115 | | |
116 | | // Return the file size flushed to disk in "flush_size" |
117 | | // This method is thread-safe. |
118 | | Status flush_single_block(const Block* block, int32_t segment_id, |
119 | | int64_t* flush_size = nullptr); |
120 | | |
121 | 17 | int64_t num_rows_written() const { return _num_rows_written; } |
122 | | |
123 | | // for partial update |
124 | 1 | int64_t num_rows_updated() const { return _num_rows_updated; } |
125 | 1 | int64_t num_rows_deleted() const { return _num_rows_deleted; } |
126 | 1 | int64_t num_rows_new_added() const { return _num_rows_new_added; } |
127 | 1 | int64_t num_rows_filtered() const { return _num_rows_filtered; } |
128 | | |
129 | | Status close(); |
130 | | |
131 | | public: |
132 | | class Writer { |
133 | | friend class SegmentFlusher; |
134 | | |
135 | | public: |
136 | | ~Writer(); |
137 | | |
138 | 2.56k | Status add_rows(const Block* block, size_t row_offset, size_t input_row_num) { |
139 | 2.56k | RETURN_IF_ERROR(_flusher->_add_rows(_writer, block, row_offset, input_row_num)); |
140 | 2.56k | _flusher->_num_rows_written += input_row_num; |
141 | 2.56k | return Status::OK(); |
142 | 2.56k | } |
143 | | |
144 | | Status flush(); |
145 | | |
146 | | int64_t max_row_to_add(size_t row_avg_size_in_bytes); |
147 | | |
148 | | private: |
149 | | Writer(SegmentFlusher* flusher, std::unique_ptr<segment_v2::SegmentWriter>& segment_writer); |
150 | | |
151 | | SegmentFlusher* _flusher = nullptr; |
152 | | std::unique_ptr<segment_v2::SegmentWriter> _writer; |
153 | | }; |
154 | | |
155 | | Status create_writer(std::unique_ptr<SegmentFlusher::Writer>& writer, uint32_t segment_id); |
156 | | |
157 | | private: |
158 | | Status _add_rows(std::unique_ptr<segment_v2::SegmentWriter>& segment_writer, const Block* block, |
159 | | size_t row_offset, size_t row_num); |
160 | | Status _add_rows(std::unique_ptr<segment_v2::VerticalSegmentWriter>& segment_writer, |
161 | | const Block* block, size_t row_offset, size_t row_num); |
162 | | Status _create_segment_writer(std::unique_ptr<segment_v2::SegmentWriter>& writer, |
163 | | int32_t segment_id, bool no_compression = false); |
164 | | Status _create_segment_writer(std::unique_ptr<segment_v2::VerticalSegmentWriter>& writer, |
165 | | int32_t segment_id, bool no_compression = false); |
166 | | Status _flush_segment_writer(std::unique_ptr<segment_v2::SegmentWriter>& writer, |
167 | | int64_t* flush_size = nullptr); |
168 | | Status _flush_segment_writer(std::unique_ptr<segment_v2::VerticalSegmentWriter>& writer, |
169 | | int64_t* flush_size = nullptr); |
170 | | void _record_segment_index_file_cache_preload( |
171 | | uint32_t segment_id, const segment_v2::SegmentIndexFileCacheInfo& info); |
172 | | Status _preload_segment_indexes_to_file_cache(); |
173 | | |
174 | | private: |
175 | | RowsetWriterContext& _context; |
176 | | SegmentFileCollection& _seg_files; |
177 | | InvertedIndexFileCollection& _idx_files; |
178 | | |
179 | | // written rows by add_block/add_row |
180 | | std::atomic<int64_t> _num_rows_written = 0; |
181 | | std::atomic<int64_t> _num_rows_updated = 0; |
182 | | std::atomic<int64_t> _num_rows_new_added = 0; |
183 | | std::atomic<int64_t> _num_rows_deleted = 0; |
184 | | std::atomic<int64_t> _num_rows_filtered = 0; |
185 | | std::mutex _segment_index_file_cache_preloads_lock; |
186 | | std::vector<segment_v2::SegmentIndexFileCachePreloadTask> _segment_index_file_cache_preloads; |
187 | | }; |
188 | | |
189 | | class SegmentCreator { |
190 | | public: |
191 | | SegmentCreator(RowsetWriterContext& context, SegmentFileCollection& seg_files, |
192 | | InvertedIndexFileCollection& idx_files); |
193 | | |
194 | 1.28k | ~SegmentCreator() = default; |
195 | | |
196 | | void set_segment_start_id(int32_t start_seg_id, |
197 | 6 | int32_t max_seg_num = std::numeric_limits<int32_t>::max()) { |
198 | 6 | DORIS_CHECK_GE(start_seg_id, 0); |
199 | 6 | DORIS_CHECK_GE(max_seg_num, 0); |
200 | 6 | DORIS_CHECK_EQ(_next_segment_id.load(std::memory_order_relaxed), _segment_start_id); |
201 | 6 | if (max_seg_num != std::numeric_limits<int32_t>::max()) { |
202 | 3 | DORIS_CHECK_LE(static_cast<int64_t>(start_seg_id) + max_seg_num, |
203 | 3 | std::numeric_limits<int32_t>::max()); |
204 | 3 | } |
205 | 6 | _segment_start_id = start_seg_id; |
206 | 6 | _max_segment_num = max_seg_num; |
207 | 6 | _next_segment_id.store(start_seg_id, std::memory_order_relaxed); |
208 | 6 | } |
209 | | |
210 | | Status add_block(const Block* block); |
211 | | |
212 | | Status flush(); |
213 | | |
214 | 3.41k | Result<int32_t> allocate_segment_id() { |
215 | 3.41k | if (_max_segment_num == std::numeric_limits<int32_t>::max()) { |
216 | 3.28k | return _next_segment_id.fetch_add(1, std::memory_order_relaxed); |
217 | 3.28k | } |
218 | | |
219 | 131 | int32_t next_seg_id = _next_segment_id.load(std::memory_order_relaxed); |
220 | 132 | while (true) { |
221 | 132 | const int64_t allocated_segment_num = |
222 | 132 | static_cast<int64_t>(next_seg_id) - _segment_start_id; |
223 | 132 | if (allocated_segment_num >= _max_segment_num) { |
224 | 66 | return ResultError(Status::Error<ErrorCode::TOO_MANY_SEGMENTS>( |
225 | 66 | "too many segments, start_seg_id:{}, max_seg_num:{}", _segment_start_id, |
226 | 66 | _max_segment_num)); |
227 | 66 | } |
228 | 66 | if (_next_segment_id.compare_exchange_weak(next_seg_id, next_seg_id + 1, |
229 | 66 | std::memory_order_relaxed)) { |
230 | 66 | return next_seg_id; |
231 | 66 | } |
232 | 66 | } |
233 | 131 | } |
234 | | |
235 | | // Return the next segment id to be allocated without advancing internal state. |
236 | 392 | int32_t get_allocated_segment_id() const { return _next_segment_id.load(); } |
237 | | |
238 | 31 | int32_t next_segment_id() const { return _next_segment_id.load(); } |
239 | | |
240 | 17 | int64_t num_rows_written() const { return _segment_flusher.num_rows_written(); } |
241 | | |
242 | | // for partial update |
243 | 1 | int64_t num_rows_updated() const { return _segment_flusher.num_rows_updated(); } |
244 | 1 | int64_t num_rows_deleted() const { return _segment_flusher.num_rows_deleted(); } |
245 | 1 | int64_t num_rows_new_added() const { return _segment_flusher.num_rows_new_added(); } |
246 | 1 | int64_t num_rows_filtered() const { return _segment_flusher.num_rows_filtered(); } |
247 | | |
248 | | // Flush a block into a single segment, with pre-allocated segment_id. |
249 | | // Return the file size flushed to disk in "flush_size" |
250 | | // This method is thread-safe. |
251 | | Status flush_single_block(const Block* block, int32_t segment_id, |
252 | | int64_t* flush_size = nullptr); |
253 | | |
254 | | // Flush a block into a single segment, without pre-allocated segment_id. |
255 | | // This method is thread-safe. |
256 | 5 | Status flush_single_block(const Block* block) { |
257 | 5 | auto segment_id = DORIS_TRY(allocate_segment_id()); |
258 | 5 | return flush_single_block(block, segment_id); |
259 | 5 | } |
260 | | |
261 | | Status close(); |
262 | | |
263 | | private: |
264 | | std::atomic<int32_t> _next_segment_id = 0; |
265 | | int32_t _segment_start_id = 0; |
266 | | int32_t _max_segment_num = std::numeric_limits<int32_t>::max(); |
267 | | SegmentFlusher _segment_flusher; |
268 | | std::unique_ptr<SegmentFlusher::Writer> _flush_writer; |
269 | | }; |
270 | | |
271 | | } // namespace doris |