package com.ripple.core.cache;
import com.ripple.core.coretypes.hash.Hash256;
import com.ripple.core.coretypes.uint.UInt32;
import com.ripple.core.types.known.sle.LedgerEntry;
import com.ripple.core.types.known.tx.result.AffectedNode;
import com.ripple.core.types.known.tx.result.TransactionMeta;
import com.ripple.core.types.known.tx.result.TransactionResult;
import java.util.TreeMap;
public class SLECache {
private final TreeMap<Hash256, CacheEntry> cache = new TreeMap<Hash256, CacheEntry>();
public static class CacheEntry {
public LedgerEntry le;
public UInt32 prevTxnIndex;
public UInt32 prevLedger;
public boolean deleted = false;
public void upateLedgerEntry(LedgerEntry le, UInt32 ledgerIndex, UInt32 txnIndex) {
if (doUpdate(txnIndex, ledgerIndex)) {
// in the first case
prevTxnIndex = txnIndex;
prevLedger = ledgerIndex;
if (le == null) {
deleted = true;
}
this.le = le;
}
}
private boolean doUpdate(UInt32 txnIndex, UInt32 ledgerIndex) {
if (le == null && !deleted) {
return true;
}
if (prevLedger == null) {
return true;
}
int ledgerCmp = ledgerIndex.compareTo(prevLedger);
if (ledgerCmp == 1) {
return true;
}
if (ledgerCmp == 0) {
if (prevTxnIndex == null) {
// We don't know, should log a warning or something
// Should we keep the first one that we have of this index
// or can we assume that the latest is the best?
return true;
}
if (txnIndex.compareTo(prevTxnIndex) == 1) {
// This happened AFTER
return true;
}
}
//ledgerCmp == -1 or txnIndex <= previousTxnIndex ss
return false;
}
}
public boolean cache(LedgerEntry le, UInt32 validatedLedgerIndex) {
Hash256 index = le.ledgerIndex();
CacheEntry ce = getOrCreate(index);
ce.upateLedgerEntry(le, validatedLedgerIndex, null);
return true;
}
private CacheEntry getEntry(Hash256 index) {
return cache.get(index);
}
private CacheEntry createEntry(Hash256 index) {
CacheEntry ce = new CacheEntry();
cache.put(index, ce);
return ce;
}
public LedgerEntry get(Hash256 index) {
CacheEntry entry = getEntry(index);
return entry == null || entry.deleted ? null : entry.le;
}
public void updateFromTransactionResult(TransactionResult tr) {
if (!tr.validated) {
return;
}
TransactionMeta meta = tr.meta;
UInt32 ledgerIndex = tr.ledgerIndex;
UInt32 txnIndex = meta.transactionIndex();
for (AffectedNode an : meta.affectedNodes()) {
Hash256 index = an.ledgerIndex();
CacheEntry ce = getOrCreate(index);
ce.upateLedgerEntry(an.isDeletedNode() ? null : (LedgerEntry) an.nodeAsFinal(),
ledgerIndex,
txnIndex);
}
}
private CacheEntry getOrCreate(Hash256 index) {
CacheEntry already = getEntry(index);
if (already == null) {
return createEntry(index);
} else {
return already;
}
}
}