1 /*
2  * Copyright (C) 2020 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_TYPED_COLUMN_H_
18 #define SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_H_
19 
20 #include "src/trace_processor/db/column.h"
21 #include "src/trace_processor/db/typed_column_internal.h"
22 
23 namespace perfetto {
24 namespace trace_processor {
25 
26 // TypedColumn<T>
27 //
28 // Introduction:
29 // TypedColumn exists to allow efficient access to the data in a Column without
30 // having to go through dynamic type checking. There are two main reasons for
31 // this:
32 // 1. Performance: dynamic type checking is not free and so if this is used
33 //    in a particularily hot codepath, the typechecking can be a significant
34 //    overhead.
35 // 2. Ergonomics: having to convert back and forth from/to SqlValue causes
36 //    signifcant clutter in parts of the code which can already be quite hard
37 //    to follow (e.g. trackers like StackProfileTracker which perform cross
38 //    checking of various ids).
39 //
40 // Implementation:
41 // TypedColumn is implemented as a memberless subclass of Column. This allows
42 // us to reinterpret case from a Column* to a TypedColumn<T> where we know the
43 // type T. The methods of TypedColumn are type-specialized methods of Column
44 // which allow callers to pass raw types instead of using SqlValue.
45 //
46 // There are two helper classes (tc_internal::TypeHandler and
47 // tc_internal::Serializer) where we specialize behaviour which needs to be
48 // different based on T. See their class documentation and below for details
49 // on their purpose.
50 template <typename T>
51 struct TypedColumn : public Column {
52  private:
53   using TH = tc_internal::TypeHandler<T>;
54 
55   // The non-optional type of the data in this column.
56   using non_optional_type =
57       typename tc_internal::TypeHandler<T>::non_optional_type;
58 
59   // The type of data in this column (including Optional wrapper if the type
60   // should be optional).
61   using get_type = typename tc_internal::TypeHandler<T>::get_type;
62 
63   // The type which should be passed to SqlValue functions.
64   using sql_value_type = typename tc_internal::TypeHandler<T>::sql_value_type;
65 
66   using Serializer = tc_internal::Serializer<non_optional_type>;
67 
68  public:
69   // The type which should be stored in the SparseVector.
70   // Used by the macro code when actually constructing the SparseVectors.
71   using serialized_type = typename Serializer::serialized_type;
72 
73   // Returns the data in the column at index |row|.
74   // Function chosen when TH::is_optional == true.
75   template <bool is_optional = TH::is_optional>
76   typename std::enable_if<is_optional, get_type>::type operator[](
77       uint32_t row) const {
78     return Serializer::Deserialize(sparse_vector().Get(row_map().Get(row)));
79   }
80 
81   // Function chosen when TH::is_optional == false.
82   template <bool is_optional = TH::is_optional>
83   typename std::enable_if<!is_optional, get_type>::type operator[](
84       uint32_t row) const {
85     return Serializer::Deserialize(
86         sparse_vector().GetNonNull(row_map().Get(row)));
87   }
88 
89   // Special function only for string types to allow retrieving the string
90   // directly from the column.
91   template <bool is_string = TH::is_string>
GetStringTypedColumn92   typename std::enable_if<is_string, NullTermStringView>::type GetString(
93       uint32_t row) const {
94     return string_pool().Get((*this)[row]);
95   }
96 
97   // Sets the data in the column at index |row|.
SetTypedColumn98   void Set(uint32_t row, non_optional_type v) {
99     auto serialized = Serializer::Serialize(v);
100     mutable_sparse_vector()->Set(row_map().Get(row), serialized);
101   }
102 
103   // Inserts the value at the end of the column.
AppendTypedColumn104   void Append(T v) {
105     mutable_sparse_vector()->Append(Serializer::Serialize(v));
106   }
107 
108   // Returns the row containing the given value in the Column.
IndexOfTypedColumn109   base::Optional<uint32_t> IndexOf(sql_value_type v) const {
110     return Column::IndexOf(ToValue(v));
111   }
112 
ToVectorForTestingTypedColumn113   std::vector<get_type> ToVectorForTesting() const {
114     std::vector<T> result(row_map().size());
115     for (uint32_t i = 0; i < row_map().size(); ++i)
116       result[i] = (*this)[i];
117     return result;
118   }
119 
120   // Helper functions to create constraints for the given value.
eqTypedColumn121   Constraint eq(sql_value_type v) const { return eq_value(ToValue(v)); }
gtTypedColumn122   Constraint gt(sql_value_type v) const { return gt_value(ToValue(v)); }
ltTypedColumn123   Constraint lt(sql_value_type v) const { return lt_value(ToValue(v)); }
neTypedColumn124   Constraint ne(sql_value_type v) const { return ne_value(ToValue(v)); }
geTypedColumn125   Constraint ge(sql_value_type v) const { return ge_value(ToValue(v)); }
leTypedColumn126   Constraint le(sql_value_type v) const { return le_value(ToValue(v)); }
127 
128   // Implements equality between two items of type |T|.
EqualsTypedColumn129   static constexpr bool Equals(T a, T b) { return TH::Equals(a, b); }
130 
131   // Encodes the default flags for a column of the current type.
default_flagsTypedColumn132   static constexpr uint32_t default_flags() {
133     return TH::is_optional ? Flag::kNoFlag : Flag::kNonNull;
134   }
135 
136   // Converts the static type T into the dynamic SqlValue type of this column.
SqlValueTypeTypedColumn137   static SqlValue::Type SqlValueType() {
138     return Column::ToSqlValueType<serialized_type>();
139   }
140 
141   // Reinterpret cast a Column to TypedColumn or crash if that is likely to be
142   // unsafe.
FromColumnTypedColumn143   static const TypedColumn<T>* FromColumn(const Column* column) {
144     if (column->IsColumnType<serialized_type>() &&
145         (column->IsNullable() == TH::is_optional) && !column->IsId()) {
146       return reinterpret_cast<const TypedColumn<T>*>(column);
147     } else {
148       PERFETTO_FATAL("Unsafe to convert Column to TypedColumn.");
149     }
150   }
151 
152  private:
ToValueTypedColumn153   static SqlValue ToValue(double value) { return SqlValue::Double(value); }
ToValueTypedColumn154   static SqlValue ToValue(uint32_t value) { return SqlValue::Long(value); }
ToValueTypedColumn155   static SqlValue ToValue(int64_t value) { return SqlValue::Long(value); }
ToValueTypedColumn156   static SqlValue ToValue(NullTermStringView value) {
157     return SqlValue::String(value.c_str());
158   }
159 
sparse_vectorTypedColumn160   const SparseVector<serialized_type>& sparse_vector() const {
161     return Column::sparse_vector<serialized_type>();
162   }
mutable_sparse_vectorTypedColumn163   SparseVector<serialized_type>* mutable_sparse_vector() {
164     return Column::mutable_sparse_vector<serialized_type>();
165   }
166 };
167 
168 // Represents a column containing ids.
169 // TODO(lalitm): think about unifying this with TypedColumn in the
170 // future.
171 template <typename Id>
172 struct IdColumn : public Column {
173   Id operator[](uint32_t row) const { return Id(row_map().Get(row)); }
IndexOfIdColumn174   base::Optional<uint32_t> IndexOf(Id id) const {
175     return row_map().IndexOf(id.value);
176   }
177 
178   // Helper functions to create constraints for the given value.
eqIdColumn179   Constraint eq(uint32_t v) const { return eq_value(SqlValue::Long(v)); }
gtIdColumn180   Constraint gt(uint32_t v) const { return gt_value(SqlValue::Long(v)); }
ltIdColumn181   Constraint lt(uint32_t v) const { return lt_value(SqlValue::Long(v)); }
neIdColumn182   Constraint ne(uint32_t v) const { return ne_value(SqlValue::Long(v)); }
geIdColumn183   Constraint ge(uint32_t v) const { return ge_value(SqlValue::Long(v)); }
leIdColumn184   Constraint le(uint32_t v) const { return le_value(SqlValue::Long(v)); }
185 };
186 
187 }  // namespace trace_processor
188 }  // namespace perfetto
189 
190 #endif  // SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_H_
191