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