This repository has been archived by the owner on Mar 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathConnectionPool.h
198 lines (138 loc) · 4.49 KB
/
ConnectionPool.h
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/* Copyright 2013 Active911 Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http: *www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* ConnectionPool manages a connection pool of some kind. Worker threads can ask for a connection, and must return it when done.
* Each connection is guaranteed to be healthy, happy, and free of disease.
*
* Connection and ConnectionFactory are virtual classes that should be overridden to their actual type.
*
* NOTE: To avoid using templates AND inheritance at the same time in the ConnectionFactory, ConnectionFactory::create must create a derved type
* but return the base class.
*/
// Define your custom logging function by overriding this #define
#ifndef _DEBUG
#define _DEBUG(x)
#endif
#include <deque>
#include <set>
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <exception>
#include <string>
using namespace std;
using boost::shared_ptr;
namespace active911 {
struct ConnectionUnavailable : std::exception {
char const* what() const throw() {
return "Unable to allocate connection";
};
};
class Connection {
public:
Connection(){};
virtual ~Connection(){};
};
class ConnectionFactory {
public:
virtual shared_ptr<Connection> create()=0;
};
struct ConnectionPoolStats {
size_t pool_size;
size_t borrowed_size;
};
template<class T>
class ConnectionPool {
public:
ConnectionPoolStats get_stats() {
// Lock
boost::mutex::scoped_lock lock(this->io_mutex);
// Get stats
ConnectionPoolStats stats;
stats.pool_size=this->pool.size();
stats.borrowed_size=this->borrowed.size();
return stats;
};
ConnectionPool(size_t pool_size, shared_ptr<ConnectionFactory> factory){
// Setup
this->pool_size=pool_size;
this->factory=factory;
// Fill the pool
while(this->pool.size() < this->pool_size){
this->pool.push_back(this->factory->create());
}
};
~ConnectionPool() {
};
/**
* Borrow
*
* Borrow a connection for temporary use
*
* When done, either (a) call unborrow() to return it, or (b) (if it's bad) just let it go out of scope. This will cause it to automatically be replaced.
* @retval a shared_ptr to the connection object
*/
shared_ptr<T> borrow(){
// Lock
boost::mutex::scoped_lock lock(this->io_mutex);
// Check for a free connection
if(this->pool.size()==0){
// Are there any crashed connections listed as "borrowed"?
for(std::set<shared_ptr<Connection> >::iterator it=this->borrowed.begin(); it!=this->borrowed.end(); ++it){
if((*it).unique()) {
// This connection has been abandoned! Destroy it and create a new connection
try {
// If we are able to create a new connection, return it
_DEBUG("Creating new connection to replace discarded connection");
shared_ptr<Connection> conn=this->factory->create();
this->borrowed.erase(it);
this->borrowed.insert(conn);
return boost::static_pointer_cast<T>(conn);
} catch(std::exception& e) {
// Error creating a replacement connection
throw ConnectionUnavailable();
}
}
}
// Nothing available
throw ConnectionUnavailable();
}
// Take one off the front
shared_ptr<Connection>conn=this->pool.front();
this->pool.pop_front();
// Add it to the borrowed list
this->borrowed.insert(conn);
return boost::static_pointer_cast<T>(conn);
};
/**
* Unborrow a connection
*
* Only call this if you are returning a working connection. If the connection was bad, just let it go out of scope (so the connection manager can replace it).
* @param the connection
*/
void unborrow(shared_ptr<T> conn) {
// Lock
boost::mutex::scoped_lock lock(this->io_mutex);
// Push onto the pool
this->pool.push_back(boost::static_pointer_cast<Connection>(conn));
// Unborrow
this->borrowed.erase(conn);
};
protected:
shared_ptr<ConnectionFactory> factory;
size_t pool_size;
deque<shared_ptr<Connection> > pool;
set<shared_ptr<Connection> > borrowed;
boost::mutex io_mutex;
};
}