1 /*
2  * Copyright (c) 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_repeat_db.h"
17 
18 #include "hiview_logger.h"
19 #include "rdb_helper.h"
20 #include "sql_util.h"
21 #include "sys_event_database.h"
22 
23 namespace OHOS {
24 namespace HiviewDFX {
25 DEFINE_LOG_TAG("HiView-SysEvent-Repeat-Db");
26 namespace {
27     const std::string DB_FILE_NAME = "sys_event_history.db";
28     const std::string TABLE_NAME = "sys_event_history";
29     constexpr int32_t DB_VERSION = 1;
30 
31     const std::string COLUMN_DOMAIN = "domain";
32     const std::string COLUMN_NAME = "name";
33     const std::string COLUMN_EVENT_HASH = "eventHash";
34     const std::string COLUMN_HAPPENTIME = "happentime";
35     constexpr int32_t MAX_DB_COUNT = 10000;
36 
37 class SysEventRepeatDbCallback : public NativeRdb::RdbOpenCallback {
38 public:
39     int OnCreate(NativeRdb::RdbStore &rdbStore) override;
40     int OnUpgrade(NativeRdb::RdbStore &rdbStore, int oldVersion, int newVersion) override;
41 };
42 
OnCreate(NativeRdb::RdbStore & rdbStore)43 int SysEventRepeatDbCallback::OnCreate(NativeRdb::RdbStore& rdbStore)
44 {
45     HIVIEW_LOGI("create dbStore");
46     return NativeRdb::E_OK;
47 }
48 
OnUpgrade(NativeRdb::RdbStore & rdbStore,int oldVersion,int newVersion)49 int SysEventRepeatDbCallback::OnUpgrade(NativeRdb::RdbStore& rdbStore, int oldVersion, int newVersion)
50 {
51     HIVIEW_LOGI("oldVersion=%{public}d, newVersion=%{public}d", oldVersion, newVersion);
52     return NativeRdb::E_OK;
53 }
54 }
55 
SysEventRepeatDb()56 SysEventRepeatDb::SysEventRepeatDb()
57 {
58     InitDbStore();
59     RefreshDbCount();
60 }
61 
InitDbStore()62 void SysEventRepeatDb::InitDbStore()
63 {
64     auto dbFullName = EventStore::SysEventDatabase::GetInstance().GetDatabaseDir() + DB_FILE_NAME;
65     NativeRdb::RdbStoreConfig config(dbFullName);
66     config.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
67     SysEventRepeatDbCallback callback;
68     auto ret = NativeRdb::E_OK;
69     dbStore_ = NativeRdb::RdbHelper::GetRdbStore(config, DB_VERSION, callback, ret);
70     if (ret != NativeRdb::E_OK) {
71         HIVIEW_LOGE("failed to init db store, db store path=%{public}s", dbFullName.c_str());
72         dbStore_ = nullptr;
73         return;
74     }
75     CreateTable();
76 }
77 
CreateTable()78 void SysEventRepeatDb::CreateTable()
79 {
80     if (dbStore_ == nullptr) {
81         return;
82     }
83     /**
84      * table: sys_event_history
85      *
86      * describe: store data that app task
87      * |---------|------|-----------|------------|
88      * |  domain | name | eventHash | happentime |
89      * |---------|------|-----------|------------|
90      * |  TEXT   | TEXT |   TEXT    |    INT64   |
91      * |---------|------|-----------|------------|
92      */
93     const std::vector<std::pair<std::string, std::string>> fields = {
94         {COLUMN_DOMAIN, SqlUtil::COLUMN_TYPE_STR},
95         {COLUMN_NAME, SqlUtil::COLUMN_TYPE_STR},
96         {COLUMN_EVENT_HASH, SqlUtil::COLUMN_TYPE_STR},
97         {COLUMN_HAPPENTIME, SqlUtil::COLUMN_TYPE_INT},
98     };
99     std::string sql = SqlUtil::GenerateCreateSql(TABLE_NAME, fields);
100     if (dbStore_->ExecuteSql(sql) != NativeRdb::E_OK) {
101         HIVIEW_LOGE("failed to create table, sql=%{public}s", sql.c_str());
102         return;
103     }
104 
105     std::string indexSql = "create index sys_event_his_index1 on ";
106     indexSql.append(TABLE_NAME).append("(").append(COLUMN_DOMAIN).append(", ")
107         .append(COLUMN_NAME).append(",").append(COLUMN_EVENT_HASH).append(");");
108     if (dbStore_->ExecuteSql(indexSql) != NativeRdb::E_OK) {
109         HIVIEW_LOGE("failed to create index1, sql=%{public}s", indexSql.c_str());
110         return;
111     }
112 
113     std::string indexHappentimeSql = "create index sys_event_his_index2 on ";
114     indexHappentimeSql.append(TABLE_NAME).append("(").append(COLUMN_HAPPENTIME).append(");");
115     if (dbStore_->ExecuteSql(indexHappentimeSql) != NativeRdb::E_OK) {
116         HIVIEW_LOGE("failed to create index2, sql=%{public}s", indexHappentimeSql.c_str());
117         return;
118     }
119 }
120 
CheckAndClearDb(const int64_t happentime)121 void SysEventRepeatDb::CheckAndClearDb(const int64_t happentime)
122 {
123     if (dbCount_ <= MAX_DB_COUNT) {
124         return;
125     }
126     Clear(happentime);
127 }
128 
Clear(const int64_t happentime)129 void SysEventRepeatDb::Clear(const int64_t happentime)
130 {
131     ClearHistory(happentime);
132     RefreshDbCount();
133 }
134 
Insert(const SysEventHashRecord & sysEventHashRecord)135 bool SysEventRepeatDb::Insert(const SysEventHashRecord &sysEventHashRecord)
136 {
137     if (dbStore_ == nullptr) {
138         return false;
139     }
140     NativeRdb::ValuesBucket bucket;
141     bucket.PutString(COLUMN_DOMAIN, sysEventHashRecord.domain);
142     bucket.PutString(COLUMN_NAME, sysEventHashRecord.name);
143     bucket.PutString(COLUMN_EVENT_HASH, sysEventHashRecord.eventHash);
144     bucket.PutLong(COLUMN_HAPPENTIME, sysEventHashRecord.happentime);
145     int64_t seq = 0;
146     int ret = dbStore_->Insert(seq, TABLE_NAME, bucket);
147     if (ret != NativeRdb::E_OK) {
148         HIVIEW_LOGE("failed to insert app event task, ret=%{public}d", ret);
149         return false;
150     }
151     ++dbCount_;
152     return true;
153 }
154 
Update(const SysEventHashRecord & sysEventHashRecord)155 bool SysEventRepeatDb::Update(const SysEventHashRecord &sysEventHashRecord)
156 {
157     if (dbStore_ == nullptr) {
158         return false;
159     }
160     NativeRdb::AbsRdbPredicates predicates(TABLE_NAME);
161     predicates.EqualTo(COLUMN_DOMAIN, sysEventHashRecord.domain);
162     predicates.EqualTo(COLUMN_NAME, sysEventHashRecord.name);
163     predicates.EqualTo(COLUMN_EVENT_HASH, sysEventHashRecord.eventHash);
164     NativeRdb::ValuesBucket bucket;
165     bucket.PutLong(COLUMN_HAPPENTIME, sysEventHashRecord.happentime);
166     int updateRowNum = 0;
167     if (dbStore_->Update(updateRowNum, bucket, predicates) != NativeRdb::E_OK) {
168         HIVIEW_LOGE("failed to update table.");
169         return false;
170     }
171     return true;
172 }
173 
ClearHistory(const int64_t happentime)174 void SysEventRepeatDb::ClearHistory(const int64_t happentime)
175 {
176     if (dbStore_ == nullptr) {
177         return;
178     }
179     std::string whereClause = COLUMN_HAPPENTIME;
180         whereClause.append(" < ").append(std::to_string(happentime));
181     int deleteRows = 0;
182     if (dbStore_->Delete(deleteRows, TABLE_NAME, whereClause) != NativeRdb::E_OK) {
183         HIVIEW_LOGE("failed to delete, whereClause=%{public}s", whereClause.c_str());
184         return;
185     }
186 }
187 
RefreshDbCount()188 void SysEventRepeatDb::RefreshDbCount()
189 {
190     if (dbStore_ == nullptr) {
191         return;
192     }
193     std::string sql;
194     sql.append("SELECT count(*) from ").append(TABLE_NAME).append(";");
195     std::shared_ptr<NativeRdb::ResultSet> resultSet = dbStore_->QuerySql(sql, std::vector<std::string> {});
196     if (resultSet == nullptr) {
197         HIVIEW_LOGE("failed to query from table %{public}s, db is null", TABLE_NAME.c_str());
198         return;
199     }
200     if (resultSet->GoToNextRow() == NativeRdb::E_OK) {
201         resultSet->GetLong(0, dbCount_);
202         resultSet->Close();
203         return;
204     }
205     resultSet->Close();
206 }
207 
QueryHappentime(SysEventHashRecord & sysEventHashRecord)208 int64_t SysEventRepeatDb::QueryHappentime(SysEventHashRecord &sysEventHashRecord)
209 {
210     if (dbStore_ == nullptr) {
211         return 0;
212     }
213     NativeRdb::AbsRdbPredicates predicates(TABLE_NAME);
214     predicates.EqualTo(COLUMN_DOMAIN, sysEventHashRecord.domain);
215     predicates.EqualTo(COLUMN_NAME, sysEventHashRecord.name);
216     predicates.EqualTo(COLUMN_EVENT_HASH, sysEventHashRecord.eventHash);
217     auto resultSet = dbStore_->Query(predicates, {COLUMN_HAPPENTIME});
218     if (resultSet == nullptr) {
219         HIVIEW_LOGE("failed to query from table %{public}s, db is null", TABLE_NAME.c_str());
220         return 0;
221     }
222 
223     if (resultSet->GoToNextRow() == NativeRdb::E_OK) {
224         int64_t happentime = 0;
225         resultSet->GetLong(0, happentime);   // 0 is result of happentime
226         resultSet->Close();
227         return happentime;
228     }
229     resultSet->Close();
230     return 0;
231 }
232 
233 } // HiviewDFX
234 } // OHOS