KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > controller > loadbalancer > raidb1 > RAIDb1_LPRF


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.loadbalancer.raidb1;
26
27 import java.sql.SQLException JavaDoc;
28 import java.util.ArrayList JavaDoc;
29
30 import org.objectweb.cjdbc.common.exceptions.NoMoreBackendException;
31 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
32 import org.objectweb.cjdbc.common.i18n.Translate;
33 import org.objectweb.cjdbc.common.sql.AbstractRequest;
34 import org.objectweb.cjdbc.common.sql.SelectRequest;
35 import org.objectweb.cjdbc.common.sql.StoredProcedure;
36 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
37 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
38 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
39 import org.objectweb.cjdbc.controller.loadbalancer.policies.WaitForCompletionPolicy;
40 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
41 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
42
43 /**
44  * RAIDb-1 Round Robin load balancer featuring (Least Pending Requests First
45  * load balancing algorithm).
46  * <p>
47  * The read requests coming from the Request Manager are sent to the node that
48  * has the least pending read requests among the nodes that can execute the
49  * request. Write requests are broadcasted to all backends.
50  *
51  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
52  * @version 1.0
53  */

54 public class RAIDb1_LPRF extends RAIDb1
55 {
56   // How the code is organized ?
57
//
58
// 1. Member variables
59
// 2. Constructor(s)
60
// 3. Request handling
61
// 4. Debug/Monitoring
62

63   /*
64    * Constructors
65    */

66
67   /**
68    * Creates a new RAIDb-1 Round Robin request load balancer.
69    *
70    * @param vdb the virtual database this load balancer belongs to.
71    * @param waitForCompletionPolicy how many backends must complete before
72    * returning the result?
73    * @throws Exception if an error occurs
74    */

75   public RAIDb1_LPRF(VirtualDatabase vdb,
76       WaitForCompletionPolicy waitForCompletionPolicy) throws Exception JavaDoc
77   {
78     super(vdb, waitForCompletionPolicy);
79   }
80
81   /*
82    * Request Handling
83    */

84
85   /**
86    * Selects the backend using a least pending request first policy. The backend
87    * that has the shortest queue of currently executing queries is chosen to
88    * execute this query.
89    *
90    * @see org.objectweb.cjdbc.controller.loadbalancer.raidb1.RAIDb1#execReadRequest(SelectRequest,
91    * MetadataCache)
92    */

93   public ControllerResultSet execReadRequest(SelectRequest request,
94       MetadataCache metadataCache) throws SQLException JavaDoc
95   {
96     return executeLPRF(request, true, "Request ", metadataCache);
97   }
98
99   /**
100    * Selects the backend using a least pending request first policy. The backend
101    * that has the shortest queue of currently executing queries is chosen to
102    * execute this stored procedure.
103    *
104    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#execReadOnlyReadStoredProcedure(StoredProcedure,
105    * MetadataCache)
106    */

107   public ControllerResultSet execReadOnlyReadStoredProcedure(
108       StoredProcedure proc, MetadataCache metadataCache) throws SQLException JavaDoc
109   {
110     return executeLPRF(proc, false, "Stored procedure ", metadataCache);
111   }
112
113   /**
114    * Common code to execute a SelectRequest or a StoredProcedure on a backend
115    * chosen using a LPRF algorithm.
116    *
117    * @param request a <code>SelectRequest</code> or
118    * <code>StoredProcedure</code>
119    * @param isSelect true if it is a <code>SelectRequest</code>, false if it
120    * is a <code>StoredProcedure</code>
121    * @param errorMsgPrefix the error message prefix, usually "Request " or
122    * "Stored procedure " ... failed because ...
123    * @param metadataCache the metadataCache if any or null
124    * @return a <code>ResultSet</code>
125    * @throws SQLException if an error occurs
126    */

127   private ControllerResultSet executeLPRF(AbstractRequest request,
128       boolean isSelect, String JavaDoc errorMsgPrefix, MetadataCache metadataCache)
129       throws SQLException JavaDoc
130   {
131     // Choose a backend
132
try
133     {
134       vdb.acquireReadLockBackendLists();
135     }
136     catch (InterruptedException JavaDoc e)
137     {
138       String JavaDoc msg = Translate.get(
139           "loadbalancer.backendlist.acquire.readlock.failed", e);
140       logger.error(msg);
141       throw new SQLException JavaDoc(msg);
142     }
143
144     DatabaseBackend backend = null; // The
145
// backend
146
// that
147
// will
148
// execute
149
// the
150
// query
151

152     // Note that vdb lock is released in the finally clause of this try/catch
153
// block
154
try
155     {
156       ArrayList JavaDoc backends = vdb.getBackends();
157       int size = backends.size();
158
159       if (size == 0)
160         throw new SQLException JavaDoc(Translate.get(
161             "loadbalancer.execute.no.backend.available", request.getId()));
162
163       // Choose the backend that has the least pending requests
164
int leastRequests = 0;
165       for (int i = 0; i < size; i++)
166       {
167         DatabaseBackend b = (DatabaseBackend) backends.get(i);
168         if (b.isReadEnabled())
169         {
170           int pending = b.getPendingRequests().size();
171           if ((backend == null) || (pending < leastRequests))
172           {
173             backend = b;
174             if (pending == 0)
175               break; // Stop here we will never find a less loaded node
176
else
177               leastRequests = pending;
178           }
179         }
180       }
181
182       if (backend == null)
183         throw new NoMoreBackendException(Translate.get(
184             "loadbalancer.execute.no.backend.enabled", request.getId()));
185     }
186     catch (RuntimeException JavaDoc e)
187     {
188       String JavaDoc msg = Translate.get("loadbalancer.execute.find.backend.failed",
189           new String JavaDoc[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
190               e.getMessage()});
191       logger.error(msg, e);
192       throw new SQLException JavaDoc(msg);
193     }
194     finally
195     {
196       vdb.releaseReadLockBackendLists();
197     }
198
199     ControllerResultSet rs = null;
200     // Execute the request on the chosen backend
201
try
202     {
203       if (isSelect)
204         rs = executeRequestOnBackend((SelectRequest) request, backend,
205             metadataCache);
206       else
207         rs = executeStoredProcedureOnBackend((StoredProcedure) request,
208             backend, metadataCache);
209     }
210     catch (UnreachableBackendException urbe)
211     {
212       // Try to execute query on different backend
213
return executeLPRF(request, isSelect, errorMsgPrefix, metadataCache);
214     }
215     catch (SQLException JavaDoc se)
216     {
217       String JavaDoc msg = Translate.get("loadbalancer.something.failed", new String JavaDoc[]{
218           errorMsgPrefix, String.valueOf(request.getId()), se.getMessage()});
219       if (logger.isInfoEnabled())
220         logger.info(msg);
221       throw se;
222     }
223     catch (RuntimeException JavaDoc e)
224     {
225       String JavaDoc msg = Translate.get("loadbalancer.something.failed.on",
226           new String JavaDoc[]{errorMsgPrefix,
227               request.getSQLShortForm(vdb.getSQLShortFormLength()),
228               backend.getName(), e.getMessage()});
229       logger.error(msg, e);
230       throw new SQLException JavaDoc(msg);
231     }
232
233     return rs;
234   }
235
236   /*
237    * Debug/Monitoring
238    */

239
240   /**
241    * Gets information about the request load balancer.
242    *
243    * @return <code>String</code> containing information
244    */

245   public String JavaDoc getInformation()
246   {
247     // We don't lock since we don't need a top accurate value
248
int size = vdb.getBackends().size();
249
250     if (size == 0)
251       return "RAIDb-1 Least Pending Request First load balancer: !!!Warning!!! No backend nodes found\n";
252     else
253       return "RAIDb-1 Least Pending Request First load balancer (" + size
254           + " backends)\n";
255   }
256
257   /**
258    * @see org.objectweb.cjdbc.controller.loadbalancer.raidb1.RAIDb1#getRaidb1Xml
259    */

260   public String JavaDoc getRaidb1Xml()
261   {
262     return "<" + DatabasesXmlTags.ELT_RAIDb_1_LeastPendingRequestsFirst + "/>";
263   }
264
265 }
266
Popular Tags