1 /*
2 * Copyright (c) 2025 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 #include "telemetry_storage.h"
16
17 #include "hiview_logger.h"
18
19 namespace OHOS::HiviewDFX {
20 DEFINE_LOG_TAG("TeleMetryStorage");
21 namespace {
22 constexpr char TABLE_TELEMETRY_CONTROL[] = "telemetry_control";
23 constexpr char COLUMN_MODULE_NAME[] = "module";
24 constexpr char COLUMN_RUNNING_TIME[] = "running_time";
25 constexpr char COLUMN_USED_SIZE[] = "used_size";
26 constexpr char COLUMN_QUOTA[] = "quota";
27 constexpr char COLUMN_TELEMTRY_ID[] = "telemetry_id";
28 constexpr char TOTAL[] = "Total";
29 }
30
QueryTable(const std::string & module,int64_t & usedSize,int64_t & quotaSize)31 bool TeleMetryStorage::QueryTable(const std::string &module, int64_t &usedSize, int64_t "aSize)
32 {
33 NativeRdb::AbsRdbPredicates predicates{std::string(TABLE_TELEMETRY_CONTROL)};
34 predicates.EqualTo(COLUMN_MODULE_NAME, module);
35 auto resultSet = dbStore_->Query(predicates, {COLUMN_USED_SIZE, COLUMN_QUOTA});
36 if (resultSet == nullptr) {
37 HIVIEW_LOGE("failed to query from table %{public}s", TABLE_TELEMETRY_CONTROL);
38 return false;
39 }
40 if (resultSet->GoToNextRow() != NativeRdb::E_OK) {
41 resultSet->Close();
42 return false;
43 }
44 resultSet->GetLong(0, usedSize); // 0 means used_size field
45 resultSet->GetLong(1, quotaSize); // 1 means quota field
46 resultSet->Close();
47 return true;
48 }
49
UpdateTable(const std::string & module,int64_t newSize)50 bool TeleMetryStorage::UpdateTable(const std::string &module, int64_t newSize)
51 {
52 NativeRdb::ValuesBucket bucket;
53 bucket.PutLong(COLUMN_USED_SIZE, newSize);
54 NativeRdb::AbsRdbPredicates predicates{std::string(TABLE_TELEMETRY_CONTROL)};
55 predicates.EqualTo(COLUMN_MODULE_NAME, module);
56 int changeRows = 0;
57 if (dbStore_->Update(changeRows, bucket, predicates) != NativeRdb::E_OK) {
58 HIVIEW_LOGW("module:%{public}s failed to update table", module.c_str());
59 return false;
60 }
61 return true;
62 }
63
InsertNewData(const std::string & telemetryId,const std::map<std::string,int64_t> & flowControlQuotas)64 void TeleMetryStorage::InsertNewData(const std::string &telemetryId,
65 const std::map<std::string, int64_t> &flowControlQuotas)
66 {
67 if (dbStore_ == nullptr) {
68 HIVIEW_LOGE("Open db failed");
69 return;
70 }
71 std::vector<NativeRdb::ValuesBucket> valuesBuckets;
72 for (const auto& quotaPair: flowControlQuotas) {
73 NativeRdb::ValuesBucket bucket;
74 if (quotaPair.first == TOTAL) {
75 bucket.PutString(COLUMN_TELEMTRY_ID, telemetryId);
76 bucket.PutLong(COLUMN_RUNNING_TIME, 0);
77 }
78 bucket.PutString(COLUMN_MODULE_NAME, quotaPair.first);
79 bucket.PutLong(COLUMN_USED_SIZE, 0);
80 bucket.PutLong(COLUMN_QUOTA, quotaPair.second);
81 valuesBuckets.push_back(bucket);
82 }
83 int64_t outInsertNum = 0;
84 int result = dbStore_->BatchInsert(outInsertNum, TABLE_TELEMETRY_CONTROL, valuesBuckets);
85 if (result != NativeRdb::E_OK) {
86 HIVIEW_LOGE("Insert batch operation failed, result: %{public}d", result);
87 }
88 }
89
InitTelemetryControl(const std::string & telemetryId,int64_t & runningTime,const std::map<std::string,int64_t> & flowControlQuotas)90 TelemetryRet TeleMetryStorage::InitTelemetryControl(const std::string &telemetryId, int64_t &runningTime,
91 const std::map<std::string, int64_t> &flowControlQuotas)
92 {
93 if (dbStore_ == nullptr) {
94 HIVIEW_LOGE("Open db failed");
95 return TelemetryRet::EXIT;
96 }
97 auto [errcode, transaction] = dbStore_->CreateTransaction(NativeRdb::Transaction::DEFERRED);
98 if (errcode != NativeRdb::E_OK || transaction == nullptr) {
99 HIVIEW_LOGE("CreateTransaction failed, error:%{public}d", errcode);
100 return TelemetryRet::EXIT;
101 }
102 NativeRdb::AbsRdbPredicates predicates{std::string(TABLE_TELEMETRY_CONTROL)};
103 predicates.EqualTo(COLUMN_MODULE_NAME, TOTAL);
104 auto resultSet = dbStore_->Query(predicates, {COLUMN_TELEMTRY_ID, COLUMN_RUNNING_TIME});
105 if (resultSet == nullptr) {
106 HIVIEW_LOGW("resultSet == nullptr");
107 transaction->Commit();
108 return TelemetryRet::EXIT;
109 }
110 if (resultSet->GoToNextRow() != NativeRdb::E_OK) {
111 HIVIEW_LOGW("empty data do init");
112 resultSet->Close();
113 InsertNewData(telemetryId, flowControlQuotas);
114 transaction->Commit();
115 return TelemetryRet::SUCCESS;
116 }
117 std::string dbTelemerty;
118 resultSet->GetString(0, dbTelemerty);
119 if (dbTelemerty != telemetryId) {
120 HIVIEW_LOGW("left over data, clear and do init");
121 resultSet->Close();
122 ClearTelemetryData();
123 InsertNewData(telemetryId, flowControlQuotas);
124 transaction->Commit();
125 return TelemetryRet::SUCCESS;
126 }
127 HIVIEW_LOGW("reboot scenario, get running time");
128 resultSet->GetLong(1, runningTime);
129 resultSet->Close();
130 transaction->Commit();
131 return TelemetryRet::SUCCESS;
132 }
133
NeedTelemetryDump(const std::string & module)134 TelemetryRet TeleMetryStorage::NeedTelemetryDump(const std::string &module)
135 {
136 if (dbStore_ == nullptr) {
137 HIVIEW_LOGE("Open db failed");
138 return TelemetryRet::EXIT;
139 }
140 TeleMetryFlowRecord flowRecord;
141 if (!GetFlowRecord(module, flowRecord)) {
142 HIVIEW_LOGE("get flow data failed");
143 return TelemetryRet::EXIT;
144 }
145 if (flowRecord.usedSize > flowRecord.quotaSize || flowRecord.totalUsedSize > flowRecord.totalQuotaSize) {
146 HIVIEW_LOGI("%{public}s over flow usedSize:%{public}" PRId64 " totalUsedSize:%{public}" PRId64 "",
147 module.c_str(), flowRecord.usedSize, flowRecord.totalUsedSize);
148 return TelemetryRet::OVER_FLOW;
149 }
150 return TelemetryRet::SUCCESS;
151 }
152
ClearTelemetryData()153 void TeleMetryStorage::ClearTelemetryData()
154 {
155 if (dbStore_ == nullptr) {
156 HIVIEW_LOGE("clear db failed");
157 return ;
158 }
159 NativeRdb::AbsRdbPredicates predicates({std::string(TABLE_TELEMETRY_CONTROL)});
160 int32_t deleteRows = 0;
161 int ret = dbStore_->Delete(deleteRows, predicates);
162 if (ret != NativeRdb::E_OK) {
163 HIVIEW_LOGE("failed to delete telemetry data, ret=%{public}d", ret);
164 }
165 }
166
QueryRunningTime(int64_t & runningTime)167 bool TeleMetryStorage::QueryRunningTime(int64_t &runningTime)
168 {
169 NativeRdb::AbsRdbPredicates predicates{std::string(TABLE_TELEMETRY_CONTROL)};
170 predicates.EqualTo(COLUMN_MODULE_NAME, TOTAL);
171 auto resultSet = dbStore_->Query(predicates, {COLUMN_RUNNING_TIME});
172 if (resultSet == nullptr) {
173 HIVIEW_LOGE("failed to query from table %{public}s", TABLE_TELEMETRY_CONTROL);
174 return false;
175 }
176 if (resultSet->GoToNextRow() != NativeRdb::E_OK) {
177 HIVIEW_LOGW("query empty");
178 resultSet->Close();
179 return true;
180 }
181 resultSet->GetLong(0, runningTime);
182 HIVIEW_LOGI("query traceOntime:%{public} " PRId64 "", runningTime);
183 resultSet->Close();
184 return true;
185 }
186
UpdateRunningTime(int64_t runningTime)187 bool TeleMetryStorage::UpdateRunningTime(int64_t runningTime)
188 {
189 NativeRdb::ValuesBucket bucket;
190 bucket.PutLong(COLUMN_RUNNING_TIME, runningTime);
191 NativeRdb::AbsRdbPredicates predicates{std::string(TABLE_TELEMETRY_CONTROL)};
192 predicates.EqualTo(COLUMN_MODULE_NAME, TOTAL);
193 int changeRows = 0;
194 if (dbStore_->Update(changeRows, bucket, predicates) != NativeRdb::E_OK) {
195 HIVIEW_LOGW("failed to update table");
196 return false;
197 }
198 HIVIEW_LOGI("Update new traceOntime:%{public} " PRId64 "", runningTime);
199 return true;
200 }
201
TelemetryStore(const std::string & module,int64_t traceSize)202 void TeleMetryStorage::TelemetryStore(const std::string &module, int64_t traceSize)
203 {
204 if (dbStore_ == nullptr) {
205 HIVIEW_LOGE("Open db failed");
206 return;
207 }
208 auto [errcode, transaction] = dbStore_->CreateTransaction(NativeRdb::Transaction::DEFERRED);
209 if (errcode != NativeRdb::E_OK || transaction == nullptr) {
210 HIVIEW_LOGE("CreateTransaction failed, error:%{public}d", errcode);
211 return;
212 }
213 TeleMetryFlowRecord flowRecord;
214 if (!GetFlowRecord(module, flowRecord)) {
215 HIVIEW_LOGE("get flow data failed");
216 transaction->Commit();
217 return;
218 }
219 flowRecord.usedSize += traceSize;
220 flowRecord.totalUsedSize += traceSize;
221 if (!UpdateTable(module, flowRecord.usedSize)) {
222 transaction->Rollback();
223 return;
224 }
225 if (!UpdateTable(TOTAL, flowRecord.totalUsedSize)) {
226 transaction->Rollback();
227 return;
228 }
229 transaction->Commit();
230 }
231
GetFlowRecord(const std::string & module,TeleMetryFlowRecord & flowRecord)232 bool TeleMetryStorage::GetFlowRecord(const std::string &module, TeleMetryFlowRecord &flowRecord)
233 {
234 if (!QueryTable(module, flowRecord.usedSize, flowRecord.quotaSize) ||
235 !QueryTable(TOTAL, flowRecord.totalUsedSize, flowRecord.totalQuotaSize)) {
236 return false;
237 }
238 return true;
239 }
240 }