/**
* Public Key Store (with LRU memory cache)
*/
package freenet.node;
import java.io.IOException;
import freenet.crypt.DSAPublicKey;
import freenet.store.BlockMetadata;
import freenet.store.GetPubkey;
import freenet.store.PubkeyStore;
import freenet.support.ByteArrayWrapper;
import freenet.support.HexUtil;
import freenet.support.LRUMap;
import freenet.support.Logger;
public class NodeGetPubkey implements GetPubkey {
private static volatile boolean logMINOR;
static {
Logger.registerClass(NodeGetPubkey.class);
}
// Debugging stuff
private static final boolean USE_RAM_PUBKEYS_CACHE = true;
private static final int MAX_MEMORY_CACHED_PUBKEYS = 1000;
private final LRUMap<ByteArrayWrapper, DSAPublicKey> cachedPubKeys;
private PubkeyStore pubKeyDatastore;
private PubkeyStore pubKeyDatacache;
private PubkeyStore pubKeyClientcache;
private PubkeyStore pubKeySlashdotcache;
private final Node node;
NodeGetPubkey(Node node) {
cachedPubKeys = LRUMap.createSafeMap(ByteArrayWrapper.FAST_COMPARATOR);
this.node = node;
}
void setDataStore(PubkeyStore pubKeyDatastore, PubkeyStore pubKeyDatacache) {
this.pubKeyDatastore = pubKeyDatastore;
this.pubKeyDatacache = pubKeyDatacache;
}
/* (non-Javadoc)
* @see freenet.node.GetPubkey#getKey(byte[], boolean, boolean, freenet.store.BlockMetadata)
*/
@Override
public DSAPublicKey getKey(byte[] hash, boolean canReadClientCache, boolean forULPR, BlockMetadata meta) {
boolean ignoreOldBlocks = !node.getWriteLocalToDatastore();
if(canReadClientCache) ignoreOldBlocks = false;
ByteArrayWrapper w = new ByteArrayWrapper(hash);
if (logMINOR)
Logger.minor(this, "Getting pubkey: " + HexUtil.bytesToHex(hash));
if (USE_RAM_PUBKEYS_CACHE) {
synchronized (cachedPubKeys) {
DSAPublicKey key = cachedPubKeys.get(w);
if (key != null) {
cachedPubKeys.push(w, key);
if (logMINOR)
Logger.minor(this, "Got " + HexUtil.bytesToHex(hash) + " from in-memory cache");
return key;
}
}
}
try {
DSAPublicKey key = null;
if(pubKeyClientcache != null && canReadClientCache)
key = pubKeyClientcache.fetch(hash, false, false, meta);
if(node.oldPKClientCache != null && canReadClientCache && key == null) {
PubkeyStore pks = node.oldPKClientCache;
if(pks != null) key = pks.fetch(hash, false, false, meta);
if(key != null && logMINOR)
Logger.minor(this, "Got "+HexUtil.bytesToHex(hash)+" from old client cache");
}
// We can *read* from the datastore even if nearby, but we cannot promote in that case.
if(key == null) {
key = pubKeyDatastore.fetch(hash, false, ignoreOldBlocks, meta);
if(key != null && logMINOR)
Logger.minor(this, "Got "+HexUtil.bytesToHex(hash)+" from store");
}
if(key == null) {
PubkeyStore pks = node.oldPK;
if(pks != null) key = pks.fetch(hash, false, ignoreOldBlocks, meta);
if(key != null && logMINOR)
Logger.minor(this, "Got "+HexUtil.bytesToHex(hash)+" from old store");
}
if (key == null) {
key = pubKeyDatacache.fetch(hash, false, ignoreOldBlocks, meta);
if(key != null && logMINOR)
Logger.minor(this, "Got "+HexUtil.bytesToHex(hash)+" from cache");
}
if(key == null) {
PubkeyStore pks = node.oldPKCache;
if(pks != null) key = pks.fetch(hash, false, ignoreOldBlocks, meta);
if(key != null && logMINOR)
Logger.minor(this, "Got "+HexUtil.bytesToHex(hash)+" from old cache");
}
if(key == null && pubKeySlashdotcache != null && forULPR) {
key = pubKeySlashdotcache.fetch(hash, false, ignoreOldBlocks, meta);
if (logMINOR)
Logger.minor(this, "Got " + HexUtil.bytesToHex(hash) + " from slashdot cache");
}
if (key != null) {
// Just put into the in-memory cache
cacheKey(hash, key, false, false, false, false, false);
}
return key;
} catch (IOException e) {
// FIXME deal with disk full, access perms etc; tell user about it.
Logger.error(this, "Error accessing pubkey store: " + e, e);
return null;
}
}
/* (non-Javadoc)
* @see freenet.node.GetPubkey#cacheKey(byte[], freenet.crypt.DSAPublicKey, boolean, boolean, boolean, boolean, boolean)
*/
@Override
public void cacheKey(byte[] hash, DSAPublicKey key, boolean deep, boolean canWriteClientCache, boolean canWriteDatastore, boolean forULPR, boolean writeLocalToDatastore) {
if (logMINOR)
Logger.minor(this, "Cache key: " + HexUtil.bytesToHex(hash) + " : " + key);
ByteArrayWrapper w = new ByteArrayWrapper(hash);
synchronized (cachedPubKeys) {
DSAPublicKey key2 = cachedPubKeys.get(w);
if ((key2 != null) && !key2.equals(key))
throw new IllegalArgumentException("Wrong hash?? Already have different key with same hash!");
cachedPubKeys.push(w, key);
while (cachedPubKeys.size() > MAX_MEMORY_CACHED_PUBKEYS)
cachedPubKeys.popKey();
}
try {
if (canWriteClientCache && !(canWriteDatastore || writeLocalToDatastore)) {
if(pubKeyClientcache != null) {
pubKeyClientcache.put(hash, key, false);
}
}
if (forULPR && !(canWriteDatastore || writeLocalToDatastore)) {
if(pubKeySlashdotcache!= null) {
pubKeySlashdotcache.put(hash, key, false);
}
}
// Cannot write to the store or cache if request started nearby.
if(!(canWriteDatastore || writeLocalToDatastore)) return;
if (deep) {
pubKeyDatastore.put(hash, key, !canWriteDatastore);
}
pubKeyDatacache.put(hash, key, !canWriteDatastore);
} catch (IOException e) {
// FIXME deal with disk full, access perms etc; tell user about it.
Logger.error(this, "Error accessing pubkey store: " + e, e);
}
}
public void setLocalDataStore(PubkeyStore pubKeyClientcache) {
this.pubKeyClientcache = pubKeyClientcache;
}
public void setLocalSlashdotcache(PubkeyStore pubKeySlashdotcache) {
this.pubKeySlashdotcache = pubKeySlashdotcache;
}
}