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