1 /*
2 * Copyright (C) 2018 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/storage_table.h"
18
19 namespace perfetto {
20 namespace trace_processor {
21
22 StorageTable::StorageTable() = default;
23 StorageTable::~StorageTable() = default;
24
Init(int,const char * const *)25 base::Optional<Table::Schema> StorageTable::Init(int, const char* const*) {
26 schema_ = CreateStorageSchema();
27 return schema_.ToTableSchema();
28 }
29
CreateCursor()30 std::unique_ptr<Table::Cursor> StorageTable::CreateCursor() {
31 return std::unique_ptr<Cursor>(new Cursor(this));
32 }
33
CreateBestRowIterator(const QueryConstraints & qc,sqlite3_value ** argv)34 std::unique_ptr<RowIterator> StorageTable::CreateBestRowIterator(
35 const QueryConstraints& qc,
36 sqlite3_value** argv) {
37 const auto& cs = qc.constraints();
38 auto obs = RemoveRedundantOrderBy(cs, qc.order_by());
39
40 // Figure out whether the data is already ordered and which order we should
41 // traverse the data.
42 bool is_ordered, is_desc = false;
43 std::tie(is_ordered, is_desc) = IsOrdered(obs);
44
45 // Create the range iterator and if we are sorted, just return it.
46 auto index = CreateRangeIterator(cs, argv);
47 if (!index.error().empty()) {
48 SetErrorMessage(sqlite3_mprintf(index.error().c_str()));
49 return nullptr;
50 }
51
52 if (is_ordered)
53 return index.ToRowIterator(is_desc);
54
55 // Otherwise, create the sorted vector of indices and create the vector
56 // iterator.
57 return std::unique_ptr<VectorRowIterator>(
58 new VectorRowIterator(CreateSortedIndexVector(std::move(index), obs)));
59 }
60
CreateRangeIterator(const std::vector<QueryConstraints::Constraint> & cs,sqlite3_value ** argv)61 FilteredRowIndex StorageTable::CreateRangeIterator(
62 const std::vector<QueryConstraints::Constraint>& cs,
63 sqlite3_value** argv) {
64 // Try and bound the search space to the smallest possible index region and
65 // store any leftover constraints to filter using bitvector.
66 uint32_t min_idx = 0;
67 uint32_t max_idx = RowCount();
68 std::vector<size_t> bitvector_cs;
69 for (size_t i = 0; i < cs.size(); i++) {
70 const auto& c = cs[i];
71 size_t column = static_cast<size_t>(c.iColumn);
72 auto bounds = schema_.GetColumn(column).BoundFilter(c.op, argv[i]);
73
74 min_idx = std::max(min_idx, bounds.min_idx);
75 max_idx = std::min(max_idx, bounds.max_idx);
76
77 // If the lower bound is higher than the upper bound, return a zero-sized
78 // range iterator.
79 if (min_idx >= max_idx)
80 return FilteredRowIndex(min_idx, min_idx);
81
82 if (!bounds.consumed)
83 bitvector_cs.emplace_back(i);
84 }
85
86 // Create an filter index and allow each of the columns filter on it.
87 FilteredRowIndex index(min_idx, max_idx);
88 for (const auto& c_idx : bitvector_cs) {
89 const auto& c = cs[c_idx];
90 auto* value = argv[c_idx];
91
92 const auto& schema_col = schema_.GetColumn(static_cast<size_t>(c.iColumn));
93 schema_col.Filter(c.op, value, &index);
94
95 if (!index.error().empty())
96 break;
97 }
98 return index;
99 }
100
IsOrdered(const std::vector<QueryConstraints::OrderBy> & obs)101 std::pair<bool, bool> StorageTable::IsOrdered(
102 const std::vector<QueryConstraints::OrderBy>& obs) {
103 if (obs.size() == 0)
104 return std::make_pair(true, false);
105
106 if (obs.size() != 1)
107 return std::make_pair(false, false);
108
109 const auto& ob = obs[0];
110 auto col = static_cast<size_t>(ob.iColumn);
111 return std::make_pair(schema_.GetColumn(col).HasOrdering(), ob.desc);
112 }
113
RemoveRedundantOrderBy(const std::vector<QueryConstraints::Constraint> & cs,const std::vector<QueryConstraints::OrderBy> & obs)114 std::vector<QueryConstraints::OrderBy> StorageTable::RemoveRedundantOrderBy(
115 const std::vector<QueryConstraints::Constraint>& cs,
116 const std::vector<QueryConstraints::OrderBy>& obs) {
117 std::vector<QueryConstraints::OrderBy> filtered;
118 std::set<int> equality_cols;
119 for (const auto& c : cs) {
120 if (sqlite_utils::IsOpEq(c.op))
121 equality_cols.emplace(c.iColumn);
122 }
123 for (const auto& o : obs) {
124 if (equality_cols.count(o.iColumn) > 0)
125 continue;
126 filtered.emplace_back(o);
127 }
128 return filtered;
129 }
130
CreateSortedIndexVector(FilteredRowIndex index,const std::vector<QueryConstraints::OrderBy> & obs)131 std::vector<uint32_t> StorageTable::CreateSortedIndexVector(
132 FilteredRowIndex index,
133 const std::vector<QueryConstraints::OrderBy>& obs) {
134 PERFETTO_DCHECK(obs.size() > 0);
135
136 // Retrieve the index created above from the index.
137 std::vector<uint32_t> sorted_rows = index.ToRowVector();
138
139 std::vector<StorageColumn::Comparator> comparators;
140 for (const auto& ob : obs) {
141 auto col = static_cast<size_t>(ob.iColumn);
142 comparators.emplace_back(schema_.GetColumn(col).Sort(ob));
143 }
144
145 auto comparator = [&comparators](uint32_t f, uint32_t s) {
146 for (const auto& comp : comparators) {
147 int c = comp(f, s);
148 if (c != 0)
149 return c < 0;
150 }
151 return false;
152 };
153 std::sort(sorted_rows.begin(), sorted_rows.end(), comparator);
154
155 return sorted_rows;
156 }
157
HasEqConstraint(const QueryConstraints & qc,const std::string & col_name)158 bool StorageTable::HasEqConstraint(const QueryConstraints& qc,
159 const std::string& col_name) {
160 size_t c_idx = schema().ColumnIndexFromName(col_name);
161 auto fn = [c_idx](const QueryConstraints::Constraint& c) {
162 return c.iColumn == static_cast<int>(c_idx) && sqlite_utils::IsOpEq(c.op);
163 };
164 const auto& cs = qc.constraints();
165 return std::find_if(cs.begin(), cs.end(), fn) != cs.end();
166 }
167
Cursor(StorageTable * table)168 StorageTable::Cursor::Cursor(StorageTable* table)
169 : Table::Cursor(table), table_(table) {}
170
Filter(const QueryConstraints & qc,sqlite3_value ** argv)171 int StorageTable::Cursor::Filter(const QueryConstraints& qc,
172 sqlite3_value** argv) {
173 iterator_ = table_->CreateBestRowIterator(qc, argv);
174 if (!iterator_)
175 return SQLITE_ERROR;
176 columns_ = table_->schema_.mutable_columns();
177 return SQLITE_OK;
178 }
179
Next()180 int StorageTable::Cursor::Next() {
181 iterator_->NextRow();
182 return SQLITE_OK;
183 }
184
Eof()185 int StorageTable::Cursor::Eof() {
186 return iterator_->IsEnd();
187 }
188
Column(sqlite3_context * context,int raw_col)189 int StorageTable::Cursor::Column(sqlite3_context* context, int raw_col) {
190 size_t column = static_cast<size_t>(raw_col);
191 (*columns_)[column]->ReportResult(context, iterator_->Row());
192 return SQLITE_OK;
193 }
194
195 } // namespace trace_processor
196 } // namespace perfetto
197