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