/*
* 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;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.exception.ErrorCode;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* A read buffer store bytes read from log, which is used as a cache by RollBack
*/
public class ReadCache {
/**
* Hashtalbe mapping lsn to data
* Key=lsn, Value=data
*/
private HashMap l2dTable = new HashMap();
private int size;
private LogFile logWr;
boolean direction;
public ReadCache(LogFile logWr) {
this.logWr = logWr;
}
/**
* Get the total buf size.
*
* @return buf size
*/
public int size() {
return size;
}
/**
* direction indicate ReadCache how to read and cache log
*
* @return false - read log from end to begin
* true - read log from begin to end
*/
public boolean direction() {
return direction;
}
/**
* direction indicate ReadCache how to read and cache log
*
* @param direction false - read log from end to begin
* true - read log from begin to end
*/
public void setDirection(boolean direction) {
this.direction = direction;
}
public synchronized byte[] getBytes(Lsn lsn) throws ChaiDBException {
return getBytes(lsn, null);
}
public synchronized LogRecord get(Lsn lsn) throws ChaiDBException {
return get(lsn, null);
}
public synchronized byte[] getBytes(Lsn lsn, Lsn stopLsn) throws ChaiDBException {
byte[] recA = null;
recA = (byte[]) l2dTable.get(lsn);
if (recA != null) {
return recA;
}
// Vector lsnList = new Vector();
// Vector dataList = new Vector();
HashMap lsnList = new HashMap();
int newsize = logWr.read(lsn, stopLsn, lsnList, direction);
if (newsize == 0) {
return null;
}
if ((size + newsize) > LogManagerImpl.LOG_READBUFFER_MAX_SIZE) {
//Collect all elements in l2dTable who will be kicked out.
//And kick them out totally.
//Must use entrySet here because when use enum and iterator
//to get a key, and use get(key) to get data may return null
Iterator eit = l2dTable.entrySet().iterator();
while (((size + newsize) > LogManagerImpl.LOG_READBUFFER_MAX_SIZE) && eit.hasNext()) {
Map.Entry e = (Map.Entry) eit.next();
size -= ((byte[]) e.getValue()).length;
eit.remove();
}
}
l2dTable.putAll(lsnList);
size += newsize;
recA = (byte[]) lsnList.get(lsn);
if (recA == null) {
String details = "Lsn: " + lsn.getFileId() + ":" + lsn.getOffset() + ".";
throw new ChaiDBException(ErrorCode.LOG_RECORD_NOT_EXIST, details);
} else {
return recA;
}
}
/**
* Get the record from buf according to lsn
*
* @param lsn Lsn of the record to get
* @param stopLsn get the record untill the stopLsn if it isn't null
* @return LogRecord if success.
* @see org.chaidb.db.log.LogManager
*/
public synchronized LogRecord get(Lsn lsn, Lsn stopLsn) throws ChaiDBException {
//modified by marriane 2001-11-21 add 'synchronized'
byte[] recA = getBytes(lsn, stopLsn);
if (recA == null) {
throw new ChaiDBException(ErrorCode.LOG_RECORD_NOT_EXIST, "Lsn=" + lsn);
}
return RecordFactory.createRecord(recA, 0);
}
/**
* Clear the cache
*/
public synchronized void clear() {
l2dTable.clear();
size = 0;
}
/**
* dump buffer information to String as XML format
*
* @return String
* date 2001-12-25
* author Marriane Miao
*/
public String dump() {
StringBuffer buf = new StringBuffer("<ReadBuffer>");
buf.append("<bufferTotalByteSize>" + size + "</bufferTotalByteSize>");
buf.append("<l2dTableSize>" + l2dTable.size() + "</l2dTableSize>");
buf.append("</ReadBuffer>");
return buf.toString();
}
}