Compensation compensation = null;
Undoable lop = null;
// stream to read the log record - initial size 4096, scanLog needs
// to resize if the log record is larget than that.
ArrayInputStream rawInput = null;
try
{
if (undoStartAt == null)
{
// don't know where to start, rollback from end of log
scanLog = (StreamLogScan)
logFactory.openBackwardsScan(undoStopAt);
}
else
{
if (undoStartAt.lessThan(undoStopAt))
{
// nothing to undo!
return;
}
long undoStartInstant =
((LogCounter) undoStartAt).getValueAsLong();
scanLog = (StreamLogScan)
logFactory.openBackwardsScan(undoStartInstant, undoStopAt);
}
if (SanityManager.DEBUG)
SanityManager.ASSERT(
scanLog != null, "cannot open log for undo");
rawInput = new ArrayInputStream(new byte[4096]);
LogRecord record;
while ((record =
scanLog.getNextRecord(rawInput, undoId, 0))
!= null)
{
if (SanityManager.DEBUG)
{
SanityManager.ASSERT(
record.getTransactionId().equals(undoId),
"getNextRecord return unqualified log record for undo");
}
logrecordseen++;
if (record.isCLR())
{
clrskipped++;
// the loggable is still in the input stream, get rid of it
record.skipLoggable();
// read the undoInstant
long undoInstant = rawInput.readLong();
if (SanityManager.DEBUG)
{
if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG))
{
SanityManager.DEBUG(
LogToFile.DBG_FLAG,
"Skipping over CLRs, reset scan to " +
LogCounter.toDebugString(undoInstant));
}
}
scanLog.resetPosition(new LogCounter(undoInstant));
// scanLog now positioned at the beginning of the log
// record that was rolled back by this CLR.
// The scan is a backward one so getNextRecord will skip
// over the record that was rolled back and go to the one
// previous to it
continue;
}
lop = record.getUndoable();
if (lop != null)
{
int optionalDataLength = rawInput.readInt();
int savePosition = rawInput.getPosition();
rawInput.setLimit(savePosition, optionalDataLength);
compensation = lop.generateUndo(t, rawInput);
if (SanityManager.DEBUG)
{
if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG))
{
SanityManager.DEBUG(
LogToFile.DBG_FLAG,
"Rollback log record at instant " +
LogCounter.toDebugString(scanLog.getInstant()) +
" : " + lop);
}
}
clrgenerated++;
if (compensation != null)
{
// generateUndo may have read stuff off the
// stream, reset it for the undo operation.
rawInput.setLimit(savePosition, optionalDataLength);
// log the compensation op that rolls back the
// operation at this instant
t.logAndUndo(
compensation, new LogCounter(scanLog.getInstant()),
rawInput);
compensation.releaseResource(t);
compensation = null;
}
// if compensation is null, log operation is redo only
}
// if this is not an undoable operation, continue with next log
// record
}
}
catch (ClassNotFoundException cnfe)
{
throw logFactory.markCorrupt(
StandardException.newException(SQLState.LOG_CORRUPTED, cnfe));
}
catch (IOException ioe)
{
throw logFactory.markCorrupt(
StandardException.newException(
SQLState.LOG_READ_LOG_FOR_UNDO, ioe));
}
catch (StandardException se)
{
// TODO (4327) - exceptions caught here are nested in the exception
// below but for some reason the nested exceptions are not logged
// or reported in any way.
throw logFactory.markCorrupt(
StandardException.newException(
SQLState.LOG_UNDO_FAILED, se, undoId, lop, compensation));
}
finally
{
if (compensation != null)
{
// errored out
compensation.releaseResource(t);
}
if (rawInput != null)
{
try
{
rawInput.close();
}
catch (IOException ioe)
{
throw logFactory.markCorrupt(
StandardException.newException(