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