KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > controller > connection > RandomWaitPoolConnectionManager


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2005 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Emmanuel Cecchet.
22  * Contributor(s): ______________________.
23  */

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

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

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

78   protected Object JavaDoc clone() throws CloneNotSupportedException JavaDoc
79   {
80     return new RandomWaitPoolConnectionManager(backendUrl, backendName, rLogin,
81         rPassword, driverPath, driverClassName, poolSize, timeout);
82   }
83
84   /**
85    * Gets the timeout.
86    *
87    * @return a <code>int</code> value.
88    */

89   public int getTimeout()
90   {
91     return timeout;
92   }
93
94   /**
95    * Gets a connection from the pool.
96    * <p>
97    * If the pool is empty, this methods blocks until a connection is freed or
98    * the timeout expires.
99    *
100    * @return a connection from the pool or <code>null</code> if the timeout
101    * has expired.
102    * @throws UnreachableBackendException if the backend must be disabled
103    * @see org.objectweb.cjdbc.controller.connection.AbstractConnectionManager#getConnection()
104    */

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

219   public synchronized void releaseConnection(Connection JavaDoc c)
220   {
221     if (!initialized)
222       return; // We probably have been disabled
223

224     if (activeConnections.remove(c))
225     {
226       freeConnections.addLast(c);
227       this.notify();
228     }
229     else
230       logger.error("Failed to release connection " + c
231           + " (not found in active pool)");
232   }
233
234   /**
235    * @see org.objectweb.cjdbc.controller.connection.AbstractPoolConnectionManager#deleteConnection(Connection)
236    */

237   public synchronized void deleteConnection(Connection JavaDoc c)
238   {
239     if (!initialized)
240       return; // We probably have been disabled
241

242     if (activeConnections.remove(c))
243     {
244       Connection JavaDoc newConnection = getConnectionFromDriver();
245       if (newConnection == null)
246       {
247         if (logger.isDebugEnabled())
248           logger.error("Bad connection " + c
249               + " has been removed but cannot be replaced.");
250       }
251       else
252       {
253         freeConnections.addLast(newConnection);
254         this.notify();
255         if (logger.isDebugEnabled())
256           logger.debug("Bad connection " + c
257               + " has been replaced by a new connection.");
258       }
259     }
260     else
261       logger.error("Failed to release connection " + c
262           + " (not found in active pool)");
263   }
264
265   /**
266    * @see org.objectweb.cjdbc.controller.connection.AbstractConnectionManager#getXmlImpl()
267    */

268   public String JavaDoc getXmlImpl()
269   {
270     StringBuffer JavaDoc info = new StringBuffer JavaDoc();
271     info.append("<" + DatabasesXmlTags.ELT_RandomWaitPoolConnectionManager
272         + " " + DatabasesXmlTags.ATT_poolSize + "=\"" + poolSize + "\" "
273         + DatabasesXmlTags.ATT_timeout + "=\"" + timeout / 1000 + "\"/>");
274     return info.toString();
275   }
276
277 }
278
Popular Tags