/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o 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.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package com.db4o.io;
import static com.db4o.foundation.Environments.*;
import com.db4o.*;
import com.db4o.ext.*;
/**
* @exclude
*/
public class BlockAwareBin extends BinDecorator {
private static final int COPY_SIZE = 4096;
private boolean _readOnly;
private final BlockSize _blockSize = my(BlockSize.class);
public BlockAwareBin(Bin bin) {
super(bin);
}
/**
* converts address and address offset to an absolute address
*/
protected final long regularAddress(int blockAddress, int blockAddressOffset) {
if (0 == blockSize()) {
throw new IllegalStateException();
}
return (long) blockAddress * blockSize() + blockAddressOffset;
}
/**
* copies a block within a file in block mode
*/
public void blockCopy(int oldAddress, int oldAddressOffset, int newAddress,
int newAddressOffset, int length) throws Db4oIOException {
copy(
regularAddress(oldAddress, oldAddressOffset),
regularAddress(newAddress, newAddressOffset),
length);
}
/**
* copies a block within a file in absolute mode
*/
public void copy(long oldAddress, long newAddress, int length)
throws Db4oIOException {
if (DTrace.enabled) {
DTrace.IO_COPY.logLength(newAddress, length);
}
if (length > COPY_SIZE) {
byte[] buffer = new byte[COPY_SIZE];
int pos = 0;
while (pos + COPY_SIZE < length) {
copy(buffer, oldAddress + pos, newAddress + pos);
pos += COPY_SIZE;
}
oldAddress += pos;
newAddress += pos;
length -= pos;
}
copy(new byte[length], oldAddress, newAddress);
}
private void copy(byte[] buffer, long oldAddress, long newAddress)
throws Db4oIOException {
read(oldAddress, buffer);
write(oldAddress, buffer);
}
/**
* reads a buffer at the seeked address
*
* @return the number of bytes read and returned
*/
public int blockRead(int address, int offset, byte[] buffer) throws Db4oIOException {
return blockRead(address, offset, buffer, buffer.length);
}
/**
* implement to read a buffer at the seeked address
*/
public int blockRead(int address, int offset, byte[] bytes, int length) throws Db4oIOException {
return read(regularAddress(address, offset), bytes, length);
}
/**
* reads a buffer at the seeked address
*
* @return the number of bytes read and returned
*/
public int blockRead(int address, byte[] buffer) throws Db4oIOException {
return blockRead(address, 0, buffer, buffer.length);
}
/**
* implement to read a buffer at the seeked address
*/
public int blockRead(int address, byte[] bytes, int length) throws Db4oIOException {
return blockRead(address, 0, bytes, length);
}
/**
* reads a buffer at the seeked address
*
* @return the number of bytes read and returned
*/
public int read(long pos, byte[] buffer) throws Db4oIOException {
return read(pos, buffer, buffer.length);
}
/**
* reads a buffer at the seeked address
*
* @return the number of bytes read and returned
*/
public void blockWrite(int address, int offset, byte[] buffer) throws Db4oIOException {
blockWrite(address, offset, buffer, buffer.length);
}
/**
* implement to read a buffer at the seeked address
*/
public void blockWrite(int address, int offset, byte[] bytes, int length) throws Db4oIOException {
write(regularAddress(address, offset), bytes, length);
}
/**
* reads a buffer at the seeked address
*
* @return the number of bytes read and returned
*/
public void blockWrite(int address, byte[] buffer) throws Db4oIOException {
blockWrite(address, 0, buffer, buffer.length);
}
/**
* implement to read a buffer at the seeked address
*/
public void blockWrite(int address, byte[] bytes, int length) throws Db4oIOException {
blockWrite(address, 0, bytes, length);
}
@Override
public void sync() {
validateReadOnly();
try{
super.sync();
} catch(Db4oIOException e){
_readOnly = true;
throw e;
}
}
@Override
public void sync(Runnable runnable) {
validateReadOnly();
try{
super.sync(runnable);
} catch(Db4oIOException e){
_readOnly = true;
throw e;
}
}
/**
* writes a buffer to the seeked address
*/
public void write(long pos, byte[] bytes) throws Db4oIOException {
validateReadOnly();
try{
write(pos, bytes, bytes.length);
} catch(Db4oIOException e){
_readOnly = true;
throw e;
}
}
private void validateReadOnly() {
if(_readOnly){
throw new EmergencyShutdownReadOnlyException();
}
}
/**
* returns the block size currently used
*/
public int blockSize() {
return _blockSize.value();
}
/**
* outside call to set the block size of this adapter
*/
public void blockSize(int blockSize) {
if (blockSize < 1) {
throw new IllegalArgumentException();
}
_blockSize.set(blockSize);
}
}