/*
* 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.exception.ChaiDBException;
import org.chaidb.db.exception.ErrorCode;
import org.chaidb.db.helper.ByteTool;
import org.chaidb.db.index.btree.BTree;
import org.chaidb.db.index.btree.BTreeSpec;
import org.chaidb.db.index.btree.DataPage;
import org.chaidb.db.index.btree.bufmgr.PageBufferManager;
import org.chaidb.db.log.LogRecord;
/**
* free page while BtreePage(or DataPage) add page to free list
* log the new allocated page number
*/
public class BTreeFreePageLogRecord extends BTreeLogRecord {
private static final Logger logger = Logger.getLogger(BTreeFreePageLogRecord.class);
private static PageBufferManager bpm = PageBufferManager.getInstance();
private byte pageFlag; //page flags
private int prevPage; //previous page
private int nextPage; //next page
private byte keyType; //Key Type of a BTreePage
private int docid; //docid of a datapage
static int PAGEFLAG_SIZE = 1; //1 bytes
static int PREVPAGE_SIZE = 4; //4 bytes
static int NEXTPAGE_SIZE = 4; //4 bytes
static byte KEYTYPE_SIZE = 1;
/**
* default Construct
*/
public BTreeFreePageLogRecord() {
super();
super.setType(LOG_BTREE_FREE_PAGE);
}
/**
* Construct
*
* @param keyType Only used for BTreePage
* @param docid Only used for DataPage
*/
public BTreeFreePageLogRecord(int treeId, int newPageNum, int newTxnId, int newPageFlag, int newPrevPage, int newNextPage, byte keyType, int docid, short btreeType) {
super(treeId, newPageNum, newTxnId, btreeType);
this.pageFlag = (byte) newPageFlag;
this.prevPage = newPrevPage;
this.nextPage = newNextPage;
this.keyType = keyType;
this.docid = docid;
super.setType(LOG_BTREE_FREE_PAGE);
}
/**
* get page flag
*/
public byte getPageFlag() {
return pageFlag;
}
/**
* get previous page
*/
public int getPrevPage() {
return prevPage;
}
/**
* get next page
*/
public int getNextPage() {
return nextPage;
}
public byte getKeyType() {
return keyType;
}
public int getDocid() {
return docid;
}
/**
* 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 BTreeMoveLogRecord Object */
int step = start + super.getRecordLength();
pageFlag = bArr[step];
step = step + PAGEFLAG_SIZE;
prevPage = ByteTool.bytesToInt(bArr, step, msbFirst);
step = step + PREVPAGE_SIZE;
nextPage = ByteTool.bytesToInt(bArr, step, msbFirst);
step += NEXTPAGE_SIZE;
keyType = bArr[step];
//set the keytype to be 0 so that we can directly construct docid in bArr
bArr[step] = 0;
docid = ByteTool.bytesToInt(bArr, step, LogRecord.msbFirst);
//restore keyType
bArr[step] = keyType;
return true;
}
/**
* do redo function
*
* @param page
* @return boolean true|false
* update date:2001-10-12 by marriane,delete freelist recover
*/
protected boolean doRedo(byte[] page) throws ChaiDBException {
try {
/* add page to freelist of BufferedPage in memory*/
PageBufferManager bp = bpm;
bp.addToFreeList(treeId, super.getPageNum(), new Integer(super.getTxnId()));
if (DataPage.isNormalDataPage((int) pageFlag)) {
bp.removeLatestDataPage(docid, treeId, super.getPageNum(), new Integer(super.getTxnId()));
}
return true;
} catch (Exception e) {
logger.debug(e);
throw new ChaiDBException(ErrorCode.LOG_REDO_FAILED, e.toString());
}
}
/**
* do undo function
*
* @param page
* @return boolean true|false
* update date:2001-10-12 by marriane,delete freelist recover
*/
protected boolean doUndo(byte[] page) throws ChaiDBException {
try {
/* get the free page location in free list */
//set metadata's lowbound and uppbound data with default value
System.arraycopy(ByteTool.shortToBytes((short) BTreeSpec.PAGE_HEADER_SIZE), 0, page, BTreeSpec.OFF_LOWERBOUND, 2);
System.arraycopy(ByteTool.shortToBytes((short) BTreeSpec.PAGE_SIZE), 0, page, BTreeSpec.OFF_UPPERBOUND, 2);
/* set metadata's pageNumber */
System.arraycopy(ByteTool.intToBytes(super.getPageNum()), 0, page, BTreeSpec.OFF_PAGENUMBER, 4);
/* set prevPage and nextPage in metadata */
System.arraycopy(ByteTool.intToBytes(prevPage), 0, page, BTreeSpec.OFF_PREVPAGE, 4);
System.arraycopy(ByteTool.intToBytes(nextPage), 0, page, BTreeSpec.OFF_NEXTPAGE, 4);
/* set flags of different page type */
System.arraycopy(ByteTool.intToBytes(pageFlag), 0, page, BTreeSpec.OFF_FLAGS, 4);
if (isBTreePage(pageFlag)) //BTreepage
page[BTreeSpec.OFF_KEYTYPE] = keyType;
else if (isDataPage(pageFlag)) {
byte[] docidArr = ByteTool.intToBytes(docid, LogRecord.msbFirst);
docidArr = ByteTool.subByteArray(docidArr, docidArr.length - BTree.DOCID_SIZE, BTree.DOCID_SIZE);
System.arraycopy(docidArr, 0, page, BTreeSpec.OFF_DOCID, docidArr.length);
}
return true;
} catch (Exception e) {
logger.debug(e);
throw new ChaiDBException(ErrorCode.LOG_UNDO_FAILED, e.toString());
}
}
/**
* print data and help in debugging log files
*/
public void print() throws ChaiDBException {
//logger.log(ServerLog.LOG_DEBUG,"begin: printing the information of BTreeFreePageLogRecord object......");
super.print();
logger.debug(" flag:" + this.getPageFlag());
logger.debug(" prev_pg:" + this.getPrevPage() + " next_pg:" + nextPage + (isBTreePage(pageFlag) ? " keytype=" + keyType : " docid=" + docid));
//logger.log(ServerLog.LOG_DEBUG,"end: printing the information of BTreeFreePageLogRecord object.");
}
/**
* converts a log record instance into a byte array.
* The byte array has the following format:
* --------------------------------------------------
* | pageFlag | prevPage | nextPage | keytype | docid
* --------------------------------------------------
* <p/>
* pageFlag: 1 bytes.
* prevPage: 4 bytes.
* nextPage: 4 bytes.
* keyType: 1 byte
* docid: 3 bytes
*/
public void toBytes(byte[] byteArray, int start) throws ChaiDBException {
super.toBytes(byteArray, start);
int step = start + super.getRecordLength();
byteArray[step] = pageFlag;
step += PAGEFLAG_SIZE;
ByteTool.intToBytes(byteArray, step, prevPage, msbFirst);
step += PREVPAGE_SIZE;
ByteTool.intToBytes(byteArray, step, nextPage, msbFirst);
step += NEXTPAGE_SIZE;
ByteTool.intToBytes(byteArray, step, docid, msbFirst);
byteArray[step] = keyType;
}
/**
* get current log record type total length
*
* @return int total lenth
*/
public int getRecordLength() {
return super.getRecordLength() + PAGEFLAG_SIZE + PREVPAGE_SIZE + NEXTPAGE_SIZE + KEYTYPE_SIZE + BTree.DOCID_SIZE;
}
}