• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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 <cmath>
20 #include <cstring>
21 
22 namespace SysTuning {
23 namespace TraceStreamer {
24 namespace {
25 struct TableContext {
26     TabTemplate tmplate;
27     TraceDataCache *dataCache;
28     sqlite3_module module;
29     std::string tableName;
30 };
31 } // namespace
32 
~TableBase()33 TableBase::~TableBase()
34 {
35     dataCache_ = nullptr;
36     cursor_ = nullptr;
37 }
38 
TableRegister(sqlite3 & db,TraceDataCache * cache,const std::string & tableName,TabTemplate tmplate)39 void TableBase::TableRegister(sqlite3 &db, TraceDataCache *cache, const std::string &tableName, TabTemplate tmplate)
40 {
41     std::unique_ptr<TableContext> context(std::make_unique<TableContext>());
42     context->dataCache = cache;
43     context->tmplate = tmplate;
44     context->tableName = tableName;
45     sqlite3_module &module = context->module;
46     module = {0};
47 
48     auto createFn = [](sqlite3 *xdb, void *pAux, int32_t argc, const char *const *argv, sqlite3_vtab **ppVTab,
49                        char **pzErr) {
50         Unused(argc);
51         Unused(argv);
52         Unused(pzErr);
53         auto xdesc = static_cast<const TableContext *>(pAux);
54         auto table = xdesc->tmplate(xdesc->dataCache);
55         table->name_ = xdesc->tableName;
56         if (table->name_ == "process" || table->name_ == "thread") {
57             table->wdataCache_ = xdesc->dataCache;
58         }
59 
60         table->Init(argc, argv);
61         std::string createStmt = table->CreateTableSql();
62         TS_LOGD("xCreate table %s, statement: %s", table->name_.c_str(), createStmt.c_str());
63         int32_t ret = sqlite3_declare_vtab(xdb, createStmt.c_str());
64         if (ret != SQLITE_OK) {
65             if ((table->name_ == "span_join") || (table->name_ == "_span_join")) {
66                 return ret;
67             }
68             TS_LOGE("sqlite3_declare_vtab %s faild: %s", table->name_.c_str(), createStmt.c_str());
69             return ret;
70         }
71         *ppVTab = table.release();
72         return SQLITE_OK;
73     };
74 
75     auto destroyFn = [](sqlite3_vtab *t) {
76         TS_LOGD("xDestroy table %s", static_cast<TableBase *>(t)->name_.c_str());
77         delete static_cast<TableBase *>(t);
78         return SQLITE_OK;
79     };
80     module.xCreate = createFn;
81     module.xConnect = createFn;
82     module.xDisconnect = destroyFn;
83     module.xDestroy = destroyFn;
84 
85     SetModuleCallbacks(module, tableName);
86     sqlite3_create_module_v2(&db, tableName.c_str(), &module, context.release(),
87                              [](void *arg) { delete static_cast<TableContext *>(arg); });
88 }
89 
SetModuleCallbacks(sqlite3_module & module,const std::string & tableName)90 void TableBase::SetModuleCallbacks(sqlite3_module &module, const std::string &tableName)
91 {
92     module.xOpen = [](sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {
93         TS_LOGD("xOpen: %s", static_cast<TableBase *>(pVTab)->name_.c_str());
94         return static_cast<TableBase *>(pVTab)->Open(ppCursor);
95     };
96 
97     module.xClose = [](sqlite3_vtab_cursor *vc) {
98         TS_LOGD("xClose: %s", static_cast<Cursor *>(vc)->table_->name_.c_str());
99         delete static_cast<Cursor *>(vc);
100         return SQLITE_OK;
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, int32_t idxNum, const char *idxStr, int32_t argc,
108                         sqlite3_value **argv) {
109         auto *c = static_cast<Cursor *>(vc);
110         c->Reset();
111         TS_LOGD("xFilter %s: [%d]%s", static_cast<Cursor *>(vc)->table_->name_.c_str(), idxNum, idxStr);
112         if (c->table_->cacheIdxNum_ != idxNum) {
113             c->table_->cacheConstraint_.Clear();
114             c->table_->cacheConstraint_.FromString(idxStr);
115             c->table_->cacheIdxNum_ = idxNum;
116         }
117         return c->Filter(c->table_->cacheConstraint_, argv);
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, int32_t 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, int32_t 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 
CreateTableSql() const133 std::string TableBase::CreateTableSql() const
134 {
135     std::string stmt = "CREATE TABLE x(";
136     for (const auto &col : tableColumn_) {
137         stmt += " " + col.name_ + " " + col.type_;
138         stmt += ",";
139     }
140     stmt += " PRIMARY KEY(";
141     for (size_t i = 0; i < tablePriKey_.size(); i++) {
142         if (i != 0)
143             stmt += ", ";
144         stmt += tablePriKey_.at(i);
145     }
146     stmt += ")) WITHOUT ROWID;";
147     return stmt;
148 }
Next()149 int32_t TableBase::Cursor::Next()
150 {
151     indexMap_->Next();
152     return SQLITE_OK;
153 }
154 
Eof()155 int32_t TableBase::Cursor::Eof()
156 {
157     return dataCache_->Cancel() || indexMap_->Eof();
158 }
CurrentRow() const159 uint32_t TableBase::Cursor::CurrentRow() const
160 {
161     return indexMap_->CurrentRow();
162 }
FilterEnd()163 void TableBase::Cursor::FilterEnd()
164 {
165     indexMap_->Sort();
166 }
BestIndex(sqlite3_index_info * idxInfo)167 int32_t TableBase::BestIndex(sqlite3_index_info *idxInfo)
168 {
169     FilterConstraints filterConstraints;
170     for (int32_t i = 0; i < idxInfo->nConstraint; i++) {
171         const auto &constraint = idxInfo->aConstraint[i];
172         if (constraint.usable) {
173             filterConstraints.AddConstraint(i, constraint.iColumn, constraint.op);
174         }
175     }
176     for (int32_t i = 0; i < idxInfo->nOrderBy; i++) {
177         filterConstraints.AddOrderBy(idxInfo->aOrderBy[i].iColumn, idxInfo->aOrderBy[i].desc);
178     }
179 
180     EstimatedIndexInfo estimate = {idxInfo->estimatedRows, idxInfo->estimatedCost, false};
181     EstimateFilterCost(filterConstraints, estimate);
182     idxInfo->orderByConsumed = estimate.isOrdered;
183     idxInfo->estimatedCost = estimate.estimatedCost;
184     idxInfo->estimatedRows = estimate.estimatedRows;
185 
186     auto cs = filterConstraints.GetConstraints();
187     for (size_t i = 0; i < cs.size(); i++) {
188         auto &c = cs[i];
189         idxInfo->aConstraintUsage[c.idxInaConstraint].argvIndex = static_cast<int32_t>(i + 1);
190         idxInfo->aConstraintUsage[c.idxInaConstraint].omit = c.isSupport;
191     }
192 
193     std::string str;
194     filterConstraints.ToString(str);
195     char *pIdxStr = static_cast<char *>(sqlite3_malloc(str.size() + 1));
196     std::copy(str.begin(), str.end(), pIdxStr);
197     pIdxStr[str.size()] = '\0';
198     idxInfo->idxStr = pIdxStr;
199     idxInfo->needToFreeIdxStr = true;
200     idxInfo->idxNum = ++bestIndexNum_;
201 
202     TS_LOGD("%s BestIndex return: %d: %s", name_.c_str(), idxInfo->idxNum, str.c_str());
203     TS_LOGD("%s, aConstraintUsage[%d]", idxInfo->idxStr, idxInfo->nConstraint);
204     for (int32_t i = 0; i < idxInfo->nConstraint; i++) {
205         TS_LOGD("col: %d op: %d, argvindex: %d omit: %d", idxInfo->aConstraint[i].iColumn, idxInfo->aConstraint[i].op,
206                 idxInfo->aConstraintUsage[i].argvIndex, idxInfo->aConstraintUsage[i].omit);
207     }
208     TS_LOGD("estimated: %lld cost:%.3f", idxInfo->estimatedRows, idxInfo->estimatedCost);
209 
210     return SQLITE_OK;
211 }
212 
Open(sqlite3_vtab_cursor ** ppCursor)213 int32_t TableBase::Open(sqlite3_vtab_cursor **ppCursor)
214 {
215     *ppCursor = static_cast<sqlite3_vtab_cursor *>(CreateCursor().release());
216     return SQLITE_OK;
217 }
218 
Cursor(const TraceDataCache * dataCache,TableBase * table,uint32_t rowCount)219 TableBase::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table, uint32_t rowCount)
220     : context_(nullptr),
221       table_(table),
222       dataCache_(dataCache),
223       indexMap_(std::make_unique<IndexMap>(0, rowCount)),
224       rowCount_(rowCount)
225 {
226 }
227 
CanFilterId(const char op,size_t & rowCount)228 bool TableBase::CanFilterId(const char op, size_t &rowCount)
229 {
230     switch (op) {
231         case SQLITE_INDEX_CONSTRAINT_EQ:
232             rowCount = 1;
233             break;
234         case SQLITE_INDEX_CONSTRAINT_GT:
235         case SQLITE_INDEX_CONSTRAINT_GE:
236         case SQLITE_INDEX_CONSTRAINT_LE:
237         case SQLITE_INDEX_CONSTRAINT_LT:
238             // assume filter out a half of rows
239             rowCount = (rowCount >> 1);
240             break;
241         default:
242             return false;
243     }
244     return true;
245 }
246 
CanFilterSorted(const char op,size_t & rowCount)247 bool TableBase::CanFilterSorted(const char op, size_t &rowCount)
248 {
249     switch (op) {
250         case SQLITE_INDEX_CONSTRAINT_EQ:
251             rowCount = log2(rowCount);
252             break;
253         case SQLITE_INDEX_CONSTRAINT_GT:
254         case SQLITE_INDEX_CONSTRAINT_GE:
255         case SQLITE_INDEX_CONSTRAINT_LE:
256         case SQLITE_INDEX_CONSTRAINT_LT:
257             rowCount = (rowCount >> 1);
258             break;
259         default:
260             return false;
261     }
262     return true;
263 }
264 
~Cursor()265 TableBase::Cursor::~Cursor()
266 {
267     context_ = nullptr;
268     dataCache_ = nullptr;
269 }
FilterTS(unsigned char op,sqlite3_value * argv,const std::deque<InternalTime> & times)270 void TableBase::Cursor::FilterTS(unsigned char op, sqlite3_value *argv, const std::deque<InternalTime> &times)
271 {
272     auto v = static_cast<uint64_t>(sqlite3_value_int64(argv));
273     auto getValue = [](const uint64_t &row) { return row; };
274     switch (op) {
275         case SQLITE_INDEX_CONSTRAINT_EQ:
276             indexMap_->IntersectabcEqual(times, v, getValue);
277             break;
278         case SQLITE_INDEX_CONSTRAINT_GT:
279             v++;
280         case SQLITE_INDEX_CONSTRAINT_GE: {
281             indexMap_->IntersectGreaterEqual(times, v, getValue);
282             break;
283         }
284         case SQLITE_INDEX_CONSTRAINT_LE:
285             v++;
286         case SQLITE_INDEX_CONSTRAINT_LT: {
287             indexMap_->IntersectLessEqual(times, v, getValue);
288             break;
289         }
290         case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: {
291             indexMap_->RemoveNullElements(times, v);
292             break;
293         }
294         default:
295             break;
296     } // end of switch (op)
297 }
298 
RowId(sqlite3_int64 * id)299 int32_t TableBase::Cursor::RowId(sqlite3_int64 *id)
300 {
301     if (dataCache_->Cancel() || indexMap_->Eof()) {
302         return SQLITE_ERROR;
303     }
304     *id = static_cast<sqlite3_int64>(indexMap_->CurrentRow());
305     return SQLITE_OK;
306 }
FilterId(unsigned char op,sqlite3_value * argv)307 void TableBase::Cursor::FilterId(unsigned char op, sqlite3_value *argv)
308 {
309     auto type = sqlite3_value_type(argv);
310     if (type != SQLITE_INTEGER) {
311         // other type consider it NULL
312         indexMap_->Intersect(0, 0);
313         return;
314     }
315     if (indexMap_->HasData()) {
316         indexMap_->CovertToIndexMap();
317     }
318 
319     auto v = static_cast<TableRowId>(sqlite3_value_int64(argv));
320     switch (op) {
321         case SQLITE_INDEX_CONSTRAINT_EQ:
322             indexMap_->Intersect(v, v + 1);
323             break;
324         case SQLITE_INDEX_CONSTRAINT_GE:
325             indexMap_->Intersect(v, rowCount_);
326             break;
327         case SQLITE_INDEX_CONSTRAINT_GT:
328             v++;
329             indexMap_->Intersect(v, rowCount_);
330             break;
331         case SQLITE_INDEX_CONSTRAINT_LE:
332             v++;
333             indexMap_->Intersect(0, v);
334             break;
335         case SQLITE_INDEX_CONSTRAINT_LT:
336             indexMap_->Intersect(0, v);
337             break;
338         default:
339             // can't filter, all rows
340             break;
341     }
342 }
343 
CalculateFilterCost(int64_t rowCount,FilterConstraints & fc)344 double TableBase::CalculateFilterCost(int64_t rowCount, FilterConstraints &fc)
345 {
346     auto constraints = fc.GetConstraints();
347     if (constraints.empty()) { // scan all rows
348         return rowCount;
349     }
350     double filterCost = 0.0;
351     for (int32_t i = 0; i < static_cast<int32_t>(constraints.size()); i++) {
352         if (rowCount <= 1) {
353             // only one row or nothing, needn't filter by constraint
354             filterCost += rowCount;
355             break;
356         }
357         FilterByConstraint(fc, filterCost, rowCount, i);
358     }
359     return filterCost;
360 }
EstimateFilterCost(FilterConstraints & fc,EstimatedIndexInfo & ei)361 void TableBase::EstimateFilterCost(FilterConstraints &fc, EstimatedIndexInfo &ei)
362 {
363     constexpr double filterBaseCost = 1000.0; // set-up and tear-down
364     constexpr double indexCost = 2.0;
365     ei.estimatedCost = filterBaseCost;
366     auto rowCount = GetSize();
367     if (rowCount > -1) {
368         if (rowCount == 0 || rowCount == 1) {
369             ei.estimatedRows = rowCount;
370             ei.estimatedCost += indexCost * rowCount;
371             return;
372         }
373         ei.estimatedCost += CalculateFilterCost(rowCount, fc);
374         ei.estimatedRows = rowCount;
375         ei.estimatedCost += rowCount * indexCost;
376         ei.isOrdered = true;
377 
378         GetOrbyes(fc, ei);
379     }
380 }
381 
382 } // namespace TraceStreamer
383 } // namespace SysTuning
384