FileDocCategorySizeDatePackage
CoordinatorLog.javaAPI DocGlassfish v2 API76731Wed Jun 13 23:03:46 BST 2007com.sun.jts.CosTransactions

CoordinatorLog

public class CoordinatorLog extends Object implements LogUpcallTarget
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.

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.

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

Fields Summary
private static final int
LOG_DEF_KEY_TRIGGER
private static final int
LOG_THRESHOLD
private static final int
STRING_TO_REF_RETRIES
private static final String
defaultstring
private static int
keypointTrigger
// 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 Hashtable
logStateHoldertable
private Hashtable
sectionMapping
private boolean
rewriteRequired
private boolean
writeDone
private String
logPath
static Logger
_logger
Long
localTID
The local transaction identifier for the transaction this object is logging.
CoordinatorLogStateHolder
logStateHolder
private static CoordinatorLogStateHolder
defaultLogStateHolder
private ByteArrayOutputStream
byteOutput
private DataOutputStream
dataOutput
Constructors Summary
CoordinatorLog()
Default CoordinatorLog constructor.

param
return
see


        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.

    
CoordinatorLog(Long localTID)
Creates and initialises a new CoordinatorLog object, with the given local transaction identifier.

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


        // 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);

    
Methods Summary
synchronized booleanaddData(java.lang.Object sectionObj, byte[] data)
Adds the given opaque data structure to the sequence of those in the given section.

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


        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;
    
private static booleanaddLog(java.lang.Long localTID, com.sun.jts.CosTransactions.CoordinatorLog clog)
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

       CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        boolean result = true;

        logStateHolder.activeLogs.put(localTID,clog);

        return result;
    
private static booleanaddLog(java.lang.Long localTID, com.sun.jts.CosTransactions.CoordinatorLog clog, java.lang.String logPath)

       CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);

        boolean result = true;

        logStateHolder.activeLogs.put(localTID,clog);

        return result;
    
synchronized booleanaddObject(java.lang.Object sectionObj, org.omg.CORBA.Object obj)
Adds the given object to the sequence of those in the given section.

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


        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;
    
synchronized java.lang.ObjectcreateSection(java.lang.String sectionName)
Creates a subsection in the CoordinatorLog in which to store related objects and data.

The object that is returned is used to identify the section on subsequent calls.

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


        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;
    
public synchronized voiddoFinalize()
Default CoordinatorLog destructor.

param
return
see


        // 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;
        }
    
voiddump()
Dumps the state of the object.

param
return
see

        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;
        }
    
static voiddumpClass()
Dumps the state of the class.

param
return
see

        // Dump the contained objects.
        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;

        logStateHolder.log.dump();
        logStateHolder.logFile.dump();
    
static synchronized voidfinalizeAll()
Destroys the state of the CoordinatorLog class.

param
return
see

       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;

    
static synchronized voidfinalizeAll(java.lang.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;

    
private booleanformatLogRecords(boolean forced)
Formats the information in all sections of the CoordinatorLog.

The formatted information is written to the log.

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


        // 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;
    
private voidformatSection(com.sun.jts.CosTransactions.CoordinatorLogSection section, boolean rewrite, java.io.DataOutputStream dataOutput)
Formats the information in a single section of the Coordinatorlog into a stream.

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

        // 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;

    
byte[][]getData(java.lang.Object sectionObj)
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[][] 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;
    
static synchronized java.util.EnumerationgetLogged()
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


        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;
    
static synchronized java.util.EnumerationgetLogged(java.lang.String logPath)
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


        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;
    
java.lang.Object[]getObjects(java.lang.Object sectionObj)
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[] 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;
    
private static com.sun.jts.CosTransactions.CoordinatorLogStateHoldergetStateHolder(java.lang.String str)
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


   
    // 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
                                               
         
        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;
        }
    
static voidkeypoint()
Performs a keypoint operation to allow old information in the log to be discarded.

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

        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, tell it to rewrite itself.

                    if( currentLog != null )
                        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 voidkeypoint(java.lang.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, tell it to rewrite itself.

                    if( currentLog != null )
                        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();

    
private static booleanopenLog()
Opens the log file for all CoordinatorLogs in this process.

If the log has already been opened, the operation uses the opened LogFile.

param
return
Indicates success of the operation.
see


        // 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 ) {}

    
        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;
    
private static booleanopenLog(java.lang.String logPath)
Opens the log file for all CoordinatorLogs in this process.

If the log has already been opened, the operation uses the opened LogFile.

param
return
Indicates success of the operation.
see

        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;
        if( logStateHolder.log != null &&
            logStateHolder.logFile == 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;
    
private synchronized voidreUse()
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

			// 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);

    
private synchronized voidreUse(java.lang.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);

    
private booleanreconstruct(java.io.DataInputStream dataInput)
Requests that the object reconstructs its state from the given stream.

There may be more than one if the CoordinatorLog elects to write to the log before it is asked to force the transaction state.

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


        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;
    
static synchronized booleanremoveLog(java.lang.Long localTID)
Removes the CoordinatorLog object from the map, and destroys it.

param
localTID The local transaction identifier.
return
Indicates success of the operation.
see


        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);
            }

            // 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;
    
static synchronized booleanremoveLog(java.lang.Long localTID, java.lang.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);
            }

            // 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;
     
private synchronized booleanrequireRewrite()
Informs the CoordinatorLog object that it must rewrite its entire state the next time it writes a log record.

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

        boolean result = true;

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

        if( writeDone )
            rewriteRequired = true;

        return result;
    
private booleanrewrite()
Rewrites the contents of the CoordinatorLog to persistent storage.

This requires that all information defined to the CoordinatorLog that has already been written be re-written (unforced) to the log.

The CoordinatorLog also writes any unwritten state at this point.

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.

This operation discharges the CoordinatorLog's requirement to rewrite.

param
return
Indicates success of the operation.
see


        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;
    
public static voidsetKeypointTrigger(int keypoint)

        keypointTrigger = keypoint;
    
synchronized voidsetLocalTID(java.lang.Long localTID)
Sets the local identifier for the CoordinatorLog object.

If the local identifier was previously 0, the CoordinatorLog object is added to the static list.

param
localTID The new local identifier.
return
see


        // 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 voidsetLocalTID(java.lang.Long localTID, java.lang.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);

    
static synchronized booleanstartKeypoint(LogLSN keypointStartLSN)
Starts a keypoint.

param
keypointStartLSN The LSN to hold the keypoint start LSN.
return
Indicates whether keypoint is required.
see

        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;
    
static synchronized booleanstartKeypoint(LogLSN keypointStartLSN, java.lang.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;
    
public voidupcall(int reason)
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


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

    
booleanwrite(boolean force)
Write the contents of the CoordinatorLog to persistent storage.

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.

If rewrite is required, all information whether previously written or not is recorded.

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.

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


        // Format the log records with a forced write.

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

        return result;