package database;
import java.util.HashMap;
import java.util.Map;
import java.util.NavigableSet;
import java.util.TreeMap;
import org.mapdb.Atomic.Var;
import org.mapdb.BTreeKeySerializer;
import org.mapdb.DB;
import org.mapdb.Fun;
import org.mapdb.Fun.Tuple2;
import org.mapdb.Fun.Tuple2Comparator;
import com.google.common.primitives.UnsignedBytes;
import qora.block.Block;
import utils.ObserverMessage;
import utils.ReverseComparator;
import database.DBSet;
import database.serializer.BlockSerializer;
public class BlockMap extends DBMap<byte[], Block>
{
public static final int HEIGHT_INDEX = 1;
private Map<Integer, Integer> observableData = new HashMap<Integer, Integer>();
private Var<byte[]> lastBlockVar;
private byte[] lastBlockSignature;
private Var<Boolean> processingVar;
private Boolean processing;
public BlockMap(DBSet databaseSet, DB database)
{
super(databaseSet, database);
this.observableData.put(DBMap.NOTIFY_ADD, ObserverMessage.ADD_BLOCK_TYPE);
this.observableData.put(DBMap.NOTIFY_REMOVE, ObserverMessage.REMOVE_BLOCK_TYPE);
this.observableData.put(DBMap.NOTIFY_LIST, ObserverMessage.LIST_BLOCK_TYPE);
//LAST BLOCK
this.lastBlockVar = database.getAtomicVar("lastBlock");
this.lastBlockSignature = lastBlockVar.get();
//PROCESSING
this.processingVar = database.getAtomicVar("processingBlock");
this.processing = processingVar.get();
}
public BlockMap(BlockMap parent)
{
super(parent);
this.lastBlockSignature = parent.getLastBlockSignature();
this.processing = parent.isProcessing();
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void createIndexes(DB database)
{
//HEIGHT INDEX
Tuple2Comparator<Integer, byte[]> comparator = new Fun.Tuple2Comparator<Integer, byte[]>(Fun.COMPARATOR, UnsignedBytes.lexicographicalComparator());
NavigableSet<Tuple2<Integer, byte[]>> heightIndex = database.createTreeSet("blocks_index_height")
.comparator(comparator)
.makeOrGet();
NavigableSet<Tuple2<Integer, byte[]>> descendingHeightIndex = database.createTreeSet("blocks_index_height_descending")
.comparator(new ReverseComparator(comparator))
.makeOrGet();
createIndex(HEIGHT_INDEX, heightIndex, descendingHeightIndex, new Fun.Function2<Integer, byte[], Block>() {
@Override
public Integer run(byte[] key, Block value) {
return value.getHeight();
}
});
}
@Override
protected Map<byte[], Block> getMap(DB database)
{
//OPEN MAP
return database.createTreeMap("blocks")
.keySerializer(BTreeKeySerializer.BASIC)
.comparator(UnsignedBytes.lexicographicalComparator())
.valueSerializer(new BlockSerializer())
.valuesOutsideNodesEnable()
.counterEnable()
.makeOrGet();
}
@Override
protected Map<byte[], Block> getMemoryMap()
{
return new TreeMap<byte[], Block>(UnsignedBytes.lexicographicalComparator());
}
@Override
protected Block getDefaultValue()
{
return null;
}
@Override
protected Map<Integer, Integer> getObservableData()
{
return this.observableData;
}
public void setLastBlock(Block block)
{
if(this.lastBlockVar != null)
{
this.lastBlockVar.set(block.getSignature());
}
this.lastBlockSignature = block.getSignature();
}
public Block getLastBlock()
{
return this.get(this.getLastBlockSignature());
}
public byte[] getLastBlockSignature()
{
return this.lastBlockSignature;
}
public boolean isProcessing()
{
if(this.processing != null)
{
return this.processing.booleanValue();
}
return false;
}
public void setProcessing(boolean processing)
{
if(this.processingVar != null)
{
this.processingVar.set(processing);
}
this.processing = processing;
}
public void add(Block block)
{
this.set(block.getSignature(), block);
}
public void delete(Block block)
{
this.delete(block.getSignature());
}
}