/Users/deen/code/yugabyte-db/src/yb/common/row.h
Line | Count | Source (jump to first uncovered line) |
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 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | #ifndef YB_COMMON_ROW_H |
33 | | #define YB_COMMON_ROW_H |
34 | | |
35 | | #include <string> |
36 | | #include <utility> |
37 | | #include <vector> |
38 | | |
39 | | #include "yb/common/common_fwd.h" |
40 | | #include "yb/common/schema.h" |
41 | | #include "yb/common/types.h" |
42 | | |
43 | | #include "yb/gutil/macros.h" |
44 | | |
45 | | #include "yb/util/bitmap.h" |
46 | | #include "yb/util/memory/arena.h" |
47 | | #include "yb/util/status.h" |
48 | | |
49 | | namespace yb { |
50 | | |
51 | | // A simple cell of data which directly corresponds to a pointer value. |
52 | | // stack. |
53 | | struct SimpleConstCell { |
54 | | public: |
55 | | // Both parameters must remain valid for the lifetime of the cell object. |
56 | | SimpleConstCell(const ColumnSchema* col_schema, |
57 | | const void* value) |
58 | | : col_schema_(col_schema), |
59 | 0 | value_(value) { |
60 | 0 | } |
61 | | |
62 | | const TypeInfo* typeinfo() const; |
63 | | size_t size() const; |
64 | | bool is_nullable() const; |
65 | 0 | const void* ptr() const { return value_; } |
66 | 0 | bool is_null() const { return value_ == NULL; } |
67 | | |
68 | | private: |
69 | | const ColumnSchema* col_schema_; |
70 | | const void* value_; |
71 | | }; |
72 | | |
73 | | // Copy the cell data from 'src' to 'dst'. This only copies the data, and not |
74 | | // the null state. Use CopyCell() if you need to copy the null-ness. |
75 | | // |
76 | | // If dst_arena is non-NULL, relocates the data into the given arena. |
77 | | template <class SrcCellType, class DstCellType, class ArenaType> |
78 | | Status CopyCellData(const SrcCellType &src, DstCellType* dst, ArenaType *dst_arena) { |
79 | | DCHECK_EQ(src.typeinfo()->type(), dst->typeinfo()->type()); |
80 | | |
81 | | if (src.typeinfo()->physical_type() == BINARY) { |
82 | | // If it's a Slice column, need to relocate the referred-to data |
83 | | // as well as the slice itself. |
84 | | // TODO: potential optimization here: if the new value is smaller than |
85 | | // the old value, we could potentially just overwrite in some cases. |
86 | | const Slice *src_slice = reinterpret_cast<const Slice *>(src.ptr()); |
87 | | Slice *dst_slice = reinterpret_cast<Slice *>(dst->mutable_ptr()); |
88 | | if (dst_arena != NULL) { |
89 | | if (PREDICT_FALSE(!dst_arena->RelocateSlice(*src_slice, dst_slice))) { |
90 | | return STATUS(IOError, "out of memory copying slice", src_slice->ToString()); |
91 | | } |
92 | | } else { |
93 | | // Just copy the slice without relocating. |
94 | | // This is used by callers who know that the source row's data is going |
95 | | // to stick around for the scope of the destination. |
96 | | *dst_slice = *src_slice; |
97 | | } |
98 | | } else { |
99 | | memcpy(dst->mutable_ptr(), src.ptr(), src.size()); // TODO: inline? |
100 | | } |
101 | | return Status::OK(); |
102 | | } |
103 | | |
104 | | // Copy the cell from 'src' to 'dst'. |
105 | | // |
106 | | // This copies the data, and relocates indirect data into the given arena, |
107 | | // if it is not NULL. |
108 | | template <class SrcCellType, class DstCellType, class ArenaType> |
109 | | Status CopyCell(const SrcCellType &src, DstCellType* dst, ArenaType *dst_arena) { |
110 | | if (src.is_nullable()) { |
111 | | // Copy the null state. |
112 | | dst->set_null(src.is_null()); |
113 | | if (src.is_null()) { |
114 | | // no need to copy any data contents once we marked the destination |
115 | | // cell as null. |
116 | | return Status::OK(); |
117 | | } |
118 | | } |
119 | | |
120 | | return CopyCellData(src, dst, dst_arena); |
121 | | } |
122 | | |
123 | | // Copy all of the cells from one row to another. The two rows must share |
124 | | // the same Schema. If they do not, use ProjectRow() below. |
125 | | // This can be used to translate between columnar and row-wise layout, for example. |
126 | | // |
127 | | // If 'dst_arena' is set, then will relocate any indirect data to that arena |
128 | | // during the copy. |
129 | | template<class RowType1, class RowType2, class ArenaType> |
130 | | inline CHECKED_STATUS CopyRow(const RowType1 &src_row, RowType2 *dst_row, ArenaType *dst_arena) { |
131 | | DCHECK_SCHEMA_EQ(*src_row.schema(), *dst_row->schema()); |
132 | | |
133 | | for (int i = 0; i < src_row.schema()->num_columns(); i++) { |
134 | | typename RowType1::Cell src = src_row.cell(i); |
135 | | typename RowType2::Cell dst = dst_row->cell(i); |
136 | | RETURN_NOT_OK(CopyCell(src, &dst, dst_arena)); |
137 | | } |
138 | | |
139 | | return Status::OK(); |
140 | | } |
141 | | |
142 | | // Projection mapping for the specified schemas. |
143 | | // A projection may contain: |
144 | | // - columns that are present in the "base schema" |
145 | | // - columns that are present in the "base schema" but with different types. |
146 | | // In this case an adapter should be used (e.g. INT8 to INT64, INT8 to STRING, ...) |
147 | | // |
148 | | // Example: |
149 | | // RowProjector projector. |
150 | | // projector.Init(base_schema, projection); |
151 | | // projector.ProjectRow(row_a, &row_b, &row_b_arena); |
152 | | class RowProjector { |
153 | | public: |
154 | | typedef std::pair<size_t, size_t> ProjectionIdxMapping; |
155 | | |
156 | | // Construct a projector. |
157 | | // The two Schema pointers must remain valid for the lifetime of this object. |
158 | | RowProjector(const Schema* base_schema, const Schema* projection); |
159 | | |
160 | | // Initialize the projection mapping with the specified base_schema and projection |
161 | | CHECKED_STATUS Init(); |
162 | | |
163 | | CHECKED_STATUS Reset(const Schema* base_schema, const Schema* projection); |
164 | | |
165 | | // Project a row from one schema into another, using the projection mapping. |
166 | | // Indirected data is copied into the provided dst arena. |
167 | | // |
168 | | // Use this method only on the read-path. |
169 | | template<class RowType1, class RowType2, class ArenaType> |
170 | | CHECKED_STATUS ProjectRowForRead( |
171 | | const RowType1& src_row, RowType2 *dst_row, ArenaType *dst_arena) const { |
172 | | return ProjectRow<RowType1, RowType2, ArenaType, true>(src_row, dst_row, dst_arena); |
173 | | } |
174 | | |
175 | | // Project a row from one schema into another, using the projection mapping. |
176 | | // Indirected data is copied into the provided dst arena. |
177 | | // |
178 | | // Use this method only on the write-path. |
179 | | template<class RowType1, class RowType2, class ArenaType> |
180 | | CHECKED_STATUS ProjectRowForWrite(const RowType1& src_row, RowType2 *dst_row, |
181 | | ArenaType *dst_arena) const { |
182 | | return ProjectRow<RowType1, RowType2, ArenaType, false>(src_row, dst_row, dst_arena); |
183 | | } |
184 | | |
185 | 0 | bool is_identity() const { return is_identity_; } |
186 | 0 | const Schema* projection() const { return projection_; } |
187 | 0 | const Schema* base_schema() const { return base_schema_; } |
188 | | |
189 | | // Returns the mapping between base schema and projection schema columns |
190 | | // first: is the projection column index, second: is the base_schema index |
191 | 10 | const vector<ProjectionIdxMapping>& base_cols_mapping() const { return base_cols_mapping_; } |
192 | | |
193 | | // Returns the mapping between base schema and projection schema columns |
194 | | // that requires a type adapter. |
195 | | // first: is the projection column index, second: is the base_schema index |
196 | 3 | const vector<ProjectionIdxMapping>& adapter_cols_mapping() const { return adapter_cols_mapping_; } |
197 | | |
198 | | private: |
199 | | friend class Schema; |
200 | | |
201 | 6 | CHECKED_STATUS ProjectBaseColumn(size_t proj_col_idx, size_t base_col_idx) { |
202 | 6 | base_cols_mapping_.push_back(ProjectionIdxMapping(proj_col_idx, base_col_idx)); |
203 | 6 | return Status::OK(); |
204 | 6 | } |
205 | | |
206 | 0 | CHECKED_STATUS ProjectAdaptedColumn(size_t proj_col_idx, size_t base_col_idx) { |
207 | 0 | adapter_cols_mapping_.push_back(ProjectionIdxMapping(proj_col_idx, base_col_idx)); |
208 | 0 | return Status::OK(); |
209 | 0 | } |
210 | | |
211 | | CHECKED_STATUS ProjectExtraColumn(size_t proj_col_idx); |
212 | | |
213 | | private: |
214 | | // Project a row from one schema into another, using the projection mapping. |
215 | | // Indirected data is copied into the provided dst arena. |
216 | | template<class RowType1, class RowType2, class ArenaType, bool FOR_READ> |
217 | | CHECKED_STATUS ProjectRow( |
218 | | const RowType1& src_row, RowType2 *dst_row, ArenaType *dst_arena) const { |
219 | | DCHECK_SCHEMA_EQ(*base_schema_, *src_row.schema()); |
220 | | DCHECK_SCHEMA_EQ(*projection_, *dst_row->schema()); |
221 | | |
222 | | // Copy directly from base Data |
223 | | for (const auto& base_mapping : base_cols_mapping_) { |
224 | | typename RowType1::Cell src_cell = src_row.cell(base_mapping.second); |
225 | | typename RowType2::Cell dst_cell = dst_row->cell(base_mapping.first); |
226 | | RETURN_NOT_OK(CopyCell(src_cell, &dst_cell, dst_arena)); |
227 | | } |
228 | | |
229 | | // TODO: Copy Adapted base Data |
230 | | DCHECK(adapter_cols_mapping_.size() == 0) << "Value Adapter not supported yet"; |
231 | | |
232 | | return Status::OK(); |
233 | | } |
234 | | |
235 | | private: |
236 | | vector<ProjectionIdxMapping> base_cols_mapping_; |
237 | | vector<ProjectionIdxMapping> adapter_cols_mapping_; |
238 | | |
239 | | const Schema* base_schema_; |
240 | | const Schema* projection_; |
241 | | bool is_identity_; |
242 | | |
243 | | DISALLOW_COPY_AND_ASSIGN(RowProjector); |
244 | | }; |
245 | | |
246 | | // Copy any indirect (eg STRING) data referenced by the given row into the |
247 | | // provided arena. |
248 | | // |
249 | | // The row itself is mutated so that the indirect data points to the relocated |
250 | | // storage. |
251 | | template <class RowType, class ArenaType> |
252 | 2 | inline CHECKED_STATUS RelocateIndirectDataToArena(RowType *row, ArenaType *dst_arena) { |
253 | 2 | const Schema* schema = row->schema(); |
254 | | // For any Slice columns, copy the sliced data into the arena |
255 | | // and update the pointers |
256 | 10 | for (size_t i = 0; i < schema->num_columns(); i++) { |
257 | 8 | typename RowType::Cell cell = row->cell(i); |
258 | 8 | if (cell.typeinfo()->physical_type() == BINARY) { |
259 | 4 | if (cell.is_nullable() && cell.is_null()) { |
260 | 0 | continue; |
261 | 0 | } |
262 | | |
263 | 4 | Slice *slice = reinterpret_cast<Slice *>(cell.mutable_ptr()); |
264 | 4 | if (!dst_arena->RelocateSlice(*slice, slice)) { |
265 | 0 | return STATUS(IOError, "Unable to relocate slice"); |
266 | 0 | } |
267 | 4 | } |
268 | 8 | } |
269 | 2 | return Status::OK(); |
270 | 2 | } |
271 | | |
272 | | class ContiguousRowHelper { |
273 | | public: |
274 | 29 | static size_t null_bitmap_size(const Schema& schema) { |
275 | 24 | return schema.has_nullables() ? BitmapSize(schema.num_columns()) : 0; |
276 | 29 | } |
277 | | |
278 | 0 | static uint8_t* null_bitmap_ptr(const Schema& schema, uint8_t* row_data) { |
279 | 0 | return row_data + schema.byte_size(); |
280 | 0 | } |
281 | | |
282 | 16 | static size_t row_size(const Schema& schema) { |
283 | 16 | return schema.byte_size() + null_bitmap_size(schema); |
284 | 16 | } |
285 | | |
286 | 0 | static void InitNullsBitmap(const Schema& schema, Slice row_data) { |
287 | 0 | InitNullsBitmap(schema, row_data.mutable_data(), row_data.size() - schema.byte_size()); |
288 | 0 | } |
289 | | |
290 | 14 | static void InitNullsBitmap(const Schema& schema, uint8_t *row_data, size_t bitmap_size) { |
291 | 14 | uint8_t *null_bitmap = row_data + schema.byte_size(); |
292 | 24 | for (size_t i = 0; i < bitmap_size; ++i) { |
293 | 10 | null_bitmap[i] = 0x00; |
294 | 10 | } |
295 | 14 | } |
296 | | |
297 | 17 | static bool is_null(const Schema& schema, const uint8_t *row_data, size_t col_idx) { |
298 | 17 | DCHECK(schema.column(col_idx).is_nullable()); |
299 | 17 | return BitmapTest(row_data + schema.byte_size(), col_idx); |
300 | 17 | } |
301 | | |
302 | 8 | static void SetCellIsNull(const Schema& schema, uint8_t *row_data, size_t col_idx, bool is_null) { |
303 | 8 | uint8_t *null_bitmap = row_data + schema.byte_size(); |
304 | 8 | BitmapChange(null_bitmap, col_idx, is_null); |
305 | 8 | } |
306 | | |
307 | 145 | static const uint8_t *cell_ptr(const Schema& schema, const uint8_t *row_data, size_t col_idx) { |
308 | 145 | return row_data + schema.column_offset(col_idx); |
309 | 145 | } |
310 | | |
311 | | static const uint8_t *nullable_cell_ptr(const Schema& schema, |
312 | | const uint8_t *row_data, |
313 | 5 | size_t col_idx) { |
314 | 5 | return is_null(schema, row_data, col_idx) ? NULL : cell_ptr(schema, row_data, col_idx); |
315 | 5 | } |
316 | | |
317 | 0 | static Slice CellSlice(const Schema& schema, const uint8_t *row_data, size_t col_idx) { |
318 | 0 | const uint8_t* cell_data_ptr = cell_ptr(schema, row_data, col_idx); |
319 | 0 | if (schema.column(col_idx).type_info()->physical_type() == BINARY) { |
320 | 0 | return *(reinterpret_cast<const Slice*>(cell_data_ptr)); |
321 | 0 | } else { |
322 | 0 | return Slice(cell_data_ptr, schema.column(col_idx).type_info()->size()); |
323 | 0 | } |
324 | 0 | } |
325 | | }; |
326 | | |
327 | | template<class ContiguousRowType> |
328 | | class ContiguousRowCell { |
329 | | public: |
330 | | ContiguousRowCell(const ContiguousRowType* row, size_t idx) |
331 | 85 | : row_(row), col_idx_(idx) { |
332 | 85 | } _ZN2yb17ContiguousRowCellINS_13ContiguousRowEEC2EPKS1_m Line | Count | Source | 331 | 79 | : row_(row), col_idx_(idx) { | 332 | 79 | } |
_ZN2yb17ContiguousRowCellINS_18ConstContiguousRowEEC2EPKS1_m Line | Count | Source | 331 | 6 | : row_(row), col_idx_(idx) { | 332 | 6 | } |
|
333 | | |
334 | 8 | const TypeInfo* typeinfo() const { return type_info(); } |
335 | | size_t size() const { return type_info()->size(); } |
336 | 42 | const void* ptr() const { return row_->cell_ptr(col_idx_); } _ZNK2yb17ContiguousRowCellINS_13ContiguousRowEE3ptrEv Line | Count | Source | 336 | 36 | const void* ptr() const { return row_->cell_ptr(col_idx_); } |
_ZNK2yb17ContiguousRowCellINS_18ConstContiguousRowEE3ptrEv Line | Count | Source | 336 | 6 | const void* ptr() const { return row_->cell_ptr(col_idx_); } |
|
337 | 38 | void* mutable_ptr() const { return row_->mutable_cell_ptr(col_idx_); } |
338 | 4 | bool is_nullable() const { return row_->schema()->column(col_idx_).is_nullable(); } |
339 | 4 | bool is_null() const { return row_->is_null(col_idx_); } _ZNK2yb17ContiguousRowCellINS_13ContiguousRowEE7is_nullEv Line | Count | Source | 339 | 4 | bool is_null() const { return row_->is_null(col_idx_); } |
Unexecuted instantiation: _ZNK2yb17ContiguousRowCellINS_18ConstContiguousRowEE7is_nullEv |
340 | | void set_null(bool is_null) const { row_->set_null(col_idx_, is_null); } |
341 | | |
342 | | private: |
343 | 8 | const TypeInfo* type_info() const { |
344 | 8 | return row_->schema()->column(col_idx_).type_info(); |
345 | 8 | } |
346 | | |
347 | | const ContiguousRowType* row_; |
348 | | size_t col_idx_; |
349 | | }; |
350 | | |
351 | | // The row has all columns layed out in memory based on the schema.column_offset() |
352 | | class ContiguousRow { |
353 | | public: |
354 | | typedef ContiguousRowCell<ContiguousRow> Cell; |
355 | | |
356 | | explicit ContiguousRow(const Schema* schema, uint8_t *row_data = NULL) |
357 | 106 | : schema_(schema), row_data_(row_data) { |
358 | 106 | } |
359 | | |
360 | 56 | const Schema* schema() const { |
361 | 56 | return schema_; |
362 | 56 | } |
363 | | |
364 | 2 | void Reset(uint8_t *row_data) { |
365 | 2 | row_data_ = row_data; |
366 | 2 | } |
367 | | |
368 | 12 | bool is_null(size_t col_idx) const { |
369 | 12 | return ContiguousRowHelper::is_null(*schema_, row_data_, col_idx); |
370 | 12 | } |
371 | | |
372 | 8 | void set_null(size_t col_idx, bool is_null) const { |
373 | 8 | ContiguousRowHelper::SetCellIsNull(*schema_, row_data_, col_idx, is_null); |
374 | 8 | } |
375 | | |
376 | 123 | const uint8_t *cell_ptr(size_t col_idx) const { |
377 | 123 | return ContiguousRowHelper::cell_ptr(*schema_, row_data_, col_idx); |
378 | 123 | } |
379 | | |
380 | 0 | Slice CellSlice(size_t col_idx) const { |
381 | 0 | return ContiguousRowHelper::CellSlice(*schema_, row_data_, col_idx); |
382 | 0 | } |
383 | | |
384 | 62 | uint8_t *mutable_cell_ptr(size_t col_idx) const { |
385 | 62 | return const_cast<uint8_t*>(cell_ptr(col_idx)); |
386 | 62 | } |
387 | | |
388 | 5 | const uint8_t *nullable_cell_ptr(size_t col_idx) const { |
389 | 5 | return ContiguousRowHelper::nullable_cell_ptr(*schema_, row_data_, col_idx); |
390 | 5 | } |
391 | | |
392 | 45 | Cell cell(size_t col_idx) const { |
393 | 45 | return Cell(this, col_idx); |
394 | 45 | } |
395 | | |
396 | | private: |
397 | | friend class ConstContiguousRow; |
398 | | |
399 | | const Schema* schema_; |
400 | | uint8_t *row_data_; |
401 | | }; |
402 | | |
403 | | // This is the same as ContiguousRow except it refers to a const area of memory that |
404 | | // should not be mutated. |
405 | | class ConstContiguousRow { |
406 | | public: |
407 | | typedef ContiguousRowCell<ConstContiguousRow> Cell; |
408 | | |
409 | | explicit ConstContiguousRow(const ContiguousRow &row) |
410 | | : schema_(row.schema_), |
411 | 0 | row_data_(row.row_data_) { |
412 | 0 | } |
413 | | |
414 | | ConstContiguousRow(const Schema* schema, const void *row_data) |
415 | 18 | : schema_(schema), row_data_(reinterpret_cast<const uint8_t *>(row_data)) { |
416 | 18 | } |
417 | | |
418 | | ConstContiguousRow(const Schema* schema, const Slice& row_slice) |
419 | 0 | : schema_(schema), row_data_(row_slice.data()) { |
420 | 0 | } |
421 | | |
422 | 3 | const Schema* schema() const { |
423 | 3 | return schema_; |
424 | 3 | } |
425 | | |
426 | 0 | const uint8_t *row_data() const { |
427 | 0 | return row_data_; |
428 | 0 | } |
429 | | |
430 | 0 | size_t row_size() const { |
431 | 0 | return ContiguousRowHelper::row_size(*schema_); |
432 | 0 | } |
433 | | |
434 | 0 | bool is_null(size_t col_idx) const { |
435 | 0 | return ContiguousRowHelper::is_null(*schema_, row_data_, col_idx); |
436 | 0 | } |
437 | | |
438 | 17 | const uint8_t *cell_ptr(size_t col_idx) const { |
439 | 17 | return ContiguousRowHelper::cell_ptr(*schema_, row_data_, col_idx); |
440 | 17 | } |
441 | | |
442 | 0 | Slice CellSlice(size_t col_idx) const { |
443 | 0 | return ContiguousRowHelper::CellSlice(*schema_, row_data_, col_idx); |
444 | 0 | } |
445 | | |
446 | 0 | const uint8_t *nullable_cell_ptr(size_t col_idx) const { |
447 | 0 | return ContiguousRowHelper::nullable_cell_ptr(*schema_, row_data_, col_idx); |
448 | 0 | } |
449 | | |
450 | 6 | Cell cell(size_t col_idx) const { |
451 | 6 | return Cell(this, col_idx); |
452 | 6 | } |
453 | | |
454 | | private: |
455 | | const Schema* schema_; |
456 | | const uint8_t *row_data_; |
457 | | }; |
458 | | |
459 | | // Delete functions from ContiguousRowCell that can mutate the cell by |
460 | | // specializing for ConstContiguousRow. |
461 | | template<> |
462 | | void* ContiguousRowCell<ConstContiguousRow>::mutable_ptr() const; |
463 | | template<> |
464 | | void ContiguousRowCell<ConstContiguousRow>::set_null(bool null) const; |
465 | | |
466 | | |
467 | | // Utility class for building rows corresponding to a given schema. |
468 | | // This is used only by tests. |
469 | | // TODO: move it into a test utility. |
470 | | class RowBuilder { |
471 | | public: |
472 | | explicit RowBuilder(const Schema& schema) |
473 | | : schema_(schema), |
474 | | arena_(1024, 1024*1024), |
475 | 1 | bitmap_size_(ContiguousRowHelper::null_bitmap_size(schema)) { |
476 | 1 | Reset(); |
477 | 1 | } |
478 | | |
479 | | // Reset the RowBuilder so that it is ready to build |
480 | | // the next row. |
481 | | // NOTE: The previous row's data is invalidated. Even |
482 | | // if the previous row's data has been copied, indirected |
483 | | // entries such as strings may end up shared or deallocated |
484 | | // after Reset. So, the previous row must be fully copied |
485 | | // (eg using CopyRowToArena()). |
486 | 2 | void Reset() { |
487 | 2 | arena_.Reset(); |
488 | 2 | size_t row_size = schema_.byte_size() + bitmap_size_; |
489 | 2 | buf_ = reinterpret_cast<uint8_t *>(arena_.AllocateBytes(row_size)); |
490 | 0 | CHECK(buf_) << "could not allocate " << row_size << " bytes for row builder"; |
491 | 2 | col_idx_ = 0; |
492 | 2 | byte_idx_ = 0; |
493 | 2 | ContiguousRowHelper::InitNullsBitmap(schema_, buf_, bitmap_size_); |
494 | 2 | } |
495 | | |
496 | 0 | void AddString(const Slice &slice) { |
497 | 0 | CheckNextType(STRING); |
498 | 0 | AddSlice(slice); |
499 | 0 | } |
500 | | |
501 | 4 | void AddString(const string &str) { |
502 | 4 | CheckNextType(STRING); |
503 | 4 | AddSlice(str); |
504 | 4 | } |
505 | | |
506 | 0 | void AddBinary(const Slice &slice) { |
507 | 0 | CheckNextType(BINARY); |
508 | 0 | AddSlice(slice); |
509 | 0 | } |
510 | | |
511 | 0 | void AddBinary(const string &str) { |
512 | 0 | CheckNextType(BINARY); |
513 | 0 | AddSlice(str); |
514 | 0 | } |
515 | | |
516 | 0 | void AddInt8(int8_t val) { |
517 | 0 | CheckNextType(INT8); |
518 | 0 | *reinterpret_cast<int8_t *>(&buf_[byte_idx_]) = val; |
519 | 0 | Advance(); |
520 | 0 | } |
521 | | |
522 | 0 | void AddUint8(uint8_t val) { |
523 | 0 | CheckNextType(UINT8); |
524 | 0 | *reinterpret_cast<uint8_t *>(&buf_[byte_idx_]) = val; |
525 | 0 | Advance(); |
526 | 0 | } |
527 | | |
528 | 0 | void AddInt16(int16_t val) { |
529 | 0 | CheckNextType(INT16); |
530 | 0 | *reinterpret_cast<int16_t *>(&buf_[byte_idx_]) = val; |
531 | 0 | Advance(); |
532 | 0 | } |
533 | | |
534 | 0 | void AddUint16(uint16_t val) { |
535 | 0 | CheckNextType(UINT16); |
536 | 0 | *reinterpret_cast<uint16_t *>(&buf_[byte_idx_]) = val; |
537 | 0 | Advance(); |
538 | 0 | } |
539 | | |
540 | 2 | void AddInt32(int32_t val) { |
541 | 2 | CheckNextType(INT32); |
542 | 2 | *reinterpret_cast<int32_t *>(&buf_[byte_idx_]) = val; |
543 | 2 | Advance(); |
544 | 2 | } |
545 | | |
546 | 2 | void AddUint32(uint32_t val) { |
547 | 2 | CheckNextType(UINT32); |
548 | 2 | *reinterpret_cast<uint32_t *>(&buf_[byte_idx_]) = val; |
549 | 2 | Advance(); |
550 | 2 | } |
551 | | |
552 | 0 | void AddInt64(int64_t val) { |
553 | 0 | CheckNextType(INT64); |
554 | 0 | *reinterpret_cast<int64_t *>(&buf_[byte_idx_]) = val; |
555 | 0 | Advance(); |
556 | 0 | } |
557 | | |
558 | 0 | void AddTimestamp(int64_t micros_utc_since_epoch) { |
559 | 0 | CheckNextType(TIMESTAMP); |
560 | 0 | *reinterpret_cast<int64_t *>(&buf_[byte_idx_]) = micros_utc_since_epoch; |
561 | 0 | Advance(); |
562 | 0 | } |
563 | | |
564 | 0 | void AddUint64(uint64_t val) { |
565 | 0 | CheckNextType(UINT64); |
566 | 0 | *reinterpret_cast<uint64_t *>(&buf_[byte_idx_]) = val; |
567 | 0 | Advance(); |
568 | 0 | } |
569 | | |
570 | 0 | void AddFloat(float val) { |
571 | 0 | CheckNextType(FLOAT); |
572 | 0 | *reinterpret_cast<float *>(&buf_[byte_idx_]) = val; |
573 | 0 | Advance(); |
574 | 0 | } |
575 | | |
576 | 0 | void AddDouble(double val) { |
577 | 0 | CheckNextType(DOUBLE); |
578 | 0 | *reinterpret_cast<double *>(&buf_[byte_idx_]) = val; |
579 | 0 | Advance(); |
580 | 0 | } |
581 | | |
582 | 0 | void AddNull() { |
583 | 0 | CHECK(schema_.column(col_idx_).is_nullable()); |
584 | 0 | BitmapSet(buf_ + schema_.byte_size(), col_idx_); |
585 | 0 | Advance(); |
586 | 0 | } |
587 | | |
588 | | // Retrieve the data slice from the current row. |
589 | | // The Add*() functions must have been called an appropriate |
590 | | // number of times such that all columns are filled in, or else |
591 | | // a crash will occur. |
592 | | // |
593 | | // The data slice returned by this is only valid until the next |
594 | | // call to Reset(). |
595 | | // Note that the Slice may also contain pointers which refer to |
596 | | // other parts of the internal Arena, so even if the returned |
597 | | // data is copied, it is not safe to Reset() before also calling |
598 | | // CopyRowIndirectDataToArena. |
599 | 2 | const Slice data() const { |
600 | 2 | CHECK_EQ(byte_idx_, schema_.byte_size()); |
601 | 2 | return Slice(buf_, byte_idx_ + bitmap_size_); |
602 | 2 | } |
603 | | |
604 | 0 | const Schema& schema() const { |
605 | 0 | return schema_; |
606 | 0 | } |
607 | | |
608 | 0 | ConstContiguousRow row() const { |
609 | 0 | return ConstContiguousRow(&schema_, data()); |
610 | 0 | } |
611 | | |
612 | | private: |
613 | 0 | void AddSlice(const Slice &slice) { |
614 | 0 | Slice *ptr = reinterpret_cast<Slice *>(buf_ + byte_idx_); |
615 | 0 | CHECK(arena_.RelocateSlice(slice, ptr)) << "could not allocate space in arena"; |
616 | 0 |
|
617 | 0 | Advance(); |
618 | 0 | } |
619 | | |
620 | 4 | void AddSlice(const string &str) { |
621 | 4 | uint8_t *in_arena = arena_.AddSlice(str); |
622 | 0 | CHECK(in_arena) << "could not allocate space in arena"; |
623 | | |
624 | 4 | Slice *ptr = reinterpret_cast<Slice *>(buf_ + byte_idx_); |
625 | 4 | *ptr = Slice(in_arena, str.size()); |
626 | | |
627 | 4 | Advance(); |
628 | 4 | } |
629 | | |
630 | 8 | void CheckNextType(DataType type) { |
631 | 8 | CHECK_EQ(schema_.column(col_idx_).type_info()->type(), |
632 | 8 | type); |
633 | 8 | } |
634 | | |
635 | 8 | void Advance() { |
636 | 8 | auto size = schema_.column(col_idx_).type_info()->size(); |
637 | 8 | byte_idx_ += size; |
638 | 8 | col_idx_++; |
639 | 8 | } |
640 | | |
641 | | const Schema schema_; |
642 | | Arena arena_; |
643 | | uint8_t *buf_; |
644 | | |
645 | | size_t col_idx_; |
646 | | size_t byte_idx_; |
647 | | size_t bitmap_size_; |
648 | | |
649 | | DISALLOW_COPY_AND_ASSIGN(RowBuilder); |
650 | | }; |
651 | | |
652 | | } // namespace yb |
653 | | |
654 | | #endif // YB_COMMON_ROW_H |