1//
2// SessionPool.cpp
3//
4// Library: Data
5// Package: SessionPooling
6// Module: SessionPool
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Data/SessionPool.h"
16#include "Poco/Data/SessionFactory.h"
17#include "Poco/Data/DataException.h"
18#include <algorithm>
19
20
21namespace Poco {
22namespace Data {
23
24
25SessionPool::SessionPool(const std::string& connector, const std::string& connectionString, int minSessions, int maxSessions, int idleTime):
26 _connector(connector),
27 _connectionString(connectionString),
28 _minSessions(minSessions),
29 _maxSessions(maxSessions),
30 _idleTime(idleTime),
31 _nSessions(0),
32 _janitorTimer(1000*idleTime, 1000*idleTime/4),
33 _shutdown(false)
34{
35 Poco::TimerCallback<SessionPool> callback(*this, &SessionPool::onJanitorTimer);
36 _janitorTimer.start(callback);
37}
38
39
40SessionPool::~SessionPool()
41{
42 try
43 {
44 shutdown();
45 }
46 catch (...)
47 {
48 poco_unexpected();
49 }
50}
51
52
53Session SessionPool::get(const std::string& rName, bool value)
54{
55 Session s = get();
56 _addFeatureMap.insert(AddFeatureMap::value_type(s.impl(),
57 std::make_pair(rName, s.getFeature(rName))));
58 s.setFeature(rName, value);
59
60 return s;
61}
62
63
64Session SessionPool::get()
65{
66 Poco::Mutex::ScopedLock lock(_mutex);
67 if (_shutdown) throw InvalidAccessException("Session pool has been shut down.");
68
69 purgeDeadSessions();
70
71 if (_idleSessions.empty())
72 {
73 if (_nSessions < _maxSessions)
74 {
75 Session newSession(SessionFactory::instance().create(_connector, _connectionString));
76 applySettings(newSession.impl());
77 customizeSession(newSession);
78
79 PooledSessionHolderPtr pHolder(new PooledSessionHolder(*this, newSession.impl()));
80 _idleSessions.push_front(pHolder);
81 ++_nSessions;
82 }
83 else throw SessionPoolExhaustedException(_connector);
84 }
85
86 PooledSessionHolderPtr pHolder(_idleSessions.front());
87 PooledSessionImplPtr pPSI(new PooledSessionImpl(pHolder));
88
89 _activeSessions.push_front(pHolder);
90 _idleSessions.pop_front();
91 return Session(pPSI);
92}
93
94
95void SessionPool::purgeDeadSessions()
96{
97 Poco::Mutex::ScopedLock lock(_mutex);
98 if (_shutdown) return;
99
100 SessionList::iterator it = _idleSessions.begin();
101 for (; it != _idleSessions.end(); )
102 {
103 if (!(*it)->session()->isConnected())
104 {
105 it = _idleSessions.erase(it);
106 --_nSessions;
107 }
108 else ++it;
109 }
110}
111
112
113int SessionPool::capacity() const
114{
115 return _maxSessions;
116}
117
118
119int SessionPool::used() const
120{
121 Poco::Mutex::ScopedLock lock(_mutex);
122 return (int) _activeSessions.size();
123}
124
125
126int SessionPool::idle() const
127{
128 Poco::Mutex::ScopedLock lock(_mutex);
129 return (int) _idleSessions.size();
130}
131
132
133int SessionPool::dead()
134{
135 Poco::Mutex::ScopedLock lock(_mutex);
136 int count = 0;
137
138 SessionList::iterator it = _activeSessions.begin();
139 SessionList::iterator itEnd = _activeSessions.end();
140 for (; it != itEnd; ++it)
141 {
142 if (!(*it)->session()->isConnected())
143 ++count;
144 }
145
146 return count;
147}
148
149
150int SessionPool::allocated() const
151{
152 Poco::Mutex::ScopedLock lock(_mutex);
153 return _nSessions;
154}
155
156
157int SessionPool::available() const
158{
159 if (_shutdown) return 0;
160 return _maxSessions - used();
161}
162
163
164void SessionPool::setFeature(const std::string& rName, bool state)
165{
166 Poco::Mutex::ScopedLock lock(_mutex);
167 if (_shutdown) throw InvalidAccessException("Session pool has been shut down.");
168
169 if (_nSessions > 0)
170 throw InvalidAccessException("Features can not be set after the first session was created.");
171
172 _featureMap.insert(FeatureMap::ValueType(rName, state));
173}
174
175
176bool SessionPool::getFeature(const std::string& rName)
177{
178 FeatureMap::ConstIterator it = _featureMap.find(rName);
179 if (_shutdown) throw InvalidAccessException("Session pool has been shut down.");
180
181 if (_featureMap.end() == it)
182 throw NotFoundException("Feature not found:" + rName);
183
184 return it->second;
185}
186
187
188void SessionPool::setProperty(const std::string& rName, const Poco::Any& value)
189{
190 Poco::Mutex::ScopedLock lock(_mutex);
191 if (_shutdown) throw InvalidAccessException("Session pool has been shut down.");
192
193 if (_nSessions > 0)
194 throw InvalidAccessException("Properties can not be set after first session was created.");
195
196 _propertyMap.insert(PropertyMap::ValueType(rName, value));
197}
198
199
200Poco::Any SessionPool::getProperty(const std::string& rName)
201{
202 PropertyMap::ConstIterator it = _propertyMap.find(rName);
203
204 if (_propertyMap.end() == it)
205 throw NotFoundException("Property not found:" + rName);
206
207 return it->second;
208}
209
210
211void SessionPool::applySettings(SessionImpl* pImpl)
212{
213 FeatureMap::Iterator fmIt = _featureMap.begin();
214 FeatureMap::Iterator fmEnd = _featureMap.end();
215 for (; fmIt != fmEnd; ++fmIt) pImpl->setFeature(fmIt->first, fmIt->second);
216
217 PropertyMap::Iterator pmIt = _propertyMap.begin();
218 PropertyMap::Iterator pmEnd = _propertyMap.end();
219 for (; pmIt != pmEnd; ++pmIt) pImpl->setProperty(pmIt->first, pmIt->second);
220}
221
222
223void SessionPool::customizeSession(Session&)
224{
225}
226
227
228void SessionPool::putBack(PooledSessionHolderPtr pHolder)
229{
230 Poco::Mutex::ScopedLock lock(_mutex);
231 if (_shutdown) return;
232
233 SessionList::iterator it = std::find(_activeSessions.begin(), _activeSessions.end(), pHolder);
234 if (it != _activeSessions.end())
235 {
236 if (pHolder->session()->isConnected())
237 {
238 // reverse settings applied at acquisition time, if any
239 AddPropertyMap::iterator pIt = _addPropertyMap.find(pHolder->session());
240 if (pIt != _addPropertyMap.end())
241 pHolder->session()->setProperty(pIt->second.first, pIt->second.second);
242
243 AddFeatureMap::iterator fIt = _addFeatureMap.find(pHolder->session());
244 if (fIt != _addFeatureMap.end())
245 pHolder->session()->setFeature(fIt->second.first, fIt->second.second);
246
247 // re-apply the default pool settings
248 applySettings(pHolder->session());
249
250 pHolder->access();
251 _idleSessions.push_front(pHolder);
252 }
253 else --_nSessions;
254
255 _activeSessions.erase(it);
256 }
257 else
258 {
259 poco_bugcheck_msg("Unknown session passed to SessionPool::putBack()");
260 }
261}
262
263
264void SessionPool::onJanitorTimer(Poco::Timer&)
265{
266 Poco::Mutex::ScopedLock lock(_mutex);
267 if (_shutdown) return;
268
269 SessionList::iterator it = _idleSessions.begin();
270 while (_nSessions > _minSessions && it != _idleSessions.end())
271 {
272 if ((*it)->idle() > _idleTime || !(*it)->session()->isConnected())
273 {
274 try { (*it)->session()->close(); }
275 catch (...) { }
276 it = _idleSessions.erase(it);
277 --_nSessions;
278 }
279 else ++it;
280 }
281}
282
283
284void SessionPool::shutdown()
285{
286 Poco::Mutex::ScopedLock lock(_mutex);
287 if (_shutdown) return;
288 _shutdown = true;
289 _janitorTimer.stop();
290 closeAll(_idleSessions);
291 closeAll(_activeSessions);
292}
293
294
295void SessionPool::closeAll(SessionList& sessionList)
296{
297 SessionList::iterator it = sessionList.begin();
298 for (; it != sessionList.end();)
299 {
300 try { (*it)->session()->close(); }
301 catch (...) { }
302 it = sessionList.erase(it);
303 if (_nSessions > 0) --_nSessions;
304 }
305}
306
307
308} } // namespace Poco::Data
309