1 /*
2  * Copyright (c) 2022-2023 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 #ifndef HIVIEW_BASE_EVENT_STORE_INCLUDE_SYS_EVENT_QUERY_WRAPPER_H
17 #define HIVIEW_BASE_EVENT_STORE_INCLUDE_SYS_EVENT_QUERY_WRAPPER_H
18 
19 #include <atomic>
20 #include <ctime>
21 #include <memory>
22 #include <mutex>
23 #include <string>
24 #include <unordered_map>
25 
26 #include "sys_event_query.h"
27 
28 namespace OHOS {
29 namespace HiviewDFX {
30 namespace EventStore {
31 constexpr size_t DEFAULT_CACHE_CAPACITY = 30;
32 constexpr size_t QUERY_CONTROL_THRESHOLD = 50;
33 constexpr uint64_t QUERY_CONTROL_PERIOD_IN_MILLI_SECONDS = 1000;
34 constexpr uint64_t INVALID_TIME_STAMP = 0;
35 
36 template<typename K, typename V, size_t capacity = DEFAULT_CACHE_CAPACITY>
37 class LruCache {
38 public:
Get(K key)39     V Get(K key)
40     {
41         std::lock_guard<std::mutex> lock(lmtMutex_);
42         V v;
43         if (keyToIndex_.count(key) == 0) {
44             return v;
45         }
46         Modify(key);
47         return keyToIndex_[key].value;
48     }
49 
Put(K key,V value)50     void Put(K key, V value)
51     {
52         std::lock_guard<std::mutex> lock(lmtMutex_);
53         if (keyToIndex_.count(key) > 0) {
54             keyToIndex_[key].value = value;
55             Modify(key);
56             return;
57         }
58         if (allKeysCache_.size() == capacity) {
59             keyToIndex_.erase(allKeysCache_.back());
60             allKeysCache_.pop_back();
61         }
62         allKeysCache_.push_front(key);
63         keyToIndex_[key] = {
64             .iter = allKeysCache_.cbegin(),
65             .value = value
66         };
67     }
68 
69 private:
70     template<typename K_, typename V_>
71     struct CacheNode {
72         typename std::list<K_>::const_iterator iter;
73         V_ value;
74     };
75 
76 private:
Modify(K key)77     void Modify(K key)
78     {
79         allKeysCache_.splice(allKeysCache_.begin(), allKeysCache_, keyToIndex_[key].iter);
80         keyToIndex_[key].iter = allKeysCache_.cbegin();
81     }
82 
83 private:
84     std::unordered_map<K, CacheNode<K, V>> keyToIndex_;
85     std::list<K> allKeysCache_;
86     std::mutex lmtMutex_;
87 };
88 
89 using ConcurrentQueries = std::pair<int, int>;
90 
91 class QueryStatusLogUtil {
92 public:
93     static void LogTooManyQueryRules(const std::string sql);
94     static void LogTooManyConcurrentQueries(const int limit, bool innerQuery = true);
95     static void LogQueryOverTime(time_t costTime, const std::string sql, bool innerQuery = true);
96     static void LogQueryCountOverLimit(const int32_t queryCount, const std::string& sql,
97         bool innerQuery = true);
98     static void LogQueryTooFrequently(const std::string& sql, const std::string& processName = std::string(""),
99         bool innerQuery = true);
100 
101 private:
102     static void Logging(const std::string& detail);
103 };
104 
105 class SysEventQueryWrapper : public SysEventQuery {
106 public:
SysEventQueryWrapper(const std::string & domain,const std::vector<std::string> & names)107     SysEventQueryWrapper(const std::string& domain, const std::vector<std::string>& names)
108         : SysEventQuery(domain, names) {}
SysEventQueryWrapper(const std::string & domain,const std::vector<std::string> & names,uint32_t type,int64_t toSeq,int64_t fromSeq)109     SysEventQueryWrapper(const std::string& domain, const std::vector<std::string>& names,
110         uint32_t type, int64_t toSeq, int64_t fromSeq) : SysEventQuery(domain, names, type, toSeq, fromSeq) {}
~SysEventQueryWrapper()111     ~SysEventQueryWrapper() {}
112 
113 public:
114     virtual ResultSet Execute(int limit, DbQueryTag tag, QueryProcessInfo callerInfo,
115         DbQueryCallback queryCallback) override;
116 
117 public:
118     struct QueryRecord {
119         size_t count;
120         uint64_t begin;
121 
122     public:
QueryRecordQueryRecord123         QueryRecord()
124         {
125             count = 0;
126             begin = INVALID_TIME_STAMP;
127         }
128 
129     public:
IsValidQueryRecord130         bool IsValid()
131         {
132             return count > 0;
133         }
134     };
135 
136 private:
137     bool IsConditionCntValid(const DbQueryTag& tag);
138     bool IsQueryCntLimitValid(const DbQueryTag& tag, const int limit, const DbQueryCallback& callback);
139     bool IsQueryCostTimeValid(const DbQueryTag& tag, const time_t before, const time_t after,
140         const DbQueryCallback& callback);
141     bool IsConcurrentQueryCntValid(const DbQueryTag& tag, const DbQueryCallback& callback);
142     bool IsQueryFrequenceValid(const DbQueryTag& tag, const QueryProcessInfo& processInfo,
143         const DbQueryCallback& callback);
144     void IncreaseConcurrentCnt(const DbQueryTag& tag);
145     void DecreaseConcurrentCnt(const DbQueryTag& tag);
146 
147 private:
148     static ConcurrentQueries concurrentQueries_;
149     static LruCache<pid_t, QueryRecord> queryController_;
150     static std::mutex concurrentQueriesMutex_;
151     static std::mutex lastQueriesMutex_;
152 };
153 } // namespace EventStore
154 } // namespace HiviewDFX
155 } // namespace OHOS
156 
157 #endif // HIVIEW_BASE_EVENT_STORE_INCLUDE_SYS_EVENT_QUERY_WRAPPER_H
158