package database;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Observable;
import java.util.Observer;
import java.util.TreeMap;
import ntp.NTP;
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.transaction.Transaction;
import utils.ObserverMessage;
import utils.ReverseComparator;
import database.DBSet;
import database.serializer.TransactionSerializer;
public class TransactionMap extends DBMap<byte[], Transaction> implements Observer
{
public static final int TIMESTAMP_INDEX = 1;
private Map<Integer, Integer> observableData = new HashMap<Integer, Integer>();
public TransactionMap(DBSet databaseSet, DB database)
{
super(databaseSet, database);
this.observableData.put(DBMap.NOTIFY_ADD, ObserverMessage.ADD_TRANSACTION_TYPE);
this.observableData.put(DBMap.NOTIFY_REMOVE, ObserverMessage.REMOVE_TRANSACTION_TYPE);
this.observableData.put(DBMap.NOTIFY_LIST, ObserverMessage.LIST_TRANSACTION_TYPE);
}
public TransactionMap(TransactionMap parent)
{
super(parent);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void createIndexes(DB database)
{
//TIMESTAMP INDEX
Tuple2Comparator<Long, byte[]> comparator = new Fun.Tuple2Comparator<Long, byte[]>(Fun.COMPARATOR, UnsignedBytes.lexicographicalComparator());
NavigableSet<Tuple2<Integer, byte[]>> heightIndex = database.createTreeSet("transactions_index_timestamp")
.comparator(comparator)
.makeOrGet();
NavigableSet<Tuple2<Integer, byte[]>> descendingHeightIndex = database.createTreeSet("transactions_index_timestamp_descending")
.comparator(new ReverseComparator(comparator))
.makeOrGet();
createIndex(TIMESTAMP_INDEX, heightIndex, descendingHeightIndex, new Fun.Function2<Long, byte[], Transaction>() {
@Override
public Long run(byte[] key, Transaction value) {
return value.getTimestamp();
}
});
}
@Override
protected Map<byte[], Transaction> getMap(DB database)
{
//OPEN MAP
return database.createTreeMap("transactions")
.keySerializer(BTreeKeySerializer.BASIC)
.comparator(UnsignedBytes.lexicographicalComparator())
.valueSerializer(new TransactionSerializer())
.counterEnable()
.makeOrGet();
}
@Override
protected Map<byte[], Transaction> getMemoryMap()
{
return new TreeMap<byte[], Transaction>(UnsignedBytes.lexicographicalComparator());
}
@Override
protected Transaction getDefaultValue()
{
return null;
}
@Override
protected Map<Integer, Integer> getObservableData()
{
return this.observableData;
}
@Override
public void update(Observable o, Object arg)
{
ObserverMessage message = (ObserverMessage) arg;
//ON NEW BLOCK
if(message.getType() == ObserverMessage.ADD_BLOCK_TYPE)
{
//CLEAN UP
for(Transaction transaction: this.getValues())
{
//CHECK IF DEADLINE PASSED
if(transaction.getDeadline() < NTP.getTime())
{
this.delete(transaction.getSignature());
//NOTIFY
/*this.setChanged();
this.notifyObservers(new ObserverMessage(ObserverMessage.REMOVE_TRANSACTION_TYPE, transaction));*/
}
}
}
}
public void add(Transaction transaction) {
this.set(transaction.getSignature(), transaction);
}
public List<Transaction> getTransactions() {
return new ArrayList<Transaction>(this.getValues());
}
public void delete(Transaction transaction) {
this.delete(transaction.getSignature());
}
public boolean contains(Transaction transaction) {
return this.contains(transaction.getSignature());
}
}