1 /*
2 * Copyright (c) 2022 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 #define LOG_TAG "ConnectionPool"
16 #include "connection_pool.h"
17
18 #include <base_transaction.h>
19
20 #include <condition_variable>
21 #include <iterator>
22 #include <mutex>
23 #include <sstream>
24 #include <vector>
25
26 #include "logger.h"
27 #include "connection.h"
28 #include "rdb_common.h"
29 #include "rdb_errno.h"
30 #include "rdb_fault_hiview_reporter.h"
31 #include "rdb_sql_statistic.h"
32 #include "sqlite_global_config.h"
33 #include "sqlite_utils.h"
34
35 namespace OHOS {
36 namespace NativeRdb {
37 using namespace OHOS::Rdb;
38 using namespace std::chrono;
39 using Conn = Connection;
40 using ConnPool = ConnectionPool;
41 using SharedConn = std::shared_ptr<Connection>;
42 using SharedConns = std::vector<std::shared_ptr<Connection>>;
43 using SqlStatistic = DistributedRdb::SqlStatistic;
44 using Reportor = RdbFaultHiViewReporter;
45 constexpr int32_t TRANSACTION_TIMEOUT(2);
46
Create(const RdbStoreConfig & config,int & errCode)47 std::shared_ptr<ConnPool> ConnPool::Create(const RdbStoreConfig &config, int &errCode)
48 {
49 std::shared_ptr<ConnPool> pool(new (std::nothrow) ConnPool(config));
50 if (pool == nullptr) {
51 LOG_ERROR("ConnPool::Create new failed, pool is nullptr.");
52 errCode = E_ERROR;
53 return nullptr;
54 }
55 std::shared_ptr<Connection> conn;
56 for (uint32_t retry = 0; retry < ITERS_COUNT; ++retry) {
57 std::tie(errCode, conn) = pool->Init();
58 if (errCode != E_SQLITE_CORRUPT) {
59 break;
60 }
61 config.SetIter(ITER_V1);
62 }
63 std::string dbPath;
64 (void)SqliteGlobalConfig::GetDbPath(config, dbPath);
65 LOG_INFO("code:%{public}d app:%{public}s path:[%{public}s] "
66 "cfg:[%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d]"
67 "%{public}s",
68 errCode, config.GetBundleName().c_str(), SqliteUtils::Anonymous(dbPath).c_str(), config.GetDBType(),
69 config.GetHaMode(), config.IsEncrypt(), config.GetArea(), config.GetSecurityLevel(), config.GetRoleType(),
70 config.IsReadOnly(),
71 Reportor::FormatBrief(Connection::Collect(config), SqliteUtils::Anonymous(config.GetName())).c_str());
72 return errCode == E_OK ? pool : nullptr;
73 }
74
HandleDataCorruption(const RdbStoreConfig & storeConfig,int & errCode)75 std::pair<RebuiltType, std::shared_ptr<ConnectionPool>> ConnPool::HandleDataCorruption
76 (const RdbStoreConfig &storeConfig, int &errCode)
77 {
78 std::pair<RebuiltType, std::shared_ptr<ConnectionPool>> result;
79 auto &[rebuiltType, pool] = result;
80
81 errCode = Connection::Repair(storeConfig);
82 if (errCode == E_OK) {
83 rebuiltType = RebuiltType::REPAIRED;
84 } else {
85 Connection::Delete(storeConfig);
86 rebuiltType = RebuiltType::REBUILT;
87 }
88 pool = Create(storeConfig, errCode);
89 if (errCode != E_OK) {
90 LOG_WARN("failed, type %{public}d db %{public}s encrypt %{public}d error %{public}d, errno",
91 static_cast<uint32_t>(rebuiltType), SqliteUtils::Anonymous(storeConfig.GetName()).c_str(),
92 storeConfig.IsEncrypt(), errCode, errno);
93 } else {
94 Reportor::ReportRestore(Reportor::Create(storeConfig, E_OK, "RestoreType:Rebuild"), false);
95 }
96
97 return result;
98 }
99
ConnectionPool(const RdbStoreConfig & storeConfig)100 ConnPool::ConnectionPool(const RdbStoreConfig &storeConfig)
101 : config_(storeConfig), attachConfig_(storeConfig), writers_(), readers_(), transactionStack_(),
102 transactionUsed_(false)
103 {
104 attachConfig_.SetJournalMode(JournalMode::MODE_TRUNCATE);
105 }
106
Init(bool isAttach,bool needWriter)107 std::pair<int32_t, std::shared_ptr<Connection>> ConnPool::Init(bool isAttach, bool needWriter)
108 {
109 const RdbStoreConfig &config = isAttach ? attachConfig_ : config_;
110 std::pair<int32_t, std::shared_ptr<Connection>> result;
111 auto &[errCode, conn] = result;
112 errCode = config.Initialize();
113 if (errCode != E_OK) {
114 return result;
115 }
116
117 if (config.GetRoleType() == OWNER && !config.IsReadOnly()) {
118 // write connect count is 1
119 std::shared_ptr<ConnPool::ConnNode> node;
120 std::tie(errCode, node) = writers_.Initialize(
121 [this, isAttach]() {
122 const RdbStoreConfig &config = isAttach ? attachConfig_ : config_;
123 return Connection::Create(config, true);
124 },
125 1, config.GetWriteTime(), true, needWriter);
126 conn = Convert2AutoConn(node);
127 if (errCode != E_OK) {
128 return result;
129 }
130 }
131
132 maxReader_ = GetMaxReaders(config);
133 // max read connect count is 64
134 if (maxReader_ > 64) {
135 return { E_ARGS_READ_CON_OVERLOAD, nullptr };
136 }
137 auto [ret, node] = readers_.Initialize(
138 [this, isAttach]() {
139 const RdbStoreConfig &config = isAttach ? attachConfig_ : config_;
140 return Connection::Create(config, false);
141 },
142 maxReader_, config.GetReadTime(), maxReader_ == 0);
143 errCode = ret;
144 return result;
145 }
146
~ConnectionPool()147 ConnPool::~ConnectionPool()
148 {
149 CloseAllConnections();
150 }
151
GetMaxReaders(const RdbStoreConfig & config)152 int32_t ConnPool::GetMaxReaders(const RdbStoreConfig &config)
153 {
154 if (config.GetStorageMode() != StorageMode::MODE_MEMORY &&
155 config.GetJournalMode() == RdbStoreConfig::GetJournalModeValue(JournalMode::MODE_WAL)) {
156 return config.GetReadConSize();
157 } else {
158 return 0;
159 }
160 }
161
Convert2AutoConn(std::shared_ptr<ConnNode> node,bool isTrans)162 std::shared_ptr<Connection> ConnPool::Convert2AutoConn(std::shared_ptr<ConnNode> node, bool isTrans)
163 {
164 if (node == nullptr) {
165 return nullptr;
166 }
167
168 auto conn = node->GetConnect();
169 if (conn == nullptr) {
170 return nullptr;
171 }
172 if (isTrans) {
173 transCount_++;
174 }
175
176 return std::shared_ptr<Connection>(conn.get(), [pool = weak_from_this(), node, isTrans](auto *) mutable {
177 auto realPool = pool.lock();
178 if (realPool == nullptr) {
179 return;
180 }
181 if (isTrans) {
182 realPool->transCount_--;
183 }
184 realPool->ReleaseNode(node, !isTrans);
185 node = nullptr;
186 });
187 }
188
CloseAllConnections()189 void ConnPool::CloseAllConnections()
190 {
191 writers_.Clear();
192 readers_.Clear();
193 }
194
IsInTransaction()195 bool ConnPool::IsInTransaction()
196 {
197 return isInTransaction_.load();
198 }
199
SetInTransaction(bool isInTransaction)200 void ConnPool::SetInTransaction(bool isInTransaction)
201 {
202 isInTransaction_.store(isInTransaction);
203 }
204
CreateTransConn(bool limited)205 std::pair<int32_t, std::shared_ptr<Connection>> ConnPool::CreateTransConn(bool limited)
206 {
207 if (transCount_ >= MAX_TRANS && limited) {
208 writers_.Dump("NO TRANS", transCount_ + isInTransaction_);
209 return { E_DATABASE_BUSY, nullptr };
210 }
211 auto [errCode, node] = writers_.Create();
212 return { errCode, Convert2AutoConn(node, true) };
213 }
214
AcquireConnection(bool isReadOnly)215 std::shared_ptr<Conn> ConnPool::AcquireConnection(bool isReadOnly)
216 {
217 SqlStatistic sqlStatistic("", SqlStatistic::Step::STEP_WAIT);
218 return Acquire(isReadOnly);
219 }
220
AcquireAll(int32_t time)221 std::pair<SharedConn, SharedConns> ConnPool::AcquireAll(int32_t time)
222 {
223 SqlStatistic sqlStatistic("", SqlStatistic::Step::STEP_WAIT);
224 using namespace std::chrono;
225 std::pair<SharedConn, SharedConns> result;
226 auto &[writer, readers] = result;
227 auto interval = duration_cast<milliseconds>(seconds(time));
228 auto start = steady_clock::now();
229 auto writerNodes = writers_.AcquireAll(interval);
230 if (writerNodes.empty()) {
231 return {};
232 }
233 writer = Convert2AutoConn(writerNodes.front());
234
235 auto usedTime = duration_cast<milliseconds>(steady_clock::now() - start);
236 if (writer == nullptr || usedTime >= interval) {
237 return {};
238 }
239
240 if (maxReader_ == 0) {
241 return result;
242 }
243
244 readers_.Disable();
245 auto nodes = readers_.AcquireAll(interval - usedTime);
246 if (nodes.empty()) {
247 readers_.Enable();
248 return {};
249 }
250
251 for (auto node : nodes) {
252 auto conn = Convert2AutoConn(node);
253 if (conn == nullptr) {
254 continue;
255 }
256 readers.push_back(conn);
257 }
258 return result;
259 }
260
Acquire(bool isReadOnly,std::chrono::milliseconds ms)261 std::shared_ptr<Conn> ConnPool::Acquire(bool isReadOnly, std::chrono::milliseconds ms)
262 {
263 Container *container = (isReadOnly && maxReader_ != 0) ? &readers_ : &writers_;
264 auto node = container->Acquire(ms);
265 if (node == nullptr) {
266 const char *header = (isReadOnly && maxReader_ != 0) ? "readers_" : "writers_";
267 container->Dump(header, transCount_ + isInTransaction_);
268 return nullptr;
269 }
270 return Convert2AutoConn(node);
271 }
272
AcquireRef(bool isReadOnly,std::chrono::milliseconds ms)273 SharedConn ConnPool::AcquireRef(bool isReadOnly, std::chrono::milliseconds ms)
274 {
275 SqlStatistic sqlStatistic("", SqlStatistic::Step::STEP_WAIT);
276 if (maxReader_ != 0) {
277 return Acquire(isReadOnly, ms);
278 }
279 auto node = writers_.Acquire(ms);
280 if (node == nullptr) {
281 writers_.Dump("writers_", transCount_ + isInTransaction_);
282 return nullptr;
283 }
284 auto conn = node->connect_;
285 writers_.Release(node);
286 return std::shared_ptr<Connection>(conn.get(), [pool = weak_from_this(), conn](Connection *) {
287 auto realPool = pool.lock();
288 if (realPool == nullptr) {
289 return;
290 }
291 realPool->writers_.cond_.notify_all();
292 });
293 }
294
ReleaseNode(std::shared_ptr<ConnNode> node,bool reuse)295 void ConnPool::ReleaseNode(std::shared_ptr<ConnNode> node, bool reuse)
296 {
297 if (node == nullptr) {
298 return;
299 }
300
301 auto transCount = transCount_ + isInTransaction_;
302 auto errCode = node->Unused(transCount);
303 if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) {
304 writers_.Dump("WAL writers_", transCount);
305 }
306
307 auto &container = node->IsWriter() ? writers_ : readers_;
308 if (reuse) {
309 container.Release(node);
310 } else {
311 container.Drop(node);
312 }
313 }
314
AcquireTransaction()315 int ConnPool::AcquireTransaction()
316 {
317 std::unique_lock<std::mutex> lock(transMutex_);
318 if (transCondition_.wait_for(lock, std::chrono::seconds(TRANSACTION_TIMEOUT), [this] {
319 return !transactionUsed_;
320 })) {
321 transactionUsed_ = true;
322 return E_OK;
323 }
324 LOG_WARN("transactionUsed_ is %{public}d", transactionUsed_);
325 return E_DATABASE_BUSY;
326 }
327
ReleaseTransaction()328 void ConnPool::ReleaseTransaction()
329 {
330 {
331 std::unique_lock<std::mutex> lock(transMutex_);
332 transactionUsed_ = false;
333 }
334 transCondition_.notify_one();
335 }
336
RestartReaders()337 int ConnPool::RestartReaders()
338 {
339 readers_.Clear();
340 auto [errCode, node] = readers_.Initialize(
341 [this]() {
342 return Connection::Create(config_, false);
343 },
344 maxReader_, config_.GetReadTime(), maxReader_ == 0);
345 return errCode;
346 }
347
348 /**
349 * The database locale.
350 */
ConfigLocale(const std::string & localeStr)351 int ConnPool::ConfigLocale(const std::string &localeStr)
352 {
353 auto errCode = readers_.ConfigLocale(localeStr);
354 if (errCode != E_OK) {
355 return errCode;
356 }
357 return writers_.ConfigLocale(localeStr);
358 }
359
360 /**
361 * Rename the backed up database.
362 */
ChangeDbFileForRestore(const std::string & newPath,const std::string & backupPath,const std::vector<uint8_t> & newKey,SlaveStatus & slaveStatus)363 int ConnPool::ChangeDbFileForRestore(const std::string &newPath, const std::string &backupPath,
364 const std::vector<uint8_t> &newKey, SlaveStatus &slaveStatus)
365 {
366 if (!writers_.IsFull() || config_.GetPath() == backupPath || newPath == backupPath) {
367 LOG_ERROR("Connection pool is busy now!");
368 return E_ERROR;
369 }
370 if (config_.GetDBType() == DB_VECTOR) {
371 CloseAllConnections();
372 auto [retVal, connection] = CreateTransConn();
373
374 if (connection == nullptr) {
375 LOG_ERROR("Get null connection.");
376 return retVal;
377 }
378 retVal = connection->Restore(backupPath, {}, slaveStatus);
379 if (retVal != E_OK) {
380 LOG_ERROR("RdDbRestore error.");
381 return retVal;
382 }
383 CloseAllConnections();
384 auto [errCode, node] = Init();
385 return errCode;
386 }
387 return RestoreByDbSqliteType(newPath, backupPath, slaveStatus);
388 }
389
RestoreByDbSqliteType(const std::string & newPath,const std::string & backupPath,SlaveStatus & slaveStatus)390 int ConnPool::RestoreByDbSqliteType(const std::string &newPath, const std::string &backupPath, SlaveStatus &slaveStatus)
391 {
392 if (SqliteUtils::IsSlaveDbName(backupPath) && config_.GetHaMode() != HAMode::SINGLE) {
393 auto connection = AcquireConnection(false);
394 if (connection == nullptr) {
395 return E_DATABASE_BUSY;
396 }
397 return connection->Restore(backupPath, {}, slaveStatus);
398 }
399
400 return RestoreMasterDb(newPath, backupPath);
401 }
402
RestoreMasterDb(const std::string & newPath,const std::string & backupPath)403 int ConnPool::RestoreMasterDb(const std::string &newPath, const std::string &backupPath)
404 {
405 if (!CheckIntegrity(backupPath)) {
406 LOG_ERROR("backup file is corrupted, %{public}s", SqliteUtils::Anonymous(backupPath).c_str());
407 return E_SQLITE_CORRUPT;
408 }
409 SqliteUtils::DeleteFile(backupPath + "-shm");
410 SqliteUtils::DeleteFile(backupPath + "-wal");
411
412 CloseAllConnections();
413 Connection::Delete(config_);
414
415 if (config_.GetPath() != newPath) {
416 RdbStoreConfig config(newPath);
417 config.SetPath(newPath);
418 Connection::Delete(config);
419 }
420
421 int ret = E_OK;
422 if (!SqliteUtils::CopyFile(backupPath, newPath)) {
423 ret = E_ERROR;
424 }
425 auto result = Init();
426 if (result.first != E_OK) {
427 CloseAllConnections();
428 Connection::Delete(config_);
429 result = Init();
430 }
431 return ret == E_OK ? result.first : ret;
432 }
433
GetTransactionStack()434 std::stack<BaseTransaction> &ConnPool::GetTransactionStack()
435 {
436 return transactionStack_;
437 }
438
GetTransactionStackMutex()439 std::mutex &ConnPool::GetTransactionStackMutex()
440 {
441 return transactionStackMutex_;
442 }
443
DisableWal()444 std::pair<int, std::shared_ptr<Conn>> ConnPool::DisableWal()
445 {
446 return Init(true, true);
447 }
448
EnableWal()449 int ConnPool::EnableWal()
450 {
451 auto [errCode, node] = Init();
452 return errCode;
453 }
454
Dump(bool isWriter,const char * header)455 int32_t ConnectionPool::Dump(bool isWriter, const char *header)
456 {
457 Container *container = (isWriter || maxReader_ == 0) ? &writers_ : &readers_;
458 container->Dump(header, transCount_ + isInTransaction_);
459 return E_OK;
460 }
461
ConnNode(std::shared_ptr<Conn> conn)462 ConnPool::ConnNode::ConnNode(std::shared_ptr<Conn> conn) : connect_(std::move(conn))
463 {
464 }
465
GetConnect()466 std::shared_ptr<Conn> ConnPool::ConnNode::GetConnect()
467 {
468 tid_ = gettid();
469 time_ = steady_clock::now();
470 return connect_;
471 }
472
GetUsingTime() const473 int64_t ConnPool::ConnNode::GetUsingTime() const
474 {
475 auto time = steady_clock::now() - time_;
476 return duration_cast<milliseconds>(time).count();
477 }
478
Unused(int32_t count)479 int32_t ConnPool::ConnNode::Unused(int32_t count)
480 {
481 time_ = steady_clock::now();
482 if (connect_ == nullptr) {
483 return E_OK;
484 }
485
486 connect_->ClearCache();
487 if (!connect_->IsWriter()) {
488 tid_ = 0;
489 }
490
491 if (count > 0) {
492 return E_OK;
493 }
494 auto timeout = time_ > (failedTime_ + minutes(CHECK_POINT_INTERVAL)) || time_ < failedTime_;
495 int32_t errCode = connect_->TryCheckPoint(timeout);
496 if (errCode == E_INNER_WARNING || errCode == E_NOT_SUPPORT) {
497 return E_OK;
498 }
499
500 failedTime_ = errCode != E_OK ? time_ : steady_clock::time_point();
501 return errCode;
502 }
503
IsWriter() const504 bool ConnPool::ConnNode::IsWriter() const
505 {
506 if (connect_ != nullptr) {
507 return connect_->IsWriter();
508 }
509 return false;
510 }
511
Initialize(Creator creator,int32_t max,int32_t timeout,bool disable,bool acquire)512 std::pair<int32_t, std::shared_ptr<ConnPool::ConnNode>> ConnPool::Container::Initialize(Creator creator, int32_t max,
513 int32_t timeout, bool disable, bool acquire)
514 {
515 std::shared_ptr<ConnNode> connNode = nullptr;
516 {
517 std::unique_lock<decltype(mutex_)> lock(mutex_);
518 disable_ = disable;
519 max_ = max;
520 creator_ = creator;
521 timeout_ = std::chrono::seconds(timeout);
522 for (int i = 0; i < max; ++i) {
523 auto errCode = ExtendNode();
524 if (errCode != E_OK) {
525 nodes_.clear();
526 details_.clear();
527 return { errCode, nullptr };
528 }
529 }
530
531 if (acquire && count_ > 0) {
532 connNode = nodes_.back();
533 nodes_.pop_back();
534 count_--;
535 }
536 }
537 cond_.notify_all();
538 return { E_OK, connNode };
539 }
540
ConfigLocale(const std::string & locale)541 int32_t ConnPool::Container::ConfigLocale(const std::string &locale)
542 {
543 std::unique_lock<decltype(mutex_)> lock(mutex_);
544 if (total_ != count_) {
545 return E_DATABASE_BUSY;
546 }
547 for (auto it = details_.begin(); it != details_.end();) {
548 auto conn = it->lock();
549 if (conn == nullptr || conn->connect_ == nullptr) {
550 it = details_.erase(it);
551 continue;
552 }
553 conn->connect_->ConfigLocale(locale);
554 }
555 return E_OK;
556 }
557
Acquire(std::chrono::milliseconds milliS)558 std::shared_ptr<ConnPool::ConnNode> ConnPool::Container::Acquire(std::chrono::milliseconds milliS)
559 {
560 auto interval = (milliS == INVALID_TIME) ? timeout_ : milliS;
561 std::unique_lock<decltype(mutex_)> lock(mutex_);
562 if (max_ == 0) {
563 return nullptr;
564 }
565 auto waiter = [this]() -> bool {
566 if (count_ > 0) {
567 return true;
568 }
569
570 if (disable_) {
571 return false;
572 }
573 return ExtendNode() == E_OK;
574 };
575 if (cond_.wait_for(lock, interval, waiter)) {
576 if (nodes_.empty()) {
577 LOG_ERROR(
578 "nodes is empty.count %{public}d max %{public}d total %{public}d left %{public}d right%{public}d",
579 count_, max_, total_, left_, right_);
580 count_ = 0;
581 return nullptr;
582 }
583 auto node = nodes_.back();
584 nodes_.pop_back();
585 count_--;
586 return node;
587 }
588 return nullptr;
589 }
590
Create()591 std::pair<int32_t, std::shared_ptr<ConnPool::ConnNode>> ConnPool::Container::Create()
592 {
593 if (creator_ == nullptr) {
594 return { E_NOT_SUPPORT, nullptr };
595 }
596
597 auto [errCode, conn] = creator_();
598 if (conn == nullptr) {
599 return { errCode, nullptr };
600 }
601
602 auto node = std::make_shared<ConnNode>(conn);
603 if (node == nullptr) {
604 return { E_ERROR, nullptr };
605 }
606 node->id_ = MIN_TRANS_ID + trans_;
607 conn->SetId(node->id_);
608 details_.push_back(node);
609 trans_++;
610 return { E_OK, node };
611 }
612
ExtendNode()613 int32_t ConnPool::Container::ExtendNode()
614 {
615 if (creator_ == nullptr) {
616 return E_ERROR;
617 }
618 auto [errCode, conn] = creator_();
619 if (conn == nullptr) {
620 return errCode;
621 }
622 auto node = std::make_shared<ConnNode>(conn);
623 node->id_ = right_++;
624 conn->SetId(node->id_);
625 nodes_.push_back(node);
626 details_.push_back(node);
627 count_++;
628 total_++;
629 return E_OK;
630 }
631
AcquireAll(std::chrono::milliseconds milliS)632 std::list<std::shared_ptr<ConnPool::ConnNode>> ConnPool::Container::AcquireAll(std::chrono::milliseconds milliS)
633 {
634 std::list<std::shared_ptr<ConnNode>> nodes;
635 int32_t count = 0;
636 auto interval = (milliS == INVALID_TIME) ? timeout_ : milliS;
637 auto time = std::chrono::steady_clock::now() + interval;
638 std::unique_lock<decltype(mutex_)> lock(mutex_);
639 while (count < total_ && cond_.wait_until(lock, time, [this]() {
640 return count_ > 0;
641 })) {
642 nodes.merge(std::move(nodes_));
643 nodes_.clear();
644 count += count_;
645 count_ = 0;
646 }
647
648 if (count != total_) {
649 count_ = count;
650 nodes_ = std::move(nodes);
651 nodes.clear();
652 return nodes;
653 }
654 auto func = [](const std::list<std::shared_ptr<ConnNode>> &nodes) -> bool {
655 for (auto &node : nodes) {
656 if (node->connect_ == nullptr) {
657 continue;
658 }
659 if (node->connect_.use_count() != 1) {
660 return false;
661 }
662 }
663 return true;
664 };
665 bool failed = false;
666 while (failed = !func(nodes), failed && cond_.wait_until(lock, time) != std::cv_status::timeout) {
667 }
668 if (failed) {
669 count_ = count;
670 nodes_ = std::move(nodes);
671 nodes.clear();
672 }
673 return nodes;
674 }
675
Disable()676 void ConnPool::Container::Disable()
677 {
678 disable_ = true;
679 cond_.notify_one();
680 }
681
Enable()682 void ConnPool::Container::Enable()
683 {
684 disable_ = false;
685 cond_.notify_one();
686 }
687
Release(std::shared_ptr<ConnNode> node)688 int32_t ConnPool::Container::Release(std::shared_ptr<ConnNode> node)
689 {
690 {
691 std::unique_lock<decltype(mutex_)> lock(mutex_);
692 if (node->id_ < left_ || node->id_ >= right_) {
693 return E_OK;
694 }
695 if (count_ == max_) {
696 total_ = total_ > count_ ? total_ - 1 : count_;
697 RelDetails(node);
698 } else {
699 nodes_.push_front(node);
700 count_++;
701 }
702 }
703 cond_.notify_one();
704 return E_OK;
705 }
706
Drop(std::shared_ptr<ConnNode> node)707 int32_t ConnectionPool::Container::Drop(std::shared_ptr<ConnNode> node)
708 {
709 {
710 std::unique_lock<decltype(mutex_)> lock(mutex_);
711 RelDetails(node);
712 }
713 cond_.notify_one();
714 return E_OK;
715 }
716
RelDetails(std::shared_ptr<ConnNode> node)717 int32_t ConnectionPool::Container::RelDetails(std::shared_ptr<ConnNode> node)
718 {
719 for (auto it = details_.begin(); it != details_.end();) {
720 auto detailNode = it->lock();
721 if (detailNode == nullptr || detailNode->id_ == node->id_) {
722 it = details_.erase(it);
723 } else {
724 it++;
725 }
726 }
727 return E_OK;
728 }
729
CheckIntegrity(const std::string & dbPath)730 bool ConnectionPool::CheckIntegrity(const std::string &dbPath)
731 {
732 RdbStoreConfig config(config_);
733 config.SetPath(dbPath);
734 config.SetIntegrityCheck(IntegrityCheck::FULL);
735 config.SetHaMode(HAMode::SINGLE);
736 auto [ret, connection] = Connection::Create(config, true);
737 return ret == E_OK;
738 }
739
Clear()740 int32_t ConnPool::Container::Clear()
741 {
742 std::list<std::shared_ptr<ConnNode>> nodes;
743 std::list<std::weak_ptr<ConnNode>> details;
744 {
745 std::unique_lock<decltype(mutex_)> lock(mutex_);
746 nodes = std::move(nodes_);
747 details = std::move(details_);
748 disable_ = true;
749 total_ = 0;
750 count_ = 0;
751 if (right_ > MAX_RIGHT) {
752 right_ = 0;
753 }
754 left_ = right_;
755 creator_ = nullptr;
756 }
757 nodes.clear();
758 details.clear();
759 return 0;
760 }
761
IsFull()762 bool ConnPool::Container::IsFull()
763 {
764 std::unique_lock<decltype(mutex_)> lock(mutex_);
765 return total_ == count_;
766 }
767
Dump(const char * header,int32_t count)768 int32_t ConnPool::Container::Dump(const char *header, int32_t count)
769 {
770 std::string info;
771 std::vector<std::shared_ptr<ConnNode>> details;
772 std::string title = "B_M_T_C[" + std::to_string(count) + "," + std::to_string(max_) + "," +
773 std::to_string(total_) + "," + std::to_string(count_) + "]";
774 {
775 std::unique_lock<decltype(mutex_)> lock(mutex_);
776 details.reserve(details_.size());
777 for (auto &detail : details_) {
778 auto node = detail.lock();
779 if (node == nullptr) {
780 continue;
781 }
782 details.push_back(node);
783 }
784 }
785
786 for (auto &node : details) {
787 info.append("<")
788 .append(std::to_string(node->id_))
789 .append(",")
790 .append(std::to_string(node->tid_))
791 .append(",")
792 .append(std::to_string(node->GetUsingTime()))
793 .append(">");
794 // 256 represent that limit to info length
795 if (info.size() > 256) {
796 LOG_WARN("%{public}s %{public}s:%{public}s", header, title.c_str(), info.c_str());
797 info.clear();
798 }
799 }
800 LOG_WARN("%{public}s %{public}s:%{public}s", header, title.c_str(), info.c_str());
801 return 0;
802 }
803 } // namespace NativeRdb
804 } // namespace OHOS
805