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 <cstdint> 21 #include <optional> 22 #include <type_traits> 23 #include <vector> 24 25 #include "perfetto/base/logging.h" 26 #include "perfetto/trace_processor/basic_types.h" 27 #include "src/trace_processor/containers/null_term_string_view.h" 28 #include "src/trace_processor/db/column.h" 29 #include "src/trace_processor/db/column/types.h" 30 #include "src/trace_processor/db/column_storage.h" 31 #include "src/trace_processor/db/typed_column_internal.h" 32 33 namespace perfetto::trace_processor { 34 35 // TypedColumn<T> 36 // 37 // Introduction: 38 // TypedColumn exists to allow efficient access to the data in a Column without 39 // having to go through dynamic type checking. There are two main reasons for 40 // this: 41 // 1. Performance: dynamic type checking is not free and so if this is used 42 // in a particularily hot codepath, the typechecking can be a significant 43 // overhead. 44 // 2. Ergonomics: having to convert back and forth from/to SqlValue causes 45 // signifcant clutter in parts of the code which can already be quite hard 46 // to follow (e.g. trackers like SequenceStackProfileTracker which perform 47 // cross checking of various ids). 48 // 49 // Implementation: 50 // TypedColumn is implemented as a memberless subclass of Column. This allows 51 // us to static cast from a Column* to a TypedColumn<T> where we know the 52 // type T. The methods of TypedColumn are type-specialized methods of Column 53 // which allow callers to pass real types instead of using SqlValue. 54 // 55 // There are two helper classes (tc_internal::TypeHandler and 56 // tc_internal::Serializer) where we specialize behaviour which needs to be 57 // different based on T. See their class documentation and below for details 58 // on their purpose. 59 template <typename T> 60 class TypedColumn : public ColumnLegacy { 61 private: 62 using TH = tc_internal::TypeHandler<T>; 63 64 public: 65 // The type of the data in this column. 66 using type = T; 67 68 // The non-optional type of the data in this column. 69 using non_optional_type = typename TH::non_optional_type; 70 71 // The type which should be passed to SqlValue functions. 72 using sql_value_type = typename TH::sql_value_type; 73 74 // The type of which is actually stored inside ColumnStorage. Can be different 75 // from T because we treat table ids to just be uint32_t inside the storage 76 // (handling ids would add an extra type to consider when filtering for no 77 // benefit. 78 using stored_type = typename TH::stored_type; 79 using non_optional_stored_type = 80 typename tc_internal::TypeHandler<non_optional_type>::stored_type; 81 82 private: 83 using Serializer = tc_internal::Serializer<non_optional_type>; 84 85 public: 86 T operator[](uint32_t row) const { return GetAtIdx(overlay().Get(row)); } 87 88 // Special function only for string types to allow retrieving the string 89 // directly from the column. 90 template <bool is_string = TH::is_string> GetString(uint32_t row)91 typename std::enable_if<is_string, NullTermStringView>::type GetString( 92 uint32_t row) const { 93 return string_pool().Get(storage().Get((overlay().Get(row)))); 94 } 95 96 // Sets the data in the column at index |row|. Set(uint32_t row,non_optional_type v)97 void Set(uint32_t row, non_optional_type v) { 98 auto serialized = Serializer::Serialize(v); 99 mutable_storage()->Set(overlay().Get(row), serialized); 100 } 101 102 // Inserts the value at the end of the column. Append(T v)103 void Append(T v) { mutable_storage()->Append(Serializer::Serialize(v)); } 104 ToVectorForTesting()105 std::vector<T> ToVectorForTesting() const { 106 std::vector<T> result(overlay().size()); 107 for (uint32_t i = 0; i < overlay().size(); ++i) 108 result[i] = (*this)[i]; 109 return result; 110 } 111 112 // Helper functions to create constraints for the given value. eq(sql_value_type v)113 Constraint eq(sql_value_type v) const { return eq_value(ToSqlValue(v)); } gt(sql_value_type v)114 Constraint gt(sql_value_type v) const { return gt_value(ToSqlValue(v)); } lt(sql_value_type v)115 Constraint lt(sql_value_type v) const { return lt_value(ToSqlValue(v)); } ne(sql_value_type v)116 Constraint ne(sql_value_type v) const { return ne_value(ToSqlValue(v)); } ge(sql_value_type v)117 Constraint ge(sql_value_type v) const { return ge_value(ToSqlValue(v)); } le(sql_value_type v)118 Constraint le(sql_value_type v) const { return le_value(ToSqlValue(v)); } glob(sql_value_type v)119 Constraint glob(sql_value_type v) const { return glob_value(ToSqlValue(v)); } regex(sql_value_type v)120 Constraint regex(sql_value_type v) const { 121 return regex_value(ToSqlValue(v)); 122 } 123 124 // Implements equality between two items of type |T|. Equals(T a,T b)125 static constexpr bool Equals(T a, T b) { return TH::Equals(a, b); } 126 127 // Encodes the default flags for a column of the current type. default_flags()128 static constexpr uint32_t default_flags() { 129 return TH::is_optional ? Flag::kNoFlag : Flag::kNonNull; 130 } 131 132 // Converts the static type T into the dynamic SqlValue type of this column. SqlValueType()133 static constexpr SqlValue::Type SqlValueType() { 134 return ColumnLegacy::ToSqlValueType<stored_type>(); 135 } 136 137 // Cast a Column to TypedColumn or crash if that is unsafe. FromColumn(ColumnLegacy * column)138 static TypedColumn<T>* FromColumn(ColumnLegacy* column) { 139 // While casting from a base to derived without constructing as a derived is 140 // technically UB, in practice, this is at the heart of protozero (see 141 // Message::BeginNestedMessage) so we use it here. 142 static_assert(sizeof(TypedColumn<T>) == sizeof(ColumnLegacy), 143 "TypedColumn cannot introduce extra state."); 144 145 if (column->template IsColumnType<stored_type>() && 146 (column->IsNullable() == TH::is_optional) && !column->IsId()) { 147 return static_cast<TypedColumn<T>*>(column); 148 } else { 149 PERFETTO_FATAL("Unsafe to convert Column TypedColumn (%s)", 150 column->name()); 151 } 152 } 153 154 // Public for use by macro tables. GetAtIdx(uint32_t idx)155 T GetAtIdx(uint32_t idx) const { 156 return Serializer::Deserialize(TH::Get(storage(), idx)); 157 } 158 159 private: 160 friend class Table; 161 storage()162 const ColumnStorage<stored_type>& storage() const { 163 return ColumnLegacy::storage<stored_type>(); 164 } mutable_storage()165 ColumnStorage<stored_type>* mutable_storage() { 166 return ColumnLegacy::mutable_storage<stored_type>(); 167 } 168 }; 169 170 // Represents a column containing ids. 171 template <typename Id> 172 class IdColumn : public ColumnLegacy { 173 public: 174 // The type of the data in this column. 175 using type = Id; 176 177 // The underlying type used when comparing ids. 178 using stored_type = uint32_t; 179 180 Id operator[](uint32_t row) const { return Id(overlay().Get(row)); } 181 IndexOf(Id id)182 std::optional<uint32_t> IndexOf(Id id) const { 183 return overlay().RowOf(id.value); 184 } 185 186 // Public for use by macro tables. GetAtIdx(uint32_t idx)187 Id GetAtIdx(uint32_t idx) const { return Id(idx); } 188 189 // Helper functions to create constraints for the given value. eq(uint32_t v)190 Constraint eq(uint32_t v) const { return eq_value(SqlValue::Long(v)); } gt(uint32_t v)191 Constraint gt(uint32_t v) const { return gt_value(SqlValue::Long(v)); } lt(uint32_t v)192 Constraint lt(uint32_t v) const { return lt_value(SqlValue::Long(v)); } ne(uint32_t v)193 Constraint ne(uint32_t v) const { return ne_value(SqlValue::Long(v)); } ge(uint32_t v)194 Constraint ge(uint32_t v) const { return ge_value(SqlValue::Long(v)); } le(uint32_t v)195 Constraint le(uint32_t v) const { return le_value(SqlValue::Long(v)); } 196 197 private: 198 friend class Table; 199 }; 200 201 } // namespace perfetto::trace_processor 202 203 #endif // SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_H_ 204