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 #include <optional> 22 23 #include "perfetto/base/logging.h" 24 #include "perfetto/trace_processor/basic_types.h" 25 #include "src/trace_processor/containers/row_map.h" 26 #include "src/trace_processor/containers/string_pool.h" 27 #include "src/trace_processor/db/column/types.h" 28 #include "src/trace_processor/db/column_storage.h" 29 #include "src/trace_processor/db/column_storage_overlay.h" 30 #include "src/trace_processor/db/compare.h" 31 #include "src/trace_processor/db/typed_column_internal.h" 32 33 namespace perfetto::trace_processor { 34 35 // Helper class for converting a type to a ColumnType. 36 template <typename T> 37 struct ColumnTypeHelper; 38 template <> 39 struct ColumnTypeHelper<int32_t> { 40 static constexpr ColumnType ToColumnType() { return ColumnType::kInt32; } 41 }; 42 template <> 43 struct ColumnTypeHelper<uint32_t> { 44 static constexpr ColumnType ToColumnType() { return ColumnType::kUint32; } 45 }; 46 template <> 47 struct ColumnTypeHelper<int64_t> { 48 static constexpr ColumnType ToColumnType() { return ColumnType::kInt64; } 49 }; 50 template <> 51 struct ColumnTypeHelper<double> { 52 static constexpr ColumnType ToColumnType() { return ColumnType::kDouble; } 53 }; 54 template <> 55 struct ColumnTypeHelper<StringPool::Id> { 56 static constexpr ColumnType ToColumnType() { return ColumnType::kString; } 57 }; 58 template <typename T> 59 struct ColumnTypeHelper<std::optional<T>> : public ColumnTypeHelper<T> {}; 60 61 class Table; 62 63 // Represents a named, strongly typed list of data. 64 class ColumnLegacy { 65 public: 66 // Flags which indicate properties of the data in the column. These features 67 // are used to speed up column methods like filtering/sorting. 68 enum Flag : uint32_t { 69 // Indicates that this column has no special properties. 70 kNoFlag = 0, 71 72 // Indicates the data in the column is sorted. This can be used to speed 73 // up filtering and skip sorting. 74 kSorted = 1 << 0, 75 76 // Indicates the data in the column is non-null. That is, the NullableVector 77 // passed in will never have any null entries. This is only used for 78 // numeric columns (string columns and id columns both have special 79 // handling which ignores this flag). 80 // 81 // This is used to speed up filters as we can safely index NullableVector 82 // directly if this flag is set. 83 kNonNull = 1 << 1, 84 85 // Indicates that the data in the column is "hidden". This can by used to 86 // hint to users of Table and Column that this column should not be 87 // displayed to the user as it is part of the internal implementation 88 // details of the table. 89 kHidden = 1 << 2, 90 91 // Indicates that the data in this column is stored densely. This 92 // allows for fast Set calls to change the data in the column. 93 // 94 // This flag is only meaningful for nullable columns has no effect for 95 // non-null columns. 96 kDense = 1 << 3, 97 98 // Indicates that the sorted numeric data in the column is laid out such 99 // that at row i, we will always have col[i] <= i and the first element, j 100 // of each group happens at the index j. 101 // 102 // This is a common pattern in trace processor and columns with this 103 // property are suffixed with "set_id" hence the name of this flag. 104 // 105 // To make this clear, here are some valid and invalid uses of this flag. 106 // 107 // Valid: 108 // [] 109 // [0] 110 // [0, 1, 2] 111 // [0, 0, 2] 112 // [0, 0, 0, 3, 3, 5, 6, 6, 7] 113 // 114 // Invalid: 115 // [1] 116 // [0, 0, 1] 117 // [0, 0, 2, 5] 118 // [0, 0, 2, 1] 119 // 120 // If this flag is set, kSorted and kNonNull should be set. Moreover, this 121 // flag can only be set when the type is ColumnType::kUint32; other types 122 // are not supported. 123 kSetId = 1 << 4, 124 }; 125 126 // Iterator over a column which conforms to std iterator interface 127 // to allow using std algorithms (e.g. upper_bound, lower_bound etc.). 128 class Iterator { 129 public: 130 using iterator_category = std::random_access_iterator_tag; 131 using value_type = SqlValue; 132 using difference_type = uint32_t; 133 using pointer = uint32_t*; 134 using reference = uint32_t&; 135 136 Iterator(const ColumnLegacy* col, uint32_t row) : col_(col), row_(row) {} 137 138 Iterator(const Iterator&) = default; 139 Iterator& operator=(const Iterator&) = default; 140 141 bool operator==(const Iterator& other) const { return other.row_ == row_; } 142 bool operator!=(const Iterator& other) const { return !(*this == other); } 143 bool operator<(const Iterator& other) const { return row_ < other.row_; } 144 bool operator>(const Iterator& other) const { return other < *this; } 145 bool operator<=(const Iterator& other) const { return !(other < *this); } 146 bool operator>=(const Iterator& other) const { return !(*this < other); } 147 148 SqlValue operator*() const { return col_->Get(row_); } 149 Iterator& operator++() { 150 row_++; 151 return *this; 152 } 153 Iterator& operator--() { 154 row_--; 155 return *this; 156 } 157 158 Iterator& operator+=(uint32_t diff) { 159 row_ += diff; 160 return *this; 161 } 162 uint32_t operator-(const Iterator& other) const { 163 return row_ - other.row_; 164 } 165 166 uint32_t row() const { return row_; } 167 168 private: 169 const ColumnLegacy* col_ = nullptr; 170 uint32_t row_ = 0; 171 }; 172 173 // Flags specified for an id column. 174 static constexpr uint32_t kIdFlags = Flag::kSorted | Flag::kNonNull; 175 176 // Flags which should *not* be inherited implicitly when a column is 177 // assocaited to another table. 178 static constexpr uint32_t kNoCrossTableInheritFlags = 179 ColumnLegacy::Flag::kSetId; 180 181 template <typename T> 182 ColumnLegacy(const char* name, 183 ColumnStorage<T>* storage, 184 /* Flag */ uint32_t flags, 185 uint32_t col_idx_in_table, 186 uint32_t row_map_idx) 187 : ColumnLegacy(name, 188 ColumnTypeHelper<stored_type<T>>::ToColumnType(), 189 flags, 190 col_idx_in_table, 191 row_map_idx, 192 storage) {} 193 194 // Create a Column backed by the same data as |column| but is associated to a 195 // different table and, optionally, having a different name. 196 ColumnLegacy(const ColumnLegacy& column, 197 uint32_t col_idx_in_table, 198 uint32_t row_map_idx, 199 const char* name = nullptr); 200 201 // Columns are movable but not copyable. 202 ColumnLegacy(ColumnLegacy&&) noexcept = default; 203 ColumnLegacy& operator=(ColumnLegacy&&) = default; 204 205 // Creates a Column which does not have any data backing it. 206 static ColumnLegacy DummyColumn(const char* name, uint32_t col_idx_in_table); 207 208 // Creates a Column which returns the index as the value of the row. 209 static ColumnLegacy IdColumn(uint32_t col_idx_in_table, 210 uint32_t overlay_idx, 211 const char* name = "id", 212 uint32_t flags = kIdFlags); 213 214 // Gets the value of the Column at the given |row|. 215 SqlValue Get(uint32_t row) const { return GetAtIdx(overlay().Get(row)); } 216 217 // Returns the row containing the given value in the Column. 218 std::optional<uint32_t> IndexOf(SqlValue value) const { 219 switch (type_) { 220 // TODO(lalitm): investigate whether we could make this more efficient 221 // by first checking the type of the column and comparing explicitly 222 // based on that type. 223 case ColumnType::kInt32: 224 case ColumnType::kUint32: 225 case ColumnType::kInt64: 226 case ColumnType::kDouble: 227 case ColumnType::kString: { 228 for (uint32_t i = 0; i < overlay().size(); i++) { 229 if (compare::SqlValue(Get(i), value) == 0) 230 return i; 231 } 232 return std::nullopt; 233 } 234 case ColumnType::kId: { 235 if (value.type != SqlValue::Type::kLong) 236 return std::nullopt; 237 return overlay().RowOf(static_cast<uint32_t>(value.long_value)); 238 } 239 case ColumnType::kDummy: 240 PERFETTO_FATAL("IndexOf not allowed on dummy column"); 241 } 242 PERFETTO_FATAL("For GCC"); 243 } 244 245 // Returns the minimum value in this column. Returns std::nullopt if this 246 // column is empty. 247 std::optional<SqlValue> Min() const { 248 if (overlay().empty()) 249 return std::nullopt; 250 251 if (IsSorted()) 252 return Get(0); 253 254 Iterator b(this, 0); 255 Iterator e(this, overlay().size()); 256 return *std::min_element(b, e, &compare::SqlValueComparator); 257 } 258 259 // Returns the minimum value in this column. Returns std::nullopt if this 260 // column is empty. 261 std::optional<SqlValue> Max() const { 262 if (overlay().empty()) 263 return std::nullopt; 264 265 if (IsSorted()) 266 return Get(overlay().size() - 1); 267 268 Iterator b(this, 0); 269 Iterator e(this, overlay().size()); 270 return *std::max_element(b, e, &compare::SqlValueComparator); 271 } 272 273 // Returns the backing RowMap for this Column. 274 // This function is defined out of line because of a circular dependency 275 // between |Table| and |Column|. 276 const ColumnStorageOverlay& overlay() const; 277 278 // Returns the name of the column. 279 const char* name() const { return name_; } 280 281 // Returns the type of this Column in terms of SqlValue::Type. 282 SqlValue::Type type() const { return ToSqlValueType(type_); } 283 284 // Returns the type of this Column in terms of ColumnType. 285 ColumnType col_type() const { return type_; } 286 287 // Test the type of this Column. 288 template <typename T> 289 bool IsColumnType() const { 290 return ColumnTypeHelper<T>::ToColumnType() == type_; 291 } 292 293 // Returns true if this column is considered an id column. 294 bool IsId() const { return type_ == ColumnType::kId; } 295 296 // Returns true if this column is a nullable column. 297 bool IsNullable() const { return IsNullable(flags_); } 298 299 // Returns true if this column is a sorted column. 300 bool IsSorted() const { return IsSorted(flags_); } 301 302 // Returns true if this column is a dense column. 303 bool IsDense() const { return IsDense(flags_); } 304 305 // Returns true if this column is a set id column. 306 // Public for testing. 307 bool IsSetId() const { return IsSetId(flags_); } 308 309 // Returns true if this column is a dummy column. 310 // Public for testing. 311 bool IsDummy() const { return type_ == ColumnType::kDummy; } 312 313 // Returns true if this column is a hidden column. 314 bool IsHidden() const { return (flags_ & Flag::kHidden) != 0; } 315 316 // Returns the index of the RowMap in the containing table. 317 uint32_t overlay_index() const { return overlay_index_; } 318 319 // Returns the index of the current column in the containing table. 320 uint32_t index_in_table() const { return index_in_table_; } 321 322 // Returns a Constraint for each type of filter operation for this Column. 323 Constraint eq_value(SqlValue value) const { 324 return Constraint{index_in_table_, FilterOp::kEq, value}; 325 } 326 Constraint gt_value(SqlValue value) const { 327 return Constraint{index_in_table_, FilterOp::kGt, value}; 328 } 329 Constraint lt_value(SqlValue value) const { 330 return Constraint{index_in_table_, FilterOp::kLt, value}; 331 } 332 Constraint ne_value(SqlValue value) const { 333 return Constraint{index_in_table_, FilterOp::kNe, value}; 334 } 335 Constraint ge_value(SqlValue value) const { 336 return Constraint{index_in_table_, FilterOp::kGe, value}; 337 } 338 Constraint le_value(SqlValue value) const { 339 return Constraint{index_in_table_, FilterOp::kLe, value}; 340 } 341 Constraint is_not_null() const { 342 return Constraint{index_in_table_, FilterOp::kIsNotNull, SqlValue()}; 343 } 344 Constraint is_null() const { 345 return Constraint{index_in_table_, FilterOp::kIsNull, SqlValue()}; 346 } 347 Constraint glob_value(SqlValue value) const { 348 return Constraint{index_in_table_, FilterOp::kGlob, value}; 349 } 350 351 Constraint regex_value(SqlValue value) const { 352 return Constraint{index_in_table_, FilterOp::kRegex, value}; 353 } 354 355 // Returns an Order for each Order type for this Column. 356 Order ascending() const { return Order{index_in_table_, false}; } 357 Order descending() const { return Order{index_in_table_, true}; } 358 359 // Returns an iterator to the first entry in this column. 360 Iterator begin() const { return Iterator(this, 0); } 361 362 // Returns an iterator pointing beyond the last entry in this column. 363 Iterator end() const { return Iterator(this, overlay().size()); } 364 365 // Returns whether the given combination of flags when the column has the 366 // given type is valid. 367 template <typename T> 368 static constexpr bool IsFlagsAndTypeValid(uint32_t flags) { 369 return IsFlagsAndTypeValid(flags, ColumnTypeHelper<T>::ToColumnType()); 370 } 371 372 template <typename T> 373 using stored_type = typename tc_internal::TypeHandler<T>::stored_type; 374 375 // Returns the backing sparse vector cast to contain data of type T. 376 // Should only be called when |type_| == ToColumnType<T>(). 377 template <typename T> 378 const ColumnStorage<stored_type<T>>& storage() const { 379 PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_); 380 PERFETTO_DCHECK(tc_internal::TypeHandler<T>::is_optional == IsNullable()); 381 return *static_cast<ColumnStorage<stored_type<T>>*>(storage_); 382 } 383 384 const ColumnStorageBase& storage_base() const { return *storage_; } 385 386 protected: 387 // Returns the backing sparse vector cast to contain data of type T. 388 // Should only be called when |type_| == ToColumnType<T>(). 389 template <typename T> 390 ColumnStorage<stored_type<T>>* mutable_storage() { 391 PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_); 392 PERFETTO_DCHECK(tc_internal::TypeHandler<T>::is_optional == IsNullable()); 393 return static_cast<ColumnStorage<stored_type<T>>*>(storage_); 394 } 395 396 const StringPool& string_pool() const { return *string_pool_; } 397 398 // Returns the type of this Column in terms of SqlValue::Type. 399 template <typename T> 400 static SqlValue::Type ToSqlValueType() { 401 return ToSqlValueType(ColumnTypeHelper<T>::ToColumnType()); 402 } 403 404 static SqlValue ToSqlValue(double value) { return SqlValue::Double(value); } 405 static SqlValue ToSqlValue(int32_t value) { return SqlValue::Long(value); } 406 static SqlValue ToSqlValue(uint32_t value) { return SqlValue::Long(value); } 407 static SqlValue ToSqlValue(int64_t value) { return SqlValue::Long(value); } 408 static SqlValue ToSqlValue(NullTermStringView value) { 409 return SqlValue::String(value.c_str()); 410 } 411 412 private: 413 friend class Table; 414 friend class View; 415 416 // Base constructor for this class which all other constructors call into. 417 ColumnLegacy(const char* name, 418 ColumnType type, 419 uint32_t flags, 420 uint32_t col_idx_in_table, 421 uint32_t overlay_index, 422 ColumnStorageBase* nullable_vector); 423 424 ColumnLegacy(const ColumnLegacy&) = delete; 425 ColumnLegacy& operator=(const ColumnLegacy&) = delete; 426 427 // Gets the value of the Column at the given |idx|. 428 SqlValue GetAtIdx(uint32_t idx) const { 429 switch (type_) { 430 case ColumnType::kInt32: 431 return GetAtIdxTyped<int32_t>(idx); 432 case ColumnType::kUint32: 433 return GetAtIdxTyped<uint32_t>(idx); 434 case ColumnType::kInt64: 435 return GetAtIdxTyped<int64_t>(idx); 436 case ColumnType::kDouble: 437 return GetAtIdxTyped<double>(idx); 438 case ColumnType::kString: { 439 auto str = GetStringPoolStringAtIdx(idx).c_str(); 440 return str == nullptr ? SqlValue() : SqlValue::String(str); 441 } 442 case ColumnType::kId: 443 return SqlValue::Long(idx); 444 case ColumnType::kDummy: 445 PERFETTO_FATAL("GetAtIdx not allowed on dummy column"); 446 } 447 PERFETTO_FATAL("For GCC"); 448 } 449 450 template <typename T> 451 SqlValue GetAtIdxTyped(uint32_t idx) const { 452 if (IsNullable()) { 453 auto opt_value = storage<std::optional<T>>().Get(idx); 454 return opt_value ? ToSqlValue(*opt_value) : SqlValue(); 455 } 456 return ToSqlValue(storage<T>().Get(idx)); 457 } 458 459 static constexpr bool IsDense(uint32_t flags) { 460 return (flags & Flag::kDense) != 0; 461 } 462 static constexpr bool IsNullable(uint32_t flags) { 463 return (flags & Flag::kNonNull) == 0; 464 } 465 static constexpr bool IsSetId(uint32_t flags) { 466 return (flags & Flag::kSetId) != 0; 467 } 468 static constexpr bool IsSorted(uint32_t flags) { 469 return (flags & Flag::kSorted) != 0; 470 } 471 472 static constexpr bool IsFlagsAndTypeValid(uint32_t flags, ColumnType type) { 473 return (!IsDense(flags) || IsFlagsForDenseValid(flags)) && 474 (!IsSetId(flags) || IsFlagsAndTypeForSetIdValid(flags, type)); 475 } 476 477 static constexpr bool IsFlagsForDenseValid(uint32_t flags) { 478 // The dense flag should only be set when the column is nullable. 479 return IsNullable(flags); 480 } 481 482 static constexpr bool IsFlagsAndTypeForSetIdValid(uint32_t flags, 483 ColumnType type) { 484 // The sorted flag should always be set for set id columns. 485 // The non-null flag should always be set for set id columns. 486 // The column type should always be kUint32. 487 return IsSorted(flags) && !IsNullable(flags) && type == ColumnType::kUint32; 488 } 489 490 static SqlValue::Type ToSqlValueType(ColumnType type) { 491 switch (type) { 492 case ColumnType::kInt32: 493 case ColumnType::kUint32: 494 case ColumnType::kInt64: 495 case ColumnType::kId: 496 return SqlValue::Type::kLong; 497 case ColumnType::kDouble: 498 return SqlValue::Type::kDouble; 499 case ColumnType::kString: 500 return SqlValue::Type::kString; 501 case ColumnType::kDummy: 502 PERFETTO_FATAL("ToSqlValueType not allowed on dummy column"); 503 } 504 PERFETTO_FATAL("For GCC"); 505 } 506 507 // Returns the string at the index |idx|. 508 // Should only be called when |type_| == ColumnType::kString. 509 NullTermStringView GetStringPoolStringAtIdx(uint32_t idx) const { 510 PERFETTO_DCHECK(type_ == ColumnType::kString); 511 return string_pool_->Get(storage<StringPool::Id>().Get(idx)); 512 } 513 514 void BindToTable(Table* table, StringPool* string_pool) { 515 PERFETTO_DCHECK(!table_); 516 table_ = table; 517 string_pool_ = string_pool; 518 519 // Check that the dense-ness of the column and the nullable vector match. 520 if (IsNullable() && !IsDummy()) { 521 bool is_storage_dense; 522 switch (type_) { 523 case ColumnType::kInt32: 524 is_storage_dense = storage<std::optional<int32_t>>().IsDense(); 525 break; 526 case ColumnType::kUint32: 527 is_storage_dense = storage<std::optional<uint32_t>>().IsDense(); 528 break; 529 case ColumnType::kInt64: 530 is_storage_dense = storage<std::optional<int64_t>>().IsDense(); 531 break; 532 case ColumnType::kDouble: 533 is_storage_dense = storage<std::optional<double>>().IsDense(); 534 break; 535 case ColumnType::kString: 536 PERFETTO_FATAL("String column should not be nullable"); 537 case ColumnType::kId: 538 PERFETTO_FATAL("Id column should not be nullable"); 539 case ColumnType::kDummy: 540 PERFETTO_FATAL("Dummy column excluded above"); 541 } 542 PERFETTO_DCHECK(is_storage_dense == IsDense()); 543 } 544 PERFETTO_DCHECK(IsFlagsAndTypeValid(flags_, type_)); 545 } 546 547 // type_ is used to cast nullable_vector_ to the correct type. 548 ColumnType type_ = ColumnType::kInt64; 549 ColumnStorageBase* storage_ = nullptr; 550 551 const char* name_ = nullptr; 552 uint32_t flags_ = Flag::kNoFlag; 553 const Table* table_ = nullptr; 554 uint32_t index_in_table_ = 0; 555 uint32_t overlay_index_ = 0; 556 const StringPool* string_pool_ = nullptr; 557 }; 558 559 } // namespace perfetto::trace_processor 560 561 #endif // SRC_TRACE_PROCESSOR_DB_COLUMN_H_ 562