• 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/db/table.h"
18 
19 namespace perfetto {
20 namespace trace_processor {
21 
22 Table::Table() = default;
23 Table::~Table() = default;
24 
Table(StringPool * pool,const Table * parent)25 Table::Table(StringPool* pool, const Table* parent) : string_pool_(pool) {
26   if (!parent)
27     return;
28 
29   // If this table has a parent, then copy over all the columns pointing to
30   // empty RowMaps.
31   for (uint32_t i = 0; i < parent->row_maps_.size(); ++i)
32     row_maps_.emplace_back();
33   for (const Column& col : parent->columns_)
34     columns_.emplace_back(col, this, columns_.size(), col.row_map_idx_);
35 }
36 
operator =(Table && other)37 Table& Table::operator=(Table&& other) noexcept {
38   row_count_ = other.row_count_;
39   string_pool_ = other.string_pool_;
40 
41   row_maps_ = std::move(other.row_maps_);
42   columns_ = std::move(other.columns_);
43   for (Column& col : columns_) {
44     col.table_ = this;
45   }
46   return *this;
47 }
48 
Copy() const49 Table Table::Copy() const {
50   Table table = CopyExceptRowMaps();
51   for (const RowMap& rm : row_maps_) {
52     table.row_maps_.emplace_back(rm.Copy());
53   }
54   return table;
55 }
56 
CopyExceptRowMaps() const57 Table Table::CopyExceptRowMaps() const {
58   Table table(string_pool_, nullptr);
59   table.row_count_ = row_count_;
60   for (const Column& col : columns_) {
61     table.columns_.emplace_back(col, &table, col.index_in_table(),
62                                 col.row_map_idx_);
63   }
64   return table;
65 }
66 
Sort(const std::vector<Order> & od) const67 Table Table::Sort(const std::vector<Order>& od) const {
68   if (od.empty())
69     return Copy();
70 
71   // Build an index vector with all the indices for the first |size_| rows.
72   std::vector<uint32_t> idx(row_count_);
73   std::iota(idx.begin(), idx.end(), 0);
74 
75   // As our data is columnar, it's always more efficient to sort one column
76   // at a time rather than try and sort lexiographically all at once.
77   // To preserve correctness, we need to stably sort the index vector once
78   // for each order by in *reverse* order. Reverse order is important as it
79   // preserves the lexiographical property.
80   //
81   // For example, suppose we have the following:
82   // Table {
83   //   Column x;
84   //   Column y
85   //   Column z;
86   // }
87   //
88   // Then, to sort "y asc, x desc", we could do one of two things:
89   //  1) sort the index vector all at once and on each index, we compare
90   //     y then z. This is slow as the data is columnar and we need to
91   //     repeatedly branch inside each column.
92   //  2) we can stably sort first on x desc and then sort on y asc. This will
93   //     first put all the x in the correct order such that when we sort on
94   //     y asc, we will have the correct order of x where y is the same (since
95   //     the sort is stable).
96   //
97   // TODO(lalitm): it is possible that we could sort the last constraint (i.e.
98   // the first constraint in the below loop) in a non-stable way. However, this
99   // is more subtle than it appears as we would then need special handling where
100   // there are order bys on a column which is already sorted (e.g. ts, id).
101   // Investigate whether the performance gains from this are worthwhile. This
102   // also needs changes to the constraint modification logic in DbSqliteTable
103   // which currently eliminates constraints on sorted columns.
104   for (auto it = od.rbegin(); it != od.rend(); ++it) {
105     columns_[it->col_idx].StableSort(it->desc, &idx);
106   }
107 
108   // Return a copy of this table with the RowMaps using the computed ordered
109   // RowMap.
110   Table table = CopyExceptRowMaps();
111   RowMap rm(std::move(idx));
112   for (const RowMap& map : row_maps_) {
113     table.row_maps_.emplace_back(map.SelectRows(rm));
114     PERFETTO_DCHECK(table.row_maps_.back().size() == table.row_count());
115   }
116 
117   // Remove the sorted flag from all the columns.
118   for (auto& col : table.columns_) {
119     col.flags_ &= ~Column::Flag::kSorted;
120   }
121 
122   // For the first order by, make the column flag itself as sorted.
123   table.columns_[od.front().col_idx].flags_ |= Column::Flag::kSorted;
124 
125   return table;
126 }
127 
LookupJoin(JoinKey left,const Table & other,JoinKey right)128 Table Table::LookupJoin(JoinKey left, const Table& other, JoinKey right) {
129   // The join table will have the same size and RowMaps as the left (this)
130   // table because the left column is indexing the right table.
131   Table table(string_pool_, nullptr);
132   table.row_count_ = row_count_;
133   for (const RowMap& rm : row_maps_) {
134     table.row_maps_.emplace_back(rm.Copy());
135   }
136 
137   for (const Column& col : columns_) {
138     // We skip id columns as they are misleading on join tables.
139     if (col.IsId())
140       continue;
141     table.columns_.emplace_back(col, &table, table.columns_.size(),
142                                 col.row_map_idx_);
143   }
144 
145   const Column& left_col = columns_[left.col_idx];
146   const Column& right_col = other.columns_[right.col_idx];
147 
148   // For each index in the left column, retrieve the index of the row inside
149   // the RowMap of the right column. By getting the index of the row rather
150   // than the row number itself, we can call |Apply| on the other RowMaps
151   // in the right table.
152   std::vector<uint32_t> indices(row_count_);
153   for (uint32_t i = 0; i < row_count_; ++i) {
154     SqlValue val = left_col.Get(i);
155     PERFETTO_CHECK(val.type != SqlValue::Type::kNull);
156     indices[i] = right_col.IndexOf(val).value();
157   }
158 
159   // Apply the computed RowMap to each of the right RowMaps, adding it to the
160   // join table as we go.
161   RowMap rm(std::move(indices));
162   for (const RowMap& ot : other.row_maps_) {
163     table.row_maps_.emplace_back(ot.SelectRows(rm));
164   }
165 
166   uint32_t left_row_maps_size = static_cast<uint32_t>(row_maps_.size());
167   for (const Column& col : other.columns_) {
168     // We skip id columns as they are misleading on join tables.
169     if (col.IsId())
170       continue;
171 
172     // Ensure that we offset the RowMap index by the number of RowMaps in the
173     // left table.
174     table.columns_.emplace_back(col, &table, table.columns_.size(),
175                                 col.row_map_idx_ + left_row_maps_size);
176   }
177   return table;
178 }
179 
180 }  // namespace trace_processor
181 }  // namespace perfetto
182