I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit f6996c7d authored by zzz's avatar zzz
Browse files

* NamingServices: Implement caching in the abstract class

parent fb7f4f2d
No related branches found
No related tags found
No related merge requests found
......@@ -7,7 +7,6 @@ package net.i2p.client.naming;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
......@@ -38,7 +37,6 @@ public class EepGetNamingService extends NamingService {
private final static String PROP_EEPGET_LIST = "i2p.naming.eepget.list";
private final static String DEFAULT_EEPGET_LIST = "http://i2host.i2p/cgi-bin/i2hostquery?";
private static Properties _hosts;
private final static Log _log = new Log(EepGetNamingService.class);
/**
......@@ -49,7 +47,6 @@ public class EepGetNamingService extends NamingService {
*/
public EepGetNamingService(I2PAppContext context) {
super(context);
_hosts = new Properties();
}
private List getURLs() {
......@@ -69,11 +66,9 @@ public class EepGetNamingService extends NamingService {
hostname = hostname.toLowerCase();
// check the cache
String key = _hosts.getProperty(hostname);
if (key != null) {
_log.error("Found in cache: " + hostname);
return lookupBase64(key);
}
Destination d = getCache(hostname);
if (d != null)
return d;
List URLs = getURLs();
if (URLs.size() == 0)
......@@ -91,16 +86,18 @@ public class EepGetNamingService extends NamingService {
// lookup
for (int i = 0; i < URLs.size(); i++) {
String url = (String)URLs.get(i);
key = fetchAddr(url, hostname);
String key = fetchAddr(url, hostname);
if (key != null) {
_log.error("Success: " + url + hostname);
_hosts.setProperty(hostname, key); // cache
return lookupBase64(key);
d = lookupBase64(key);
putCache(hostname, d);
return d;
}
}
return null;
}
// FIXME allow larger Dests for non-null Certs
private static final int DEST_SIZE = 516; // Std. Base64 length (no certificate)
private static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
private String fetchAddr(String url, String hostname) {
......
......@@ -5,7 +5,6 @@
package net.i2p.client.naming;
import java.io.InputStream;
import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.data.Destination;
......@@ -47,7 +46,6 @@ public class ExecNamingService extends NamingService {
private final static String DEFAULT_EXEC_CMD = "/usr/local/bin/i2presolve";
private final static String PROP_SHELL_CMD = "i2p.naming.exec.shell";
private final static String DEFAULT_SHELL_CMD = "/bin/bash";
private static Properties _hosts;
private final static Log _log = new Log(ExecNamingService.class);
/**
......@@ -58,7 +56,6 @@ public class ExecNamingService extends NamingService {
*/
public ExecNamingService(I2PAppContext context) {
super(context);
_hosts = new Properties();
}
public Destination lookup(String hostname) {
......@@ -69,22 +66,22 @@ public class ExecNamingService extends NamingService {
hostname = hostname.toLowerCase();
// check the cache
String key = _hosts.getProperty(hostname);
if (key != null) {
_log.error("Found in cache: " + hostname);
return lookupBase64(key);
}
Destination d = getCache(hostname);
if (d != null)
return d;
// lookup
key = fetchAddr(hostname);
String key = fetchAddr(hostname);
if (key != null) {
_log.error("Success: " + hostname);
_hosts.setProperty(hostname, key); // cache
return lookupBase64(key);
d = lookupBase64(key);
putCache(hostname, d);
return d;
}
return null;
}
// FIXME allow larger Dests for non-null Certs
private static final int DEST_SIZE = 516; // Std. Base64 length (no certificate)
private static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
private String fetchAddr(String hostname) {
......
......@@ -56,13 +56,18 @@ public class HostsTxtNamingService extends NamingService {
}
public Destination lookup(String hostname) {
Destination d = getCache(hostname);
if (d != null)
return d;
// If it's long, assume it's a key.
if (hostname.length() >= 516)
return lookupBase64(hostname);
if (hostname.length() >= 516) {
d = lookupBase64(hostname);
// What the heck, cache these too
putCache(hostname, d);
return d;
}
// check the list each time, reloading the file on each
// lookup
List filenames = getFilenames();
for (int i = 0; i < filenames.size(); i++) {
String hostsfile = (String)filenames.get(i);
......@@ -74,7 +79,9 @@ public class HostsTxtNamingService extends NamingService {
String key = hosts.getProperty(hostname.toLowerCase());
if ( (key != null) && (key.trim().length() > 0) ) {
return lookupBase64(key);
d = lookupBase64(key);
putCache(hostname, d);
return d;
}
} else {
......
......@@ -8,6 +8,10 @@
package net.i2p.client.naming;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
......@@ -21,11 +25,14 @@ public abstract class NamingService {
private final static Log _log = new Log(NamingService.class);
protected I2PAppContext _context;
private HashMap _cache;
/** what classname should be used as the naming service impl? */
public static final String PROP_IMPL = "i2p.naming.impl";
private static final String DEFAULT_IMPL = "net.i2p.client.naming.HostsTxtNamingService";
protected static final int CACHE_MAX_SIZE = 8;
/**
* The naming service should only be constructed and accessed through the
......@@ -35,6 +42,7 @@ public abstract class NamingService {
*/
protected NamingService(I2PAppContext context) {
_context = context;
_cache = new HashMap(CACHE_MAX_SIZE);
}
private NamingService() { // nop
}
......@@ -89,4 +97,77 @@ public abstract class NamingService {
}
return instance;
}
/**
* Provide basic caching for the service
* The service may override the age and/or size limit
*/
/** Don't know why a dest would ever change but keep this short anyway */
protected static final long CACHE_MAX_AGE = 60*1000;
private class CacheEntry {
public Destination dest;
public long exp;
public CacheEntry(Destination d) {
dest = d;
exp = _context.clock().now() + CACHE_MAX_AGE;
}
public boolean isExpired() {
return exp < _context.clock().now();
}
}
/**
* Clean up when full.
* Don't bother removing old entries unless full.
* Caller must synchronize on _cache.
*/
private void cacheClean() {
if (_cache.size() < CACHE_MAX_SIZE)
return;
boolean full = true;
Object oldestKey = null;
long oldestExp = Long.MAX_VALUE;
ArrayList deleteList = new ArrayList(CACHE_MAX_SIZE);
for (Iterator iter = _cache.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry) iter.next();
CacheEntry ce = (CacheEntry) entry.getValue();
if (ce.isExpired()) {
deleteList.add(entry.getKey());
full = false;
continue;
}
if (oldestKey == null || ce.exp < oldestExp) {
oldestKey = entry.getKey();
oldestExp = ce.exp;
}
}
if (full && oldestKey != null)
deleteList.add(oldestKey);
for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
_cache.remove(iter.next());
}
}
protected void putCache(String s, Destination d) {
if (d == null)
return;
synchronized (_cache) {
_cache.put(s, new CacheEntry(d));
cacheClean();
}
}
protected Destination getCache(String s) {
synchronized (_cache) {
CacheEntry ce = (CacheEntry) _cache.get(s);
if (ce == null)
return null;
if (ce.isExpired()) {
_cache.remove(s);
return null;
}
return ce.dest;
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment