• 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 #include "src/trace_processor/sqlite/db_sqlite_table.h"
18 
19 #include "perfetto/ext/base/string_writer.h"
20 #include "src/trace_processor/containers/bit_vector.h"
21 #include "src/trace_processor/sqlite/query_cache.h"
22 #include "src/trace_processor/sqlite/sqlite_utils.h"
23 #include "src/trace_processor/tp_metatrace.h"
24 
25 namespace perfetto {
26 namespace trace_processor {
27 
28 namespace {
29 
SqliteOpToFilterOp(int sqlite_op)30 base::Optional<FilterOp> SqliteOpToFilterOp(int sqlite_op) {
31   switch (sqlite_op) {
32     case SQLITE_INDEX_CONSTRAINT_EQ:
33     case SQLITE_INDEX_CONSTRAINT_IS:
34       return FilterOp::kEq;
35     case SQLITE_INDEX_CONSTRAINT_GT:
36       return FilterOp::kGt;
37     case SQLITE_INDEX_CONSTRAINT_LT:
38       return FilterOp::kLt;
39     case SQLITE_INDEX_CONSTRAINT_ISNOT:
40     case SQLITE_INDEX_CONSTRAINT_NE:
41       return FilterOp::kNe;
42     case SQLITE_INDEX_CONSTRAINT_GE:
43       return FilterOp::kGe;
44     case SQLITE_INDEX_CONSTRAINT_LE:
45       return FilterOp::kLe;
46     case SQLITE_INDEX_CONSTRAINT_ISNULL:
47       return FilterOp::kIsNull;
48     case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
49       return FilterOp::kIsNotNull;
50     case SQLITE_INDEX_CONSTRAINT_LIKE:
51     case SQLITE_INDEX_CONSTRAINT_GLOB:
52       return base::nullopt;
53 #if SQLITE_VERSION_NUMBER >= 3038000
54     // LIMIT and OFFSET constraints were introduced in 3.38 but we
55     // still build for older versions in most places. We still need
56     // to handle this here as Chrome is very good at staying up to date
57     // with SQLite versions and crashes if we don't have this.
58     case SQLITE_INDEX_CONSTRAINT_LIMIT:
59     case SQLITE_INDEX_CONSTRAINT_OFFSET:
60       return base::nullopt;
61 #endif
62     default:
63       PERFETTO_FATAL("Currently unsupported constraint");
64   }
65 }
66 
SqliteValueToSqlValue(sqlite3_value * sqlite_val)67 SqlValue SqliteValueToSqlValue(sqlite3_value* sqlite_val) {
68   auto col_type = sqlite3_value_type(sqlite_val);
69   SqlValue value;
70   switch (col_type) {
71     case SQLITE_INTEGER:
72       value.type = SqlValue::kLong;
73       value.long_value = sqlite3_value_int64(sqlite_val);
74       break;
75     case SQLITE_TEXT:
76       value.type = SqlValue::kString;
77       value.string_value =
78           reinterpret_cast<const char*>(sqlite3_value_text(sqlite_val));
79       break;
80     case SQLITE_FLOAT:
81       value.type = SqlValue::kDouble;
82       value.double_value = sqlite3_value_double(sqlite_val);
83       break;
84     case SQLITE_BLOB:
85       value.type = SqlValue::kBytes;
86       value.bytes_value = sqlite3_value_blob(sqlite_val);
87       value.bytes_count = static_cast<size_t>(sqlite3_value_bytes(sqlite_val));
88       break;
89     case SQLITE_NULL:
90       value.type = SqlValue::kNull;
91       break;
92   }
93   return value;
94 }
95 
ColsUsedBitVector(uint64_t sqlite_cols_used,size_t col_count)96 BitVector ColsUsedBitVector(uint64_t sqlite_cols_used, size_t col_count) {
97   return BitVector::Range(
98       0, static_cast<uint32_t>(col_count), [sqlite_cols_used](uint32_t idx) {
99         // If the lowest bit of |sqlite_cols_used| is set, the first column is
100         // used. The second lowest bit corresponds to the second column etc. If
101         // the most significant bit of |sqlite_cols_used| is set, that means
102         // that any column after the first 63 columns could be used.
103         return sqlite_cols_used & (1ull << std::min(idx, 63u));
104       });
105 }
106 
107 }  // namespace
108 
DbSqliteTable(sqlite3 *,Context context)109 DbSqliteTable::DbSqliteTable(sqlite3*, Context context)
110     : cache_(context.cache),
111       schema_(std::move(context.schema)),
112       computation_(context.computation),
113       static_table_(context.static_table),
114       generator_(std::move(context.generator)) {}
115 DbSqliteTable::~DbSqliteTable() = default;
116 
RegisterTable(sqlite3 * db,QueryCache * cache,Table::Schema schema,const Table * table,const std::string & name)117 void DbSqliteTable::RegisterTable(sqlite3* db,
118                                   QueryCache* cache,
119                                   Table::Schema schema,
120                                   const Table* table,
121                                   const std::string& name) {
122   Context context{cache, schema, TableComputation::kStatic, table, nullptr};
123   SqliteTable::Register<DbSqliteTable, Context>(db, std::move(context), name);
124 }
125 
RegisterTable(sqlite3 * db,QueryCache * cache,std::unique_ptr<DynamicTableGenerator> generator)126 void DbSqliteTable::RegisterTable(
127     sqlite3* db,
128     QueryCache* cache,
129     std::unique_ptr<DynamicTableGenerator> generator) {
130   Table::Schema schema = generator->CreateSchema();
131   std::string name = generator->TableName();
132 
133   // Figure out if the table needs explicit args (in the form of constraints
134   // on hidden columns) passed to it in order to make the query valid.
135   base::Status status = generator->ValidateConstraints(
136       QueryConstraints(std::numeric_limits<uint64_t>::max()));
137   bool requires_args = !status.ok();
138 
139   Context context{cache, std::move(schema), TableComputation::kDynamic, nullptr,
140                   std::move(generator)};
141   SqliteTable::Register<DbSqliteTable, Context>(db, std::move(context), name,
142                                                 false, requires_args);
143 }
144 
Init(int,const char * const *,Schema * schema)145 base::Status DbSqliteTable::Init(int, const char* const*, Schema* schema) {
146   *schema = ComputeSchema(schema_, name().c_str());
147   return base::OkStatus();
148 }
149 
ComputeSchema(const Table::Schema & schema,const char * table_name)150 SqliteTable::Schema DbSqliteTable::ComputeSchema(const Table::Schema& schema,
151                                                  const char* table_name) {
152   std::vector<SqliteTable::Column> schema_cols;
153   for (uint32_t i = 0; i < schema.columns.size(); ++i) {
154     const auto& col = schema.columns[i];
155     schema_cols.emplace_back(i, col.name, col.type, col.is_hidden);
156   }
157 
158   // TODO(lalitm): this is hardcoded to be the id column but change this to be
159   // more generic in the future.
160   auto it = std::find_if(
161       schema.columns.begin(), schema.columns.end(),
162       [](const Table::Schema::Column& c) { return c.name == "id"; });
163   if (it == schema.columns.end()) {
164     PERFETTO_FATAL(
165         "id column not found in %s. Currently all db Tables need to contain an "
166         "id column; this constraint will be relaxed in the future.",
167         table_name);
168   }
169 
170   std::vector<size_t> primary_keys;
171   primary_keys.emplace_back(std::distance(schema.columns.begin(), it));
172   return Schema(std::move(schema_cols), std::move(primary_keys));
173 }
174 
BestIndex(const QueryConstraints & qc,BestIndexInfo * info)175 int DbSqliteTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
176   switch (computation_) {
177     case TableComputation::kStatic:
178       BestIndex(schema_, static_table_->row_count(), qc, info);
179       break;
180     case TableComputation::kDynamic:
181       base::Status status = generator_->ValidateConstraints(qc);
182       if (!status.ok())
183         return SQLITE_CONSTRAINT;
184       BestIndex(schema_, generator_->EstimateRowCount(), qc, info);
185       break;
186   }
187   return SQLITE_OK;
188 }
189 
BestIndex(const Table::Schema & schema,uint32_t row_count,const QueryConstraints & qc,BestIndexInfo * info)190 void DbSqliteTable::BestIndex(const Table::Schema& schema,
191                               uint32_t row_count,
192                               const QueryConstraints& qc,
193                               BestIndexInfo* info) {
194   auto cost_and_rows = EstimateCost(schema, row_count, qc);
195   info->estimated_cost = cost_and_rows.cost;
196   info->estimated_rows = cost_and_rows.rows;
197 
198   const auto& cs = qc.constraints();
199   for (uint32_t i = 0; i < cs.size(); ++i) {
200     // SqliteOpToFilterOp will return nullopt for any constraint which we don't
201     // support filtering ourselves. Only omit filtering by SQLite when we can
202     // handle filtering.
203     base::Optional<FilterOp> opt_op = SqliteOpToFilterOp(cs[i].op);
204     info->sqlite_omit_constraint[i] = opt_op.has_value();
205   }
206 
207   // We can sort on any column correctly.
208   info->sqlite_omit_order_by = true;
209 }
210 
ModifyConstraints(QueryConstraints * qc)211 int DbSqliteTable::ModifyConstraints(QueryConstraints* qc) {
212   ModifyConstraints(schema_, qc);
213   return SQLITE_OK;
214 }
215 
ModifyConstraints(const Table::Schema & schema,QueryConstraints * qc)216 void DbSqliteTable::ModifyConstraints(const Table::Schema& schema,
217                                       QueryConstraints* qc) {
218   using C = QueryConstraints::Constraint;
219 
220   // Reorder constraints to consider the constraints on columns which are
221   // cheaper to filter first.
222   auto* cs = qc->mutable_constraints();
223   std::sort(cs->begin(), cs->end(), [&schema](const C& a, const C& b) {
224     uint32_t a_idx = static_cast<uint32_t>(a.column);
225     uint32_t b_idx = static_cast<uint32_t>(b.column);
226     const auto& a_col = schema.columns[a_idx];
227     const auto& b_col = schema.columns[b_idx];
228 
229     // Id columns are always very cheap to filter on so try and get them
230     // first.
231     if (a_col.is_id && !b_col.is_id)
232       return true;
233 
234     // Sorted columns are also quite cheap to filter so order them after
235     // any id columns.
236     if (a_col.is_sorted && !b_col.is_sorted)
237       return true;
238 
239     // TODO(lalitm): introduce more orderings here based on empirical data.
240     return false;
241   });
242 
243   // Remove any order by constraints which also have an equality constraint.
244   auto* ob = qc->mutable_order_by();
245   {
246     auto p = [&cs](const QueryConstraints::OrderBy& o) {
247       auto inner_p = [&o](const QueryConstraints::Constraint& c) {
248         return c.column == o.iColumn && sqlite_utils::IsOpEq(c.op);
249       };
250       return std::any_of(cs->begin(), cs->end(), inner_p);
251     };
252     auto remove_it = std::remove_if(ob->begin(), ob->end(), p);
253     ob->erase(remove_it, ob->end());
254   }
255 
256   // Go through the order by constraints in reverse order and eliminate
257   // constraints until the first non-sorted column or the first order by in
258   // descending order.
259   {
260     auto p = [&schema](const QueryConstraints::OrderBy& o) {
261       const auto& col = schema.columns[static_cast<uint32_t>(o.iColumn)];
262       return o.desc || !col.is_sorted;
263     };
264     auto first_non_sorted_it = std::find_if(ob->rbegin(), ob->rend(), p);
265     auto pop_count = std::distance(ob->rbegin(), first_non_sorted_it);
266     ob->resize(ob->size() - static_cast<uint32_t>(pop_count));
267   }
268 }
269 
EstimateCost(const Table::Schema & schema,uint32_t row_count,const QueryConstraints & qc)270 DbSqliteTable::QueryCost DbSqliteTable::EstimateCost(
271     const Table::Schema& schema,
272     uint32_t row_count,
273     const QueryConstraints& qc) {
274   // Currently our cost estimation algorithm is quite simplistic but is good
275   // enough for the simplest cases.
276   // TODO(lalitm): replace hardcoded constants with either more heuristics
277   // based on the exact type of constraint or profiling the queries themselves.
278 
279   // We estimate the fixed cost of set-up and tear-down of a query in terms of
280   // the number of rows scanned.
281   constexpr double kFixedQueryCost = 1000.0;
282 
283   // Setup the variables for estimating the number of rows we will have at the
284   // end of filtering. Note that |current_row_count| should always be at least 1
285   // unless we are absolutely certain that we will return no rows as otherwise
286   // SQLite can make some bad choices.
287   uint32_t current_row_count = row_count;
288 
289   // If the table is empty, any constraint set only pays the fixed cost. Also we
290   // can return 0 as the row count as we are certain that we will return no
291   // rows.
292   if (current_row_count == 0)
293     return QueryCost{kFixedQueryCost, 0};
294 
295   // Setup the variables for estimating the cost of filtering.
296   double filter_cost = 0.0;
297   const auto& cs = qc.constraints();
298   for (const auto& c : cs) {
299     if (current_row_count < 2)
300       break;
301     const auto& col_schema = schema.columns[static_cast<uint32_t>(c.column)];
302     if (sqlite_utils::IsOpEq(c.op) && col_schema.is_id) {
303       // If we have an id equality constraint, we can very efficiently filter
304       // down to a single row in C++. However, if we're joining with another
305       // table, SQLite will do this once per row which can be extremely
306       // expensive because of all the virtual table (which is implemented using
307       // virtual function calls) machinery. Indicate this by saying that an
308       // entire filter call is ~10x the cost of iterating a single row.
309       filter_cost += 10;
310       current_row_count = 1;
311     } else if (sqlite_utils::IsOpEq(c.op)) {
312       // If there is only a single equality constraint, we have special logic
313       // to sort by that column and then binary search if we see the constraint
314       // set often. Model this by dividing by the log of the number of rows as
315       // a good approximation. Otherwise, we'll need to do a full table scan.
316       // Alternatively, if the column is sorted, we can use the same binary
317       // search logic so we have the same low cost (even better because we don't
318       // have to sort at all).
319       filter_cost += cs.size() == 1 || col_schema.is_sorted
320                          ? log2(current_row_count)
321                          : current_row_count;
322 
323       // As an extremely rough heuristic, assume that an equalty constraint will
324       // cut down the number of rows by approximately double log of the number
325       // of rows.
326       double estimated_rows = current_row_count / (2 * log2(current_row_count));
327       current_row_count = std::max(static_cast<uint32_t>(estimated_rows), 1u);
328     } else if (col_schema.is_sorted &&
329                (sqlite_utils::IsOpLe(c.op) || sqlite_utils::IsOpLt(c.op) ||
330                 sqlite_utils::IsOpGt(c.op) || sqlite_utils::IsOpGe(c.op))) {
331       // On a sorted column, if we see any partition constraints, we can do this
332       // filter very efficiently. Model this using the log of the  number of
333       // rows as a good approximation.
334       filter_cost += log2(current_row_count);
335 
336       // As an extremely rough heuristic, assume that an partition constraint
337       // will cut down the number of rows by approximately double log of the
338       // number of rows.
339       double estimated_rows = current_row_count / (2 * log2(current_row_count));
340       current_row_count = std::max(static_cast<uint32_t>(estimated_rows), 1u);
341     } else {
342       // Otherwise, we will need to do a full table scan and we estimate we will
343       // maybe (at best) halve the number of rows.
344       filter_cost += current_row_count;
345       current_row_count = std::max(current_row_count / 2u, 1u);
346     }
347   }
348 
349   // Now, to figure out the cost of sorting, multiply the final row count
350   // by |qc.order_by().size()| * log(row count). This should act as a crude
351   // estimation of the cost.
352   double sort_cost =
353       static_cast<double>(qc.order_by().size() * current_row_count) *
354       log2(current_row_count);
355 
356   // The cost of iterating rows is more expensive than just filtering the rows
357   // so multiply by an appropriate factor.
358   double iteration_cost = current_row_count * 2.0;
359 
360   // To get the final cost, add up all the individual components.
361   double final_cost =
362       kFixedQueryCost + filter_cost + sort_cost + iteration_cost;
363   return QueryCost{final_cost, current_row_count};
364 }
365 
CreateCursor()366 std::unique_ptr<SqliteTable::Cursor> DbSqliteTable::CreateCursor() {
367   return std::unique_ptr<Cursor>(new Cursor(this, cache_));
368 }
369 
Cursor(DbSqliteTable * sqlite_table,QueryCache * cache)370 DbSqliteTable::Cursor::Cursor(DbSqliteTable* sqlite_table, QueryCache* cache)
371     : SqliteTable::Cursor(sqlite_table),
372       db_sqlite_table_(sqlite_table),
373       cache_(cache) {}
374 
TryCacheCreateSortedTable(const QueryConstraints & qc,FilterHistory history)375 void DbSqliteTable::Cursor::TryCacheCreateSortedTable(
376     const QueryConstraints& qc,
377     FilterHistory history) {
378   // Check if we have a cache. Some subclasses (e.g. the flamegraph table) may
379   // pass nullptr to disable caching.
380   if (!cache_)
381     return;
382 
383   if (history == FilterHistory::kDifferent) {
384     repeated_cache_count_ = 0;
385 
386     // Check if the new constraint set is cached by another cursor.
387     sorted_cache_table_ =
388         cache_->GetIfCached(upstream_table_, qc.constraints());
389     return;
390   }
391 
392   PERFETTO_DCHECK(history == FilterHistory::kSame);
393 
394   // TODO(lalitm): all of the caching policy below should live in QueryCache and
395   // not here. This is only here temporarily to allow migration of sched without
396   // regressing UI performance and should be removed ASAP.
397 
398   // Only try and create the cached table on exactly the third time we see this
399   // constraint set.
400   constexpr uint32_t kRepeatedThreshold = 3;
401   if (sorted_cache_table_ || repeated_cache_count_++ != kRepeatedThreshold)
402     return;
403 
404   // If we have more than one constraint, we can't cache the table using
405   // this method.
406   if (qc.constraints().size() != 1)
407     return;
408 
409   // If the constraing is not an equality constraint, there's little
410   // benefit to caching
411   const auto& c = qc.constraints().front();
412   if (!sqlite_utils::IsOpEq(c.op))
413     return;
414 
415   // If the column is already sorted, we don't need to cache at all.
416   uint32_t col = static_cast<uint32_t>(c.column);
417   if (upstream_table_->GetColumn(col).IsSorted())
418     return;
419 
420   // Try again to get the result or start caching it.
421   sorted_cache_table_ =
422       cache_->GetOrCache(upstream_table_, qc.constraints(), [this, col]() {
423         return upstream_table_->Sort({Order{col, false}});
424       });
425 }
426 
Filter(const QueryConstraints & qc,sqlite3_value ** argv,FilterHistory history)427 int DbSqliteTable::Cursor::Filter(const QueryConstraints& qc,
428                                   sqlite3_value** argv,
429                                   FilterHistory history) {
430   // Clear out the iterator before filtering to ensure the destructor is run
431   // before the table's destructor.
432   iterator_ = base::nullopt;
433 
434   // We reuse this vector to reduce memory allocations on nested subqueries.
435   constraints_.resize(qc.constraints().size());
436   uint32_t constraints_pos = 0;
437   for (size_t i = 0; i < qc.constraints().size(); ++i) {
438     const auto& cs = qc.constraints()[i];
439     uint32_t col = static_cast<uint32_t>(cs.column);
440 
441     // If we get a nullopt FilterOp, that means we should allow SQLite
442     // to handle the constraint.
443     base::Optional<FilterOp> opt_op = SqliteOpToFilterOp(cs.op);
444     if (!opt_op)
445       continue;
446 
447     SqlValue value = SqliteValueToSqlValue(argv[i]);
448     constraints_[constraints_pos++] = Constraint{col, *opt_op, value};
449   }
450   constraints_.resize(constraints_pos);
451 
452   // We reuse this vector to reduce memory allocations on nested subqueries.
453   orders_.resize(qc.order_by().size());
454   for (size_t i = 0; i < qc.order_by().size(); ++i) {
455     const auto& ob = qc.order_by()[i];
456     uint32_t col = static_cast<uint32_t>(ob.iColumn);
457     orders_[i] = Order{col, static_cast<bool>(ob.desc)};
458   }
459 
460   // Setup the upstream table based on the computation state.
461   switch (db_sqlite_table_->computation_) {
462     case TableComputation::kStatic:
463       // If we have a static table, just set the upstream table to be the static
464       // table.
465       upstream_table_ = db_sqlite_table_->static_table_;
466 
467       // Tries to create a sorted cached table which can be used to speed up
468       // filters below.
469       TryCacheCreateSortedTable(qc, history);
470       break;
471     case TableComputation::kDynamic: {
472       PERFETTO_TP_TRACE("DYNAMIC_TABLE_GENERATE", [this](metatrace::Record* r) {
473         r->AddArg("Table", db_sqlite_table_->name());
474       });
475       // If we have a dynamically created table, regenerate the table based on
476       // the new constraints.
477       std::unique_ptr<Table> computed_table;
478       BitVector cols_used_bv = ColsUsedBitVector(
479           qc.cols_used(), db_sqlite_table_->schema_.columns.size());
480       auto status = db_sqlite_table_->generator_->ComputeTable(
481           constraints_, orders_, cols_used_bv, computed_table);
482 
483       if (!status.ok()) {
484         auto* sqlite_err = sqlite3_mprintf(
485             "%s: %s", db_sqlite_table_->name().c_str(), status.c_message());
486         db_sqlite_table_->SetErrorMessage(sqlite_err);
487         return SQLITE_CONSTRAINT;
488       }
489       PERFETTO_DCHECK(computed_table);
490       dynamic_table_ = std::move(computed_table);
491       upstream_table_ = dynamic_table_.get();
492       break;
493     }
494   }
495 
496   PERFETTO_TP_TRACE("DB_TABLE_FILTER_AND_SORT", [this](metatrace::Record* r) {
497     const Table* source = SourceTable();
498     char buffer[2048];
499     for (const Constraint& c : constraints_) {
500       base::StringWriter writer(buffer, sizeof(buffer));
501       writer.AppendString(source->GetColumn(c.col_idx).name());
502 
503       writer.AppendChar(' ');
504       switch (c.op) {
505         case FilterOp::kEq:
506           writer.AppendString("=");
507           break;
508         case FilterOp::kGe:
509           writer.AppendString(">=");
510           break;
511         case FilterOp::kGt:
512           writer.AppendString(">");
513           break;
514         case FilterOp::kLe:
515           writer.AppendString("<=");
516           break;
517         case FilterOp::kLt:
518           writer.AppendString("<");
519           break;
520         case FilterOp::kNe:
521           writer.AppendString("!=");
522           break;
523         case FilterOp::kIsNull:
524           writer.AppendString("IS");
525           break;
526         case FilterOp::kIsNotNull:
527           writer.AppendString("IS NOT");
528           break;
529       }
530       writer.AppendChar(' ');
531 
532       switch (c.value.type) {
533         case SqlValue::kString:
534           writer.AppendString(c.value.AsString());
535           break;
536         case SqlValue::kBytes:
537           writer.AppendString("<bytes>");
538           break;
539         case SqlValue::kNull:
540           writer.AppendString("<null>");
541           break;
542         case SqlValue::kDouble: {
543           writer.AppendDouble(c.value.AsDouble());
544           break;
545         }
546         case SqlValue::kLong: {
547           writer.AppendInt(c.value.AsLong());
548           break;
549         }
550       }
551       r->AddArg("Table", db_sqlite_table_->name());
552       r->AddArg("Constraint", writer.GetStringView());
553     }
554 
555     for (const auto& o : orders_) {
556       base::StringWriter writer(buffer, sizeof(buffer));
557       writer.AppendString(source->GetColumn(o.col_idx).name());
558       if (o.desc)
559         writer.AppendString(" desc");
560       r->AddArg("Order by", writer.GetStringView());
561     }
562   });
563 
564   // Attempt to filter into a RowMap first - weall figure out whether to apply
565   // this to the table or we should use the RowMap directly. Also, if we are
566   // going to sort on the RowMap, it makes sense that we optimize for lookup
567   // speed so our sorting is not super slow.
568   RowMap::OptimizeFor optimize_for = orders_.empty()
569                                          ? RowMap::OptimizeFor::kMemory
570                                          : RowMap::OptimizeFor::kLookupSpeed;
571   RowMap filter_map = SourceTable()->FilterToRowMap(constraints_, optimize_for);
572 
573   // If we have no order by constraints and it's cheap for us to use the
574   // RowMap, just use the RowMap directoy.
575   if (filter_map.IsRange() && filter_map.size() <= 1) {
576     // Currently, our criteria where we have a special fast path is if it's
577     // a single ranged row. We have tihs fast path for joins on id columns
578     // where we get repeated queries filtering down to a single row. The
579     // other path performs allocations when creating the new table as well
580     // as the iterator on the new table whereas this path only uses a single
581     // number and lives entirely on the stack.
582 
583     // TODO(lalitm): investigate some other criteria where it is beneficial
584     // to have a fast path and expand to them.
585     mode_ = Mode::kSingleRow;
586     single_row_ = filter_map.size() == 1
587                       ? base::make_optional(filter_map.Get(0))
588                       : base::nullopt;
589     eof_ = !single_row_.has_value();
590   } else {
591     mode_ = Mode::kTable;
592 
593     db_table_ = SourceTable()->Apply(std::move(filter_map));
594     if (!orders_.empty())
595       db_table_ = db_table_->Sort(orders_);
596 
597     iterator_ = db_table_->IterateRows();
598 
599     eof_ = !*iterator_;
600   }
601 
602   return SQLITE_OK;
603 }
604 
Next()605 int DbSqliteTable::Cursor::Next() {
606   if (mode_ == Mode::kSingleRow) {
607     eof_ = true;
608   } else {
609     iterator_->Next();
610     eof_ = !*iterator_;
611   }
612   return SQLITE_OK;
613 }
614 
Eof()615 int DbSqliteTable::Cursor::Eof() {
616   return eof_;
617 }
618 
Column(sqlite3_context * ctx,int raw_col)619 int DbSqliteTable::Cursor::Column(sqlite3_context* ctx, int raw_col) {
620   uint32_t column = static_cast<uint32_t>(raw_col);
621   SqlValue value = mode_ == Mode::kSingleRow
622                        ? SourceTable()->GetColumn(column).Get(*single_row_)
623                        : iterator_->Get(column);
624   // We can say kSqliteStatic for strings  because all strings are expected to
625   // come from the string pool and thus will be valid for the lifetime
626   // of trace processor.
627   // Similarily for bytes we can also use kSqliteStatic because for our iterator
628   // will hold onto the pointer as long as we don't call Next() but that only
629   // happens with Next() is called on the Cursor itself at which point
630   // SQLite no longer cares about the bytes pointer.
631   sqlite_utils::ReportSqlValue(ctx, value, sqlite_utils::kSqliteStatic,
632                                sqlite_utils::kSqliteStatic);
633   return SQLITE_OK;
634 }
635 
636 DbSqliteTable::DynamicTableGenerator::~DynamicTableGenerator() = default;
637 
638 }  // namespace trace_processor
639 }  // namespace perfetto
640