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