1 //
2 // SessionPool.h
3 //
4 // Library: Data
5 // Package: SessionPooling
6 // Module:  SessionPool
7 //
8 // Definition of the SessionPool class.
9 //
10 // Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
11 // and Contributors.
12 //
13 // SPDX-License-Identifier:	BSL-1.0
14 //
15 
16 
17 #ifndef Data_SessionPool_INCLUDED
18 #define Data_SessionPool_INCLUDED
19 
20 
21 #include "Poco/Data/Data.h"
22 #include "Poco/Data/PooledSessionHolder.h"
23 #include "Poco/Data/PooledSessionImpl.h"
24 #include "Poco/Data/Session.h"
25 #include "Poco/HashMap.h"
26 #include "Poco/Any.h"
27 #include "Poco/Timer.h"
28 #include "Poco/Mutex.h"
29 #include <list>
30 
31 
32 namespace Poco {
33 namespace Data {
34 
35 
36 class Data_API SessionPool: public RefCountedObject
37 	/// This class implements session pooling for POCO Data.
38 	///
39 	/// Creating a connection to a database is often a time consuming
40 	/// operation. Therefore it makes sense to reuse a session object
41 	/// once it is no longer needed.
42 	///
43 	/// A SessionPool manages a collection of SessionImpl objects
44 	/// (decorated with a PooledSessionImpl).
45 	///
46 	/// When a SessionImpl object is requested, the SessionPool first
47 	/// looks in its set of already initialized SessionImpl for an
48 	/// available object. If one is found, it is returned to the
49 	/// client and marked as "in-use". If no SessionImpl is available,
50 	/// the SessionPool attempts to create a new one for the client.
51 	/// To avoid excessive creation of SessionImpl objects, a limit
52 	/// can be set on the maximum number of objects.
53 	/// Sessions found not to be connected to the database are purged
54 	/// from the pool whenever one of the following events occurs:
55 	///
56 	///   - JanitorTimer event
57 	///   - get() request
58 	///   - putBack() request
59 	///
60 	/// Not connected idle sessions can not exist.
61 	///
62 	/// Usage example:
63 	///
64 	///     SessionPool pool("ODBC", "...");
65 	///     ...
66 	///     Session sess(pool.get());
67 	///     ...
68 {
69 public:
70 	SessionPool(const std::string& connector,
71 		const std::string& connectionString,
72 		int minSessions = 1,
73 		int maxSessions = 32,
74 		int idleTime = 60);
75 		/// Creates the SessionPool for sessions with the given connector
76 		/// and connectionString.
77 		///
78 		/// The pool allows for at most maxSessions sessions to be created.
79 		/// If a session has been idle for more than idleTime seconds, and more than
80 		/// minSessions sessions are in the pool, the session is automatically destroyed.
81 
82 	~SessionPool();
83 		/// Destroys the SessionPool.
84 
85 	Session get();
86 		/// Returns a Session.
87 		///
88 		/// If there are unused sessions available, one of the
89 		/// unused sessions is recycled. Otherwise, a new session
90 		/// is created.
91 		///
92 		/// If the maximum number of sessions for this pool has
93 		/// already been created, a SessionPoolExhaustedException
94 		/// is thrown.
95 
96 	template <typename T>
get(const std::string & name,const T & value)97 	Session get(const std::string& name, const T& value)
98 		/// Returns a Session with requested property set.
99 		/// The property can be different from the default pool
100 		/// value, in which case it is reset back to the pool
101 		/// value when the session is reclaimed by the pool.
102 	{
103 		Session s = get();
104 		_addPropertyMap.insert(AddPropertyMap::value_type(s.impl(),
105 			std::make_pair(name, s.getProperty(name))));
106 		s.setProperty(name, value);
107 
108 		return s;
109 	}
110 
111 	Session get(const std::string& name, bool value);
112 		/// Returns a Session with requested feature set.
113 		/// The feature can be different from the default pool
114 		/// value, in which case it is reset back to the pool
115 		/// value when the session is reclaimed by the pool.
116 
117 	int capacity() const;
118 		/// Returns the maximum number of sessions the SessionPool will manage.
119 
120 	int used() const;
121 		/// Returns the number of sessions currently in use.
122 
123 	int idle() const;
124 		/// Returns the number of idle sessions.
125 
126 	int dead();
127 		/// Returns the number of not connected active sessions.
128 
129 	int allocated() const;
130 		/// Returns the number of allocated sessions.
131 
132 	int available() const;
133 		/// Returns the number of available (idle + remaining capacity) sessions.
134 
135 	std::string name() const;
136 		/// Returns the name for this pool.
137 
138 	static std::string name(const std::string& connector,
139 		const std::string& connectionString);
140 	/// Returns the name formatted from supplied arguments as "connector:///connectionString".
141 
142 	void setFeature(const std::string& name, bool state);
143 		/// Sets feature for all the sessions.
144 
145 	bool getFeature(const std::string& name);
146 		/// Returns the requested feature.
147 
148 	void setProperty(const std::string& name, const Poco::Any& value);
149 		/// Sets property for all sessions.
150 
151 	Poco::Any getProperty(const std::string& name);
152 		/// Returns the requested property.
153 
154 	void shutdown();
155 		/// Shuts down the session pool.
156 
157 	bool isActive() const;
158 		/// Returns true if session pool is active (not shut down).
159 
160 protected:
161 	virtual void customizeSession(Session& session);
162 		/// Can be overridden by subclass to perform custom initialization
163 		/// of a newly created database session.
164 		///
165 		/// The default implementation does nothing.
166 
167 	typedef Poco::AutoPtr<PooledSessionHolder>    PooledSessionHolderPtr;
168 	typedef Poco::AutoPtr<PooledSessionImpl>      PooledSessionImplPtr;
169 	typedef std::list<PooledSessionHolderPtr>     SessionList;
170 	typedef Poco::HashMap<std::string, bool>      FeatureMap;
171 	typedef Poco::HashMap<std::string, Poco::Any> PropertyMap;
172 
173 	void purgeDeadSessions();
174 	int deadImpl(SessionList& rSessions);
175 	void applySettings(SessionImpl* pImpl);
176 	void putBack(PooledSessionHolderPtr pHolder);
177 	void onJanitorTimer(Poco::Timer&);
178 
179 private:
180 	typedef std::pair<std::string, Poco::Any> PropertyPair;
181 	typedef std::pair<std::string, bool> FeaturePair;
182 	typedef std::map<SessionImpl*, PropertyPair> AddPropertyMap;
183 	typedef std::map<SessionImpl*, FeaturePair> AddFeatureMap;
184 
185 	SessionPool(const SessionPool&);
186 	SessionPool& operator = (const SessionPool&);
187 
188 	void closeAll(SessionList& sessionList);
189 
190 	std::string    _connector;
191 	std::string    _connectionString;
192 	int            _minSessions;
193 	int            _maxSessions;
194 	int            _idleTime;
195 	int            _nSessions;
196 	SessionList    _idleSessions;
197 	SessionList    _activeSessions;
198 	Poco::Timer    _janitorTimer;
199 	FeatureMap     _featureMap;
200 	PropertyMap    _propertyMap;
201 	bool           _shutdown;
202 	AddPropertyMap _addPropertyMap;
203 	AddFeatureMap  _addFeatureMap;
204 	mutable
205 	Poco::Mutex _mutex;
206 
207 	friend class PooledSessionImpl;
208 };
209 
210 
name(const std::string & connector,const std::string & connectionString)211 inline std::string SessionPool::name(const std::string& connector,
212 	const std::string& connectionString)
213 {
214 	return Session::uri(connector, connectionString);
215 }
216 
217 
name()218 inline std::string SessionPool::name() const
219 {
220 	return name(_connector, _connectionString);
221 }
222 
223 
isActive()224 inline bool SessionPool::isActive() const
225 {
226 	return !_shutdown;
227 }
228 
229 
230 } } // namespace Poco::Data
231 
232 
233 #endif // Data_SessionPool_INCLUDED
234