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

JDBCLoggerThread.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2005 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.recoverylog;
00026 
00027 import java.sql.PreparedStatement;
00028 import java.sql.SQLException;
00029 import java.util.ArrayList;
00030 
00031 import org.objectweb.cjdbc.common.i18n.Translate;
00032 import org.objectweb.cjdbc.common.log.Trace;
00033 
00034 /**
00035  * Logger thread for the JDBCRecoveryLog.
00036  * 
00037  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00038  * @version 1.0
00039  */
00040 public class JDBCLoggerThread extends Thread
00041 {
00042   private boolean           killed = false; // Control thread death
00043   private ArrayList         logQueue;
00044   private PreparedStatement pstmt;
00045   private Trace             logger;
00046 
00047   private class LogObject
00048   {
00049     private long    tid;
00050     private String  query;
00051     private String  login;
00052     private long    id;
00053     private boolean escapeProcessing;
00054 
00055     /**
00056      * Create a log object.
00057      * 
00058      * @param id unique request id
00059      * @param login login used for this request
00060      * @param query query to log
00061      * @param tid transaction id of this request
00062      * @param escapeProcessing true if escape processing must be done
00063      */
00064     public LogObject(long id, String login, String query, long tid,
00065         boolean escapeProcessing)
00066     {
00067       this.id = id;
00068       this.login = login;
00069       this.query = query;
00070       this.tid = tid;
00071       this.escapeProcessing = escapeProcessing;
00072     }
00073 
00074     /**
00075      * @return the request id
00076      */
00077     public long getId()
00078     {
00079       return id;
00080     }
00081 
00082     /**
00083      * @return the login used for this request
00084      */
00085     public String getLogin()
00086     {
00087       return login;
00088     }
00089 
00090     /**
00091      * @return the request itself
00092      */
00093     public String getQuery()
00094     {
00095       return query;
00096     }
00097 
00098     /**
00099      * @return the transaction id
00100      */
00101     public long getTid()
00102     {
00103       return tid;
00104     }
00105 
00106     /**
00107      * @return true if escape processing is needed
00108      */
00109     public boolean getEscapeProcessing()
00110     {
00111       return escapeProcessing;
00112     }
00113   }
00114 
00115   /**
00116    * Create a new JDBCLoggerThread
00117    * 
00118    * @param pstmt the PreparedStatement to use to log the requests
00119    * @param logger where to log error messages
00120    */
00121   public JDBCLoggerThread(PreparedStatement pstmt, Trace logger)
00122   {
00123     super("JDBCLoggerThread");
00124     this.pstmt = pstmt;
00125     this.logger = logger;
00126     logQueue = new ArrayList();
00127   }
00128 
00129   /**
00130    * Log a query.
00131    * 
00132    * @param id unique request id
00133    * @param login login used for this request
00134    * @param query query to log
00135    * @param tid transaction id of this request
00136    * @param escapeProcessing true if escape processing must be done
00137    */
00138   public synchronized void log(long id, String login, String query, long tid,
00139       boolean escapeProcessing)
00140   {
00141     logQueue.add(new LogObject(id, login, query, tid, escapeProcessing));
00142     notify();
00143   }
00144 
00145   /**
00146    * Rollback all unfinished transactions.
00147    */
00148   public synchronized void rollbackTransactions()
00149   {
00150     if (logQueue.isEmpty())
00151     {
00152       if (logger.isDebugEnabled())
00153         logger
00154             .debug(Translate.get("recovery.jdbc.loggerthread.no.transaction"));
00155       return;
00156     }
00157     // Find all begun transactions
00158     LogObject log;
00159     for (int i = 0; i < logQueue.size(); i++)
00160     {
00161       log = (LogObject) logQueue.get(i);
00162       if (log.getQuery().equalsIgnoreCase("begin"))
00163       {
00164         // Found beginning of transaction, let's roll it back
00165         removeQueriesOfTransactionFromQueue(log.getTid());
00166       }
00167     }
00168   }
00169 
00170   /**
00171    * Remove all queries that have not been logged yet and belonging to the
00172    * specified transaction.
00173    * 
00174    * @param tid transaction id to rollback
00175    */
00176   public synchronized void removeQueriesOfTransactionFromQueue(long tid)
00177   {
00178     if (logger.isDebugEnabled())
00179       logger.debug(Translate.get("recovery.jdbc.loggerthread.removing", tid));
00180     LogObject logEntry;
00181     for (int i = 0; i < logQueue.size(); i++)
00182     {
00183       logEntry = (LogObject) logQueue.get(i);
00184       if (logEntry.getTid() == tid)
00185         logQueue.remove(i);
00186     }
00187   }
00188 
00189   /**
00190    * Tells whether there are pending logs
00191    * 
00192    * @return true if no more jobs in the log queue
00193    */
00194   public synchronized boolean getLogQueueIsEmpty()
00195   {
00196     if (logQueue.isEmpty())
00197     {
00198       // Notifies the Recovery log that the queue is empty.
00199       notify();
00200       return true;
00201     }
00202     else
00203     {
00204       return false;
00205     }
00206   }
00207 
00208   /**
00209    * Log the requests from queue until the thread is explicetly killed. The
00210    * logger used is the one of the JDBCRecoveryLog.
00211    */
00212   public void run()
00213   {
00214     LogObject params;
00215 
00216     while (!killed)
00217     {
00218       synchronized (this)
00219       {
00220         while (getLogQueueIsEmpty())
00221         {
00222           try
00223           {
00224             wait();
00225           }
00226           catch (InterruptedException e)
00227           {
00228             logger.warn(Translate.get("recovery.jdbc.loggerthread.awaken"), e);
00229           }
00230         }
00231         // Pump first log entry from the queue
00232         params = (LogObject) logQueue.remove(0);
00233         try
00234         {
00235           pstmt.setLong(1, params.getId());
00236           pstmt.setString(2, params.getLogin());
00237           pstmt.setString(3, params.getQuery());
00238           pstmt.setLong(4, params.getTid());
00239           try
00240           {
00241             pstmt.setEscapeProcessing(params.getEscapeProcessing());
00242           }
00243           catch (Exception ignore)
00244           {
00245           }
00246           pstmt.executeUpdate();
00247           if (logger.isDebugEnabled())
00248             logger.debug(Translate.get("recovery.jdbc.loggerthread.log.debug",
00249                 new String[]{String.valueOf(params.getId()), params.getLogin(),
00250                     params.getQuery(), String.valueOf(params.getTid()),
00251                     String.valueOf(params.getEscapeProcessing())}));
00252           else if (logger.isInfoEnabled())
00253             logger.info(Translate.get("recovery.jdbc.loggerthread.log.info",
00254                 params.getId()));
00255         }
00256         catch (SQLException e)
00257         {
00258           logger.error(
00259               Translate.get("recovery.jdbc.loggerthread.log.failed",
00260                   new String[]{params.getQuery(),
00261                       String.valueOf(params.getTid())}), e);
00262           // Push object back in the queue, it needs to be logged again
00263           logQueue.add(0, params);
00264         }
00265       }
00266     }
00267   }
00268 
00269 }

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