mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 13:49:53 +01:00
Refactored exponential backoff code out of JdbcDatabase and added tests.
This commit is contained in:
30
briar-core/src/net/sf/briar/db/ExponentialBackoff.java
Normal file
30
briar-core/src/net/sf/briar/db/ExponentialBackoff.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
class ExponentialBackoff {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the expiry time of a packet transmitted at time <tt>now</tt>
|
||||||
|
* over a transport with maximum latency <tt>maxLatency</tt>, where the
|
||||||
|
* packet has previously been transmitted <tt>txCount</tt> times. All times
|
||||||
|
* are in milliseconds. The expiry time is
|
||||||
|
* <tt>now + maxLatency * 2 ^ (txCount + 1)</tt>, so the interval between
|
||||||
|
* transmissions increases exponentially. If the expiry time would
|
||||||
|
* be greater than Long.MAX_VALUE, Long.MAX_VALUE is returned.
|
||||||
|
*/
|
||||||
|
static long calculateExpiry(long now, long maxLatency, int txCount) {
|
||||||
|
if(now < 0) throw new IllegalArgumentException();
|
||||||
|
if(maxLatency <= 0) throw new IllegalArgumentException();
|
||||||
|
if(txCount < 0) throw new IllegalArgumentException();
|
||||||
|
// The maximum round-trip time is twice the maximum latency
|
||||||
|
long roundTrip = maxLatency * 2;
|
||||||
|
if(roundTrip < 0) return Long.MAX_VALUE;
|
||||||
|
// The interval between transmissions is roundTrip * 2 ^ txCount
|
||||||
|
for(int i = 0; i < txCount; i++) {
|
||||||
|
roundTrip <<= 1;
|
||||||
|
if(roundTrip < 0) return Long.MAX_VALUE;
|
||||||
|
}
|
||||||
|
// The expiry time is the current time plus the interval
|
||||||
|
long expiry = now + roundTrip;
|
||||||
|
return expiry < 0 ? Long.MAX_VALUE : expiry;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import static java.util.logging.Level.INFO;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static net.sf.briar.api.Rating.UNRATED;
|
import static net.sf.briar.api.Rating.UNRATED;
|
||||||
import static net.sf.briar.db.DatabaseConstants.RETENTION_MODULUS;
|
import static net.sf.briar.db.DatabaseConstants.RETENTION_MODULUS;
|
||||||
|
import static net.sf.briar.db.ExponentialBackoff.calculateExpiry;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@@ -2877,17 +2878,4 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Refactor the exponential backoff logic into a separate class
|
|
||||||
private long calculateExpiry(long now, long maxLatency, int txCount) {
|
|
||||||
long roundTrip = maxLatency * 2;
|
|
||||||
if(roundTrip < 0) return Long.MAX_VALUE;
|
|
||||||
for(int i = 0; i < txCount; i++) {
|
|
||||||
roundTrip <<= 1;
|
|
||||||
if(roundTrip < 0) return Long.MAX_VALUE;
|
|
||||||
}
|
|
||||||
long expiry = now + roundTrip;
|
|
||||||
if(expiry < 0) return Long.MAX_VALUE;
|
|
||||||
return expiry;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@
|
|||||||
<test name='net.sf.briar.db.BasicH2Test'/>
|
<test name='net.sf.briar.db.BasicH2Test'/>
|
||||||
<test name='net.sf.briar.db.DatabaseCleanerImplTest'/>
|
<test name='net.sf.briar.db.DatabaseCleanerImplTest'/>
|
||||||
<test name='net.sf.briar.db.DatabaseComponentImplTest'/>
|
<test name='net.sf.briar.db.DatabaseComponentImplTest'/>
|
||||||
|
<test name='net.sf.briar.db.ExponentialBackoffTest'/>
|
||||||
<test name='net.sf.briar.lifecycle.ShutdownManagerImplTest'/>
|
<test name='net.sf.briar.lifecycle.ShutdownManagerImplTest'/>
|
||||||
<test name='net.sf.briar.lifecycle.WindowsShutdownManagerImplTest'/>
|
<test name='net.sf.briar.lifecycle.WindowsShutdownManagerImplTest'/>
|
||||||
<test name='net.sf.briar.messaging.ConstantsTest'/>
|
<test name='net.sf.briar.messaging.ConstantsTest'/>
|
||||||
|
|||||||
64
briar-tests/src/net/sf/briar/db/ExponentialBackoffTest.java
Normal file
64
briar-tests/src/net/sf/briar/db/ExponentialBackoffTest.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import net.sf.briar.BriarTestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class ExponentialBackoffTest extends BriarTestCase {
|
||||||
|
|
||||||
|
private static final int ONE_HOUR = 60 * 60 * 1000;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFirstIntervalEqualsRoundTripTime() {
|
||||||
|
long first = ExponentialBackoff.calculateExpiry(0, ONE_HOUR, 0);
|
||||||
|
assertEquals(2 * ONE_HOUR, first);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIntervalsIncreaseExponentially() {
|
||||||
|
long first = ExponentialBackoff.calculateExpiry(0, ONE_HOUR, 0);
|
||||||
|
long second = ExponentialBackoff.calculateExpiry(0, ONE_HOUR, 1);
|
||||||
|
long third = ExponentialBackoff.calculateExpiry(0, ONE_HOUR, 2);
|
||||||
|
long fourth = ExponentialBackoff.calculateExpiry(0, ONE_HOUR, 3);
|
||||||
|
assertEquals(third, fourth / 2);
|
||||||
|
assertEquals(second, third / 2);
|
||||||
|
assertEquals(first, second / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIntervalIsAddedToCurrentTime() {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long fromZero = ExponentialBackoff.calculateExpiry(0, ONE_HOUR, 0);
|
||||||
|
long fromNow = ExponentialBackoff.calculateExpiry(now, ONE_HOUR, 0);
|
||||||
|
assertEquals(now, fromNow - fromZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRoundTripTimeOverflow() {
|
||||||
|
long maxLatency = Long.MAX_VALUE / 2 + 1; // RTT will overflow
|
||||||
|
long expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 0);
|
||||||
|
assertEquals(Long.MAX_VALUE, expiry); // Overflow caught
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransmissionCountOverflow() {
|
||||||
|
long maxLatency = (Long.MAX_VALUE - 1) / 2; // RTT will not overflow
|
||||||
|
long expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 0);
|
||||||
|
assertEquals(Long.MAX_VALUE - 1, expiry); // No overflow
|
||||||
|
expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 1);
|
||||||
|
assertEquals(Long.MAX_VALUE, expiry); // Overflow caught
|
||||||
|
expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 2);
|
||||||
|
assertEquals(Long.MAX_VALUE, expiry); // Overflow caught
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCurrentTimeOverflow() {
|
||||||
|
long maxLatency = (Long.MAX_VALUE - 1) / 2; // RTT will not overflow
|
||||||
|
long expiry = ExponentialBackoff.calculateExpiry(0, maxLatency, 0);
|
||||||
|
assertEquals(Long.MAX_VALUE - 1, expiry); // No overflow
|
||||||
|
expiry = ExponentialBackoff.calculateExpiry(1, maxLatency, 0);
|
||||||
|
assertEquals(Long.MAX_VALUE, expiry); // No overflow
|
||||||
|
expiry = ExponentialBackoff.calculateExpiry(2, maxLatency, 0);
|
||||||
|
assertEquals(Long.MAX_VALUE, expiry); // Overflow caught
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user