/*
* Copyright (C) 2006 http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
package org.chaidb.db.log.logrecord;
import org.apache.log4j.Logger;
import org.chaidb.db.Db;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.helper.ByteTool;
import org.chaidb.db.log.LogManager;
import org.chaidb.db.log.LogRecord;
import org.chaidb.db.log.Lsn;
import java.util.Date;
/*
* This is the checkpoint record. It contains the lsn that the checkpoint
* guarantees and a pointer to the last checkpoint so we can walk backwards
* by checkpoint.
*
* last_ckp:
* The previous checkpoint.
* timestamp:
* See comment in commit about timestamps.
*/
public class TxnCkpLogRecord extends LogRecord {
private static final Logger logger = Logger.getLogger(TxnCkpLogRecord.class);
/*The previous checkpoint*/
private Lsn lastCkpLsn;
private long timeStamp;
/* checkpoint flag: normal or shutdown */
private byte flag;
public static final byte NORMAL_CHECKPOINT = 1; //normal checkpoint
public static final byte SHUTDOWN_CHECKPOINT = 2; //do checkpoint while system shut down
public static final byte FUZZY_CHECKPOINT = 3; //do fuzzy checkpoint without block any active txn
static int TXN_CHKPT_TIMESTAMP_SIZE = 8;//8 bytes
static int TXN_CHKPT_TXNID = 0; //default checkpoint transaction id
static int FLAG_SIZE = 1; //1 byte
/**
* Default Constructor
*/
public TxnCkpLogRecord() {
super();
lastCkpLsn = new Lsn();
super.setType(LOG_TXN_CHECKPOINT);
}
/**
* Constructor
*
* @param newLastCkpLsn
* @param newTimeStamp
*/
public TxnCkpLogRecord(Lsn newLastCkpLsn, long newTimeStamp, byte flag) {
super();
this.lastCkpLsn = newLastCkpLsn;
this.timeStamp = newTimeStamp;
this.flag = flag;
super.setType(LOG_TXN_CHECKPOINT);
super.setTxnId(TXN_CHKPT_TXNID);
}
/**
* Constructor
*
* @param newLastCkpLsn
* @param newTimeStamp
* @param newTxnId
*/
public TxnCkpLogRecord(Lsn newLastCkpLsn, long newTimeStamp, int newTxnId, byte flag) {
super();
this.lastCkpLsn = newLastCkpLsn;
this.timeStamp = newTimeStamp;
this.flag = flag;
super.setType(LOG_TXN_CHECKPOINT);
super.setTxnId(newTxnId);
}
/**
* get penultimate CkpLsn of current TxnCkpLogRecord Object
*
* @return Lsn lastCkpLsn
*/
public Lsn getLastCkpLsn() {
if (lastCkpLsn == null) {
return null;
}
return new Lsn(lastCkpLsn);
}
/**
* get timeStamp of current TxnCkpLogRecord Object
*
* @return int version
*/
public long getTimeStamp() {
return timeStamp;
}
/**
* get flag of checkpoint,used in LogManagerImpl
*
* @return byte flag
*/
public byte getFlag() {
return flag;
}
/**
* just for compatible
*/
public String getBTreeFileName() {
return null;
}
/**
* user interface to add a log record and put it to buffer pool
*/
public Lsn log() throws ChaiDBException {
super.log();
LogManager logMgr = Db.getLogManager();
Lsn newLsn = logMgr.put(this, LogManager.LOG_CHECKPOINT);
return newLsn;
}
/**
* converts a byte array into a log record instance
*/
public boolean read(byte[] bArr, int start) throws ChaiDBException {
/* construct a new LogRecord instance */
super.read(bArr, start);
/* get the values of TxnCkpLogRecord Object */
int step = start + super.getRecordLength();
// Lsn newLastCkpLsn = new Lsn();
lastCkpLsn.read(bArr, step);
step = step + Lsn.getLsnLength();
timeStamp = ByteTool.bytesToLong(bArr, step, msbFirst);
step = step + TXN_CHKPT_TIMESTAMP_SIZE;
flag = bArr[step];
return true;
}
/**
* redo or undo the operation for recovery
*/
public boolean recover(short flag) throws ChaiDBException {
return true;
}
/**
* print data and help in debugging log files
*/
public void print() throws ChaiDBException {
//logger.debug("begin: printing the information of TxnCkpLogRecord object......");
super.print();
logger.debug("lastCkpLsn's file id:" + this.getLastCkpLsn().getFileId());
logger.debug("lastCkpLsn's offset:0x" + Integer.toHexString(this.getLastCkpLsn().getOffset()));
logger.debug("timeStamp:" + new Date(this.getTimeStamp()).toString());
if (flag == NORMAL_CHECKPOINT) {
logger.debug("flag:" + flag + " normal checkpoint");
} else if (flag == SHUTDOWN_CHECKPOINT) {
logger.debug("flag:" + flag + " shutdown checkpoint");
} else if (flag == FUZZY_CHECKPOINT) {
logger.debug("flag:" + flag + " fuzzy checkpoint");
}
//logger.debug("end: printing the information of TxnCkpLogRecord object.");
}
/**
* converts a log record instance into a byte array.
* The byte array has the following format:
* ----------------------------------------------------------------
* | hdr | type | txnId | prevLsn | lastCkpLsn | timeStamp | flag
* ----------------------------------------------------------------
* hdr: 12 bytes,the byte array of the header,generated by Hdr.toBytes().
* type: 4 bytes.
* txnId: 4 bytes.
* prevLsn: 8 bytes,the byte array of the header of lsn,generated by Lsn.toBytes().
* <p/>
* lastCkpLsn: 8 bytes,generated by Lsn.toBytes().
* timeStamp: 8 bytes.
* flag : 1 byte
*/
public void toBytes(byte[] byteArray, int start) throws ChaiDBException {
super.toBytes(byteArray, start);
int step = start + super.getRecordLength();
lastCkpLsn.toBytes(byteArray, step);
step += Lsn.getLsnLength();
ByteTool.longToBytes(byteArray, step, timeStamp);
step += TXN_CHKPT_TIMESTAMP_SIZE;
byteArray[step] = flag;
}
/**
* get current log record type total length
*
* @return int total lenth
*/
public int getRecordLength() {
return super.getRecordLength() + Lsn.getLsnLength() + TXN_CHKPT_TIMESTAMP_SIZE + FLAG_SIZE;
}
}