1 /*
2 * Copyright (c) 2024-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 "daily_controller.h"
16
17 #include <cmath>
18
19 #include "hiview_config_util.h"
20 #include "hiview_logger.h"
21 #include "time_util.h"
22
23 namespace OHOS {
24 namespace HiviewDFX {
25 DEFINE_LOG_TAG("DailyController");
26 namespace {
27 constexpr int32_t COUNT_OF_INIT = 1;
28 }
29
DailyController(const std::string & workPath,const std::string & configPath)30 DailyController::DailyController(const std::string& workPath, const std::string& configPath)
31 {
32 dbHelper_ = std::make_unique<DailyDbHelper>(workPath);
33 config_ = std::make_unique<DailyConfig>(configPath);
34 }
35
CheckThreshold(std::shared_ptr<SysEvent> event)36 bool DailyController::CheckThreshold(std::shared_ptr<SysEvent> event)
37 {
38 if (event == nullptr) {
39 HIVIEW_LOGW("event is null");
40 return false;
41 }
42
43 // try to update cache to db and report db before checking
44 int64_t nowTime = TimeUtil::GetSeconds();
45 TryToUpdateCacheToDb(nowTime);
46 TryToReportDb(nowTime);
47
48 // check the threshold of event
49 auto cacheKey = std::make_pair(event->domain_, event->eventName_);
50 int32_t threshold = GetThreshold(cacheKey, event->eventType_);
51 int32_t count = GetCount(cacheKey) + 1;
52
53 // update cache and db after checking
54 UpdateCacheAndDb(cacheKey, threshold, count);
55 return config_->IsValid() ? (count <= threshold) : true;
56 }
57
TryToUpdateCacheToDb(int64_t nowTime)58 void DailyController::TryToUpdateCacheToDb(int64_t nowTime)
59 {
60 if (CheckTimeOfCache(nowTime) || CheckSizeOfCache()) {
61 UpdateCacheToDb();
62 }
63 }
64
CheckTimeOfCache(int64_t nowTime)65 bool DailyController::CheckTimeOfCache(int64_t nowTime)
66 {
67 static int64_t lastUpdateTime = 0;
68 if (lastUpdateTime == 0) {
69 lastUpdateTime = TimeUtil::GetSeconds();
70 return false;
71 }
72
73 constexpr int64_t updateInterval = 600; // 10min
74 if (std::abs(nowTime - lastUpdateTime) <= updateInterval) {
75 return false;
76 }
77 lastUpdateTime = nowTime;
78 return true;
79 }
80
CheckSizeOfCache()81 bool DailyController::CheckSizeOfCache()
82 {
83 constexpr size_t maxSizeOfCache = 1000;
84 return cache_.size() > maxSizeOfCache;
85 }
86
UpdateCacheToDb()87 void DailyController::UpdateCacheToDb()
88 {
89 HIVIEW_LOGI("start to update cache to db, size=%{public}zu", cache_.size());
90 for (const auto& [key, value] : cache_) {
91 // means that the record has been inserted and does not need to be updated
92 if (value.count == COUNT_OF_INIT) {
93 continue;
94 }
95
96 DailyDbHelper::EventInfo eventInfo = {
97 .domain = key.first,
98 .name = key.second,
99 .count = value.count,
100 .exceedTime = value.exceedTime,
101 };
102 if (dbHelper_->UpdateEventInfo(eventInfo) < 0) {
103 HIVIEW_LOGW("failed to update, domain=%{public}s, name=%{public}s",
104 key.first.c_str(), key.second.c_str());
105 }
106 }
107 cache_.clear();
108 }
109
TryToReportDb(int64_t nowTime)110 void DailyController::TryToReportDb(int64_t nowTime)
111 {
112 if (dbHelper_->NeedReport(nowTime)) {
113 UpdateCacheToDb();
114 dbHelper_->Report();
115 }
116 }
117
GetThreshold(const CacheKey & cachekey,int32_t type)118 int32_t DailyController::GetThreshold(const CacheKey& cachekey, int32_t type)
119 {
120 if (cache_.find(cachekey) != cache_.end()) {
121 return cache_[cachekey].threshold;
122 }
123 int32_t threshold = config_->GetThreshold(cachekey.first, cachekey.second, type);
124 if (threshold < 0) {
125 HIVIEW_LOGW("failed to get threshold from config, threshold=%{public}d", threshold);
126 return 0;
127 }
128 return threshold;
129 }
130
GetCount(const CacheKey & cachekey)131 int32_t DailyController::GetCount(const CacheKey& cachekey)
132 {
133 if (cache_.find(cachekey) != cache_.end()) {
134 return cache_[cachekey].count;
135 }
136
137 DailyDbHelper::EventInfo eventInfo = {
138 .domain = cachekey.first,
139 .name = cachekey.second,
140 };
141 if (dbHelper_->QueryEventInfo(eventInfo) < 0) {
142 HIVIEW_LOGW("failed to query event info from db, count=%{public}d", eventInfo.count);
143 return 0;
144 }
145 return eventInfo.count;
146 }
147
UpdateCacheAndDb(const CacheKey & cachekey,int32_t threshold,int32_t count)148 void DailyController::UpdateCacheAndDb(const CacheKey& cachekey, int32_t threshold, int32_t count)
149 {
150 // check the first time the event crosses the threshold
151 int64_t exceedTime = 0;
152 if (count == (threshold + 1)) {
153 exceedTime = TimeUtil::GetSeconds();
154 HIVIEW_LOGI("event first exceeds threshold=%{public}d, domain=%{public}s, name=%{public}s",
155 threshold, cachekey.first.c_str(), cachekey.second.c_str());
156 }
157
158 UpdateCache(cachekey, threshold, count, exceedTime);
159 UpdateDb(cachekey, count, exceedTime);
160 }
161
UpdateCache(const CacheKey & cachekey,int32_t threshold,int32_t count,int64_t exceedTime)162 void DailyController::UpdateCache(const CacheKey& cachekey, int32_t threshold, int32_t count, int64_t exceedTime)
163 {
164 if (cache_.find(cachekey) == cache_.end()) {
165 cache_[cachekey] = {
166 .threshold = threshold,
167 .count = count,
168 .exceedTime = exceedTime,
169 };
170 return;
171 }
172
173 cache_[cachekey].count = count;
174 if (exceedTime != 0) {
175 cache_[cachekey].exceedTime = exceedTime;
176 }
177 }
178
UpdateDb(const CacheKey & cachekey,int32_t count,int64_t exceedTime)179 void DailyController::UpdateDb(const CacheKey& cachekey, int32_t count, int64_t exceedTime)
180 {
181 // the record does not exist in the db, need to init the record
182 if (count == COUNT_OF_INIT) {
183 DailyDbHelper::EventInfo eventInfo = {
184 .domain = cachekey.first,
185 .name = cachekey.second,
186 .count = count,
187 .exceedTime = exceedTime,
188 };
189 if (dbHelper_->InsertEventInfo(eventInfo) < 0) {
190 HIVIEW_LOGW("failed to insert, domain=%{public}s, name=%{public}s",
191 eventInfo.domain.c_str(), eventInfo.name.c_str());
192 }
193 }
194 }
195
OnConfigUpdate(const std::string & configPath)196 void DailyController::OnConfigUpdate(const std::string& configPath)
197 {
198 UpdateCacheToDb();
199 config_ = std::make_unique<DailyConfig>(configPath);
200 }
201 } // namespace HiviewDFX
202 } // namespace OHOS
203