• 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 "trace_data_db.h"
17 #include <cmath>
18 #include <cstdio>
19 #include <cstring>
20 #include <fcntl.h>
21 #include <functional>
22 #include <sqlite3.h>
23 #include <string_view>
24 #include <unistd.h>
25 
26 #include "codec_cov.h"
27 #include "ext/sqlite_ext_funcs.h"
28 #include "file.h"
29 #include "log.h"
30 
31 namespace SysTuning {
32 namespace TraceStreamer {
PrintQueryResult(void * para,int column,char ** columnValue,char ** columnName)33 int PrintQueryResult(void* para, int column, char** columnValue, char** columnName)
34 {
35     int i;
36     printf("Query results include %d column\n", column);
37     for (i = 0; i < column; i++) {
38         printf("name : %s \t value : %s\n", columnName[i], columnValue[i]);
39     }
40     printf("------------------\n");
41     return 0;
42 }
TraceDataDB()43 TraceDataDB::TraceDataDB() : db_(nullptr)
44 {
45     if (sqlite3_threadsafe() > 0) {
46         int retCode = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
47         if (retCode == SQLITE_OK) {
48             TS_LOGI("Can now use sqlite on multiple threads, using the same connection");
49         } else {
50             TS_LOGE("setting sqlite thread safe mode to serialized failed!!! return code: %d", retCode);
51         }
52     } else {
53         TS_LOGE("Your SQLite database is not compiled to be threadsafe.");
54     }
55     if (sqlite3_open(":memory:", &db_)) {
56         TS_LOGF("open :memory db failed");
57     }
58     CreateExtendFunction(db_);
59 }
60 
~TraceDataDB()61 TraceDataDB::~TraceDataDB()
62 {
63     sqlite3_close(db_);
64 }
65 
AppendNewTable(std::string tableName)66 void TraceDataDB::AppendNewTable(std::string tableName)
67 {
68     internalTables_.push_back(tableName);
69 }
EnableMetaTable(bool enabled)70 void TraceDataDB::EnableMetaTable(bool enabled)
71 {
72     exportMetaTable_ = enabled;
73 }
ExportDatabase(const std::string & outputName)74 int TraceDataDB::ExportDatabase(const std::string& outputName)
75 {
76     {
77         int fd(base::OpenFile(outputName, O_CREAT | O_RDWR, 0600));
78         if (!fd) {
79             fprintf(stdout, "Failed to create file: %s", outputName.c_str());
80             return 1;
81         }
82         ftruncate(fd, 0);
83         close(fd);
84     }
85 
86     std::string attachSql("ATTACH DATABASE '" + outputName + "' AS systuning_export");
87 #ifdef _WIN32
88     if (!base::GetCoding(reinterpret_cast<const uint8_t*>(attachSql.c_str()), attachSql.length())) {
89         attachSql = base::GbkToUtf8(attachSql.c_str());
90     }
91 #endif
92     ExecuteSql(attachSql);
93 
94     for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) {
95         if (*itor == "meta") {
96             if (!exportMetaTable_) {
97                 continue;
98             }
99             if ((*itor) != "_data_dict") {
100                 std::string exportSql("CREATE TABLE systuning_export." + (*itor).substr(1, -1) +
101                                         " AS SELECT * FROM " + *itor);
102                 ExecuteSql(exportSql);
103             }
104         } else {
105             std::string exportSql("CREATE TABLE systuning_export." + (*itor).substr(1, -1) +
106                                   " AS SELECT * FROM " + *itor);
107             ExecuteSql(exportSql);
108         }
109     }
110     std::string createArgsView =
111         "create view systuning_export.args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when "
112         "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on (D.typeId "
113         "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key";
114     ExecuteSql(createArgsView);
115     std::string updateProcessName =
116         "update process set name =  (select name from thread t where t.ipid = process.id and t.name is not null and "
117         "is_main_thread = 1)";
118     ExecuteSql(updateProcessName);
119     std::string detachSql("DETACH DATABASE systuning_export");
120     ExecuteSql(detachSql);
121     return 0;
122 }
Prepare()123 void TraceDataDB::Prepare()
124 {
125     if (pared_) {
126         return;
127     }
128     pared_ = true;
129     for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) {
130         std::string exportSql("CREATE TABLE " + (*itor).substr(1, -1) + " AS SELECT * FROM " + *itor);
131         ExecuteSql(exportSql);
132     }
133     std::string createArgsView =
134         "create view args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when "
135         "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on "
136         "(D.typeId "
137         "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key";
138     ExecuteSql(createArgsView);
139     std::string updateProcessNewName =
140         "update process set name =  (select name from thread t where t.ipid = process.id and t.name is not "
141         "null and "
142         "is_main_thread = 1)";
143     ExecuteSql(updateProcessNewName);
144 }
ExecuteSql(const std::string_view & sql)145 void TraceDataDB::ExecuteSql(const std::string_view& sql)
146 {
147     sqlite3_stmt* stmt = nullptr;
148     int ret = sqlite3_prepare_v2(db_, sql.data(), static_cast<int>(sql.size()), &stmt, nullptr);
149 
150     while (!ret) {
151         int err = sqlite3_step(stmt);
152         if (err == SQLITE_ROW) {
153             continue;
154         }
155         if (err == SQLITE_DONE) {
156             break;
157         }
158         ret = err;
159     }
160 
161     sqlite3_finalize(stmt);
162 }
SearchData()163 int TraceDataDB::SearchData()
164 {
165     Prepare();
166     int result;
167     char* errmsg = nullptr;
168     std::string line;
169     for (;;) {
170         std::cout << "> ";
171         getline(std::cin, line);
172         if (line.empty()) {
173             std::cout << "If you want to quit either type -q or press CTRL-Z" << std::endl;
174             continue;
175         }
176         if (!line.compare("-q") || !line.compare("-quit")) {
177             break;
178         } else if (!line.compare("-e")) {
179             TS_LOGI("the db file will be at current folder, the name is default.db");
180             return ExportDatabase("default.db");
181         } else if (!line.compare("-help") || !line.compare("-h")) {
182             std::cout << "use info" << std::endl;
183             continue;
184         }
185         result = sqlite3_exec(db_, line.c_str(), PrintQueryResult, NULL, &errmsg);
186     }
187     return 0;
188 }
OperateDatabase(const std::string & sql)189 int TraceDataDB::OperateDatabase(const std::string& sql)
190 {
191     Prepare();
192     char* errmsg = nullptr;
193     int ret = sqlite3_exec(db_, sql.c_str(), NULL, NULL, &errmsg);
194     if (ret != SQLITE_OK && errmsg) {
195         TS_LOGE("sqlite3_exec(%s) failed: %d:%s", sql.c_str(), ret, errmsg);
196         sqlite3_free(errmsg);
197     }
198     return ret;
199 }
SearchDatabase(const std::string & sql,ResultCallBack resultCallBack)200 int TraceDataDB::SearchDatabase(const std::string& sql, ResultCallBack resultCallBack)
201 {
202     Prepare();
203     sqlite3_stmt* stmt = nullptr;
204     int ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast<int>(sql.size()), &stmt, nullptr);
205     if (ret != SQLITE_OK) {
206         TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:", sql.c_str(), ret);
207         return ret;
208     }
209     if (!resultCallBack) {
210         return ret;
211     }
212 
213     const size_t maxLenResponse = 4 * 1024;
214     std::string res;
215     res.reserve(maxLenResponse);
216     res = "ok\r\n";
217     int colCount = sqlite3_column_count(stmt);
218     if (colCount == 0) {
219         resultCallBack(res);
220         return ret;
221     }
222     res += "{\"columns\":[";
223     for (int i = 0; i < colCount; i++) {
224         res += "\"";
225         res += sqlite3_column_name(stmt, i);
226         res += "\",";
227     }
228     res.pop_back(); // remove the last ","
229     res += "],\"values\":[";
230     bool hasRow = false;
231     constexpr int defaultLenRowString = 1024;
232     std::string row;
233     row.reserve(defaultLenRowString);
234     while (sqlite3_step(stmt) == SQLITE_ROW) {
235         hasRow = true;
236         GetRowString(stmt, colCount, row);
237         if (res.size() + row.size() + strlen(",]}\r\n") >= maxLenResponse) {
238             resultCallBack(res);
239             res.clear();
240         }
241         res += row + ",";
242     }
243     if (hasRow) {
244         res.pop_back(); // remove the last ','
245     }
246     res += "]}\r\n";
247     resultCallBack(res);
248 
249     sqlite3_finalize(stmt);
250     return ret;
251 }
SearchDatabase(const std::string & sql,uint8_t * out,int outLen)252 int TraceDataDB::SearchDatabase(const std::string& sql, uint8_t* out, int outLen)
253 {
254     Prepare();
255     sqlite3_stmt* stmt = nullptr;
256     int ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast<int>(sql.size()), &stmt, nullptr);
257     if (ret != SQLITE_OK) {
258         TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:", sql.c_str(), ret);
259         return -1;
260     }
261     char* res = reinterpret_cast<char*>(out);
262     int retSnprintf = std::snprintf(res, outLen, "%s", "ok\r\n");
263     if (retSnprintf < 0) {
264         return -1;
265     }
266     int pos = retSnprintf;
267     int colCount = sqlite3_column_count(stmt);
268     if (colCount == 0) {
269         return pos;
270     }
271     retSnprintf = std::snprintf(res + pos, outLen - pos, "%s", "{\"columns\":[");
272     if (retSnprintf < 0) {
273         return -1;
274     }
275     pos += retSnprintf;
276     for (int i = 0; i < colCount; i++) {
277         retSnprintf = std::snprintf(res + pos, outLen - pos, "%s%s%s", "\"", sqlite3_column_name(stmt, i), "\",");
278         if (retSnprintf < 0) {
279             return -1;
280         }
281         pos += retSnprintf;
282     }
283     pos--; // rmove the last ','
284     retSnprintf = std::snprintf(res + pos, outLen - pos, "%s", "],\"values\":[");
285     if (retSnprintf < 0) {
286         return -1;
287     }
288     pos += retSnprintf;
289     bool hasRow = false;
290     constexpr int defaultLenRowString = 1024;
291     std::string row;
292     row.reserve(defaultLenRowString);
293     while (sqlite3_step(stmt) == SQLITE_ROW) {
294         hasRow = true;
295         GetRowString(stmt, colCount, row);
296         if (pos + row.size() + strlen(",]}\r\n") >= size_t(outLen)) {
297             retSnprintf = std::snprintf(res + pos, outLen - pos, "%s", "]}\r\n");
298             if (retSnprintf < 0) {
299                 return -1;
300             }
301             pos += retSnprintf;
302             sqlite3_finalize(stmt);
303             return pos;
304         }
305         retSnprintf = std::snprintf(res + pos, outLen - pos, "%s%s", row.c_str(), ",");
306         if (retSnprintf < 0) {
307             return -1;
308         }
309         pos += retSnprintf;
310     }
311     if (hasRow) {
312         pos--; // remove the last ','
313     }
314     retSnprintf = std::snprintf(res + pos, outLen - pos, "%s", "]}\r\n");
315     if (retSnprintf < 0) {
316         return -1;
317     }
318     pos += retSnprintf;
319     sqlite3_finalize(stmt);
320     return pos;
321 }
GetRowString(sqlite3_stmt * stmt,int colCount,std::string & rowStr)322 void TraceDataDB::GetRowString(sqlite3_stmt* stmt, int colCount, std::string& rowStr)
323 {
324     rowStr.clear();
325     rowStr = "[";
326     for (int i = 0; i < colCount; i++) {
327         const char* p = reinterpret_cast<const char*>(sqlite3_column_text(stmt, i));
328         if (p == nullptr) {
329             rowStr += "null,";
330             continue;
331         }
332         int type = sqlite3_column_type(stmt, i);
333         switch (type) {
334             case SQLITE_TEXT:
335                 rowStr += "\"";
336                 rowStr += p;
337                 rowStr += "\"";
338                 break;
339             default:
340                 rowStr += p;
341                 break;
342         }
343         rowStr += ",";
344     }
345     rowStr.pop_back(); // remove the last ','
346     rowStr += "]";
347 }
348 } // namespace TraceStreamer
349 } // namespace SysTuning
350