forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p.zzz.test2' (head b6de226d1664089488ab2b438fe7457e9fb8e563)
to branch 'i2p.i2p' (head 0cf35c87b68a5360bd35257e36dfe7f740e53693)
This commit is contained in:
@ -75,7 +75,7 @@ public class JobQueue {
|
||||
|
||||
/** default max # job queue runners operating */
|
||||
private final static int DEFAULT_MAX_RUNNERS = 1;
|
||||
/** router.config parameter to override the max runners @deprecated unimplemented */
|
||||
/** router.config parameter to override the max runners */
|
||||
private final static String PROP_MAX_RUNNERS = "router.maxJobRunners";
|
||||
|
||||
/** how frequently should we check and update the max runners */
|
||||
@ -330,7 +330,7 @@ public class JobQueue {
|
||||
|
||||
public void allowParallelOperation() {
|
||||
_allowParallelOperation = true;
|
||||
runQueue(RUNNERS);
|
||||
runQueue(_context.getProperty(PROP_MAX_RUNNERS, RUNNERS));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,15 +8,10 @@ package net.i2p.router;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
@ -49,7 +44,6 @@ import net.i2p.router.util.EventLog;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.stat.StatManager;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.FortunaRandomSource;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.I2PThread;
|
||||
@ -113,6 +107,7 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
private final static String DNS_CACHE_TIME = "" + (5*60);
|
||||
private static final String EVENTLOG = "eventlog.txt";
|
||||
private static final String PROP_JBIGI = "jbigi.loadedResource";
|
||||
public static final String UPDATE_FILE = "i2pupdate.zip";
|
||||
|
||||
private static final String originalTimeZoneID;
|
||||
static {
|
||||
@ -1497,199 +1492,11 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
// If it does an update, it never returns.
|
||||
// I guess it's better to have the other-router check above this, we don't want to
|
||||
// overwrite an existing running router's jar files. Other than ours.
|
||||
r.installUpdates();
|
||||
InstallUpdate.installUpdates(r);
|
||||
// ********* Start no threads before here ********* //
|
||||
r.runRouter();
|
||||
}
|
||||
}
|
||||
|
||||
public static final String UPDATE_FILE = "i2pupdate.zip";
|
||||
private static final String DELETE_FILE = "deletelist.txt";
|
||||
|
||||
/**
|
||||
* Context must be available.
|
||||
* Unzip update file found in the router dir OR base dir, to the base dir
|
||||
*
|
||||
* If successful, will call exit() and never return.
|
||||
*
|
||||
* If we can't write to the base dir, complain.
|
||||
* Note: _log not available here.
|
||||
*/
|
||||
private void installUpdates() {
|
||||
File updateFile = new File(_context.getRouterDir(), UPDATE_FILE);
|
||||
boolean exists = updateFile.exists();
|
||||
if (!exists) {
|
||||
updateFile = new File(_context.getBaseDir(), UPDATE_FILE);
|
||||
exists = updateFile.exists();
|
||||
}
|
||||
if (exists) {
|
||||
// do a simple permissions test, if it fails leave the file in place and don't restart
|
||||
File test = new File(_context.getBaseDir(), "history.txt");
|
||||
if ((test.exists() && !test.canWrite()) || (!_context.getBaseDir().canWrite())) {
|
||||
System.out.println("ERROR: No write permissions on " + _context.getBaseDir() +
|
||||
" to extract software update file");
|
||||
// carry on
|
||||
return;
|
||||
}
|
||||
System.out.println("INFO: Update file exists [" + UPDATE_FILE + "] - installing");
|
||||
// verify the whole thing first
|
||||
// we could remember this fails, and not bother restarting, but who cares...
|
||||
boolean ok = FileUtil.verifyZip(updateFile);
|
||||
if (ok) {
|
||||
// This may be useful someday. First added in 0.8.2
|
||||
// Moved above the extract so we don't NCDFE
|
||||
_config.put("router.updateLastInstalled", "" + System.currentTimeMillis());
|
||||
// Set the last version to the current version, since 0.8.13
|
||||
_config.put("router.previousVersion", RouterVersion.VERSION);
|
||||
_config.put("router.previousFullVersion", RouterVersion.FULL_VERSION);
|
||||
saveConfig();
|
||||
ok = FileUtil.extractZip(updateFile, _context.getBaseDir());
|
||||
}
|
||||
|
||||
// Very important - we have now trashed our jars.
|
||||
// After this point, do not use any new I2P classes, or they will fail to load
|
||||
// and we will die with NCDFE.
|
||||
// Ideally, do not use I2P classes at all, new or not.
|
||||
try {
|
||||
if (ok) {
|
||||
// We do this here so we may delete old jars before we restart
|
||||
deleteListedFiles();
|
||||
System.out.println("INFO: Update installed");
|
||||
} else {
|
||||
System.out.println("ERROR: Update failed!");
|
||||
}
|
||||
if (!ok) {
|
||||
// we can't leave the file in place or we'll continually restart, so rename it
|
||||
File bad = new File(_context.getRouterDir(), "BAD-" + UPDATE_FILE);
|
||||
boolean renamed = updateFile.renameTo(bad);
|
||||
if (renamed) {
|
||||
System.out.println("Moved update file to " + bad.getAbsolutePath());
|
||||
} else {
|
||||
System.out.println("Deleting file " + updateFile.getAbsolutePath());
|
||||
ok = true; // so it will be deleted
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
boolean deleted = updateFile.delete();
|
||||
if (!deleted) {
|
||||
System.out.println("ERROR: Unable to delete the update file!");
|
||||
updateFile.deleteOnExit();
|
||||
}
|
||||
}
|
||||
// exit whether ok or not
|
||||
if (_context.hasWrapper())
|
||||
System.out.println("INFO: Restarting after update");
|
||||
else
|
||||
System.out.println("WARNING: Exiting after update, restart I2P");
|
||||
} catch (Throwable t) {
|
||||
// hide the NCDFE
|
||||
// hopefully the update file got deleted or we will loop
|
||||
}
|
||||
System.exit(EXIT_HARD_RESTART);
|
||||
} else {
|
||||
deleteJbigiFiles();
|
||||
// It was here starting in 0.8.12 so it could be used the very first time
|
||||
// Now moved up so it is usually run only after an update
|
||||
// But the first time before jetty 6 it will run here...
|
||||
// Here we can't remove jars
|
||||
deleteListedFiles();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove extracted libjbigi.so and libjcpuid.so files if we have a newer jbigi.jar,
|
||||
* so the new ones will be extracted.
|
||||
* We do this after the restart, not after the extract, because it's safer, and
|
||||
* because people may upgrade their jbigi.jar file manually.
|
||||
*
|
||||
* Copied from NativeBigInteger, which we can't access here or the
|
||||
* libs will get loaded.
|
||||
*/
|
||||
private void deleteJbigiFiles() {
|
||||
boolean isX86 = SystemVersion.isX86();
|
||||
String osName = System.getProperty("os.name").toLowerCase(Locale.US);
|
||||
boolean isWin = SystemVersion.isWindows();
|
||||
boolean isMac = SystemVersion.isMac();
|
||||
// only do this on these OSes
|
||||
boolean goodOS = isWin || isMac ||
|
||||
osName.contains("linux") || osName.contains("freebsd");
|
||||
|
||||
// only do this on these x86
|
||||
File jbigiJar = new File(_context.getBaseDir(), "lib/jbigi.jar");
|
||||
if (isX86 && goodOS && jbigiJar.exists()) {
|
||||
String libPrefix = (isWin ? "" : "lib");
|
||||
String libSuffix = (isWin ? ".dll" : isMac ? ".jnilib" : ".so");
|
||||
|
||||
File jcpuidLib = new File(_context.getBaseDir(), libPrefix + "jcpuid" + libSuffix);
|
||||
if (jcpuidLib.canWrite() && jbigiJar.lastModified() > jcpuidLib.lastModified()) {
|
||||
String path = jcpuidLib.getAbsolutePath();
|
||||
boolean success = FileUtil.copy(path, path + ".bak", true, true);
|
||||
if (success) {
|
||||
boolean success2 = jcpuidLib.delete();
|
||||
if (success2) {
|
||||
System.out.println("New jbigi.jar detected, moved jcpuid library to " +
|
||||
path + ".bak");
|
||||
System.out.println("Check logs for successful installation of new library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File jbigiLib = new File(_context.getBaseDir(), libPrefix + "jbigi" + libSuffix);
|
||||
if (jbigiLib.canWrite() && jbigiJar.lastModified() > jbigiLib.lastModified()) {
|
||||
String path = jbigiLib.getAbsolutePath();
|
||||
boolean success = FileUtil.copy(path, path + ".bak", true, true);
|
||||
if (success) {
|
||||
boolean success2 = jbigiLib.delete();
|
||||
if (success2) {
|
||||
System.out.println("New jbigi.jar detected, moved jbigi library to " +
|
||||
path + ".bak");
|
||||
System.out.println("Check logs for successful installation of new library");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all files listed in the delete file.
|
||||
* Format: One file name per line, comment lines start with '#'.
|
||||
* All file names must be relative to $I2P, absolute file names not allowed.
|
||||
* We probably can't remove old jars this way.
|
||||
* Fails silently.
|
||||
* Use no new I2P classes here so it may be called after zip extraction.
|
||||
* @since 0.8.12
|
||||
*/
|
||||
private void deleteListedFiles() {
|
||||
File deleteFile = new File(_context.getBaseDir(), DELETE_FILE);
|
||||
if (!deleteFile.exists())
|
||||
return;
|
||||
// this is similar to FileUtil.readTextFile() but we can't use any I2P classes here
|
||||
FileInputStream fis = null;
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
fis = new FileInputStream(deleteFile);
|
||||
in = new BufferedReader(new InputStreamReader(fis, "UTF-8"));
|
||||
String line;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
String fl = line.trim();
|
||||
if (fl.contains("..") || fl.startsWith("#") || fl.length() == 0)
|
||||
continue;
|
||||
File df = new File(fl);
|
||||
if (df.isAbsolute())
|
||||
continue;
|
||||
df = new File(_context.getBaseDir(), fl);
|
||||
if (df.exists() && !df.isDirectory()) {
|
||||
if (df.delete())
|
||||
System.out.println("INFO: File [" + fl + "] deleted");
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
finally {
|
||||
if (in != null) try { in.close(); } catch(IOException ioe) {}
|
||||
if (deleteFile.delete())
|
||||
System.out.println("INFO: File [" + DELETE_FILE + "] deleted");
|
||||
}
|
||||
}
|
||||
|
||||
/*******
|
||||
private static void verifyWrapperConfig() {
|
||||
|
215
router/java/src/net/i2p/router/tasks/InstallUpdate.java
Normal file
215
router/java/src/net/i2p/router/tasks/InstallUpdate.java
Normal file
@ -0,0 +1,215 @@
|
||||
package net.i2p.router.tasks;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.RouterVersion;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
/**
|
||||
* If the i2pupdate.zip file is present,
|
||||
* unzip it and JVM exit.
|
||||
*
|
||||
* @since 0.9.20 moved from Router.java
|
||||
*/
|
||||
public class InstallUpdate {
|
||||
|
||||
private static final String DELETE_FILE = "deletelist.txt";
|
||||
|
||||
/**
|
||||
* Context must be available.
|
||||
* Unzip update file found in the router dir OR base dir, to the base dir
|
||||
*
|
||||
* If successful, will call exit() and never return.
|
||||
*
|
||||
* If we can't write to the base dir, write message to System.out and return.
|
||||
* Note: _log not available here.
|
||||
*/
|
||||
public static void installUpdates(Router r) {
|
||||
RouterContext context = r.getContext();
|
||||
File updateFile = new File(context.getRouterDir(), Router.UPDATE_FILE);
|
||||
boolean exists = updateFile.exists();
|
||||
if (!exists) {
|
||||
updateFile = new File(context.getBaseDir(), Router.UPDATE_FILE);
|
||||
exists = updateFile.exists();
|
||||
}
|
||||
if (exists) {
|
||||
// do a simple permissions test, if it fails leave the file in place and don't restart
|
||||
File test = new File(context.getBaseDir(), "history.txt");
|
||||
if ((test.exists() && !test.canWrite()) || (!context.getBaseDir().canWrite())) {
|
||||
System.out.println("ERROR: No write permissions on " + context.getBaseDir() +
|
||||
" to extract software update file");
|
||||
// carry on
|
||||
return;
|
||||
}
|
||||
System.out.println("INFO: Update file exists [" + Router.UPDATE_FILE + "] - installing");
|
||||
// verify the whole thing first
|
||||
// we could remember this fails, and not bother restarting, but who cares...
|
||||
boolean ok = FileUtil.verifyZip(updateFile);
|
||||
if (ok) {
|
||||
// This may be useful someday. First added in 0.8.2
|
||||
// Moved above the extract so we don't NCDFE
|
||||
Map<String, String> config = new HashMap<String, String>(4);
|
||||
config.put("router.updateLastInstalled", "" + System.currentTimeMillis());
|
||||
// Set the last version to the current version, since 0.8.13
|
||||
config.put("router.previousVersion", RouterVersion.VERSION);
|
||||
config.put("router.previousFullVersion", RouterVersion.FULL_VERSION);
|
||||
r.saveConfig(config, null);
|
||||
ok = FileUtil.extractZip(updateFile, context.getBaseDir());
|
||||
}
|
||||
|
||||
// Very important - we have now trashed our jars.
|
||||
// After this point, do not use any new I2P classes, or they will fail to load
|
||||
// and we will die with NCDFE.
|
||||
// Ideally, do not use I2P classes at all, new or not.
|
||||
try {
|
||||
if (ok) {
|
||||
// We do this here so we may delete old jars before we restart
|
||||
deleteListedFiles(context);
|
||||
System.out.println("INFO: Update installed");
|
||||
} else {
|
||||
System.out.println("ERROR: Update failed!");
|
||||
}
|
||||
if (!ok) {
|
||||
// we can't leave the file in place or we'll continually restart, so rename it
|
||||
File bad = new File(context.getRouterDir(), "BAD-" + Router.UPDATE_FILE);
|
||||
boolean renamed = updateFile.renameTo(bad);
|
||||
if (renamed) {
|
||||
System.out.println("Moved update file to " + bad.getAbsolutePath());
|
||||
} else {
|
||||
System.out.println("Deleting file " + updateFile.getAbsolutePath());
|
||||
ok = true; // so it will be deleted
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
boolean deleted = updateFile.delete();
|
||||
if (!deleted) {
|
||||
System.out.println("ERROR: Unable to delete the update file!");
|
||||
updateFile.deleteOnExit();
|
||||
}
|
||||
}
|
||||
// exit whether ok or not
|
||||
if (context.hasWrapper())
|
||||
System.out.println("INFO: Restarting after update");
|
||||
else
|
||||
System.out.println("WARNING: Exiting after update, restart I2P");
|
||||
} catch (Throwable t) {
|
||||
// hide the NCDFE
|
||||
// hopefully the update file got deleted or we will loop
|
||||
}
|
||||
System.exit(Router.EXIT_HARD_RESTART);
|
||||
} else {
|
||||
deleteJbigiFiles(context);
|
||||
// It was here starting in 0.8.12 so it could be used the very first time
|
||||
// Now moved up so it is usually run only after an update
|
||||
// But the first time before jetty 6 it will run here...
|
||||
// Here we can't remove jars
|
||||
deleteListedFiles(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove extracted libjbigi.so and libjcpuid.so files if we have a newer jbigi.jar,
|
||||
* so the new ones will be extracted.
|
||||
* We do this after the restart, not after the extract, because it's safer, and
|
||||
* because people may upgrade their jbigi.jar file manually.
|
||||
*
|
||||
* Copied from NativeBigInteger, which we can't access here or the
|
||||
* libs will get loaded.
|
||||
*/
|
||||
private static void deleteJbigiFiles(RouterContext context) {
|
||||
boolean isX86 = SystemVersion.isX86();
|
||||
String osName = System.getProperty("os.name").toLowerCase(Locale.US);
|
||||
boolean isWin = SystemVersion.isWindows();
|
||||
boolean isMac = SystemVersion.isMac();
|
||||
// only do this on these OSes
|
||||
boolean goodOS = isWin || isMac ||
|
||||
osName.contains("linux") || osName.contains("freebsd");
|
||||
|
||||
// only do this on these x86
|
||||
File jbigiJar = new File(context.getBaseDir(), "lib/jbigi.jar");
|
||||
if (isX86 && goodOS && jbigiJar.exists()) {
|
||||
String libPrefix = (isWin ? "" : "lib");
|
||||
String libSuffix = (isWin ? ".dll" : isMac ? ".jnilib" : ".so");
|
||||
|
||||
File jcpuidLib = new File(context.getBaseDir(), libPrefix + "jcpuid" + libSuffix);
|
||||
if (jcpuidLib.canWrite() && jbigiJar.lastModified() > jcpuidLib.lastModified()) {
|
||||
String path = jcpuidLib.getAbsolutePath();
|
||||
boolean success = FileUtil.copy(path, path + ".bak", true, true);
|
||||
if (success) {
|
||||
boolean success2 = jcpuidLib.delete();
|
||||
if (success2) {
|
||||
System.out.println("New jbigi.jar detected, moved jcpuid library to " +
|
||||
path + ".bak");
|
||||
System.out.println("Check logs for successful installation of new library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File jbigiLib = new File(context.getBaseDir(), libPrefix + "jbigi" + libSuffix);
|
||||
if (jbigiLib.canWrite() && jbigiJar.lastModified() > jbigiLib.lastModified()) {
|
||||
String path = jbigiLib.getAbsolutePath();
|
||||
boolean success = FileUtil.copy(path, path + ".bak", true, true);
|
||||
if (success) {
|
||||
boolean success2 = jbigiLib.delete();
|
||||
if (success2) {
|
||||
System.out.println("New jbigi.jar detected, moved jbigi library to " +
|
||||
path + ".bak");
|
||||
System.out.println("Check logs for successful installation of new library");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all files listed in the delete file.
|
||||
* Format: One file name per line, comment lines start with '#'.
|
||||
* All file names must be relative to $I2P, absolute file names not allowed.
|
||||
* We probably can't remove old jars this way.
|
||||
* Fails silently.
|
||||
* Use no new I2P classes here so it may be called after zip extraction.
|
||||
* @since 0.8.12
|
||||
*/
|
||||
private static void deleteListedFiles(RouterContext context) {
|
||||
File deleteFile = new File(context.getBaseDir(), DELETE_FILE);
|
||||
if (!deleteFile.exists())
|
||||
return;
|
||||
// this is similar to FileUtil.readTextFile() but we can't use any I2P classes here
|
||||
FileInputStream fis = null;
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
fis = new FileInputStream(deleteFile);
|
||||
in = new BufferedReader(new InputStreamReader(fis, "UTF-8"));
|
||||
String line;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
String fl = line.trim();
|
||||
if (fl.contains("..") || fl.startsWith("#") || fl.length() == 0)
|
||||
continue;
|
||||
File df = new File(fl);
|
||||
if (df.isAbsolute())
|
||||
continue;
|
||||
df = new File(context.getBaseDir(), fl);
|
||||
if (df.exists() && !df.isDirectory()) {
|
||||
if (df.delete())
|
||||
System.out.println("INFO: File [" + fl + "] deleted");
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
finally {
|
||||
if (in != null) try { in.close(); } catch(IOException ioe) {}
|
||||
if (deleteFile.delete())
|
||||
System.out.println("INFO: File [" + DELETE_FILE + "] deleted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
Miscellaneous classes, mostly things that are executed periodically as
|
||||
Jobs, Threads, and SimpleTimer.TimedEvents.
|
||||
These are used only by Router.java.
|
||||
Nothing here is to be used externally, not a part of the public API.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -70,8 +70,12 @@ public class FIFOBandwidthRefiller implements Runnable {
|
||||
public static final int MIN_INBOUND_BANDWIDTH_PEAK = 3;
|
||||
/** For now, until there is some tuning and safe throttling, we set the floor at a 3KBps during burst */
|
||||
public static final int MIN_OUTBOUND_BANDWIDTH_PEAK = 3;
|
||||
/** Max for reasonable bloom filter false positive rate. See util/DecayingBloomFilter and tunnel/BloomFilterIVValidator */
|
||||
public static final int MAX_OUTBOUND_BANDWIDTH = 4096;
|
||||
/**
|
||||
* Max for reasonable Bloom filter false positive rate.
|
||||
* Do not increase without adding a new Bloom filter size!
|
||||
* See util/DecayingBloomFilter and tunnel/BloomFilterIVValidator.
|
||||
*/
|
||||
public static final int MAX_OUTBOUND_BANDWIDTH = 8192;
|
||||
|
||||
/**
|
||||
* how often we replenish the queues.
|
||||
|
@ -1,9 +1,12 @@
|
||||
package net.i2p.router.tunnel;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.util.DecayingBloomFilter;
|
||||
import net.i2p.router.util.DecayingHashSet;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleByteCache;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
@ -26,12 +29,19 @@ class BloomFilterIVValidator implements IVValidator {
|
||||
private static final int MIN_SHARE_KBPS_TO_USE_BLOOM = 64;
|
||||
private static final int MIN_SHARE_KBPS_FOR_BIG_BLOOM = 512;
|
||||
private static final int MIN_SHARE_KBPS_FOR_HUGE_BLOOM = 1536;
|
||||
private static final int MIN_SHARE_KBPS_FOR_HUGE2_BLOOM = 4096;
|
||||
private static final long MIN_MEM_TO_USE_BLOOM = 64*1024*1024l;
|
||||
private static final long MIN_MEM_FOR_BIG_BLOOM = 128*1024*1024l;
|
||||
private static final long MIN_MEM_FOR_HUGE_BLOOM = 256*1024*1024l;
|
||||
private static final long MIN_MEM_FOR_HUGE2_BLOOM = 384*1024*1024l;
|
||||
/** for testing */
|
||||
private static final String PROP_FORCE = "router.forceDecayingBloomFilter";
|
||||
/** for testing */
|
||||
private static final String PROP_DISABLE = "router.disableDecayingBloomFilter";
|
||||
|
||||
/**
|
||||
* @param Kbps share bandwidth
|
||||
*/
|
||||
public BloomFilterIVValidator(RouterContext ctx, int KBps) {
|
||||
_context = ctx;
|
||||
// Select the filter based on share bandwidth and memory.
|
||||
@ -39,21 +49,36 @@ class BloomFilterIVValidator implements IVValidator {
|
||||
// to keep acceptable false positive rates.
|
||||
// See DBF, BloomSHA1, and KeySelector for details.
|
||||
long maxMemory = SystemVersion.getMaxMemory();
|
||||
if (_context.getBooleanProperty(PROP_FORCE))
|
||||
if (_context.getBooleanProperty(PROP_FORCE)) {
|
||||
_filter = new DecayingBloomFilter(ctx, HALFLIFE_MS, 16, "TunnelIVV"); // 2MB fixed
|
||||
else if (KBps < MIN_SHARE_KBPS_TO_USE_BLOOM || maxMemory < MIN_MEM_TO_USE_BLOOM)
|
||||
} else if (_context.getBooleanProperty(PROP_DISABLE)) {
|
||||
_filter = null;
|
||||
} else if (KBps < MIN_SHARE_KBPS_TO_USE_BLOOM || maxMemory < MIN_MEM_TO_USE_BLOOM) {
|
||||
if (KBps >= MIN_SHARE_KBPS_TO_USE_BLOOM)
|
||||
warn(maxMemory, KBps, MIN_MEM_TO_USE_BLOOM, MIN_SHARE_KBPS_TO_USE_BLOOM);
|
||||
_filter = new DecayingHashSet(ctx, HALFLIFE_MS, 16, "TunnelIVV"); // appx. 4MB max
|
||||
else if (KBps >= MIN_SHARE_KBPS_FOR_HUGE_BLOOM && maxMemory >= MIN_MEM_FOR_HUGE_BLOOM)
|
||||
} else if (KBps >= MIN_SHARE_KBPS_FOR_HUGE2_BLOOM && maxMemory >= MIN_MEM_FOR_HUGE2_BLOOM) {
|
||||
_filter = new DecayingBloomFilter(ctx, HALFLIFE_MS, 16, "TunnelIVV", 26); // 16MB fixed
|
||||
} else if (KBps >= MIN_SHARE_KBPS_FOR_HUGE_BLOOM && maxMemory >= MIN_MEM_FOR_HUGE_BLOOM) {
|
||||
if (KBps >= MIN_SHARE_KBPS_FOR_HUGE2_BLOOM)
|
||||
warn(maxMemory, KBps, MIN_MEM_FOR_HUGE2_BLOOM, MIN_SHARE_KBPS_FOR_HUGE2_BLOOM);
|
||||
_filter = new DecayingBloomFilter(ctx, HALFLIFE_MS, 16, "TunnelIVV", 25); // 8MB fixed
|
||||
else if (KBps >= MIN_SHARE_KBPS_FOR_BIG_BLOOM && maxMemory >= MIN_MEM_FOR_BIG_BLOOM)
|
||||
} else if (KBps >= MIN_SHARE_KBPS_FOR_BIG_BLOOM && maxMemory >= MIN_MEM_FOR_BIG_BLOOM) {
|
||||
if (KBps >= MIN_SHARE_KBPS_FOR_HUGE_BLOOM)
|
||||
warn(maxMemory, KBps, MIN_MEM_FOR_HUGE_BLOOM, MIN_SHARE_KBPS_FOR_HUGE_BLOOM);
|
||||
_filter = new DecayingBloomFilter(ctx, HALFLIFE_MS, 16, "TunnelIVV", 24); // 4MB fixed
|
||||
else
|
||||
} else {
|
||||
if (KBps >= MIN_SHARE_KBPS_FOR_BIG_BLOOM)
|
||||
warn(maxMemory, KBps, MIN_MEM_FOR_BIG_BLOOM, MIN_SHARE_KBPS_FOR_BIG_BLOOM);
|
||||
_filter = new DecayingBloomFilter(ctx, HALFLIFE_MS, 16, "TunnelIVV"); // 2MB fixed
|
||||
}
|
||||
ctx.statManager().createRateStat("tunnel.duplicateIV", "Note that a duplicate IV was received", "Tunnels",
|
||||
new long[] { 60*60*1000l });
|
||||
}
|
||||
|
||||
public boolean receiveIV(byte ivData[], int ivOffset, byte payload[], int payloadOffset) {
|
||||
if (_filter == null) // testing only
|
||||
return true;
|
||||
byte[] buf = SimpleByteCache.acquire(HopProcessor.IV_LENGTH);
|
||||
DataHelper.xor(ivData, ivOffset, payload, payloadOffset, buf, 0, HopProcessor.IV_LENGTH);
|
||||
boolean dup = _filter.add(buf);
|
||||
@ -62,5 +87,26 @@ class BloomFilterIVValidator implements IVValidator {
|
||||
return !dup; // return true if it is OK, false if it isn't
|
||||
}
|
||||
|
||||
public void destroy() { _filter.stopDecaying(); }
|
||||
public void destroy() {
|
||||
if (_filter != null)
|
||||
_filter.stopDecaying();
|
||||
}
|
||||
|
||||
/** @since 0.9.20 */
|
||||
private void warn(long maxMemory, int KBps, long recMaxMem, int threshKBps) {
|
||||
if (SystemVersion.isAndroid())
|
||||
return;
|
||||
String msg =
|
||||
"Configured for " + DataHelper.formatSize(KBps *1024) +
|
||||
"Bps share bandwidth but only " +
|
||||
DataHelper.formatSize(maxMemory) + "B available memory." +
|
||||
" Recommend increasing wrapper.java.maxmemory in " +
|
||||
_context.getBaseDir() + File.separatorChar + "wrapper.config" +
|
||||
// getMaxMemory() returns significantly lower than wrapper config, so add 10%
|
||||
" to at least " + (recMaxMem * 11 / 10 / (1024*1024)) + " (MB)" +
|
||||
" if the actual share bandwidth exceeds " +
|
||||
DataHelper.formatSize(threshKBps * 1024) + "Bps.";
|
||||
System.out.println("WARN: " + msg);
|
||||
_context.logManager().getLog(BloomFilterIVValidator.class).logAlways(Log.WARN, msg);
|
||||
}
|
||||
}
|
||||
|
@ -372,6 +372,9 @@ public class DecayingBloomFilter {
|
||||
*
|
||||
* Following stats for m=25, k=10:
|
||||
* 1792 2.4E-6; 4096 0.14%; 5120 0.6%; 6144 1.7%; 8192 6.8%; 10240 15%
|
||||
*
|
||||
* Following stats for m=26, k=10:
|
||||
* 4096 7.3E-6; 5120 4.5E-5; 6144 1.8E-4; 8192 0.14%; 10240 0.6%, 12288 1.7%
|
||||
*</pre>
|
||||
*/
|
||||
/*****
|
||||
@ -400,16 +403,23 @@ public class DecayingBloomFilter {
|
||||
}
|
||||
|
||||
private static void testByLong(int kbps, int m, int numRuns) {
|
||||
System.out.println("Starting 8 byte test");
|
||||
int messages = 60 * 10 * kbps;
|
||||
Random r = new Random();
|
||||
java.util.Random r = new java.util.Random();
|
||||
DecayingBloomFilter filter = new DecayingBloomFilter(I2PAppContext.getGlobalContext(), 600*1000, 8, "test", m);
|
||||
int falsePositives = 0;
|
||||
long totalTime = 0;
|
||||
double fpr = 0d;
|
||||
for (int j = 0; j < numRuns; j++) {
|
||||
// screen out birthday paradoxes (waste of time and space?)
|
||||
java.util.Set<Long> longs = new java.util.HashSet<Long>(messages);
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < messages; i++) {
|
||||
if (filter.add(r.nextLong())) {
|
||||
long rand;
|
||||
do {
|
||||
rand = r.nextLong();
|
||||
} while (!longs.add(Long.valueOf(rand)));
|
||||
if (filter.add(rand)) {
|
||||
falsePositives++;
|
||||
//System.out.println("False positive " + falsePositives + " (testByLong j=" + j + " i=" + i + ")");
|
||||
}
|
||||
@ -422,13 +432,14 @@ public class DecayingBloomFilter {
|
||||
System.out.println("False postive rate should be " + fpr);
|
||||
System.out.println("After " + numRuns + " runs pushing " + messages + " entries in "
|
||||
+ DataHelper.formatDuration(totalTime/numRuns) + " per run, there were "
|
||||
+ falsePositives + " false positives");
|
||||
|
||||
+ falsePositives + " false positives (" +
|
||||
(((double) falsePositives) / messages) + ')');
|
||||
}
|
||||
|
||||
private static void testByBytes(int kbps, int m, int numRuns) {
|
||||
System.out.println("Starting 16 byte test");
|
||||
byte iv[][] = new byte[60*10*kbps][16];
|
||||
Random r = new Random();
|
||||
java.util.Random r = new java.util.Random();
|
||||
for (int i = 0; i < iv.length; i++)
|
||||
r.nextBytes(iv[i]);
|
||||
|
||||
@ -452,7 +463,8 @@ public class DecayingBloomFilter {
|
||||
System.out.println("False postive rate should be " + fpr);
|
||||
System.out.println("After " + numRuns + " runs pushing " + iv.length + " entries in "
|
||||
+ DataHelper.formatDuration(totalTime/numRuns) + " per run, there were "
|
||||
+ falsePositives + " false positives");
|
||||
+ falsePositives + " false positives (" +
|
||||
(((double) falsePositives) / iv.length) + ')');
|
||||
//System.out.println("inserted: " + bloom.size() + " with " + bloom.capacity()
|
||||
// + " (" + bloom.falsePositives()*100.0d + "% false positive)");
|
||||
}
|
||||
|
Reference in New Issue
Block a user