Branch data 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 ::rtl::OUString& getTimeoutNodeName()
55 : : {
56 [ # # ][ # # ]: 0 : static ::rtl::OUString s_sNodeName( RTL_CONSTASCII_USTRINGPARAM( "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(sal_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 : : sal_Bool m_bDispose;
100 : :
101 : 0 : TRemoveEventListenerFunctor(OConnectionPool* _pConnectionPool,sal_Bool _bDispose = sal_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,sal_True));
143 : 0 : }
144 : : };
145 : : // -----------------------------------------------------------------------------
146 : 0 : void OConnectionPool::clear(sal_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 ::rtl::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)
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 ::rtl::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,sal_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)
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: */
|