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 SequenceStackProfileTracker which perform
38 //    cross 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 NullableVector.
70   // Used by the macro code when actually constructing the NullableVectors.
71   using serialized_type = typename Serializer::serialized_type;
72 
73   get_type operator[](uint32_t row) const {
74     return Serializer::Deserialize(
75         TH::Get(nullable_vector(), row_map().Get(row)));
76   }
77 
78   // Special function only for string types to allow retrieving the string
79   // directly from the column.
80   template <bool is_string = TH::is_string>
GetStringTypedColumn81   typename std::enable_if<is_string, NullTermStringView>::type GetString(
82       uint32_t row) const {
83     return string_pool().Get(nullable_vector().GetNonNull(row_map().Get(row)));
84   }
85 
86   // Sets the data in the column at index |row|.
SetTypedColumn87   void Set(uint32_t row, non_optional_type v) {
88     auto serialized = Serializer::Serialize(v);
89     mutable_nullable_vector()->Set(row_map().Get(row), serialized);
90   }
91 
92   // Inserts the value at the end of the column.
AppendTypedColumn93   void Append(T v) {
94     mutable_nullable_vector()->Append(Serializer::Serialize(v));
95   }
96 
97   // Returns the row containing the given value in the Column.
IndexOfTypedColumn98   base::Optional<uint32_t> IndexOf(sql_value_type v) const {
99     return Column::IndexOf(ToValue(v));
100   }
101 
ToVectorForTestingTypedColumn102   std::vector<get_type> ToVectorForTesting() const {
103     std::vector<T> result(row_map().size());
104     for (uint32_t i = 0; i < row_map().size(); ++i)
105       result[i] = (*this)[i];
106     return result;
107   }
108 
109   // Helper functions to create constraints for the given value.
eqTypedColumn110   Constraint eq(sql_value_type v) const { return eq_value(ToValue(v)); }
gtTypedColumn111   Constraint gt(sql_value_type v) const { return gt_value(ToValue(v)); }
ltTypedColumn112   Constraint lt(sql_value_type v) const { return lt_value(ToValue(v)); }
neTypedColumn113   Constraint ne(sql_value_type v) const { return ne_value(ToValue(v)); }
geTypedColumn114   Constraint ge(sql_value_type v) const { return ge_value(ToValue(v)); }
leTypedColumn115   Constraint le(sql_value_type v) const { return le_value(ToValue(v)); }
116 
117   // Implements equality between two items of type |T|.
EqualsTypedColumn118   static constexpr bool Equals(T a, T b) { return TH::Equals(a, b); }
119 
120   // Encodes the default flags for a column of the current type.
default_flagsTypedColumn121   static constexpr uint32_t default_flags() {
122     return TH::is_optional ? Flag::kNoFlag : Flag::kNonNull;
123   }
124 
125   // Converts the static type T into the dynamic SqlValue type of this column.
SqlValueTypeTypedColumn126   static SqlValue::Type SqlValueType() {
127     return Column::ToSqlValueType<serialized_type>();
128   }
129 
130   // Reinterpret cast a Column to TypedColumn or crash if that is likely to be
131   // unsafe.
FromColumnTypedColumn132   static const TypedColumn<T>* FromColumn(const Column* column) {
133     if (column->IsColumnType<serialized_type>() &&
134         (column->IsNullable() == TH::is_optional) && !column->IsId()) {
135       return reinterpret_cast<const TypedColumn<T>*>(column);
136     } else {
137       PERFETTO_FATAL("Unsafe to convert Column TypedColumn (%s)",
138                      column->name());
139     }
140   }
141 
142  private:
ToValueTypedColumn143   static SqlValue ToValue(double value) { return SqlValue::Double(value); }
ToValueTypedColumn144   static SqlValue ToValue(uint32_t value) { return SqlValue::Long(value); }
ToValueTypedColumn145   static SqlValue ToValue(int64_t value) { return SqlValue::Long(value); }
ToValueTypedColumn146   static SqlValue ToValue(NullTermStringView value) {
147     return SqlValue::String(value.c_str());
148   }
149 
nullable_vectorTypedColumn150   const NullableVector<serialized_type>& nullable_vector() const {
151     return Column::nullable_vector<serialized_type>();
152   }
mutable_nullable_vectorTypedColumn153   NullableVector<serialized_type>* mutable_nullable_vector() {
154     return Column::mutable_nullable_vector<serialized_type>();
155   }
156 };
157 
158 // Represents a column containing ids.
159 // TODO(lalitm): think about unifying this with TypedColumn in the
160 // future.
161 template <typename Id>
162 struct IdColumn : public Column {
163   Id operator[](uint32_t row) const { return Id(row_map().Get(row)); }
IndexOfIdColumn164   base::Optional<uint32_t> IndexOf(Id id) const {
165     return row_map().IndexOf(id.value);
166   }
167 
168   // Reinterpret cast a Column to IdColumn or crash if that is likely to be
169   // unsafe.
FromColumnIdColumn170   static const IdColumn<Id>* FromColumn(const Column* column) {
171     if (column->IsId()) {
172       return reinterpret_cast<const IdColumn<Id>*>(column);
173     } else {
174       PERFETTO_FATAL("Unsafe to convert Column to IdColumn (%s)",
175                      column->name());
176     }
177   }
178 
179   // Helper functions to create constraints for the given value.
eqIdColumn180   Constraint eq(uint32_t v) const { return eq_value(SqlValue::Long(v)); }
gtIdColumn181   Constraint gt(uint32_t v) const { return gt_value(SqlValue::Long(v)); }
ltIdColumn182   Constraint lt(uint32_t v) const { return lt_value(SqlValue::Long(v)); }
neIdColumn183   Constraint ne(uint32_t v) const { return ne_value(SqlValue::Long(v)); }
geIdColumn184   Constraint ge(uint32_t v) const { return ge_value(SqlValue::Long(v)); }
leIdColumn185   Constraint le(uint32_t v) const { return le_value(SqlValue::Long(v)); }
186 };
187 
188 }  // namespace trace_processor
189 }  // namespace perfetto
190 
191 #endif  // SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_H_
192