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/sqlite/window_operator_table.h"
18
19 #include "src/trace_processor/sqlite/sqlite_utils.h"
20
21 namespace perfetto {
22 namespace trace_processor {
23
24 namespace {
25 using namespace sqlite_utils;
26 } // namespace
27
WindowOperatorTable(sqlite3 *,const TraceStorage *)28 WindowOperatorTable::WindowOperatorTable(sqlite3*, const TraceStorage*) {}
29
RegisterTable(sqlite3 * db,const TraceStorage * storage)30 void WindowOperatorTable::RegisterTable(sqlite3* db,
31 const TraceStorage* storage) {
32 SqliteTable::Register<WindowOperatorTable>(db, storage, "window", true);
33 }
34
Init(int,const char * const *,Schema * schema)35 util::Status WindowOperatorTable::Init(int,
36 const char* const*,
37 Schema* schema) {
38 const bool kHidden = true;
39 *schema = Schema(
40 {
41 // These are the operator columns:
42 SqliteTable::Column(Column::kRowId, "rowid", SqlValue::Type::kLong,
43 kHidden),
44 SqliteTable::Column(Column::kQuantum, "quantum",
45 SqlValue::Type::kLong, kHidden),
46 SqliteTable::Column(Column::kWindowStart, "window_start",
47 SqlValue::Type::kLong, kHidden),
48 SqliteTable::Column(Column::kWindowDur, "window_dur",
49 SqlValue::Type::kLong, kHidden),
50 // These are the ouput columns:
51 SqliteTable::Column(Column::kTs, "ts", SqlValue::Type::kLong),
52 SqliteTable::Column(Column::kDuration, "dur", SqlValue::Type::kLong),
53 SqliteTable::Column(Column::kQuantumTs, "quantum_ts",
54 SqlValue::Type::kLong),
55 },
56 {Column::kRowId});
57 return util::OkStatus();
58 }
59
CreateCursor()60 std::unique_ptr<SqliteTable::Cursor> WindowOperatorTable::CreateCursor() {
61 return std::unique_ptr<SqliteTable::Cursor>(new Cursor(this));
62 }
63
BestIndex(const QueryConstraints &,BestIndexInfo *)64 int WindowOperatorTable::BestIndex(const QueryConstraints&, BestIndexInfo*) {
65 return SQLITE_OK;
66 }
67
ModifyConstraints(QueryConstraints * qc)68 int WindowOperatorTable::ModifyConstraints(QueryConstraints* qc) {
69 // Remove ordering on timestamp if it is the only ordering as we are already
70 // sorted on TS. This makes span joining significantly faster.
71 const auto& ob = qc->order_by();
72 if (ob.size() == 1 && ob[0].iColumn == Column::kTs && !ob[0].desc) {
73 qc->mutable_order_by()->clear();
74 }
75 return SQLITE_OK;
76 }
77
Update(int argc,sqlite3_value ** argv,sqlite3_int64 *)78 int WindowOperatorTable::Update(int argc,
79 sqlite3_value** argv,
80 sqlite3_int64*) {
81 // We only support updates to ts and dur. Disallow deletes (argc == 1) and
82 // inserts (argv[0] == null).
83 if (argc < 2 || sqlite3_value_type(argv[0]) == SQLITE_NULL)
84 return SQLITE_READONLY;
85
86 int64_t new_quantum = sqlite3_value_int64(argv[3]);
87 int64_t new_start = sqlite3_value_int64(argv[4]);
88 int64_t new_dur = sqlite3_value_int64(argv[5]);
89 if (new_dur == 0) {
90 auto* err = sqlite3_mprintf("Cannot set duration of window table to zero.");
91 SetErrorMessage(err);
92 return SQLITE_ERROR;
93 }
94
95 quantum_ = new_quantum;
96 window_start_ = new_start;
97 window_dur_ = new_dur;
98
99 return SQLITE_OK;
100 }
101
Cursor(WindowOperatorTable * table)102 WindowOperatorTable::Cursor::Cursor(WindowOperatorTable* table)
103 : SqliteTable::Cursor(table), table_(table) {}
104
Filter(const QueryConstraints & qc,sqlite3_value ** argv,FilterHistory)105 int WindowOperatorTable::Cursor::Filter(const QueryConstraints& qc,
106 sqlite3_value** argv,
107 FilterHistory) {
108 *this = Cursor(table_);
109 window_start_ = table_->window_start_;
110 window_end_ = table_->window_start_ + table_->window_dur_;
111 step_size_ = table_->quantum_ == 0 ? table_->window_dur_ : table_->quantum_;
112
113 current_ts_ = window_start_;
114
115 // Set return first if there is a equals constraint on the row id asking to
116 // return the first row.
117 bool return_first = qc.constraints().size() == 1 &&
118 qc.constraints()[0].column == Column::kRowId &&
119 IsOpEq(qc.constraints()[0].op) &&
120 sqlite3_value_int(argv[0]) == 0;
121 if (return_first) {
122 filter_type_ = FilterType::kReturnFirst;
123 } else {
124 filter_type_ = FilterType::kReturnAll;
125 }
126 return SQLITE_OK;
127 }
128
Column(sqlite3_context * context,int N)129 int WindowOperatorTable::Cursor::Column(sqlite3_context* context, int N) {
130 switch (N) {
131 case Column::kQuantum: {
132 sqlite3_result_int64(context,
133 static_cast<sqlite_int64>(table_->quantum_));
134 break;
135 }
136 case Column::kWindowStart: {
137 sqlite3_result_int64(context,
138 static_cast<sqlite_int64>(table_->window_start_));
139 break;
140 }
141 case Column::kWindowDur: {
142 sqlite3_result_int(context, static_cast<int>(table_->window_dur_));
143 break;
144 }
145 case Column::kTs: {
146 sqlite3_result_int64(context, static_cast<sqlite_int64>(current_ts_));
147 break;
148 }
149 case Column::kDuration: {
150 sqlite3_result_int64(context, static_cast<sqlite_int64>(step_size_));
151 break;
152 }
153 case Column::kQuantumTs: {
154 sqlite3_result_int64(context, static_cast<sqlite_int64>(quantum_ts_));
155 break;
156 }
157 case Column::kRowId: {
158 sqlite3_result_int64(context, static_cast<sqlite_int64>(row_id_));
159 break;
160 }
161 default: {
162 PERFETTO_FATAL("Unknown column %d", N);
163 break;
164 }
165 }
166 return SQLITE_OK;
167 }
168
Next()169 int WindowOperatorTable::Cursor::Next() {
170 switch (filter_type_) {
171 case FilterType::kReturnFirst:
172 current_ts_ = window_end_;
173 break;
174 case FilterType::kReturnAll:
175 current_ts_ += step_size_;
176 quantum_ts_++;
177 break;
178 }
179 row_id_++;
180 return SQLITE_OK;
181 }
182
Eof()183 int WindowOperatorTable::Cursor::Eof() {
184 return current_ts_ >= window_end_;
185 }
186
187 } // namespace trace_processor
188 } // namespace perfetto
189