YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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
61
      value_(value) {
60
61
  }
61
62
  const TypeInfo* typeinfo() const;
63
  size_t size() const;
64
  bool is_nullable() const;
65
61
  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()->var_length()) {
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
  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
  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
inline CHECKED_STATUS RelocateIndirectDataToArena(RowType *row, ArenaType *dst_arena) {
253
  const Schema* schema = row->schema();
254
  // For any Slice columns, copy the sliced data into the arena
255
  // and update the pointers
256
  for (size_t i = 0; i < schema->num_columns(); i++) {
257
    typename RowType::Cell cell = row->cell(i);
258
    if (cell.typeinfo()->var_length()) {
259
      if (cell.is_nullable() && cell.is_null()) {
260
        continue;
261
      }
262
263
      Slice *slice = reinterpret_cast<Slice *>(cell.mutable_ptr());
264
      if (!dst_arena->RelocateSlice(*slice, slice)) {
265
        return STATUS(IOError, "Unable to relocate slice");
266
      }
267
    }
268
  }
269
  return Status::OK();
270
}
271
272
class ContiguousRowHelper {
273
 public:
274
142
  static size_t null_bitmap_size(const Schema& schema) {
275
142
    return schema.has_nullables() ? 
BitmapSize(schema.num_columns())138
:
04
;
276
142
  }
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
73
  static size_t row_size(const Schema& schema) {
283
73
    return schema.byte_size() + null_bitmap_size(schema);
284
73
  }
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
69
  static void InitNullsBitmap(const Schema& schema, uint8_t *row_data, size_t bitmap_size) {
291
69
    uint8_t *null_bitmap = row_data + schema.byte_size();
292
220
    for (size_t i = 0; i < bitmap_size; 
++i151
) {
293
151
      null_bitmap[i] = 0x00;
294
151
    }
295
69
  }
296
297
12
  static bool is_null(const Schema& schema, const uint8_t *row_data, size_t col_idx) {
298
12
    DCHECK(schema.column(col_idx).is_nullable());
299
12
    return BitmapTest(row_data + schema.byte_size(), col_idx);
300
12
  }
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
75
  static const uint8_t *cell_ptr(const Schema& schema, const uint8_t *row_data, size_t col_idx) {
308
75
    return row_data + schema.column_offset(col_idx);
309
75
  }
310
311
  static const uint8_t *nullable_cell_ptr(const Schema& schema,
312
                                          const uint8_t *row_data,
313
0
                                          size_t col_idx) {
314
0
    return is_null(schema, row_data, col_idx) ? NULL : cell_ptr(schema, row_data, col_idx);
315
0
  }
316
317
16
  static Slice CellSlice(const Schema& schema, const uint8_t *row_data, size_t col_idx) {
318
16
    const uint8_t* cell_data_ptr = cell_ptr(schema, row_data, col_idx);
319
16
    if (schema.column(col_idx).type_info()->var_length()) {
320
16
      return *(reinterpret_cast<const Slice*>(cell_data_ptr));
321
16
    } else {
322
0
      return Slice(cell_data_ptr, schema.column(col_idx).type_info()->size);
323
0
    }
324
16
  }
325
};
326
327
template<class ContiguousRowType>
328
class ContiguousRowCell {
329
 public:
330
  ContiguousRowCell(const ContiguousRowType* row, size_t idx)
331
39
    : row_(row), col_idx_(idx) {
332
39
  }
Unexecuted instantiation: yb::ContiguousRowCell<yb::ConstContiguousRow>::ContiguousRowCell(yb::ConstContiguousRow const*, unsigned long)
yb::ContiguousRowCell<yb::ContiguousRow>::ContiguousRowCell(yb::ContiguousRow const*, unsigned long)
Line
Count
Source
331
39
    : row_(row), col_idx_(idx) {
332
39
  }
333
334
  const TypeInfo* typeinfo() const { return type_info(); }
335
  size_t size() const { return type_info()->size(); }
336
16
  const void* ptr() const { return row_->cell_ptr(col_idx_); }
Unexecuted instantiation: yb::ContiguousRowCell<yb::ConstContiguousRow>::ptr() const
yb::ContiguousRowCell<yb::ContiguousRow>::ptr() const
Line
Count
Source
336
16
  const void* ptr() const { return row_->cell_ptr(col_idx_); }
337
22
  void* mutable_ptr() const { return row_->mutable_cell_ptr(col_idx_); }
338
  bool is_nullable() const { return row_->schema()->column(col_idx_).is_nullable(); }
339
4
  bool is_null() const { return row_->is_null(col_idx_); }
Unexecuted instantiation: yb::ContiguousRowCell<yb::ConstContiguousRow>::is_null() const
yb::ContiguousRowCell<yb::ContiguousRow>::is_null() const
Line
Count
Source
339
4
  bool is_null() const { return row_->is_null(col_idx_); }
340
  void set_null(bool is_null) const { row_->set_null(col_idx_, is_null); }
341
342
 private:
343
  const TypeInfo* type_info() const {
344
    return row_->schema()->column(col_idx_).type_info();
345
  }
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
133
    : schema_(schema), row_data_(row_data) {
358
133
  }
359
360
0
  const Schema* schema() const {
361
0
    return schema_;
362
0
  }
363
364
0
  void Reset(uint8_t *row_data) {
365
0
    row_data_ = row_data;
366
0
  }
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
48
  const uint8_t *cell_ptr(size_t col_idx) const {
377
48
    return ContiguousRowHelper::cell_ptr(*schema_, row_data_, col_idx);
378
48
  }
379
380
16
  Slice CellSlice(size_t col_idx) const {
381
16
    return ContiguousRowHelper::CellSlice(*schema_, row_data_, col_idx);
382
16
  }
383
384
23
  uint8_t *mutable_cell_ptr(size_t col_idx) const {
385
23
    return const_cast<uint8_t*>(cell_ptr(col_idx));
386
23
  }
387
388
0
  const uint8_t *nullable_cell_ptr(size_t col_idx) const {
389
0
    return ContiguousRowHelper::nullable_cell_ptr(*schema_, row_data_, col_idx);
390
0
  }
391
392
17
  Cell cell(size_t col_idx) const {
393
17
    return Cell(this, col_idx);
394
17
  }
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
76
    : schema_(schema), row_data_(reinterpret_cast<const uint8_t *>(row_data)) {
416
76
  }
417
418
  ConstContiguousRow(const Schema* schema, const Slice& row_slice)
419
0
    : schema_(schema), row_data_(row_slice.data()) {
420
0
  }
421
422
0
  const Schema* schema() const {
423
0
    return schema_;
424
0
  }
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
11
  const uint8_t *cell_ptr(size_t col_idx) const {
439
11
    return ContiguousRowHelper::cell_ptr(*schema_, row_data_, col_idx);
440
11
  }
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
0
  Cell cell(size_t col_idx) const {
451
0
    return Cell(this, col_idx);
452
0
  }
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
} // namespace yb
467
468
#endif // YB_COMMON_ROW_H