/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/trace_processor/storage_table.h" namespace perfetto { namespace trace_processor { StorageTable::StorageTable() = default; StorageTable::~StorageTable() = default; base::Optional StorageTable::Init(int, const char* const*) { schema_ = CreateStorageSchema(); return schema_.ToTableSchema(); } std::unique_ptr StorageTable::CreateCursor() { return std::unique_ptr(new Cursor(this)); } std::unique_ptr StorageTable::CreateBestRowIterator( const QueryConstraints& qc, sqlite3_value** argv) { const auto& cs = qc.constraints(); auto obs = RemoveRedundantOrderBy(cs, qc.order_by()); // Figure out whether the data is already ordered and which order we should // traverse the data. bool is_ordered, is_desc = false; std::tie(is_ordered, is_desc) = IsOrdered(obs); // Create the range iterator and if we are sorted, just return it. auto index = CreateRangeIterator(cs, argv); if (!index.error().empty()) { SetErrorMessage(sqlite3_mprintf(index.error().c_str())); return nullptr; } if (is_ordered) return index.ToRowIterator(is_desc); // Otherwise, create the sorted vector of indices and create the vector // iterator. return std::unique_ptr( new VectorRowIterator(CreateSortedIndexVector(std::move(index), obs))); } FilteredRowIndex StorageTable::CreateRangeIterator( const std::vector& cs, sqlite3_value** argv) { // Try and bound the search space to the smallest possible index region and // store any leftover constraints to filter using bitvector. uint32_t min_idx = 0; uint32_t max_idx = RowCount(); std::vector bitvector_cs; for (size_t i = 0; i < cs.size(); i++) { const auto& c = cs[i]; size_t column = static_cast(c.iColumn); auto bounds = schema_.GetColumn(column).BoundFilter(c.op, argv[i]); min_idx = std::max(min_idx, bounds.min_idx); max_idx = std::min(max_idx, bounds.max_idx); // If the lower bound is higher than the upper bound, return a zero-sized // range iterator. if (min_idx >= max_idx) return FilteredRowIndex(min_idx, min_idx); if (!bounds.consumed) bitvector_cs.emplace_back(i); } // Create an filter index and allow each of the columns filter on it. FilteredRowIndex index(min_idx, max_idx); for (const auto& c_idx : bitvector_cs) { const auto& c = cs[c_idx]; auto* value = argv[c_idx]; const auto& schema_col = schema_.GetColumn(static_cast(c.iColumn)); schema_col.Filter(c.op, value, &index); if (!index.error().empty()) break; } return index; } std::pair StorageTable::IsOrdered( const std::vector& obs) { if (obs.size() == 0) return std::make_pair(true, false); if (obs.size() != 1) return std::make_pair(false, false); const auto& ob = obs[0]; auto col = static_cast(ob.iColumn); return std::make_pair(schema_.GetColumn(col).HasOrdering(), ob.desc); } std::vector StorageTable::RemoveRedundantOrderBy( const std::vector& cs, const std::vector& obs) { std::vector filtered; std::set equality_cols; for (const auto& c : cs) { if (sqlite_utils::IsOpEq(c.op)) equality_cols.emplace(c.iColumn); } for (const auto& o : obs) { if (equality_cols.count(o.iColumn) > 0) continue; filtered.emplace_back(o); } return filtered; } std::vector StorageTable::CreateSortedIndexVector( FilteredRowIndex index, const std::vector& obs) { PERFETTO_DCHECK(obs.size() > 0); // Retrieve the index created above from the index. std::vector sorted_rows = index.ToRowVector(); std::vector comparators; for (const auto& ob : obs) { auto col = static_cast(ob.iColumn); comparators.emplace_back(schema_.GetColumn(col).Sort(ob)); } auto comparator = [&comparators](uint32_t f, uint32_t s) { for (const auto& comp : comparators) { int c = comp(f, s); if (c != 0) return c < 0; } return false; }; std::sort(sorted_rows.begin(), sorted_rows.end(), comparator); return sorted_rows; } bool StorageTable::HasEqConstraint(const QueryConstraints& qc, const std::string& col_name) { size_t c_idx = schema().ColumnIndexFromName(col_name); auto fn = [c_idx](const QueryConstraints::Constraint& c) { return c.iColumn == static_cast(c_idx) && sqlite_utils::IsOpEq(c.op); }; const auto& cs = qc.constraints(); return std::find_if(cs.begin(), cs.end(), fn) != cs.end(); } StorageTable::Cursor::Cursor(StorageTable* table) : Table::Cursor(table), table_(table) {} int StorageTable::Cursor::Filter(const QueryConstraints& qc, sqlite3_value** argv) { iterator_ = table_->CreateBestRowIterator(qc, argv); if (!iterator_) return SQLITE_ERROR; columns_ = table_->schema_.mutable_columns(); return SQLITE_OK; } int StorageTable::Cursor::Next() { iterator_->NextRow(); return SQLITE_OK; } int StorageTable::Cursor::Eof() { return iterator_->IsEnd(); } int StorageTable::Cursor::Column(sqlite3_context* context, int raw_col) { size_t column = static_cast(raw_col); (*columns_)[column]->ReportResult(context, iterator_->Row()); return SQLITE_OK; } } // namespace trace_processor } // namespace perfetto