Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <stdio.h>
22 : #include "ZConnectionPool.hxx"
23 : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
24 : #include <com/sun/star/container/ElementExistException.hpp>
25 : #include <comphelper/extract.hxx>
26 : #include <comphelper/types.hxx>
27 : #include <com/sun/star/lang/XComponent.hpp>
28 : #include "ZPooledConnection.hxx"
29 : #include "ZPoolCollection.hxx"
30 : #include <connectivity/ConnectionWrapper.hxx>
31 : #include <com/sun/star/beans/XPropertySet.hpp>
32 :
33 :
34 : using namespace ::com::sun::star::uno;
35 : using namespace ::com::sun::star::lang;
36 : using namespace ::com::sun::star::sdbc;
37 : using namespace ::com::sun::star::beans;
38 : using namespace ::com::sun::star::container;
39 : using namespace ::osl;
40 : using namespace connectivity;
41 :
42 : #include <algorithm>
43 :
44 :
45 : //= OPoolTimer
46 :
47 0 : void SAL_CALL OPoolTimer::onShot()
48 : {
49 0 : m_pPool->invalidatePooledConnections();
50 0 : }
51 : namespace
52 : {
53 :
54 0 : static const OUString& getTimeoutNodeName()
55 : {
56 0 : static OUString s_sNodeName( "Timeout" );
57 0 : return s_sNodeName;
58 : }
59 :
60 : }
61 :
62 : //= OConnectionPool
63 :
64 :
65 0 : OConnectionPool::OConnectionPool(const Reference< XDriver >& _xDriver,
66 : const Reference< XInterface >& _xDriverNode,
67 : const Reference< ::com::sun::star::reflection::XProxyFactory >& _rxProxyFactory)
68 : :m_xDriver(_xDriver)
69 : ,m_xDriverNode(_xDriverNode)
70 : ,m_xProxyFactory(_rxProxyFactory)
71 : ,m_nTimeOut(10)
72 0 : ,m_nALiveCount(10)
73 : {
74 : OSL_ENSURE(m_xDriverNode.is(),"NO valid Driver node set!");
75 0 : Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY);
76 0 : if (xComponent.is())
77 0 : xComponent->addEventListener(this);
78 :
79 0 : Reference<XPropertySet> xProp(m_xDriverNode,UNO_QUERY);
80 0 : if(xProp.is())
81 0 : xProp->addPropertyChangeListener(getTimeoutNodeName(),this);
82 :
83 0 : OPoolCollection::getNodeValue(getTimeoutNodeName(),m_xDriverNode) >>= m_nALiveCount;
84 0 : calculateTimeOuts();
85 :
86 0 : m_xInvalidator = new OPoolTimer(this,::salhelper::TTimeValue(m_nTimeOut,0));
87 0 : m_xInvalidator->start();
88 0 : }
89 :
90 0 : OConnectionPool::~OConnectionPool()
91 : {
92 0 : clear(false);
93 0 : }
94 :
95 : struct TRemoveEventListenerFunctor : ::std::unary_function<TPooledConnections::value_type,void>
96 : ,::std::unary_function<TActiveConnectionMap::value_type,void>
97 : {
98 : OConnectionPool* m_pConnectionPool;
99 : bool m_bDispose;
100 :
101 0 : TRemoveEventListenerFunctor(OConnectionPool* _pConnectionPool,bool _bDispose = false)
102 : : m_pConnectionPool(_pConnectionPool)
103 0 : ,m_bDispose(_bDispose)
104 : {
105 : OSL_ENSURE(m_pConnectionPool,"No connection pool!");
106 0 : }
107 :
108 0 : void dispose(const Reference<XInterface>& _xComponent)
109 : {
110 0 : Reference< XComponent > xComponent(_xComponent, UNO_QUERY);
111 :
112 0 : if ( xComponent.is() )
113 : {
114 0 : xComponent->removeEventListener(m_pConnectionPool);
115 0 : if ( m_bDispose )
116 0 : xComponent->dispose();
117 0 : }
118 0 : }
119 :
120 0 : void operator()(const TPooledConnections::value_type& _aValue)
121 : {
122 0 : dispose(_aValue);
123 0 : }
124 :
125 0 : void operator()(const TActiveConnectionMap::value_type& _aValue)
126 : {
127 0 : dispose(_aValue.first);
128 0 : }
129 : };
130 :
131 : struct TConnectionPoolFunctor : ::std::unary_function<TConnectionMap::value_type,void>
132 : {
133 : OConnectionPool* m_pConnectionPool;
134 :
135 0 : TConnectionPoolFunctor(OConnectionPool* _pConnectionPool)
136 0 : : m_pConnectionPool(_pConnectionPool)
137 : {
138 : OSL_ENSURE(m_pConnectionPool,"No connection pool!");
139 0 : }
140 0 : void operator()(const TConnectionMap::value_type& _aValue)
141 : {
142 0 : ::std::for_each(_aValue.second.aConnections.begin(),_aValue.second.aConnections.end(),TRemoveEventListenerFunctor(m_pConnectionPool,true));
143 0 : }
144 : };
145 :
146 0 : void OConnectionPool::clear(bool _bDispose)
147 : {
148 0 : MutexGuard aGuard(m_aMutex);
149 :
150 0 : if(m_xInvalidator->isTicking())
151 0 : m_xInvalidator->stop();
152 :
153 0 : ::std::for_each(m_aPool.begin(),m_aPool.end(),TConnectionPoolFunctor(this));
154 0 : m_aPool.clear();
155 :
156 0 : ::std::for_each(m_aActiveConnections.begin(),m_aActiveConnections.end(),TRemoveEventListenerFunctor(this,_bDispose));
157 0 : m_aActiveConnections.clear();
158 :
159 0 : Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY);
160 0 : if (xComponent.is())
161 0 : xComponent->removeEventListener(this);
162 0 : Reference< XPropertySet > xProp(m_xDriverNode, UNO_QUERY);
163 0 : if (xProp.is())
164 0 : xProp->removePropertyChangeListener(getTimeoutNodeName(),this);
165 :
166 0 : m_xDriverNode.clear();
167 0 : m_xDriver.clear();
168 0 : }
169 :
170 0 : Reference< XConnection > SAL_CALL OConnectionPool::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo ) throw(SQLException, RuntimeException)
171 : {
172 0 : MutexGuard aGuard(m_aMutex);
173 :
174 0 : Reference<XConnection> xConnection;
175 :
176 : // create a unique id and look for it in our map
177 0 : Sequence< PropertyValue > aInfo(_rInfo);
178 0 : TConnectionMap::key_type nId;
179 0 : OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer);
180 0 : TConnectionMap::iterator aIter = m_aPool.find(nId);
181 :
182 0 : if ( m_aPool.end() != aIter )
183 0 : xConnection = getPooledConnection(aIter);
184 :
185 0 : if ( !xConnection.is() )
186 0 : xConnection = createNewConnection(_rURL,_rInfo);
187 :
188 0 : return xConnection;
189 : }
190 :
191 0 : void SAL_CALL OConnectionPool::disposing( const ::com::sun::star::lang::EventObject& Source ) throw (RuntimeException, std::exception)
192 : {
193 0 : Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
194 0 : if(xConnection.is())
195 : {
196 0 : MutexGuard aGuard(m_aMutex);
197 0 : TActiveConnectionMap::iterator aIter = m_aActiveConnections.find(xConnection);
198 : OSL_ENSURE(aIter != m_aActiveConnections.end(),"OConnectionPool::disposing: Conenction wasn't in pool");
199 0 : if(aIter != m_aActiveConnections.end())
200 : { // move the pooled connection back to the pool
201 0 : aIter->second.aPos->second.nALiveCount = m_nALiveCount;
202 0 : aIter->second.aPos->second.aConnections.push_back(aIter->second.xPooledConnection);
203 0 : m_aActiveConnections.erase(aIter);
204 0 : }
205 : }
206 : else
207 : {
208 0 : m_xDriverNode.clear();
209 0 : }
210 0 : }
211 :
212 0 : Reference< XConnection> OConnectionPool::createNewConnection(const OUString& _rURL,const Sequence< PropertyValue >& _rInfo)
213 : {
214 : // create new pooled conenction
215 0 : Reference< XPooledConnection > xPooledConnection = new ::connectivity::OPooledConnection(m_xDriver->connect(_rURL,_rInfo),m_xProxyFactory);
216 : // get the new connection from the pooled connection
217 0 : Reference<XConnection> xConnection = xPooledConnection->getConnection();
218 0 : if(xConnection.is())
219 : {
220 : // add our own as dispose listener to know when we should put the connection back to the pool
221 0 : Reference< XComponent > xComponent(xConnection, UNO_QUERY);
222 0 : if (xComponent.is())
223 0 : xComponent->addEventListener(this);
224 :
225 : // save some information to find the right pool later on
226 0 : Sequence< PropertyValue > aInfo(_rInfo);
227 0 : TConnectionMap::key_type nId;
228 0 : OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer);
229 0 : TConnectionPool aPack;
230 :
231 : // insert the new connection and struct into the active connection map
232 0 : aPack.nALiveCount = m_nALiveCount;
233 0 : TActiveConnectionInfo aActiveInfo;
234 0 : aActiveInfo.aPos = m_aPool.insert(TConnectionMap::value_type(nId,aPack)).first;
235 0 : aActiveInfo.xPooledConnection = xPooledConnection;
236 0 : m_aActiveConnections.insert(TActiveConnectionMap::value_type(xConnection,aActiveInfo));
237 :
238 0 : if(m_xInvalidator->isExpired())
239 0 : m_xInvalidator->start();
240 : }
241 :
242 0 : return xConnection;
243 : }
244 :
245 0 : void OConnectionPool::invalidatePooledConnections()
246 : {
247 0 : MutexGuard aGuard(m_aMutex);
248 0 : TConnectionMap::iterator aIter = m_aPool.begin();
249 0 : for (; aIter != m_aPool.end(); )
250 : {
251 0 : if(!(--(aIter->second.nALiveCount))) // connections are invalid
252 : {
253 0 : ::std::for_each(aIter->second.aConnections.begin(),aIter->second.aConnections.end(),TRemoveEventListenerFunctor(this,true));
254 :
255 0 : aIter->second.aConnections.clear();
256 :
257 : // look if the iterator aIter is still present in the active connection map
258 0 : TActiveConnectionMap::iterator aActIter = m_aActiveConnections.begin();
259 0 : for (; aActIter != m_aActiveConnections.end(); ++aActIter)
260 : {
261 0 : if(aIter == aActIter->second.aPos)
262 0 : break;
263 : }
264 0 : if(aActIter == m_aActiveConnections.end())
265 : {// he isn't so we can delete him
266 0 : TConnectionMap::iterator aDeleteIter = aIter;
267 0 : ++aIter;
268 0 : m_aPool.erase(aDeleteIter);
269 : }
270 : else
271 0 : ++aIter;
272 : }
273 : else
274 0 : ++aIter;
275 : }
276 0 : if(!m_aPool.empty())
277 0 : m_xInvalidator->start();
278 0 : }
279 :
280 0 : Reference< XConnection> OConnectionPool::getPooledConnection(TConnectionMap::iterator& _rIter)
281 : {
282 0 : Reference<XConnection> xConnection;
283 :
284 0 : if(!_rIter->second.aConnections.empty())
285 : {
286 0 : Reference< XPooledConnection > xPooledConnection = _rIter->second.aConnections.back();
287 0 : _rIter->second.aConnections.pop_back();
288 :
289 : OSL_ENSURE(xPooledConnection.is(),"Can not be null here!");
290 0 : xConnection = xPooledConnection->getConnection();
291 0 : Reference< XComponent > xComponent(xConnection, UNO_QUERY);
292 0 : if (xComponent.is())
293 0 : xComponent->addEventListener(this);
294 :
295 0 : TActiveConnectionInfo aActiveInfo;
296 0 : aActiveInfo.aPos = _rIter;
297 0 : aActiveInfo.xPooledConnection = xPooledConnection;
298 0 : m_aActiveConnections[xConnection] = aActiveInfo;
299 : }
300 0 : return xConnection;
301 : }
302 :
303 0 : void SAL_CALL OConnectionPool::propertyChange( const PropertyChangeEvent& evt ) throw (::com::sun::star::uno::RuntimeException, std::exception)
304 : {
305 0 : if(getTimeoutNodeName() == evt.PropertyName)
306 : {
307 0 : evt.NewValue >>= m_nALiveCount;
308 0 : calculateTimeOuts();
309 : }
310 0 : }
311 :
312 0 : void OConnectionPool::calculateTimeOuts()
313 : {
314 0 : sal_Int32 nTimeOutCorrection = 10;
315 0 : if(m_nALiveCount < 100)
316 0 : nTimeOutCorrection = 20;
317 :
318 0 : m_nTimeOut = m_nALiveCount / nTimeOutCorrection;
319 0 : m_nALiveCount = m_nALiveCount / m_nTimeOut;
320 0 : }
321 :
322 :
323 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|