• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)> &notifier)
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 &notifier : 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