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 const std::string TABLE_TELEMETRY_CONTROL = "telemetry_control";
23 const std::string COLUMN_MODULE_NAME = "module";
24 const std::string COLUMN_BEGIN_TIME = "begin_time";
25 const std::string COLUMN_USED_SIZE = "used_size";
26 const std::string COLUMN_QUOTA = "quota";
27 const std::string COLUMN_THRESHOLD = "threshold";
28 const std::string COLUMN_TELEMTRY_ID = "telemetry_id";
29 const std::string TOTAL = "Total";
30 }
31
QueryTable(const std::string & module,int64_t & usedSize,int64_t & quotaSize)32 bool TeleMetryStorage::QueryTable(const std::string &module, int64_t &usedSize, int64_t "aSize)
33 {
34 NativeRdb::AbsRdbPredicates predicates(TABLE_TELEMETRY_CONTROL);
35 predicates.EqualTo(COLUMN_MODULE_NAME, module);
36 auto resultSet = dbStore_->Query(predicates, {COLUMN_USED_SIZE, COLUMN_QUOTA});
37 if (resultSet == nullptr) {
38 HIVIEW_LOGE("failed to query from table %{public}s", TABLE_TELEMETRY_CONTROL.c_str());
39 return false;
40 }
41 if (resultSet->GoToNextRow() != NativeRdb::E_OK) {
42 resultSet->Close();
43 return false;
44 }
45 resultSet->GetLong(0, usedSize); // 0 means used_size field
46 resultSet->GetLong(1, quotaSize); // 1 means quota field
47 resultSet->Close();
48 return true;
49 }
50
UpdateTable(const std::string & module,int64_t newSize)51 void TeleMetryStorage::UpdateTable(const std::string &module, int64_t newSize)
52 {
53 NativeRdb::ValuesBucket bucket;
54 bucket.PutLong(COLUMN_USED_SIZE, newSize);
55 NativeRdb::AbsRdbPredicates predicates(TABLE_TELEMETRY_CONTROL);
56 predicates.EqualTo(COLUMN_MODULE_NAME, module);
57 int changeRows = 0;
58 if (dbStore_->Update(changeRows, bucket, predicates) != NativeRdb::E_OK) {
59 HIVIEW_LOGW("failed to update table");
60 }
61 }
62
InsertNewData(const std::string & telemetryId,int64_t beginTime,const std::map<std::string,int64_t> & flowControlQuotas)63 void TeleMetryStorage::InsertNewData(const std::string &telemetryId, int64_t beginTime,
64 const std::map<std::string, int64_t> &flowControlQuotas)
65 {
66 if (dbStore_ == nullptr) {
67 HIVIEW_LOGE("Open db failed");
68 return;
69 }
70 std::vector<NativeRdb::ValuesBucket> valuesBuckets;
71 for (const auto& quotaPair: flowControlQuotas) {
72 NativeRdb::ValuesBucket bucket;
73 bucket.PutString(COLUMN_TELEMTRY_ID, telemetryId);
74 bucket.PutString(COLUMN_MODULE_NAME, quotaPair.first);
75 bucket.PutLong(COLUMN_USED_SIZE, 0);
76 bucket.PutLong(COLUMN_QUOTA, quotaPair.second);
77 bucket.PutLong(COLUMN_BEGIN_TIME, beginTime);
78 valuesBuckets.push_back(bucket);
79 }
80 int64_t outInsertNum = 0;
81 int result = dbStore_->BatchInsert(outInsertNum, TABLE_TELEMETRY_CONTROL, valuesBuckets);
82 if (result != NativeRdb::E_OK) {
83 HIVIEW_LOGE("Insert batch operation failed, result: %{public}d", result);
84 }
85 }
86
InitTelemetryControl(const std::string & telemetryId,int64_t & beginTime,const std::map<std::string,int64_t> & flowControlQuotas)87 TelemetryRet TeleMetryStorage::InitTelemetryControl(const std::string &telemetryId, int64_t &beginTime,
88 const std::map<std::string, int64_t> &flowControlQuotas)
89 {
90 if (dbStore_ == nullptr) {
91 HIVIEW_LOGE("Open db failed");
92 return TelemetryRet::EXIT;
93 }
94 auto [errcode, transaction] = dbStore_->CreateTransaction(NativeRdb::Transaction::DEFERRED);
95 if (errcode != NativeRdb::E_OK || transaction == nullptr) {
96 HIVIEW_LOGE("CreateTransaction failed, error:%{public}d", errcode);
97 return TelemetryRet::EXIT;
98 }
99 NativeRdb::AbsRdbPredicates predicates(TABLE_TELEMETRY_CONTROL);
100 predicates.EqualTo(COLUMN_MODULE_NAME, TOTAL);
101 auto resultSet = dbStore_->Query(predicates, {COLUMN_TELEMTRY_ID, COLUMN_BEGIN_TIME});
102 if (resultSet == nullptr) {
103 HIVIEW_LOGW("resultSet == nullptr");
104 transaction->Commit();
105 return TelemetryRet::EXIT;
106 }
107 if (resultSet->GoToNextRow() != NativeRdb::E_OK) {
108 HIVIEW_LOGW("empty data do init");
109 resultSet->Close();
110 InsertNewData(telemetryId, beginTime, flowControlQuotas);
111 transaction->Commit();
112 return TelemetryRet::SUCCESS;
113 }
114 std::string dbTelemerty;
115 resultSet->GetString(0, dbTelemerty);
116 if (dbTelemerty != telemetryId) {
117 HIVIEW_LOGW("left over data, clear and do init");
118 resultSet->Close();
119 ClearTelemetryData();
120 InsertNewData(telemetryId, beginTime, flowControlQuotas);
121 transaction->Commit();
122 return TelemetryRet::SUCCESS;
123 }
124 HIVIEW_LOGW("reboot scenario, update begin time");
125 resultSet->GetLong(1, beginTime);
126 resultSet->Close();
127 transaction->Commit();
128 return TelemetryRet::SUCCESS;
129 }
130
NeedTelemetryDump(const std::string & module,int64_t traceSize)131 TelemetryRet TeleMetryStorage::NeedTelemetryDump(const std::string &module, int64_t traceSize)
132 {
133 if (dbStore_ == nullptr) {
134 HIVIEW_LOGE("Open db failed");
135 return TelemetryRet::EXIT;
136 }
137 auto [errcode, transaction] = dbStore_->CreateTransaction(NativeRdb::Transaction::DEFERRED);
138 if (errcode != NativeRdb::E_OK || transaction == nullptr) {
139 HIVIEW_LOGE("CreateTransaction failed, error:%{public}d", errcode);
140 return TelemetryRet::EXIT;
141 }
142 int64_t usedSize = 0;
143 int64_t quotaSize = 0;
144 int64_t totalUsedSize = 0;
145 int64_t totalQuotaSize = 0;
146 if (!QueryTable(module, usedSize, quotaSize) || !QueryTable(TOTAL, totalUsedSize, totalQuotaSize)) {
147 transaction->Commit();
148 HIVIEW_LOGE("db data init failed");
149 return TelemetryRet::EXIT;
150 }
151 usedSize += traceSize;
152 totalUsedSize += traceSize;
153 if (usedSize > quotaSize || totalUsedSize > totalQuotaSize) {
154 transaction->Commit();
155 HIVIEW_LOGI("%{public}s over flow usedSize:%{public}lu totalUsedSize:%{public}lu", module.c_str(),
156 static_cast<long>(usedSize), static_cast<long>(totalUsedSize));
157 return TelemetryRet::OVER_FLOW;
158 }
159 UpdateTable(module, usedSize);
160 UpdateTable(TOTAL, totalUsedSize);
161 transaction->Commit();
162 return TelemetryRet::SUCCESS;
163 }
164
ClearTelemetryData()165 void TeleMetryStorage::ClearTelemetryData()
166 {
167 if (dbStore_ == nullptr) {
168 HIVIEW_LOGE("clear db failed");
169 return ;
170 }
171 NativeRdb::AbsRdbPredicates predicates({TABLE_TELEMETRY_CONTROL});
172 int32_t deleteRows = 0;
173 int ret = dbStore_->Delete(deleteRows, predicates);
174 if (ret != NativeRdb::E_OK) {
175 HIVIEW_LOGE("failed to delete telemetry data, ret=%{public}d", ret);
176 }
177 }
178 }