Brian O'Connor
Committed by Ray Milkey

adding sender-side accumulator to ecmap

Change-Id: I63de27131c067c07b41ca311b14ef3ac85b6ae3e
......@@ -15,51 +15,55 @@
*/
package org.onosproject.store.ecmap;
import com.google.common.collect.ImmutableList;
import org.onosproject.store.Timestamp;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Internal inter-instance event used by EventuallyConsistentMap for PUT events.
* Base class for events in an EventuallyConsistentMap.
*/
final class InternalPutEvent<K, V> {
private final List<PutEntry<K, V>> entries;
public abstract class AbstractEntry<K, V> implements Comparable<AbstractEntry<K, V>> {
private final K key;
private final Timestamp timestamp;
/**
* Creates a put event for a single key.
* Creates a new put entry.
*
* @param key key the event concerns
* @param value value of the key
* @param timestamp timestamp of the event
* @param key key of the entry
* @param timestamp timestamp of the put event
*/
public InternalPutEvent(K key, V value, Timestamp timestamp) {
entries = ImmutableList.of(new PutEntry<>(key, value, timestamp));
public AbstractEntry(K key, Timestamp timestamp) {
this.key = checkNotNull(key);
this.timestamp = checkNotNull(timestamp);
}
// Needed for serialization.
@SuppressWarnings("unused")
protected AbstractEntry() {
this.key = null;
this.timestamp = null;
}
/**
* Creates a put event for multiple keys.
* Returns the key of the entry.
*
* @param entries list of put entries to send an event for
* @return the key
*/
public InternalPutEvent(List<PutEntry<K, V>> entries) {
this.entries = checkNotNull(entries);
}
// Needed for serialization.
@SuppressWarnings("unused")
private InternalPutEvent() {
entries = null;
public K key() {
return key;
}
/**
* Returns the list of put entries this event concerns.
* Returns the timestamp of the event.
*
* @return list of put entries
* @return the timestamp
*/
public List<PutEntry<K, V>> entries() {
return entries;
public Timestamp timestamp() {
return timestamp;
}
@Override
public int compareTo(AbstractEntry<K, V> o) {
return this.timestamp.compareTo(o.timestamp);
}
}
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.store.ecmap;
import com.google.common.collect.ImmutableList;
import org.onosproject.store.Timestamp;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Internal inter-instance event used by EventuallyConsistentMap for REMOVE
* events.
*/
final class InternalRemoveEvent<K> {
private final List<RemoveEntry<K>> entries;
/**
* Creates a remove event for a single key.
*
* @param key key the event concerns
* @param timestamp timestamp of the event
*/
public InternalRemoveEvent(K key, Timestamp timestamp) {
entries = ImmutableList.of(new RemoveEntry<>(key, timestamp));
}
/**
* Creates a remove event for multiple keys.
*
* @param entries list of remove entries to send an event for
*/
public InternalRemoveEvent(List<RemoveEntry<K>> entries) {
this.entries = checkNotNull(entries);
}
// Needed for serialization.
@SuppressWarnings("unused")
private InternalRemoveEvent() {
entries = null;
}
/**
* Returns the list of remove entries this event concerns.
*
* @return list of remove entries
*/
public List<RemoveEntry<K>> entries() {
return entries;
}
}
......@@ -23,10 +23,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Describes a single put event in an EventuallyConsistentMap.
*/
final class PutEntry<K, V> {
private final K key;
final class PutEntry<K, V> extends AbstractEntry<K, V> {
private final V value;
private final Timestamp timestamp;
/**
* Creates a new put entry.
......@@ -36,26 +34,15 @@ final class PutEntry<K, V> {
* @param timestamp timestamp of the put event
*/
public PutEntry(K key, V value, Timestamp timestamp) {
this.key = checkNotNull(key);
super(key, timestamp);
this.value = checkNotNull(value);
this.timestamp = checkNotNull(timestamp);
}
// Needed for serialization.
@SuppressWarnings("unused")
private PutEntry() {
this.key = null;
super();
this.value = null;
this.timestamp = null;
}
/**
* Returns the key of the entry.
*
* @return the key
*/
public K key() {
return key;
}
/**
......@@ -67,21 +54,12 @@ final class PutEntry<K, V> {
return value;
}
/**
* Returns the timestamp of the event.
*
* @return the timestamp
*/
public Timestamp timestamp() {
return timestamp;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("key", key)
.add("key", key())
.add("value", value)
.add("timestamp", timestamp)
.add("timestamp", timestamp())
.toString();
}
}
......
......@@ -18,15 +18,10 @@ package org.onosproject.store.ecmap;
import com.google.common.base.MoreObjects;
import org.onosproject.store.Timestamp;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Describes a single remove event in an EventuallyConsistentMap.
*/
final class RemoveEntry<K> {
private final K key;
private final Timestamp timestamp;
final class RemoveEntry<K, V> extends AbstractEntry<K, V> {
/**
* Creates a new remove entry.
*
......@@ -34,40 +29,20 @@ final class RemoveEntry<K> {
* @param timestamp timestamp of the remove event
*/
public RemoveEntry(K key, Timestamp timestamp) {
this.key = checkNotNull(key);
this.timestamp = checkNotNull(timestamp);
super(key, timestamp);
}
// Needed for serialization.
@SuppressWarnings("unused")
private RemoveEntry() {
this.key = null;
this.timestamp = null;
}
/**
* Returns the key of the entry.
*
* @return the key
*/
public K key() {
return key;
}
/**
* Returns the timestamp of the event.
*
* @return the timestamp
*/
public Timestamp timestamp() {
return timestamp;
super();
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("key", key)
.add("timestamp", timestamp)
.add("key", key())
.add("timestamp", timestamp())
.toString();
}
}
......
......@@ -17,6 +17,7 @@ package org.onosproject.store.ecmap;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.After;
......@@ -67,10 +68,8 @@ public class EventuallyConsistentMapImplTest {
private SequentialClockService<String, String> clockService;
private static final String MAP_NAME = "test";
private static final MessageSubject PUT_MESSAGE_SUBJECT
private static final MessageSubject UPDATE_MESSAGE_SUBJECT
= new MessageSubject("ecm-" + MAP_NAME + "-update");
private static final MessageSubject REMOVE_MESSAGE_SUBJECT
= new MessageSubject("ecm-" + MAP_NAME + "-remove");
private static final MessageSubject ANTI_ENTROPY_MESSAGE_SUBJECT
= new MessageSubject("ecm-" + MAP_NAME + "-anti-entropy");
......@@ -82,8 +81,7 @@ public class EventuallyConsistentMapImplTest {
private final ControllerNode self =
new DefaultControllerNode(new NodeId("local"), IpAddress.valueOf(1));
private ClusterMessageHandler putHandler;
private ClusterMessageHandler removeHandler;
private ClusterMessageHandler updateHandler;
private ClusterMessageHandler antiEntropyHandler;
/*
......@@ -105,8 +103,6 @@ public class EventuallyConsistentMapImplTest {
.register(PutEntry.class)
.register(RemoveEntry.class)
.register(ArrayList.class)
.register(InternalPutEvent.class)
.register(InternalRemoveEvent.class)
.register(AntiEntropyAdvertisement.class)
.register(HashMap.class)
.build();
......@@ -237,7 +233,7 @@ public class EventuallyConsistentMapImplTest {
ecMap.addListener(new TestListener(latch));
assertNull(ecMap.get(KEY2));
putHandler.handle(message);
updateHandler.handle(message);
assertTrue("External listener never got notified of internal event",
latch.await(100, TimeUnit.MILLISECONDS));
assertEquals(VALUE2, ecMap.get(KEY2));
......@@ -254,7 +250,7 @@ public class EventuallyConsistentMapImplTest {
latch = new CountDownLatch(1);
ecMap.addListener(new TestListener(latch));
removeHandler.handle(removeMessage);
updateHandler.handle(removeMessage);
assertTrue("External listener never got notified of internal event",
latch.await(100, TimeUnit.MILLISECONDS));
assertNull(ecMap.get(KEY1));
......@@ -568,8 +564,7 @@ public class EventuallyConsistentMapImplTest {
@Test
public void testDestroy() throws Exception {
clusterCommunicator.removeSubscriber(PUT_MESSAGE_SUBJECT);
clusterCommunicator.removeSubscriber(REMOVE_MESSAGE_SUBJECT);
clusterCommunicator.removeSubscriber(UPDATE_MESSAGE_SUBJECT);
clusterCommunicator.removeSubscriber(ANTI_ENTROPY_MESSAGE_SUBJECT);
replay(clusterCommunicator);
......@@ -594,12 +589,11 @@ public class EventuallyConsistentMapImplTest {
}
private ClusterMessage generatePutMessage(String key, String value, Timestamp timestamp) {
InternalPutEvent<String, String> event =
new InternalPutEvent<>(key, value, timestamp);
PutEntry<String, String> event = new PutEntry<>(key, value, timestamp);
return new ClusterMessage(
clusterService.getLocalNode().id(), PUT_MESSAGE_SUBJECT,
SERIALIZER.encode(event));
clusterService.getLocalNode().id(), UPDATE_MESSAGE_SUBJECT,
SERIALIZER.encode(Lists.newArrayList(event)));
}
private ClusterMessage generatePutMessage(String key1, String value1, String key2, String value2) {
......@@ -614,38 +608,35 @@ public class EventuallyConsistentMapImplTest {
list.add(pe1);
list.add(pe2);
InternalPutEvent<String, String> event = new InternalPutEvent<>(list);
return new ClusterMessage(
clusterService.getLocalNode().id(), PUT_MESSAGE_SUBJECT,
SERIALIZER.encode(event));
clusterService.getLocalNode().id(), UPDATE_MESSAGE_SUBJECT,
SERIALIZER.encode(list));
}
private ClusterMessage generateRemoveMessage(String key, Timestamp timestamp) {
InternalRemoveEvent<String> event = new InternalRemoveEvent<>(key, timestamp);
RemoveEntry<String, String> event = new RemoveEntry<>(key, timestamp);
return new ClusterMessage(
clusterService.getLocalNode().id(), REMOVE_MESSAGE_SUBJECT,
SERIALIZER.encode(event));
clusterService.getLocalNode().id(), UPDATE_MESSAGE_SUBJECT,
SERIALIZER.encode(Lists.newArrayList(event)));
}
private ClusterMessage generateRemoveMessage(String key1, String key2) {
ArrayList<RemoveEntry<String>> list = new ArrayList<>();
ArrayList<RemoveEntry<String, String>> list = new ArrayList<>();
Timestamp timestamp1 = clockService.peek(1);
Timestamp timestamp2 = clockService.peek(2);
RemoveEntry<String> re1 = new RemoveEntry<>(key1, timestamp1);
RemoveEntry<String> re2 = new RemoveEntry<>(key2, timestamp2);
RemoveEntry<String, String> re1 = new RemoveEntry<>(key1, timestamp1);
RemoveEntry<String, String> re2 = new RemoveEntry<>(key2, timestamp2);
list.add(re1);
list.add(re2);
InternalRemoveEvent<String> event = new InternalRemoveEvent<>(list);
return new ClusterMessage(
clusterService.getLocalNode().id(), REMOVE_MESSAGE_SUBJECT,
SERIALIZER.encode(event));
clusterService.getLocalNode().id(), UPDATE_MESSAGE_SUBJECT,
SERIALIZER.encode(list));
}
/**
......@@ -655,10 +646,14 @@ public class EventuallyConsistentMapImplTest {
* @param m message we expect to be sent
* @param clusterCommunicator a mock ClusterCommunicationService to set up
*/
//FIXME rename
private static void expectSpecificBroadcastMessage(ClusterMessage m,
ClusterCommunicationService clusterCommunicator) {
reset(clusterCommunicator);
expect(clusterCommunicator.broadcast(m)).andReturn(true);
// expect(clusterCommunicator.broadcast(m)).andReturn(true);
expect(clusterCommunicator.unicast(eq(m), anyObject(NodeId.class)))
.andReturn(true)
.anyTimes();
replay(clusterCommunicator);
}
......@@ -669,10 +664,14 @@ public class EventuallyConsistentMapImplTest {
* @param m message we expect to be sent
* @param clusterCommunicator a mock ClusterCommunicationService to set up
*/
//FIXME rename
private static void expectSpecificMulticastMessage(ClusterMessage m,
ClusterCommunicationService clusterCommunicator) {
reset(clusterCommunicator);
expect(clusterCommunicator.multicast(eq(m), anyObject(Set.class))).andReturn(true);
// expect(clusterCommunicator.multicast(eq(m), anyObject(Set.class))).andReturn(true);
expect(clusterCommunicator.unicast(eq(m), anyObject(NodeId.class)))
.andReturn(true)
.anyTimes();
replay(clusterCommunicator);
}
......@@ -684,10 +683,13 @@ public class EventuallyConsistentMapImplTest {
*
* @param clusterCommunicator a mock ClusterCommunicationService to set up
*/
//FIXME rename
private void expectPeerMessage(ClusterCommunicationService clusterCommunicator) {
reset(clusterCommunicator);
expect(clusterCommunicator.multicast(anyObject(ClusterMessage.class),
anyObject(Iterable.class)))
// expect(clusterCommunicator.multicast(anyObject(ClusterMessage.class),
// anyObject(Iterable.class)))
expect(clusterCommunicator.unicast(anyObject(ClusterMessage.class),
anyObject(NodeId.class)))
.andReturn(true)
.anyTimes();
replay(clusterCommunicator);
......@@ -700,9 +702,13 @@ public class EventuallyConsistentMapImplTest {
*
* @param clusterCommunicator a mock ClusterCommunicationService to set up
*/
//FIXME rename
private void expectBroadcastMessage(ClusterCommunicationService clusterCommunicator) {
reset(clusterCommunicator);
expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
// expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
// .andReturn(true)
// .anyTimes();
expect(clusterCommunicator.unicast(anyObject(ClusterMessage.class), anyObject(NodeId.class)))
.andReturn(true)
.anyTimes();
replay(clusterCommunicator);
......@@ -747,10 +753,8 @@ public class EventuallyConsistentMapImplTest {
@Override
public void addSubscriber(MessageSubject subject,
ClusterMessageHandler subscriber) {
if (subject.equals(PUT_MESSAGE_SUBJECT)) {
putHandler = subscriber;
} else if (subject.equals(REMOVE_MESSAGE_SUBJECT)) {
removeHandler = subscriber;
if (subject.equals(UPDATE_MESSAGE_SUBJECT)) {
updateHandler = subscriber;
} else if (subject.equals(ANTI_ENTROPY_MESSAGE_SUBJECT)) {
antiEntropyHandler = subscriber;
} else {
......@@ -762,10 +766,8 @@ public class EventuallyConsistentMapImplTest {
public void addSubscriber(MessageSubject subject,
ClusterMessageHandler subscriber,
ExecutorService executor) {
if (subject.equals(PUT_MESSAGE_SUBJECT)) {
putHandler = subscriber;
} else if (subject.equals(REMOVE_MESSAGE_SUBJECT)) {
removeHandler = subscriber;
if (subject.equals(UPDATE_MESSAGE_SUBJECT)) {
updateHandler = subscriber;
} else if (subject.equals(ANTI_ENTROPY_MESSAGE_SUBJECT)) {
antiEntropyHandler = subscriber;
} else {
......