• 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 
22 #include "perfetto/base/logging.h"
23 #include "perfetto/ext/base/optional.h"
24 #include "perfetto/trace_processor/basic_types.h"
25 #include "src/trace_processor/containers/nullable_vector.h"
26 #include "src/trace_processor/containers/row_map.h"
27 #include "src/trace_processor/containers/string_pool.h"
28 #include "src/trace_processor/db/compare.h"
29 
30 namespace perfetto {
31 namespace trace_processor {
32 
33 // Id type which can be used as a base for strongly typed ids.
34 // TypedColumn has support for storing descendents of BaseId seamlessly
35 // in a Column.
36 struct BaseId {
37   BaseId() = default;
BaseIdBaseId38   explicit constexpr BaseId(uint32_t v) : value(v) {}
39 
40   bool operator==(const BaseId& o) const { return o.value == value; }
41   bool operator!=(const BaseId& o) const { return !(*this == o); }
42   bool operator<(const BaseId& o) const { return value < o.value; }
43 
44   uint32_t value;
45 };
46 
47 // Represents the possible filter operations on a column.
48 enum class FilterOp {
49   kEq,
50   kNe,
51   kGt,
52   kLt,
53   kGe,
54   kLe,
55   kIsNull,
56   kIsNotNull,
57 };
58 
59 // Represents a constraint on a column.
60 struct Constraint {
61   uint32_t col_idx;
62   FilterOp op;
63   SqlValue value;
64 };
65 
66 // Represents an order by operation on a column.
67 struct Order {
68   uint32_t col_idx;
69   bool desc;
70 };
71 
72 class Table;
73 
74 // Represents a named, strongly typed list of data.
75 class Column {
76  public:
77   // Flags which indicate properties of the data in the column. These features
78   // are used to speed up column methods like filtering/sorting.
79   enum Flag : uint32_t {
80     // Indicates that this column has no special properties.
81     kNoFlag = 0,
82 
83     // Indicates the data in the column is sorted. This can be used to speed
84     // up filtering and skip sorting.
85     kSorted = 1 << 0,
86 
87     // Indicates the data in the column is non-null. That is, the NullableVector
88     // passed in will never have any null entries. This is only used for
89     // numeric columns (string columns and id columns both have special
90     // handling which ignores this flag).
91     //
92     // This is used to speed up filters as we can safely index NullableVector
93     // directly if this flag is set.
94     kNonNull = 1 << 1,
95 
96     // Indicates that the data in the column is "hidden". This can by used to
97     // hint to users of Table and Column that this column should not be
98     // displayed to the user as it is part of the internal implementation
99     // details of the table.
100     kHidden = 1 << 2,
101 
102     // Indicates that the data in this column is stored densely. This
103     // allows for fast Set calls to change the data in the column.
104     //
105     // This flag is only meaningful for nullable columns has no effect for
106     // non-null columns.
107     kDense = 1 << 3,
108   };
109 
110   // Iterator over a column which conforms to std iterator interface
111   // to allow using std algorithms (e.g. upper_bound, lower_bound etc.).
112   class Iterator {
113    public:
114     using iterator_category = std::random_access_iterator_tag;
115     using value_type = SqlValue;
116     using difference_type = uint32_t;
117     using pointer = uint32_t*;
118     using reference = uint32_t&;
119 
Iterator(const Column * col,uint32_t row)120     Iterator(const Column* col, uint32_t row) : col_(col), row_(row) {}
121 
122     Iterator(const Iterator&) = default;
123     Iterator& operator=(const Iterator&) = default;
124 
125     bool operator==(const Iterator& other) const { return other.row_ == row_; }
126     bool operator!=(const Iterator& other) const { return !(*this == other); }
127     bool operator<(const Iterator& other) const { return row_ < other.row_; }
128     bool operator>(const Iterator& other) const { return other < *this; }
129     bool operator<=(const Iterator& other) const { return !(other < *this); }
130     bool operator>=(const Iterator& other) const { return !(*this < other); }
131 
132     SqlValue operator*() const { return col_->Get(row_); }
133     Iterator& operator++() {
134       row_++;
135       return *this;
136     }
137     Iterator& operator--() {
138       row_--;
139       return *this;
140     }
141 
142     Iterator& operator+=(uint32_t diff) {
143       row_ += diff;
144       return *this;
145     }
146     uint32_t operator-(const Iterator& other) const {
147       return row_ - other.row_;
148     }
149 
row()150     uint32_t row() const { return row_; }
151 
152    private:
153     const Column* col_ = nullptr;
154     uint32_t row_ = 0;
155   };
156 
157   // Flags specified for an id column.
158   static constexpr uint32_t kIdFlags = Flag::kSorted | Flag::kNonNull;
159 
160   template <typename T>
Column(const char * name,NullableVector<T> * storage,uint32_t flags,Table * table,uint32_t col_idx_in_table,uint32_t row_map_idx)161   Column(const char* name,
162          NullableVector<T>* storage,
163          /* Flag */ uint32_t flags,
164          Table* table,
165          uint32_t col_idx_in_table,
166          uint32_t row_map_idx)
167       : Column(name,
168                ToColumnType<T>(),
169                flags,
170                table,
171                col_idx_in_table,
172                row_map_idx,
173                storage,
174                nullptr) {}
175 
176   // Create a Column has the same name and is backed by the same data as
177   // |column| but is associated to a different table.
178   Column(const Column& column,
179          Table* table,
180          uint32_t col_idx_in_table,
181          uint32_t row_map_idx);
182 
183   // Columns are movable but not copyable.
184   Column(Column&&) noexcept = default;
185   Column& operator=(Column&&) = default;
186 
187   template <typename T>
WithOwnedStorage(const char * name,std::unique_ptr<NullableVector<T>> storage,uint32_t flags,Table * table,uint32_t col_idx_in_table,uint32_t row_map_idx)188   static Column WithOwnedStorage(const char* name,
189                                  std::unique_ptr<NullableVector<T>> storage,
190                                  /* Flag */ uint32_t flags,
191                                  Table* table,
192                                  uint32_t col_idx_in_table,
193                                  uint32_t row_map_idx) {
194     NullableVector<T>* ptr = storage.get();
195     return Column(name, ToColumnType<T>(), flags, table, col_idx_in_table,
196                   row_map_idx, ptr, std::move(storage));
197   }
198 
199   // Creates a Column which does not have any data backing it.
200   static Column DummyColumn(const char* name,
201                             Table* table,
202                             uint32_t col_idx_in_table);
203 
204   // Creates a Column which returns the index as the value of the row.
205   static Column IdColumn(Table* table,
206                          uint32_t col_idx_in_table,
207                          uint32_t row_map_idx);
208 
209   // Gets the value of the Column at the given |row|.
Get(uint32_t row)210   SqlValue Get(uint32_t row) const { return GetAtIdx(row_map().Get(row)); }
211 
212   // Returns the row containing the given value in the Column.
IndexOf(SqlValue value)213   base::Optional<uint32_t> IndexOf(SqlValue value) const {
214     switch (type_) {
215       // TODO(lalitm): investigate whether we could make this more efficient
216       // by first checking the type of the column and comparing explicitly
217       // based on that type.
218       case ColumnType::kInt32:
219       case ColumnType::kUint32:
220       case ColumnType::kInt64:
221       case ColumnType::kDouble:
222       case ColumnType::kString: {
223         for (uint32_t i = 0; i < row_map().size(); i++) {
224           if (compare::SqlValue(Get(i), value) == 0)
225             return i;
226         }
227         return base::nullopt;
228       }
229       case ColumnType::kId: {
230         if (value.type != SqlValue::Type::kLong)
231           return base::nullopt;
232         return row_map().RowOf(static_cast<uint32_t>(value.long_value));
233       }
234       case ColumnType::kDummy:
235         PERFETTO_FATAL("IndexOf not allowed on dummy column");
236     }
237     PERFETTO_FATAL("For GCC");
238   }
239 
240   // Sets the value of the column at the given |row|.
Set(uint32_t row,SqlValue value)241   void Set(uint32_t row, SqlValue value) {
242     PERFETTO_CHECK(value.type == type());
243     switch (type_) {
244       case ColumnType::kInt32: {
245         mutable_nullable_vector<int32_t>()->Set(
246             row, static_cast<int32_t>(value.long_value));
247         break;
248       }
249       case ColumnType::kUint32: {
250         mutable_nullable_vector<uint32_t>()->Set(
251             row, static_cast<uint32_t>(value.long_value));
252         break;
253       }
254       case ColumnType::kInt64: {
255         mutable_nullable_vector<int64_t>()->Set(
256             row, static_cast<int64_t>(value.long_value));
257         break;
258       }
259       case ColumnType::kDouble: {
260         mutable_nullable_vector<double>()->Set(row, value.double_value);
261         break;
262       }
263       case ColumnType::kString: {
264         PERFETTO_FATAL(
265             "Setting a generic value on a string column is not implemented");
266       }
267       case ColumnType::kId: {
268         PERFETTO_FATAL("Cannot set value on a id column");
269       }
270       case ColumnType::kDummy:
271         PERFETTO_FATAL("Set not allowed on dummy column");
272     }
273   }
274 
275   // Sorts |idx| in ascending or descending order (determined by |desc|) based
276   // on the contents of this column.
277   void StableSort(bool desc, std::vector<uint32_t>* idx) const;
278 
279   // Updates the given RowMap by only keeping rows where this column meets the
280   // given filter constraint.
FilterInto(FilterOp op,SqlValue value,RowMap * rm)281   void FilterInto(FilterOp op, SqlValue value, RowMap* rm) const {
282     if (IsId() && op == FilterOp::kEq) {
283       // If this is an equality constraint on an id column, try and find the
284       // single row with the id (if it exists).
285       auto opt_idx = IndexOf(value);
286       if (opt_idx) {
287         rm->Intersect(RowMap::SingleRow(*opt_idx));
288       } else {
289         rm->Intersect(RowMap());
290       }
291       return;
292     }
293 
294     if (IsSorted() && value.type == type()) {
295       // If the column is sorted and the value has the same type as the column,
296       // we should be able to just do a binary search to find the range of rows
297       // instead of a full table scan.
298       bool handled = FilterIntoSorted(op, value, rm);
299       if (handled)
300         return;
301     }
302 
303     FilterIntoSlow(op, value, rm);
304   }
305 
306   // Returns the minimum value in this column. Returns nullopt if this column
307   // is empty.
Min()308   base::Optional<SqlValue> Min() const {
309     if (row_map().empty())
310       return base::nullopt;
311 
312     if (IsSorted())
313       return Get(0);
314 
315     Iterator b(this, 0);
316     Iterator e(this, row_map().size());
317     return *std::min_element(b, e, &compare::SqlValueComparator);
318   }
319 
320   // Returns the minimum value in this column. Returns nullopt if this column
321   // is empty.
Max()322   base::Optional<SqlValue> Max() const {
323     if (row_map().empty())
324       return base::nullopt;
325 
326     if (IsSorted())
327       return Get(row_map().size() - 1);
328 
329     Iterator b(this, 0);
330     Iterator e(this, row_map().size());
331     return *std::max_element(b, e, &compare::SqlValueComparator);
332   }
333 
334   // Returns true if this column is considered an id column.
IsId()335   bool IsId() const { return type_ == ColumnType::kId; }
336 
337   // Returns true if this column is a dummy column.
IsDummy()338   bool IsDummy() const { return type_ == ColumnType::kDummy; }
339 
340   // Returns true if this column is a nullable column.
IsNullable()341   bool IsNullable() const { return (flags_ & Flag::kNonNull) == 0; }
342 
343   // Returns true if this column is a sorted column.
IsSorted()344   bool IsSorted() const { return (flags_ & Flag::kSorted) != 0; }
345 
346   // Returns true if this column is a dense column.
IsDense()347   bool IsDense() const { return (flags_ & Flag::kDense) != 0; }
348 
349   // Returns the backing RowMap for this Column.
350   // This function is defined out of line because of a circular dependency
351   // between |Table| and |Column|.
352   const RowMap& row_map() const;
353 
354   // Returns the name of the column.
name()355   const char* name() const { return name_; }
356 
357   // Returns the type of this Column in terms of SqlValue::Type.
type()358   SqlValue::Type type() const { return ToSqlValueType(type_); }
359 
360   // Test the type of this Column.
361   template <typename T>
IsColumnType()362   bool IsColumnType() const {
363     return ToColumnType<T>() == type_;
364   }
365 
366   // Returns the index of the current column in the containing table.
index_in_table()367   uint32_t index_in_table() const { return col_idx_in_table_; }
368 
369   // Returns a Constraint for each type of filter operation for this Column.
eq_value(SqlValue value)370   Constraint eq_value(SqlValue value) const {
371     return Constraint{col_idx_in_table_, FilterOp::kEq, value};
372   }
gt_value(SqlValue value)373   Constraint gt_value(SqlValue value) const {
374     return Constraint{col_idx_in_table_, FilterOp::kGt, value};
375   }
lt_value(SqlValue value)376   Constraint lt_value(SqlValue value) const {
377     return Constraint{col_idx_in_table_, FilterOp::kLt, value};
378   }
ne_value(SqlValue value)379   Constraint ne_value(SqlValue value) const {
380     return Constraint{col_idx_in_table_, FilterOp::kNe, value};
381   }
ge_value(SqlValue value)382   Constraint ge_value(SqlValue value) const {
383     return Constraint{col_idx_in_table_, FilterOp::kGe, value};
384   }
le_value(SqlValue value)385   Constraint le_value(SqlValue value) const {
386     return Constraint{col_idx_in_table_, FilterOp::kLe, value};
387   }
is_not_null()388   Constraint is_not_null() const {
389     return Constraint{col_idx_in_table_, FilterOp::kIsNotNull, SqlValue()};
390   }
is_null()391   Constraint is_null() const {
392     return Constraint{col_idx_in_table_, FilterOp::kIsNull, SqlValue()};
393   }
394 
395   // Returns an Order for each Order type for this Column.
ascending()396   Order ascending() const { return Order{col_idx_in_table_, false}; }
descending()397   Order descending() const { return Order{col_idx_in_table_, true}; }
398 
399   // Returns an iterator to the first entry in this column.
begin()400   Iterator begin() const { return Iterator(this, 0); }
401 
402   // Returns an iterator pointing beyond the last entry in this column.
end()403   Iterator end() const { return Iterator(this, row_map().size()); }
404 
405  protected:
406   // Returns the backing sparse vector cast to contain data of type T.
407   // Should only be called when |type_| == ToColumnType<T>().
408   template <typename T>
mutable_nullable_vector()409   NullableVector<T>* mutable_nullable_vector() {
410     PERFETTO_DCHECK(ToColumnType<T>() == type_);
411     return static_cast<NullableVector<T>*>(nullable_vector_);
412   }
413 
414   // Returns the backing sparse vector cast to contain data of type T.
415   // Should only be called when |type_| == ToColumnType<T>().
416   template <typename T>
nullable_vector()417   const NullableVector<T>& nullable_vector() const {
418     PERFETTO_DCHECK(ToColumnType<T>() == type_);
419     return *static_cast<const NullableVector<T>*>(nullable_vector_);
420   }
421 
422   // Returns the type of this Column in terms of SqlValue::Type.
423   template <typename T>
ToSqlValueType()424   static SqlValue::Type ToSqlValueType() {
425     return ToSqlValueType(ToColumnType<T>());
426   }
427 
string_pool()428   const StringPool& string_pool() const { return *string_pool_; }
429 
430  private:
431   enum class ColumnType {
432     // Standard primitive types.
433     kInt32,
434     kUint32,
435     kInt64,
436     kDouble,
437     kString,
438 
439     // Types generated on the fly.
440     kId,
441 
442     // Types which don't have any data backing them.
443     kDummy,
444   };
445 
446   friend class Table;
447 
448   // Base constructor for this class which all other constructors call into.
449   Column(const char* name,
450          ColumnType type,
451          uint32_t flags,
452          Table* table,
453          uint32_t col_idx_in_table,
454          uint32_t row_map_idx,
455          NullableVectorBase* nullable_vector,
456          std::shared_ptr<NullableVectorBase> owned_nullable_vector);
457 
458   Column(const Column&) = delete;
459   Column& operator=(const Column&) = delete;
460 
461   // Gets the value of the Column at the given |row|.
GetAtIdx(uint32_t idx)462   SqlValue GetAtIdx(uint32_t idx) const {
463     switch (type_) {
464       case ColumnType::kInt32: {
465         auto opt_value = nullable_vector<int32_t>().Get(idx);
466         return opt_value ? SqlValue::Long(*opt_value) : SqlValue();
467       }
468       case ColumnType::kUint32: {
469         auto opt_value = nullable_vector<uint32_t>().Get(idx);
470         return opt_value ? SqlValue::Long(*opt_value) : SqlValue();
471       }
472       case ColumnType::kInt64: {
473         auto opt_value = nullable_vector<int64_t>().Get(idx);
474         return opt_value ? SqlValue::Long(*opt_value) : SqlValue();
475       }
476       case ColumnType::kDouble: {
477         auto opt_value = nullable_vector<double>().Get(idx);
478         return opt_value ? SqlValue::Double(*opt_value) : SqlValue();
479       }
480       case ColumnType::kString: {
481         auto str = GetStringPoolStringAtIdx(idx).c_str();
482         return str == nullptr ? SqlValue() : SqlValue::String(str);
483       }
484       case ColumnType::kId:
485         return SqlValue::Long(idx);
486       case ColumnType::kDummy:
487         PERFETTO_FATAL("GetAtIdx not allowed on dummy column");
488     }
489     PERFETTO_FATAL("For GCC");
490   }
491 
492   // Optimized filter method for sorted columns.
493   // Returns whether the constraint was handled by the method.
FilterIntoSorted(FilterOp op,SqlValue value,RowMap * rm)494   bool FilterIntoSorted(FilterOp op, SqlValue value, RowMap* rm) const {
495     PERFETTO_DCHECK(IsSorted());
496     PERFETTO_DCHECK(value.type == type());
497 
498     Iterator b(this, 0);
499     Iterator e(this, row_map().size());
500     switch (op) {
501       case FilterOp::kEq: {
502         uint32_t beg = std::distance(
503             b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
504         uint32_t end = std::distance(
505             b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
506         rm->Intersect(RowMap(beg, end));
507         return true;
508       }
509       case FilterOp::kLe: {
510         uint32_t end = std::distance(
511             b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
512         rm->Intersect(RowMap(0, end));
513         return true;
514       }
515       case FilterOp::kLt: {
516         uint32_t end = std::distance(
517             b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
518         rm->Intersect(RowMap(0, end));
519         return true;
520       }
521       case FilterOp::kGe: {
522         uint32_t beg = std::distance(
523             b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
524         rm->Intersect(RowMap(beg, row_map().size()));
525         return true;
526       }
527       case FilterOp::kGt: {
528         uint32_t beg = std::distance(
529             b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
530         rm->Intersect(RowMap(beg, row_map().size()));
531         return true;
532       }
533       case FilterOp::kNe:
534       case FilterOp::kIsNull:
535       case FilterOp::kIsNotNull:
536         break;
537     }
538     return false;
539   }
540 
541   // Slow path filter method which will perform a full table scan.
542   void FilterIntoSlow(FilterOp op, SqlValue value, RowMap* rm) const;
543 
544   // Slow path filter method for numerics which will perform a full table scan.
545   template <typename T, bool is_nullable>
546   void FilterIntoNumericSlow(FilterOp op, SqlValue value, RowMap* rm) const;
547 
548   // Slow path filter method for numerics with a comparator which will perform a
549   // full table scan.
550   template <typename T, bool is_nullable, typename Comparator = int(T)>
551   void FilterIntoNumericWithComparatorSlow(FilterOp op,
552                                            RowMap* rm,
553                                            Comparator cmp) const;
554 
555   // Slow path filter method for strings which will perform a full table scan.
556   void FilterIntoStringSlow(FilterOp op, SqlValue value, RowMap* rm) const;
557 
558   // Slow path filter method for ids which will perform a full table scan.
559   void FilterIntoIdSlow(FilterOp op, SqlValue value, RowMap* rm) const;
560 
561   // Stable sorts this column storing the result in |out|.
562   template <bool desc>
563   void StableSort(std::vector<uint32_t>* out) const;
564 
565   // Stable sorts this column storing the result in |out|.
566   // |T| and |is_nullable| should match the type and nullability of this column.
567   template <bool desc, typename T, bool is_nullable>
568   void StableSortNumeric(std::vector<uint32_t>* out) const;
569 
570   template <typename T>
ToColumnType()571   static ColumnType ToColumnType() {
572     if (std::is_same<T, uint32_t>::value) {
573       return ColumnType::kUint32;
574     } else if (std::is_same<T, int64_t>::value) {
575       return ColumnType::kInt64;
576     } else if (std::is_same<T, int32_t>::value) {
577       return ColumnType::kInt32;
578     } else if (std::is_same<T, StringPool::Id>::value) {
579       return ColumnType::kString;
580     } else if (std::is_same<T, double>::value) {
581       return ColumnType::kDouble;
582     } else {
583       PERFETTO_FATAL("Unsupported type of column");
584     }
585   }
586 
ToSqlValueType(ColumnType type)587   static SqlValue::Type ToSqlValueType(ColumnType type) {
588     switch (type) {
589       case ColumnType::kInt32:
590       case ColumnType::kUint32:
591       case ColumnType::kInt64:
592       case ColumnType::kId:
593         return SqlValue::Type::kLong;
594       case ColumnType::kDouble:
595         return SqlValue::Type::kDouble;
596       case ColumnType::kString:
597         return SqlValue::Type::kString;
598       case ColumnType::kDummy:
599         PERFETTO_FATAL("ToSqlValueType not allowed on dummy column");
600     }
601     PERFETTO_FATAL("For GCC");
602   }
603 
604   // Returns the string at the index |idx|.
605   // Should only be called when |type_| == ColumnType::kString.
GetStringPoolStringAtIdx(uint32_t idx)606   NullTermStringView GetStringPoolStringAtIdx(uint32_t idx) const {
607     PERFETTO_DCHECK(type_ == ColumnType::kString);
608     return string_pool_->Get(nullable_vector<StringPool::Id>().GetNonNull(idx));
609   }
610 
611   // Only filled for columns which own the data inside them. Generally this is
612   // only true for columns which are dynamically generated at runtime.
613   // Keep this before |nullable_vector_|.
614   std::shared_ptr<NullableVectorBase> owned_nullable_vector_;
615 
616   // type_ is used to cast nullable_vector_ to the correct type.
617   ColumnType type_ = ColumnType::kInt64;
618   NullableVectorBase* nullable_vector_ = nullptr;
619 
620   const char* name_ = nullptr;
621   uint32_t flags_ = Flag::kNoFlag;
622   const Table* table_ = nullptr;
623   uint32_t col_idx_in_table_ = 0;
624   uint32_t row_map_idx_ = 0;
625   const StringPool* string_pool_ = nullptr;
626 };
627 
628 }  // namespace trace_processor
629 }  // namespace perfetto
630 
631 #endif  // SRC_TRACE_PROCESSOR_DB_COLUMN_H_
632