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     delete connection;
97     connection = nullptr;
98 }
99 
ReleaseDBConnection(GenericKvDBConnection * connection)100 void GenericKvDB::ReleaseDBConnection(GenericKvDBConnection *connection)
101 {
102     if (connectionCount_.load() == 1) {
103         SetConnectionFlag(false);
104     }
105 
106     if (connection != nullptr) {
107         {
108             std::lock_guard<std::mutex> lock(connectMutex_);
109             connection->SetSafeDeleted();
110             DelConnection(connection);
111             DecreaseConnectionCounter();
112         }
113         DecObjRef(this);
114     }
115 }
116 
CommitNotify(int notifyEvent,KvDBCommitNotifyFilterAbleData * data)117 void GenericKvDB::CommitNotify(int notifyEvent, KvDBCommitNotifyFilterAbleData *data)
118 {
119     if (notificationChain_ == nullptr) {
120         LOGE("Failed to do commit notify, notificationChain_ is nullptr.");
121         return;
122     }
123     ++eventNotifyCounter_;
124     if (data == nullptr) {
125         notificationChain_->NotifyEvent(static_cast<EventType>(notifyEvent), nullptr);
126     } else {
127         data->SetMyDb(this, eventNotifyCounter_);
128         data->IncObjRef(data);
129         int errCode = RuntimeContext::GetInstance()->ScheduleQueuedTask(GetStoreId(),
130             [this, notifyEvent, data] { CommitNotifyAsync(notifyEvent, data); });
131         if (errCode != E_OK) {
132             LOGE("Failed to do commit notify, schedule task err:%d.", errCode);
133             data->DecObjRef(data);
134             data = nullptr;
135         }
136     }
137 }
138 
CorruptNotifyAsync() const139 void GenericKvDB::CorruptNotifyAsync() const
140 {
141     {
142         std::lock_guard<std::mutex> lock(corruptMutex_);
143         if (corruptHandler_) {
144             corruptHandler_();
145         }
146     }
147 
148     DecObjRef(this);
149 }
150 
CorruptNotify() const151 void GenericKvDB::CorruptNotify() const
152 {
153     IncObjRef(this);
154     int errCode = RuntimeContext::GetInstance()->ScheduleQueuedTask(GetStoreId(),
155         [this] { CorruptNotifyAsync(); });
156     if (errCode != E_OK) {
157         LOGE("Failed to do the corrupt notify, schedule task err:%d.", errCode);
158         DecObjRef(this);
159     }
160 }
161 
TryToDisableConnection(OperatePerm perm)162 int GenericKvDB::TryToDisableConnection(OperatePerm perm)
163 {
164     std::lock_guard<std::mutex> lock(connectMutex_);
165     if (operatePerm_ != OperatePerm::NORMAL_PERM) {
166         return -E_BUSY;
167     }
168     // more than one connection, should prevent the rekey/import operation.
169     if ((perm == OperatePerm::REKEY_MONOPOLIZE_PERM || perm == OperatePerm::IMPORT_MONOPOLIZE_PERM) &&
170         connectionCount_ > 1) {
171         return -E_BUSY;
172     }
173     operatePerm_ = perm;
174     return E_OK;
175 }
176 
ReEnableConnection(OperatePerm perm)177 void GenericKvDB::ReEnableConnection(OperatePerm perm)
178 {
179     std::lock_guard<std::mutex> lock(connectMutex_);
180     if (perm == operatePerm_) {
181         operatePerm_ = OperatePerm::NORMAL_PERM;
182     }
183 }
184 
RegisterEventListener(EventType type,const NotificationChain::Listener::OnEvent & onEvent,const NotificationChain::Listener::OnFinalize & onFinalize,int & errCode)185 NotificationChain::Listener *GenericKvDB::RegisterEventListener(EventType type,
186     const NotificationChain::Listener::OnEvent &onEvent,
187     const NotificationChain::Listener::OnFinalize &onFinalize, int &errCode)
188 {
189     NotificationChain::Listener *listener = nullptr;
190     if (notificationChain_ != nullptr) {
191         listener = notificationChain_->RegisterListener(type, onEvent, onFinalize, errCode);
192     } else {
193         errCode = -E_NOT_PERMIT;
194     }
195     return listener;
196 }
197 
GetEventNotifyCounter() const198 uint64_t GenericKvDB::GetEventNotifyCounter() const
199 {
200     return eventNotifyCounter_;
201 }
202 
203 // Called when a new connection created.
IncreaseConnectionCounter()204 void GenericKvDB::IncreaseConnectionCounter()
205 {
206     connectionCount_.fetch_add(1, std::memory_order_seq_cst);
207     if (connectionCount_.load() > 0) {
208         SetConnectionFlag(true);
209     }
210 }
211 
212 // Called when a connection released.
DecreaseConnectionCounter()213 void GenericKvDB::DecreaseConnectionCounter()
214 {
215     int count = connectionCount_.fetch_sub(1, std::memory_order_seq_cst);
216     if (count <= 0) {
217         LOGF("Decrease kvdb connection counter failed, count <= 0.");
218         return;
219     }
220     if (count != 1) {
221         return;
222     }
223 
224     operatePerm_ = OperatePerm::DISABLE_PERM;
225     LockObj();
226     auto notifiers = std::move(closeNotifiers_);
227     UnlockObj();
228 
229     for (const auto &notifier : notifiers) {
230         if (notifier) {
231             notifier();
232         }
233     }
234 
235     Close();
236 }
237 
238 // Register a new notification event type.
RegisterNotificationEventType(int eventType)239 int GenericKvDB::RegisterNotificationEventType(int eventType)
240 {
241     if (notificationChain_ == nullptr) {
242         // Lazy init.
243         notificationChain_ = new (std::nothrow) NotificationChain;
244         if (notificationChain_ == nullptr) {
245             return -E_OUT_OF_MEMORY;
246         }
247     }
248     // We DON'T release 'notificationChain_' here event if RegisterEventType()
249     // is failed, it belongs to the class object and is released in the destructor.
250     return notificationChain_->RegisterEventType(static_cast<EventType>(eventType));
251 }
252 
253 // Unregister a notification event type.
UnRegisterNotificationEventType(int eventType)254 void GenericKvDB::UnRegisterNotificationEventType(int eventType)
255 {
256     if (notificationChain_ != nullptr) {
257         notificationChain_->UnRegisterEventType(static_cast<EventType>(eventType));
258     }
259 }
260 
MyProp() const261 const KvDBProperties &GenericKvDB::MyProp() const
262 {
263     return properties_;
264 }
265 
MyProp()266 KvDBProperties &GenericKvDB::MyProp()
267 {
268     return properties_;
269 }
270 
271 #ifndef OMIT_MULTI_VER
GetWorkDir(const KvDBProperties & kvDBProp,std::string & workDir)272 int GenericKvDB::GetWorkDir(const KvDBProperties &kvDBProp, std::string &workDir)
273 {
274     std::string origDataDir = kvDBProp.GetStringProp(KvDBProperties::DATA_DIR, "");
275     std::string identifierDir = kvDBProp.GetStringProp(KvDBProperties::IDENTIFIER_DIR, "");
276     if (origDataDir.empty()) {
277         return -E_INVALID_ARGS;
278     }
279 
280     workDir = origDataDir + "/" + identifierDir;
281     return E_OK;
282 }
283 #endif
284 
SetCorruptHandler(const DatabaseCorruptHandler & handler)285 void GenericKvDB::SetCorruptHandler(const DatabaseCorruptHandler &handler)
286 {
287     std::lock_guard<std::mutex> lock(corruptMutex_);
288     corruptHandler_ = handler;
289 }
290 
CommitNotifyAsync(int notifyEvent,KvDBCommitNotifyFilterAbleData * data)291 void GenericKvDB::CommitNotifyAsync(int notifyEvent, KvDBCommitNotifyFilterAbleData *data)
292 {
293     notificationChain_->NotifyEvent(static_cast<EventType>(notifyEvent), data);
294     data->DecObjRef(data);
295     data = nullptr;
296 }
297 
RegisterFunction(RegisterFuncType type)298 int GenericKvDB::RegisterFunction(RegisterFuncType type)
299 {
300     if (type >= RegisterFuncType::REGISTER_FUNC_TYPE_MAX) {
301         return -E_NOT_SUPPORT;
302     }
303     std::lock_guard<std::mutex> lock(regFuncCountMutex_);
304     if (registerFunctionCount_.empty()) {
305         registerFunctionCount_.resize(static_cast<uint32_t>(RegisterFuncType::REGISTER_FUNC_TYPE_MAX), 0);
306         if (registerFunctionCount_.size() != static_cast<size_t>(RegisterFuncType::REGISTER_FUNC_TYPE_MAX)) {
307             return -E_OUT_OF_MEMORY;
308         }
309     }
310     registerFunctionCount_[static_cast<int>(type)]++;
311     return E_OK;
312 }
313 
UnregisterFunction(RegisterFuncType type)314 int GenericKvDB::UnregisterFunction(RegisterFuncType type)
315 {
316     if (type >= RegisterFuncType::REGISTER_FUNC_TYPE_MAX) {
317         return -E_NOT_SUPPORT;
318     }
319     std::lock_guard<std::mutex> lock(regFuncCountMutex_);
320     if (registerFunctionCount_.size() != static_cast<size_t>(RegisterFuncType::REGISTER_FUNC_TYPE_MAX) ||
321         registerFunctionCount_[static_cast<int>(type)] == 0) {
322         return -E_UNEXPECTED_DATA;
323     }
324     registerFunctionCount_[static_cast<int>(type)]--;
325     return E_OK;
326 }
327 
GetRegisterFunctionCount(RegisterFuncType type) const328 uint32_t GenericKvDB::GetRegisterFunctionCount(RegisterFuncType type) const
329 {
330     std::lock_guard<std::mutex> lock(regFuncCountMutex_);
331     if (type >= RegisterFuncType::REGISTER_FUNC_TYPE_MAX ||
332         registerFunctionCount_.size() != static_cast<size_t>(RegisterFuncType::REGISTER_FUNC_TYPE_MAX)) {
333         return 0;
334     }
335     return registerFunctionCount_[static_cast<int>(type)];
336 }
337 
TransObserverTypeToRegisterFunctionType(int observerType,RegisterFuncType & type) const338 int GenericKvDB::TransObserverTypeToRegisterFunctionType(int observerType, RegisterFuncType &type) const
339 {
340     (void)observerType;
341     (void)type;
342     return -E_NOT_SUPPORT;
343 }
344 
TransConflictTypeToRegisterFunctionType(int conflictType,RegisterFuncType & type) const345 int GenericKvDB::TransConflictTypeToRegisterFunctionType(int conflictType, RegisterFuncType &type) const
346 {
347     (void)conflictType;
348     (void)type;
349     return -E_NOT_SUPPORT;
350 }
351 
CheckDataStatus(const Key & key,const Value & value,bool isDeleted) const352 int GenericKvDB::CheckDataStatus(const Key &key, const Value &value, bool isDeleted) const
353 {
354     if (key.empty() || key.size() > DBConstant::MAX_KEY_SIZE ||
355         value.size() > DBConstant::MAX_VALUE_SIZE) {
356         return -E_INVALID_ARGS;
357     }
358     return E_OK;
359 }
360 
CheckWritePermission() const361 bool GenericKvDB::CheckWritePermission() const
362 {
363     return true;
364 }
365 
IsDataMigrating() const366 bool GenericKvDB::IsDataMigrating() const
367 {
368     return false;
369 }
370 
SetConnectionFlag(bool isExisted) const371 void GenericKvDB::SetConnectionFlag(bool isExisted) const
372 {
373     (void)isExisted;
374 }
375 
CheckIntegrity() const376 int GenericKvDB::CheckIntegrity() const
377 {
378     return E_OK;
379 }
380 
GetStoreDirectory(const KvDBProperties & properties,int dbType,std::string & storeDir,std::string & storeOnlyDir) const381 void GenericKvDB::GetStoreDirectory(const KvDBProperties &properties, int dbType,
382     std::string &storeDir, std::string &storeOnlyDir) const
383 {
384     std::string identifierDir = properties.GetStringProp(KvDBProperties::IDENTIFIER_DIR, "");
385     std::string dataDir = properties.GetStringProp(KvDBProperties::DATA_DIR, "");
386     std::string subDir = KvDBProperties::GetStoreSubDirectory(dbType);
387 
388     std::string storeOnlyIdentifier = GetStoreIdOnlyIdentifier(properties);
389     storeOnlyDir = dataDir + "/" + storeOnlyIdentifier + "/" + subDir + "/";
390     storeDir = dataDir + "/" + identifierDir + "/" + subDir + "/";
391 }
392 
GetStoreIdOnlyIdentifier(const KvDBProperties & properties) const393 std::string GenericKvDB::GetStoreIdOnlyIdentifier(const KvDBProperties &properties) const
394 {
395     std::string storeId = properties.GetStringProp(KvDBProperties::STORE_ID, "");
396     std::string hashStoreId = DBCommon::TransferHashString(storeId);
397     std::string hashStoreDir = DBCommon::TransferStringToHex(hashStoreId);
398     return hashStoreDir;
399 }
400 
GetStorePath() const401 std::string GenericKvDB::GetStorePath() const
402 {
403     return properties_.GetStringProp(KvDBProperties::DATA_DIR, "");
404 }
405 
Dump(int fd)406 void GenericKvDB::Dump(int fd)
407 {
408 }
409 
ResetSyncStatus()410 void GenericKvDB::ResetSyncStatus()
411 {
412 }
413 
MarkRebuild()414 void GenericKvDB::MarkRebuild()
415 {
416     isRebuild_ = true;
417 }
418 } // namespace DistributedDB
419