KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > loadbalancer > raidb2 > RAIDb2_WRR


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

22
23 package org.continuent.sequoia.controller.loadbalancer.raidb2;
24
25 import java.sql.SQLException JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.HashMap JavaDoc;
28
29 import org.continuent.sequoia.common.exceptions.NoMoreBackendException;
30 import org.continuent.sequoia.common.exceptions.UnreachableBackendException;
31 import org.continuent.sequoia.common.i18n.Translate;
32 import org.continuent.sequoia.common.xml.DatabasesXmlTags;
33 import org.continuent.sequoia.controller.backend.DatabaseBackend;
34 import org.continuent.sequoia.controller.backend.result.ControllerResultSet;
35 import org.continuent.sequoia.controller.backend.result.ExecuteResult;
36 import org.continuent.sequoia.controller.cache.metadata.MetadataCache;
37 import org.continuent.sequoia.controller.loadbalancer.WeightedBalancer;
38 import org.continuent.sequoia.controller.loadbalancer.policies.WaitForCompletionPolicy;
39 import org.continuent.sequoia.controller.loadbalancer.policies.createtable.CreateTablePolicy;
40 import org.continuent.sequoia.controller.requests.SelectRequest;
41 import org.continuent.sequoia.controller.requests.StoredProcedure;
42 import org.continuent.sequoia.controller.virtualdatabase.VirtualDatabase;
43
44 /**
45  * RAIDb-2 Weighted Round Robin load balancer.
46  * <p>
47  * The read requests coming from the request manager are sent to the backend
48  * nodes using a weighted round robin. Write requests are broadcasted to all
49  * backends.
50  * <p>
51  * The weighted round-robin works as follows. If the backend weight is set to 0,
52  * no read requests are sent to this backend unless it is the last one available
53  * on this controller. The load balancer maintains a current weight that is
54  * increased by one each time a new read request is executed. <br>
55  * If backend1 has a weight of 5 and backend2 a weight of 10, backend1 will
56  * receive the 5 first requests and backend2 the next 10 requests. Then we
57  * restart with backend1. Be careful that large weight values will heavily load
58  * backends in turn but will probably not balance the load in an effective way.
59  *
60  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
61  * @author <a HREF="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
62  * @version 1.0
63  */

