KickJava   Java API By Example, From Geeks To Geeks.

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


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

23
24 package org.continuent.sequoia.controller.loadbalancer.raidb1;
25
26 import java.sql.SQLException JavaDoc;
27 import java.util.ArrayList 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.policies.WaitForCompletionPolicy;
38 import org.continuent.sequoia.controller.requests.AbstractRequest;
39 import org.continuent.sequoia.controller.requests.SelectRequest;
40 import org.continuent.sequoia.controller.requests.StoredProcedure;
41 import org.continuent.sequoia.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.continuent.sequoia.controller.loadbalancer.raidb1.RAIDb1#statementExecuteQuery(SelectRequest,
91    * MetadataCache)
92    */

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

108   public ControllerResultSet readOnlyCallableStatementExecuteQuery(
109       StoredProcedure proc, MetadataCache metadataCache) throws SQLException JavaDoc
110   {
111     return (ControllerResultSet) executeLPRF(proc,
112         CALLABLE_STATEMENT_EXECUTE_QUERY, "Stored procedure ", metadataCache);
113   }
114
115   /**
116    * Selects the backend using a least pending request first policy. The backend
117    * that has the shortest queue of currently executing queries is chosen to
118    * execute this stored procedure.
119    *
120    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#readOnlyCallableStatementExecute(StoredProcedure,
121    * MetadataCache)
122    */

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

145   private Object JavaDoc executeLPRF(AbstractRequest request, int callType,
146       String JavaDoc errorMsgPrefix, MetadataCache metadataCache) throws SQLException JavaDoc
147   {
148     // Choose a backend
149
try
150     {
151       vdb.acquireReadLockBackendLists();
152     }
153     catch (InterruptedException JavaDoc e)
154     {
155       String JavaDoc msg = Translate.get(
156           "loadbalancer.backendlist.acquire.readlock.failed", e);
157       logger.error(msg);
158       throw new SQLException JavaDoc(msg);
159     }
160
161     /*
162      * The backend that will execute the query
163      */

164     DatabaseBackend backend = null;
165
166     // Note that vdb lock is released in the finally clause of this try/catch
167
// block
168
try
169     {
170       ArrayList JavaDoc backends = vdb.getBackends();
171       int size = backends.size();
172
173       // Choose the backend that has the least pending requests
174
int leastRequests = 0;
175       for (int i = 0; i < size; i++)
176       {
177         DatabaseBackend b = (DatabaseBackend) backends.get(i);
178         if (b.isReadEnabled())
179         {
180           int pending = b.getPendingRequests().size();
181           if ((backend == null) || (pending < leastRequests))
182           {
183             backend = b;
184             if (pending == 0)
185               break; // Stop here we will never find a less loaded node
186
else
187               leastRequests = pending;
188           }
189         }
190       }
191
192     }
193     catch (Throwable JavaDoc e)
194     {
195       String JavaDoc msg = Translate.get("loadbalancer.execute.find.backend.failed",
196           new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
197               e.getMessage()});
198       logger.error(msg, e);
199       throw new SQLException JavaDoc(msg);
200     }
201     finally
202     {
203       vdb.releaseReadLockBackendLists();
204     }
205
206     if (backend == null)
207       throw new NoMoreBackendException(Translate.get(
208           "loadbalancer.execute.no.backend.enabled", request.getId()));
209
210     // Execute the request on the chosen backend
211
try
212     {
213       switch (callType)
214       {
215         case STATEMENT_EXECUTE_QUERY :
216           return executeRequestOnBackend((SelectRequest) request, backend,
217               metadataCache);
218         case CALLABLE_STATEMENT_EXECUTE_QUERY :
219           return executeStoredProcedureOnBackend((StoredProcedure) request,
220               true, backend, metadataCache);
221         case CALLABLE_STATEMENT_EXECUTE :
222           return executeStoredProcedureOnBackend((StoredProcedure) request,
223               false, backend, metadataCache);
224         default :
225           throw new RuntimeException JavaDoc("Unhandled call type " + callType
226               + " in executeLPRF");
227       }
228     }
229     catch (UnreachableBackendException urbe)
230     {
231       // Try to execute query on different backend
232
return executeLPRF(request, callType, errorMsgPrefix, metadataCache);
233     }
234     catch (SQLException JavaDoc se)
235     {
236       String JavaDoc msg = Translate.get("loadbalancer.something.failed", new String JavaDoc[]{
237           errorMsgPrefix, String.valueOf(request.getId()), se.getMessage()});
238       if (logger.isInfoEnabled())
239         logger.info(msg);
240       throw se;
241     }
242     catch (RuntimeException JavaDoc e)
243     {
244       String JavaDoc msg = Translate.get("loadbalancer.something.failed.on",
245           new String JavaDoc[]{errorMsgPrefix,
246               request.getSqlShortForm(vdb.getSqlShortFormLength()),
247               backend.getName(), e.getMessage()});
248       logger.error(msg, e);
249       throw new SQLException JavaDoc(msg);
250     }
251   }
252
253   /*
254    * Debug/Monitoring
255    */

256
257   /**
258    * Gets information about the request load balancer.
259    *
260    * @return <code>String</code> containing information
261    */

262   public String JavaDoc getInformation()
263   {
264     // We don't lock since we don't need a top accurate value
265
int size = vdb.getBackends().size();
266
267     if (size == 0)
268       return "RAIDb-1 Least Pending Request First load balancer: !!!Warning!!! No backend nodes found\n";
269     else
270       return "RAIDb-1 Least Pending Request First load balancer (" + size
271           + " backends)\n";
272   }
273
274   /**
275    * @see org.continuent.sequoia.controller.loadbalancer.raidb1.RAIDb1#getRaidb1Xml
276    */

277   public String JavaDoc getRaidb1Xml()
278   {
279     return "<" + DatabasesXmlTags.ELT_RAIDb_1_LeastPendingRequestsFirst + "/>";
280   }
281
282 }
283
Popular Tags