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

AbstractTask.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.ResultSet;
00028 import java.sql.SQLException;
00029 import java.util.ArrayList;
00030 
00031 import org.objectweb.cjdbc.common.exceptions.SQLExceptionFactory;
00032 import org.objectweb.cjdbc.controller.loadbalancer.BackendWorkerThread;
00033 
00034 /**
00035  * Defines an abstract task to be processed by a
00036  * <code>BackendWorkerThread</code>.
00037  * 
00038  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00039  * @author <a href="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
00040  * @version 1.0
00041  */
00042 public abstract class AbstractTask
00043 {
00044   //
00045   // How the code is organized ?
00046   // 1. Member variables
00047   // 2. Constructor(s)
00048   // 3. Task management
00049   // 4. Getter/Setter
00050   //
00051 
00052   /** Total number of threads. */
00053   private int       totalNb;
00054 
00055   /** Number of threads that must succeed before returning. */
00056   private int       nbToComplete;
00057 
00058   /** Number of thread that have started the execution of the task */
00059   private int       executionStarted;
00060   /** Number of backendThread that have succeeded */
00061   private int       success        = 0;
00062   /** Number of backendThread that have failed */
00063   private int       failed         = 0;
00064   /** List of exceptions of failed nodes */
00065   private ArrayList exceptions     = null;
00066 
00067   // Internal tid flag used by BackendWorkerThread
00068   private boolean   hasTid         = false;
00069 
00070   // ResultSet for getting back autogenerated keys in an update with keys
00071   private ResultSet generatedKeysResultSet;
00072 
00073   // True if the timeout has expired on this task
00074   private boolean   timeoutExpired = false;
00075 
00076   /*
00077    * Constructor
00078    */
00079 
00080   /**
00081    * Sets the number of threads among the total number of threads that must
00082    * successfully complete the execution of this AbstractTask before returning.
00083    * 
00084    * @param nbToComplete number of threads that must succeed before returning
00085    * @param totalNb total number of threads
00086    */
00087   public AbstractTask(int nbToComplete, int totalNb)
00088   {
00089     this.nbToComplete = nbToComplete;
00090     this.totalNb = totalNb;
00091     success = 0;
00092     failed = 0;
00093     executionStarted = 0;
00094   }
00095 
00096   /*
00097    * Task management
00098    */
00099 
00100   /**
00101    * The task code executed by the backendThread.
00102    * 
00103    * @param backendThread The backend thread executing this task
00104    * @throws SQLException if an error occurs
00105    */
00106   public void execute(BackendWorkerThread backendThread) throws SQLException
00107   {
00108     synchronized (this)
00109     {
00110       // If the task has expired and nobody has executed it yet, we ignore it
00111       // else we have to play it.
00112       // Note that the exception corresponding to the timeout is set by the
00113       // caller of setExpiredTimeout.
00114       if (timeoutExpired && (executionStarted == 0))
00115         return;
00116       this.executionStarted++;
00117     }
00118     executeTask(backendThread);
00119     // Completed executions are handled by the task internal code that calls
00120     // notifyFailure or notifySuccess.
00121   }
00122 
00123   /**
00124    * The implementation specific task code to be executed by backendThread.
00125    * 
00126    * @param backendThread The backend thread executing this task
00127    * @throws SQLException if an error occurs
00128    */
00129   public abstract void executeTask(BackendWorkerThread backendThread)
00130       throws SQLException;
00131 
00132   /**
00133    * Notifies the successful completion of this task.
00134    */
00135   public synchronized void notifySuccess()
00136 
00137   {
00138     success++;
00139 
00140     // Notify if needed
00141     if ((success == nbToComplete) || (success + failed == totalNb))
00142     {
00143       if (failed > 0)
00144         notifyAll(); // Notify all failed threads too
00145       else
00146         notify();
00147     }
00148   }
00149 
00150   /**
00151    * This is used to notify the completion of this task without success or
00152    * failure. This is usually used when the task has been discarded for example
00153    * by a backend that is currently disabling but still needs to execute the
00154    * remaining queries in open transactions.
00155    * <p>
00156    * Therefore, this only decrements by one the number of threads that needs to
00157    * complete.
00158    */
00159   public synchronized void notifyCompletion()
00160   {
00161     totalNb--;
00162     // Notify if needed
00163     if (success + failed == totalNb)
00164     {
00165       notifyAll(); // Notify all failed threads
00166     }
00167   }
00168 
00169   /**
00170    * Notifies that the specified backendThread failed to execute this task. If
00171    * all nodes failed, this method return <code>false</code> meaning that the
00172    * problem was due to the task and not to the thread. If the method returns
00173    * <code>true</code>, it can mean that this thread failed and is no more
00174    * coherent, therefore the backend associated to this thread should be
00175    * disabled.
00176    * 
00177    * @param backendThread the backend thread that has failed
00178    * @param timeout time in milliseconds to wait for other threads to signal
00179    *          success or failure
00180    * @param e the exception causing the failure
00181    * @return <code>true</code> if at least one node succeeded to execute this
00182    *         task, <code>false</code> if all threads failed
00183    * @throws SQLException if an error occured in the notification process
00184    */
00185   public synchronized boolean notifyFailure(BackendWorkerThread backendThread,
00186       long timeout, Exception e) throws SQLException
00187   {
00188     failed++;
00189 
00190     // Log the exception
00191     if (exceptions == null)
00192       exceptions = new ArrayList();
00193     if (e instanceof SQLException)
00194     {
00195       SQLException sqlEx = (SQLException) e;
00196       exceptions
00197           .add(SQLExceptionFactory.getSQLException(sqlEx,"BackendThread "
00198               + backendThread.getBackend().getName() + " failed ("
00199               + sqlEx.getMessage() + ")"));
00200     }
00201     else
00202       exceptions.add(new SQLException("BackendThread "
00203           + backendThread.getBackend().getName() + " failed (" + e + ")"));
00204 
00205     // Notify if needed
00206     if (success + failed == totalNb)
00207     {
00208       notifyAll(); // Notify all failed threads
00209     }
00210     else
00211     {
00212       try
00213       { // Wait to check if all other threads failed or not
00214         wait(timeout);
00215       }
00216       catch (InterruptedException ie)
00217       {
00218         throw new SQLException("Wait interrupted() in failed task of backend "
00219             + backendThread.getBackend().getName() + " (" + e + ")");
00220       }
00221     }
00222     return success > 0;
00223   }
00224 
00225   //
00226   // Getter/Setter
00227   //
00228 
00229   /**
00230    * Returns the exceptions lists.
00231    * 
00232    * @return an <code>ArrayList</code>
00233    */
00234   public ArrayList getExceptions()
00235   {
00236     return exceptions;
00237   }
00238 
00239   /**
00240    * Returns the number of threads that have started the execution of the task.
00241    * 
00242    * @return Returns the number of started executions.
00243    */
00244   public synchronized int getExecutionStarted()
00245   {
00246     return executionStarted;
00247   }
00248 
00249   /**
00250    * Returns the failed.
00251    * 
00252    * @return an <code>int</code> value
00253    */
00254   public int getFailed()
00255   {
00256     return failed;
00257   }
00258 
00259   /**
00260    * Returns the number of threads that must succeed before returning.
00261    * 
00262    * @return an <code>int</code> value
00263    */
00264   public int getNbToComplete()
00265   {
00266     return nbToComplete;
00267   }
00268 
00269   /**
00270    * Returns the success.
00271    * 
00272    * @return an <code>int</code> value
00273    */
00274   public int getSuccess()
00275   {
00276     return success;
00277   }
00278 
00279   /**
00280    * Returns the total number of threads.
00281    * 
00282    * @return an <code>int</code> value
00283    * @see #setTotalNb
00284    */
00285   public int getTotalNb()
00286   {
00287     return totalNb;
00288   }
00289 
00290   /**
00291    * Sets the total number of threads.
00292    * 
00293    * @param totalNb the total number of threads to set
00294    * @see #getTotalNb
00295    */
00296   public void setTotalNb(int totalNb)
00297   {
00298     this.totalNb = totalNb;
00299   }
00300 
00301   /**
00302    * Returns true if this task has a tid attached to it.
00303    * <p>
00304    * Used internally by BackendWorkerThread.
00305    * 
00306    * @return Returns the hasTid.
00307    */
00308   public boolean hasTid()
00309   {
00310     return hasTid;
00311   }
00312 
00313   /**
00314    * Sets the hasTid value.
00315    * <p>
00316    * Used internally by BackendWorkerThread.
00317    * 
00318    * @param hasTid The hasTid to set.
00319    */
00320   public void setHasTid(boolean hasTid)
00321   {
00322     this.hasTid = hasTid;
00323   }
00324 
00325   /**
00326    * Returns the generatedKeysResultSet value.
00327    * 
00328    * @return Returns the generatedKeysResultSet.
00329    */
00330   public ResultSet getGeneratedKeysResultSet()
00331   {
00332     return generatedKeysResultSet;
00333   }
00334 
00335   /**
00336    * Sets the generatedKeysResultSet value.
00337    * 
00338    * @param generatedKeysResultSet The generatedKeysResultSet to set.
00339    */
00340   public void setGeneratedKeysResultSet(ResultSet generatedKeysResultSet)
00341   {
00342     this.generatedKeysResultSet = generatedKeysResultSet;
00343   }
00344 
00345   /**
00346    * Set the flag to tell that the timeout has expired on this task. If no
00347    * backend has started the task execution then the task will be canceled and
00348    * the method will return true. Otherwise, all backends will execute the
00349    * request and the method will return false.
00350    * 
00351    * @return true if BackendThreads will ignore the task, false if all backends
00352    *         will execute the task.
00353    */
00354   public synchronized boolean setExpiredTimeout()
00355   {
00356     this.timeoutExpired = true;
00357     return executionStarted == 0;
00358   }
00359 
00360 }

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