• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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