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_SQLITE_DB_SQLITE_TABLE_H_ 18 #define SRC_TRACE_PROCESSOR_SQLITE_DB_SQLITE_TABLE_H_ 19 20 #include "src/trace_processor/db/table.h" 21 #include "src/trace_processor/sqlite/query_cache.h" 22 #include "src/trace_processor/sqlite/sqlite_table.h" 23 24 namespace perfetto { 25 namespace trace_processor { 26 27 // Implements the SQLite table interface for db tables. 28 class DbSqliteTable : public SqliteTable { 29 public: 30 enum class TableComputation { 31 // Mode when the table is static (i.e. passed in at construction 32 // time). 33 kStatic, 34 35 // Mode when table is dynamically computed at filter time. 36 kDynamic, 37 }; 38 39 // Interface which can be subclassed to allow generation of tables dynamically 40 // at filter time. 41 // This class is used to implement table-valued functions and other similar 42 // tables. 43 class DynamicTableGenerator { 44 public: 45 virtual ~DynamicTableGenerator(); 46 47 // Returns the schema of the table that will be returned by ComputeTable. 48 virtual Table::Schema CreateSchema() = 0; 49 50 // Returns the name of the dynamic table. 51 // This will be used to register the table with SQLite. 52 virtual std::string TableName() = 0; 53 54 // Returns the estimated number of rows the table would generate. 55 virtual uint32_t EstimateRowCount() = 0; 56 57 // Checks that the constraint set is valid. 58 // 59 // Returning util::OkStatus means that the required constraints are present 60 // in |qc| for dynamically computing the table (e.g. any required 61 // constraints on hidden columns for table-valued functions are present). 62 virtual util::Status ValidateConstraints(const QueryConstraints& qc) = 0; 63 64 // Dynamically computes the table given the constraints and order by 65 // vectors. 66 virtual std::unique_ptr<Table> ComputeTable( 67 const std::vector<Constraint>& cs, 68 const std::vector<Order>& ob) = 0; 69 }; 70 71 class Cursor : public SqliteTable::Cursor { 72 public: 73 Cursor(DbSqliteTable*, QueryCache*); 74 75 Cursor(Cursor&&) noexcept = default; 76 Cursor& operator=(Cursor&&) = default; 77 78 // Implementation of SqliteTable::Cursor. 79 int Filter(const QueryConstraints& qc, 80 sqlite3_value** argv, 81 FilterHistory) override; 82 int Next() override; 83 int Eof() override; 84 int Column(sqlite3_context*, int N) override; 85 86 private: 87 enum class Mode { 88 kSingleRow, 89 kTable, 90 }; 91 92 // Tries to create a sorted table to cache in |sorted_cache_table_| if the 93 // constraint set matches the requirements. 94 void TryCacheCreateSortedTable(const QueryConstraints&, FilterHistory); 95 SourceTable()96 const Table* SourceTable() const { 97 // Try and use the sorted cache table (if it exists) to speed up the 98 // sorting. Otherwise, just use the original table. 99 return sorted_cache_table_ ? &*sorted_cache_table_ : upstream_table_; 100 } 101 102 Cursor(const Cursor&) = delete; 103 Cursor& operator=(const Cursor&) = delete; 104 105 DbSqliteTable* db_sqlite_table_ = nullptr; 106 QueryCache* cache_ = nullptr; 107 108 const Table* upstream_table_ = nullptr; 109 110 // Only valid for |db_sqlite_table_->computation_| == 111 // TableComputation::kDynamic. 112 std::unique_ptr<Table> dynamic_table_; 113 114 // Only valid for Mode::kSingleRow. 115 base::Optional<uint32_t> single_row_; 116 117 // Only valid for Mode::kTable. 118 base::Optional<Table> db_table_; 119 base::Optional<Table::Iterator> iterator_; 120 121 bool eof_ = true; 122 123 // Stores a sorted version of |db_table_| sorted on a repeated equals 124 // constraint. This allows speeding up repeated subqueries in joins 125 // significantly. 126 std::shared_ptr<Table> sorted_cache_table_; 127 128 // Stores the count of repeated equality queries to decide whether it is 129 // wortwhile to sort |db_table_| to create |sorted_cache_table_|. 130 uint32_t repeated_cache_count_ = 0; 131 132 Mode mode_ = Mode::kSingleRow; 133 134 std::vector<Constraint> constraints_; 135 std::vector<Order> orders_; 136 }; 137 struct QueryCost { 138 double cost; 139 uint32_t rows; 140 }; 141 struct Context { 142 QueryCache* cache; 143 Table::Schema schema; 144 TableComputation computation; 145 146 // Only valid when computation == TableComputation::kStatic. 147 const Table* static_table; 148 149 // Only valid when computation == TableComputation::kDynamic. 150 std::unique_ptr<DynamicTableGenerator> generator; 151 }; 152 153 static void RegisterTable(sqlite3* db, 154 QueryCache* cache, 155 Table::Schema schema, 156 const Table* table, 157 const std::string& name); 158 159 static void RegisterTable(sqlite3* db, 160 QueryCache* cache, 161 std::unique_ptr<DynamicTableGenerator> generator); 162 163 DbSqliteTable(sqlite3*, Context context); 164 virtual ~DbSqliteTable() override; 165 166 // Table implementation. 167 util::Status Init(int, 168 const char* const*, 169 SqliteTable::Schema*) override final; 170 std::unique_ptr<SqliteTable::Cursor> CreateCursor() override; 171 int ModifyConstraints(QueryConstraints*) override final; 172 int BestIndex(const QueryConstraints&, BestIndexInfo*) override final; 173 174 // These static functions are useful to allow other callers to make use 175 // of them. 176 static SqliteTable::Schema ComputeSchema(const Table::Schema&, 177 const char* table_name); 178 static void ModifyConstraints(const Table::Schema&, QueryConstraints*); 179 static void BestIndex(const Table::Schema&, 180 uint32_t row_count, 181 const QueryConstraints&, 182 BestIndexInfo*); 183 184 // static for testing. 185 static QueryCost EstimateCost(const Table::Schema&, 186 uint32_t row_count, 187 const QueryConstraints& qc); 188 189 private: 190 QueryCache* cache_ = nullptr; 191 Table::Schema schema_; 192 193 TableComputation computation_ = TableComputation::kStatic; 194 195 // Only valid when computation_ == TableComputation::kStatic. 196 const Table* static_table_ = nullptr; 197 198 // Only valid when computation_ == TableComputation::kDynamic. 199 std::unique_ptr<DynamicTableGenerator> generator_; 200 }; 201 202 } // namespace trace_processor 203 } // namespace perfetto 204 205 #endif // SRC_TRACE_PROCESSOR_SQLITE_DB_SQLITE_TABLE_H_ 206