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:
jrandom
2005-04-24 18:42:02 +00:00
committed by zzz
parent dae6be14b7
commit b2f0d17e94
25 changed files with 517 additions and 97 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View 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();
}
}

View File

@ -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; }