alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (CoordinatorLog.java)

This example Glassfish source code file (CoordinatorLog.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

coordinatorlog, coordinatorlogsection, coordinatorlogsection, coordinatorlogstateholder, coordinatorlogstateholder, corba, enumeration, enumeration, hashtable, io, ioexception, log, logging, loglsn, long, string, string, util, vector

The Glassfish CoordinatorLog.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

//----------------------------------------------------------------------------
//
// Module:      CoordinatorLog.java
//
// Description: Coordinator state logging.
//
// Product:     com.sun.jts.CosTransactions
//
// Author:      Simon Holdsworth
//
// Date:        March, 1997
//
// Copyright (c):   1995-1997 IBM Corp.
//
//   The source code for this program is not published or otherwise divested
//   of its trade secrets, irrespective of what has been deposited with the
//   U.S. Copyright Office.
//
//   This software contains confidential and proprietary information of
//   IBM Corp.
//----------------------------------------------------------------------------

package com.sun.jts.CosTransactions;

// Import required classes.

import java.util.*;
import java.io.*;

import org.omg.CORBA.*;

import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;
import com.sun.jts.utils.LogFormatter;

/**The CoordinatorLog interface provides operations to record transaction-
 * specific information that needs to be persistently stored at a particular
 * point in time, and subsequently restored.
 * <p>
 * The CoordinatorLog contains an attribute value which is the local transaction
 * identifier associated with the transaction operating on the log. The
 * CoordinatorLog maintains the LSN of the last log record written for the
 * transaction, and a flag indicating whether rewrite is required for a
 * keypoint.
 * <p>
 * As an instance of this class may be accessed from multiple threads within
 * a process, serialisation for thread-safety and locking during keypoint is
 * necessary.
 *
 * @version 0.01
 *
 * @author Simon Holdsworth, IBM Corporation
 *
 * @see
*/
//----------------------------------------------------------------------------
// CHANGE HISTORY
//
// Version By     Change Description
//   0.01  SAJH   Initial implementation.
//------------------------------------------------------------------------------

class CoordinatorLog extends java.lang.Object implements LogUpcallTarget {
    private static final int LOG_DEF_KEY_TRIGGER = 100;
    private static final int LOG_THRESHOLD = 10000;
    private static final int STRING_TO_REF_RETRIES = 20;
    private static final String defaultstring = "DEFAULT_LOG";

    /**
    // Since muliple logs have to coexist as part of delegated recovery 
    // support, static data can not be maintained. Now this data is stored
    // per log location
    private static LogFile logFile        = null;
    private static Log log                = null;
    private static Hashtable activeLogs   = new Hashtable();
    private static Hashtable keypointLogs = new Hashtable();
    private static int tranCount          = 0;
    private static int keypointTrigger    = 100;
    private static boolean keypointInProgress = false;
    private static java.lang.Object keypointLock = new java.lang.Object();
    private static java.lang.Object keypointStateLock = new java.lang.Object();
   **/
    private static int keypointTrigger    = 100;
    private static Hashtable logStateHoldertable = new Hashtable();
    private static final java.lang.Object NULL_ENTRY = new java.lang.Object();

    private Hashtable sectionMapping = null;
    private boolean rewriteRequired  = false;
    private boolean writeDone = false;

    private String logPath = null;

	/*
		Logger to log transaction messages
	*/
	static Logger _logger = LogDomains.getLogger(CoordinatorLog.class, LogDomains.TRANSACTION_LOGGER);
    
	/**The local transaction identifier for the transaction this object is logging.
     */
    Long localTID = null;
    CoordinatorLogStateHolder logStateHolder = null;
    private static CoordinatorLogStateHolder defaultLogStateHolder = getStateHolder(defaultstring);

    // Static variables to handle byte array formatting.

    private ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(2000);
    private DataOutputStream      dataOutput = new DataOutputStream(byteOutput);

   
    // All the methods which take "String logPath" as parameter are same as the
    // ones with out that parameter. These methods are added for delegated
    // recovery support
    /**
     * Get the state for the given log location.
     * If the state does not exists, creates the state and retuns, otherwise existing
     * state is returned.
     *
     * @param str  log location.
     *
     * @return  state for the given log location.
     *
     * @see
     */
    static private CoordinatorLogStateHolder getStateHolder(String str) {
        synchronized (logStateHoldertable) {
            CoordinatorLogStateHolder logStateHolder = (CoordinatorLogStateHolder)logStateHoldertable.get(str);
            if (logStateHolder == null) {
                logStateHolder =  new CoordinatorLogStateHolder();
                 logStateHolder.logFile        = null;
                 logStateHolder.log            = null;
                 logStateHolder.activeLogs   = new Hashtable();
                 logStateHolder.keypointLogs = new Hashtable();
                 logStateHolder.tranCount          = 0;
                 logStateHolder.keypointInProgress = false;
                 // logStateHolder.keypointLock = new java.lang.Object();
                 logStateHolder.keypointLock = new RWLock();
                 logStateHolder.keypointStateLock = new java.lang.Object();
                 logStateHoldertable.put(str,logStateHolder);
            }
            return logStateHolder;
        }
    }

    /**Default CoordinatorLog constructor.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    CoordinatorLog() {

        sectionMapping = new Hashtable();
        logStateHolder = defaultLogStateHolder;
        

        // Do not inform the metaclass about the existence of this object yet, as it
        // does not have a transaction identifier.

    }

    CoordinatorLog(String logPath) {

        sectionMapping = new Hashtable();
        logStateHolder = getStateHolder(logPath);
        this.logPath = logPath;
        

        // Do not inform the metaclass about the existence of this object yet, as it
        // does not have a transaction identifier.

    }

    /**Default CoordinatorLog destructor.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    synchronized public void doFinalize() {

        // Clear up the section mapping.

        if( sectionMapping != null ) {
            Enumeration sections = sectionMapping.elements();
	    // the traditional way of iterating through the enumeration
	    // using sections.hasMoreElements was showing up as a
	    // hot spot during performance tests.	Arun 9/27/99
	    int sz = sectionMapping.size();
	    while (sz-- > 0) {
                CoordinatorLogSection section = (CoordinatorLogSection)sections.nextElement();
                section.reUse();
            }
            sectionMapping.clear();
            sectionMapping = null;
        }
    }

    /**
     * reUse method is called explicitly to clean up
     * and return this instance to the pool
     *
     * Note: the implementation of the cache does not ensure
     *       that when an object is re-used there are no
     *	     outstanding references to that object. However, the
     *	     risk involved is minimal since reUse() replaces the
     *	     existing call to finalize(). The existing call to
     *	     finalize also does not ensure that there are no
     *	     outstanding references to the object being finalized.
     *
     *
     * @param
     *
     * @return
     *
     * @see
     */
    synchronized private void reUse() {			// Arun 9/27/99

        // Clear up the section mapping.

        if( sectionMapping != null ) {
            Enumeration sections = sectionMapping.elements();
	    int sz = sectionMapping.size();
	    while (sz-- > 0) {
                CoordinatorLogSection section = (CoordinatorLogSection)sections.nextElement();
                section.reUse();
            }
            sectionMapping.clear();
        }
        rewriteRequired  = false;
        writeDone = false;
        localTID = null;

        byteOutput.reset();

	// cache the coordinator log in the coordinator log pool
	CoordinatorLogPool.putCoordinatorLog(this);

    }

    synchronized private void reUse(String logPath) {	

        // Clear up the section mapping.

        if( sectionMapping != null ) {
            Enumeration sections = sectionMapping.elements();
	    int sz = sectionMapping.size();
	    while (sz-- > 0) {
                CoordinatorLogSection section = (CoordinatorLogSection)sections.nextElement();
                section.reUse();
            }
            sectionMapping.clear();
        }
        rewriteRequired  = false;
        writeDone = false;
        localTID = null;

        byteOutput.reset();

	// cache the coordinator log in the coordinator log pool
	CoordinatorLogPool.putCoordinatorLog(this, logPath);

    }

    /**Creates and initialises a new CoordinatorLog object, with the given local
     * transaction identifier.
     * <p>
     * If the local transaction identifier is non-NULL,
     * the CoordinatorLog adds itself to the static list of instances.
     *
     * @param localTID  The local transaction identifier.
     *
     * @return
     *
     * @see
     */
    CoordinatorLog( Long localTID ) {

        // Set up the local transaction identifier; if it is not NULL, inform the
        // metaclass of the object's existence.

        this.localTID = localTID;
        if( localTID.longValue() != 0 )
            addLog(localTID,this);

    }

    /**
     * Creates a subsection in the CoordinatorLog in which to store related
     * objects and data.
     * <p>
     * The object that is returned is used to identify the section on subsequent
     * calls.
     * <p>
     * If the section has already been created, the object for the existing
     * section is returned.
     *
     * @param sectionName  The name of the section.
     *
     * @return  An object representing the section.
     *
     * @see
     */
    synchronized java.lang.Object createSection( String sectionName ) {

        CoordinatorLogSection result = null;

        // Check whether the given name already has a corresponding section.

        result = (CoordinatorLogSection) sectionMapping.get(sectionName);
        if (result == null) {
            int nameLength = sectionName.length();

            // Create a new section.
            // If a section info structure cannot be allocated, return.
            // Note that the section name is added to the end of the section
            // info structure to reduce the number of SOMMalloc calls.

	    // get a new section object from the cache Arun 9/27/99
            result = SectionPool.getCoordinatorLogSection(sectionName);
            if( result == null ) {
            }

            // Copy in the name and set initial values of the other variables.

            else {

                // Add the new section information to the map.

                sectionMapping.put(sectionName,result);
            }
        }

        return result;
    }

    /**Adds the given object to the sequence of those in the given section.
     * <p>
     * The objects are stored in the order that they are added to the sequence.
     * No checking is done for duplicates.
     *
     * @param sectionObj  The object representing the section.
     * @param obj         The object to be added.
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */

    synchronized boolean addObject( java.lang.Object sectionObj,
                                    org.omg.CORBA.Object obj ) {

        boolean result = true;

        // Determine if section is valid

        if( sectionObj != null ) {
            CoordinatorLogSection section = (CoordinatorLogSection)sectionObj;

            // Add header length to unwritten data length if section has currently has no
            // unwritten information.

            section.unwrittenEmpty = false;		// Arun 9/27/99

            if( section.unwrittenObjects == null )
                section.unwrittenObjects = new Vector(10,10);

            // Convert the object reference to string value

            String objRefStr = null;
            try {
                objRefStr = Configuration.getORB().object_to_string(obj);

                // Add object reference to section and update counts

                section.unwrittenObjects.addElement(objRefStr);

                //$Write logrecord if threshold is exceeded
                //$
                //$     if( unwrittenLength >= LOG_THRESHOLD )
                //$       try
                //$         { formatLogRecords(false); }
                //$       catch( IOException exc )
                //$         {
                //$         if( trc != null ) trc.error(ERR_WRITE).data(exc).write();
                //$         result = false;
                //$         }
            } catch( Throwable exc ) {
                result = false;
            }
        } else {
            result = false;
        }

        return result;
    }

    /**Adds the given opaque data structure to the sequence of those in the
     * given section.
     * <p>
     * The data structures are stored in the order that they are added to the
     * sequence. No checking is done for duplicates.
     *
     * @param sectionObj  The object representing the section.
     * @param data        The data to be added.
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */

    synchronized boolean addData( java.lang.Object sectionObj,
                                  byte[] data ) {

        boolean result = true;
        byte[] dataCopy;

        // Determine if section is valid

        if( sectionObj != null ) {
            CoordinatorLogSection section = (CoordinatorLogSection)sectionObj;

            // Add header length to unwritten data length if section has currently has no
            // unwritten information.

            section.unwrittenEmpty = false;		// Arun 9/27/99

            if( section.unwrittenData == null )
                section.unwrittenData = new Vector(4,4);

            // Make a copy of the data to add to the unwritten data queue.

            dataCopy = new byte[data.length];
            System.arraycopy(data,0,dataCopy,0,data.length);

            // Add data item (sequence of octets) to section and update counts

            section.unwrittenData.addElement(dataCopy);

            //$Write logrecord if threshold is exceeded

            //$   if( unwrittenLength >= LOG_THRESHOLD )
            //$     try
            //$       { formatLogRecords(false); }
            //$     catch( IOException exc )
            //$       {
            //$       if( trc != null ) trc.error(ERR_WRITE).data(exc).write();
            //$       result = false;
            //$       }
        } else {
            result = false;
        }

        return result;
    }

    /**Write the contents of the CoordinatorLog to persistent storage.
     * <p>
     * If the force parameter is set, this requires that all information defined
     * to the CoordinatorLog that has not already been written be recorded before
     * the operation returns.
     * <p>
     * If rewrite is required, all information whether previously written or not
     * is recorded.
     * <p>
     * The log record should include the LSN of the previous record
     * written for the same transaction, if any, otherwise it is NULL. Further
     * information may be added to the CoordinatorLog after it has been forced,
     * and will be separately written in a subsequent log record, whose LSN will
     * point to the current one.
     * <p>
     * This operation discharges the CoordinatorLog's requirement to rewrite. The
     * keypoint lock must be obtained from the metaclass before checking whether
     * a rewrite is required, and released after the write is complete.
     *
     * @param force  Indicates whether the log data should be forced before this
     *               method returns.
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */
    boolean write( boolean force ) {

        // Format the log records with a forced write.

        boolean result = true;
        try {
            result = formatLogRecords(force);
        } catch( IOException exc ) {
            result = false;
        }

        return result;
    }

    /**Informs the CoordinatorLog object that it must rewrite its entire state
     * the next time it writes a log record.
     * <p>
     * If the CoordinatorLog has state that has previously been written, it records
     * the requirement to rewrite, otherwise it does not record the requirement.
     *
     * @param
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */
    private synchronized boolean requireRewrite() {
        boolean result = true;

        // Record the fact that a rewrite is required if a write has been done.

        if( writeDone )
            rewriteRequired = true;

        return result;
    }

    /**Rewrites the contents of the CoordinatorLog to persistent storage.
     * <p>
     * This requires that all information defined to the CoordinatorLog that has
     * already been written be re-written (unforced) to the log.
     * <p>
     * The CoordinatorLog also writes any unwritten state at this point.
     * <p>
     * The log record will contain a NULL LSN to indicate that no previous records
     * for this transaction should be used for recovery. If no state has previously
     * been written, the CoordinatorLog does nothing at this point and waits for
     * a subsequent force operation.
     * <p>
     * This operation discharges the CoordinatorLog's requirement to rewrite.
     *
     * @param
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */

    private boolean rewrite() {

        boolean result = true;

        // If a rewrite is required, format a log record with all the CoordinatorLog
        // data, with a non-forced write.

        if( rewriteRequired )
            try {
                result = formatLogRecords(false);
            } catch( IOException exc ) {
                result = false;
            }

        return result;
    }

    /**
     * Requests that the object reconstructs its state from the given stream.
     * <p>
     * There may be more than one if the CoordinatorLog elects to write to the
     * log before it is asked to force the transaction state.
     * <p>
     * This operation is invoked when there are log records that need to
     * be recovered. The CoordinatorLog should reconstruct the sequences of
     * objects and data from each of the sections so that they can be queried by
     * the callers that set them up.
     *
     * @param data  The data to be used to create the CoordinatorLog object.
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */
    private boolean reconstruct( DataInputStream dataInput )
        throws IOException {

        boolean result = true;

        // Read in the number of sections.

        int numSections = dataInput.readUnsignedShort();


        // Reconstruct each of the sections in the log record

        while( --numSections >= 0 ) {

            // Get the section name, number of objects and number of data items from the
            // log record passed in.

            int length = dataInput.readUnsignedShort();

            // If the section name length is zero, then it contains no data, so skip it.

            if( length > 0 ) {

                int numObjects = dataInput.readUnsignedShort();
                int numData = dataInput.readUnsignedShort();

                // Make a copy of the section name.

                byte[] stringData = new byte[length];
                dataInput.read(stringData);
                String sectionName = new String(stringData);

                // Create a section in the CoordinatorLog

                CoordinatorLogSection section = (CoordinatorLogSection) createSection(sectionName);

                // Add each object reference from the log record to the section.

                // BUGFIX(Ram J) added (writtenObject == null) check, so that
                // the previously collected objects are not discarded.
                if (numObjects > 0 && section.writtenObjects == null) {
                    section.writtenObjects = new Vector(numObjects, 10);
                }

                for( int i = 0; i < numObjects; i++ ) {

                    // Get the size of the object reference and allocate a buffer to make a copy
                    // of it.

                    length = dataInput.readUnsignedShort();
                    stringData = new byte[length];
                    dataInput.read(stringData);
                    String objRefStr = new String(stringData);

                    // Add the object reference to the list of written objects.

                    section.writtenObjects.addElement(objRefStr);
                }

                // Add each data item from the log record to the section.

                // BUGFIX(Ram J) added (writtenData == null) check, so that
                // the previously collected data are not discarded.
                if (numData > 0 && section.writtenData == null) {
                    section.writtenData = new Vector(numData, 4);
                }

                for( int i = 0; i < numData; i++ ) {

                    // Get the size of the data item and allocate a buffer to make a copy of it.

                    length = dataInput.readUnsignedShort();
                    byte[] dataItem = new byte[length];

                    // Copy the data item into the storage allocated, and add that to the list
                    // of written data items.

                    dataInput.read(dataItem);
                    section.writtenData.addElement(dataItem);
                }
            }
        }

        return result;
    }

    /**Returns a sequence containing all of the objects in the given section.
     *
     * @param sectionObj  The object representing the section.
     *
     * @return  The objects.
     *
     * @see
     */
    java.lang.Object[] getObjects( java.lang.Object sectionObj ) {
        java.lang.Object[] result = null;

        // Check that the section identifier is valid.
        // Browse through the Queue of stringified object references, converting each
        // to an actual object reference and adding it to the sequence returned from
        // this method.

        if( sectionObj != null ) {

            CoordinatorLogSection section = (CoordinatorLogSection)sectionObj;

            int unwrittenSize = 0;
            if( section.unwrittenObjects != null )
                unwrittenSize = section.unwrittenObjects.size();

            int writtenSize = 0;
            if( section.writtenObjects != null )
                writtenSize = section.writtenObjects.size();

            result = new java.lang.Object[unwrittenSize + writtenSize];
            int currObject = 0;

            // Obtain the reference of the ORB.

            ORB orb = Configuration.getORB();

            // Go through the written objects.

            for( int i = 0; i < writtenSize; i++ ) {

                org.omg.CORBA.Object obj = null;
                String refStr = (String)section.writtenObjects.elementAt(i);

                // Try ten times to convert the reference to a string.

                int retries = STRING_TO_REF_RETRIES;
                boolean discard = false;
                while( obj == null && retries-- > 0 && !discard ) {
                    try {
                        obj = orb.string_to_object(refStr);
                    } catch( MARSHAL exc ) {
                        // The MARSHAL exception indicates that the ImplHelper for the object has not been
                        // started, so try again after two seconds.

                        try {
                            Thread.sleep(2000);
                        } catch( InterruptedException ex2 ) {
							_logger.log(Level.WARNING,
									"jts.wait_for_resync_complete_interrupted");
							String msg = LogFormatter.getLocalizedMessage(_logger,
						    			"jts.wait_for_resync_complete_interrupted");
							throw  new org.omg.CORBA.INTERNAL(msg);
                        }
                    } catch( Throwable exc ) {
                        // Any other exception indicates that the reference is invalid, so just discard it.

                        discard = true;
                    }
                }

                // Add the valid object to the list.

                if( !discard ){
                    if( obj != null ){
                        result[currObject++] = obj;
					}
					else {
						_logger.log(Level.SEVERE,
						"jts.unable_to_convert_object_reference_to_string_in_recovery");
						 
						  String msg = LogFormatter.getLocalizedMessage(_logger,
			  			"jts.unable_to_convert_object_reference_to_string_in_recovery");
						
						throw  new org.omg.CORBA.INTERNAL(msg);
					}
				}
            }

            // Now get the unwritten objects.  We do not need to do all the above error
            // checking as these objects have not been recovered from the log.

            for( int i = 0; i < unwrittenSize; i++ ) {
                try {

                    // Add the valid object to the list.

                    org.omg.CORBA.Object obj = orb.string_to_object((String)section.unwrittenObjects.elementAt(i));
                    result[currObject++] = obj;
                } catch( Throwable exc ) {
                    // If the object resulting from the string is invalid, then don't add it to
                    // the list.
                }
            }
        }

        return result;
    }

    /**Returns a sequence containing all of the opaque data in the given section.
     *
     * @param sectionObj  The object representing the section.
     *
     * @return  The data.
     *
     * @see
     */

    byte[][] getData( java.lang.Object sectionObj ) {

        byte[][] result = null;

        // Check that the section identifier is valid.
        // Browse through the Queues of data items, adding each to the sequence
        // returned from this method.

        if( sectionObj != null ) {
            CoordinatorLogSection section = (CoordinatorLogSection)sectionObj;

            int unwrittenSize = 0;
            if( section.unwrittenData != null )
                unwrittenSize = section.unwrittenData.size();

            int writtenSize = 0;
            if( section.writtenData != null )
                writtenSize = section.writtenData.size();

            result = new byte[unwrittenSize+writtenSize][];

            if( unwrittenSize > 0 )
                section.unwrittenData.copyInto(result);

            for( int i = 0; i < writtenSize; i++ )
                result[unwrittenSize++] = (byte[])section.writtenData.elementAt(i);
        }

        return result;
    }


    /**Sets the local identifier for the CoordinatorLog object.
     * <p>
     * If the local identifier was previously 0, the CoordinatorLog object is
     * added to the static list.
     *
     * @param localTID  The new local identifier.
     *
     * @return
     *
     * @see
     */
    synchronized void setLocalTID( Long localTID ) {

        // Check whether the local identifier is currently NULL.

        boolean addToMetaclass = (localTID.longValue() != 0 && (this.localTID == null || this.localTID.longValue() == 0));

        // Set the local identifier, and add the object to the metaclass if required.

        this.localTID = localTID;
        if( addToMetaclass )
            addLog(localTID,this);

    }

    synchronized void setLocalTID( Long localTID, String logPath ) {

        // Check whether the local identifier is currently NULL.

        boolean addToMetaclass = (localTID.longValue() != 0 && (this.localTID == null || this.localTID.longValue() == 0));

        // Set the local identifier, and add the object to the metaclass if required.

        this.localTID = localTID;
        if( addToMetaclass )
            addLog(localTID,this, logPath);

    }

    /**Formats the information in a single section of the Coordinatorlog into a
     * stream.
     * <p>
     * This internal method does not need to be synchronized.
     * If the rewrite flag is not set, only information that has not already been
     * written is formatted, otherwise all information is formatted.
     *
     * @param section     The section.
     * @param rewrite     Indicates if the record is being rewritten.
     * @param dataOutput  The stream to which to data is output.
     *
     * @return
     *
     * @exception IOException  The format failed.
     *
     * @see
     */
    private void formatSection( CoordinatorLogSection section,
                                boolean               rewrite,
                                DataOutputStream      dataOutput )
        throws IOException {
        // No formatting is done if the section is empty, and if rewrite is required,
        // the written section is also empty.
        // Note that we still need to write something out to satisfy the number of
        // sections originally written, so we write out a name length of zero.

        if( section.unwrittenEmpty &&
            (!rewrite || section.writtenEmpty) ) {
            dataOutput.writeShort(0);
            return;
        }

        // Place length of section name into buffer.

        dataOutput.writeShort(section.sectionName.length());

        // Place count of number of object references into buffer, including written
        // object references if rewrite is required.

        int unwrittenObjectsSize = 0;
        int writtenObjectsSize = 0;
        if( section.unwrittenObjects != null )
            unwrittenObjectsSize = section.unwrittenObjects.size();
        if( rewrite &&
            section.writtenObjects != null )
            writtenObjectsSize = section.writtenObjects.size();

        dataOutput.writeShort(unwrittenObjectsSize + writtenObjectsSize);

        // Place count of number of data items into buffer, including written data
        // items if rewrite is required.

        int unwrittenDataSize = 0;
        int writtenDataSize = 0;
        if( section.unwrittenData != null )
            unwrittenDataSize = section.unwrittenData.size();
        if( rewrite &&
            section.writtenData != null )
            writtenDataSize = section.writtenData.size();

        dataOutput.writeShort(unwrittenDataSize + writtenDataSize);

        // Copy the section name into the buffer.

        dataOutput.writeBytes(section.sectionName);

        // If rewrite is required, first write the already-written object references

        for( int i = 0; i < writtenObjectsSize; i++ ) {
            String objRefStr = (String)section.writtenObjects.elementAt(i);
            dataOutput.writeShort(objRefStr.length());
            dataOutput.writeBytes(objRefStr);
        }

        // Next place length of each stringified object reference and the stringified
        // object reference into the buffer. Move each from unwritten to written queue

        for( int i = 0; i < unwrittenObjectsSize; i++ ) {
            String objRefStr = (String)section.unwrittenObjects.elementAt(i);
            dataOutput.writeShort(objRefStr.length());
            dataOutput.writeBytes(objRefStr);

            if( section.writtenObjects == null )
                section.writtenObjects = new Vector(unwrittenObjectsSize,10);

            section.writtenObjects.addElement(objRefStr);
        }

        if( unwrittenObjectsSize > 0 )
            section.unwrittenObjects.removeAllElements();

        // Now we process the data items.
        // If rewrite is required, first write the already-written data items.

        for( int i = 0; i < writtenDataSize; i++ ) {
            byte[] dataItem = (byte[])section.writtenData.elementAt(i);
            dataOutput.writeShort(dataItem.length);
            dataOutput.write(dataItem);
        }

        // Next place length of each stringified object reference and the stringified
        // object reference into the buffer. Move each from unwritten to written queue

        for( int i = 0; i < unwrittenDataSize; i++ ) {
            byte[] dataItem = (byte[])section.unwrittenData.elementAt(i);
            dataOutput.writeShort(dataItem.length);
            dataOutput.write(dataItem);

            if( section.writtenData == null )
                section.writtenData = new Vector(unwrittenDataSize,4);

            section.writtenData.addElement(dataItem);
        }
        if( unwrittenDataSize > 0 )
            section.unwrittenData.removeAllElements();

        // Set unwritten_empty to TRUE and written_empty to FALSE since everything    //
        // has moved from the unwritten to the written queues.                        //

        section.unwrittenEmpty = true;
        section.writtenEmpty = false;

    }

    /**Formats the information in all sections of the CoordinatorLog.
     * <p>
     * The formatted information is written to the log.
     * <p>
     * This internal method does not need to be synchronized.
     * If the rewrite flag is not set, only information that has not already been
     * written is formatted, otherwise all information is formatted.
     *
     * @param forced  Forced/unforced write indicator.
     *
     * @return  Indicates success of the operation.
     *
     * @exception IOException  The format failed.
     *
     * @see
     */
    private boolean formatLogRecords( boolean forced )
	throws IOException {

        // If there is no LogFile for this transaction, and one cannot be obtained
        // from the metaclass, then no formatting can be done.

        if (logPath == null)
            openLog();
        else
            openLog(logPath);
        if( logStateHolder.logFile == null ) {
            return false;
        }

        // In order to check whether rewrite is required, we must first obtain the
        // keypoint lock to ensure that the metaclass is not in the process of
        // informing us that a rewrite is required.
        //$We must not wait for the keypoint lock while holding our own lock so
        //$release it now.

        boolean result = false;
        try {
            logStateHolder.keypointLock.acquireReadLock();
            // Once we have the keypoint lock, it is OK to obtain our own.

            synchronized( this ) {

                // Place the tid in the buffer.

                byteOutput.reset();
                dataOutput.writeLong(localTID.longValue());

                // Write out the number of sections.

                dataOutput.writeShort(sectionMapping.size());

                // Format log section within map and add the information to buffer. Browse
                // through the CoordinatorLog filling in the buffer for each entry.

                Enumeration sections = sectionMapping.elements();
		int sz = sectionMapping.size();		// Arun 9/27/99
		while (sz-- > 0) {			// Arun 9/27/99
                    formatSection((CoordinatorLogSection)sections.nextElement(),
						rewriteRequired,dataOutput);
		}

                // Write the buffer to the LogFile.

                result = logStateHolder.logFile.write( forced ? LogFile.FORCED : LogFile.UNFORCED,
                                        byteOutput.toByteArray(),
                                        rewriteRequired ? LogFile.REWRITE : LogFile.NORMAL,
                                        null );

                rewriteRequired = false;
                writeDone = true;
            }
        } finally {
            logStateHolder.keypointLock.releaseReadLock();
        }

        return result;
    }

    /**Provides static initialisation of the CoordinatorLog class.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    static {

        // Get the value of the keypoint trigger from the environment.

        String keypointCountEnv = Configuration.getPropertyValue(Configuration.KEYPOINT_COUNT);
        keypointTrigger = LOG_DEF_KEY_TRIGGER;
        if( keypointCountEnv != null )
            try {
                keypointTrigger = Integer.parseInt(keypointCountEnv);
            } catch( Throwable e ) {}

    }

    /**Opens the log file for all CoordinatorLogs in this process.
     * <p>
     * If the log has already been opened, the operation uses the opened LogFile.
     *
     * @param
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */
    private static boolean openLog() {
        boolean result = false;
        String logName;
        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        // If the log has been opened, there is nothing to do.

        if( logStateHolder.log == null ) {
            logStateHolder.log = new Log();
            if( !logStateHolder.log.initialise() ) {
                logStateHolder.log = null;
				_logger.log(Level.SEVERE,"jts.cannot_initialise_log");
				String msg = LogFormatter.getLocalizedMessage(_logger,
							"jts.cannot_initialise_log");
				throw  new org.omg.CORBA.INTERNAL(msg);
            }
        }


        // Open the Log and set the logfile object reference.  If there is no
        // ImplementationDef object available, then we cannot determine the log file


        // name, so the log cannot be opened.
        // Note that this does not preclude the log file being opened at some later
        // time.

        String serverName = null;
        if( logStateHolder.log != null &&
            logStateHolder.logFile == null &&
            (serverName = Configuration.getServerName()) != null ) {

	    // get a coordinator log object from cache instead
	    // of instantiating a new one		Arun 9/27/99
            logStateHolder.logFile = logStateHolder.log.open(serverName,
			       CoordinatorLogPool.getCoordinatorLog());

            if( logStateHolder.logFile == null ) {
				_logger.log(Level.SEVERE,"jts.cannot_open_log_file",serverName);
				 String msg = LogFormatter.getLocalizedMessage(_logger,
				 						"jts.cannot_open_log_file");
				 throw  new org.omg.CORBA.INTERNAL(msg);
            } else 
                Configuration.setLogFile(logStateHolder.logFile);
        }

        result = (logStateHolder.log != null && logStateHolder.logFile != null);

        return result;
    }

    /**Opens the log file for all CoordinatorLogs in this process.
     * <p>
     * If the log has already been opened, the operation uses the opened LogFile.
     *
     * @param
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */
    private static boolean openLog(String logPath) {
        boolean result = false;
        String logName;
        CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);

        // If the log has been opened, there is nothing to do.

        if( logStateHolder.log == null ) {
            logStateHolder.log = new Log(logPath);
            if( !logStateHolder.log.initialise() ) {
                logStateHolder.log = null;
				_logger.log(Level.SEVERE,"jts.cannot_initialise_log");
				String msg = LogFormatter.getLocalizedMessage(_logger,
							"jts.cannot_initialise_log");
				throw  new org.omg.CORBA.INTERNAL(msg);
            }
        }


        // Open the Log and set the logfile object reference.  If there is no
        // ImplementationDef object available, then we cannot determine the log file


        // name, so the log cannot be opened.
        // Note that this does not preclude the log file being opened at some later
        // time.

        String serverName = null;
        // Always reopen logFile for a delegated recovery: do not check for logStateHolder.logFile == null
        if( logStateHolder.log != null &&
            (serverName = Configuration.getServerName(logPath)) != null ) {

	    // get a coordinator log object from cache instead
	    // of instantiating a new one		Arun 9/27/99
            logStateHolder.logFile = logStateHolder.log.open(serverName,
			       CoordinatorLogPool.getCoordinatorLog(logPath));

            if( logStateHolder.logFile == null ) {
				_logger.log(Level.SEVERE,"jts.cannot_open_log_file",serverName);
				 String msg = LogFormatter.getLocalizedMessage(_logger,
				 						"jts.cannot_open_log_file");
				 throw  new org.omg.CORBA.INTERNAL(msg);
            } else 
                Configuration.setLogFile(logPath,logStateHolder.logFile);
        }

        result = (logStateHolder.log != null && logStateHolder.logFile != null);

        return result;
    }

    /**Process the log to build a sequence of CoordinatorLog objects which
     * represent all logged transactions.
     *
     * @param
     *
     * @return  The CoordinatorLog objects, or null if there are none.
     *
     * @see
     */
    synchronized static Enumeration getLogged() {

        Vector logRecords = null;
        Enumeration coordLogs = null;

        // Initialise the Log.  If the log cannot be opened, return an empty
        // sequence, with whatever exception the open returned.

        if( openLog() ) {
             CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

            // Get the log records returned from the log and browse through them.  Take
            // Take the sequence of log records returned from the LogFile and convert
            // them into the sequence of CoordinatorLog objects that are returned from
            // this method.

            logRecords = logStateHolder.logFile.getLogRecords();
            for( int i = 0; i < logRecords.size(); i++ ) {

                // Get tid value from the log record. Get the CoordinatorLog reference if
                // it exists in map, else create a new CoordinatorLog object; it will
                // added to the map when we set the transaction id.

                byte[] buffer = (byte[])logRecords.elementAt(i);
                ByteArrayInputStream byteInput = new ByteArrayInputStream(buffer);
                DataInputStream dataInput = new DataInputStream(byteInput);

                try {
                    Long localTID = new Long(dataInput.readLong());
                    CoordinatorLog coordLog = (CoordinatorLog)logStateHolder.activeLogs.get(localTID);
                    if( coordLog == null ) {

	                // get a coordinator log object from cache instead
	                // of instantiating a new one		Arun 9/27/99
                        coordLog = CoordinatorLogPool.getCoordinatorLog();

                        coordLog.setLocalTID(localTID);
                    }

                    // Reconstruct the CoordinatorLog information from the log record.

                    coordLog.reconstruct(dataInput);
                } catch( IOException exc ) {
                }
            }

            // Return a copy of the list of active CoordinatorLog objects.

            coordLogs = logStateHolder.activeLogs.elements();
        }

        // If the log could not be opened, return an empty Enumeration.

        else
            coordLogs = new Hashtable().elements();


        return coordLogs;
    }

    /**Process the log to build a sequence of CoordinatorLog objects which
     * represent all logged transactions.
     *
     * @param
     *
     * @return  The CoordinatorLog objects, or null if there are none.
     *
     * @see
     */
    synchronized static Enumeration getLogged(String logPath) {

        Vector logRecords = null;
        Enumeration coordLogs = null;

        // Initialise the Log.  If the log cannot be opened, return an empty
        // sequence, with whatever exception the open returned.

        if( openLog(logPath) ) {
             CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);

            // Get the log records returned from the log and browse through them.  Take
            // Take the sequence of log records returned from the LogFile and convert
            // them into the sequence of CoordinatorLog objects that are returned from
            // this method.

            logRecords = logStateHolder.logFile.getLogRecords();
            for( int i = 0; i < logRecords.size(); i++ ) {

                // Get tid value from the log record. Get the CoordinatorLog reference if
                // it exists in map, else create a new CoordinatorLog object; it will
                // added to the map when we set the transaction id.

                byte[] buffer = (byte[])logRecords.elementAt(i);
                ByteArrayInputStream byteInput = new ByteArrayInputStream(buffer);
                DataInputStream dataInput = new DataInputStream(byteInput);

                try {
                    Long localTID = new Long(dataInput.readLong());
                    CoordinatorLog coordLog = (CoordinatorLog)logStateHolder.activeLogs.get(localTID);
                    if( coordLog == null ) {

	                // get a coordinator log object from cache instead
	                // of instantiating a new one		Arun 9/27/99
                        coordLog = CoordinatorLogPool.getCoordinatorLog(logPath);

                        coordLog.setLocalTID(localTID, logPath);
                    }

                    // Reconstruct the CoordinatorLog information from the log record.

                    coordLog.reconstruct(dataInput);
                } catch( IOException exc ) {
                }
            }

            // Return a copy of the list of active CoordinatorLog objects.

            coordLogs = logStateHolder.activeLogs.elements();
        }

        // If the log could not be opened, return an empty Enumeration.

        else
            coordLogs = new Hashtable().elements();


        return coordLogs;
    }


    /**Remembers the mapping between the local transaction identifier and the
     * CoordinatorLog object.
     *
     * @param localTID  The local transaction identifier.
     * @param clog      The CoordinatorLog object.
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */
    private static boolean addLog(Long localTID,
                                               CoordinatorLog clog ) {
       CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        boolean result = true;

        logStateHolder.activeLogs.put(localTID,clog);

        return result;
    }

    private static boolean addLog(Long localTID,
                                               CoordinatorLog clog, String logPath ) {
       CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);

        boolean result = true;

        logStateHolder.activeLogs.put(localTID,clog);

        return result;
    }

    /**Removes the CoordinatorLog object from the map, and destroys it.
     *
     * @param localTID  The local transaction identifier.
     *
     * @return  Indicates success of the operation.
     *
     * @see
     */
    synchronized static boolean removeLog( Long localTID ) {

        boolean result = true;
        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        // Remove the given CoordinatorLog and local identifier from the map.
        // If the CoordinatorLog could be removed, we need to check whether a
        // keypoint is in progress, and if so, prevent the CoordinatorLog from being
        // called during the keypoint.

        CoordinatorLog clog = (CoordinatorLog)logStateHolder.activeLogs.remove(localTID);
        if( clog != null ) {

            // Obtaining the keypoint state lock prevents us from doing this while the
            // keypoint method is using the map.

            synchronized( logStateHolder.keypointStateLock ) {
                // If a keypoint is in progress, look up the entry for the transaction in the
                // map and replace the value with a NULL entry.

                if( logStateHolder.keypointInProgress && logStateHolder.keypointLogs != null )
                    logStateHolder.keypointLogs.put(localTID,NULL_ENTRY);
            }

            // If the transaction is read-only, then do not increment the transaction count.

            if( clog.writeDone )
                logStateHolder.tranCount++;

            // return the CoordinatorLog object to the pool to be reused.
	    //					Arun 9/27/99
            clog.reUse();


            // Check whether a keypoint is required.  This is based solely on the number
            // of (non-readonly) transactions since the last keypoint.

            if( logStateHolder.tranCount >= keypointTrigger ) {
                logStateHolder.tranCount = 0;
                keypoint();
            }
        }


        return result;
    }

    synchronized static boolean removeLog( Long localTID , String logPath) {

        boolean result = true;
        CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);

        // Remove the given CoordinatorLog and local identifier from the map.
        // If the CoordinatorLog could be removed, we need to check whether a
        // keypoint is in progress, and if so, prevent the CoordinatorLog from being
        // called during the keypoint.

        CoordinatorLog clog = (CoordinatorLog)logStateHolder.activeLogs.remove(localTID);
        if( clog != null ) {

            // Obtaining the keypoint state lock prevents us from doing this while the
            // keypoint method is using the map.

            synchronized( logStateHolder.keypointStateLock ) {
                // If a keypoint is in progress, look up the entry for the transaction in the
                // map and replace the value with a NULL entry.

                if( logStateHolder.keypointInProgress && logStateHolder.keypointLogs != null )
                    logStateHolder.keypointLogs.put(localTID,NULL_ENTRY);
            }

            // If the transaction is read-only, then do not increment the transaction count.

            if( clog.writeDone )
                logStateHolder.tranCount++;

            // return the CoordinatorLog object to the pool to be reused.
	    //					Arun 9/27/99
            clog.reUse(logPath);


            // Check whether a keypoint is required.  This is based solely on the number
            // of (non-readonly) transactions since the last keypoint.

            if( logStateHolder.tranCount >= keypointTrigger ) {
                logStateHolder.tranCount = 0;
                keypoint(logPath);
            }
        }


        return result;
     }

    /**Performs a keypoint operation to allow old information in the log to be
     * discarded.
     * <p>
     * This operation is not synchronized as we do not want the latter part of the
     * operation to block other logging operations.  The start of the keypoint is
     * in a separate method which is synchronized.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    static void keypoint() {
        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        byte[] keypointEndRecord = {
            (byte) 'K',
            (byte) 'E',
            (byte) 'Y',
            (byte) 'E',
            (byte) 'N',
            (byte) 'D'};

        LogLSN previousLSN = new LogLSN();
        LogLSN keypointStartLSN = new LogLSN();
        boolean keypointRequired = false;

        // Obtain the global keypoint lock to prevent any activity until the keypoint
        // start has been recorded.
        // Once the keypoint start has been completed, we can release the
        // keypoint lock.  This will allow waiting CoordinatorLog writes to complete.

        try {
            logStateHolder.keypointLock.acquireWriteLock();
            keypointRequired = startKeypoint(keypointStartLSN);
        } finally {
            logStateHolder.keypointLock.releaseWriteLock();
        }

        // If no keypoint start record was written, then just return.

        if( keypointStartLSN.isNULL() ) {
            return;
        }

        // Once all of the CoordinatorLog objects have been unlocked, we must make
        // sure each of them has been rewritten before the keypoint end record is
        // written.  Note that it is possible that one or more of the CoordinatorLog
        // objects in this list has already been deleted.  We must be careful
        // to make sure that we do not invoke a method on a deleted object.

        if( keypointRequired ) {
            Enumeration keypointLocalTIDs = logStateHolder.keypointLogs.keys();
            while( keypointLocalTIDs.hasMoreElements() )

                // Obtain the keypoint state lock before obtaining the value from the map, as the
                // remove operation might be changing the value to NULL.  Note that the
                // remove operation only changes the value of an entry in this map, it does
                // not change the number of entries in the map, so we do not need to hold the
                // mutex for the browse.

                synchronized( logStateHolder.keypointStateLock ) {
                    CoordinatorLog currentLog = (CoordinatorLog)logStateHolder.keypointLogs.get(keypointLocalTIDs.nextElement());

                    // Get the value out of the map, and if not NULL entry, tell it to rewrite itself.

                    if( currentLog != NULL_ENTRY )
                        currentLog.rewrite();
                }
        }

        // Now we know all CoordinatorLog objects have either independently rewritten
        // themselves, or we have done it explicitly.  A keypoint end record is
        // written to indicate that the keypoint is complete.

        logStateHolder.logFile.write(LogFile.UNFORCED,
                      keypointEndRecord,
                      LogFile.KEYPOINT_END,
                      previousLSN);

        // All that is left to do is to inform the LogFile that the records before
        // the keypoint start record are no longer required.
        // Checkpoint the log.  This allows the log to discard previous entries that
        // are no longer required.

        logStateHolder.logFile.checkpoint(keypointStartLSN);

        // Clear the keypoint in progress flag, empty the map of CoordinatorLog
        // objects being keypointed, release muteces and return.

        logStateHolder.keypointInProgress = false;
        logStateHolder.keypointLogs.clear();

    }
    static void keypoint(String logPath) {
        CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);

        byte[] keypointEndRecord = {
            (byte) 'K',
            (byte) 'E',
            (byte) 'Y',
            (byte) 'E',
            (byte) 'N',
            (byte) 'D'};

        LogLSN previousLSN = new LogLSN();
        LogLSN keypointStartLSN = new LogLSN();
        boolean keypointRequired = false;

        // Obtain the global keypoint lock to prevent any activity until the keypoint
        // start has been recorded.
        // Once the keypoint start has been completed, we can release the
        // keypoint lock.  This will allow waiting CoordinatorLog writes to complete.

        try {
            logStateHolder.keypointLock.acquireWriteLock();
            keypointRequired = startKeypoint(keypointStartLSN, logPath);
        } finally {
           logStateHolder.keypointLock.releaseWriteLock();
        }

        // If no keypoint start record was written, then just return.

        if( keypointStartLSN.isNULL() ) {
            return;
        }

        // Once all of the CoordinatorLog objects have been unlocked, we must make
        // sure each of them has been rewritten before the keypoint end record is
        // written.  Note that it is possible that one or more of the CoordinatorLog
        // objects in this list has already been deleted.  We must be careful
        // to make sure that we do not invoke a method on a deleted object.

        if( keypointRequired ) {
            Enumeration keypointLocalTIDs = logStateHolder.keypointLogs.keys();
            while( keypointLocalTIDs.hasMoreElements() )

                // Obtain the keypoint state lock before obtaining the value from the map, as the
                // remove operation might be changing the value to NULL.  Note that the
                // remove operation only changes the value of an entry in this map, it does
                // not change the number of entries in the map, so we do not need to hold the
                // mutex for the browse.

                synchronized( logStateHolder.keypointStateLock ) {
                    CoordinatorLog currentLog = (CoordinatorLog)logStateHolder.keypointLogs.get(keypointLocalTIDs.nextElement());

                    // Get the value out of the map, and if not NULL entry, tell it to rewrite itself.

                    if( currentLog != NULL_ENTRY )
                        currentLog.rewrite();
                }
        }

        // Now we know all CoordinatorLog objects have either independently rewritten
        // themselves, or we have done it explicitly.  A keypoint end record is
        // written to indicate that the keypoint is complete.

        logStateHolder.logFile.write(LogFile.UNFORCED,
                      keypointEndRecord,
                      LogFile.KEYPOINT_END,
                      previousLSN);

        // All that is left to do is to inform the LogFile that the records before
        // the keypoint start record are no longer required.
        // Checkpoint the log.  This allows the log to discard previous entries that
        // are no longer required.

        logStateHolder.logFile.checkpoint(keypointStartLSN);

        // Clear the keypoint in progress flag, empty the map of CoordinatorLog
        // objects being keypointed, release muteces and return.

        logStateHolder.keypointInProgress = false;
        logStateHolder.keypointLogs.clear();

    }

    /**Handles a short-on-storage situation in the log by taking a keypoint.

    /**Handles a short-on-storage situation in the log by taking a keypoint.
     *
     * @param reason  The reason for the upcall.
     *
     * @return
     *
     * @see
     */

    public void upcall( int reason ){

        // Just perform a keypoint.
       if (logPath == null)
           CoordinatorLog.keypoint();
       else
           CoordinatorLog.keypoint(logPath);

    }

    /**Destroys the state of the CoordinatorLog class.
     *
     * @param
     *
     * @return
     *
     * @see
     */

    synchronized static void finalizeAll(){
       CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        boolean deleteFile = false;

        // Obtain the keypoint state lock for this operation.

        synchronized( logStateHolder.keypointStateLock ) {

            // Close the LogFile.

            if( logStateHolder.activeLogs != null ) {

                // If there are no active log records sete delete_file to TRUE so that
                // LogFile_close will cause the logfile to be deleted

                if( logStateHolder.activeLogs.size() == 0 )
                    deleteFile = true;
                logStateHolder.activeLogs.clear();
                logStateHolder.activeLogs = null;
            }

            if( logStateHolder.logFile != null ) logStateHolder.logFile.close(deleteFile);
            logStateHolder.logFile = null;

            // Discard the CoordinatorLog mappings.

            if( logStateHolder.keypointLogs != null )
                logStateHolder.keypointLogs.clear();
            logStateHolder.keypointLogs = null;
        }

        // Discard the locks.

        logStateHolder.keypointStateLock = null;
        logStateHolder.keypointLock = null;

    }

    synchronized static void finalizeAll(String logPath){
       CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);

        boolean deleteFile = false;

        // Obtain the keypoint state lock for this operation.

        synchronized( logStateHolder.keypointStateLock ) {

            // Close the LogFile.

            if( logStateHolder.activeLogs != null ) {

                // If there are no active log records sete delete_file to TRUE so that
                // LogFile_close will cause the logfile to be deleted

                if( logStateHolder.activeLogs.size() == 0 )
                    deleteFile = true;
                logStateHolder.activeLogs.clear();
                logStateHolder.activeLogs = null;
            }

            if( logStateHolder.logFile != null ) logStateHolder.logFile.close(deleteFile);
            logStateHolder.logFile = null;

            // Discard the CoordinatorLog mappings.

            if( logStateHolder.keypointLogs != null )
                logStateHolder.keypointLogs.clear();
            logStateHolder.keypointLogs = null;
        }

        // Discard the locks.

        logStateHolder.keypointStateLock = null;
        logStateHolder.keypointLock = null;

    }

    /**Starts a keypoint.
     *
     * @param keypointStartLSN  The LSN to hold the keypoint start LSN.
     *
     * @return  Indicates whether keypoint is required.
     *
     * @see
     */

    synchronized static boolean startKeypoint( LogLSN keypointStartLSN ) {
        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        boolean keypointRequired = false;

        // If a keypoint is in progress, return and do nothing.

        if( logStateHolder.keypointInProgress ) {
            return false;
        }
        logStateHolder.keypointInProgress = true;

        // Initialise the Log.  If this fails, then return whatever exception the
        // open raised.

        if( !openLog() ) {
            logStateHolder.keypointInProgress = false;
            return false;
        }

        // If there are no known CoordinatorLog objects, then all that the keypoint
        // operation does is checkpoint the log at the head.

        if( logStateHolder.activeLogs.size() == 0 )
            keypointRequired = false;

        // Else go round all currently known CoordinatorLog objects and build a list
        // of them.  New CoordinatorLog objects that are created during this time
        // will be suspended when they try to do an CoordinatorLog.addLog operation as
        // this thread has the lock.

        else {

            // Go through all current CoordinatorLog objects, telling them that they
            // must rewrite their state if necessary.
            // Each CoordinatorLog that exists at this time is copied to a separate list.

            Enumeration clogs = logStateHolder.activeLogs.elements();
            while( clogs.hasMoreElements() ) {
                CoordinatorLog currentLog = (CoordinatorLog)clogs.nextElement();
                Long localTID = currentLog.localTID;

                currentLog.requireRewrite();
                logStateHolder.keypointLogs.put(localTID,currentLog);
            }
            keypointRequired = logStateHolder.keypointLogs.size() > 0;
        }

        // Write a keypoint start record now that we know no logging activity is
        // taking place.

        byte[] keypointStartRecord = {(byte) 'K',
                                      (byte) 'E',
                                      (byte) 'Y',
                                      (byte) 'S',
                                      (byte) 'T',
                                      (byte) 'A',
                                      (byte) 'R',
                                      (byte) 'T'};
        logStateHolder.logFile.write(LogFile.UNFORCED,
                      keypointStartRecord,
                      LogFile.KEYPOINT_START,
                      keypointStartLSN);

        return keypointRequired;
    }

    synchronized static boolean startKeypoint( LogLSN keypointStartLSN, String logPath ) {
        CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);

        boolean keypointRequired = false;

        // If a keypoint is in progress, return and do nothing.

        if( logStateHolder.keypointInProgress ) {
            return false;
        }
        logStateHolder.keypointInProgress = true;

        // Initialise the Log.  If this fails, then return whatever exception the
        // open raised.

        if( !openLog(logPath) ) {
            logStateHolder.keypointInProgress = false;
            return false;
        }

        // If there are no known CoordinatorLog objects, then all that the keypoint
        // operation does is checkpoint the log at the head.

        if( logStateHolder.activeLogs.size() == 0 )
            keypointRequired = false;

        // Else go round all currently known CoordinatorLog objects and build a list
        // of them.  New CoordinatorLog objects that are created during this time
        // will be suspended when they try to do an CoordinatorLog.addLog operation as
        // this thread has the lock.

        else {

            // Go through all current CoordinatorLog objects, telling them that they
            // must rewrite their state if necessary.
            // Each CoordinatorLog that exists at this time is copied to a separate list.

            Enumeration clogs = logStateHolder.activeLogs.elements();
            while( clogs.hasMoreElements() ) {
                CoordinatorLog currentLog = (CoordinatorLog)clogs.nextElement();
                Long localTID = currentLog.localTID;

                currentLog.requireRewrite();
                logStateHolder.keypointLogs.put(localTID,currentLog);
            }
            keypointRequired = logStateHolder.keypointLogs.size() > 0;
        }

        // Write a keypoint start record now that we know no logging activity is
        // taking place.

        byte[] keypointStartRecord = {(byte) 'K',
                                      (byte) 'E',
                                      (byte) 'Y',
                                      (byte) 'S',
                                      (byte) 'T',
                                      (byte) 'A',
                                      (byte) 'R',
                                      (byte) 'T'};
        logStateHolder.logFile.write(LogFile.UNFORCED,
                      keypointStartRecord,
                      LogFile.KEYPOINT_START,
                      keypointStartLSN);

        return keypointRequired;
    }

    /**Dumps the state of the class.
     *
     * @param
     *
     * @return
     *
     * @see
     */

    static void dumpClass() {
        // Dump the contained objects.
        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        logStateHolder.log.dump();
        logStateHolder.logFile.dump();
    }

    /**Dumps the state of the object.
     *
     * @param
     *
     * @return
     *
     * @see
     */

    void dump() {
        // NOT USED: CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        //$ somtrDUMP_OBJECT_HEADER;

        // First dump the local transaction id.

        // Dump each section in the CoordinatorLog object.

        if( sectionMapping != null ) {
            //$   somtrDUMP_LIST_START;

            Enumeration sections = sectionMapping.elements();
            while( sections.hasMoreElements() ) {
                CoordinatorLogSection section = (CoordinatorLogSection)sections.nextElement();

                // Dump the section name.

                //$     somtrDUMP_LIST_ELEMENT;

                // Dump Written objects.

                if( section.writtenObjects != null ) {
                    //$       somtrDUMP_LIST_START;

                    Enumeration objects = section.writtenObjects.elements();
                    while( objects.hasMoreElements() ) {
                        String objStr = (String)objects.nextElement();

                        //$         somtrDUMP_LIST_ELEMENT;
                    }

                    //$       somtrDUMP_LIST_END;
                }

                // Dump unwritten objects.

                if( section.unwrittenObjects != null ) {
                    //$       somtrDUMP_LIST_START;

                    Enumeration objects = section.unwrittenObjects.elements();
                    while( objects.hasMoreElements() ) {
                        String objStr = (String)objects.nextElement();

                        //$         somtrDUMP_LIST_ELEMENT;
                    }

                    //$       somtrDUMP_LIST_END;
                }

                // Dump Written data.

                if( section.writtenData != null ) {
                    //$       somtrDUMP_LIST_START;

                    Enumeration data = section.writtenData.elements();
                    while( data.hasMoreElements() ) {
                        byte[] dataItem = (byte[])data.nextElement();

                        //$         somtrDUMP_LIST_ELEMENT;
                    }

                    //$       somtrDUMP_LIST_END;
                }

                // Dump unwritten data.

                if( section.unwrittenData != null ) {
                    //$       somtrDUMP_LIST_START;

                    Enumeration data = section.unwrittenData.elements();
                    while( data.hasMoreElements() ) {
                        byte[] dataItem = (byte[])data.nextElement();

                        //$         somtrDUMP_LIST_ELEMENT;
                    }

                    //$       somtrDUMP_LIST_END;
                }


                // That is the end of the section.

            }

            //$   somtrDUMP_LIST_END;
        }
    }
    // START IASRI 4662745
    public static void setKeypointTrigger(int keypoint)
    {
        keypointTrigger = keypoint;
    }
    // END IASRI 4662745

}

