KickJava   Java API By Example, From Geeks To Geeks.

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


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2004 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): Julie Marguerite.
23  */

24
25 package org.objectweb.cjdbc.controller.loadbalancer.raidb1;
26
27 import java.sql.SQLException JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.HashMap JavaDoc;
30
31 import org.objectweb.cjdbc.common.exceptions.NoMoreBackendException;
32 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
33 import org.objectweb.cjdbc.common.i18n.Translate;
34 import org.objectweb.cjdbc.common.sql.AbstractRequest;
35 import org.objectweb.cjdbc.common.sql.SelectRequest;
36 import org.objectweb.cjdbc.common.sql.StoredProcedure;
37 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
38 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
39 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
40 import org.objectweb.cjdbc.controller.loadbalancer.WeightedBalancer;
41 import org.objectweb.cjdbc.controller.loadbalancer.policies.WaitForCompletionPolicy;
42 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
43 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
44
45 /**
46  * RAIDb-1 Weighted Round Robin load balancer
47  * <p>
48  * The read requests coming from the request manager are sent to the backend
49  * nodes using a weighted round robin. Write requests are broadcasted to all
50  * backends.
51  *
52  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
53  * @author <a HREF="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
54  * @author <a HREF="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
55  * @version 1.0
56  */

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

63
64   private HashMap JavaDoc weights = new HashMap JavaDoc();
65   private int index; // index in the backend
66
// vector the
67

68   // Round-Robin
69

70   /*
71    * Constructors
72    */

73
74   /**
75    * Creates a new RAIDb-1 Weighted Round Robin request load balancer.
76    *
77    * @param vdb the virtual database this load balancer belongs to.
78    * @param waitForCompletionPolicy How many backends must complete before
79    * returning the result?
80    * @throws Exception if an error occurs
81    */

82   public RAIDb1_WRR(VirtualDatabase vdb,
83       WaitForCompletionPolicy waitForCompletionPolicy) throws Exception JavaDoc
84   {
85     super(vdb, waitForCompletionPolicy);
86     index = -1;
87   }
88
89   /*
90    * Request Handling
91    */

92
93   /**
94    * Selects the backend using a weighted round-robin algorithm and executes the
95    * read request.
96    *
97    * @see org.objectweb.cjdbc.controller.loadbalancer.raidb1.RAIDb1#execReadRequest(SelectRequest,
98    * MetadataCache)
99    */

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

114   public ControllerResultSet execReadOnlyReadStoredProcedure(
115       StoredProcedure proc, MetadataCache metadataCache) throws SQLException JavaDoc
116   {
117     return executeWRR(proc, false, "Stored procedure ", metadataCache);
118   }
119
120   /**
121    * Common code to execute a SelectRequest or a StoredProcedure on a backend
122    * chosen using a weighted round-robin algorithm.
123    *
124    * @param request a <code>SelectRequest</code> or
125    * <code>StoredProcedure</code>
126    * @param isSelect true if it is a <code>SelectRequest</code>, false if it
127    * is a <code>StoredProcedure</code>
128    * @param errorMsgPrefix the error message prefix, usually "Request " or
129    * "Stored procedure " ... failed because ...
130    * @param metadataCache a metadataCache if any or null
131    * @return a <code>ResultSet</code>
132    * @throws SQLException if an error occurs
133    */

134   private ControllerResultSet executeWRR(AbstractRequest request,
135       boolean isSelect, String JavaDoc errorMsgPrefix, MetadataCache metadataCache)
136       throws SQLException JavaDoc
137   {
138     // Choose a backend
139
try
140     {
141       vdb.acquireReadLockBackendLists();
142     }
143     catch (InterruptedException JavaDoc e)
144     {
145       String JavaDoc msg = Translate.get(
146           "loadbalancer.backendlist.acquire.readlock.failed", e);
147       logger.error(msg);
148       throw new SQLException JavaDoc(msg);
149     }
150
151     DatabaseBackend backend = null;
152
153     // Note that vdb lock is released in the finally clause of this try/catch
154
// block
155
try
156     {
157       ArrayList JavaDoc backends = vdb.getBackends();
158       int size = backends.size();
159
160       if (size == 0)
161         throw new SQLException JavaDoc(Translate.get(
162             "loadbalancer.execute.no.backend.available", request.getId()));
163
164       // Choose the backend (WRR algorithm starts here)
165
int w = 0; // cumulative weight
166
for (int i = 0; i < size; i++)
167       {
168         DatabaseBackend b = (DatabaseBackend) backends.get(index);
169         if (b.isReadEnabled())
170         {
171           if (backend == null)
172             backend = b; // Fallback if no backend found
173

174           // Add the weight of this backend
175
Integer JavaDoc weight = (Integer JavaDoc) weights.get(b.getName());
176           if (weight == null)
177             logger.error("No weight defined for backend " + b.getName());
178           else
179             w += weight.intValue();
180
181           // Ok we reached the needed weight, take this backend
182
if (index <= w)
183           {
184             backend = b;
185             index++; // Next time take the next
186
break;
187           }
188         }
189       }
190
191       if (backend == null)
192         throw new NoMoreBackendException(Translate.get(
193             "loadbalancer.execute.no.backend.enabled", request.getId()));
194
195       // We are over the total weight and we are using the
196
// first available node. Let's reset the index to 1
197
// since we used this first node (0++).
198
if (index > w)
199         index = 1;
200     }
201     catch (RuntimeException JavaDoc e)
202     {
203       String JavaDoc msg = Translate.get("loadbalancer.execute.find.backend.failed",
204           new String JavaDoc[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
205               e.getMessage()});
206       logger.error(msg, e);
207       throw new SQLException JavaDoc(msg);
208     }
209     finally
210     {
211       vdb.releaseReadLockBackendLists();
212     }
213
214     ControllerResultSet rs = null;
215     // Execute the request on the chosen backend
216
try
217     {
218       if (isSelect)
219         rs = executeRequestOnBackend((SelectRequest) request, backend,
220             metadataCache);
221       else
222         rs = executeStoredProcedureOnBackend((StoredProcedure) request,
223             backend, metadataCache);
224     }
225     catch (UnreachableBackendException urbe)
226     {
227       // Try to execute query on different backend
228
return executeWRR(request, isSelect, errorMsgPrefix, metadataCache);
229     }
230     catch (SQLException JavaDoc se)
231     {
232       String JavaDoc msg = Translate.get("loadbalancer.something.failed", new String JavaDoc[]{
233           errorMsgPrefix, String.valueOf(request.getId()), se.getMessage()});
234       if (logger.isInfoEnabled())
235         logger.info(msg);
236       throw se;
237     }
238     catch (RuntimeException JavaDoc e)
239     {
240       String JavaDoc msg = Translate.get("loadbalancer.something.failed.on",
241           new String JavaDoc[]{errorMsgPrefix,
242               request.getSQLShortForm(vdb.getSQLShortFormLength()),
243               backend.getName(), e.getMessage()});
244       logger.error(msg, e);
245       throw new SQLException JavaDoc(msg);
246     }
247
248     return rs;
249   }
250
251   /*
252    * Backends management
253    */

254
255   /**
256    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#setWeight(String,
257    * int)
258    */

259   public void setWeight(String JavaDoc name, int w) throws SQLException JavaDoc
260   {
261     if (logger.isDebugEnabled())
262       logger.debug(Translate.get("loadbalancer.weight.set", new String JavaDoc[]{
263           String.valueOf(w), name}));
264
265     weights.put(name, new Integer JavaDoc(w));
266   }
267
268   /*
269    * Debug/Monitoring
270    */

271
272   /**
273    * Gets information about the request load balancer.
274    *
275    * @return <code>String</code> containing information
276    */

277   public String JavaDoc getInformation()
278   {
279     // We don't lock since we don't need a top accurate value
280
int size = vdb.getBackends().size();
281
282     if (size == 0)
283       return "RAIDb-1 with Weighted Round Robin Request load balancer: !!!Warning!!! No backend nodes found\n";
284     else
285       return "RAIDb-1 Weighted Round-Robin Request load balancer (" + size
286           + " backends)\n";
287   }
288
289   /**
290    * @see org.objectweb.cjdbc.controller.loadbalancer.raidb1.RAIDb1#getRaidb1Xml
291    */

292   public String JavaDoc getRaidb1Xml()
293   {
294     return WeightedBalancer.getRaidbXml(weights,
295         DatabasesXmlTags.ELT_RAIDb_1_WeightedRoundRobin);
296   }
297
298 }
299
Popular Tags