• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023-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 "trace_storage.h"
16 
17 #include <cinttypes>
18 
19 #include "cjson_util.h"
20 #include "hiview_logger.h"
21 #include "time_util.h"
22 
23 namespace OHOS {
24 namespace HiviewDFX {
25 namespace {
26 DEFINE_LOG_TAG("TraceStorage");
27 constexpr char TABLE_NAME[] = "trace_flow_control";
28 constexpr char COLUMN_SYSTEM_TIME[] = "system_time";
29 constexpr char COLUMN_CALLER_NAME[] = "caller_name";
30 constexpr char COLUMN_USED_SIZE[] = "used_size";
31 constexpr char COLUMN_DYNAMIC_DECREASE[] = "dynamic_decrease";
32 constexpr char DYNAMIC_DECREASE_KEY[] = "DecreaseUnit";
33 constexpr char TRACE_QUOTA_CONFIG_FILE[] = "trace_quota_config.json";
34 const float TEN_PERCENT_LIMIT = 0.1;
35 
GetBucket(const TraceFlowRecord & traceFlowRecord)36 NativeRdb::ValuesBucket GetBucket(const TraceFlowRecord& traceFlowRecord)
37 {
38     NativeRdb::ValuesBucket bucket;
39     bucket.PutString(COLUMN_SYSTEM_TIME, traceFlowRecord.systemTime);
40     bucket.PutString(COLUMN_CALLER_NAME, traceFlowRecord.callerName);
41     bucket.PutLong(COLUMN_USED_SIZE, traceFlowRecord.usedSize);
42     bucket.PutLong(COLUMN_DYNAMIC_DECREASE, traceFlowRecord.dynamicDecrease);
43     return bucket;
44 }
45 }
46 
TraceStorage(std::shared_ptr<NativeRdb::RdbStore> dbStore,const std::string & caller,const std::string & configPath)47 TraceStorage::TraceStorage(std::shared_ptr<NativeRdb::RdbStore> dbStore, const std::string& caller,
48     const std::string& configPath): caller_(caller), dbStore_(dbStore)
49 {
50     traceQuotaConfig_ = configPath + TRACE_QUOTA_CONFIG_FILE;
51     quota_ = GetTraceQuota(caller);
52     decreaseUnit_ = GetTraceQuota(DYNAMIC_DECREASE_KEY);
53 #ifdef TRACE_MANAGER_UNITTEST
54     testDate_ = TimeUtil::TimestampFormatToDate(std::time(nullptr), "%Y-%m-%d");
55 #endif
56     InitTableRecord();
57 }
58 
InitTableRecord()59 void TraceStorage::InitTableRecord()
60 {
61     traceFlowRecord_.callerName = caller_;
62     Query(traceFlowRecord_);
63     HIVIEW_LOGI("systemTime:%{public}s, callerName:%{public}s, usedSize:%{public}" PRId64 " threshold:%{public}" PRId64,
64         traceFlowRecord_.systemTime.c_str(), traceFlowRecord_.callerName.c_str(), traceFlowRecord_.usedSize,
65             traceFlowRecord_.dynamicDecrease);
66 }
67 
Store(const TraceFlowRecord & traceFlowRecord)68 void TraceStorage::Store(const TraceFlowRecord& traceFlowRecord)
69 {
70     if (dbStore_ == nullptr) {
71         HIVIEW_LOGE("db store is null,");
72         return;
73     }
74     TraceFlowRecord tmpTraceFlowRecord = {.callerName = traceFlowRecord.callerName};
75     Query(tmpTraceFlowRecord);
76     if (!tmpTraceFlowRecord.systemTime.empty()) { // time not empty means record exist
77         UpdateTable(traceFlowRecord);
78     } else {
79         InsertTable(traceFlowRecord);
80     }
81 }
82 
UpdateTable(const TraceFlowRecord & traceFlowRecord)83 void TraceStorage::UpdateTable(const TraceFlowRecord& traceFlowRecord)
84 {
85     NativeRdb::ValuesBucket bucket = GetBucket(traceFlowRecord);
86     NativeRdb::AbsRdbPredicates predicates(TABLE_NAME);
87     predicates.EqualTo(COLUMN_CALLER_NAME, traceFlowRecord.callerName);
88     int changeRows = 0;
89     if (dbStore_->Update(changeRows, bucket, predicates) != NativeRdb::E_OK) {
90         HIVIEW_LOGW("failed to update table");
91     }
92 }
93 
InsertTable(const TraceFlowRecord & traceFlowRecord)94 void TraceStorage::InsertTable(const TraceFlowRecord& traceFlowRecord)
95 {
96     NativeRdb::ValuesBucket bucket = GetBucket(traceFlowRecord);
97     int64_t seq = 0;
98     if (dbStore_->Insert(seq, TABLE_NAME, bucket) != NativeRdb::E_OK) {
99         HIVIEW_LOGW("failed to insert table");
100     }
101 }
102 
Query(TraceFlowRecord & traceFlowRecord)103 void TraceStorage::Query(TraceFlowRecord& traceFlowRecord)
104 {
105     if (dbStore_ == nullptr) {
106         HIVIEW_LOGE("db store is null");
107         return;
108     }
109     QueryTable(traceFlowRecord);
110 }
111 
QueryTable(TraceFlowRecord & traceFlowRecord)112 void TraceStorage::QueryTable(TraceFlowRecord& traceFlowRecord)
113 {
114     NativeRdb::AbsRdbPredicates predicates(TABLE_NAME);
115     predicates.EqualTo(COLUMN_CALLER_NAME, traceFlowRecord.callerName);
116     auto resultSet = dbStore_->Query(predicates, {COLUMN_SYSTEM_TIME, COLUMN_USED_SIZE, COLUMN_DYNAMIC_DECREASE});
117     if (resultSet == nullptr) {
118         HIVIEW_LOGE("failed to query from table %{public}s, db is null", TABLE_NAME);
119         return;
120     }
121 
122     if (resultSet->GoToNextRow() == NativeRdb::E_OK) {
123         resultSet->GetString(0, traceFlowRecord.systemTime); // 0 means system_time field
124         resultSet->GetLong(1, traceFlowRecord.usedSize); // 1 means used_size field
125         resultSet->GetLong(2, traceFlowRecord.dynamicDecrease); // 2 means dynamic_threshold field
126     }
127     resultSet->Close();
128 }
129 
GetDate()130 std::string TraceStorage::GetDate()
131 {
132 #ifndef TRACE_MANAGER_UNITTEST
133     std::string dateStr = TimeUtil::TimestampFormatToDate(std::time(nullptr), "%Y-%m-%d");
134     return dateStr;
135 #else
136     return testDate_;
137 #endif
138 }
139 
140 // remaining trace size contains 10% fluctuation of the quota when quota not completely used up
GetRemainingTraceSize()141 int64_t TraceStorage::GetRemainingTraceSize()
142 {
143     if (quota_ <= 0) {
144         return 0;
145     }
146     if (IsDateChange()) {
147         return quota_ + quota_ * TEN_PERCENT_LIMIT;
148     }
149     if (quota_ <= traceFlowRecord_.usedSize) {
150         return 0;
151     }
152     return (quota_ - traceFlowRecord_.usedSize) + quota_ * TEN_PERCENT_LIMIT;
153 }
154 
IsOverLimit()155 bool TraceStorage::IsOverLimit()
156 {
157     if (quota_ <= 0) {
158         return true;
159     }
160     if (IsDateChange()) {
161         return false;
162     }
163     return (quota_ - traceFlowRecord_.dynamicDecrease) < traceFlowRecord_.usedSize;
164 }
165 
DecreaseDynamicThreshold()166 void TraceStorage::DecreaseDynamicThreshold()
167 {
168     if (quota_ <= 0) {
169         return;
170     }
171     traceFlowRecord_.dynamicDecrease += decreaseUnit_;
172     Store(traceFlowRecord_);
173 }
174 
StoreDb(int64_t traceSize)175 void TraceStorage::StoreDb(int64_t traceSize)
176 {
177     if (quota_ <= 0) {
178         return;
179     }
180     traceFlowRecord_.usedSize += traceSize;
181     HIVIEW_LOGI("systemTime:%{public}s, callerName:%{public}s, usedSize:%{public}" PRId64,
182         traceFlowRecord_.systemTime.c_str(), traceFlowRecord_.callerName.c_str(), traceFlowRecord_.usedSize);
183     Store(traceFlowRecord_);
184 }
185 
GetTraceQuota(const std::string & key)186 int64_t TraceStorage::GetTraceQuota(const std::string& key)
187 {
188     auto root = CJsonUtil::ParseJsonRoot(traceQuotaConfig_);
189     if (root == nullptr) {
190         HIVIEW_LOGW("failed to parse config");
191         return -1;
192     }
193     int64_t traceQuota = CJsonUtil::GetIntValue(root, key, 0);
194     if (traceQuota <= 0) {
195         HIVIEW_LOGW("failed to get value for key=%{public}s", key.c_str());
196     }
197     cJSON_Delete(root);
198     return traceQuota;
199 }
200 
IsDateChange()201 bool TraceStorage::IsDateChange()
202 {
203     std::string nowDays = GetDate();
204     HIVIEW_LOGI("start to dump, nowDays = %{public}s, systemTime = %{public}s.",
205                 nowDays.c_str(), traceFlowRecord_.systemTime.c_str());
206     if (nowDays != traceFlowRecord_.systemTime) {
207         HIVIEW_LOGD("date changes");
208         traceFlowRecord_.systemTime = nowDays;
209         traceFlowRecord_.usedSize = 0;
210         traceFlowRecord_.dynamicDecrease = 0;
211         return true;
212     }
213     return false;
214 }
215 }  // namespace HiviewDFX
216 }  // namespace OHOS
217