/**The CoordinatorLogSection class stores information relevant to a section.
 *
 * @version 0.1
 *
 * @author Simon Holdsworth, IBM Corporation
 *
 * @see
*/
// CHANGE HISTORY
//
// Version By     Change Description
//   0.1   SAJH   Initial implementation.
//------------------------------------------------------------------------------

class CoordinatorLogSection extends java.lang.Object {
    String  sectionName      = null;
    boolean unwrittenEmpty   = true;
    boolean writtenEmpty     = true;
    Vector  unwrittenObjects = null;
    Vector  unwrittenData    = null;
    Vector  writtenObjects   = null;
    Vector  writtenData      = null;
    int     headerLength     = 0;

    /**Creates a CoordinatorLogSection with the given name.
     *
     * @param sectionName  The name of the section.
     *
     * @return
     *
     * @see
     */
    CoordinatorLogSection( String sectionName ) {
        this.sectionName = sectionName;
    }

    /**Destroys the contents of a CoordinatorLogSection.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    public void doFinalize() {
        if( unwrittenObjects != null )
            unwrittenObjects.removeAllElements();

        if( unwrittenData != null )
            unwrittenData.removeAllElements();

        if( writtenObjects != null )
            writtenObjects.removeAllElements();

        if( writtenData != null )
            writtenData.removeAllElements();

        sectionName = null;

        unwrittenObjects = null;
        unwrittenData    = null;
        writtenObjects   = null;
        writtenData      = null;
    }

    /**Cleans up the CoordinatorLogSection and
     * returns it to the pool for re-use
     *
     * Note: the implementation of the cache does not ensure
     *       that when an object is re-used there are no
     *	     outstanding references to that object. However, the
     *	     risk involved is minimal since reUse() replaces the
     *	     existing call to finalize(). The existing call to
     *	     finalize also does not ensure that there are no
     *	     outstanding references to the object being finalized.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    synchronized void reUse() {			// Arun 9/27/99

        if( unwrittenObjects != null )
            unwrittenObjects.removeAllElements();

        if( unwrittenData != null )
            unwrittenData.removeAllElements();

        if( writtenObjects != null )
            writtenObjects.removeAllElements();

        if( writtenData != null )
            writtenData.removeAllElements();

        sectionName = null;
        unwrittenEmpty   = true;
        writtenEmpty     = true;
        headerLength     = 0;

	SectionPool.putCoordinatorLogSection(this);
    }
}

/**
 * The SectionPool is used as a cache for CoordinatorLogSection objects.
 * This pool allows the re-use of these objects which are very expensive
 * to instantiate.
 *
 * The pool was added to improve performance of trnasaction logging
 *
 * @version 0.01
 *
 * @author Arun Krishnan
 *
 * @see
*/

class SectionPool {

