KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > loadbalancer > raidb1 > RAIDb1_RR


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.raidb1;
24
25 import java.sql.SQLException JavaDoc;
26 import java.util.ArrayList JavaDoc;
27
28 import org.continuent.sequoia.common.exceptions.NoMoreBackendException;
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 import org.continuent.sequoia.controller.backend.DatabaseBackend;
33 import org.continuent.sequoia.controller.backend.result.ControllerResultSet;
34 import org.continuent.sequoia.controller.backend.result.ExecuteResult;
35 import org.continuent.sequoia.controller.cache.metadata.MetadataCache;
36 import org.continuent.sequoia.controller.loadbalancer.policies.WaitForCompletionPolicy;
37 import org.continuent.sequoia.controller.requests.AbstractRequest;
38 import org.continuent.sequoia.controller.requests.SelectRequest;
39 import org.continuent.sequoia.controller.requests.StoredProcedure;
40 import org.continuent.sequoia.controller.virtualdatabase.VirtualDatabase;
41
42 /**
43  * RAIDb-1 Round Robin load balancer
44  * <p>
45  * The read requests coming from the Request Manager are sent in a round robin
46  * to the backend nodes. Write requests are broadcasted to all backends.
47  *
48  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
49  * @author <a HREF="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
50  * @version 1.0
51  */

