• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static cast 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 real 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 class TypedColumn : public ColumnLegacy {
52  private:
53   using TH = tc_internal::TypeHandler<T>;
54 
55  public:
56   // The type of the data in this column.
57   using type = T;
58 
59   // The non-optional type of the data in this column.
60   using non_optional_type = typename TH::non_optional_type;
61 
62   // The type which should be passed to SqlValue functions.
63   using sql_value_type = typename TH::sql_value_type;
64 
65   // The type of which is actually stored inside ColumnStorage. Can be different
66   // from T because we treat table ids to just be uint32_t inside the storage
67   // (handling ids would add an extra type to consider when filtering for no
68   // benefit.
69   using stored_type = typename TH::stored_type;
70   using non_optional_stored_type =
71       typename tc_internal::TypeHandler<non_optional_type>::stored_type;
72 
73  private:
74   using Serializer = tc_internal::Serializer<non_optional_type>;
75 
76  public:
77   T operator[](uint32_t row) const { return GetAtIdx(overlay().Get(row)); }
78 
79   // Special function only for string types to allow retrieving the string
80   // directly from the column.
81   template <bool is_string = TH::is_string>
GetString(uint32_t row)82   typename std::enable_if<is_string, NullTermStringView>::type GetString(
83       uint32_t row) const {
84     return GetStringAtIdx(overlay().Get(row));
85   }
86 
87   // Sets the data in the column at index |row|.
Set(uint32_t row,non_optional_type v)88   void Set(uint32_t row, non_optional_type v) {
89     SetAtIdx(overlay().Get(row), v);
90   }
91 
92   // Inserts the value at the end of the column.
Append(T v)93   void Append(T v) { mutable_storage()->Append(Serializer::Serialize(v)); }
94 
95   // Returns the row containing the given value in the Column.
IndexOf(sql_value_type v)96   std::optional<uint32_t> IndexOf(sql_value_type v) const {
97     return ColumnLegacy::IndexOf(ToSqlValue(v));
98   }
99 
ToVectorForTesting()100   std::vector<T> ToVectorForTesting() const {
101     std::vector<T> result(overlay().size());
102     for (uint32_t i = 0; i < overlay().size(); ++i)
103       result[i] = (*this)[i];
104     return result;
105   }
106 
107   // Helper functions to create constraints for the given value.
eq(sql_value_type v)108   Constraint eq(sql_value_type v) const { return eq_value(ToSqlValue(v)); }
gt(sql_value_type v)109   Constraint gt(sql_value_type v) const { return gt_value(ToSqlValue(v)); }
lt(sql_value_type v)110   Constraint lt(sql_value_type v) const { return lt_value(ToSqlValue(v)); }
ne(sql_value_type v)111   Constraint ne(sql_value_type v) const { return ne_value(ToSqlValue(v)); }
ge(sql_value_type v)112   Constraint ge(sql_value_type v) const { return ge_value(ToSqlValue(v)); }
le(sql_value_type v)113   Constraint le(sql_value_type v) const { return le_value(ToSqlValue(v)); }
glob(sql_value_type v)114   Constraint glob(sql_value_type v) const { return glob_value(ToSqlValue(v)); }
regex(sql_value_type v)115   Constraint regex(sql_value_type v) const {
116     return regex_value(ToSqlValue(v));
117   }
118 
119   // Implements equality between two items of type |T|.
Equals(T a,T b)120   static constexpr bool Equals(T a, T b) { return TH::Equals(a, b); }
121 
122   // Encodes the default flags for a column of the current type.
default_flags()123   static constexpr uint32_t default_flags() {
124     return TH::is_optional ? Flag::kNoFlag : Flag::kNonNull;
125   }
126 
127   // Converts the static type T into the dynamic SqlValue type of this column.
SqlValueType()128   static constexpr SqlValue::Type SqlValueType() {
129     return ColumnLegacy::ToSqlValueType<stored_type>();
130   }
131 
132   // Cast a Column to TypedColumn or crash if that is unsafe.
FromColumn(ColumnLegacy * column)133   static TypedColumn<T>* FromColumn(ColumnLegacy* column) {
134     return FromColumnInternal<TypedColumn<T>>(column);
135   }
136 
137   // Cast a Column to TypedColumn or crash if that is unsafe.
FromColumn(const ColumnLegacy * column)138   static const TypedColumn<T>* FromColumn(const ColumnLegacy* column) {
139     return FromColumnInternal<const TypedColumn<T>>(column);
140   }
141 
142   // Public for use by macro tables.
SetAtIdx(uint32_t idx,non_optional_type v)143   void SetAtIdx(uint32_t idx, non_optional_type v) {
144     auto serialized = Serializer::Serialize(v);
145     mutable_storage()->Set(idx, serialized);
146   }
147 
148   // Public for use by macro tables.
GetAtIdx(uint32_t idx)149   T GetAtIdx(uint32_t idx) const {
150     return Serializer::Deserialize(TH::Get(storage(), idx));
151   }
152 
153   template <bool is_string = TH::is_string>
GetStringAtIdx(uint32_t idx)154   typename std::enable_if<is_string, NullTermStringView>::type GetStringAtIdx(
155       uint32_t idx) const {
156     return string_pool().Get(storage().Get(idx));
157   }
158 
159  private:
160   friend class Table;
161 
162   template <typename Output, typename Input>
FromColumnInternal(Input * column)163   static Output* FromColumnInternal(Input* column) {
164     // While casting from a base to derived without constructing as a derived is
165     // technically UB, in practice, this is at the heart of protozero (see
166     // Message::BeginNestedMessage) so we use it here.
167     static_assert(sizeof(TypedColumn<T>) == sizeof(ColumnLegacy),
168                   "TypedColumn cannot introduce extra state.");
169 
170     if (column->template IsColumnType<stored_type>() &&
171         (column->IsNullable() == TH::is_optional) && !column->IsId()) {
172       return static_cast<Output*>(column);
173     } else {
174       PERFETTO_FATAL("Unsafe to convert Column TypedColumn (%s)",
175                      column->name());
176     }
177   }
178 
storage()179   const ColumnStorage<stored_type>& storage() const {
180     return ColumnLegacy::storage<stored_type>();
181   }
mutable_storage()182   ColumnStorage<stored_type>* mutable_storage() {
183     return ColumnLegacy::mutable_storage<stored_type>();
184   }
185 };
186 
187 // Represents a column containing ids.
188 template <typename Id>
189 class IdColumn : public ColumnLegacy {
190  public:
191   // The type of the data in this column.
192   using type = Id;
193 
194   // The underlying type used when comparing ids.
195   using stored_type = uint32_t;
196 
197   Id operator[](uint32_t row) const { return Id(overlay().Get(row)); }
198 
IndexOf(Id id)199   std::optional<uint32_t> IndexOf(Id id) const {
200     return overlay().RowOf(id.value);
201   }
202 
203   // Public for use by macro tables.
GetAtIdx(uint32_t idx)204   Id GetAtIdx(uint32_t idx) const { return Id(idx); }
205 
206   // Static cast a Column to IdColumn or crash if that is likely to be
207   // unsafe.
FromColumn(const ColumnLegacy * column)208   static const IdColumn<Id>* FromColumn(const ColumnLegacy* column) {
209     // While casting from a base to derived without constructing as a derived is
210     // technically UB, in practice, this is at the heart of protozero (see
211     // Message::BeginNestedMessage) so we use it here.
212     static_assert(sizeof(IdColumn<Id>) == sizeof(ColumnLegacy),
213                   "TypedColumn cannot introduce extra state.");
214 
215     if (column->IsId()) {
216       return static_cast<const IdColumn<Id>*>(column);
217     } else {
218       PERFETTO_FATAL("Unsafe to convert Column to IdColumn (%s)",
219                      column->name());
220     }
221   }
222 
223   // Helper functions to create constraints for the given value.
eq(uint32_t v)224   Constraint eq(uint32_t v) const { return eq_value(SqlValue::Long(v)); }
gt(uint32_t v)225   Constraint gt(uint32_t v) const { return gt_value(SqlValue::Long(v)); }
lt(uint32_t v)226   Constraint lt(uint32_t v) const { return lt_value(SqlValue::Long(v)); }
ne(uint32_t v)227   Constraint ne(uint32_t v) const { return ne_value(SqlValue::Long(v)); }
ge(uint32_t v)228   Constraint ge(uint32_t v) const { return ge_value(SqlValue::Long(v)); }
le(uint32_t v)229   Constraint le(uint32_t v) const { return le_value(SqlValue::Long(v)); }
230 
231  private:
232   friend class Table;
233 };
234 
235 }  // namespace trace_processor
236 }  // namespace perfetto
237 
238 #endif  // SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_H_
239