1 package net.pterodactylus.xdcc.core;
3 import java.time.Clock;
4 import java.time.Instant;
5 import java.util.HashMap;
7 import java.util.concurrent.TimeUnit;
9 import net.pterodactylus.xdcc.data.Network;
12 * Manages backoff times for connections.
14 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
16 public class ConnectionBackoff {
18 private static final long MILLIS_PER_SECOND = TimeUnit.MINUTES.toMillis(1);
19 private static final long MILLIS_PER_HOUR = TimeUnit.HOURS.toMillis(1);
21 private final Clock clock;
22 private final Map<Network, ConnectionFailureCounter> connectionFailures = new HashMap<>();
24 public ConnectionBackoff() {
25 this(Clock.systemDefaultZone());
28 public ConnectionBackoff(Clock clock) {
32 public void connectionFailed(Network network) {
33 ConnectionFailureCounter connectionFailureCounter = getConnectionFailureCounter(network);
34 connectionFailureCounter.countFailure();
37 public void connectionSuccessful(Network network) {
38 ConnectionFailureCounter connectionFailureCounter = getConnectionFailureCounter(network);
39 connectionFailureCounter.reset();
42 public long getBackoff(Network network) {
43 ConnectionFailureCounter connectionFailureCounter = getConnectionFailureCounter(network);
44 if (!connectionFailureCounter.hasFailure()) {
47 long delay = (long) (MILLIS_PER_SECOND *
48 Math.pow(1.2, connectionFailureCounter.getFailureCount() - 1));
49 return Math.min(MILLIS_PER_HOUR, Math.max(0,
50 (connectionFailureCounter.getLastFailureTime() + delay) - Instant.now(clock)
54 private ConnectionFailureCounter getConnectionFailureCounter(Network network) {
55 ConnectionFailureCounter connectionFailureCounter;
56 synchronized (connectionFailures) {
57 if (!connectionFailures.containsKey(network)) {
58 connectionFailures.put(network, new ConnectionFailureCounter());
60 connectionFailureCounter = connectionFailures.get(network);
62 return connectionFailureCounter;
65 private class ConnectionFailureCounter {
67 private final Object lock = new Object();
69 private long lastFailureTime;
78 public void countFailure() {
81 lastFailureTime = Instant.now(clock).toEpochMilli();
85 public boolean hasFailure() {
91 public int getFailureCount() {
97 public long getLastFailureTime() {
99 return lastFailureTime;