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; ...@@ -7,7 +7,6 @@ package net.i2p.client.naming;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
...@@ -38,7 +37,6 @@ public class EepGetNamingService extends NamingService { ...@@ -38,7 +37,6 @@ public class EepGetNamingService extends NamingService {
private final static String PROP_EEPGET_LIST = "i2p.naming.eepget.list"; 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 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); private final static Log _log = new Log(EepGetNamingService.class);
/** /**
...@@ -49,7 +47,6 @@ public class EepGetNamingService extends NamingService { ...@@ -49,7 +47,6 @@ public class EepGetNamingService extends NamingService {
*/ */
public EepGetNamingService(I2PAppContext context) { public EepGetNamingService(I2PAppContext context) {
super(context); super(context);
_hosts = new Properties();
} }
private List getURLs() { private List getURLs() {
...@@ -69,11 +66,9 @@ public class EepGetNamingService extends NamingService { ...@@ -69,11 +66,9 @@ public class EepGetNamingService extends NamingService {
hostname = hostname.toLowerCase(); hostname = hostname.toLowerCase();
// check the cache // check the cache
String key = _hosts.getProperty(hostname); Destination d = getCache(hostname);
if (key != null) { if (d != null)
_log.error("Found in cache: " + hostname); return d;
return lookupBase64(key);
}
List URLs = getURLs(); List URLs = getURLs();
if (URLs.size() == 0) if (URLs.size() == 0)
...@@ -91,16 +86,18 @@ public class EepGetNamingService extends NamingService { ...@@ -91,16 +86,18 @@ public class EepGetNamingService extends NamingService {
// lookup // lookup
for (int i = 0; i < URLs.size(); i++) { for (int i = 0; i < URLs.size(); i++) {
String url = (String)URLs.get(i); String url = (String)URLs.get(i);
key = fetchAddr(url, hostname); String key = fetchAddr(url, hostname);
if (key != null) { if (key != null) {
_log.error("Success: " + url + hostname); _log.error("Success: " + url + hostname);
_hosts.setProperty(hostname, key); // cache d = lookupBase64(key);
return lookupBase64(key); putCache(hostname, d);
return d;
} }
} }
return null; 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 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 static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
private String fetchAddr(String url, String hostname) { private String fetchAddr(String url, String hostname) {
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
package net.i2p.client.naming; package net.i2p.client.naming;
import java.io.InputStream; import java.io.InputStream;
import java.util.Properties;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.data.Destination; import net.i2p.data.Destination;
...@@ -47,7 +46,6 @@ public class ExecNamingService extends NamingService { ...@@ -47,7 +46,6 @@ public class ExecNamingService extends NamingService {
private final static String DEFAULT_EXEC_CMD = "/usr/local/bin/i2presolve"; 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 PROP_SHELL_CMD = "i2p.naming.exec.shell";
private final static String DEFAULT_SHELL_CMD = "/bin/bash"; private final static String DEFAULT_SHELL_CMD = "/bin/bash";
private static Properties _hosts;
private final static Log _log = new Log(ExecNamingService.class); private final static Log _log = new Log(ExecNamingService.class);
/** /**
...@@ -58,7 +56,6 @@ public class ExecNamingService extends NamingService { ...@@ -58,7 +56,6 @@ public class ExecNamingService extends NamingService {
*/ */
public ExecNamingService(I2PAppContext context) { public ExecNamingService(I2PAppContext context) {
super(context); super(context);
_hosts = new Properties();
} }
public Destination lookup(String hostname) { public Destination lookup(String hostname) {
...@@ -69,22 +66,22 @@ public class ExecNamingService extends NamingService { ...@@ -69,22 +66,22 @@ public class ExecNamingService extends NamingService {
hostname = hostname.toLowerCase(); hostname = hostname.toLowerCase();
// check the cache // check the cache
String key = _hosts.getProperty(hostname); Destination d = getCache(hostname);
if (key != null) { if (d != null)
_log.error("Found in cache: " + hostname); return d;
return lookupBase64(key);
}
// lookup // lookup
key = fetchAddr(hostname); String key = fetchAddr(hostname);
if (key != null) { if (key != null) {
_log.error("Success: " + hostname); _log.error("Success: " + hostname);
_hosts.setProperty(hostname, key); // cache d = lookupBase64(key);
return lookupBase64(key); putCache(hostname, d);
return d;
} }
return null; 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 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 static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
private String fetchAddr(String hostname) { private String fetchAddr(String hostname) {
......
...@@ -56,13 +56,18 @@ public class HostsTxtNamingService extends NamingService { ...@@ -56,13 +56,18 @@ public class HostsTxtNamingService extends NamingService {
} }
public Destination lookup(String hostname) { public Destination lookup(String hostname) {
Destination d = getCache(hostname);
if (d != null)
return d;
// If it's long, assume it's a key. // If it's long, assume it's a key.
if (hostname.length() >= 516) if (hostname.length() >= 516) {
return lookupBase64(hostname); 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(); List filenames = getFilenames();
for (int i = 0; i < filenames.size(); i++) { for (int i = 0; i < filenames.size(); i++) {
String hostsfile = (String)filenames.get(i); String hostsfile = (String)filenames.get(i);
...@@ -74,7 +79,9 @@ public class HostsTxtNamingService extends NamingService { ...@@ -74,7 +79,9 @@ public class HostsTxtNamingService extends NamingService {
String key = hosts.getProperty(hostname.toLowerCase()); String key = hosts.getProperty(hostname.toLowerCase());
if ( (key != null) && (key.trim().length() > 0) ) { if ( (key != null) && (key.trim().length() > 0) ) {
return lookupBase64(key); d = lookupBase64(key);
putCache(hostname, d);
return d;
} }
} else { } else {
......
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
package net.i2p.client.naming; package net.i2p.client.naming;
import java.lang.reflect.Constructor; 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.I2PAppContext;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
...@@ -21,11 +25,14 @@ public abstract class NamingService { ...@@ -21,11 +25,14 @@ public abstract class NamingService {
private final static Log _log = new Log(NamingService.class); private final static Log _log = new Log(NamingService.class);
protected I2PAppContext _context; protected I2PAppContext _context;
private HashMap _cache;
/** what classname should be used as the naming service impl? */ /** what classname should be used as the naming service impl? */
public static final String PROP_IMPL = "i2p.naming.impl"; public static final String PROP_IMPL = "i2p.naming.impl";
private static final String DEFAULT_IMPL = "net.i2p.client.naming.HostsTxtNamingService"; 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 * The naming service should only be constructed and accessed through the
...@@ -35,6 +42,7 @@ public abstract class NamingService { ...@@ -35,6 +42,7 @@ public abstract class NamingService {
*/ */
protected NamingService(I2PAppContext context) { protected NamingService(I2PAppContext context) {
_context = context; _context = context;
_cache = new HashMap(CACHE_MAX_SIZE);
} }
private NamingService() { // nop private NamingService() { // nop
} }
...@@ -89,4 +97,77 @@ public abstract class NamingService { ...@@ -89,4 +97,77 @@ public abstract class NamingService {
} }
return instance; 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