64 public class RAIDb2_WRR extends RAIDb2
65 {
66   private HashMap JavaDoc weights;
67   private int currentWeight;
68
69   /*
70    * Constructors
71    */

72
73   /**
74    * Creates a new RAIDb-2 Weighted Round Robin request load balancer.
75    *
76    * @param vdb The virtual database this load balancer belongs to.
77    * @param waitForCompletionPolicy How many backends must complete before
78    * returning the result?
79    * @param createTablePolicy The policy defining how 'create table' statements
80    * should be handled
81    * @exception Exception if an error occurs
82    */

83   public RAIDb2_WRR(VirtualDatabase vdb,
84       WaitForCompletionPolicy waitForCompletionPolicy,
85       CreateTablePolicy createTablePolicy) throws Exception JavaDoc
86   {
87     super(vdb, waitForCompletionPolicy, createTablePolicy);
88     currentWeight = -1;
89   }
90
91   /*
92    * Request Handling
93    */

94
95   /**
96    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#statementExecuteQuery(org.continuent.sequoia.controller.requests.SelectRequest,
97    * org.continuent.sequoia.controller.cache.metadata.MetadataCache)
98    */

99   public ControllerResultSet statementExecuteQuery(SelectRequest request,
100       MetadataCache metadataCache) throws SQLException JavaDoc
101   {
102     return null;
103   }
104
105   /**
106    * Chooses the node to execute the stored procedure using a round-robin
107    * algorithm. If the next node has not the needed stored procedure, we try the
108    * next one and so on until a suitable backend is found.
109    *
110    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#readOnlyCallableStatementExecuteQuery(StoredProcedure,
111    * MetadataCache)
112    */

113   public ControllerResultSet readOnlyCallableStatementExecuteQuery(
114       StoredProcedure proc, MetadataCache metadataCache) throws SQLException JavaDoc
115   {
116     return (ControllerResultSet) callStoredProcedure(proc,
117         CALLABLE_STATEMENT_EXECUTE_QUERY, metadataCache);
118   }
119
120   /**
121    * Chooses the node to execute the stored procedure using a round-robin
122    * algorithm. If the next node has not the needed stored procedure, we try the
123    * next one and so on until a suitable backend is found.
124    *
125    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#readOnlyCallableStatementExecute(org.continuent.sequoia.controller.requests.StoredProcedure,
126    * org.continuent.sequoia.controller.cache.metadata.MetadataCache)
127    */

128   public ExecuteResult readOnlyCallableStatementExecute(StoredProcedure proc,
129       MetadataCache metadataCache) throws SQLException JavaDoc
130   {
131     return (ExecuteResult) callStoredProcedure(proc,
132         CALLABLE_STATEMENT_EXECUTE, metadataCache);
133   }
134
135   /**
136    * Common code to execute a StoredProcedure using executeQuery or
137    * executeUpdate on a backend chosen using a LPRF algorithm.
138    *
139    * @param proc a <code>StoredProcedure</code>
140    * @param callType one of CALLABLE_STATEMENT_EXECUTE_QUERY or
141    * CALLABLE_STATEMENT_EXECUTE
142    * @param metadataCache the metadataCache if any or null
143    * @return a <code>ControllerResultSet</code> or an
144    * <code>ExecuteResult</code> object
145    * @throws SQLException if an error occurs
146    */

147   private Object JavaDoc callStoredProcedure(StoredProcedure proc, int callType,
148       MetadataCache metadataCache) throws SQLException JavaDoc
149   {
150     // Choose a backend
151
try
152     {
153       vdb.acquireReadLockBackendLists();
154     }
155     catch (InterruptedException JavaDoc e)
156     {
157       String JavaDoc msg = Translate.get(
158           "loadbalancer.backendlist.acquire.readlock.failed", e);
159       logger.error(msg);
160       throw new SQLException JavaDoc(msg);
161     }
162
163     DatabaseBackend backend = null;
164
165     // Note that vdb lock is released in the finally clause of this try/catch
166
// block
167
try
168     {
169       ArrayList JavaDoc backends = vdb.getBackends();
170       int size = backends.size();
171
172       if (size == 0)
173         throw new NoMoreBackendException(Translate.get(
174             "loadbalancer.execute.no.backend.available", proc.getId()));
175
176       // Choose the backend (WRR algorithm starts here)
177
int w = 0; // cumulative weight
178
for (int i = 0; i < size; i++)
179       {
180         DatabaseBackend b = (DatabaseBackend) backends.get(i);
181         if (b.isReadEnabled()
182             && b.hasStoredProcedure(proc.getProcedureKey(), proc
183                 .getNbOfParameters()))
184         {
185           if (backend == null)
186             backend = b; // Fallback if no backend found
187

188           // Add the weight of this backend
189
Integer JavaDoc weight = (Integer JavaDoc) weights.get(b.getName());
190           if (weight == null)
191             logger.error("No weight defined for backend " + b.getName());
192           else
193           {
194             int backendWeight = weight.intValue();
195             if (backendWeight == 0)
196               continue; // Weight of 0, avoid using that backend
197
else
198               w += backendWeight;
199           }
200
201           // Ok we reached the needed weight, take this backend
202
if (currentWeight <= w)
203           {
204             backend = b;
205             currentWeight++; // Next time take the next
206
break;
207           }
208         }
209       }
210
211       if (backend == null)
212         throw new NoMoreBackendException(Translate.get(
213             "loadbalancer.execute.no.backend.enabled", proc.getId()));
214
215       // We are over the total weight and we are using the
216
// first available node. Let's reset the index to 1
217
// since we used this first node (0++).
218
if (currentWeight > w)
219         currentWeight = 1;
220     }
221     catch (RuntimeException JavaDoc e)
222     {
223       String JavaDoc msg = Translate.get("loadbalancer.execute.find.backend.failed",
224           new String JavaDoc[]{proc.getSqlShortForm(vdb.getSqlShortFormLength()),
225               e.getMessage()});
226       logger.error(msg, e);
227       throw new SQLException JavaDoc(msg);
228     }
229     finally
230     {
231       vdb.releaseReadLockBackendLists();
232     }
233
234     // Execute the request on the chosen backend
235
try
236     {
237       switch (callType)
238       {
239         case CALLABLE_STATEMENT_EXECUTE_QUERY :
240           return executeStoredProcedureOnBackend(proc, true, backend,
241               metadataCache);
242         case CALLABLE_STATEMENT_EXECUTE :
243           return executeStoredProcedureOnBackend(proc, false, backend,
244               metadataCache);
245         default :
246           throw new RuntimeException JavaDoc("Unhandled call type " + callType
247               + " in executeRoundRobin");
248       }
249     }
250     catch (UnreachableBackendException urbe)
251     {
252       // Try to execute query on different backend
253
return callStoredProcedure(proc, callType, metadataCache);
254     }
255     catch (SQLException JavaDoc se)
256     {
257       String JavaDoc msg = Translate.get("loadbalancer.something.failed", new String JavaDoc[]{
258           "Stored procedure ", String.valueOf(proc.getId()), se.getMessage()});
259       if (logger.isInfoEnabled())
260         logger.info(msg);
261       throw se;
262     }
263     catch (RuntimeException JavaDoc e)
264     {
265       String JavaDoc msg = Translate.get("loadbalancer.something.failed.on",
266           new String JavaDoc[]{"Stored procedure ",
267               proc.getSqlShortForm(vdb.getSqlShortFormLength()),
268               backend.getName(), e.getMessage()});
269       logger.error(msg, e);
270       throw new SQLException JavaDoc(msg);
271     }
272   }
273
274   /*
275    * Backends management
276    */

277
278   /**
279    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#setWeight(String,
280    * int)
281    */

282   public void setWeight(String JavaDoc name, int w) throws SQLException JavaDoc
283   {
284     throw new SQLException JavaDoc("Weight is not supported with this load balancer");
285   }
286
287   /*
288    * Debug/Monitoring
289    */

290
291   /**
292    * Gets information about the request load balancer.
293    *
294    * @return <code>String</code> containing information
295    */

296   public String JavaDoc getInformation()
297   {
298     if (weights == null)
299       return "RAIDb-2 Weighted Round Robin Request load balancer: !!!Warning!!! No backend nodes found\n";
300     else
301       return "RAIDb-2 Weighted Round Robin Request load balancer balancing over "
302           + weights.size() + " nodes\n";
303   }
304
305   /**
306    * @see org.continuent.sequoia.controller.loadbalancer.raidb2.RAIDb2#getRaidb2Xml
307    */

308   public String JavaDoc getRaidb2Xml()
309   {
310     return WeightedBalancer.getRaidbXml(weights,
311         DatabasesXmlTags.ELT_RAIDb_2_WeightedRoundRobin);
312   }
313 }
Popular Tags