forked from I2P_Developers/i2p.i2p
* IP Lookup:
- Add caching in RouterAddress with secondary caching in Addresses; use caches to speed up transport bids, blocklist checks, geoip lookups, and profile organizer checks (ticket #707) - Limit IP cache size in TransportImpl - Clear caches at shutdown * RouterAddress: Remove unused expiration field to save space
This commit is contained in:
@ -17,6 +17,7 @@ import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.OrderedProperties;
|
||||
|
||||
/**
|
||||
@ -33,9 +34,15 @@ import net.i2p.util.OrderedProperties;
|
||||
*/
|
||||
public class RouterAddress extends DataStructureImpl {
|
||||
private int _cost;
|
||||
private Date _expiration;
|
||||
//private Date _expiration;
|
||||
private String _transportStyle;
|
||||
private final Properties _options;
|
||||
// cached values
|
||||
private byte[] _ip;
|
||||
private int _port;
|
||||
|
||||
public static final String PROP_HOST = "host";
|
||||
public static final String PROP_PORT = "port";
|
||||
|
||||
public RouterAddress() {
|
||||
_cost = -1;
|
||||
@ -68,18 +75,21 @@ public class RouterAddress extends DataStructureImpl {
|
||||
* is null, then the address never expires.
|
||||
*
|
||||
* @deprecated unused for now
|
||||
* @return null always
|
||||
*/
|
||||
public Date getExpiration() {
|
||||
return _expiration;
|
||||
//return _expiration;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the expiration date of the address (null for no expiration)
|
||||
*
|
||||
* Unused for now, always null
|
||||
* @deprecated unused for now
|
||||
*/
|
||||
public void setExpiration(Date expiration) {
|
||||
_expiration = expiration;
|
||||
//_expiration = expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,6 +150,51 @@ public class RouterAddress extends DataStructureImpl {
|
||||
_options.putAll(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Caching version of InetAddress.getByName(getOption("host")).getAddress(), which is slow.
|
||||
* Caches numeric host names only.
|
||||
* Will resolve but not cache resolution of DNS host names.
|
||||
*
|
||||
* @return IP or null
|
||||
* @since 0.9.3
|
||||
*/
|
||||
public byte[] getIP() {
|
||||
if (_ip != null)
|
||||
return _ip;
|
||||
byte[] rv = null;
|
||||
String host = _options.getProperty(PROP_HOST);
|
||||
if (host != null) {
|
||||
rv = Addresses.getIP(host);
|
||||
if (rv != null &&
|
||||
(host.replaceAll("[0-9\\.]", "").length() == 0 ||
|
||||
host.replaceAll("[0-9a-fA-F:]", "").length() == 0)) {
|
||||
_ip = rv;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caching version of Integer.parseInt(getOption("port"))
|
||||
* Caches valid ports 1-65535 only.
|
||||
*
|
||||
* @return 1-65535 or 0 if invalid
|
||||
* @since 0.9.3
|
||||
*/
|
||||
public int getPort() {
|
||||
if (_port != 0)
|
||||
return _port;
|
||||
String port = _options.getProperty(PROP_PORT);
|
||||
if (port != null) {
|
||||
try {
|
||||
int rv = Integer.parseInt(port);
|
||||
if (rv > 0 && rv <= 65535)
|
||||
_port = rv;
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
return _port;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalStateException if was already read in
|
||||
*/
|
||||
@ -147,7 +202,8 @@ public class RouterAddress extends DataStructureImpl {
|
||||
if (_transportStyle != null)
|
||||
throw new IllegalStateException();
|
||||
_cost = (int) DataHelper.readLong(in, 1);
|
||||
_expiration = DataHelper.readDate(in);
|
||||
//_expiration = DataHelper.readDate(in);
|
||||
DataHelper.readDate(in);
|
||||
_transportStyle = DataHelper.readString(in);
|
||||
// reduce Object proliferation
|
||||
if (_transportStyle.equals("SSU"))
|
||||
@ -161,7 +217,8 @@ public class RouterAddress extends DataStructureImpl {
|
||||
if ((_cost < 0) || (_transportStyle == null))
|
||||
throw new DataFormatException("Not enough data to write a router address");
|
||||
DataHelper.writeLong(out, 1, _cost);
|
||||
DataHelper.writeDate(out, _expiration);
|
||||
//DataHelper.writeDate(out, _expiration);
|
||||
DataHelper.writeDate(out, null);
|
||||
DataHelper.writeString(out, _transportStyle);
|
||||
DataHelper.writeProperties(out, _options);
|
||||
}
|
||||
@ -198,15 +255,13 @@ public class RouterAddress extends DataStructureImpl {
|
||||
buf.append("[RouterAddress: ");
|
||||
buf.append("\n\tTransportStyle: ").append(_transportStyle);
|
||||
buf.append("\n\tCost: ").append(_cost);
|
||||
buf.append("\n\tExpiration: ").append(_expiration);
|
||||
if (_options != null) {
|
||||
//buf.append("\n\tExpiration: ").append(_expiration);
|
||||
buf.append("\n\tOptions: #: ").append(_options.size());
|
||||
for (Map.Entry e : _options.entrySet()) {
|
||||
String key = (String) e.getKey();
|
||||
String val = (String) e.getValue();
|
||||
buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
|
||||
}
|
||||
}
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
@ -10,10 +10,13 @@ import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
|
||||
/**
|
||||
* Methods to get the local addresses, and other IP utilities
|
||||
@ -152,6 +155,69 @@ public abstract class Addresses {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Textual IP to bytes, because InetAddress.getByName() is slow.
|
||||
*
|
||||
* @since 0.9.3
|
||||
*/
|
||||
private static final Map<String, byte[]> _IPAddress;
|
||||
|
||||
static {
|
||||
int size;
|
||||
I2PAppContext ctx = I2PAppContext.getCurrentContext();
|
||||
if (ctx != null && ctx.isRouterContext()) {
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
if (maxMemory == Long.MAX_VALUE)
|
||||
maxMemory = 96*1024*1024l;
|
||||
long min = 128;
|
||||
long max = 4096;
|
||||
// 512 nominal for 128 MB
|
||||
size = (int) Math.max(min, Math.min(max, 1 + (maxMemory / (256*1024))));
|
||||
} else {
|
||||
size = 32;
|
||||
}
|
||||
_IPAddress = new LHMCache(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Caching version of InetAddress.getByName(host).getAddress(), which is slow.
|
||||
* Caches numeric host names only.
|
||||
* Will resolve but not cache DNS host names.
|
||||
*
|
||||
* @param host DNS or IPv4 or IPv6 host name; if null returns null
|
||||
* @return IP or null
|
||||
* @since 0.9.3
|
||||
*/
|
||||
public static byte[] getIP(String host) {
|
||||
if (host == null)
|
||||
return null;
|
||||
byte[] rv;
|
||||
synchronized (_IPAddress) {
|
||||
rv = _IPAddress.get(host);
|
||||
}
|
||||
if (rv == null) {
|
||||
try {
|
||||
rv = InetAddress.getByName(host).getAddress();
|
||||
if (host.replaceAll("[0-9\\.]", "").length() == 0 ||
|
||||
host.replaceAll("[0-9a-fA-F:]", "").length() == 0) {
|
||||
synchronized (_IPAddress) {
|
||||
_IPAddress.put(host, rv);
|
||||
}
|
||||
}
|
||||
} catch (UnknownHostException uhe) {}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.3
|
||||
*/
|
||||
public static void clearCaches() {
|
||||
synchronized(_IPAddress) {
|
||||
_IPAddress.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print out the local addresses
|
||||
*/
|
||||
|
Reference in New Issue
Block a user