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