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

WriteRequestWithKeysTask.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): Jaco Swart.
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.i18n.Translate;
00033 import org.objectweb.cjdbc.common.log.Trace;
00034 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
00035 import org.objectweb.cjdbc.common.sql.CreateRequest;
00036 import org.objectweb.cjdbc.common.sql.schema.DatabaseSchema;
00037 import org.objectweb.cjdbc.common.sql.schema.DatabaseTable;
00038 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
00039 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
00040 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager;
00041 import org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer;
00042 import org.objectweb.cjdbc.controller.loadbalancer.BackendWorkerThread;
00043 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
00044 
00045 /**
00046  * Executes a <code>AbstractWriteRequest</code> statement and return the auto
00047  * generated keys.
00048  * 
00049  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00050  * @author <a href="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
00051  * @version 1.0
00052  */
00053 public class WriteRequestWithKeysTask extends AbstractTask
00054 {
00055   private AbstractWriteRequest request;
00056   private ControllerResultSet  result;
00057   private MetadataCache        metadataCache;
00058 
00059   /**
00060    * Creates a new <code>WriteRequestTask</code>.
00061    * 
00062    * @param nbToComplete number of threads that must succeed before returning
00063    * @param totalNb total number of threads
00064    * @param request an <code>AbstractWriteRequest</code>
00065    * @param metadataCache the metadataCache if any or null
00066    */
00067   public WriteRequestWithKeysTask(int nbToComplete, int totalNb,
00068       AbstractWriteRequest request, MetadataCache metadataCache)
00069   {
00070     super(nbToComplete, totalNb);
00071     this.request = request;
00072     this.metadataCache = metadataCache;
00073   }
00074 
00075   /**
00076    * Executes a write request with the given backend thread.
00077    * 
00078    * @param backendThread the backend thread that will execute the task
00079    * @throws SQLException if an error occurs
00080    */
00081   public void executeTask(BackendWorkerThread backendThread)
00082       throws SQLException
00083   {
00084     DatabaseBackend backend = backendThread.getBackend();
00085 
00086     if (!backend.getDriverCompliance().supportGetGeneratedKeys())
00087       throw new SQLException(Translate.get(
00088           "loadbalancer.backend.autogeneratedkeys.unsupported", backend
00089               .getName()));
00090 
00091     AbstractConnectionManager cm = backend.getConnectionManager(request
00092         .getLogin());
00093     if (cm == null)
00094     {
00095       SQLException se = new SQLException(
00096           "No Connection Manager for Virtual Login:" + request.getLogin());
00097       try
00098       {
00099         notifyFailure(backendThread, 1, se);
00100       }
00101       catch (SQLException ignore)
00102       {
00103 
00104       }
00105       throw se;
00106     }
00107 
00108     Trace logger = backendThread.getLogger();
00109     if (request.isAutoCommit())
00110     {
00111       if (backend.isDisabling())
00112       {
00113         // Backend is disabling, we do not start new transactions, just notify
00114         // the completion for the others
00115         notifyCompletion();
00116         return;
00117       }
00118 
00119       // Use a connection just for this request
00120       Connection c = null;
00121       try
00122       {
00123         c = cm.getConnection();
00124       }
00125       catch (UnreachableBackendException e1)
00126       {
00127         SQLException se = new SQLException("Backend " + backend.getName()
00128             + " is no more reachable.");
00129         try
00130         {
00131           notifyFailure(backendThread, 1, se);
00132         }
00133         catch (SQLException ignore)
00134         {
00135         }
00136         // Disable this backend (it is no more in sync) by killing the backend
00137         // thread
00138         backendThread.kill();
00139         logger.error("Disabling backend " + backend.getName()
00140             + " because it is no more reachable.");
00141         throw se;
00142       }
00143 
00144       // Sanity check
00145       if (c == null)
00146       {
00147         SQLException se = new SQLException("No more connections");
00148         try
00149         { // All backends failed, just ignore
00150           if (!notifyFailure(backendThread, (long) request.getTimeout() * 1000,
00151               se))
00152             return;
00153         }
00154         catch (SQLException ignore)
00155         {
00156         }
00157         // Disable this backend (it is no more in sync) by killing the backend
00158         // thread
00159         backendThread.kill();
00160         String msg = "Request '"
00161             + request.getSQLShortForm(backend.getSQLShortFormLength())
00162             + "' failed on backend " + backend.getName() + " but "
00163             + getSuccess() + " succeeded (" + se + ")";
00164         logger.error(msg);
00165         throw new SQLException(msg);
00166       }
00167 
00168       // Execute Query
00169       try
00170       {
00171         result = AbstractLoadBalancer.executeUpdateRequestOnBackendWithKeys(
00172             request, backend, c, metadataCache);
00173 
00174         // Update schema
00175         if (request.isCreate())
00176         { // Add the table to the schema
00177           DatabaseSchema dbs = backend.getDatabaseSchema();
00178           if (dbs != null)
00179           {
00180             DatabaseTable t = ((CreateRequest) request).getDatabaseTable();
00181             if (t != null)
00182             {
00183               dbs.addTable(t);
00184               if (logger.isDebugEnabled())
00185                 logger.debug("Added table '" + request.getTableName()
00186                     + "' to backend database schema");
00187             }
00188           }
00189         }
00190         else if (request.isDrop())
00191         { // Delete the table from the schema
00192           DatabaseSchema dbs = backend.getDatabaseSchema();
00193           if (dbs != null)
00194           {
00195             DatabaseTable t = dbs.getTable(request.getTableName());
00196             if (t != null)
00197             {
00198               dbs.removeTable(t);
00199               if (logger.isDebugEnabled())
00200                 logger.debug("Removed table '" + request.getTableName()
00201                     + "' from backend database schema");
00202             }
00203           }
00204         }
00205       }
00206       catch (Exception e)
00207       {
00208         try
00209         { // All backends failed, just ignore
00210           if (!notifyFailure(backendThread, (long) request.getTimeout() * 1000,
00211               e))
00212             return;
00213         }
00214         catch (SQLException ignore)
00215         {
00216         }
00217         // Disable this backend (it is no more in sync) by killing the backend
00218         // thread
00219         backendThread.kill();
00220         String msg = "Request '"
00221             + request.getSQLShortForm(backend.getSQLShortFormLength())
00222             + "' failed on backend " + backend.getName() + " but "
00223             + getSuccess() + " succeeded (" + e + ")";
00224         logger.error(msg);
00225         throw new SQLException(msg);
00226       }
00227       finally
00228       {
00229         cm.releaseConnection(c);
00230       }
00231     }
00232     else
00233     { // Re-use the connection used by this transaction
00234       Connection c;
00235       long tid = request.getTransactionId();
00236       Long lTid = new Long(tid);
00237 
00238       try
00239       {
00240         c = backend.getConnectionForTransactionAndLazyBeginIfNeeded(lTid, cm);
00241       }
00242       catch (UnreachableBackendException ube)
00243       {
00244         SQLException se = new SQLException("Backend " + backend.getName()
00245             + " is no more reachable.");
00246         try
00247         {
00248           notifyFailure(backendThread, 1, se);
00249         }
00250         catch (SQLException ignore)
00251         {
00252         }
00253         // Disable this backend (it is no more in sync) by killing the backend
00254         // thread
00255         backendThread.kill();
00256         logger.error("Disabling backend " + backend.getName()
00257             + " because it is no more reachable.");
00258         throw se;
00259       }
00260       catch (NoTransactionStartWhenDisablingException e)
00261       {
00262         // Backend is disabling, we do not execute queries except the one in the
00263         // transaction we already started. Just notify the completion for the
00264         // others.
00265         notifyCompletion();
00266         return;
00267       }
00268       catch (SQLException e1)
00269       {
00270         SQLException se = new SQLException(
00271             "Unable to get connection for transaction " + tid);
00272         try
00273         { // All backends failed, just ignore
00274           if (!notifyFailure(backendThread, (long) request.getTimeout() * 1000,
00275               se))
00276             return;
00277         }
00278         catch (SQLException ignore)
00279         {
00280         }
00281         // Disable this backend (it is no more in sync) by killing the
00282         // backend thread
00283         backendThread.kill();
00284         String msg = "Request '"
00285             + request.getSQLShortForm(backend.getSQLShortFormLength())
00286             + "' failed on backend " + backend.getName() + " but "
00287             + getSuccess() + " succeeded (" + se + ")";
00288         logger.error(msg);
00289         throw new SQLException(msg);
00290       }
00291 
00292       // Sanity check
00293       if (c == null)
00294       { // Bad connection
00295         SQLException se = new SQLException(
00296             "Unable to retrieve connection for transaction " + tid);
00297         try
00298         { // All backends failed, just ignore
00299           if (!notifyFailure(backendThread, (long) request.getTimeout() * 1000,
00300               se))
00301             return;
00302         }
00303         catch (SQLException ignore)
00304         {
00305         }
00306         // Disable this backend (it is no more in sync) by killing the
00307         // backend thread
00308         backendThread.kill();
00309         String msg = "Request '"
00310             + request.getSQLShortForm(backend.getSQLShortFormLength())
00311             + "' failed on backend " + backend.getName() + " but "
00312             + getSuccess() + " succeeded (" + se + ")";
00313         logger.error(msg);
00314         throw new SQLException(msg);
00315       }
00316 
00317       // Execute Query
00318       try
00319       {
00320         result = AbstractLoadBalancer.executeUpdateRequestOnBackendWithKeys(
00321             request, backend, c, metadataCache);
00322 
00323         // Update schema
00324         if (request.isCreate())
00325         { // Add the table to the schema
00326           DatabaseSchema dbs = backend.getDatabaseSchema();
00327           if (dbs != null)
00328           {
00329             DatabaseTable t = ((CreateRequest) request).getDatabaseTable();
00330             if (t != null)
00331             {
00332               dbs.addTable(t);
00333               if (logger.isDebugEnabled())
00334                 logger.debug("Added table '" + request.getTableName()
00335                     + "' to backend database schema");
00336             }
00337           }
00338         }
00339         else if (request.isDrop())
00340         { // Delete the table from the schema
00341           DatabaseSchema dbs = backend.getDatabaseSchema();
00342           if (dbs != null)
00343           {
00344             DatabaseTable t = dbs.getTable(request.getTableName());
00345             if (t != null)
00346             {
00347               dbs.removeTable(t);
00348               if (logger.isDebugEnabled())
00349                 logger.debug("Removed table '" + request.getTableName()
00350                     + "' from backend database schema");
00351             }
00352           }
00353         }
00354       }
00355       catch (Exception e)
00356       {
00357         try
00358         { // All backends failed, just ignore
00359           if (!notifyFailure(backendThread, (long) request.getTimeout() * 1000,
00360               e))
00361             return;
00362         }
00363         catch (SQLException ignore)
00364         {
00365         }
00366         // Disable this backend (it is no more in sync) by killing the backend
00367         // thread
00368         backendThread.kill();
00369         String msg = "Request '"
00370             + request.getSQLShortForm(backend.getSQLShortFormLength())
00371             + "' failed on backend " + backend.getName() + " but "
00372             + getSuccess() + " succeeded (" + e + ")";
00373         logger.error(msg);
00374         throw new SQLException(msg);
00375       }
00376     }
00377     notifySuccess();
00378   }
00379 
00380   /**
00381    * Returns the auto generated keys.
00382    * 
00383    * @return ResultSet
00384    */
00385   public ControllerResultSet getResult()
00386   {
00387     return result;
00388   }
00389 
00390   /**
00391    * @see java.lang.Object#toString()
00392    */
00393   public String toString()
00394   {
00395     if (request.isAutoCommit())
00396       return "WriteWithKeys  Autocommit Task (" + request.getSQL() + ")";
00397     else
00398       return "WriteWithKeys Task from transaction:"
00399           + request.getTransactionId() + "(" + request.getSQL() + ")";
00400   }
00401 
00402 }

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