blob: 1e3016c23c77ebb99499effba1b3cf65438b2564 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SRC_TRACE_PROCESSOR_DB_COLUMN_H_
#define SRC_TRACE_PROCESSOR_DB_COLUMN_H_
#include <stdint.h>
#include <optional>
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/containers/string_pool.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column_storage.h"
#include "src/trace_processor/db/column_storage_overlay.h"
#include "src/trace_processor/db/compare.h"
#include "src/trace_processor/db/typed_column_internal.h"
namespace perfetto::trace_processor {
// Helper class for converting a type to a ColumnType.
template <typename T>
struct ColumnTypeHelper;
template <>
struct ColumnTypeHelper<int32_t> {
static constexpr ColumnType ToColumnType() { return ColumnType::kInt32; }
};
template <>
struct ColumnTypeHelper<uint32_t> {
static constexpr ColumnType ToColumnType() { return ColumnType::kUint32; }
};
template <>
struct ColumnTypeHelper<int64_t> {
static constexpr ColumnType ToColumnType() { return ColumnType::kInt64; }
};
template <>
struct ColumnTypeHelper<double> {
static constexpr ColumnType ToColumnType() { return ColumnType::kDouble; }
};
template <>
struct ColumnTypeHelper<StringPool::Id> {
static constexpr ColumnType ToColumnType() { return ColumnType::kString; }
};
template <typename T>
struct ColumnTypeHelper<std::optional<T>> : public ColumnTypeHelper<T> {};
class Table;
// Represents a named, strongly typed list of data.
class ColumnLegacy {
public:
// Flags which indicate properties of the data in the column. These features
// are used to speed up column methods like filtering/sorting.
enum Flag : uint32_t {
// Indicates that this column has no special properties.
kNoFlag = 0,
// Indicates the data in the column is sorted. This can be used to speed
// up filtering and skip sorting.
kSorted = 1 << 0,
// Indicates the data in the column is non-null. That is, the NullableVector
// passed in will never have any null entries. This is only used for
// numeric columns (string columns and id columns both have special
// handling which ignores this flag).
//
// This is used to speed up filters as we can safely index NullableVector
// directly if this flag is set.
kNonNull = 1 << 1,
// Indicates that the data in the column is "hidden". This can by used to
// hint to users of Table and Column that this column should not be
// displayed to the user as it is part of the internal implementation
// details of the table.
kHidden = 1 << 2,
// Indicates that the data in this column is stored densely. This
// allows for fast Set calls to change the data in the column.
//
// This flag is only meaningful for nullable columns has no effect for
// non-null columns.
kDense = 1 << 3,
// Indicates that the sorted numeric data in the column is laid out such
// that at row i, we will always have col[i] <= i and the first element, j
// of each group happens at the index j.
//
// This is a common pattern in trace processor and columns with this
// property are suffixed with "set_id" hence the name of this flag.
//
// To make this clear, here are some valid and invalid uses of this flag.
//
// Valid:
// []
// [0]
// [0, 1, 2]
// [0, 0, 2]
// [0, 0, 0, 3, 3, 5, 6, 6, 7]
//
// Invalid:
// [1]
// [0, 0, 1]
// [0, 0, 2, 5]
// [0, 0, 2, 1]
//
// If this flag is set, kSorted and kNonNull should be set. Moreover, this
// flag can only be set when the type is ColumnType::kUint32; other types
// are not supported.
kSetId = 1 << 4,
};
// Iterator over a column which conforms to std iterator interface
// to allow using std algorithms (e.g. upper_bound, lower_bound etc.).
class Iterator {
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = SqlValue;
using difference_type = uint32_t;
using pointer = uint32_t*;
using reference = uint32_t&;
Iterator(const ColumnLegacy* col, uint32_t row) : col_(col), row_(row) {}
Iterator(const Iterator&) = default;
Iterator& operator=(const Iterator&) = default;
bool operator==(const Iterator& other) const { return other.row_ == row_; }
bool operator!=(const Iterator& other) const { return !(*this == other); }
bool operator<(const Iterator& other) const { return row_ < other.row_; }
bool operator>(const Iterator& other) const { return other < *this; }
bool operator<=(const Iterator& other) const { return !(other < *this); }
bool operator>=(const Iterator& other) const { return !(*this < other); }
SqlValue operator*() const { return col_->Get(row_); }
Iterator& operator++() {
row_++;
return *this;
}
Iterator& operator--() {
row_--;
return *this;
}
Iterator& operator+=(uint32_t diff) {
row_ += diff;
return *this;
}
uint32_t operator-(const Iterator& other) const {
return row_ - other.row_;
}
uint32_t row() const { return row_; }
private:
const ColumnLegacy* col_ = nullptr;
uint32_t row_ = 0;
};
// Flags specified for an id column.
static constexpr uint32_t kIdFlags = Flag::kSorted | Flag::kNonNull;
// Flags which should *not* be inherited implicitly when a column is
// assocaited to another table.
static constexpr uint32_t kNoCrossTableInheritFlags =
ColumnLegacy::Flag::kSetId;
template <typename T>
ColumnLegacy(const char* name,
ColumnStorage<T>* storage,
/* Flag */ uint32_t flags,
uint32_t col_idx_in_table,
uint32_t row_map_idx)
: ColumnLegacy(name,
ColumnTypeHelper<stored_type<T>>::ToColumnType(),
flags,
col_idx_in_table,
row_map_idx,
storage) {}
// Create a Column backed by the same data as |column| but is associated to a
// different table and, optionally, having a different name.
ColumnLegacy(const ColumnLegacy& column,
uint32_t col_idx_in_table,
uint32_t row_map_idx,
const char* name = nullptr);
// Columns are movable but not copyable.
ColumnLegacy(ColumnLegacy&&) noexcept = default;
ColumnLegacy& operator=(ColumnLegacy&&) = default;
// Creates a Column which does not have any data backing it.
static ColumnLegacy DummyColumn(const char* name, uint32_t col_idx_in_table);
// Creates a Column which returns the index as the value of the row.
static ColumnLegacy IdColumn(uint32_t col_idx_in_table,
uint32_t overlay_idx,
const char* name = "id",
uint32_t flags = kIdFlags);
// Gets the value of the Column at the given |row|.
SqlValue Get(uint32_t row) const { return GetAtIdx(overlay().Get(row)); }
// Returns the backing RowMap for this Column.
// This function is defined out of line because of a circular dependency
// between |Table| and |Column|.
const ColumnStorageOverlay& overlay() const;
// Returns the name of the column.
const char* name() const { return name_; }
// Returns the type of this Column in terms of ColumnType.
ColumnType col_type() const { return type_; }
// Test the type of this Column.
template <typename T>
bool IsColumnType() const {
return ColumnTypeHelper<T>::ToColumnType() == type_;
}
// Returns true if this column is considered an id column.
bool IsId() const { return type_ == ColumnType::kId; }
// Returns true if this column is a nullable column.
bool IsNullable() const { return IsNullable(flags_); }
// Returns true if this column is a sorted column.
bool IsSorted() const { return IsSorted(flags_); }
// Returns true if this column is a dense column.
bool IsDense() const { return IsDense(flags_); }
// Returns true if this column is a set id column.
// Public for testing.
bool IsSetId() const { return IsSetId(flags_); }
// Returns true if this column is a dummy column.
// Public for testing.
bool IsDummy() const { return type_ == ColumnType::kDummy; }
// Returns true if this column is a hidden column.
bool IsHidden() const { return (flags_ & Flag::kHidden) != 0; }
// Returns the index of the RowMap in the containing table.
uint32_t overlay_index() const { return overlay_index_; }
// Returns the index of the current column in the containing table.
uint32_t index_in_table() const { return index_in_table_; }
// Returns a Constraint for each type of filter operation for this Column.
Constraint eq_value(SqlValue value) const {
return Constraint{index_in_table_, FilterOp::kEq, value};
}
Constraint gt_value(SqlValue value) const {
return Constraint{index_in_table_, FilterOp::kGt, value};
}
Constraint lt_value(SqlValue value) const {
return Constraint{index_in_table_, FilterOp::kLt, value};
}
Constraint ne_value(SqlValue value) const {
return Constraint{index_in_table_, FilterOp::kNe, value};
}
Constraint ge_value(SqlValue value) const {
return Constraint{index_in_table_, FilterOp::kGe, value};
}
Constraint le_value(SqlValue value) const {
return Constraint{index_in_table_, FilterOp::kLe, value};
}
Constraint is_not_null() const {
return Constraint{index_in_table_, FilterOp::kIsNotNull, SqlValue()};
}
Constraint is_null() const {
return Constraint{index_in_table_, FilterOp::kIsNull, SqlValue()};
}
Constraint glob_value(SqlValue value) const {
return Constraint{index_in_table_, FilterOp::kGlob, value};
}
Constraint regex_value(SqlValue value) const {
return Constraint{index_in_table_, FilterOp::kRegex, value};
}
// Returns an Order for each Order type for this Column.
Order ascending() const { return Order{index_in_table_, false}; }
Order descending() const { return Order{index_in_table_, true}; }
// Returns an iterator to the first entry in this column.
Iterator begin() const { return Iterator(this, 0); }
// Returns an iterator pointing beyond the last entry in this column.
Iterator end() const { return Iterator(this, overlay().size()); }
// Returns whether the given combination of flags when the column has the
// given type is valid.
template <typename T>
static constexpr bool IsFlagsAndTypeValid(uint32_t flags) {
return IsFlagsAndTypeValid(flags, ColumnTypeHelper<T>::ToColumnType());
}
template <typename T>
using stored_type = typename tc_internal::TypeHandler<T>::stored_type;
// Returns the backing sparse vector cast to contain data of type T.
// Should only be called when |type_| == ToColumnType<T>().
template <typename T>
const ColumnStorage<stored_type<T>>& storage() const {
PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_);
PERFETTO_DCHECK(tc_internal::TypeHandler<T>::is_optional == IsNullable());
return *static_cast<ColumnStorage<stored_type<T>>*>(storage_);
}
const ColumnStorageBase& storage_base() const { return *storage_; }
static SqlValue::Type ToSqlValueType(ColumnType type) {
switch (type) {
case ColumnType::kInt32:
case ColumnType::kUint32:
case ColumnType::kInt64:
case ColumnType::kId:
return SqlValue::Type::kLong;
case ColumnType::kDouble:
return SqlValue::Type::kDouble;
case ColumnType::kString:
return SqlValue::Type::kString;
case ColumnType::kDummy:
PERFETTO_FATAL("ToSqlValueType not allowed on dummy column");
}
PERFETTO_FATAL("For GCC");
}
protected:
// Returns the backing sparse vector cast to contain data of type T.
// Should only be called when |type_| == ToColumnType<T>().
template <typename T>
ColumnStorage<stored_type<T>>* mutable_storage() {
PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_);
PERFETTO_DCHECK(tc_internal::TypeHandler<T>::is_optional == IsNullable());
return static_cast<ColumnStorage<stored_type<T>>*>(storage_);
}
const StringPool& string_pool() const { return *string_pool_; }
// Returns the type of this Column in terms of SqlValue::Type.
template <typename T>
static SqlValue::Type ToSqlValueType() {
return ToSqlValueType(ColumnTypeHelper<T>::ToColumnType());
}
static SqlValue ToSqlValue(double value) { return SqlValue::Double(value); }
static SqlValue ToSqlValue(int32_t value) { return SqlValue::Long(value); }
static SqlValue ToSqlValue(uint32_t value) { return SqlValue::Long(value); }
static SqlValue ToSqlValue(int64_t value) { return SqlValue::Long(value); }
static SqlValue ToSqlValue(NullTermStringView value) {
return SqlValue::String(value.c_str());
}
private:
friend class Table;
friend class View;
// Base constructor for this class which all other constructors call into.
ColumnLegacy(const char* name,
ColumnType type,
uint32_t flags,
uint32_t col_idx_in_table,
uint32_t overlay_index,
ColumnStorageBase* nullable_vector);
ColumnLegacy(const ColumnLegacy&) = delete;
ColumnLegacy& operator=(const ColumnLegacy&) = delete;
// Gets the value of the Column at the given |idx|.
SqlValue GetAtIdx(uint32_t idx) const {
switch (type_) {
case ColumnType::kInt32:
return GetAtIdxTyped<int32_t>(idx);
case ColumnType::kUint32:
return GetAtIdxTyped<uint32_t>(idx);
case ColumnType::kInt64:
return GetAtIdxTyped<int64_t>(idx);
case ColumnType::kDouble:
return GetAtIdxTyped<double>(idx);
case ColumnType::kString: {
auto str = GetStringPoolStringAtIdx(idx).c_str();
return str == nullptr ? SqlValue() : SqlValue::String(str);
}
case ColumnType::kId:
return SqlValue::Long(idx);
case ColumnType::kDummy:
PERFETTO_FATAL("GetAtIdx not allowed on dummy column");
}
PERFETTO_FATAL("For GCC");
}
template <typename T>
SqlValue GetAtIdxTyped(uint32_t idx) const {
if (IsNullable()) {
auto opt_value = storage<std::optional<T>>().Get(idx);
return opt_value ? ToSqlValue(*opt_value) : SqlValue();
}
return ToSqlValue(storage<T>().Get(idx));
}
static constexpr bool IsDense(uint32_t flags) {
return (flags & Flag::kDense) != 0;
}
static constexpr bool IsNullable(uint32_t flags) {
return (flags & Flag::kNonNull) == 0;
}
static constexpr bool IsSetId(uint32_t flags) {
return (flags & Flag::kSetId) != 0;
}
static constexpr bool IsSorted(uint32_t flags) {
return (flags & Flag::kSorted) != 0;
}
static constexpr bool IsFlagsAndTypeValid(uint32_t flags, ColumnType type) {
return (!IsDense(flags) || IsFlagsForDenseValid(flags)) &&
(!IsSetId(flags) || IsFlagsAndTypeForSetIdValid(flags, type));
}
static constexpr bool IsFlagsForDenseValid(uint32_t flags) {
// The dense flag should only be set when the column is nullable.
return IsNullable(flags);
}
static constexpr bool IsFlagsAndTypeForSetIdValid(uint32_t flags,
ColumnType type) {
// The sorted flag should always be set for set id columns.
// The non-null flag should always be set for set id columns.
// The column type should always be kUint32.
return IsSorted(flags) && !IsNullable(flags) && type == ColumnType::kUint32;
}
// Returns the string at the index |idx|.
// Should only be called when |type_| == ColumnType::kString.
NullTermStringView GetStringPoolStringAtIdx(uint32_t idx) const {
PERFETTO_DCHECK(type_ == ColumnType::kString);
return string_pool_->Get(storage<StringPool::Id>().Get(idx));
}
void BindToTable(Table* table, StringPool* string_pool) {
PERFETTO_DCHECK(!table_);
table_ = table;
string_pool_ = string_pool;
// Check that the dense-ness of the column and the nullable vector match.
if (IsNullable() && !IsDummy()) {
bool is_storage_dense;
switch (type_) {
case ColumnType::kInt32:
is_storage_dense = storage<std::optional<int32_t>>().IsDense();
break;
case ColumnType::kUint32:
is_storage_dense = storage<std::optional<uint32_t>>().IsDense();
break;
case ColumnType::kInt64:
is_storage_dense = storage<std::optional<int64_t>>().IsDense();
break;
case ColumnType::kDouble:
is_storage_dense = storage<std::optional<double>>().IsDense();
break;
case ColumnType::kString:
PERFETTO_FATAL("String column should not be nullable");
case ColumnType::kId:
PERFETTO_FATAL("Id column should not be nullable");
case ColumnType::kDummy:
PERFETTO_FATAL("Dummy column excluded above");
}
PERFETTO_DCHECK(is_storage_dense == IsDense());
}
PERFETTO_DCHECK(IsFlagsAndTypeValid(flags_, type_));
}
// type_ is used to cast nullable_vector_ to the correct type.
ColumnType type_ = ColumnType::kInt64;
ColumnStorageBase* storage_ = nullptr;
const char* name_ = nullptr;
uint32_t flags_ = Flag::kNoFlag;
const Table* table_ = nullptr;
uint32_t index_in_table_ = 0;
uint32_t overlay_index_ = 0;
const StringPool* string_pool_ = nullptr;
};
} // namespace perfetto::trace_processor
#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_H_