1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "table_base.h"
17
18 #include <cctype>
19 #include <cstring>
20
21 #include "log.h"
22
23 #define UNUSED(expr) \
24 do { \
25 static_cast<void>(expr); \
26 } while (0)
27
28 namespace SysTuning {
29 namespace TraceStreamer {
30 namespace {
31 struct TableContext {
32 TabTemplate tmplate;
33 TraceDataCache* dataCache;
34 sqlite3_module module;
35 std::string tableName;
36 };
37 } // namespace
38
~TableBase()39 TableBase::~TableBase()
40 {
41 dataCache_ = nullptr;
42 cursor_ = nullptr;
43 }
44
TableRegister(sqlite3 & db,TraceDataCache * cache,const std::string & tableName,TabTemplate tmplate)45 void TableBase::TableRegister(sqlite3& db, TraceDataCache* cache, const std::string& tableName, TabTemplate tmplate)
46 {
47 std::unique_ptr<TableContext> context(std::make_unique<TableContext>());
48 context->dataCache = cache;
49 context->tmplate = tmplate;
50 context->tableName = tableName;
51 sqlite3_module& module = context->module;
52 module = {0};
53
54 auto createFn = [](sqlite3* xdb, void* pAux, int argc, const char* const* argv, sqlite3_vtab** ppVTab,
55 char** pzErr) {
56 UNUSED(argc);
57 UNUSED(argv);
58 UNUSED(pzErr);
59 auto xdesc = static_cast<const TableContext*>(pAux);
60 auto table = xdesc->tmplate(xdesc->dataCache);
61 table->name_ = xdesc->tableName;
62 if (table->name_ == "process" || table->name_ == "thread") {
63 table->wdataCache_ = xdesc->dataCache;
64 }
65
66 table->Init(argc, argv);
67 std::string createStmt = table->CreateTableSql();
68 TS_LOGD("xCreate table %s, statement: %s", table->name_.c_str(), createStmt.c_str());
69 int ret = sqlite3_declare_vtab(xdb, createStmt.c_str());
70 if (ret != SQLITE_OK) {
71 if ((table->name_ == "span_join") || (table->name_ == "_span_join")) {
72 return ret;
73 }
74 TS_LOGE("sqlite3_declare_vtab %s faild: %s", table->name_.c_str(), createStmt.c_str());
75 return ret;
76 }
77 *ppVTab = table.release();
78 return SQLITE_OK;
79 };
80
81 auto destroyFn = [](sqlite3_vtab* t) {
82 TS_LOGD("xDestroy table %s", static_cast<TableBase*>(t)->name_.c_str());
83 delete static_cast<TableBase*>(t);
84 return SQLITE_OK;
85 };
86 module.xCreate = createFn;
87 module.xConnect = createFn;
88 module.xDisconnect = destroyFn;
89 module.xDestroy = destroyFn;
90
91 module.xOpen = [](sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor) {
92 TS_LOGD("xOpen: %s", static_cast<TableBase*>(pVTab)->name_.c_str());
93 return static_cast<TableBase*>(pVTab)->Open(ppCursor);
94 };
95
96 module.xClose = [](sqlite3_vtab_cursor* vc) {
97 TS_LOGD("xClose: %s", static_cast<Cursor*>(vc)->table_->name_.c_str());
98 delete static_cast<Cursor*>(vc);
99 return SQLITE_OK;
100 };
101
102 module.xBestIndex = [](sqlite3_vtab* pVTab, sqlite3_index_info* idxInfo) {
103 TS_LOGD("xBestIndex: %s %d", static_cast<TableBase*>(pVTab)->name_.c_str(), idxInfo->nConstraint);
104 return static_cast<TableBase*>(pVTab)->BestIndex(idxInfo);
105 };
106
107 module.xFilter = [](sqlite3_vtab_cursor* vc, int idxNum, const char* idxStr, int argc, sqlite3_value** argv) {
108 auto* c = static_cast<Cursor*>(vc);
109 c->Reset();
110 TS_LOGD("xFilter %s: [%d]%s", static_cast<Cursor*>(vc)->table_->name_.c_str(), idxNum, idxStr);
111 if (c->table_->cacheIdxNum_ != idxNum) {
112 c->table_->cacheConstraint_.Clear();
113 c->table_->cacheConstraint_.FromString(idxStr);
114 c->table_->cacheIdxNum_ = idxNum;
115 }
116 return c->Filter(c->table_->cacheConstraint_, argv);
117 };
118
119 module.xNext = [](sqlite3_vtab_cursor* vc) { return static_cast<TableBase::Cursor*>(vc)->Next(); };
120 module.xEof = [](sqlite3_vtab_cursor* vc) { return static_cast<TableBase::Cursor*>(vc)->Eof(); };
121 module.xColumn = [](sqlite3_vtab_cursor* vc, sqlite3_context* ctx, int col) {
122 static_cast<TableBase::Cursor*>(vc)->context_ = ctx;
123 return static_cast<TableBase::Cursor*>(vc)->Column(col);
124 };
125 if (tableName == "process" || tableName == "thread") {
126 module.xUpdate = [](sqlite3_vtab* pVTab, int argc, sqlite3_value** argv, sqlite3_int64* pRowid) {
127 TS_LOGD("xUpdate: %s", static_cast<TableBase*>(pVTab)->name_.c_str());
128 return static_cast<TableBase*>(pVTab)->Update(argc, argv, pRowid);
129 };
130 }
131
132 sqlite3_create_module_v2(&db, tableName.c_str(), &module, context.release(),
133 [](void* arg) { delete static_cast<TableContext*>(arg); });
134 }
135
CreateTableSql() const136 std::string TableBase::CreateTableSql() const
137 {
138 std::string stmt = "CREATE TABLE x(";
139 for (const auto& col : tableColumn_) {
140 stmt += " " + col.name_ + " " + col.type_;
141 stmt += ",";
142 }
143 stmt += " PRIMARY KEY(";
144 for (size_t i = 0; i < tablePriKey_.size(); i++) {
145 if (i != 0)
146 stmt += ", ";
147 stmt += tablePriKey_.at(i);
148 }
149 stmt += ")) WITHOUT ROWID;";
150 return stmt;
151 }
Next()152 int TableBase::Cursor::Next()
153 {
154 indexMap_->Next();
155 return SQLITE_OK;
156 }
157
Eof()158 int TableBase::Cursor::Eof()
159 {
160 return dataCache_->Cancel() || indexMap_->Eof();
161 }
CurrentRow() const162 uint32_t TableBase::Cursor::CurrentRow() const
163 {
164 return indexMap_->CurrentRow();
165 }
FilterEnd()166 void TableBase::Cursor::FilterEnd()
167 {
168 indexMap_->Sort();
169 }
BestIndex(sqlite3_index_info * idxInfo)170 int TableBase::BestIndex(sqlite3_index_info* idxInfo)
171 {
172 FilterConstraints filterConstraints;
173 for (int i = 0; i < idxInfo->nConstraint; i++) {
174 const auto& constraint = idxInfo->aConstraint[i];
175 if (constraint.usable) {
176 filterConstraints.AddConstraint(i, constraint.iColumn, constraint.op);
177 }
178 }
179 for (int i = 0; i < idxInfo->nOrderBy; i++) {
180 filterConstraints.AddOrderBy(idxInfo->aOrderBy[i].iColumn, idxInfo->aOrderBy[i].desc);
181 }
182
183 EstimatedIndexInfo estimate = {idxInfo->estimatedRows, idxInfo->estimatedCost, false};
184 EstimateFilterCost(filterConstraints, estimate);
185 idxInfo->orderByConsumed = estimate.isOrdered;
186 idxInfo->estimatedCost = estimate.estimatedCost;
187 idxInfo->estimatedRows = estimate.estimatedRows;
188
189 auto cs = filterConstraints.GetConstraints();
190 for (size_t i = 0; i < cs.size(); i++) {
191 auto& c = cs[i];
192 idxInfo->aConstraintUsage[c.idxInaConstraint].argvIndex = static_cast<int>(i + 1);
193 idxInfo->aConstraintUsage[c.idxInaConstraint].omit = c.isSupport;
194 }
195
196 std::string str;
197 filterConstraints.ToString(str);
198 char* pIdxStr = static_cast<char*>(sqlite3_malloc(str.size() + 1));
199 std::copy(str.begin(), str.end(), pIdxStr);
200 pIdxStr[str.size()] = '\0';
201 idxInfo->idxStr = pIdxStr;
202 idxInfo->needToFreeIdxStr = true;
203 idxInfo->idxNum = ++bestIndexNum_;
204
205 TS_LOGD("%s BestIndex return: %d: %s", name_.c_str(), idxInfo->idxNum, str.c_str());
206 TS_LOGD("%s, aConstraintUsage[%d]", idxInfo->idxStr, idxInfo->nConstraint);
207 for (int i = 0; i < idxInfo->nConstraint; i++) {
208 TS_LOGD("col: %d op: %d, argvindex: %d omit: %d", idxInfo->aConstraint[i].iColumn, idxInfo->aConstraint[i].op,
209 idxInfo->aConstraintUsage[i].argvIndex, idxInfo->aConstraintUsage[i].omit);
210 }
211 TS_LOGD("estimated: %lld cost:%.3f", idxInfo->estimatedRows, idxInfo->estimatedCost);
212
213 return SQLITE_OK;
214 }
215
Open(sqlite3_vtab_cursor ** ppCursor)216 int TableBase::Open(sqlite3_vtab_cursor** ppCursor)
217 {
218 *ppCursor = static_cast<sqlite3_vtab_cursor*>(CreateCursor().release());
219 return SQLITE_OK;
220 }
221
Cursor(const TraceDataCache * dataCache,TableBase * table,uint32_t rowCount)222 TableBase::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table, uint32_t rowCount)
223 : context_(nullptr), table_(table), dataCache_(dataCache), rowCount_(rowCount)
224 {
225 indexMap_ = std::make_unique<IndexMap>(0, rowCount);
226 }
227
~Cursor()228 TableBase::Cursor::~Cursor()
229 {
230 context_ = nullptr;
231 dataCache_ = nullptr;
232 }
FilterTS(unsigned char op,sqlite3_value * argv,const std::deque<InternalTime> & times)233 void TableBase::Cursor::FilterTS(unsigned char op, sqlite3_value* argv, const std::deque<InternalTime>& times)
234 {
235 auto v = static_cast<uint64_t>(sqlite3_value_int64(argv));
236 auto getValue = [](const uint64_t& row) { return row; };
237 switch (op) {
238 case SQLITE_INDEX_CONSTRAINT_EQ:
239 indexMap_->IntersectabcEqual(times, v, getValue);
240 break;
241 case SQLITE_INDEX_CONSTRAINT_GT:
242 v++;
243 case SQLITE_INDEX_CONSTRAINT_GE: {
244 indexMap_->IntersectGreaterEqual(times, v, getValue);
245 break;
246 }
247 case SQLITE_INDEX_CONSTRAINT_LE:
248 v++;
249 case SQLITE_INDEX_CONSTRAINT_LT: {
250 indexMap_->IntersectLessEqual(times, v, getValue);
251 break;
252 case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: {
253 indexMap_->RemoveNullElements(times, v);
254 break;
255 }
256 default:
257 break;
258 } // end of switch (op)
259 }
260 }
261
RowId(sqlite3_int64 * id)262 int TableBase::Cursor::RowId(sqlite3_int64* id)
263 {
264 if (dataCache_->Cancel() || indexMap_->Eof()) {
265 return SQLITE_ERROR;
266 }
267 *id = static_cast<sqlite3_int64>(indexMap_->CurrentRow());
268 return SQLITE_OK;
269 }
FilterId(unsigned char op,sqlite3_value * argv)270 void TableBase::Cursor::FilterId(unsigned char op, sqlite3_value* argv)
271 {
272 auto type = sqlite3_value_type(argv);
273 if (type != SQLITE_INTEGER) {
274 // other type consider it NULL
275 indexMap_->Intersect(0, 0);
276 return;
277 }
278 if (indexMap_->HasData()) {
279 indexMap_->CovertToIndexMap();
280 }
281
282 auto v = static_cast<TableRowId>(sqlite3_value_int64(argv));
283 switch (op) {
284 case SQLITE_INDEX_CONSTRAINT_EQ:
285 indexMap_->Intersect(v, v + 1);
286 break;
287 case SQLITE_INDEX_CONSTRAINT_GE:
288 indexMap_->Intersect(v, rowCount_);
289 break;
290 case SQLITE_INDEX_CONSTRAINT_GT:
291 v++;
292 indexMap_->Intersect(v, rowCount_);
293 break;
294 case SQLITE_INDEX_CONSTRAINT_LE:
295 v++;
296 indexMap_->Intersect(0, v);
297 break;
298 case SQLITE_INDEX_CONSTRAINT_LT:
299 indexMap_->Intersect(0, v);
300 break;
301 default:
302 // can't filter, all rows
303 break;
304 }
305 }
306 } // namespace TraceStreamer
307 } // namespace SysTuning
308