package com.neocoretechs.arieslogger.core.impl;
import java.io.IOException;
import java.nio.ByteBuffer;
import com.neocoretechs.arieslogger.core.LogInstance;
import com.neocoretechs.bigsack.io.pooled.GlobalDBIO;
/**
* Maintains the checksum for a given record. All records checksummed and flushed to durable store for logs
* make sure to call updateChecksum last, before processing, as it sets up entire checksum buffer for writing
* @author jg
*
*/
public final class LogAccessFileChecksum {
private long checksumInstance = LogCounter.makeLogInstanceAsLong(1, LogToFile.LOG_FILE_HEADER_SIZE);
private int checksumLogRecordSize; //checksumLength + LOG_RECORD_FIXED_OVERHEAD_SIZE
private ChecksumOperation checksumLogOperation;
private LogRecord checksumLogRecord;
private boolean DEBUG = false;
ByteBuffer checksumBuffer;
public LogAccessFileChecksum() {
/**
* setup structures that are required to write the checksum log records
* for a group of log records are being written to the disk.
*/
checksumLogOperation = new ChecksumOperation();
checksumLogOperation.init();
checksumLogRecord = new LogRecord();
// Note: Checksum log records are not related any particular transaction,
// they are written to store a checksum to identify
// incomplete log record writes. No transaction id is set for this
// log record. That is why a null argument is passed below
// setValue(..) call.
checksumLogRecord.setValue(-1, checksumLogOperation);
checksumLogRecordSize = checksumLogRecord.getRecordSize();
if( DEBUG ) {
System.out.println("LogAccessFileChecksum: checksum log record len:"+checksumLogRecordSize);
}
checksumBuffer = ByteBuffer.allocate(checksumLogRecordSize+LogAccessFile.LOG_RECORD_FIXED_OVERHEAD_SIZE);
}
public long getChecksumInstance() {
return checksumInstance;
}
public void setChecksumInstance(long checksumInstance) {
this.checksumInstance = checksumInstance;
}
public int getChecksumLogRecordSize() {
return checksumLogRecordSize;
}
public void setChecksumLogRecordSize(int checksumLogRecordSize) {
this.checksumLogRecordSize = checksumLogRecordSize;
}
public ChecksumOperation getChecksumLogOperation() {
return checksumLogOperation;
}
public void setChecksumLogOperation(ChecksumOperation checksumLogOperation) {
this.checksumLogOperation = checksumLogOperation;
}
public LogRecord getChecksumLogRecord() {
return checksumLogRecord;
}
public void setChecksumLogRecord(LogRecord checksumLogRecord) {
this.checksumLogRecord = checksumLogRecord;
}
/**
* Generate the checskum log record and write it into the log
* buffer. The checksum applies to all bytes from this checksum
* log record to the next one.
* NOTE:make sure to call updateChecksum last, before processing, as it sets up entire checksum buffer for writing
* @param bigbuffer The byte[] the checksum is written to. The
* checksum is always written at the beginning of buffer.
*/
public int updateChecksum() throws IOException {
// calculate the checksum for the current log buffer
// and write the record to the space reserved in
// the beginning of the buffer.
//checksumLogOperation.reset();
//checksumLogOperation.update(currentBuffer.buffer.array(),
// checksumLogRecordSize + LOG_RECORD_FIXED_OVERHEAD_SIZE,
// currentBuffer.length - (checksumLogRecordSize + LOG_RECORD_FIXED_OVERHEAD_SIZE) );
checksumBuffer.clear();
checksumBuffer.putInt(checksumLogRecordSize);
assert(checksumInstance != LogInstance.INVALID_LOG_INSTANCE);
checksumBuffer.putLong(checksumInstance);
if( DEBUG )
System.out.println("writing checksum log record of size "+checksumLogRecordSize);
//write the checksum log operation
byte[] checkObj = GlobalDBIO.getObjectAsBytes(checksumLogRecord);
if( DEBUG ) {
System.out.println("checksum log record len:"+checkObj.length+" "+checksumLogRecord.toString());
assert( checksumLogRecordSize == checkObj.length) : "Assumed checksum log record size unequal to deserilized byte count";
}
checksumBuffer.put(checkObj);
checksumBuffer.putInt(checksumLogRecordSize);
int pos = checksumBuffer.position(); // total length
checksumBuffer.flip();
if (DEBUG)
{
System.out.println(
"LogAccessFileChecksum.updateChecksum: " +
" instance: " + LogCounter.toDebugString(checksumInstance) +
" op:" + checksumLogOperation);
}
return pos;
}
/**
* reserve the space for the checksum log record in the log file.
*
* @param length the length of the log record to be written
* @param logFileNumber current log file number
* @param currentPosition current position in the log file.
*
* @return the space that is needed to write a checksum log record.
*/
protected long setChecksumInstance(int logFileNumber, long currentPosition ) throws IOException
{
/* checksum log record is calculated for a log
* record When a new buffer
* is required to write a log record, log space
* has to be reserved before writing the log record
* because checksum is written in the before the
* log records that are being checksummed.
* What it also means is a real log instance has to be
* reserved for writing the checksum log record in addition
* to the log buffer space.
*/
checksumInstance = LogCounter.makeLogInstanceAsLong(logFileNumber, currentPosition);
if( DEBUG ) {
System.out.println("LogAccessFileChecksum.reserveSpaceForChecksum Reserved checksum size:"+checksumLogRecordSize+" instance:"+LogCounter.toDebugString(checksumInstance));
}
return checksumLogRecordSize;
}
}