• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 
16 #include "sys_event_query_wrapper.h"
17 
18 #include "data_query.h"
19 #include "running_status_logger.h"
20 
21 namespace OHOS {
22 namespace HiviewDFX {
23 namespace {
24 constexpr char SPACE_CONCAT[] = " ";
25 constexpr int DEFAULT_CONCURRENT_CNT = 0;
GetCurTime()26 time_t GetCurTime()
27 {
28     time_t current;
29     (void)time(&current);
30     return current;
31 }
32 
GetSubStrCount(const std::string & content,const std::string & sub)33 int GetSubStrCount(const std::string& content, const std::string& sub)
34 {
35     int cnt = 0;
36     if (content.empty() || sub.empty()) {
37         return cnt;
38     }
39     size_t start = 0;
40     while ((start = content.find(sub, start)) != std::string::npos) {
41         start += sub.size();
42         cnt++;
43     }
44     return cnt;
45 }
46 }
47 
48 namespace EventStore {
LogTooManyQueryRules(const std::string sql)49 void QueryStatusLogUtil::LogTooManyQueryRules(const std::string sql)
50 {
51     std::string info { "PLUGIN TOOMANYQUERYCONDITION SQL=" };
52     info.append(sql);
53     Logging(info);
54 }
55 
LogTooManyConcurrentQueries(const int limit,bool innerQuery)56 void QueryStatusLogUtil::LogTooManyConcurrentQueries(const int limit, bool innerQuery)
57 {
58     std::string info { innerQuery ? "HIVIEW TOOMANYCOCURRENTQUERIES " : "TOOMANYCOCURRENTQUERIES " };
59     info.append("COUNT > ");
60     info.append(std::to_string(limit));
61     Logging(info);
62 }
63 
LogQueryOverTime(time_t costTime,const std::string sql,bool innerQuery)64 void QueryStatusLogUtil::LogQueryOverTime(time_t costTime, const std::string sql, bool innerQuery)
65 {
66     std::string info { innerQuery ? "PLUGIN QUERYOVERTIME " : "QUERYOVERTIME " };
67     info.append(std::to_string(costTime)).append(SPACE_CONCAT).append("SQL=").append(sql);
68     Logging(info);
69 }
70 
LogQueryCountOverLimit(const int32_t queryCount,const std::string & sql,bool innerQuery)71 void QueryStatusLogUtil::LogQueryCountOverLimit(const int32_t queryCount, const std::string& sql,
72     bool innerQuery)
73 {
74     std::string info { innerQuery ? "PLUGIN QUERYCOUNTOVERLIMIT " : "QUERYCOUNTOVERLIMIT " };
75     info.append(std::to_string(queryCount)).append(SPACE_CONCAT).append("SQL=").append(sql);
76     Logging(info);
77 }
78 
LogQueryTooFrequently(const std::string & sql,const std::string & processName,bool innerQuery)79 void QueryStatusLogUtil::LogQueryTooFrequently(const std::string& sql, const std::string& processName,
80     bool innerQuery)
81 {
82     std::string info { innerQuery ? "HIVIEW QUERYTOOFREQUENTLY " : "QUERYTOOFREQUENTLY " };
83     if (!processName.empty()) {
84         info.append(processName).append(SPACE_CONCAT);
85     }
86     info.append("SQL=").append(sql);
87     Logging(info);
88 }
89 
Logging(const std::string & detail)90 void QueryStatusLogUtil::Logging(const std::string& detail)
91 {
92     std::string info = RunningStatusLogger::GetInstance().FormatTimeStamp();
93     info.append(SPACE_CONCAT).append(detail);
94     RunningStatusLogger::GetInstance().Log(info);
95 }
96 
97 ConcurrentQueries SysEventQueryWrapper::concurrentQueries_;
98 LastQueries SysEventQueryWrapper::lastQueries_;
99 std::mutex SysEventQueryWrapper::lastQueriesMutex_;
100 std::mutex SysEventQueryWrapper::concurrentQueriesMutex_;
Execute(int limit,DbQueryTag tag,QueryProcessInfo callerInfo,DbQueryCallback queryCallback)101 ResultSet SysEventQueryWrapper::Execute(int limit, DbQueryTag tag, QueryProcessInfo callerInfo,
102     DbQueryCallback queryCallback)
103 {
104     DataQuery dataQuery;
105     SysEventQuery::BuildDataQuery(dataQuery, limit);
106     ResultSet resultSet;
107     int queryErrorCode = -1;
108     (void)IsConditionCntValid(dataQuery, tag);
109     if (!IsQueryCntLimitValid(dataQuery, tag, limit, queryCallback) ||
110         !IsConcurrentQueryCntValid(GetDbFile(), tag, queryCallback) ||
111         !IsQueryFrequenceValid(dataQuery, tag, GetDbFile(), callerInfo, queryCallback)) {
112         resultSet.Set(queryErrorCode, false);
113         return resultSet;
114     }
115     time_t beforeExecute = GetCurTime();
116     IncreaseConcurrentCnt(GetDbFile(), tag);
117     resultSet = SysEventQuery::Execute(limit, tag, callerInfo, queryCallback);
118     DecreaseConcurrentCnt(GetDbFile(), tag);
119     time_t afterExecute = GetCurTime();
120     if (!IsQueryCostTimeValid(dataQuery, tag, beforeExecute, afterExecute, queryCallback)) {
121         resultSet.Set(queryErrorCode, false);
122         return resultSet;
123     }
124     if (queryCallback != nullptr) {
125         queryCallback(DbQueryStatus::SUCCEED);
126     }
127     return resultSet;
128 }
129 
IsConditionCntValid(const DataQuery & query,const DbQueryTag & tag)130 bool SysEventQueryWrapper::IsConditionCntValid(const DataQuery& query, const DbQueryTag& tag)
131 {
132     int conditionCntLimit = 8;
133     if (tag.isInnerQuery && GetSubStrCount(query.ToString(), "domain_=") > conditionCntLimit) {
134         QueryStatusLogUtil::LogTooManyQueryRules(query.ToString());
135         return false;
136     }
137     return true;
138 }
139 
IsQueryCntLimitValid(const DataQuery & query,const DbQueryTag & tag,const int limit,const DbQueryCallback & callback)140 bool SysEventQueryWrapper::IsQueryCntLimitValid(const DataQuery& query, const DbQueryTag& tag, const int limit,
141     const DbQueryCallback& callback)
142 {
143     int queryLimit = tag.isInnerQuery ? 50 : 1000;
144     if (limit > queryLimit) {
145         QueryStatusLogUtil::LogQueryCountOverLimit(limit, query.ToString(), tag.isInnerQuery);
146         if (callback != nullptr) {
147             callback(DbQueryStatus::OVER_LIMIT);
148         }
149         return tag.isInnerQuery;
150     }
151     return true;
152 }
153 
IsQueryCostTimeValid(const DataQuery & query,const DbQueryTag & tag,const time_t before,const time_t after,const DbQueryCallback & callback)154 bool SysEventQueryWrapper::IsQueryCostTimeValid(const DataQuery& query, const DbQueryTag& tag, const time_t before,
155     const time_t after, const DbQueryCallback& callback)
156 {
157     time_t maxQueryTime = 20;
158     time_t duration = after - before;
159     if (duration < maxQueryTime) {
160         return true;
161     }
162     QueryStatusLogUtil::LogQueryOverTime(duration, query.ToString(), tag.isInnerQuery);
163     if (callback != nullptr) {
164         callback(DbQueryStatus::OVER_TIME);
165     }
166     return tag.isInnerQuery;
167 }
168 
IsConcurrentQueryCntValid(const std::string & dbFile,const DbQueryTag & tag,const DbQueryCallback & callback)169 bool SysEventQueryWrapper::IsConcurrentQueryCntValid(const std::string& dbFile, const DbQueryTag& tag,
170     const DbQueryCallback& callback)
171 {
172     std::lock_guard<std::mutex> lock(concurrentQueriesMutex_);
173     auto iter = concurrentQueries_.find(dbFile);
174     if (iter != concurrentQueries_.end()) {
175         auto& concurrentQueryCnt = tag.isInnerQuery ? iter->second.first : iter->second.second;
176         int conCurrentQueryCntLimit = 4;
177         if (concurrentQueryCnt < conCurrentQueryCntLimit) {
178             return true;
179         }
180         QueryStatusLogUtil::LogTooManyConcurrentQueries(conCurrentQueryCntLimit, tag.isInnerQuery);
181         if (callback != nullptr) {
182             callback(DbQueryStatus::CONCURRENT);
183         }
184         return tag.isInnerQuery;
185     }
186     concurrentQueries_[dbFile] = { DEFAULT_CONCURRENT_CNT, DEFAULT_CONCURRENT_CNT };
187     return true;
188 }
189 
IsQueryFrequenceValid(const DataQuery & query,const DbQueryTag & tag,const std::string & dbFile,const QueryProcessInfo & processInfo,const DbQueryCallback & callback)190 bool SysEventQueryWrapper::IsQueryFrequenceValid(const DataQuery& query, const DbQueryTag& tag,
191     const std::string& dbFile, const QueryProcessInfo& processInfo, const DbQueryCallback& callback)
192 {
193     std::lock_guard<std::mutex> lock(lastQueriesMutex_);
194     if (!tag.needFrequenceCheck) {
195         return true;
196     }
197     time_t current;
198     (void)time(&current);
199     auto execIter = lastQueries_.find(dbFile);
200     auto queryProcessId = processInfo.first;
201     if (execIter == lastQueries_.end()) {
202         lastQueries_[dbFile].insert(std::make_pair(queryProcessId, current));
203         return true;
204     }
205     auto processIter = execIter->second.find(queryProcessId);
206     if (processIter == execIter->second.end()) {
207         execIter->second[queryProcessId] = current;
208         return true;
209     }
210     time_t queryFrequent = 1;
211     if (abs(current - processIter->second) > queryFrequent) {
212         execIter->second[queryProcessId] = current;
213         return true;
214     }
215     QueryStatusLogUtil::LogQueryTooFrequently(query.ToString(), processInfo.second, tag.isInnerQuery);
216     if (callback != nullptr) {
217         callback(DbQueryStatus::TOO_FREQENTLY);
218     }
219     return tag.isInnerQuery;
220 }
221 
IncreaseConcurrentCnt(const std::string & dbFile,const DbQueryTag & tag)222 void SysEventQueryWrapper::IncreaseConcurrentCnt(const std::string& dbFile, const DbQueryTag& tag)
223 {
224     std::lock_guard<std::mutex> lock(concurrentQueriesMutex_);
225     auto iter = concurrentQueries_.find(dbFile);
226     if (iter != concurrentQueries_.end()) {
227         auto& concurrentQueryCnt = tag.isInnerQuery ? iter->second.first : iter->second.second;
228         concurrentQueryCnt++;
229         return;
230     }
231     concurrentQueries_[dbFile] = std::make_pair(DEFAULT_CONCURRENT_CNT, DEFAULT_CONCURRENT_CNT);
232 }
233 
DecreaseConcurrentCnt(const std::string & dbFile,const DbQueryTag & tag)234 void SysEventQueryWrapper::DecreaseConcurrentCnt(const std::string& dbFile, const DbQueryTag& tag)
235 {
236     std::lock_guard<std::mutex> lock(concurrentQueriesMutex_);
237     auto iter = concurrentQueries_.find(dbFile);
238     if (iter != concurrentQueries_.end()) {
239         auto& concurrentQueryCnt = tag.isInnerQuery ? iter->second.first : iter->second.second;
240         concurrentQueryCnt--;
241     }
242 }
243 } // namespace EventStore
244 } // namespace HiviewDFX
245 } // namespace OHOS
246