CoordinatorLogpublic class CoordinatorLog extends Object implements LogUpcallTargetThe 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. |
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 | localTIDThe 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.
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.
// 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 boolean | addData(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.
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 boolean | addLog(java.lang.Long localTID, com.sun.jts.CosTransactions.CoordinatorLog clog)Remembers the mapping between the local transaction identifier and the
CoordinatorLog object.
CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
boolean result = true;
logStateHolder.activeLogs.put(localTID,clog);
return result;
| private static boolean | addLog(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 boolean | addObject(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.
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.Object | createSection(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.
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 void | doFinalize()Default CoordinatorLog destructor.
// 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;
}
| void | dump()Dumps the state of the object.
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 void | dumpClass()Dumps the state of the class.
// Dump the contained objects.
CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
logStateHolder.log.dump();
logStateHolder.logFile.dump();
| static synchronized void | finalizeAll()Destroys the state of the CoordinatorLog class.
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 void | finalizeAll(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 boolean | formatLogRecords(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.
// 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 void | formatSection(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.
// 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.
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.Enumeration | getLogged()Process the log to build a sequence of CoordinatorLog objects which
represent all logged transactions.
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.Enumeration | getLogged(java.lang.String logPath)Process the log to build a sequence of CoordinatorLog objects which
represent all logged transactions.
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.
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.CoordinatorLogStateHolder | getStateHolder(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.
// 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 void | keypoint()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.
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 void | keypoint(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 boolean | openLog()Opens the log file for all CoordinatorLogs in this process.
If the log has already been opened, the operation uses the opened LogFile.
// 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 boolean | openLog(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.
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 void | reUse()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. // 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 void | reUse(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 boolean | reconstruct(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.
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 boolean | removeLog(java.lang.Long localTID)Removes the CoordinatorLog object from the map, and destroys it.
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 boolean | removeLog(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 boolean | requireRewrite()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.
boolean result = true;
// Record the fact that a rewrite is required if a write has been done.
if( writeDone )
rewriteRequired = true;
return result;
| private boolean | rewrite()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.
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 void | setKeypointTrigger(int keypoint)
keypointTrigger = keypoint;
| synchronized void | setLocalTID(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.
// 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(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 boolean | startKeypoint(LogLSN keypointStartLSN)Starts a keypoint.
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 boolean | startKeypoint(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 void | upcall(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.
// Just perform a keypoint.
if (logPath == null)
CoordinatorLog.keypoint();
else
CoordinatorLog.keypoint(logPath);
| boolean | write(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.
// Format the log records with a forced write.
boolean result = true;
try {
result = formatLogRecords(force);
} catch( IOException exc ) {
result = false;
}
return result;
|
|