• 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 "demo_table_base.h"
17 
18 #include <cctype>
19 #include <cstring>
20 
21 #include "log.h"
22 
23 namespace SysTuning {
24 namespace TraceStreamer {
25 struct TableContext {
26     TabTemplate tmplate;
27     TraceDataCache* dataCache;
28     sqlite3_module module;
29     std::string tableName;
30 };
31 
~DemoTableBase()32 DemoTableBase::~DemoTableBase()
33 {
34     demoTraceDataCache_ = nullptr;
35     demoCursor_ = nullptr;
36 }
37 
DemoTableRegister(sqlite3 & db,TraceDataCache * cache,const std::string & demoTableName,TabTemplate tmplate)38 void DemoTableBase::DemoTableRegister(sqlite3& db,
39                                       TraceDataCache* cache,
40                                       const std::string& demoTableName,
41                                       TabTemplate tmplate)
42 {
43     std::unique_ptr<TableContext> demoContext(std::make_unique<TableContext>());
44     demoContext->dataCache = cache;
45     demoContext->tmplate = tmplate;
46     demoContext->tableName = demoTableName;
47     sqlite3_module& demoModule = demoContext->module;
48     demoModule = {0};
49 
50     auto demoCreateFn = [](sqlite3* xdb, void* pAux, int32_t argc, const char* const* argv, sqlite3_vtab** ppVTab,
51                            char** pzErr) {
52         Unused(argc);
53         Unused(argv);
54         Unused(pzErr);
55         auto demoXdesc = static_cast<const TableContext*>(pAux);
56         auto demoTable = demoXdesc->tmplate(demoXdesc->dataCache);
57         demoTable->name_ = demoXdesc->tableName;
58         if (demoTable->name_ == "process" || demoTable->name_ == "thread") {
59             demoTable->demoWdataCache_ = demoXdesc->dataCache;
60         }
61 
62         demoTable->DemoInit(argc, argv);
63         std::string demoCreateStmt = demoTable->DemoCreateTableSql();
64         TS_LOGD("xCreate table %s, statement: %s", demoTable->name_.c_str(), demoCreateStmt.c_str());
65         int32_t ret = sqlite3_declare_vtab(xdb, demoCreateStmt.c_str());
66         if (ret != SQLITE_OK) {
67             TS_LOGE("sqlite3_declare_vtab %s faild: %s", demoTable->name_.c_str(), demoCreateStmt.c_str());
68             return ret;
69         }
70         *ppVTab = demoTable.release();
71         return SQLITE_OK;
72     };
73 
74     auto demoDestroyFn = [](sqlite3_vtab* t) {
75         TS_LOGD("xDestroy table %s", static_cast<DemoTableBase*>(t)->name_.c_str());
76         delete static_cast<DemoTableBase*>(t);
77         return SQLITE_OK;
78     };
79     demoModule.xCreate = demoCreateFn;
80     demoModule.xConnect = demoCreateFn;
81     demoModule.xDisconnect = demoDestroyFn;
82     demoModule.xDestroy = demoDestroyFn;
83     SetModuleCallbacks(demoModule, demoTableName);
84     sqlite3_create_module_v2(&db, demoTableName.c_str(), &demoModule, demoContext.release(),
85                              [](void* arg) { delete static_cast<TableContext*>(arg); });
86 }
87 
SetModuleCallbacks(sqlite3_module & demoModule,const std::string & demoTableName)88 void DemoTableBase::SetModuleCallbacks(sqlite3_module& demoModule, const std::string& demoTableName)
89 {
90     demoModule.xOpen = [](sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor) {
91         TS_LOGD("xOpen: %s", static_cast<DemoTableBase*>(pVTab)->name_.c_str());
92         return static_cast<DemoTableBase*>(pVTab)->DemoOpen(ppCursor);
93     };
94 
95     demoModule.xClose = [](sqlite3_vtab_cursor* vc) {
96         TS_LOGD("xClose: %s", static_cast<Cursor*>(vc)->demoTable_->name_.c_str());
97         delete static_cast<Cursor*>(vc);
98         return SQLITE_OK;
99     };
100 
101     demoModule.xBestIndex = [](sqlite3_vtab* pVTab, sqlite3_index_info* idxInfo) {
102         TS_LOGD("xBestIndex: %s %d", static_cast<DemoTableBase*>(pVTab)->name_.c_str(), idxInfo->nConstraint);
103         return static_cast<DemoTableBase*>(pVTab)->DemoBestIndex(idxInfo);
104     };
105 
106     demoModule.xFilter = [](sqlite3_vtab_cursor* vc, int32_t idxNum, const char* idxStr, int32_t argc,
107                             sqlite3_value** argv) {
108         auto* demoVc = static_cast<Cursor*>(vc);
109         demoVc->Reset();
110         TS_LOGD("xFilter %s: [%d]%s", static_cast<Cursor*>(vc)->demoTable_->name_.c_str(), idxNum, idxStr);
111         if (demoVc->demoTable_->demoCacheIdxNum_ != idxNum) {
112             demoVc->demoTable_->demoCacheConstraint_.Clear();
113             demoVc->demoTable_->demoCacheConstraint_.FromString(idxStr);
114             demoVc->demoTable_->demoCacheIdxNum_ = idxNum;
115         }
116         return demoVc->DemoFilter(demoVc->demoTable_->demoCacheConstraint_, argv);
117     };
118 
119     demoModule.xNext = [](sqlite3_vtab_cursor* vc) { return static_cast<DemoTableBase::Cursor*>(vc)->Next(); };
120     demoModule.xEof = [](sqlite3_vtab_cursor* vc) { return static_cast<DemoTableBase::Cursor*>(vc)->Eof(); };
121     demoModule.xColumn = [](sqlite3_vtab_cursor* vc, sqlite3_context* ctx, int32_t col) {
122         static_cast<DemoTableBase::Cursor*>(vc)->demoContext_ = ctx;
123         return static_cast<DemoTableBase::Cursor*>(vc)->Column(col);
124     };
125     if (demoTableName == "process" || demoTableName == "thread") {
126         demoModule.xUpdate = [](sqlite3_vtab* pVTab, int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) {
127             TS_LOGD("xUpdate: %s", static_cast<DemoTableBase*>(pVTab)->name_.c_str());
128             return static_cast<DemoTableBase*>(pVTab)->DemoUpdate(argc, argv, pRowid);
129         };
130     }
131 }
132 
DemoCreateTableSql() const133 std::string DemoTableBase::DemoCreateTableSql() const
134 {
135     std::string demoStmt = "CREATE TABLE x(";
136     for (const auto& col : demoTableColumn_) {
137         demoStmt += " " + col.name_ + " " + col.type_;
138         demoStmt += ",";
139     }
140     demoStmt += " PRIMARY KEY(";
141     for (size_t i = 0; i < demoTablePriKey_.size(); i++) {
142         if (i != 0)
143             demoStmt += ", ";
144         demoStmt += demoTablePriKey_.at(i);
145     }
146     demoStmt += ")) WITHOUT ROWID;";
147     return demoStmt;
148 }
149 
DemoBestIndex(sqlite3_index_info * demoIdxInfo)150 int32_t DemoTableBase::DemoBestIndex(sqlite3_index_info* demoIdxInfo)
151 {
152     FilterConstraints demoFilterConstraints;
153     for (int32_t i = 0; i < demoIdxInfo->nConstraint; i++) {
154         const auto& constraint = demoIdxInfo->aConstraint[i];
155         if (constraint.usable) {
156             demoFilterConstraints.AddConstraint(i, constraint.iColumn, constraint.op);
157         }
158     }
159     for (int32_t i = 0; i < demoIdxInfo->nOrderBy; i++) {
160         demoFilterConstraints.AddOrderBy(demoIdxInfo->aOrderBy[i].iColumn, demoIdxInfo->aOrderBy[i].desc);
161     }
162 
163     EstimatedIndexInfo demoEstimate = {demoIdxInfo->estimatedRows, demoIdxInfo->estimatedCost, false};
164     DemoEstimateFilterCost(demoFilterConstraints, demoEstimate);
165     demoIdxInfo->orderByConsumed = demoEstimate.isOrdered;
166     demoIdxInfo->estimatedCost = demoEstimate.estimatedCost;
167     demoIdxInfo->estimatedRows = demoEstimate.estimatedRows;
168 
169     auto cs = demoFilterConstraints.GetConstraints();
170     for (size_t i = 0; i < cs.size(); i++) {
171         auto& c = cs[i];
172         demoIdxInfo->aConstraintUsage[c.idxInaConstraint].argvIndex = static_cast<int32_t>(i + 1);
173         demoIdxInfo->aConstraintUsage[c.idxInaConstraint].omit = c.isSupport;
174     }
175 
176     std::string str;
177     demoFilterConstraints.ToString(str);
178     char* demoPIdxStr = static_cast<char*>(sqlite3_malloc(str.size() + 1));
179     std::copy(str.begin(), str.end(), demoPIdxStr);
180     demoPIdxStr[str.size()] = '\0';
181     demoIdxInfo->idxStr = demoPIdxStr;
182     demoIdxInfo->needToFreeIdxStr = true;
183     demoIdxInfo->idxNum = ++demoBestIndexNum_;
184 
185     TS_LOGD("%s DemoBestIndex return: %d: %s", name_.c_str(), demoIdxInfo->idxNum, str.c_str());
186     TS_LOGD("%s, aConstraintUsage[%d]", demoIdxInfo->idxStr, demoIdxInfo->nConstraint);
187     for (int32_t i = 0; i < demoIdxInfo->nConstraint; i++) {
188         TS_LOGD("col: %d op: %d, argvindex: %d omit: %d", demoIdxInfo->aConstraint[i].iColumn,
189                 demoIdxInfo->aConstraint[i].op, demoIdxInfo->aConstraintUsage[i].argvIndex,
190                 demoIdxInfo->aConstraintUsage[i].omit);
191     }
192     TS_LOGD("estimated: %lld cost:%.3f", demoIdxInfo->estimatedRows, demoIdxInfo->estimatedCost);
193 
194     return SQLITE_OK;
195 }
196 
DemoOpen(sqlite3_vtab_cursor ** demoPpCursor)197 int32_t DemoTableBase::DemoOpen(sqlite3_vtab_cursor** demoPpCursor)
198 {
199     *demoPpCursor = static_cast<sqlite3_vtab_cursor*>(CreateCursor().release());
200     return SQLITE_OK;
201 }
202 
Cursor(const TraceDataCache * demoDataCache,DemoTableBase * demoTable,uint32_t demoRowCount)203 DemoTableBase::Cursor::Cursor(const TraceDataCache* demoDataCache, DemoTableBase* demoTable, uint32_t demoRowCount)
204     : demoContext_(nullptr),
205       demoTable_(demoTable),
206       demoDataCache_(demoDataCache),
207       demoIndexMap_(std::make_unique<IndexMap>(0, demoRowCount)),
208       demoRowCount_(demoRowCount)
209 {
210 }
211 
~Cursor()212 DemoTableBase::Cursor::~Cursor()
213 {
214     demoContext_ = nullptr;
215     demoDataCache_ = nullptr;
216 }
DemoFilterTS(unsigned char op,sqlite3_value * argv,const std::deque<InternalTime> & times)217 void DemoTableBase::Cursor::DemoFilterTS(unsigned char op, sqlite3_value* argv, const std::deque<InternalTime>& times)
218 {
219     auto demoArgv = static_cast<uint64_t>(sqlite3_value_int64(argv));
220     auto getDemoValue = [](const uint64_t& row) { return row; };
221     switch (op) {
222         case SQLITE_INDEX_CONSTRAINT_EQ:
223             demoIndexMap_->IntersectabcEqual(times, demoArgv, getDemoValue);
224             break;
225         case SQLITE_INDEX_CONSTRAINT_GT:
226             demoArgv++;
227         case SQLITE_INDEX_CONSTRAINT_GE: {
228             demoIndexMap_->IntersectGreaterEqual(times, demoArgv, getDemoValue);
229             break;
230         }
231         case SQLITE_INDEX_CONSTRAINT_LE:
232             demoArgv++;
233         case SQLITE_INDEX_CONSTRAINT_LT: {
234             demoIndexMap_->IntersectLessEqual(times, demoArgv, getDemoValue);
235             break;
236             case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: {
237                 demoIndexMap_->RemoveNullElements(times, demoArgv);
238                 break;
239             }
240             default:
241                 break;
242         } // end of switch (op)
243     }
244 }
245 
DemoRowId(sqlite3_int64 * id)246 int32_t DemoTableBase::Cursor::DemoRowId(sqlite3_int64* id)
247 {
248     if (demoDataCache_->DemoCancel() || demoIndexMap_->Eof()) {
249         return SQLITE_ERROR;
250     }
251     *id = static_cast<sqlite3_int64>(demoIndexMap_->CurrentRow());
252     return SQLITE_OK;
253 }
DemoFilterId(unsigned char op,sqlite3_value * argv)254 void DemoTableBase::Cursor::DemoFilterId(unsigned char op, sqlite3_value* argv)
255 {
256     auto demoType = sqlite3_value_type(argv);
257     if (demoType != SQLITE_INTEGER) {
258         // other demoType consider it NULL
259         demoIndexMap_->Intersect(0, 0);
260         return;
261     }
262 
263     auto demoArgv = static_cast<TableRowId>(sqlite3_value_int64(argv));
264     switch (op) {
265         case SQLITE_INDEX_CONSTRAINT_EQ:
266             demoIndexMap_->Intersect(demoArgv, demoArgv + 1);
267             break;
268         case SQLITE_INDEX_CONSTRAINT_GE:
269             demoIndexMap_->Intersect(demoArgv, demoRowCount_);
270             break;
271         case SQLITE_INDEX_CONSTRAINT_GT:
272             demoArgv++;
273             demoIndexMap_->Intersect(demoArgv, demoRowCount_);
274             break;
275         case SQLITE_INDEX_CONSTRAINT_LE:
276             demoArgv++;
277             demoIndexMap_->Intersect(0, demoArgv);
278             break;
279         case SQLITE_INDEX_CONSTRAINT_LT:
280             demoIndexMap_->Intersect(0, demoArgv);
281             break;
282         default:
283             // can't filter, all rows
284             break;
285     }
286 }
287 } // namespace TraceStreamer
288 } // namespace SysTuning
289