• 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 #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)> &notifier)
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 &notifier : 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