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