Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

RAIDb1_RR.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Emmanuel Cecchet.
00022  * Contributor(s): Julie Marguerite.
00023  */
00024 
00025 package org.objectweb.cjdbc.controller.loadbalancer.raidb1;
00026 
00027 import java.sql.SQLException;
00028 import java.util.ArrayList;
00029 
00030 import org.objectweb.cjdbc.common.exceptions.NoMoreBackendException;
00031 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
00032 import org.objectweb.cjdbc.common.i18n.Translate;
00033 import org.objectweb.cjdbc.common.sql.AbstractRequest;
00034 import org.objectweb.cjdbc.common.sql.SelectRequest;
00035 import org.objectweb.cjdbc.common.sql.StoredProcedure;
00036 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00037 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
00038 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
00039 import org.objectweb.cjdbc.controller.loadbalancer.policies.WaitForCompletionPolicy;
00040 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
00041 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
00042 
00043 /**
00044  * RAIDb-1 Round Robin load balancer
00045  * <p>
00046  * The read requests coming from the Request Manager are sent in a round robin
00047  * to the backend nodes. Write requests are broadcasted to all backends.
00048  * 
00049  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00050  * @author <a href="mailto:Julie.Marguerite@inria.fr">Julie Marguerite </a>
00051  * @version 1.0
00052  */
00053 public class RAIDb1_RR extends RAIDb1
00054 {
00055   /*
00056    * How the code is organized ? 1. Member variables 2. Constructor(s) 3.
00057    * Request handling 4. Debug/Monitoring
00058    */
00059 
00060   private int index; // index in the backend vector the Round-Robin
00061 
00062   /*
00063    * Constructors
00064    */
00065 
00066   /**
00067    * Creates a new RAIDb-1 Round Robin request load balancer.
00068    * 
00069    * @param vdb the virtual database this load balancer belongs to.
00070    * @param waitForCompletionPolicy How many backends must complete before
00071    *          returning the result?
00072    * @throws Exception if an error occurs
00073    */
00074   public RAIDb1_RR(VirtualDatabase vdb,
00075       WaitForCompletionPolicy waitForCompletionPolicy) throws Exception
00076   {
00077     super(vdb, waitForCompletionPolicy);
00078     index = -1;
00079   }
00080 
00081   /*
00082    * Request Handling
00083    */
00084 
00085   /**
00086    * Selects the backend using a simple round-robin algorithm and executes the
00087    * read request.
00088    * 
00089    * @see org.objectweb.cjdbc.controller.loadbalancer.raidb1.RAIDb1#execReadRequest(SelectRequest,
00090    *      MetadataCache)
00091    */
00092   public ControllerResultSet execReadRequest(SelectRequest request,
00093       MetadataCache metadataCache) throws SQLException
00094   {
00095     return executeRoundRobinRequest(request, true, "Request ", metadataCache);
00096   }
00097 
00098   /**
00099    * Selects the backend using a simple round-robin algorithm and executes the
00100    * read request.
00101    * 
00102    * @see org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer#execReadOnlyReadStoredProcedure(StoredProcedure,
00103    *      MetadataCache)
00104    */
00105   public ControllerResultSet execReadOnlyReadStoredProcedure(
00106       StoredProcedure proc, MetadataCache metadataCache) throws SQLException
00107   {
00108     return executeRoundRobinRequest(proc, false, "Stored procedure ",
00109         metadataCache);
00110   }
00111 
00112   /**
00113    * Common code to execute a SelectRequest or a StoredProcedure on a backend
00114    * chosen using a round-robin algorithm.
00115    * 
00116    * @param request a <code>SelectRequest</code> or
00117    *          <code>StoredProcedure</code>
00118    * @param isSelect true if it is a <code>SelectRequest</code>, false if it
00119    *          is a <code>StoredProcedure</code>
00120    * @param errorMsgPrefix the error message prefix, usually "Request " or
00121    *          "Stored procedure " ... failed because ...
00122    * @param metadataCache a metadataCache if any or null
00123    * @return a <code>ResultSet</code>
00124    * @throws SQLException if an error occurs
00125    */
00126   private ControllerResultSet executeRoundRobinRequest(AbstractRequest request,
00127       boolean isSelect, String errorMsgPrefix, MetadataCache metadataCache)
00128       throws SQLException
00129   {
00130     // Choose a backend
00131     try
00132     {
00133       vdb.acquireReadLockBackendLists();
00134     }
00135     catch (InterruptedException e)
00136     {
00137       String msg = Translate.get(
00138           "loadbalancer.backendlist.acquire.readlock.failed", e);
00139       logger.error(msg);
00140       throw new SQLException(msg);
00141     }
00142 
00143     DatabaseBackend backend = null; // The
00144     // backend
00145     // that
00146     // will
00147     // execute
00148     // the
00149     // query
00150 
00151     // Note that vdb lock is released in the finally clause of this try/catch
00152     // block
00153     try
00154     {
00155       ArrayList backends = vdb.getBackends();
00156       int size = backends.size();
00157 
00158       if (size == 0)
00159         throw new SQLException(Translate.get(
00160             "loadbalancer.execute.no.backend.available", request.getId()));
00161 
00162       // Take the next backend
00163       int maxTries = size;
00164       synchronized (this)
00165       {
00166         do
00167         {
00168           index = (index + 1) % size;
00169           backend = (DatabaseBackend) backends.get(index);
00170           maxTries--;
00171         }
00172         while ((!backend.isReadEnabled() && maxTries >= 0));
00173       }
00174 
00175       if (maxTries < 0)
00176         throw new NoMoreBackendException(Translate.get(
00177             "loadbalancer.execute.no.backend.enabled", request.getId()));
00178     }
00179     catch (RuntimeException e)
00180     {
00181       String msg = Translate.get("loadbalancer.execute.find.backend.failed",
00182           new String[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
00183               e.getMessage()});
00184       logger.error(msg, e);
00185       throw new SQLException(msg);
00186     }
00187     finally
00188     {
00189       vdb.releaseReadLockBackendLists();
00190     }
00191 
00192     ControllerResultSet rs = null;
00193     // Execute the request on the chosen backend
00194     try
00195     {
00196       if (isSelect)
00197         rs = executeRequestOnBackend((SelectRequest) request, backend,
00198             metadataCache);
00199       else
00200         rs = executeStoredProcedureOnBackend((StoredProcedure) request,
00201             backend, metadataCache);
00202     }
00203     catch (UnreachableBackendException urbe)
00204     {
00205       // Try to execute query on different backend
00206       return executeRoundRobinRequest(request, isSelect, errorMsgPrefix,
00207           metadataCache);
00208     }
00209     catch (SQLException se)
00210     {
00211       String msg = Translate.get("loadbalancer.something.failed", new String[]{
00212           errorMsgPrefix, String.valueOf(request.getId()), se.getMessage()});
00213       if (logger.isInfoEnabled())
00214         logger.info(msg);
00215       throw se;
00216     }
00217     catch (RuntimeException e)
00218     {
00219       String msg = Translate.get("loadbalancer.something.failed.on",
00220           new String[]{errorMsgPrefix,
00221               request.getSQLShortForm(vdb.getSQLShortFormLength()),
00222               backend.getName(), e.getMessage()});
00223       logger.error(msg, e);
00224       throw new SQLException(msg);
00225     }
00226 
00227     return rs;
00228   }
00229 
00230   /*
00231    * Debug/Monitoring
00232    */
00233 
00234   /**
00235    * Gets information about the request load balancer.
00236    * 
00237    * @return <code>String</code> containing information
00238    */
00239   public String getInformation()
00240   {
00241     // We don't lock since we don't need a top accurate value
00242     int size = vdb.getBackends().size();
00243 
00244     if (size == 0)
00245       return "RAIDb-1 Round-Robin Request load balancer: !!!Warning!!! No backend nodes found\n";
00246     else
00247       return "RAIDb-1 Round-Robin Request load balancer (" + size
00248           + " backends)\n";
00249   }
00250 
00251   /**
00252    * @see org.objectweb.cjdbc.controller.loadbalancer.raidb1.RAIDb1#getRaidb1Xml
00253    */
00254   public String getRaidb1Xml()
00255   {
00256     return "<" + DatabasesXmlTags.ELT_RAIDb_1_RoundRobin + "/>";
00257   }
00258 
00259 }

Generated on Mon Apr 11 22:01:33 2005 for C-JDBC by  doxygen 1.3.9.1