/* 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.internal.freespace;
import com.db4o.*;
import com.db4o.foundation.*;
import com.db4o.internal.*;
import com.db4o.internal.slots.*;
public abstract class AbstractFreespaceManager implements FreespaceManager {
public static final byte FM_DEBUG = 127;
public static final byte FM_DEFAULT = 0;
public static final byte FM_LEGACY_RAM = 1;
public static final byte FM_RAM = 2;
public static final byte FM_IX = 3;
public static final byte FM_BTREE = 4;
private static final int INTS_IN_SLOT = 12;
public static final int REMAINDER_SIZE_LIMIT = 20;
public static byte checkType(byte systemType){
if(systemType == FM_DEFAULT){
return FM_RAM;
}
return systemType;
}
protected Procedure4<Slot> _slotFreedCallback;
private final int _discardLimit;
private final int _remainderSizeLimit;
public AbstractFreespaceManager(Procedure4<Slot> slotFreedCallback, int discardLimit, int remainderSizeLimit){
_slotFreedCallback = slotFreedCallback;
_discardLimit = discardLimit;
_remainderSizeLimit = remainderSizeLimit;
}
public static AbstractFreespaceManager createNew(LocalObjectContainer file){
return createNew(file, file.systemData().freespaceSystem());
}
public static AbstractFreespaceManager createNew(final LocalObjectContainer file, byte systemType){
systemType = checkType(systemType);
int unblockedDiscardLimit = file.configImpl().discardFreeSpace();
int blockedDiscardLimit = unblockedDiscardLimit == Integer.MAX_VALUE ?
unblockedDiscardLimit :
file.blockConverter().bytesToBlocks(unblockedDiscardLimit);
int remainderSizeLimit = file.blockConverter().bytesToBlocks(REMAINDER_SIZE_LIMIT);
Procedure4<Slot> slotFreedCallback = new Procedure4<Slot>() {
public void apply(Slot slot) {
file.overwriteDeletedBlockedSlot(slot);
}
};
switch(systemType){
case FM_IX:
return new FreespaceManagerIx(blockedDiscardLimit, remainderSizeLimit);
case FM_BTREE:
return new BTreeFreespaceManager(file, slotFreedCallback, blockedDiscardLimit, remainderSizeLimit);
default:
return new InMemoryFreespaceManager(slotFreedCallback, blockedDiscardLimit, remainderSizeLimit);
}
}
public static int initSlot(LocalObjectContainer file){
int address = file.allocateSlot(slotLength()).address();
slotEntryToZeroes(file, address);
return address;
}
public void migrateTo(final FreespaceManager fm) {
traverse(new Visitor4() {
public void visit(Object obj) {
fm.free((Slot) obj);
}
});
}
static void slotEntryToZeroes(LocalObjectContainer file, int address){
StatefulBuffer writer = new StatefulBuffer(file.systemTransaction(), address, slotLength());
for (int i = 0; i < INTS_IN_SLOT; i++) {
writer.writeInt(0);
}
if (Debug4.xbytes) {
writer.checkXBytes(false);
}
writer.writeEncrypt();
}
final static int slotLength(){
return Const4.INT_LENGTH * INTS_IN_SLOT;
}
public int totalFreespace() {
final IntByRef mint = new IntByRef();
traverse(new Visitor4() {
public void visit(Object obj) {
Slot slot = (Slot) obj;
mint.value += slot.length();
}
});
return mint.value;
}
protected int discardLimit() {
return _discardLimit;
}
protected final boolean splitRemainder(int length){
if(canDiscard(length)){
return false;
}
return length > _remainderSizeLimit;
}
final boolean canDiscard(int length) {
return length == 0 || length < discardLimit();
}
public static void migrate(FreespaceManager oldFM, FreespaceManager newFM) {
oldFM.migrateTo(newFM);
oldFM.freeSelf();
}
public void debugCheckIntegrity(){
final IntByRef lastStart = new IntByRef();
final IntByRef lastEnd = new IntByRef();
traverse(new Visitor4() {
public void visit(Object obj) {
Slot slot = (Slot) obj;
if(slot.address() <= lastEnd.value){
throw new IllegalStateException();
}
lastStart.value = slot.address();
lastEnd.value = slot.address() + slot.length();
}
});
}
public static boolean migrationRequired(byte systemType) {
return systemType == FM_LEGACY_RAM || systemType == FM_IX ;
}
public void slotFreed(Slot slot) {
if(_slotFreedCallback == null){
return;
}
_slotFreedCallback.apply(slot);
}
}