• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &quotaSize)
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 }