| /* | |
| * 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_TABLE_H_ | |
| #define SRC_TRACE_PROCESSOR_DB_TABLE_H_ | |
| #include <algorithm> | |
| #include <cstdint> | |
| #include <memory> | |
| #include <optional> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include "perfetto/base/logging.h" | |
| #include "perfetto/base/status.h" | |
| #include "perfetto/trace_processor/basic_types.h" | |
| #include "perfetto/trace_processor/ref_counted.h" | |
| #include "src/trace_processor/containers/row_map.h" | |
| #include "src/trace_processor/containers/string_pool.h" | |
| #include "src/trace_processor/db/column.h" | |
| #include "src/trace_processor/db/column/data_layer.h" | |
| #include "src/trace_processor/db/column/overlay_layer.h" | |
| #include "src/trace_processor/db/column/storage_layer.h" | |
| #include "src/trace_processor/db/column/types.h" | |
| #include "src/trace_processor/db/column_storage_overlay.h" | |
| namespace perfetto::trace_processor { | |
| namespace { | |
| using OrderedIndices = column::DataLayerChain::OrderedIndices; | |
| OrderedIndices OrderedIndicesFromIndex(const std::vector<uint32_t>& index) { | |
| OrderedIndices o; | |
| o.data = index.data(); | |
| o.size = static_cast<uint32_t>(index.size()); | |
| return o; | |
| } | |
| } // namespace | |
| // Represents a table of data with named, strongly typed columns. | |
| class Table { | |
| public: | |
| // Iterator over the rows of the table. | |
| class Iterator { | |
| public: | |
| explicit Iterator(const Table* table) : table_(table) { | |
| its_.reserve(table->overlays().size()); | |
| for (const auto& rm : table->overlays()) { | |
| its_.emplace_back(rm.IterateRows()); | |
| } | |
| } | |
| // Creates an iterator which iterates over |table| by first creating | |
| // overlays by Applying |apply| to the existing overlays and using the | |
| // indices there for iteration. | |
| explicit Iterator(const Table* table, RowMap apply) : table_(table) { | |
| overlays_.reserve(table->overlays().size()); | |
| its_.reserve(table->overlays().size()); | |
| for (const auto& rm : table->overlays()) { | |
| overlays_.emplace_back(rm.SelectRows(apply)); | |
| its_.emplace_back(overlays_.back().IterateRows()); | |
| } | |
| } | |
| Iterator(Iterator&&) noexcept = default; | |
| Iterator& operator=(Iterator&&) = default; | |
| Iterator(const Iterator&) = delete; | |
| Iterator& operator=(const Iterator&) = delete; | |
| // Advances the iterator to the next row of the table. | |
| Iterator& operator++() { | |
| for (auto& it : its_) { | |
| it.Next(); | |
| } | |
| return *this; | |
| } | |
| // Returns whether the row the iterator is pointing at is valid. | |
| explicit operator bool() const { return bool(its_[0]); } | |
| // Returns the value at the current row for column |col_idx|. | |
| SqlValue Get(uint32_t col_idx) const { | |
| const auto& col = table_->columns_[col_idx]; | |
| return col.GetAtIdx(its_[col.overlay_index()].index()); | |
| } | |
| // Returns the storage index for the current row for column |col_idx|. | |
| uint32_t StorageIndexForColumn(uint32_t col_idx) const { | |
| const auto& col = table_->columns_[col_idx]; | |
| return its_[col.overlay_index()].index(); | |
| } | |
| // Returns the storage index for the last overlay. | |
| uint32_t StorageIndexForLastOverlay() const { return its_.back().index(); } | |
| private: | |
| const Table* table_ = nullptr; | |
| std::vector<ColumnStorageOverlay> overlays_; | |
| std::vector<ColumnStorageOverlay::Iterator> its_; | |
| }; | |
| // Helper class storing the schema of the table. This allows decisions to be | |
| // made about operations on the table without materializing the table - this | |
| // may be expensive for dynamically computed tables. | |
| // | |
| // Subclasses of Table usually provide a method (named Schema()) to statically | |
| // generate an instance of this class. | |
| struct Schema { | |
| struct Column { | |
| std::string name; | |
| SqlValue::Type type; | |
| bool is_id; | |
| bool is_sorted; | |
| bool is_hidden; | |
| bool is_set_id; | |
| }; | |
| std::vector<Column> columns; | |
| }; | |
| virtual ~Table(); | |
| // We explicitly define the move constructor here because we need to update | |
| // the Table pointer in each column in the table. | |
| Table(Table&& other) noexcept { *this = std::move(other); } | |
| Table& operator=(Table&& other) noexcept; | |
| // Filters and sorts the tables with the arguments specified, returning the | |
| // result as a RowMap. | |
| RowMap QueryToRowMap(const Query&) const; | |
| // Applies the RowMap |rm| onto this table and returns an iterator over the | |
| // resulting rows. | |
| Iterator QueryToIterator(const Query& q) const { | |
| return ApplyAndIterateRows(QueryToRowMap(q)); | |
| } | |
| // Do not add any further uses. | |
| // TODO(lalitm): make this private. | |
| Iterator ApplyAndIterateRows(RowMap rm) const { | |
| return Iterator(this, std::move(rm)); | |
| } | |
| std::optional<OrderedIndices> GetIndex( | |
| const std::vector<uint32_t>& cols) const { | |
| for (const auto& idx : indexes_) { | |
| if (cols.size() > idx.columns.size()) { | |
| continue; | |
| } | |
| if (std::equal(cols.begin(), cols.end(), idx.columns.begin())) { | |
| return OrderedIndicesFromIndex(idx.index); | |
| } | |
| } | |
| return std::nullopt; | |
| } | |
| // Adds an index onto column. | |
| // Returns an error if index already exists and `!replace`. | |
| base::Status CreateIndex(const std::string& name, | |
| std::vector<uint32_t> col_idxs, | |
| bool replace); | |
| // Removes index from the table. | |
| // Returns an error if index doesn't exist. | |
| base::Status DropIndex(const std::string& name); | |
| // Sorts the table using the specified order by constraints. | |
| Table Sort(const std::vector<Order>&) const; | |
| // Returns an iterator over the rows in this table. | |
| Iterator IterateRows() const { return Iterator(this); } | |
| // Creates a copy of this table. | |
| Table Copy() const; | |
| // Looks for a column in a table. | |
| // TODO(mayzner): This is not a long term function, it should be used with | |
| // caution. | |
| std::optional<uint32_t> ColumnIdxFromName(const std::string& col_name) const { | |
| auto x = std::find_if( | |
| columns_.begin(), columns_.end(), | |
| [col_name](const ColumnLegacy& col) { return col_name == col.name(); }); | |
| return x == columns_.end() ? std::nullopt | |
| : std::make_optional(x->index_in_table()); | |
| } | |
| uint32_t row_count() const { return row_count_; } | |
| const std::vector<ColumnLegacy>& columns() const { return columns_; } | |
| StringPool* string_pool() const { return string_pool_; } | |
| const std::vector<RefPtr<column::StorageLayer>>& storage_layers() const { | |
| return storage_layers_; | |
| } | |
| const std::vector<RefPtr<column::OverlayLayer>>& null_layers() const { | |
| return null_layers_; | |
| } | |
| protected: | |
| Table(StringPool*, | |
| uint32_t row_count, | |
| std::vector<ColumnLegacy>, | |
| std::vector<ColumnStorageOverlay>); | |
| void CopyLastInsertFrom(const std::vector<ColumnStorageOverlay>& overlays) { | |
| PERFETTO_DCHECK(overlays.size() <= overlays_.size()); | |
| // Add the last inserted row in each of the parent row maps to the | |
| // corresponding row map in the child. | |
| for (uint32_t i = 0; i < overlays.size(); ++i) { | |
| const ColumnStorageOverlay& other = overlays[i]; | |
| overlays_[i].Insert(other.Get(other.size() - 1)); | |
| } | |
| } | |
| void IncrementRowCountAndAddToLastOverlay() { | |
| // Also add the index of the new row to the identity row map and increment | |
| // the size. | |
| overlays_.back().Insert(row_count_++); | |
| } | |
| void OnConstructionCompleted( | |
| std::vector<RefPtr<column::StorageLayer>> storage_layers, | |
| std::vector<RefPtr<column::OverlayLayer>> null_layers, | |
| std::vector<RefPtr<column::OverlayLayer>> overlay_layers); | |
| ColumnLegacy* GetColumn(uint32_t index) { return &columns_[index]; } | |
| const std::vector<ColumnStorageOverlay>& overlays() const { | |
| return overlays_; | |
| } | |
| private: | |
| friend class ColumnLegacy; | |
| friend class QueryExecutor; | |
| struct ColumnIndex { | |
| std::string name; | |
| std::vector<uint32_t> columns; | |
| std::vector<uint32_t> index; | |
| }; | |
| bool HasNullOrOverlayLayer(uint32_t col_idx) const; | |
| void CreateChains() const; | |
| Table CopyExceptOverlays() const; | |
| void ApplyDistinct(const Query&, RowMap*) const; | |
| void ApplySort(const Query&, RowMap*) const; | |
| RowMap TryApplyIndex(const std::vector<Constraint>&, | |
| uint32_t& cs_offset) const; | |
| RowMap ApplyIdJoinConstraints(const std::vector<Constraint>&, | |
| uint32_t& cs_offset) const; | |
| const column::DataLayerChain& ChainForColumn(uint32_t col_idx) const { | |
| return *chains_[col_idx]; | |
| } | |
| StringPool* string_pool_ = nullptr; | |
| uint32_t row_count_ = 0; | |
| std::vector<ColumnStorageOverlay> overlays_; | |
| std::vector<ColumnLegacy> columns_; | |
| std::vector<RefPtr<column::StorageLayer>> storage_layers_; | |
| std::vector<RefPtr<column::OverlayLayer>> null_layers_; | |
| std::vector<RefPtr<column::OverlayLayer>> overlay_layers_; | |
| mutable std::vector<std::unique_ptr<column::DataLayerChain>> chains_; | |
| std::vector<ColumnIndex> indexes_; | |
| }; | |
| } // namespace perfetto::trace_processor | |
| #endif // SRC_TRACE_PROCESSOR_DB_TABLE_H_ |