Refactor connection registry implementation.

This commit is contained in:
akwizgran
2020-05-25 14:22:27 +01:00
parent d3d7212b08
commit e8dbc00712
2 changed files with 86 additions and 40 deletions

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.connection; package org.briarproject.bramble.connection;
import org.briarproject.bramble.api.Multiset;
import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.connection.ConnectionRegistry; import org.briarproject.bramble.api.connection.ConnectionRegistry;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
@@ -22,6 +21,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -41,22 +41,30 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
getLogger(ConnectionRegistryImpl.class.getName()); getLogger(ConnectionRegistryImpl.class.getName());
private final EventBus eventBus; private final EventBus eventBus;
private final List<Pair<TransportId, TransportId>> preferences; private final Map<TransportId, List<TransportId>> betterTransports;
private final Object lock = new Object(); private final Object lock = new Object();
@GuardedBy("lock") @GuardedBy("lock")
private final Map<TransportId, Multiset<ContactId>> contactConnections; private final Map<ContactId, List<ConnectionRecord>> contactConnections;
@GuardedBy("lock")
private final Multiset<ContactId> contactCounts;
@GuardedBy("lock") @GuardedBy("lock")
private final Set<PendingContactId> connectedPendingContacts; private final Set<PendingContactId> connectedPendingContacts;
@Inject @Inject
ConnectionRegistryImpl(EventBus eventBus, PluginConfig pluginConfig) { ConnectionRegistryImpl(EventBus eventBus, PluginConfig pluginConfig) {
this.eventBus = eventBus; this.eventBus = eventBus;
preferences = pluginConfig.getTransportPreferences(); betterTransports = new HashMap<>();
for (Pair<TransportId, TransportId> pair :
pluginConfig.getTransportPreferences()) {
TransportId better = pair.getFirst();
TransportId worse = pair.getSecond();
List<TransportId> list = betterTransports.get(worse);
if (list == null) {
list = new ArrayList<>();
betterTransports.put(worse, list);
}
list.add(better);
}
contactConnections = new HashMap<>(); contactConnections = new HashMap<>();
contactCounts = new Multiset<>();
connectedPendingContacts = new HashSet<>(); connectedPendingContacts = new HashSet<>();
} }
@@ -69,13 +77,13 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
} }
boolean firstConnection = false; boolean firstConnection = false;
synchronized (lock) { synchronized (lock) {
Multiset<ContactId> m = contactConnections.get(t); List<ConnectionRecord> recs = contactConnections.get(c);
if (m == null) { if (recs == null) {
m = new Multiset<>(); recs = new ArrayList<>();
contactConnections.put(t, m); contactConnections.put(c, recs);
} }
m.add(c); if (recs.isEmpty()) firstConnection = true;
if (contactCounts.add(c) == 1) firstConnection = true; recs.add(new ConnectionRecord(t));
} }
eventBus.broadcast(new ConnectionOpenedEvent(c, t, incoming)); eventBus.broadcast(new ConnectionOpenedEvent(c, t, incoming));
if (firstConnection) { if (firstConnection) {
@@ -93,11 +101,10 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
} }
boolean lastConnection = false; boolean lastConnection = false;
synchronized (lock) { synchronized (lock) {
Multiset<ContactId> m = contactConnections.get(t); List<ConnectionRecord> recs = contactConnections.get(c);
if (m == null || !m.contains(c)) if (recs == null || !recs.remove(new ConnectionRecord(t)))
throw new IllegalArgumentException(); throw new IllegalArgumentException();
m.remove(c); if (recs.isEmpty()) lastConnection = true;
if (contactCounts.remove(c) == 0) lastConnection = true;
} }
eventBus.broadcast(new ConnectionClosedEvent(c, t, incoming)); eventBus.broadcast(new ConnectionClosedEvent(c, t, incoming));
if (lastConnection) { if (lastConnection) {
@@ -109,12 +116,20 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
@Override @Override
public Collection<ContactId> getConnectedContacts(TransportId t) { public Collection<ContactId> getConnectedContacts(TransportId t) {
synchronized (lock) { synchronized (lock) {
Multiset<ContactId> m = contactConnections.get(t); List<ContactId> contactIds = new ArrayList<>();
if (m == null) return emptyList(); for (Entry<ContactId, List<ConnectionRecord>> e :
List<ContactId> ids = new ArrayList<>(m.keySet()); contactConnections.entrySet()) {
if (LOG.isLoggable(INFO)) for (ConnectionRecord rec : e.getValue()) {
LOG.info(ids.size() + " contacts connected: " + t); if (rec.transportId.equals(t)) {
return ids; contactIds.add(e.getKey());
break;
}
}
}
if (LOG.isLoggable(INFO)) {
LOG.info(contactIds.size() + " contacts connected: " + t);
}
return contactIds;
} }
} }
@@ -122,34 +137,43 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
public Collection<ContactId> getConnectedOrPreferredContacts( public Collection<ContactId> getConnectedOrPreferredContacts(
TransportId t) { TransportId t) {
synchronized (lock) { synchronized (lock) {
Multiset<ContactId> m = contactConnections.get(t); List<TransportId> better = betterTransports.get(t);
if (m == null) return emptyList(); if (better == null) better = emptyList();
Set<ContactId> ids = new HashSet<>(m.keySet()); List<ContactId> contactIds = new ArrayList<>();
for (Pair<TransportId, TransportId> pair : preferences) { for (Entry<ContactId, List<ConnectionRecord>> e :
if (pair.getSecond().equals(t)) { contactConnections.entrySet()) {
TransportId better = pair.getFirst(); for (ConnectionRecord rec : e.getValue()) {
Multiset<ContactId> m1 = contactConnections.get(better); if (rec.transportId.equals(t) ||
if (m1 != null) ids.addAll(m1.keySet()); better.contains(rec.transportId)) {
contactIds.add(e.getKey());
break;
}
} }
} }
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO)) {
LOG.info(ids.size() + " contacts connected or preferred: " + t); LOG.info(contactIds.size()
return ids; + " contacts connected or preferred: " + t);
}
return contactIds;
} }
} }
@Override @Override
public boolean isConnected(ContactId c, TransportId t) { public boolean isConnected(ContactId c, TransportId t) {
synchronized (lock) { synchronized (lock) {
Multiset<ContactId> m = contactConnections.get(t); List<ConnectionRecord> recs = contactConnections.get(c);
return m != null && m.contains(c); if (recs == null) return false;
for (ConnectionRecord rec : recs) {
if (rec.transportId.equals(t)) return true;
}
return false;
} }
} }
@Override @Override
public boolean isConnected(ContactId c) { public boolean isConnected(ContactId c) {
synchronized (lock) { synchronized (lock) {
return contactCounts.contains(c); return contactConnections.containsKey(c);
} }
} }
@@ -171,4 +195,27 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
} }
eventBus.broadcast(new RendezvousConnectionClosedEvent(p, success)); eventBus.broadcast(new RendezvousConnectionClosedEvent(p, success));
} }
private static class ConnectionRecord {
private final TransportId transportId;
private ConnectionRecord(TransportId transportId) {
this.transportId = transportId;
}
@Override
public boolean equals(Object o) {
if (o instanceof ConnectionRecord) {
ConnectionRecord rec = (ConnectionRecord) o;
return transportId.equals(rec.transportId);
}
return false;
}
@Override
public int hashCode() {
return transportId.hashCode();
}
}
} }

View File

@@ -19,7 +19,6 @@ import org.junit.Test;
import java.util.Collection; import java.util.Collection;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.briarproject.bramble.test.TestUtils.getContactId; import static org.briarproject.bramble.test.TestUtils.getContactId;
import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getRandomId;
@@ -45,7 +44,7 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
public void testRegisterAndUnregister() { public void testRegisterAndUnregister() {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
allowing(pluginConfig).getTransportPreferences(); allowing(pluginConfig).getTransportPreferences();
will(returnValue(emptyMap())); will(returnValue(emptyList()));
}}); }});
ConnectionRegistry c = ConnectionRegistry c =
@@ -133,7 +132,7 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
public void testRegisterAndUnregisterPendingContacts() { public void testRegisterAndUnregisterPendingContacts() {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
allowing(pluginConfig).getTransportPreferences(); allowing(pluginConfig).getTransportPreferences();
will(returnValue(emptyMap())); will(returnValue(emptyList()));
}}); }});
ConnectionRegistry c = ConnectionRegistry c =