52 public class RAIDb1_RR extends RAIDb1
53 {
54   /*
55    * How the code is organized ? 1. Member variables 2. Constructor(s) 3.
56    * Request handling 4. Debug/Monitoring
57    */

58
59   private int index; // index in the backend vector the Round-Robin
60

61   /*
62    * Constructors
63    */

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

73   public RAIDb1_RR(VirtualDatabase vdb,
74       WaitForCompletionPolicy waitForCompletionPolicy) throws Exception JavaDoc
75   {
76     super(vdb, waitForCompletionPolicy);
77     index = -1;
78   }
79
80   /*
81    * Request Handling
82    */

83
84   /**
85    * Selects the backend using a simple round-robin algorithm and executes the
86    * read request.
87    *
88    * @see org.continuent.sequoia.controller.loadbalancer.raidb1.RAIDb1#statementExecuteQuery(SelectRequest,
89    * MetadataCache)
90    */

91   public ControllerResultSet execSingleBackendReadRequest(
92       SelectRequest request, MetadataCache metadataCache) throws SQLException JavaDoc
93   {
94     return (ControllerResultSet) executeRoundRobinRequest(request,
95         STATEMENT_EXECUTE_QUERY, "Request ", metadataCache);
96   }
97
98   /**
99    * Selects the backend using a simple round-robin algorithm and executes the
100    * read request.
101    *
102    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#readOnlyCallableStatementExecuteQuery(StoredProcedure,
103    * MetadataCache)
104    */

105   public ControllerResultSet readOnlyCallableStatementExecuteQuery(
106       StoredProcedure proc, MetadataCache metadataCache) throws SQLException JavaDoc
107   {
108     return (ControllerResultSet) executeRoundRobinRequest(proc,
109         CALLABLE_STATEMENT_EXECUTE_QUERY, "Stored procedure ", metadataCache);
110   }
111
112   /**
113    * Selects the backend using a simple round-robin algorithm. The backend that
114    * has the shortest queue of currently executing queries is chosen to execute
115    * this stored procedure.
116    *
117    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#readOnlyCallableStatementExecute(StoredProcedure,
118    * MetadataCache)
119    */

120   public ExecuteResult readOnlyCallableStatementExecute(StoredProcedure proc,
121       MetadataCache metadataCache) throws SQLException JavaDoc
122   {
123     return (ExecuteResult) executeRoundRobinRequest(proc,
124         CALLABLE_STATEMENT_EXECUTE, "Stored procedure ", metadataCache);
125   }
126
127   /**
128    * Common code to execute a SelectRequest or a StoredProcedure on a backend
129    * chosen using a round-robin algorithm.
130    *
131    * @param request a <code>SelectRequest</code> or
132    * <code>StoredProcedure</code>
133    * @param callType one of STATEMENT_EXECUTE_QUERY,
134    * CALLABLE_STATEMENT_EXECUTE_QUERY or CALLABLE_STATEMENT_EXECUTE
135    * @param errorMsgPrefix the error message prefix, usually "Request " or
136    * "Stored procedure " ... failed because ...
137    * @param metadataCache a metadataCache if any or null
138    * @return a <code>ResultSet</code>
139    * @throws SQLException if an error occurs
140    */

141   private Object JavaDoc executeRoundRobinRequest(AbstractRequest request,
142       int callType, String JavaDoc errorMsgPrefix, MetadataCache metadataCache)
143       throws SQLException JavaDoc
144   {
145     // Choose a backend
146
try
147     {
148       vdb.acquireReadLockBackendLists();
149     }
150     catch (InterruptedException JavaDoc e)
151     {
152       String JavaDoc msg = Translate.get(
153           "loadbalancer.backendlist.acquire.readlock.failed", e);
154       logger.error(msg);
155       throw new SQLException JavaDoc(msg);
156     }
157
158     // The backend that will execute the query
159
DatabaseBackend backend = null;
160
161     // Note that vdb lock is released in the finally clause of this try/catch
162
// block
163
try
164     {
165       ArrayList JavaDoc backends = vdb.getBackends();
166       int size = backends.size();
167
168       if (size == 0)
169         throw new NoMoreBackendException(Translate.get(
170             "loadbalancer.execute.no.backend.available", request.getId()));
171
172       // Take the next backend
173
int maxTries = size;
174       synchronized (this)
175       {
176         do
177         {
178           index = (index + 1) % size;
179           backend = (DatabaseBackend) backends.get(index);
180           maxTries--;
181         }
182         while ((!backend.isReadEnabled() && maxTries >= 0));
183       }
184
185       if (maxTries < 0)
186         throw new NoMoreBackendException(Translate.get(
187             "loadbalancer.execute.no.backend.enabled", request.getId()));
188     }
189     catch (RuntimeException JavaDoc e)
190     {
191       String JavaDoc msg = Translate.get("loadbalancer.execute.find.backend.failed",
192           new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
193               e.getMessage()});
194       logger.error(msg, e);
195       throw new SQLException JavaDoc(msg);
196     }
197     finally
198     {
199       vdb.releaseReadLockBackendLists();
200     }
201
202     // Execute the request on the chosen backend
203
try
204     {
205       switch (callType)
206       {
207         case STATEMENT_EXECUTE_QUERY :
208           return executeRequestOnBackend((SelectRequest) request, backend,
209               metadataCache);
210         case CALLABLE_STATEMENT_EXECUTE_QUERY :
211           return executeStoredProcedureOnBackend((StoredProcedure) request,
212               true, backend, metadataCache);
213         case CALLABLE_STATEMENT_EXECUTE :
214           return executeStoredProcedureOnBackend((StoredProcedure) request,
215               false, backend, metadataCache);
216         default :
217           throw new RuntimeException JavaDoc("Unhandled call type " + callType
218               + " in executeRoundRobin");
219       }
220     }
221     catch (UnreachableBackendException urbe)
222     {
223       // Try to execute query on different backend
224
return executeRoundRobinRequest(request, callType, errorMsgPrefix,
225           metadataCache);
226     }
227     catch (SQLException JavaDoc se)
228     {
229       String JavaDoc msg = Translate.get("loadbalancer.something.failed", new String JavaDoc[]{
230           errorMsgPrefix, String.valueOf(request.getId()), se.getMessage()});
231       if (logger.isInfoEnabled())
232         logger.info(msg);
233       throw se;
234     }
235     catch (RuntimeException JavaDoc e)
236     {
237       String JavaDoc msg = Translate.get("loadbalancer.something.failed.on",
238           new String JavaDoc[]{errorMsgPrefix,
239               request.getSqlShortForm(vdb.getSqlShortFormLength()),
240               backend.getName(), e.getMessage()});
241       logger.error(msg, e);
242       throw new SQLException JavaDoc(msg);
243     }
244   }
245
246   /*
247    * Debug/Monitoring
248    */

249
250   /**
251    * Gets information about the request load balancer.
252    *
253    * @return <code>String</code> containing information
254    */

255   public String JavaDoc getInformation()
256   {
257     // We don't lock since we don't need a top accurate value
258
int size = vdb.getBackends().size();
259
260     if (size == 0)
261       return "RAIDb-1 Round-Robin Request load balancer: !!!Warning!!! No backend nodes found\n";
262     else
263       return "RAIDb-1 Round-Robin Request load balancer (" + size
264           + " backends)\n";
265   }
266
267   /**
268    * @see org.continuent.sequoia.controller.loadbalancer.raidb1.RAIDb1#getRaidb1Xml
269    */

270   public String JavaDoc getRaidb1Xml()
271   {
272     return "<" + DatabasesXmlTags.ELT_RAIDb_1_RoundRobin + "/>";
273   }
274
275 }
Popular Tags