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 "generic_kvdb.h"
17
18 #include "db_common.h"
19 #include "db_constant.h"
20 #include "db_errno.h"
21 #include "kvdb_commit_notify_filterable_data.h"
22 #include "kvdb_utils.h"
23 #include "log_print.h"
24 #include "package_file.h"
25 #include "runtime_context.h"
26
27 namespace DistributedDB {
28 DEFINE_OBJECT_TAG_FACILITIES(GenericKvDB);
29
GenericKvDB()30 GenericKvDB::GenericKvDB()
31 : performance_(nullptr),
32 eventNotifyCounter_(0),
33 connectionCount_(0),
34 notificationChain_(nullptr),
35 operatePerm_(OperatePerm::NORMAL_PERM),
36 isRebuild_(false)
37 {}
38
~GenericKvDB()39 GenericKvDB::~GenericKvDB()
40 {
41 if (connectionCount_ > 0) {
42 LOGF("KvDB destructed with connection count > 0.");
43 }
44
45 if (notificationChain_ != nullptr) {
46 RefObject::KillAndDecObjRef(notificationChain_);
47 notificationChain_ = nullptr;
48 }
49 }
50
GetMyProperties() const51 const KvDBProperties &GenericKvDB::GetMyProperties() const
52 {
53 return MyProp();
54 }
55
GetDBConnection(int & errCode)56 IKvDBConnection *GenericKvDB::GetDBConnection(int &errCode)
57 {
58 std::lock_guard<std::mutex> lock(connectMutex_);
59 if (operatePerm_ == OperatePerm::DISABLE_PERM) {
60 errCode = -E_STALE;
61 return nullptr;
62 } else if (operatePerm_ == OperatePerm::REKEY_MONOPOLIZE_PERM ||
63 operatePerm_ == OperatePerm::IMPORT_MONOPOLIZE_PERM) {
64 errCode = -E_BUSY;
65 return nullptr;
66 }
67
68 GenericKvDBConnection *connection = NewConnection(errCode);
69 if (connection != nullptr) {
70 IncObjRef(this);
71 IncreaseConnectionCounter();
72 if (isRebuild_) {
73 connection->MarkRebuild();
74 }
75 }
76 return connection;
77 }
78
OnClose(const std::function<void (void)> & notifier)79 void GenericKvDB::OnClose(const std::function<void(void)> ¬ifier)
80 {
81 AutoLock lockGuard(this);
82 if (notifier) {
83 closeNotifiers_.push_back(notifier);
84 } else {
85 LOGW("Register kvdb 'Close()' notifier failed, notifier is null.");
86 }
87 }
88
GetStoreId() const89 std::string GenericKvDB::GetStoreId() const
90 {
91 return MyProp().GetStringProp(KvDBProperties::STORE_ID, "");
92 }
93
DelConnection(GenericKvDBConnection * connection)94 void GenericKvDB::DelConnection(GenericKvDBConnection *connection)
95 {
96 if (connection == nullptr) {
97 return;
98 }
99 delete connection;
100 connection = nullptr;
101 }
102
ReleaseDBConnection(GenericKvDBConnection * connection)103 void GenericKvDB::ReleaseDBConnection(GenericKvDBConnection *connection)
104 {
105 if (connectionCount_.load() == 1) {
106 SetConnectionFlag(false);
107 }
108
109 if (connection != nullptr) {
110 {
111 std::lock_guard<std::mutex> lock(connectMutex_);
112 connection->SetSafeDeleted();
113 DelConnection(connection);
114 DecreaseConnectionCounter();
115 }
116 DecObjRef(this);
117 }
118 }
119
CommitNotify(int notifyEvent,KvDBCommitNotifyFilterAbleData * data)120 void GenericKvDB::CommitNotify(int notifyEvent, KvDBCommitNotifyFilterAbleData *data)
121 {
122 if (notificationChain_ == nullptr) {
123 LOGE("Failed to do commit notify, notificationChain_ is nullptr.");
124 return;
125 }
126 ++eventNotifyCounter_;
127 if (data == nullptr) {
128 notificationChain_->NotifyEvent(static_cast<EventType>(notifyEvent), nullptr);
129 } else {
130 data->SetMyDb(this, eventNotifyCounter_);
131 RefObject::IncObjRef(data);
132 int errCode = RuntimeContext::GetInstance()->ScheduleQueuedTask(GetStoreId(),
133 [this, notifyEvent, data] { CommitNotifyAsync(notifyEvent, data); });
134 if (errCode != E_OK) {
135 LOGE("Failed to do commit notify, schedule task err:%d.", errCode);
136 RefObject::DecObjRef(data);
137 data = nullptr;
138 }
139 }
140 }
141
CorruptNotifyAsync() const142 void GenericKvDB::CorruptNotifyAsync() const
143 {
144 {
145 std::lock_guard<std::mutex> lock(corruptMutex_);
146 if (corruptHandler_) {
147 corruptHandler_();
148 }
149 }
150
151 DecObjRef(this);
152 }
153
CorruptNotify() const154 void GenericKvDB::CorruptNotify() const
155 {
156 IncObjRef(this);
157 int errCode = RuntimeContext::GetInstance()->ScheduleQueuedTask(GetStoreId(),
158 [this] { CorruptNotifyAsync(); });
159 if (errCode != E_OK) {
160 LOGE("Failed to do the corrupt notify, schedule task err:%d.", errCode);
161 DecObjRef(this);
162 }
163 }
164
TryToDisableConnection(OperatePerm perm)165 int GenericKvDB::TryToDisableConnection(OperatePerm perm)
166 {
167 std::lock_guard<std::mutex> lock(connectMutex_);
168 if (operatePerm_ != OperatePerm::NORMAL_PERM) {
169 return -E_BUSY;
170 }
171 // more than one connection, should prevent the rekey/import operation.
172 if ((perm == OperatePerm::REKEY_MONOPOLIZE_PERM || perm == OperatePerm::IMPORT_MONOPOLIZE_PERM) &&
173 connectionCount_ > 1) {
174 return -E_BUSY;
175 }
176 operatePerm_ = perm;
177 return E_OK;
178 }
179
ReEnableConnection(OperatePerm perm)180 void GenericKvDB::ReEnableConnection(OperatePerm perm)
181 {
182 std::lock_guard<std::mutex> lock(connectMutex_);
183 if (perm == operatePerm_) {
184 operatePerm_ = OperatePerm::NORMAL_PERM;
185 }
186 }
187
RegisterEventListener(EventType type,const NotificationChain::Listener::OnEvent & onEvent,const NotificationChain::Listener::OnFinalize & onFinalize,int & errCode)188 NotificationChain::Listener *GenericKvDB::RegisterEventListener(EventType type,
189 const NotificationChain::Listener::OnEvent &onEvent,
190 const NotificationChain::Listener::OnFinalize &onFinalize, int &errCode)
191 {
192 NotificationChain::Listener *listener = nullptr;
193 if (notificationChain_ != nullptr) {
194 listener = notificationChain_->RegisterListener(type, onEvent, onFinalize, errCode);
195 } else {
196 errCode = -E_NOT_PERMIT;
197 }
198 return listener;
199 }
200
GetEventNotifyCounter() const201 uint64_t GenericKvDB::GetEventNotifyCounter() const
202 {
203 return eventNotifyCounter_;
204 }
205
206 // Called when a new connection created.
IncreaseConnectionCounter()207 void GenericKvDB::IncreaseConnectionCounter()
208 {
209 connectionCount_.fetch_add(1, std::memory_order_seq_cst);
210 if (connectionCount_.load() > 0) {
211 SetConnectionFlag(true);
212 }
213 }
214
215 // Called when a connection released.
DecreaseConnectionCounter()216 void GenericKvDB::DecreaseConnectionCounter()
217 {
218 int count = connectionCount_.fetch_sub(1, std::memory_order_seq_cst);
219 if (count <= 0) {
220 LOGF("Decrease kvdb connection counter failed, count <= 0.");
221 return;
222 }
223 if (count != 1) {
224 return;
225 }
226
227 operatePerm_ = OperatePerm::DISABLE_PERM;
228 LockObj();
229 auto notifiers = std::move(closeNotifiers_);
230 UnlockObj();
231
232 for (const auto ¬ifier : notifiers) {
233 if (notifier) {
234 notifier();
235 }
236 }
237
238 Close();
239 }
240
241 // Register a new notification event type.
RegisterNotificationEventType(int eventType)242 int GenericKvDB::RegisterNotificationEventType(int eventType)
243 {
244 if (notificationChain_ == nullptr) {
245 // Lazy init.
246 notificationChain_ = new (std::nothrow) NotificationChain;
247 if (notificationChain_ == nullptr) {
248 return -E_OUT_OF_MEMORY;
249 }
250 }
251 // We DON'T release 'notificationChain_' here event if RegisterEventType()
252 // is failed, it belongs to the class object and is released in the destructor.
253 return notificationChain_->RegisterEventType(static_cast<EventType>(eventType));
254 }
255
256 // Unregister a notification event type.
UnRegisterNotificationEventType(int eventType)257 void GenericKvDB::UnRegisterNotificationEventType(int eventType)
258 {
259 if (notificationChain_ != nullptr) {
260 notificationChain_->UnRegisterEventType(static_cast<EventType>(eventType));
261 }
262 }
263
MyProp() const264 const KvDBProperties &GenericKvDB::MyProp() const
265 {
266 return properties_;
267 }
268
MyProp()269 KvDBProperties &GenericKvDB::MyProp()
270 {
271 return properties_;
272 }
273
274 #ifndef OMIT_MULTI_VER
GetWorkDir(const KvDBProperties & kvDBProp,std::string & workDir)275 int GenericKvDB::GetWorkDir(const KvDBProperties &kvDBProp, std::string &workDir)
276 {
277 std::string origDataDir = kvDBProp.GetStringProp(KvDBProperties::DATA_DIR, "");
278 std::string identifierDir = kvDBProp.GetStringProp(KvDBProperties::IDENTIFIER_DIR, "");
279 if (origDataDir.empty()) {
280 return -E_INVALID_ARGS;
281 }
282
283 workDir = origDataDir + "/" + identifierDir;
284 return E_OK;
285 }
286 #endif
287
SetCorruptHandler(const DatabaseCorruptHandler & handler)288 void GenericKvDB::SetCorruptHandler(const DatabaseCorruptHandler &handler)
289 {
290 std::lock_guard<std::mutex> lock(corruptMutex_);
291 corruptHandler_ = handler;
292 }
293
CommitNotifyAsync(int notifyEvent,KvDBCommitNotifyFilterAbleData * data)294 void GenericKvDB::CommitNotifyAsync(int notifyEvent, KvDBCommitNotifyFilterAbleData *data)
295 {
296 notificationChain_->NotifyEvent(static_cast<EventType>(notifyEvent), data);
297 RefObject::DecObjRef(data);
298 data = nullptr;
299 }
300
RegisterFunction(RegisterFuncType type)301 int GenericKvDB::RegisterFunction(RegisterFuncType type)
302 {
303 if (type >= RegisterFuncType::REGISTER_FUNC_TYPE_MAX) {
304 return -E_NOT_SUPPORT;
305 }
306 std::lock_guard<std::mutex> lock(regFuncCountMutex_);
307 if (registerFunctionCount_.empty()) {
308 registerFunctionCount_.resize(static_cast<uint32_t>(RegisterFuncType::REGISTER_FUNC_TYPE_MAX), 0);
309 if (registerFunctionCount_.size() != static_cast<size_t>(RegisterFuncType::REGISTER_FUNC_TYPE_MAX)) {
310 return -E_OUT_OF_MEMORY;
311 }
312 }
313 registerFunctionCount_[static_cast<int>(type)]++;
314 return E_OK;
315 }
316
UnregisterFunction(RegisterFuncType type)317 int GenericKvDB::UnregisterFunction(RegisterFuncType type)
318 {
319 if (type >= RegisterFuncType::REGISTER_FUNC_TYPE_MAX) {
320 return -E_NOT_SUPPORT;
321 }
322 std::lock_guard<std::mutex> lock(regFuncCountMutex_);
323 if (registerFunctionCount_.size() != static_cast<size_t>(RegisterFuncType::REGISTER_FUNC_TYPE_MAX) ||
324 registerFunctionCount_[static_cast<int>(type)] == 0) {
325 return -E_UNEXPECTED_DATA;
326 }
327 registerFunctionCount_[static_cast<int>(type)]--;
328 return E_OK;
329 }
330
GetRegisterFunctionCount(RegisterFuncType type) const331 uint32_t GenericKvDB::GetRegisterFunctionCount(RegisterFuncType type) const
332 {
333 std::lock_guard<std::mutex> lock(regFuncCountMutex_);
334 if (type >= RegisterFuncType::REGISTER_FUNC_TYPE_MAX ||
335 registerFunctionCount_.size() != static_cast<size_t>(RegisterFuncType::REGISTER_FUNC_TYPE_MAX)) {
336 return 0;
337 }
338 return registerFunctionCount_[static_cast<int>(type)];
339 }
340
TransObserverTypeToRegisterFunctionType(int observerType,RegisterFuncType & type) const341 int GenericKvDB::TransObserverTypeToRegisterFunctionType(int observerType, RegisterFuncType &type) const
342 {
343 (void)observerType;
344 (void)type;
345 return -E_NOT_SUPPORT;
346 }
347
TransConflictTypeToRegisterFunctionType(int conflictType,RegisterFuncType & type) const348 int GenericKvDB::TransConflictTypeToRegisterFunctionType(int conflictType, RegisterFuncType &type) const
349 {
350 (void)conflictType;
351 (void)type;
352 return -E_NOT_SUPPORT;
353 }
354
GetMaxValueSize() const355 uint32_t GenericKvDB::GetMaxValueSize() const
356 {
357 return DBConstant::MAX_VALUE_SIZE;
358 }
359
CheckDataStatus(const Key & key,const Value & value,bool isDeleted) const360 int GenericKvDB::CheckDataStatus(const Key &key, const Value &value, [[gnu::unused]] bool isDeleted) const
361 {
362 if (key.empty() || key.size() > DBConstant::MAX_KEY_SIZE || value.size() > GetMaxValueSize()) {
363 return -E_INVALID_ARGS;
364 }
365 return E_OK;
366 }
367
CheckWritePermission() const368 bool GenericKvDB::CheckWritePermission() const
369 {
370 return true;
371 }
372
IsDataMigrating() const373 bool GenericKvDB::IsDataMigrating() const
374 {
375 return false;
376 }
377
SetConnectionFlag(bool isExisted) const378 void GenericKvDB::SetConnectionFlag(bool isExisted) const
379 {
380 (void)isExisted;
381 }
382
CheckIntegrity() const383 int GenericKvDB::CheckIntegrity() const
384 {
385 return E_OK;
386 }
387
GetStoreDirectory(const KvDBProperties & properties,int dbType,std::string & storeDir,std::string & storeOnlyDir) const388 void GenericKvDB::GetStoreDirectory(const KvDBProperties &properties, int dbType,
389 std::string &storeDir, std::string &storeOnlyDir) const
390 {
391 std::string identifierDir = properties.GetStringProp(KvDBProperties::IDENTIFIER_DIR, "");
392 std::string dataDir = properties.GetStringProp(KvDBProperties::DATA_DIR, "");
393 std::string subDir = KvDBProperties::GetStoreSubDirectory(dbType);
394
395 std::string storeOnlyIdentifier = GetStoreIdOnlyIdentifier(properties);
396 storeOnlyDir = dataDir + "/" + storeOnlyIdentifier + "/" + subDir + "/";
397 storeDir = dataDir + "/" + identifierDir + "/" + subDir + "/";
398 }
399
GetStoreIdOnlyIdentifier(const KvDBProperties & properties) const400 std::string GenericKvDB::GetStoreIdOnlyIdentifier(const KvDBProperties &properties) const
401 {
402 std::string storeId = properties.GetStringProp(KvDBProperties::STORE_ID, "");
403 std::string hashStoreId = DBCommon::TransferHashString(storeId);
404 std::string hashStoreDir = DBCommon::TransferStringToHex(hashStoreId);
405 return hashStoreDir;
406 }
407
GetStorePath() const408 std::string GenericKvDB::GetStorePath() const
409 {
410 return properties_.GetStringProp(KvDBProperties::DATA_DIR, "");
411 }
412
Dump(int fd)413 void GenericKvDB::Dump(int fd)
414 {
415 }
416
ResetSyncStatus()417 void GenericKvDB::ResetSyncStatus()
418 {
419 }
420
MarkRebuild()421 void GenericKvDB::MarkRebuild()
422 {
423 isRebuild_ = true;
424 }
425
PreClose()426 int GenericKvDB::PreClose()
427 {
428 if (connectionCount_.load() == 1) {
429 return E_OK;
430 }
431 // it will not cause busy when close db, only to verify the last conn
432 return -E_BUSY;
433 }
434 } // namespace DistributedDB
435