• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SRC_TRACE_PROCESSOR_DB_COLUMN_H_
18 #define SRC_TRACE_PROCESSOR_DB_COLUMN_H_
19 
20 #include <stdint.h>
21 #include <optional>
22 
23 #include "perfetto/base/logging.h"
24 #include "perfetto/trace_processor/basic_types.h"
25 #include "src/trace_processor/containers/row_map.h"
26 #include "src/trace_processor/containers/string_pool.h"
27 #include "src/trace_processor/db/column/types.h"
28 #include "src/trace_processor/db/column_storage.h"
29 #include "src/trace_processor/db/column_storage_overlay.h"
30 #include "src/trace_processor/db/compare.h"
31 #include "src/trace_processor/db/typed_column_internal.h"
32 
33 namespace perfetto::trace_processor {
34 
35 // Helper class for converting a type to a ColumnType.
36 template <typename T>
37 struct ColumnTypeHelper;
38 template <>
39 struct ColumnTypeHelper<int32_t> {
40   static constexpr ColumnType ToColumnType() { return ColumnType::kInt32; }
41 };
42 template <>
43 struct ColumnTypeHelper<uint32_t> {
44   static constexpr ColumnType ToColumnType() { return ColumnType::kUint32; }
45 };
46 template <>
47 struct ColumnTypeHelper<int64_t> {
48   static constexpr ColumnType ToColumnType() { return ColumnType::kInt64; }
49 };
50 template <>
51 struct ColumnTypeHelper<double> {
52   static constexpr ColumnType ToColumnType() { return ColumnType::kDouble; }
53 };
54 template <>
55 struct ColumnTypeHelper<StringPool::Id> {
56   static constexpr ColumnType ToColumnType() { return ColumnType::kString; }
57 };
58 template <typename T>
59 struct ColumnTypeHelper<std::optional<T>> : public ColumnTypeHelper<T> {};
60 
61 class Table;
62 
63 // Represents a named, strongly typed list of data.
64 class ColumnLegacy {
65  public:
66   // Flags which indicate properties of the data in the column. These features
67   // are used to speed up column methods like filtering/sorting.
68   enum Flag : uint32_t {
69     // Indicates that this column has no special properties.
70     kNoFlag = 0,
71 
72     // Indicates the data in the column is sorted. This can be used to speed
73     // up filtering and skip sorting.
74     kSorted = 1 << 0,
75 
76     // Indicates the data in the column is non-null. That is, the NullableVector
77     // passed in will never have any null entries. This is only used for
78     // numeric columns (string columns and id columns both have special
79     // handling which ignores this flag).
80     //
81     // This is used to speed up filters as we can safely index NullableVector
82     // directly if this flag is set.
83     kNonNull = 1 << 1,
84 
85     // Indicates that the data in the column is "hidden". This can by used to
86     // hint to users of Table and Column that this column should not be
87     // displayed to the user as it is part of the internal implementation
88     // details of the table.
89     kHidden = 1 << 2,
90 
91     // Indicates that the data in this column is stored densely. This
92     // allows for fast Set calls to change the data in the column.
93     //
94     // This flag is only meaningful for nullable columns has no effect for
95     // non-null columns.
96     kDense = 1 << 3,
97 
98     // Indicates that the sorted numeric data in the column is laid out such
99     // that at row i, we will always have col[i] <= i and the first element, j
100     // of each group happens at the index j.
101     //
102     // This is a common pattern in trace processor and columns with this
103     // property are suffixed with "set_id" hence the name of this flag.
104     //
105     // To make this clear, here are some valid and invalid uses of this flag.
106     //
107     // Valid:
108     // []
109     // [0]
110     // [0, 1, 2]
111     // [0, 0, 2]
112     // [0, 0, 0, 3, 3, 5, 6, 6, 7]
113     //
114     // Invalid:
115     // [1]
116     // [0, 0, 1]
117     // [0, 0, 2, 5]
118     // [0, 0, 2, 1]
119     //
120     // If this flag is set, kSorted and kNonNull should be set. Moreover, this
121     // flag can only be set when the type is ColumnType::kUint32; other types
122     // are not supported.
123     kSetId = 1 << 4,
124   };
125 
126   // Iterator over a column which conforms to std iterator interface
127   // to allow using std algorithms (e.g. upper_bound, lower_bound etc.).
128   class Iterator {
129    public:
130     using iterator_category = std::random_access_iterator_tag;
131     using value_type = SqlValue;
132     using difference_type = uint32_t;
133     using pointer = uint32_t*;
134     using reference = uint32_t&;
135 
136     Iterator(const ColumnLegacy* col, uint32_t row) : col_(col), row_(row) {}
137 
138     Iterator(const Iterator&) = default;
139     Iterator& operator=(const Iterator&) = default;
140 
141     bool operator==(const Iterator& other) const { return other.row_ == row_; }
142     bool operator!=(const Iterator& other) const { return !(*this == other); }
143     bool operator<(const Iterator& other) const { return row_ < other.row_; }
144     bool operator>(const Iterator& other) const { return other < *this; }
145     bool operator<=(const Iterator& other) const { return !(other < *this); }
146     bool operator>=(const Iterator& other) const { return !(*this < other); }
147 
148     SqlValue operator*() const { return col_->Get(row_); }
149     Iterator& operator++() {
150       row_++;
151       return *this;
152     }
153     Iterator& operator--() {
154       row_--;
155       return *this;
156     }
157 
158     Iterator& operator+=(uint32_t diff) {
159       row_ += diff;
160       return *this;
161     }
162     uint32_t operator-(const Iterator& other) const {
163       return row_ - other.row_;
164     }
165 
166     uint32_t row() const { return row_; }
167 
168    private:
169     const ColumnLegacy* col_ = nullptr;
170     uint32_t row_ = 0;
171   };
172 
173   // Flags specified for an id column.
174   static constexpr uint32_t kIdFlags = Flag::kSorted | Flag::kNonNull;
175 
176   // Flags which should *not* be inherited implicitly when a column is
177   // assocaited to another table.
178   static constexpr uint32_t kNoCrossTableInheritFlags =
179       ColumnLegacy::Flag::kSetId;
180 
181   template <typename T>
182   ColumnLegacy(const char* name,
183                ColumnStorage<T>* storage,
184                /* Flag */ uint32_t flags,
185                uint32_t col_idx_in_table,
186                uint32_t row_map_idx)
187       : ColumnLegacy(name,
188                      ColumnTypeHelper<stored_type<T>>::ToColumnType(),
189                      flags,
190                      col_idx_in_table,
191                      row_map_idx,
192                      storage) {}
193 
194   // Create a Column backed by the same data as |column| but is associated to a
195   // different table and, optionally, having a different name.
196   ColumnLegacy(const ColumnLegacy& column,
197                uint32_t col_idx_in_table,
198                uint32_t row_map_idx,
199                const char* name = nullptr);
200 
201   // Columns are movable but not copyable.
202   ColumnLegacy(ColumnLegacy&&) noexcept = default;
203   ColumnLegacy& operator=(ColumnLegacy&&) = default;
204 
205   // Creates a Column which does not have any data backing it.
206   static ColumnLegacy DummyColumn(const char* name, uint32_t col_idx_in_table);
207 
208   // Creates a Column which returns the index as the value of the row.
209   static ColumnLegacy IdColumn(uint32_t col_idx_in_table,
210                                uint32_t overlay_idx,
211                                const char* name = "id",
212                                uint32_t flags = kIdFlags);
213 
214   // Gets the value of the Column at the given |row|.
215   SqlValue Get(uint32_t row) const { return GetAtIdx(overlay().Get(row)); }
216 
217   // Returns the row containing the given value in the Column.
218   std::optional<uint32_t> IndexOf(SqlValue value) const {
219     switch (type_) {
220       // TODO(lalitm): investigate whether we could make this more efficient
221       // by first checking the type of the column and comparing explicitly
222       // based on that type.
223       case ColumnType::kInt32:
224       case ColumnType::kUint32:
225       case ColumnType::kInt64:
226       case ColumnType::kDouble:
227       case ColumnType::kString: {
228         for (uint32_t i = 0; i < overlay().size(); i++) {
229           if (compare::SqlValue(Get(i), value) == 0)
230             return i;
231         }
232         return std::nullopt;
233       }
234       case ColumnType::kId: {
235         if (value.type != SqlValue::Type::kLong)
236           return std::nullopt;
237         return overlay().RowOf(static_cast<uint32_t>(value.long_value));
238       }
239       case ColumnType::kDummy:
240         PERFETTO_FATAL("IndexOf not allowed on dummy column");
241     }
242     PERFETTO_FATAL("For GCC");
243   }
244 
245   // Returns the minimum value in this column. Returns std::nullopt if this
246   // column is empty.
247   std::optional<SqlValue> Min() const {
248     if (overlay().empty())
249       return std::nullopt;
250 
251     if (IsSorted())
252       return Get(0);
253 
254     Iterator b(this, 0);
255     Iterator e(this, overlay().size());
256     return *std::min_element(b, e, &compare::SqlValueComparator);
257   }
258 
259   // Returns the minimum value in this column. Returns std::nullopt if this
260   // column is empty.
261   std::optional<SqlValue> Max() const {
262     if (overlay().empty())
263       return std::nullopt;
264 
265     if (IsSorted())
266       return Get(overlay().size() - 1);
267 
268     Iterator b(this, 0);
269     Iterator e(this, overlay().size());
270     return *std::max_element(b, e, &compare::SqlValueComparator);
271   }
272 
273   // Returns the backing RowMap for this Column.
274   // This function is defined out of line because of a circular dependency
275   // between |Table| and |Column|.
276   const ColumnStorageOverlay& overlay() const;
277 
278   // Returns the name of the column.
279   const char* name() const { return name_; }
280 
281   // Returns the type of this Column in terms of SqlValue::Type.
282   SqlValue::Type type() const { return ToSqlValueType(type_); }
283 
284   // Returns the type of this Column in terms of ColumnType.
285   ColumnType col_type() const { return type_; }
286 
287   // Test the type of this Column.
288   template <typename T>
289   bool IsColumnType() const {
290     return ColumnTypeHelper<T>::ToColumnType() == type_;
291   }
292 
293   // Returns true if this column is considered an id column.
294   bool IsId() const { return type_ == ColumnType::kId; }
295 
296   // Returns true if this column is a nullable column.
297   bool IsNullable() const { return IsNullable(flags_); }
298 
299   // Returns true if this column is a sorted column.
300   bool IsSorted() const { return IsSorted(flags_); }
301 
302   // Returns true if this column is a dense column.
303   bool IsDense() const { return IsDense(flags_); }
304 
305   // Returns true if this column is a set id column.
306   // Public for testing.
307   bool IsSetId() const { return IsSetId(flags_); }
308 
309   // Returns true if this column is a dummy column.
310   // Public for testing.
311   bool IsDummy() const { return type_ == ColumnType::kDummy; }
312 
313   // Returns true if this column is a hidden column.
314   bool IsHidden() const { return (flags_ & Flag::kHidden) != 0; }
315 
316   // Returns the index of the RowMap in the containing table.
317   uint32_t overlay_index() const { return overlay_index_; }
318 
319   // Returns the index of the current column in the containing table.
320   uint32_t index_in_table() const { return index_in_table_; }
321 
322   // Returns a Constraint for each type of filter operation for this Column.
323   Constraint eq_value(SqlValue value) const {
324     return Constraint{index_in_table_, FilterOp::kEq, value};
325   }
326   Constraint gt_value(SqlValue value) const {
327     return Constraint{index_in_table_, FilterOp::kGt, value};
328   }
329   Constraint lt_value(SqlValue value) const {
330     return Constraint{index_in_table_, FilterOp::kLt, value};
331   }
332   Constraint ne_value(SqlValue value) const {
333     return Constraint{index_in_table_, FilterOp::kNe, value};
334   }
335   Constraint ge_value(SqlValue value) const {
336     return Constraint{index_in_table_, FilterOp::kGe, value};
337   }
338   Constraint le_value(SqlValue value) const {
339     return Constraint{index_in_table_, FilterOp::kLe, value};
340   }
341   Constraint is_not_null() const {
342     return Constraint{index_in_table_, FilterOp::kIsNotNull, SqlValue()};
343   }
344   Constraint is_null() const {
345     return Constraint{index_in_table_, FilterOp::kIsNull, SqlValue()};
346   }
347   Constraint glob_value(SqlValue value) const {
348     return Constraint{index_in_table_, FilterOp::kGlob, value};
349   }
350 
351   Constraint regex_value(SqlValue value) const {
352     return Constraint{index_in_table_, FilterOp::kRegex, value};
353   }
354 
355   // Returns an Order for each Order type for this Column.
356   Order ascending() const { return Order{index_in_table_, false}; }
357   Order descending() const { return Order{index_in_table_, true}; }
358 
359   // Returns an iterator to the first entry in this column.
360   Iterator begin() const { return Iterator(this, 0); }
361 
362   // Returns an iterator pointing beyond the last entry in this column.
363   Iterator end() const { return Iterator(this, overlay().size()); }
364 
365   // Returns whether the given combination of flags when the column has the
366   // given type is valid.
367   template <typename T>
368   static constexpr bool IsFlagsAndTypeValid(uint32_t flags) {
369     return IsFlagsAndTypeValid(flags, ColumnTypeHelper<T>::ToColumnType());
370   }
371 
372   template <typename T>
373   using stored_type = typename tc_internal::TypeHandler<T>::stored_type;
374 
375   // Returns the backing sparse vector cast to contain data of type T.
376   // Should only be called when |type_| == ToColumnType<T>().
377   template <typename T>
378   const ColumnStorage<stored_type<T>>& storage() const {
379     PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_);
380     PERFETTO_DCHECK(tc_internal::TypeHandler<T>::is_optional == IsNullable());
381     return *static_cast<ColumnStorage<stored_type<T>>*>(storage_);
382   }
383 
384   const ColumnStorageBase& storage_base() const { return *storage_; }
385 
386  protected:
387   // Returns the backing sparse vector cast to contain data of type T.
388   // Should only be called when |type_| == ToColumnType<T>().
389   template <typename T>
390   ColumnStorage<stored_type<T>>* mutable_storage() {
391     PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_);
392     PERFETTO_DCHECK(tc_internal::TypeHandler<T>::is_optional == IsNullable());
393     return static_cast<ColumnStorage<stored_type<T>>*>(storage_);
394   }
395 
396   const StringPool& string_pool() const { return *string_pool_; }
397 
398   // Returns the type of this Column in terms of SqlValue::Type.
399   template <typename T>
400   static SqlValue::Type ToSqlValueType() {
401     return ToSqlValueType(ColumnTypeHelper<T>::ToColumnType());
402   }
403 
404   static SqlValue ToSqlValue(double value) { return SqlValue::Double(value); }
405   static SqlValue ToSqlValue(int32_t value) { return SqlValue::Long(value); }
406   static SqlValue ToSqlValue(uint32_t value) { return SqlValue::Long(value); }
407   static SqlValue ToSqlValue(int64_t value) { return SqlValue::Long(value); }
408   static SqlValue ToSqlValue(NullTermStringView value) {
409     return SqlValue::String(value.c_str());
410   }
411 
412  private:
413   friend class Table;
414   friend class View;
415 
416   // Base constructor for this class which all other constructors call into.
417   ColumnLegacy(const char* name,
418                ColumnType type,
419                uint32_t flags,
420                uint32_t col_idx_in_table,
421                uint32_t overlay_index,
422                ColumnStorageBase* nullable_vector);
423 
424   ColumnLegacy(const ColumnLegacy&) = delete;
425   ColumnLegacy& operator=(const ColumnLegacy&) = delete;
426 
427   // Gets the value of the Column at the given |idx|.
428   SqlValue GetAtIdx(uint32_t idx) const {
429     switch (type_) {
430       case ColumnType::kInt32:
431         return GetAtIdxTyped<int32_t>(idx);
432       case ColumnType::kUint32:
433         return GetAtIdxTyped<uint32_t>(idx);
434       case ColumnType::kInt64:
435         return GetAtIdxTyped<int64_t>(idx);
436       case ColumnType::kDouble:
437         return GetAtIdxTyped<double>(idx);
438       case ColumnType::kString: {
439         auto str = GetStringPoolStringAtIdx(idx).c_str();
440         return str == nullptr ? SqlValue() : SqlValue::String(str);
441       }
442       case ColumnType::kId:
443         return SqlValue::Long(idx);
444       case ColumnType::kDummy:
445         PERFETTO_FATAL("GetAtIdx not allowed on dummy column");
446     }
447     PERFETTO_FATAL("For GCC");
448   }
449 
450   template <typename T>
451   SqlValue GetAtIdxTyped(uint32_t idx) const {
452     if (IsNullable()) {
453       auto opt_value = storage<std::optional<T>>().Get(idx);
454       return opt_value ? ToSqlValue(*opt_value) : SqlValue();
455     }
456     return ToSqlValue(storage<T>().Get(idx));
457   }
458 
459   static constexpr bool IsDense(uint32_t flags) {
460     return (flags & Flag::kDense) != 0;
461   }
462   static constexpr bool IsNullable(uint32_t flags) {
463     return (flags & Flag::kNonNull) == 0;
464   }
465   static constexpr bool IsSetId(uint32_t flags) {
466     return (flags & Flag::kSetId) != 0;
467   }
468   static constexpr bool IsSorted(uint32_t flags) {
469     return (flags & Flag::kSorted) != 0;
470   }
471 
472   static constexpr bool IsFlagsAndTypeValid(uint32_t flags, ColumnType type) {
473     return (!IsDense(flags) || IsFlagsForDenseValid(flags)) &&
474            (!IsSetId(flags) || IsFlagsAndTypeForSetIdValid(flags, type));
475   }
476 
477   static constexpr bool IsFlagsForDenseValid(uint32_t flags) {
478     // The dense flag should only be set when the column is nullable.
479     return IsNullable(flags);
480   }
481 
482   static constexpr bool IsFlagsAndTypeForSetIdValid(uint32_t flags,
483                                                     ColumnType type) {
484     // The sorted flag should always be set for set id columns.
485     // The non-null flag should always be set for set id columns.
486     // The column type should always be kUint32.
487     return IsSorted(flags) && !IsNullable(flags) && type == ColumnType::kUint32;
488   }
489 
490   static SqlValue::Type ToSqlValueType(ColumnType type) {
491     switch (type) {
492       case ColumnType::kInt32:
493       case ColumnType::kUint32:
494       case ColumnType::kInt64:
495       case ColumnType::kId:
496         return SqlValue::Type::kLong;
497       case ColumnType::kDouble:
498         return SqlValue::Type::kDouble;
499       case ColumnType::kString:
500         return SqlValue::Type::kString;
501       case ColumnType::kDummy:
502         PERFETTO_FATAL("ToSqlValueType not allowed on dummy column");
503     }
504     PERFETTO_FATAL("For GCC");
505   }
506 
507   // Returns the string at the index |idx|.
508   // Should only be called when |type_| == ColumnType::kString.
509   NullTermStringView GetStringPoolStringAtIdx(uint32_t idx) const {
510     PERFETTO_DCHECK(type_ == ColumnType::kString);
511     return string_pool_->Get(storage<StringPool::Id>().Get(idx));
512   }
513 
514   void BindToTable(Table* table, StringPool* string_pool) {
515     PERFETTO_DCHECK(!table_);
516     table_ = table;
517     string_pool_ = string_pool;
518 
519     // Check that the dense-ness of the column and the nullable vector match.
520     if (IsNullable() && !IsDummy()) {
521       bool is_storage_dense;
522       switch (type_) {
523         case ColumnType::kInt32:
524           is_storage_dense = storage<std::optional<int32_t>>().IsDense();
525           break;
526         case ColumnType::kUint32:
527           is_storage_dense = storage<std::optional<uint32_t>>().IsDense();
528           break;
529         case ColumnType::kInt64:
530           is_storage_dense = storage<std::optional<int64_t>>().IsDense();
531           break;
532         case ColumnType::kDouble:
533           is_storage_dense = storage<std::optional<double>>().IsDense();
534           break;
535         case ColumnType::kString:
536           PERFETTO_FATAL("String column should not be nullable");
537         case ColumnType::kId:
538           PERFETTO_FATAL("Id column should not be nullable");
539         case ColumnType::kDummy:
540           PERFETTO_FATAL("Dummy column excluded above");
541       }
542       PERFETTO_DCHECK(is_storage_dense == IsDense());
543     }
544     PERFETTO_DCHECK(IsFlagsAndTypeValid(flags_, type_));
545   }
546 
547   // type_ is used to cast nullable_vector_ to the correct type.
548   ColumnType type_ = ColumnType::kInt64;
549   ColumnStorageBase* storage_ = nullptr;
550 
551   const char* name_ = nullptr;
552   uint32_t flags_ = Flag::kNoFlag;
553   const Table* table_ = nullptr;
554   uint32_t index_in_table_ = 0;
555   uint32_t overlay_index_ = 0;
556   const StringPool* string_pool_ = nullptr;
557 };
558 
559 }  // namespace perfetto::trace_processor
560 
561 #endif  // SRC_TRACE_PROCESSOR_DB_COLUMN_H_
562