diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index a3d77a814a88df19d08969eafc906db5ca144d21..77207ec08acd336a002927092dff51d4e1bf50fd 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -857,29 +857,33 @@ public class I2PSnarkServlet extends Default { out.write("<td class=\"center " + rowClass + "\">"); out.write(statusString + "</td>\n\t"); + // (i) icon column out.write("<td class=\"" + rowClass + "\">"); + if (isValid && meta.getAnnounce() != null) { + // Link to local details page - note that trailing slash on a single-file torrent + // gets us to the details page instead of the file. + //StringBuilder buf = new StringBuilder(128); + //buf.append("<a href=\"").append(snark.getBaseName()) + // .append("/\" title=\"").append(_("Torrent details")) + // .append("\"><img alt=\"").append(_("Info")).append("\" border=\"0\" src=\"") + // .append(_imgPath).append("details.png\"></a>"); + //out.write(buf.toString()); + + // Link to tracker details page + String trackerLink = getTrackerLink(meta.getAnnounce(), snark.getInfoHash()); + if (trackerLink != null) + out.write(trackerLink); + } + + // File type icon column + out.write("</td>\n<td class=\"" + rowClass + "\">"); if (isValid) { + // Link to local details page - note that trailing slash on a single-file torrent + // gets us to the details page instead of the file. StringBuilder buf = new StringBuilder(128); buf.append("<a href=\"").append(snark.getBaseName()) .append("/\" title=\"").append(_("Torrent details")) - .append("\"><img alt=\"").append(_("Info")).append("\" border=\"0\" src=\"") - .append(_imgPath).append("details.png\"></a>"); - out.write(buf.toString()); - } - - out.write("</td>\n<td class=\"" + rowClass + "\">"); - StringBuilder buf = null; - if (remaining == 0 || isMultiFile) { - buf = new StringBuilder(128); - buf.append("<a href=\"").append(snark.getBaseName()); - if (isMultiFile) - buf.append('/'); - buf.append("\" title=\""); - if (isMultiFile) - buf.append(_("View files")); - else - buf.append(_("Open file")); - buf.append("\">"); + .append("\">"); out.write(buf.toString()); } String icon; @@ -889,15 +893,28 @@ public class I2PSnarkServlet extends Default { icon = toIcon(meta.getName()); else icon = "magnet"; - if (remaining == 0 || isMultiFile) { - out.write(toImg(icon, _("Open"))); + if (isValid) { + out.write(toImg(icon, _("Info"))); out.write("</a>"); } else { out.write(toImg(icon)); } + + // Torrent name column out.write("</td><td class=\"snarkTorrentName " + rowClass + "\">"); - if (remaining == 0 || isMultiFile) + if (remaining == 0 || isMultiFile) { + StringBuilder buf = new StringBuilder(128); + buf.append("<a href=\"").append(snark.getBaseName()); + if (isMultiFile) + buf.append('/'); + buf.append("\" title=\""); + if (isMultiFile) + buf.append(_("View files")); + else + buf.append(_("Open file")); + buf.append("\">"); out.write(buf.toString()); + } out.write(filename); if (remaining == 0 || isMultiFile) out.write("</a>"); @@ -1169,7 +1186,7 @@ public class I2PSnarkServlet extends Default { out.write(_("From URL")); out.write(":<td><input type=\"text\" name=\"newURL\" size=\"85\" value=\"" + newURL + "\""); out.write("title=\""); - out.write(_("Torrent file must originate from an I2P-based tracker")); + out.write(_("Enter the torrent file download URL (I2P only), magnet link, or maggot link")); out.write("\"> \n"); // not supporting from file at the moment, since the file name passed isn't always absolute (so it may not resolve) //out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br>"); diff --git a/core/java/build.xml b/core/java/build.xml index 86e0039ac2f1917f73c60c0d9dea2c04e9d2296c..27ca00e6fe6dcf785957d1de77ea8f236d94bdb7 100644 --- a/core/java/build.xml +++ b/core/java/build.xml @@ -49,6 +49,7 @@ <cobertura-instrument todir="./build/obj_test"> <fileset dir="./build/obj"> <include name="**/*.class"/> + <exclude name="**/*Test.class" /> </fileset> </cobertura-instrument> </target> diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 69b315a1a478be9ac84877478997734ab6d2e5b9..4e3db770b0674ac6785094181ed6bcee2592ba18 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -179,6 +179,7 @@ public class DataHelper { * @param props source * @return new offset */ + @Deprecated public static int toProperties(byte target[], int offset, Properties props) throws DataFormatException, IOException { if (props != null) { OrderedProperties p = new OrderedProperties(); @@ -219,6 +220,7 @@ public class DataHelper { * @param target returned Properties * @return new offset */ + @Deprecated public static int fromProperties(byte source[], int offset, Properties target) throws DataFormatException, IOException { int size = (int)fromLong(source, offset, 2); offset += 2; @@ -254,6 +256,7 @@ public class DataHelper { * * @throws RuntimeException if either is too long. */ + @Deprecated public static byte[] toProperties(Properties opts) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(2); @@ -544,6 +547,7 @@ public class DataHelper { } /** @deprecated unused */ + @Deprecated public static byte[] toDate(Date date) throws IllegalArgumentException { if (date == null) return toLong(DATE_LENGTH, 0L); @@ -678,6 +682,7 @@ public class DataHelper { * @throws IOException if there is an IO error writing the boolean * @deprecated unused */ + @Deprecated public static void writeBoolean(OutputStream out, Boolean bool) throws DataFormatException, IOException { if (bool == null) @@ -689,6 +694,7 @@ public class DataHelper { } /** @deprecated unused */ + @Deprecated public static Boolean fromBoolean(byte data[], int offset) { if (data[offset] == BOOLEAN_TRUE) return Boolean.TRUE; @@ -699,11 +705,13 @@ public class DataHelper { } /** @deprecated unused */ + @Deprecated public static void toBoolean(byte data[], int offset, boolean value) { data[offset] = (value ? BOOLEAN_TRUE : BOOLEAN_FALSE); } /** @deprecated unused */ + @Deprecated public static void toBoolean(byte data[], int offset, Boolean value) { if (value == null) data[offset] = BOOLEAN_UNKNOWN; @@ -712,12 +720,16 @@ public class DataHelper { } /** deprecated - used only in DatabaseLookupMessage */ + @Deprecated public static final byte BOOLEAN_TRUE = 0x1; /** deprecated - used only in DatabaseLookupMessage */ + @Deprecated public static final byte BOOLEAN_FALSE = 0x0; /** @deprecated unused */ + @Deprecated public static final byte BOOLEAN_UNKNOWN = 0x2; /** @deprecated unused */ + @Deprecated public static final int BOOLEAN_LENGTH = 1; // @@ -780,6 +792,7 @@ public class DataHelper { * Compare two integers, really just for consistency. * @deprecated inefficient */ + @Deprecated public final static boolean eq(int lhs, int rhs) { return lhs == rhs; } @@ -788,6 +801,7 @@ public class DataHelper { * Compare two longs, really just for consistency. * @deprecated inefficient */ + @Deprecated public final static boolean eq(long lhs, long rhs) { return lhs == rhs; } @@ -796,6 +810,7 @@ public class DataHelper { * Compare two bytes, really just for consistency. * @deprecated inefficient */ + @Deprecated public final static boolean eq(byte lhs, byte rhs) { return lhs == rhs; } @@ -974,6 +989,7 @@ public class DataHelper { * @return true if the line was read, false if eof was reached before a * newline was found */ + @Deprecated public static boolean readLine(InputStream in, StringBuffer buf) throws IOException { return readLine(in, buf, null); } @@ -987,6 +1003,7 @@ public class DataHelper { * Warning - 8KB line length limit as of 0.7.13, @throws IOException if exceeded * @deprecated use StringBuilder version */ + @Deprecated public static boolean readLine(InputStream in, StringBuffer buf, Sha256Standalone hash) throws IOException { int c = -1; int i = 0; diff --git a/core/java/src/net/i2p/data/DateAndFlags.java b/core/java/src/net/i2p/data/DateAndFlags.java index 70f88ce655b27e4af5ca9bea42d624a5656f409f..0810cddca6e9db88719b7ace262f38803c0ca30b 100644 --- a/core/java/src/net/i2p/data/DateAndFlags.java +++ b/core/java/src/net/i2p/data/DateAndFlags.java @@ -36,7 +36,7 @@ public class DateAndFlags extends DataStructureImpl { /** * @param flags 0 - 65535 */ - public DateAndFlags(int flags, long date) { + public DateAndFlags(long date, int flags) { _flags = flags; _date = date; } @@ -44,7 +44,7 @@ public class DateAndFlags extends DataStructureImpl { /** * @param flags 0 - 65535 */ - public DateAndFlags(int flags, Date date) { + public DateAndFlags(Date date, int flags) { _flags = flags; _date = date.getTime(); } diff --git a/core/java/src/net/i2p/util/Executor.java b/core/java/src/net/i2p/util/Executor.java index 8092d7ac447ee98f152306101d59e925fb18baf6..3c81d46f157f581455d30c4ea19f52b2b6232e19 100644 --- a/core/java/src/net/i2p/util/Executor.java +++ b/core/java/src/net/i2p/util/Executor.java @@ -5,10 +5,10 @@ import java.util.List; import net.i2p.I2PAppContext; class Executor implements Runnable { - private I2PAppContext _context; + private final I2PAppContext _context; private Log _log; private final List _readyEvents; - private SimpleStore runn; + private final SimpleStore runn; public Executor(I2PAppContext ctx, Log log, List events, SimpleStore x) { _context = ctx; @@ -31,9 +31,10 @@ class Executor implements Runnable { try { evt.timeReached(); } catch (Throwable t) { - log("wtf, event borked: " + evt, t); + log("Executing task " + evt + " exited unexpectedly, please report", t); } long time = _context.clock().now() - before; + // FIXME _log won't be non-null unless we already had a CRIT if ( (time > 1000) && (_log != null) && (_log.shouldLog(Log.WARN)) ) _log.warn("wtf, event execution took " + time + ": " + evt); } diff --git a/core/java/src/net/i2p/util/SimpleScheduler.java b/core/java/src/net/i2p/util/SimpleScheduler.java index f764debe99f6cad3d730c64bae342b9679011d13..951f5929eb5cf6c1489ad053f203f3dc4983e4ac 100644 --- a/core/java/src/net/i2p/util/SimpleScheduler.java +++ b/core/java/src/net/i2p/util/SimpleScheduler.java @@ -30,10 +30,10 @@ public class SimpleScheduler { public static SimpleScheduler getInstance() { return _instance; } private static final int MIN_THREADS = 2; private static final int MAX_THREADS = 4; - private I2PAppContext _context; - private Log _log; - private ScheduledThreadPoolExecutor _executor; - private String _name; + private final I2PAppContext _context; + private final Log _log; + private final ScheduledThreadPoolExecutor _executor; + private final String _name; private int _count; private final int _threads; @@ -42,7 +42,6 @@ public class SimpleScheduler { _context = I2PAppContext.getGlobalContext(); _log = _context.logManager().getLog(SimpleScheduler.class); _name = name; - _count = 0; long maxMemory = Runtime.getRuntime().maxMemory(); _threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024)))); _executor = new ScheduledThreadPoolExecutor(_threads, new CustomThreadFactory()); @@ -139,7 +138,7 @@ public class SimpleScheduler { try { _timedEvent.timeReached(); } catch (Throwable t) { - _log.log(Log.CRIT, _name + " wtf, event borked: " + _timedEvent, t); + _log.log(Log.CRIT, _name + ": Scheduled task " + _timedEvent + " exited unexpectedly, please report", t); } long time = System.currentTimeMillis() - before; if (time > 1000 && _log.shouldLog(Log.WARN)) diff --git a/core/java/src/net/i2p/util/SimpleTimer.java b/core/java/src/net/i2p/util/SimpleTimer.java index f428afceb91be35badc734c848d48d3aa33123bd..ee3f35120f9b37363d1163cb9b4287706e740229 100644 --- a/core/java/src/net/i2p/util/SimpleTimer.java +++ b/core/java/src/net/i2p/util/SimpleTimer.java @@ -14,6 +14,8 @@ import net.i2p.I2PAppContext; * appropriate time. The method that is fired however should NOT block (otherwise * they b0rk the timer). * + * WARNING - Deprecated. + * This is an inefficient mess. Use SimpleScheduler or SimpleTimer2 if possible. */ public class SimpleTimer { private static final SimpleTimer _instance = new SimpleTimer(); diff --git a/core/java/src/net/i2p/util/SimpleTimer2.java b/core/java/src/net/i2p/util/SimpleTimer2.java index 44e405b2484bb1287f8154f93e114026f538aaa1..a497915e2358e4db6081a1c91fa5fd54559d27e2 100644 --- a/core/java/src/net/i2p/util/SimpleTimer2.java +++ b/core/java/src/net/i2p/util/SimpleTimer2.java @@ -29,10 +29,10 @@ public class SimpleTimer2 { public static SimpleTimer2 getInstance() { return _instance; } private static final int MIN_THREADS = 2; private static final int MAX_THREADS = 4; - private I2PAppContext _context; + private final I2PAppContext _context; private static Log _log; // static so TimedEvent can use it - private ScheduledThreadPoolExecutor _executor; - private String _name; + private final ScheduledThreadPoolExecutor _executor; + private final String _name; private int _count; private final int _threads; @@ -223,7 +223,7 @@ public class SimpleTimer2 { try { timeReached(); } catch (Throwable t) { - _log.log(Log.CRIT, _pool + " wtf, event borked: " + this, t); + _log.log(Log.CRIT, _pool + ": Timed task " + this + " exited unexpectedly, please report", t); } long time = System.currentTimeMillis() - before; if (time > 500 && _log.shouldLog(Log.WARN)) diff --git a/core/java/test/net/i2p/data/LeaseSetTest.java b/core/java/test/net/i2p/data/LeaseSetTest.java index 61c3b73c6de2625c97f4427efe47b38f5c3d0aed..30fb8c11fb2041ee3d69076d7b5d1fc4b0f92c22 100644 --- a/core/java/test/net/i2p/data/LeaseSetTest.java +++ b/core/java/test/net/i2p/data/LeaseSetTest.java @@ -25,4 +25,50 @@ public class LeaseSetTest extends StructureTest { return leaseSet; } public DataStructure createStructureToRead() { return new LeaseSet(); } + + public void testGetLeaseInvalid() { + // create test subject + LeaseSet subj = new LeaseSet(); + + // should contain no leases now.. + try { + assertNull(subj.getLease(0)); + } catch(RuntimeException exc) { + // all good + } + + // this shouldn't work either + try { + assertNull(subj.getLease(-1)); + } catch(RuntimeException exc) { + // all good + } + } + + public void testAddLeaseNull() { + // create test subject + LeaseSet subj = new LeaseSet(); + + // now add an null lease + try { + subj.addLease(null); + fail("Failed at failing."); + } catch(IllegalArgumentException exc) { + // all good + } + } + + public void testAddLeaseInvalid() { + // create test subject + LeaseSet subj = new LeaseSet(); + + // try to add completely invalid lease(ie. no data) + try { + subj.addLease(new Lease()); + fail("Failed at failing."); + } catch(IllegalArgumentException exc) { + // all good + } + } + } diff --git a/core/java/test/net/i2p/data/RouterAddressTest.java b/core/java/test/net/i2p/data/RouterAddressTest.java index 65a44f92128aff26350a5467bef22d09e17b1718..aab4a88bb9ac593362200f066a2d4774ffd54d57 100644 --- a/core/java/test/net/i2p/data/RouterAddressTest.java +++ b/core/java/test/net/i2p/data/RouterAddressTest.java @@ -58,6 +58,7 @@ public class RouterAddressTest extends StructureTest { addr.setOptions(options); addr.setTransportStyle("Blah"); assertFalse(addr.equals(null)); + assertFalse(addr.equals("")); } public void testToString(){ @@ -73,5 +74,7 @@ public class RouterAddressTest extends StructureTest { addr.setOptions(options); addr.setTransportStyle("Blah"); addr.toString(); + addr.setOptions(null); + addr.toString(); } } diff --git a/history.txt b/history.txt index 967b5b763256c93978ba946d3ead513740a6e6c4..4aa6626fac9656225dd48551d5054d667226b2ce 100644 --- a/history.txt +++ b/history.txt @@ -1,9 +1,15 @@ +2011-02-15 zzz + * i2psnark: Details link shuffle, mostly restore 0.8.3 behavior + * Profiles: Punish rejections more, in an attempt to spread the + load more through the network + * Timers: Log cleanup + 2011-02-14 Mathiasdm * Fix headless issue without reboot 2011-02-13 zzz * Connect Client: Minor NPE fix cleanup - * JobQueue: Prevet NPE at shutdown (thanks liberty) + * JobQueue: Prevent NPE at shutdown (thanks liberty) * GeoIP: Prevent startup NPE (ticket #413, thanks RN) * NetDB: Prevent ExpireLeaseJob NPE (thanks sponge) @@ -21,6 +27,7 @@ * I2CP: Correctly close internal connections on the router side when closed by the client, was causing massive memory leak for internal clients using lots of sessions (thanks sponge) + (ticket #397) * i2psnark: - Improved magnet link parsing, use tr parameter if present * i2ptunnel: Change shared clients default for new clients to false diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 5a58b19bc22ea9b489b5610aade18177efc4505e..e36cd3b14352a16a1e79c5fea474cb2f20cbaa5c 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 11; + public final static long BUILD = 12; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/peermanager/CapacityCalculator.java b/router/java/src/net/i2p/router/peermanager/CapacityCalculator.java index 9d23ceddf5349216fa082977b47ca235d6a0e3f1..96570260c5de43c09b24efe897e8ca963b4a0b8c 100644 --- a/router/java/src/net/i2p/router/peermanager/CapacityCalculator.java +++ b/router/java/src/net/i2p/router/peermanager/CapacityCalculator.java @@ -11,7 +11,7 @@ class CapacityCalculator { private static final I2PAppContext _context = I2PAppContext.getGlobalContext(); /** used to adjust each period so that we keep trying to expand the peer's capacity */ - static long GROWTH_FACTOR = 5; + static final long GROWTH_FACTOR = 5; /** the calculator estimates over a 1 hour period */ private static long ESTIMATE_PERIOD = 60*60*1000; @@ -83,37 +83,42 @@ class CapacityCalculator { * * Let A = accects, R = rejects, F = fails * @return estimated and adjusted accepts per hour, for the given period - * which is, more or less, max(0, 5 + (A * (A / (A + R))) - (4 * F)) + * which is, more or less, max(0, 5 + (A * (A / (A + 2R))) - (4 * F)) */ private static double estimateCapacity(RateStat acceptStat, RateStat rejectStat, RateStat failedStat, int period) { Rate curAccepted = acceptStat.getRate(period); Rate curRejected = rejectStat.getRate(period); Rate curFailed = failedStat.getRate(period); - long eventCount = 0; - if (curAccepted != null) + double eventCount = 0; + if (curAccepted != null) { eventCount = curAccepted.getCurrentEventCount() + curAccepted.getLastEventCount(); - // Punish for rejections. - // We don't want to simply do eventCount -= rejected or we get to zero with 50% rejection, - // and we don't want everybody to be at zero during times of congestion. - if (eventCount > 0) { - long rejected = curRejected.getCurrentEventCount() + curRejected.getLastEventCount(); - eventCount = eventCount * eventCount / (eventCount + rejected); + // Punish for rejections. + // We don't want to simply do eventCount -= rejected or we get to zero with 50% rejection, + // and we don't want everybody to be at zero during times of congestion. + if (eventCount > 0 && curRejected != null) { + long rejected = curRejected.getCurrentEventCount() + curRejected.getLastEventCount(); + if (rejected > 0) + eventCount *= eventCount / (eventCount + (2 * rejected)); + } } + double stretch = ((double)ESTIMATE_PERIOD) / period; double val = eventCount * stretch; - long failed = 0; + // Let's say a failure is 4 times worse than a rejection. // It's actually much worse than that, but with 2-hop tunnels and a 8-peer // fast pool, for example, you have a 1/7 chance of being falsely blamed. // We also don't want to drive everybody's capacity to zero, that isn't helpful. - if (curFailed != null) - failed = (long) (0.5 + (4.0 * (curFailed.getCurrentTotalValue() + curFailed.getLastTotalValue()) / 100.0)); - if (failed > 0) { - //if ( (period <= 10*60*1000) && (curFailed.getCurrentEventCount() > 0) ) - // return 0.0d; // their tunnels have failed in the last 0-10 minutes - //else - val -= failed * stretch; + if (curFailed != null) { + double failed = curFailed.getCurrentTotalValue() + curFailed.getLastTotalValue(); + if (failed > 0) { + //if ( (period <= 10*60*1000) && (curFailed.getCurrentEventCount() > 0) ) + // return 0.0d; // their tunnels have failed in the last 0-10 minutes + //else + // .04 = 4.0 / 100.0 adjustment to failed + val -= 0.04 * failed * stretch; + } } val += GROWTH_FACTOR;