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_TABLE_H_ 18 #define SRC_TRACE_PROCESSOR_DB_TABLE_H_ 19 20 #include <stdint.h> 21 22 #include <limits> 23 #include <numeric> 24 #include <optional> 25 #include <vector> 26 27 #include "perfetto/base/logging.h" 28 #include "src/trace_processor/containers/string_pool.h" 29 #include "src/trace_processor/db/column.h" 30 #include "src/trace_processor/db/column_storage_overlay.h" 31 #include "src/trace_processor/db/typed_column.h" 32 33 namespace perfetto { 34 namespace trace_processor { 35 36 // Represents a table of data with named, strongly typed columns. 37 class Table { 38 public: 39 // Iterator over the rows of the table. 40 class Iterator { 41 public: Iterator(const Table * table)42 explicit Iterator(const Table* table) : table_(table) { 43 its_.reserve(table->overlays().size()); 44 for (const auto& rm : table->overlays()) { 45 its_.emplace_back(rm.IterateRows()); 46 } 47 } 48 49 Iterator(Iterator&&) noexcept = default; 50 Iterator& operator=(Iterator&&) = default; 51 52 Iterator(const Iterator&) = delete; 53 Iterator& operator=(const Iterator&) = delete; 54 55 // Advances the iterator to the next row of the table. Next()56 void Next() { 57 for (auto& it : its_) { 58 it.Next(); 59 } 60 } 61 62 // Returns whether the row the iterator is pointing at is valid. 63 explicit operator bool() const { return its_[0]; } 64 65 // Returns the value at the current row for column |col_idx|. Get(uint32_t col_idx)66 SqlValue Get(uint32_t col_idx) const { 67 const auto& col = table_->columns_[col_idx]; 68 return col.GetAtIdx(its_[col.overlay_index()].index()); 69 } 70 71 private: 72 const Table* table_ = nullptr; 73 std::vector<ColumnStorageOverlay::Iterator> its_; 74 }; 75 76 // Helper class storing the schema of the table. This allows decisions to be 77 // made about operations on the table without materializing the table - this 78 // may be expensive for dynamically computed tables. 79 // 80 // Subclasses of Table usually provide a method (named Schema()) to statically 81 // generate an instance of this class. 82 struct Schema { 83 struct Column { 84 std::string name; 85 SqlValue::Type type; 86 bool is_id; 87 bool is_sorted; 88 bool is_hidden; 89 bool is_set_id; 90 }; 91 std::vector<Column> columns; 92 }; 93 94 Table(); 95 virtual ~Table(); 96 97 // We explicitly define the move constructor here because we need to update 98 // the Table pointer in each column in the table. Table(Table && other)99 Table(Table&& other) noexcept { *this = std::move(other); } 100 Table& operator=(Table&& other) noexcept; 101 102 // Filters the Table using the specified filter constraints. 103 Table Filter( 104 const std::vector<Constraint>& cs, 105 RowMap::OptimizeFor optimize_for = RowMap::OptimizeFor::kMemory) const { 106 if (cs.empty()) 107 return Copy(); 108 return Apply(FilterToRowMap(cs, optimize_for)); 109 } 110 111 // Filters the Table using the specified filter constraints optionally 112 // specifying what the returned RowMap should optimize for. 113 // Returns a RowMap which, if applied to the table, would contain the rows 114 // post filter. 115 RowMap FilterToRowMap( 116 const std::vector<Constraint>& cs, 117 RowMap::OptimizeFor optimize_for = RowMap::OptimizeFor::kMemory) const { 118 RowMap rm(0, row_count_, optimize_for); 119 for (const Constraint& c : cs) { 120 columns_[c.col_idx].FilterInto(c.op, c.value, &rm); 121 } 122 return rm; 123 } 124 125 // Applies the given RowMap to the current table by picking out the rows 126 // specified in the RowMap to be present in the output table. 127 // Note: the RowMap should not reorder this table; this is guaranteed if the 128 // passed RowMap is generated using |FilterToRowMap|. Apply(RowMap rm)129 Table Apply(RowMap rm) const { 130 Table table = CopyExceptOverlays(); 131 table.row_count_ = rm.size(); 132 table.overlays_.reserve(overlays_.size()); 133 for (const ColumnStorageOverlay& map : overlays_) { 134 table.overlays_.emplace_back(map.SelectRows(rm)); 135 PERFETTO_DCHECK(table.overlays_.back().size() == table.row_count()); 136 } 137 // Pretty much any application of a RowMap will break the requirements on 138 // kSetId so remove it. 139 for (auto& col : table.columns_) { 140 col.flags_ &= ~Column::Flag::kSetId; 141 } 142 return table; 143 } 144 145 // Sorts the Table using the specified order by constraints. 146 Table Sort(const std::vector<Order>& od) const; 147 148 // Returns the column at index |idx| in the Table. GetColumn(uint32_t idx)149 const Column& GetColumn(uint32_t idx) const { return columns_[idx]; } 150 151 // Returns the column index with the given name or std::nullopt otherwise. GetColumnIndexByName(const char * name)152 std::optional<uint32_t> GetColumnIndexByName(const char* name) const { 153 auto it = std::find_if( 154 columns_.begin(), columns_.end(), 155 [name](const Column& col) { return strcmp(col.name(), name) == 0; }); 156 if (it == columns_.end()) 157 return std::nullopt; 158 return static_cast<uint32_t>(std::distance(columns_.begin(), it)); 159 } 160 161 // Returns the column with the given name or nullptr otherwise. GetColumnByName(const char * name)162 const Column* GetColumnByName(const char* name) const { 163 std::optional<uint32_t> opt_idx = GetColumnIndexByName(name); 164 if (!opt_idx) 165 return nullptr; 166 return &columns_[*opt_idx]; 167 } 168 169 template <typename T> GetTypedColumnByName(const char * name)170 const TypedColumn<T>& GetTypedColumnByName(const char* name) const { 171 return *TypedColumn<T>::FromColumn(GetColumnByName(name)); 172 } 173 174 template <typename T> GetIdColumnByName(const char * name)175 const IdColumn<T>& GetIdColumnByName(const char* name) const { 176 return *IdColumn<T>::FromColumn(GetColumnByName(name)); 177 } 178 179 // Returns the number of columns in the Table. GetColumnCount()180 uint32_t GetColumnCount() const { 181 return static_cast<uint32_t>(columns_.size()); 182 } 183 184 // Returns an iterator into the Table. IterateRows()185 Iterator IterateRows() const { return Iterator(this); } 186 187 // Creates a copy of this table. 188 Table Copy() const; 189 190 // Computes the schema of this table and returns it. ComputeSchema()191 Schema ComputeSchema() const { 192 Schema schema; 193 schema.columns.reserve(columns_.size()); 194 for (const auto& col : columns_) { 195 schema.columns.emplace_back( 196 Schema::Column{col.name(), col.type(), col.IsId(), col.IsSorted(), 197 col.IsHidden(), col.IsSetId()}); 198 } 199 return schema; 200 } 201 row_count()202 uint32_t row_count() const { return row_count_; } string_pool()203 StringPool* string_pool() const { return string_pool_; } overlays()204 const std::vector<ColumnStorageOverlay>& overlays() const { 205 return overlays_; 206 } columns()207 const std::vector<Column>& columns() const { return columns_; } 208 209 protected: 210 explicit Table(StringPool* pool); 211 CopyOverlays()212 std::vector<ColumnStorageOverlay> CopyOverlays() const { 213 std::vector<ColumnStorageOverlay> rm(overlays_.size()); 214 for (uint32_t i = 0; i < overlays_.size(); ++i) { 215 rm[i] = overlays_[i].Copy(); 216 } 217 return rm; 218 } 219 220 std::vector<ColumnStorageOverlay> overlays_; 221 std::vector<Column> columns_; 222 uint32_t row_count_ = 0; 223 224 StringPool* string_pool_ = nullptr; 225 226 private: 227 friend class Column; 228 friend class View; 229 230 Table CopyExceptOverlays() const; 231 }; 232 233 } // namespace trace_processor 234 } // namespace perfetto 235 236 #endif // SRC_TRACE_PROCESSOR_DB_TABLE_H_ 237