forked from qicosmos/ormpp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
connection_pool.hpp
120 lines (101 loc) · 3.4 KB
/
connection_pool.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//
// Created by qiyu on 12/14/17.
//
#ifndef ORMPP_CONNECTION_POOL_HPP
#define ORMPP_CONNECTION_POOL_HPP
#include <deque>
#include <memory>
#include <mutex>
#include <chrono>
#include <condition_variable>
#include <string>
#include <tuple>
namespace ormpp{
template<typename DB>
class connection_pool{
public:
static connection_pool<DB>& instance(){
static connection_pool<DB> instance;
return instance;
}
//call_once
template<typename... Args>
void init(int maxsize, Args&&... args){
std::call_once(flag_, &connection_pool<DB>::init_impl<Args...>, this, maxsize, std::forward<Args>(args)...);
}
std::shared_ptr<DB> get(){
std::unique_lock<std::mutex> lock( mutex_ );
while ( pool_.empty() ){
if(condition_.wait_for(lock, std::chrono::seconds(3))== std::cv_status::timeout){
//timeout
return nullptr;
}
}
auto conn = pool_.front();
pool_.pop_front();
lock.unlock();
if (!conn->ping()) {
return create_connection();
}
//check timeout, idle time shuold less than 8 hours
auto now = std::chrono::system_clock::now();
auto last = conn->get_latest_operate_time();
auto mins = std::chrono::duration_cast<std::chrono::minutes>(now - last).count();
if((mins-6*60)>0){
return create_connection();
}
conn->update_operate_time();
return conn;
}
void return_back(std::shared_ptr<DB> conn){
if (conn == nullptr||conn->has_error()) {
conn = create_connection();
}
std::unique_lock<std::mutex> lock( mutex_ );
pool_.push_back( conn );
lock.unlock();
condition_.notify_one();
}
private:
template<typename... Args>
void init_impl(int maxsize, Args&&... args){
args_ = std::make_tuple(std::forward<Args>(args)...);
for (int i = 0; i < maxsize; ++i) {
auto conn = std::make_shared<DB>();
if(conn->connect(std::forward<Args>(args)...)){
pool_.push_back(conn);
}
else{
throw std::invalid_argument("init failed");
}
}
}
auto create_connection(){
auto conn = std::make_shared<DB>();
auto fn = [conn](auto... targs){
return conn->connect(targs...);
};
return std::apply(fn, args_)? conn: nullptr;
}
connection_pool()= default;
~connection_pool()= default;
connection_pool(const connection_pool&)= delete;
connection_pool& operator=(const connection_pool&)= delete;
std::deque<std::shared_ptr<DB>> pool_;
std::mutex mutex_;
std::condition_variable condition_;
std::once_flag flag_;
std::tuple<const char*, const char*, const char*, const char*, int> args_;
};
template<typename DB>
struct conn_guard{
conn_guard(std::shared_ptr<DB> con) : conn_(con){}
~conn_guard(){
if(conn_!= nullptr)
connection_pool<DB>::instance().return_back(conn_);
}
private:
std::shared_ptr<DB> conn_;
};
}
#endif //ORMPP_CONNECTION_POOL_HPP