1 /*
2 * Copyright (c) 2021 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 "doc_store.h"
17
18 #include <cinttypes>
19 #include <memory>
20
21 #include "doc_db.h"
22 #include "doc_util.h"
23 #include "ejdb2.h"
24 #include "hilog/log.h"
25
26 namespace OHOS {
27 namespace HiviewDFX {
28 constexpr HiLogLabel LABEL = {LOG_CORE, 0xD002D10, "HiView-DOCDB"};
29 class CallBackInfo {
30 public:
CallBackInfo(IWXSTR * xstr,std::function<int (int,const Entry &)> callback)31 CallBackInfo(IWXSTR *xstr, std::function<int (int, const Entry&)> callback)
32 : finish_(false), xstr_(xstr), callback_(callback)
33 {
34 }
35
~CallBackInfo()36 ~CallBackInfo()
37 {
38 }
39
Clear()40 void Clear()
41 {
42 if (xstr_ != nullptr) {
43 iwxstr_clear(xstr_);
44 }
45 }
46
DoCallBack(int id,const Entry & entry)47 void DoCallBack(int id, const Entry& entry)
48 {
49 if (callback_(id, entry) != 0) {
50 finish_ = true;
51 }
52 }
53
GetIWXSTR()54 IWXSTR* GetIWXSTR()
55 {
56 return xstr_;
57 }
58
IsFinish() const59 bool IsFinish() const
60 {
61 return finish_;
62 }
63 private:
64 bool finish_;
65 IWXSTR *xstr_;
66 std::function<int (int, const Entry&)> callback_;
67 };
68
Put(const Entry & entry,const char * coll)69 int DocStore::Put(const Entry &entry, const char* coll)
70 {
71 std::lock_guard<std::mutex> lock(dbStoreMutex);
72 if (dbPtr == nullptr) {
73 return -1;
74 }
75
76 JBL jbl = 0;
77 iwrc rc = 0;
78 rc = jbl_from_json(&jbl, entry.value.c_str());
79 RCGO(rc, FINISH);
80
81 rc = ejdb_put_new(dbPtr->db_, coll, jbl, const_cast<int64_t*>(&entry.id));
82 RCGO(rc, FINISH);
83 HiLog::Debug(LABEL, "put data to doc store success, coll=%{public}s", coll);
84 FINISH:
85 if (jbl != 0) {
86 jbl_destroy(&jbl);
87 }
88 if (rc != 0) {
89 iwlog_ecode_error3(rc);
90 HiLog::Error(LABEL, "put data to doc store failed, reason:%{public}s", iwlog_ecode_explained(rc));
91 return MapErrorCode(rc);
92 }
93 return 0;
94 }
95
PutBatch(const std::vector<Entry> & entries)96 int DocStore::PutBatch(const std::vector<Entry> &entries)
97 {
98 if (dbPtr == nullptr) {
99 return -1;
100 }
101 for (auto entry = entries.begin(); entry != entries.end(); entry++) {
102 Put(*entry);
103 }
104 return 0;
105 }
106
Merge(const Entry & entry,const char * coll)107 int DocStore::Merge(const Entry &entry, const char* coll)
108 {
109 std::lock_guard<std::mutex> lock(dbStoreMutex);
110 if (entry.id <= 0) {
111 HiLog::Error(LABEL, "id less than 0");
112 return -1;
113 }
114
115 if (entry.value.empty()) {
116 HiLog::Error(LABEL, "value is empty");
117 return -1;
118 }
119
120 iwrc rc = ejdb_patch(dbPtr->db_, coll, entry.value.c_str(), entry.id);
121 if (rc != 0) {
122 HiLog::Error(LABEL, "merge data to doc store failed, reason:%{public}s", iwlog_ecode_explained(rc));
123 return MapErrorCode(rc);
124 }
125 return 0;
126 }
127
Delete(const DataQuery & query,const char * coll)128 int DocStore::Delete(const DataQuery &query, const char* coll)
129 {
130 std::lock_guard<std::mutex> lock(dbStoreMutex);
131 if (dbPtr == nullptr) {
132 return -1;
133 }
134 std::string delSql = query.ToDelString(query.limit_);
135 HiLog::Debug(LABEL, "delete=%{public}s", delSql.c_str());
136 JQL q = 0;
137 iwrc rc = jql_create(&q, coll, delSql.c_str());
138 RCGO(rc, FINISH);
139
140 EJDB_EXEC ux;
141 ux.cnt = 0;
142 ux.db = dbPtr->db_;
143 ux.limit = 0;
144 ux.log = 0;
145 ux.opaque = 0;
146 ux.pool = 0;
147 ux.q = q;
148 ux.skip = 0;
149 ux.visitor = 0;
150 rc = ejdb_exec(&ux);
151 RCGO(rc, FINISH);
152 FINISH:
153 if (q) {
154 jql_destroy(&q);
155 }
156 if (rc != 0) {
157 iwlog_ecode_error3(rc);
158 HiLog::Error(LABEL, "delete data from doc store failed, reason:%{public}s", iwlog_ecode_explained(rc));
159 return MapErrorCode(rc);
160 }
161 HiLog::Debug(LABEL, "delete num=%{public}" PRId64, ux.cnt);
162 return ux.cnt;
163 }
164
GetNum()165 int DocStore::GetNum()
166 {
167 std::lock_guard<std::mutex> lock(dbStoreMutex);
168 if (dbPtr == nullptr) {
169 return -1;
170 }
171 int num = 0;
172 JBL meta = nullptr;
173 JBL jbl = nullptr;
174 iwrc rc = ejdb_get_meta(dbPtr->db_, &meta);
175 RCGO(rc, FINISH);
176 rc = jbl_at(meta, "/collections/0/rnum", &jbl);
177 RCGO(rc, FINISH);
178 num = jbl_get_i64(jbl);
179 FINISH:
180 if (meta != nullptr) {
181 jbl_destroy(&meta);
182 }
183 if (jbl != nullptr) {
184 jbl_destroy(&jbl);
185 }
186 if (rc != 0) {
187 iwlog_ecode_error3(rc);
188 HiLog::Error(LABEL, "failed to get meta from doc store, reason:%{public}s", iwlog_ecode_explained(rc));
189 return MapErrorCode(rc);
190 }
191 HiLog::Debug(LABEL, "get num=%{public}d", num);
192 return num;
193 }
194
GetEntriesWithQuery(const DataQuery & query,std::vector<Entry> & entries,const char * coll) const195 int DocStore::GetEntriesWithQuery(const DataQuery &query, std::vector<Entry> &entries, const char* coll) const
196 {
197 if (dbPtr == nullptr) {
198 return -1;
199 }
200
201 unsigned int count = 0;
202 IWXSTR *xstr = iwxstr_new();
203 EJDB_DOC doc = nullptr;
204 EJDB_LIST listp;
205 HiLog::Debug(LABEL, "query=%{public}s, limit=%{public}d", query.ToString().c_str(), query.limit_);
206 iwrc rc = ejdb_list2(dbPtr->db_, coll, query.ToString().c_str(), query.limit_, &listp);
207 RCGO(rc, FINISH);
208 doc = listp->first;
209 while (doc != nullptr) {
210 count++;
211 iwxstr_clear(xstr);
212 iwrc resRc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
213 if (resRc != 0) {
214 HiLog::Error(LABEL, "query result=%{public}" PRId64 " value is invalid, reason:%{public}s",
215 doc->id, iwlog_ecode_explained(resRc));
216 doc = doc->next;
217 continue;
218 }
219
220 Entry entry;
221 entry.id = doc->id;
222 entry.value = iwxstr_ptr(xstr);
223 if (entry.value.empty()) {
224 HiLog::Debug(LABEL, "query result=%{public}" PRId64 " value is empty", doc->id);
225 doc = doc->next;
226 continue;
227 }
228 entries.emplace_back(entry);
229 doc = doc->next;
230 }
231 HiLog::Debug(LABEL, "query count=%{public}u", count);
232 FINISH:
233 if (xstr) {
234 iwxstr_destroy(xstr);
235 }
236
237 if (rc == 0) {
238 ejdb_list_destroy(&listp);
239 } else {
240 iwlog_ecode_error3(rc);
241 HiLog::Error(LABEL, "query data from doc store failed, reason:%{public}s", iwlog_ecode_explained(rc));
242 return MapErrorCode(rc);
243 }
244 return 0;
245 }
246
DocumentsVisitor(EJDB_EXEC * ctx,const EJDB_DOC doc,int64_t * step)247 static iwrc DocumentsVisitor(EJDB_EXEC *ctx, const EJDB_DOC doc, int64_t *step)
248 {
249 CallBackInfo* callBackInfoPtr = reinterpret_cast<CallBackInfo*>(ctx->opaque);
250 if (callBackInfoPtr == nullptr) {
251 return 0;
252 }
253 if (callBackInfoPtr->IsFinish()) {
254 return 0;
255 }
256 callBackInfoPtr->Clear();
257 Entry entry;
258 entry.id = doc->id;
259 iwrc rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, callBackInfoPtr->GetIWXSTR(), 0);
260 entry.value = iwxstr_ptr(callBackInfoPtr->GetIWXSTR());
261 callBackInfoPtr->DoCallBack(ctx->cnt, entry);
262 return rc;
263 }
264
GetEntryDuringQuery(const DataQuery & query,std::function<int (int,const Entry &)> callback,const char * coll) const265 int DocStore::GetEntryDuringQuery(const DataQuery &query, std::function<int (int, const Entry&)> callback,
266 const char* coll) const
267 {
268 if (dbPtr == nullptr) {
269 return -1;
270 }
271 HiLog::Debug(LABEL, "query=%{public}s, limit=%{public}d", query.ToString().c_str(), query.limit_);
272 IWXSTR *xstr = iwxstr_new();
273 CallBackInfo *callBackInfoPtr = new CallBackInfo(xstr, callback);
274 JQL q = 0;
275 iwrc rc = jql_create(&q, coll, query.ToString().c_str());
276 RCGO(rc, FINISH);
277
278 EJDB_EXEC ux;
279 ux.cnt = 1;
280 ux.db = dbPtr->db_;
281 ux.limit = 0;
282 ux.log = 0;
283 ux.opaque = reinterpret_cast<CallBackInfo*>(callBackInfoPtr);
284 ux.pool = 0;
285 ux.q = q;
286 ux.skip = 0;
287 ux.visitor = DocumentsVisitor;
288 rc = ejdb_exec(&ux);
289 RCGO(rc, FINISH);
290 FINISH:
291 if (q) {
292 jql_destroy(&q);
293 }
294
295 if (xstr) {
296 iwxstr_clear(xstr);
297 }
298
299 if (callBackInfoPtr) {
300 delete callBackInfoPtr;
301 }
302
303 if (rc != 0) {
304 iwlog_ecode_error3(rc);
305 HiLog::Error(LABEL, "query data from doc store failed, reason:%{public}s", iwlog_ecode_explained(rc));
306 return MapErrorCode(rc);
307 }
308 return 0;
309 }
310 } // HiviewDFX
311 } // OHOS