    private Stack pool;
    private static final int MAXSTACKSIZE = 15;

    static SectionPool SPool = new SectionPool();


    public SectionPool() {
	pool = new Stack();
    }

    /**
     * Fetch a CoordinatorLogSection object from the cache. This method
     * should be called instead of "new CoordinatorLogSection()". If the
     * cache is empty this method will instantiate a new
     * CoordinatorLogSection object.
     *
     * @param String name the section name
     *
     * @return CoordinatorLogSection
     *
     */
    public static synchronized
	   CoordinatorLogSection getCoordinatorLogSection(String name) {

	CoordinatorLogSection cls;
	if (SPool.pool.empty()) {
	    return new CoordinatorLogSection(name);
	}
	else {
	    cls = (CoordinatorLogSection) SPool.pool.pop();
	    cls.sectionName = name;
	    return cls;
	}
    }

    /**
     * Return a CoordinatorLogSection object to cache. Cache size is
     * limited to MAXSTACKSIZE by discarding objects when the cache
     * is already at max size.
     *
     * @param CoordinatorLogSection object to be returned to cache
     *
     */
    public static void putCoordinatorLogSection(CoordinatorLogSection cls) {
	if (SPool.pool.size() <= MAXSTACKSIZE) {
	    SPool.pool.push(cls);
	}
    }

}

class CoordinatorLogStateHolder {
   LogFile logFile        = null;
   Log log                = null;
   Hashtable activeLogs   = null;
   Hashtable keypointLogs = null;
   int tranCount          = 0;
   boolean keypointInProgress = false;
   // java.lang.Object keypointLock = new java.lang.Object();
   RWLock keypointLock = null;
   java.lang.Object keypointStateLock = null;
}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish CoordinatorLog.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.