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