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 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 ¬ifier : 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