1 /*
2  * Copyright (c) 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 #include "sys_event_doc.h"
16 
17 #include <cerrno>
18 
19 #include "base_def.h"
20 #include "event_store_config.h"
21 #include "file_util.h"
22 #include "hiview_logger.h"
23 #include "sys_event_database.h"
24 #include "sys_event_doc_reader.h"
25 #include "sys_event_doc_writer.h"
26 
27 namespace OHOS {
28 namespace HiviewDFX {
29 namespace EventStore {
30 DEFINE_LOG_TAG("HiView-SysEventDoc");
31 namespace {
32 const char FILE_NAME_SEPARATOR[] = "-";
33 const char FILE_SEPARATOR[] = "/";
34 const char FILE_EXT[] = ".db";
35 }
36 
SysEventDoc(const std::string & domain,const std::string & name)37 SysEventDoc::SysEventDoc(const std::string& domain, const std::string& name)
38     : writer_(nullptr), reader_(nullptr), domain_(domain), name_(name), type_(0)
39 {}
40 
SysEventDoc(const std::string & file)41 SysEventDoc::SysEventDoc(const std::string& file) : writer_(nullptr), reader_(nullptr), type_(0), curFile_(file)
42 {}
43 
~SysEventDoc()44 SysEventDoc::~SysEventDoc()
45 {}
46 
Insert(const std::shared_ptr<SysEvent> & sysEvent)47 int SysEventDoc::Insert(const std::shared_ptr<SysEvent>& sysEvent)
48 {
49     if (sysEvent == nullptr) {
50         HIVIEW_LOGI("event is null");
51         return DOC_STORE_ERROR_NULL;
52     }
53 
54     // init a writer for writing
55     auto ret = DOC_STORE_SUCCESS;
56     if (ret = InitWriter(sysEvent); ret != 0) {
57         HIVIEW_LOGE("failed to init writer from file=%{public}s", curFile_.c_str());
58         return ret;
59     }
60 
61     // write event to the file
62     if (ret = writer_->Write(sysEvent); ret == DOC_STORE_NEW_FILE) {
63         // need to store to a new file
64         if (ret = CreateCurFile(GetDir(), sysEvent); ret != DOC_STORE_SUCCESS) {
65             HIVIEW_LOGE("failed to update curFile=%{public}s", curFile_.c_str());
66             return ret;
67         }
68         writer_ = std::make_shared<SysEventDocWriter>(curFile_);
69         HIVIEW_LOGD("update writer in new File=%{public}s", curFile_.c_str());
70         return writer_->Write(sysEvent);
71     }
72     return ret;
73 }
74 
Query(const DocQuery & query,EntryQueue & entries,int & num)75 int SysEventDoc::Query(const DocQuery& query, EntryQueue& entries, int& num)
76 {
77     auto ret = DOC_STORE_SUCCESS;
78     if (reader_ == nullptr) {
79         if (ret = InitReader(); ret != DOC_STORE_SUCCESS) {
80             return ret;
81         }
82     }
83     return reader_->Read(query, entries, num);
84 }
85 
InitWriter(const std::shared_ptr<SysEvent> & sysEvent)86 int SysEventDoc::InitWriter(const std::shared_ptr<SysEvent>& sysEvent)
87 {
88     if (writer_ == nullptr || IsNeedUpdateCurFile()) {
89         type_ = sysEvent->eventType_;
90         level_ = sysEvent->GetLevel();
91         if (auto ret = UpdateCurFile(sysEvent); ret != 0) {
92             HIVIEW_LOGE("failed to update current file");
93             return ret;
94         }
95         writer_ = std::make_shared<SysEventDocWriter>(curFile_);
96         HIVIEW_LOGD("init writer in curFile=%{public}s", curFile_.c_str());
97     }
98     return DOC_STORE_SUCCESS;
99 }
100 
InitReader()101 int SysEventDoc::InitReader()
102 {
103     if (curFile_.empty() || !FileUtil::FileExists(curFile_)) {
104         HIVIEW_LOGE("failed to init reader from file=%{public}s", curFile_.c_str());
105         return DOC_STORE_ERROR_IO;
106     }
107     reader_ = std::make_shared<SysEventDocReader>(curFile_);
108     return DOC_STORE_SUCCESS;
109 }
110 
IsFileFull(const std::string & file)111 bool SysEventDoc::IsFileFull(const std::string& file)
112 {
113     return FileUtil::GetFileSize(file) >= GetMaxFileSize();
114 }
115 
IsNeedUpdateCurFile()116 bool SysEventDoc::IsNeedUpdateCurFile()
117 {
118     return curFile_.empty() || IsFileFull(curFile_);
119 }
120 
UpdateCurFile(const std::shared_ptr<SysEvent> & sysEvent)121 int SysEventDoc::UpdateCurFile(const std::shared_ptr<SysEvent>& sysEvent)
122 {
123     std::string dir = GetDir();
124     if (dir.empty()) {
125         return DOC_STORE_ERROR_IO;
126     }
127     std::string filePath = GetCurFile(dir);
128     if (filePath.empty() || IsFileFull(filePath)) {
129         return CreateCurFile(dir, sysEvent);
130     }
131     curFile_ = filePath;
132     return DOC_STORE_SUCCESS;
133 }
134 
GetDir()135 std::string SysEventDoc::GetDir()
136 {
137     std::string dir = SysEventDatabase::GetInstance().GetDatabaseDir() + domain_;
138     if (!FileUtil::IsDirectory(dir) && !FileUtil::ForceCreateDirectory(dir)) {
139         HIVIEW_LOGE("failed to create domain dir=%{public}s", dir.c_str());
140         return "";
141     }
142     return dir;
143 }
144 
GetCurFile(const std::string & dir)145 std::string SysEventDoc::GetCurFile(const std::string& dir)
146 {
147     std::vector<std::string> files;
148     FileUtil::GetDirFiles(dir, files);
149     std::string curFile;
150     for (auto& file : files) {
151         if (file.find(FILE_SEPARATOR + name_ + FILE_NAME_SEPARATOR) == std::string::npos) {
152             continue;
153         }
154         if ((file.size() == curFile.size() && file > curFile) || file.size() > curFile.size()) {
155             curFile = file;
156         }
157     }
158     return curFile;
159 }
160 
GetMaxFileSize()161 uint32_t SysEventDoc::GetMaxFileSize()
162 {
163     return EventStoreConfig::GetInstance().GetMaxFileSize(type_) * NUM_OF_BYTES_IN_KB;
164 }
165 
CreateCurFile(const std::string & dir,const std::shared_ptr<SysEvent> & sysEvent)166 int SysEventDoc::CreateCurFile(const std::string& dir, const std::shared_ptr<SysEvent>& sysEvent)
167 {
168     auto seq = sysEvent->GetEventSeq();
169     std::string filePath = dir + FILE_SEPARATOR;
170     filePath.append(name_).append(FILE_NAME_SEPARATOR).append(std::to_string(type_)).append(FILE_NAME_SEPARATOR)
171         .append(level_).append(FILE_NAME_SEPARATOR).append(std::to_string(seq)).append(FILE_EXT);
172     if (FileUtil::CreateFile(filePath, FileUtil::FILE_PERM_660) != 0 && !FileUtil::FileExists(filePath)) {
173         HIVIEW_LOGE("failed to create file=%{public}s, errno=%{public}d", filePath.c_str(), errno);
174         return DOC_STORE_ERROR_IO;
175     }
176     curFile_ = filePath;
177     return DOC_STORE_SUCCESS;
178 }
179 } // EventStore
180 } // HiviewDFX
181 } // OHOS
182