KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > connection > RandomWaitPoolConnectionManager


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
6  * Contact: sequoia@continuent.org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  * Initial developer(s): Emmanuel Cecchet.
21  * Contributor(s): ______________________.
22  */

23
24 package org.continuent.sequoia.controller.connection;
25
26 import java.sql.Connection JavaDoc;
27 import java.util.NoSuchElementException JavaDoc;
28
29 import org.continuent.sequoia.common.exceptions.UnreachableBackendException;
30 import org.continuent.sequoia.common.i18n.Translate;
31 import org.continuent.sequoia.common.xml.DatabasesXmlTags;
32
33 /**
34  * This connection manager waits when the pool is empty. Requests are stacked
35  * using the Java wait/notify mechanism. Therefore the FIFO order is not
36  * guaranteed and the first request to get the freed connection is the thread
37  * that gets elected by the scheduler.
38  *
39  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
40  * @author <a HREF="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
41  * @version 1.0
42  */

43 public class RandomWaitPoolConnectionManager
44     extends AbstractPoolConnectionManager
45 {
46   /** Time to wait for a connection in milliseconds (0 means wait forever). */
47   private int timeout;
48
49   /**
50    * Creates a new <code>RandomWaitPoolConnectionManager</code> instance.
51    *
52    * @param backendUrl URL of the <code>DatabaseBackend</code> owning this
53    * connection manager
54    * @param backendName name of the <code>DatabaseBackend</code> owning this
55    * connection manager
56    * @param login backend connection login to be used by this connection manager
57    * @param password backend connection password to be used by this connection
58    * manager
59    * @param driverPath path for driver
60    * @param driverClassName class name for driver
61    * @param poolSize size of the connection pool
62    * @param timeout time to wait for a connection in seconds (0 means wait
63    * forever)
64    */

65   public RandomWaitPoolConnectionManager(String JavaDoc backendUrl, String JavaDoc backendName,
66       String JavaDoc login, String JavaDoc password, String JavaDoc driverPath, String JavaDoc driverClassName,
67       int poolSize, int timeout)
68   {
69     super(backendUrl, backendName, login, password, driverPath,
70         driverClassName, poolSize);
71     this.timeout = timeout * 1000;
72   }
73
74   /**
75    * @see java.lang.Object#clone()
76    */

77   protected Object JavaDoc clone() throws CloneNotSupportedException JavaDoc
78   {
79     return new RandomWaitPoolConnectionManager(backendUrl, backendName, rLogin,
80         rPassword, driverPath, driverClassName, poolSize, timeout);
81   }
82
83   /**
84    * @see org.continuent.sequoia.controller.connection.AbstractConnectionManager#clone(String,
85    * String)
86    */

87   public AbstractConnectionManager clone(String JavaDoc rLogin, String JavaDoc rPassword)
88   {
89     return new RandomWaitPoolConnectionManager(backendUrl, backendName, rLogin,
90         rPassword, driverPath, driverClassName, poolSize, timeout);
91   }
92
93   /**
94    * Gets the timeout.
95    *
96    * @return a <code>int</code> value.
97    */

98   public int getTimeout()
99   {
100     return timeout;
101   }
102
103   /**
104    * Gets a connection from the pool.
105    * <p>
106    * If the pool is empty, this methods blocks until a connection is freed or
107    * the timeout expires.
108    *
109    * @return a connection from the pool or <code>null</code> if the timeout
110    * has expired.
111    * @throws UnreachableBackendException if the backend must be disabled
112    * @see org.continuent.sequoia.controller.connection.AbstractConnectionManager#getConnection()
113    */

114   public synchronized PooledConnection getConnection()
115       throws UnreachableBackendException
116   {
117     if (!initialized)
118     {
119       logger
120           .error("Requesting a connection from a non-initialized connection manager");
121       return null;
122     }
123     if (isShutdown)
124     {
125       return null;
126     }
127     long lTimeout = timeout;
128
129     // We have to do a while loop() because there is a potential race here.
130
// When freeConnections is notified in releaseConnection, a new thread
131
// can
132
// take the lock on freeConnections before we wake up/reacquire the lock
133
// on freeConnections. Therefore, we could wake up and have no connection
134
// to take! We ensure that everything is correct with a while statement
135
// and recomputing the timeout between 2 wakeup.
136
while (freeConnections.isEmpty())
137     {
138       // Wait
139
try
140       {
141         if (lTimeout > 0)
142         {
143           long start = System.currentTimeMillis();
144           // Convert seconds to milliseconds for wait call
145
this.wait(timeout);
146           long end = System.currentTimeMillis();
147           lTimeout -= end - start;
148           if (lTimeout <= 0)
149           {
150             if (activeConnections.size() == 0)
151             { // No connection active and backend unreachable, the backend
152
// is probably dead
153
logger
154                   .error("Backend " + backendName + " is no more accessible.");
155               throw new UnreachableBackendException();
156             }
157             if (logger.isWarnEnabled())
158               logger.warn("Timeout expired for connection on backend '"
159                   + backendName
160                   + "', consider increasing pool size (current size is "
161                   + poolSize + ") or timeout (current timeout is "
162                   + (timeout / 1000) + " seconds)");
163             return null;
164           }
165         }
166         else
167           this.wait();
168       }
169       catch (InterruptedException JavaDoc e)
170       {
171         logger
172             .error("Wait on freeConnections interrupted in RandomWaitPoolConnectionManager: "
173                 + e);
174         return null;
175       }
176     }
177     if (isShutdown)
178     {
179       return null;
180     }
181     // Get the connection
182
try
183     {
184       PooledConnection c = (PooledConnection) freeConnections.removeLast();
185       activeConnections.add(c);
186       return c;
187     }
188     catch (NoSuchElementException JavaDoc e)
189     {
190       int missing = poolSize
191           - (activeConnections.size() + freeConnections.size());
192       if (missing > 0)
193       { // Re-allocate missing connections
194
logger
195             .info("Trying to reallocate " + missing + " missing connections.");
196         PooledConnection connectionToBeReturned = null;
197         while (missing > 0)
198         {
199           Connection JavaDoc c = getConnectionFromDriver();
200           if (c == null)
201           {
202             if (missing == poolSize)
203             {
204               String JavaDoc msg = Translate.get("loadbalancer.backend.unreacheable",
205                   backendName);
206               logger.error(msg);
207               throw new UnreachableBackendException(msg);
208             }
209             logger.warn("Unable to re-allocate " + missing
210                 + " missing connections.");
211             break;
212           }
213           else
214           {
215             if (connectionToBeReturned == null)
216               connectionToBeReturned = new PooledConnection(c);
217             else
218               freeConnections.addLast(new PooledConnection(c));
219           }
220           missing--;
221         }
222         return connectionToBeReturned;
223       }
224       if (logger.isErrorEnabled())
225         logger.error("Failed to get a connection on backend '" + backendName
226             + "' whereas an idle connection was expected");
227       return null;
228     }
229   }
230
231   /**
232    * @see org.continuent.sequoia.controller.connection.AbstractConnectionManager#releaseConnection(org.continuent.sequoia.controller.connection.PooledConnection)
233    */

234   public synchronized void releaseConnection(PooledConnection c)
235   {
236     if (!initialized)
237     {
238       closeConnection(c);
239       return; // We probably have been disabled
240
}
241
242     if (activeConnections.remove(c))
243     {
244       freeConnections.addLast(c);
245       this.notify();
246     }
247     else
248       logger.error("Failed to release connection " + c
249           + " (not found in active pool)");
250   }
251
252   /**
253    * @see org.continuent.sequoia.controller.connection.AbstractConnectionManager#deleteConnection(org.continuent.sequoia.controller.connection.PooledConnection)
254    */

255   public synchronized void deleteConnection(PooledConnection c)
256   {
257     closeConnection(c);
258     if (!initialized)
259       return; // We probably have been disabled
260

261     if (activeConnections.remove(c))
262     {
263       Connection JavaDoc newConnection = getConnectionFromDriver();
264       if (newConnection == null)
265       {
266         if (logger.isDebugEnabled())
267           logger.error("Bad connection " + c
268               + " has been removed but cannot be replaced.");
269       }
270       else
271       {
272         freeConnections.addLast(newConnection);
273         this.notify();
274         if (logger.isDebugEnabled())
275           logger.debug("Bad connection " + c
276               + " has been replaced by a new connection.");
277       }
278     }
279     else
280       logger.error("Failed to release connection " + c
281           + " (not found in active pool)");
282   }
283
284   /**
285    * @see org.continuent.sequoia.controller.connection.AbstractConnectionManager#getXmlImpl()
286    */

287   public String JavaDoc getXmlImpl()
288   {
289     StringBuffer JavaDoc info = new StringBuffer JavaDoc();
290     info.append("<" + DatabasesXmlTags.ELT_RandomWaitPoolConnectionManager
291         + " " + DatabasesXmlTags.ATT_poolSize + "=\"" + poolSize + "\" "
292         + DatabasesXmlTags.ATT_timeout + "=\"" + timeout / 1000 + "\"/>");
293     return info.toString();
294   }
295
296 }
297
Popular Tags