2005-04-24 jrandom
* Added a pool of PRNGs using a different synchronization technique, hopefully sufficient to work around IBM's PRNG bugs until we get our own Fortuna. * In the streaming lib, don't jack up the RTT on NACK, and have the window size bound the not-yet-ready messages to the peer, not the unacked message count (not sure yet whether this is worthwile). * Many additions to the messageHistory log. * Handle out of order tunnel fragment delivery (not an issue on the live net with TCP, but critical with UDP). and for udp stuff: * implemented tcp-esque rto code in the udp transport * make sure we don't ACK too many messages at once * transmit fragments in a simple (nonrandom) order so that we can more easily adjust timeouts/etc. * let the active outbound pool grow dynamically if there are outbound slots to spare * use a simple decaying bloom filter at the UDP level to drop duplicate resent packets.
This commit is contained in:
@ -22,6 +22,7 @@ import net.i2p.stat.StatManager;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.LogManager;
|
||||
import net.i2p.util.RandomSource;
|
||||
import net.i2p.util.PooledRandomSource;
|
||||
|
||||
/**
|
||||
* <p>Provide a base scope for accessing singletons that I2P exposes. Rather than
|
||||
@ -432,7 +433,7 @@ public class I2PAppContext {
|
||||
private void initializeRandom() {
|
||||
synchronized (this) {
|
||||
if (_random == null)
|
||||
_random = new RandomSource(this);
|
||||
_random = new PooledRandomSource(this);
|
||||
_randomInitialized = true;
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,29 @@ public class DecayingBloomFilter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if the entry is already known. this does NOT add the
|
||||
* entry however.
|
||||
*
|
||||
*/
|
||||
public boolean isKnown(long entry) {
|
||||
synchronized (this) {
|
||||
if (_entryBytes <= 7)
|
||||
entry &= _longToEntryMask;
|
||||
if (entry < 0) {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, 0-entry);
|
||||
_longToEntry[0] |= (1 << 7);
|
||||
} else {
|
||||
DataHelper.toLong(_longToEntry, 0, _entryBytes, entry);
|
||||
}
|
||||
return locked_add(_longToEntry, false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean locked_add(byte entry[]) {
|
||||
return locked_add(entry, true);
|
||||
}
|
||||
private boolean locked_add(byte entry[], boolean addIfNew) {
|
||||
if (_extended != null) {
|
||||
// extend the entry to 32 bytes
|
||||
System.arraycopy(entry, 0, _extended, 0, entry.length);
|
||||
@ -121,8 +143,10 @@ public class DecayingBloomFilter {
|
||||
_currentDuplicates++;
|
||||
return true;
|
||||
} else {
|
||||
_current.insert(_extended);
|
||||
_previous.insert(_extended);
|
||||
if (addIfNew) {
|
||||
_current.insert(_extended);
|
||||
_previous.insert(_extended);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@ -132,8 +156,10 @@ public class DecayingBloomFilter {
|
||||
_currentDuplicates++;
|
||||
return true;
|
||||
} else {
|
||||
_current.locked_insert(entry);
|
||||
_previous.locked_insert(entry);
|
||||
if (addIfNew) {
|
||||
_current.locked_insert(entry);
|
||||
_previous.locked_insert(entry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ public class LogManager {
|
||||
public Log getLog(String name) { return getLog(null, name); }
|
||||
public Log getLog(Class cls, String name) {
|
||||
Log rv = null;
|
||||
String scope = Log.getScope(name, cls);
|
||||
synchronized (_logs) {
|
||||
String scope = Log.getScope(name, cls);
|
||||
rv = (Log)_logs.get(scope);
|
||||
if (rv == null) {
|
||||
rv = new Log(this, cls, name);
|
||||
@ -154,10 +154,7 @@ public class LogManager {
|
||||
public List getLogs() {
|
||||
List rv = null;
|
||||
synchronized (_logs) {
|
||||
rv = new ArrayList(_logs.size());
|
||||
for (Iterator iter = _logs.values().iterator(); iter.hasNext(); ) {
|
||||
rv.add(iter.next());
|
||||
}
|
||||
rv = new ArrayList(_logs.values());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
141
core/java/src/net/i2p/util/PooledRandomSource.java
Normal file
141
core/java/src/net/i2p/util/PooledRandomSource.java
Normal file
@ -0,0 +1,141 @@
|
||||
package net.i2p.util;
|
||||
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2005 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.EntropyHarvester;
|
||||
|
||||
/**
|
||||
* Maintain a set of PRNGs to feed the apps
|
||||
*/
|
||||
public class PooledRandomSource extends RandomSource {
|
||||
private Log _log;
|
||||
private RandomSource _pool[];
|
||||
private volatile int _nextPool;
|
||||
|
||||
private static final int POOL_SIZE = 16;
|
||||
|
||||
public PooledRandomSource(I2PAppContext context) {
|
||||
super(context);
|
||||
_log = context.logManager().getLog(PooledRandomSource.class);
|
||||
_pool = new RandomSource[POOL_SIZE];
|
||||
for (int i = 0; i < POOL_SIZE; i++) {
|
||||
_pool[i] = new RandomSource(context);
|
||||
_pool[i].nextBoolean();
|
||||
}
|
||||
_nextPool = 0;
|
||||
}
|
||||
|
||||
private final RandomSource pickPRNG() {
|
||||
return _pool[(_nextPool++) % POOL_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* According to the java docs (http://java.sun.com/j2se/1.4.1/docs/api/java/util/Random.html#nextInt(int))
|
||||
* nextInt(n) should return a number between 0 and n (including 0 and excluding n). However, their pseudocode,
|
||||
* as well as sun's, kaffe's, and classpath's implementation INCLUDES NEGATIVE VALUES.
|
||||
* WTF. Ok, so we're going to have it return between 0 and n (including 0, excluding n), since
|
||||
* thats what it has been used for.
|
||||
*
|
||||
*/
|
||||
public int nextInt(int n) {
|
||||
RandomSource prng = pickPRNG();
|
||||
synchronized (prng) {
|
||||
return prng.nextInt(n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the modified nextInt, nextLong(n) returns a random number from 0 through n,
|
||||
* including 0, excluding n.
|
||||
*/
|
||||
public long nextLong(long n) {
|
||||
RandomSource prng = pickPRNG();
|
||||
synchronized (prng) {
|
||||
return prng.nextLong(n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public boolean nextBoolean() {
|
||||
RandomSource prng = pickPRNG();
|
||||
synchronized (prng) {
|
||||
return prng.nextBoolean();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public void nextBytes(byte buf[]) {
|
||||
RandomSource prng = pickPRNG();
|
||||
synchronized (prng) {
|
||||
prng.nextBytes(buf);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public double nextDouble() {
|
||||
RandomSource prng = pickPRNG();
|
||||
synchronized (prng) {
|
||||
return prng.nextDouble();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public float nextFloat() {
|
||||
RandomSource prng = pickPRNG();
|
||||
synchronized (prng) {
|
||||
return prng.nextFloat();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public double nextGaussian() {
|
||||
RandomSource prng = pickPRNG();
|
||||
synchronized (prng) {
|
||||
return prng.nextGaussian();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public int nextInt() {
|
||||
RandomSource prng = pickPRNG();
|
||||
synchronized (prng) {
|
||||
return prng.nextInt();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public long nextLong() {
|
||||
RandomSource prng = pickPRNG();
|
||||
synchronized (prng) {
|
||||
return prng.nextLong();
|
||||
}
|
||||
}
|
||||
|
||||
public EntropyHarvester harvester() {
|
||||
RandomSource prng = pickPRNG();
|
||||
return prng.harvester();
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ public class RandomSource extends SecureRandom {
|
||||
* thats what it has been used for.
|
||||
*
|
||||
*/
|
||||
public synchronized int nextInt(int n) {
|
||||
public int nextInt(int n) {
|
||||
if (n == 0) return 0;
|
||||
int val = super.nextInt(n);
|
||||
if (val < 0) val = 0 - val;
|
||||
@ -54,7 +54,7 @@ public class RandomSource extends SecureRandom {
|
||||
* Like the modified nextInt, nextLong(n) returns a random number from 0 through n,
|
||||
* including 0, excluding n.
|
||||
*/
|
||||
public synchronized long nextLong(long n) {
|
||||
public long nextLong(long n) {
|
||||
long v = super.nextLong();
|
||||
if (v < 0) v = 0 - v;
|
||||
if (v >= n) v = v % n;
|
||||
@ -65,37 +65,37 @@ public class RandomSource extends SecureRandom {
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public synchronized boolean nextBoolean() { return super.nextBoolean(); }
|
||||
public boolean nextBoolean() { return super.nextBoolean(); }
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public synchronized void nextBytes(byte buf[]) { super.nextBytes(buf); }
|
||||
public void nextBytes(byte buf[]) { super.nextBytes(buf); }
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public synchronized double nextDouble() { return super.nextDouble(); }
|
||||
public double nextDouble() { return super.nextDouble(); }
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public synchronized float nextFloat() { return super.nextFloat(); }
|
||||
public float nextFloat() { return super.nextFloat(); }
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public synchronized double nextGaussian() { return super.nextGaussian(); }
|
||||
public double nextGaussian() { return super.nextGaussian(); }
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public synchronized int nextInt() { return super.nextInt(); }
|
||||
public int nextInt() { return super.nextInt(); }
|
||||
/**
|
||||
* override as synchronized, for those JVMs that don't always pull via
|
||||
* nextBytes (cough ibm)
|
||||
*/
|
||||
public synchronized long nextLong() { return super.nextLong(); }
|
||||
public long nextLong() { return super.nextLong(); }
|
||||
|
||||
public EntropyHarvester harvester() { return _entropyHarvester; }
|
||||
|
||||
|
Reference in New Issue
Block a user