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

ReadStoredProcedureTask.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): ______________________.
00023  */
00024 
00025 package org.objectweb.cjdbc.controller.loadbalancer.tasks;
00026 
00027 import java.sql.Connection;
00028 import java.sql.SQLException;
00029 
00030 import org.objectweb.cjdbc.common.exceptions.NoTransactionStartWhenDisablingException;
00031 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
00032 import org.objectweb.cjdbc.common.log.Trace;
00033 import org.objectweb.cjdbc.common.sql.StoredProcedure;
00034 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
00035 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
00036 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager;
00037 import org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer;
00038 import org.objectweb.cjdbc.controller.loadbalancer.BackendWorkerThread;
00039 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
00040 
00041 /**
00042  * Executes a <code>StoredProcedure</code> call that returns a ResultSet.
00043  * 
00044  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00045  * @version 1.0
00046  */
00047 public class ReadStoredProcedureTask extends AbstractTask
00048 {
00049   private StoredProcedure     proc;
00050   private ControllerResultSet result;
00051   private MetadataCache       metadataCache;
00052 
00053   /**
00054    * Creates a new <code>ReadStoredProcedureTask</code>.
00055    * 
00056    * @param nbToComplete number of threads that must succeed before returning
00057    * @param totalNb total number of threads
00058    * @param proc the <code>StoredProcedure</code> to call
00059    * @param metadataCache the metadataCache if any or null
00060    */
00061   public ReadStoredProcedureTask(int nbToComplete, int totalNb,
00062       StoredProcedure proc, MetadataCache metadataCache)
00063   {
00064     super(nbToComplete, totalNb);
00065     this.proc = proc;
00066     this.metadataCache = metadataCache;
00067   }
00068 
00069   /**
00070    * Call a stored procedure that returns a ResultSet on the given backend
00071    * thread.
00072    * 
00073    * @param backendThread the backend thread that will execute the task
00074    * @throws SQLException if an error occurs
00075    */
00076   public void executeTask(BackendWorkerThread backendThread)
00077       throws SQLException
00078   {
00079     DatabaseBackend backend = backendThread.getBackend();
00080 
00081     AbstractConnectionManager cm = backend
00082         .getConnectionManager(proc.getLogin());
00083     if (cm == null)
00084     {
00085       SQLException se = new SQLException(
00086           "No Connection Manager for Virtual Login:" + proc.getLogin());
00087       try
00088       {
00089         notifyFailure(backendThread, 1, se);
00090       }
00091       catch (SQLException ignore)
00092       {
00093 
00094       }
00095       throw se;
00096     }
00097 
00098     Trace logger = backendThread.getLogger();
00099     if (proc.isAutoCommit())
00100     { // Use a connection just for this request
00101       Connection c = null;
00102       try
00103       {
00104         c = cm.getConnection();
00105       }
00106       catch (UnreachableBackendException e1)
00107       {
00108         SQLException se = new SQLException("Backend " + backend.getName()
00109             + " is no more reachable.");
00110         try
00111         {
00112           notifyFailure(backendThread, 1, se);
00113         }
00114         catch (SQLException ignore)
00115         {
00116         }
00117         // Disable this backend (it is no more in sync) by killing the backend
00118         // thread
00119         backendThread.kill();
00120         logger.error("Disabling backend " + backend.getName()
00121             + " because it is no more reachable.");
00122         throw se;
00123       }
00124 
00125       // Sanity check
00126       if (c == null)
00127       {
00128         SQLException se = new SQLException("No more connections");
00129         try
00130         { // All backends failed, just ignore
00131           if (!notifyFailure(backendThread, (long) proc.getTimeout() * 1000, se))
00132             return;
00133         }
00134         catch (SQLException ignore)
00135         {
00136         }
00137         // Disable this backend (it is no more in sync) by killing the backend
00138         // thread
00139         backendThread.kill();
00140         String msg = "Stored procedure '"
00141             + proc.getSQLShortForm(backend.getSQLShortFormLength())
00142             + "' failed on backend " + backend.getName() + " but "
00143             + getSuccess() + " succeeded (" + se + ")";
00144         logger.error(msg);
00145         throw new SQLException(msg);
00146       }
00147 
00148       // Execute Query
00149       try
00150       {
00151         result = AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
00152             backend, c, metadataCache);
00153       }
00154       catch (Exception e)
00155       {
00156         try
00157         { // All backends failed, just ignore
00158           if (!notifyFailure(backendThread, (long) proc.getTimeout() * 1000, e))
00159             return;
00160         }
00161         catch (SQLException ignore)
00162         {
00163         }
00164         // Disable this backend (it is no more in sync) by killing the backend
00165         // thread
00166         backendThread.kill();
00167         String msg = "Stored procedure '"
00168             + proc.getSQLShortForm(backend.getSQLShortFormLength())
00169             + "' failed on backend " + backend.getName() + " but "
00170             + getSuccess() + " succeeded (" + e + ")";
00171         logger.error(msg);
00172         throw new SQLException(msg);
00173       }
00174       finally
00175       {
00176         cm.releaseConnection(c);
00177       }
00178     }
00179     else
00180     { // Re-use the connection used by this transaction
00181       Connection c;
00182       long tid = proc.getTransactionId();
00183       Long lTid = new Long(tid);
00184 
00185       try
00186       {
00187         c = backend.getConnectionForTransactionAndLazyBeginIfNeeded(lTid, cm);
00188       }
00189       catch (UnreachableBackendException ube)
00190       {
00191         SQLException se = new SQLException("Backend " + backend.getName()
00192             + " is no more reachable.");
00193         try
00194         {
00195           notifyFailure(backendThread, 1, se);
00196         }
00197         catch (SQLException ignore)
00198         {
00199         }
00200         // Disable this backend (it is no more in sync) by killing the backend
00201         // thread
00202         backendThread.kill();
00203         logger.error("Disabling backend " + backend.getName()
00204             + " because it is no more reachable.");
00205         throw se;
00206       }
00207       catch (NoTransactionStartWhenDisablingException e)
00208       {
00209         logger
00210             .error("Disabling backend "
00211                 + backend.getName()
00212                 + " has been assigned a select request but it cannot start a new transaction for it.");
00213         notifyFailure(backendThread, (long) proc.getTimeout() * 1000, e);
00214         return;
00215       }
00216       catch (SQLException e1)
00217       {
00218         SQLException se = new SQLException(
00219             "Unable to get connection for transaction " + tid);
00220         try
00221         { // All backends failed, just ignore
00222           if (!notifyFailure(backendThread, (long) proc.getTimeout() * 1000, se))
00223             return;
00224         }
00225         catch (SQLException ignore)
00226         {
00227         }
00228         // Disable this backend (it is no more in sync) by killing the
00229         // backend thread
00230         backendThread.kill();
00231         String msg = "Request '"
00232             + proc.getSQLShortForm(backend.getSQLShortFormLength())
00233             + "' failed on backend " + backend.getName() + " but "
00234             + getSuccess() + " succeeded (" + se + ")";
00235         logger.error(msg);
00236         throw new SQLException(msg);
00237       }
00238 
00239       // Sanity check
00240       if (c == null)
00241       { // Bad connection
00242         SQLException se = new SQLException(
00243             "Unable to retrieve connection for transaction " + tid);
00244         try
00245         { // All backends failed, just ignore
00246           if (!notifyFailure(backendThread, (long) proc.getTimeout() * 1000, se))
00247             return;
00248         }
00249         catch (SQLException ignore)
00250         {
00251         }
00252         // Disable this backend (it is no more in sync) by killing the
00253         // backend thread
00254         backendThread.kill();
00255         String msg = "Request '"
00256             + proc.getSQLShortForm(backend.getSQLShortFormLength())
00257             + "' failed on backend " + backend.getName() + " but "
00258             + getSuccess() + " succeeded (" + se + ")";
00259         logger.error(msg);
00260         throw new SQLException(msg);
00261       }
00262 
00263       // Execute Query
00264       try
00265       {
00266         result = AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
00267             backend, c, metadataCache);
00268 
00269         // Warning! No way to detect if schema has been modified unless
00270         // we ask the backend again using DatabaseMetaData.getTables().
00271       }
00272       catch (Exception e)
00273       {
00274         try
00275         { // All backends failed, just ignore
00276           if (!notifyFailure(backendThread, (long) proc.getTimeout() * 1000, e))
00277             return;
00278         }
00279         catch (SQLException ignore)
00280         {
00281         }
00282         // Disable this backend (it is no more in sync) by killing the backend
00283         // thread
00284         backendThread.kill();
00285         String msg = "Stored procedure '"
00286             + proc.getSQLShortForm(backend.getSQLShortFormLength())
00287             + "' failed on backend " + backend.getName() + " but "
00288             + getSuccess() + " succeeded (" + e + ")";
00289         logger.error(msg);
00290         throw new SQLException(msg);
00291       }
00292     }
00293     notifySuccess();
00294   }
00295 
00296   /**
00297    * Returns the result.
00298    * 
00299    * @return a <code>ResultSet</code>
00300    */
00301   public ControllerResultSet getResult()
00302   {
00303     return result;
00304   }
00305 
00306   /**
00307    * @see java.lang.Object#toString()
00308    */
00309   public String toString()
00310   {
00311     return "ReadStoredProcedureTask (" + proc.getSQL() + ")";
00312   }
00313 }

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