Jonathan Hart
Committed by Ray Milkey

Implemented a Builder pattern for EventuallyConsistentMaps.

EventuallyConsistentMap has been moved to the API package so is now available outside the stores.

ONOS-1357

Change-Id: I1c892eb3dbefa72cb3f3eb3ccc74e9a02c7e2ac9
Showing 17 changed files with 589 additions and 237 deletions
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.store.impl; 16 +package org.onosproject.store.service;
17 17
18 import org.onosproject.store.Timestamp; 18 import org.onosproject.store.Timestamp;
19 19
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.store.ecmap; 16 +package org.onosproject.store.service;
17 17
18 import java.util.Collection; 18 import java.util.Collection;
19 import java.util.Map; 19 import java.util.Map;
...@@ -114,7 +114,7 @@ public interface EventuallyConsistentMap<K, V> { ...@@ -114,7 +114,7 @@ public interface EventuallyConsistentMap<K, V> {
114 * Removes the given key-value mapping from the map, if it exists. 114 * Removes the given key-value mapping from the map, if it exists.
115 * <p> 115 * <p>
116 * This actually means remove any values up to and including the timestamp 116 * This actually means remove any values up to and including the timestamp
117 - * given by {@link org.onosproject.store.impl.ClockService#getTimestamp(Object, Object)}. 117 + * given by {@link org.onosproject.store.service.ClockService#getTimestamp(Object, Object)}.
118 * Any mappings that produce an earlier timestamp than this given key-value 118 * Any mappings that produce an earlier timestamp than this given key-value
119 * pair will be removed, and any mappings that produce a later timestamp 119 * pair will be removed, and any mappings that produce a later timestamp
120 * will supersede this remove. 120 * will supersede this remove.
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.store.service;
18 +
19 +import org.onlab.util.KryoNamespace;
20 +import org.onosproject.cluster.NodeId;
21 +
22 +import java.util.Collection;
23 +import java.util.concurrent.ExecutorService;
24 +import java.util.concurrent.ScheduledExecutorService;
25 +import java.util.concurrent.TimeUnit;
26 +import java.util.function.BiFunction;
27 +
28 +/**
29 + * Builder for eventually consistent maps.
30 + *
31 + * @param <K> type for map keys
32 + * @param <V> type for map values
33 + */
34 +public interface EventuallyConsistentMapBuilder<K, V> {
35 +
36 + /**
37 + * Sets the name of the map.
38 + * <p>
39 + * Each map is identified by a string map name. EventuallyConsistentMapImpl
40 + * objects in different JVMs that use the same map name will form a
41 + * distributed map across JVMs (provided the cluster service is aware of
42 + * both nodes).
43 + * </p>
44 + * <p>
45 + * Note: This is a mandatory parameter.
46 + * </p>
47 + *
48 + * @param name name of the map
49 + * @return this EventuallyConsistentMapBuilder
50 + */
51 + public EventuallyConsistentMapBuilder<K, V> withName(String name);
52 +
53 + /**
54 + * Sets a serializer builder that can be used to create a serializer that
55 + * can serialize both the keys and values put into the map. The serializer
56 + * builder should be pre-populated with any classes that will be put into
57 + * the map.
58 + * <p>
59 + * Note: This is a mandatory parameter.
60 + * </p>
61 + *
62 + * @param serializerBuilder serializer builder
63 + * @return this EventuallyConsistentMapBuilder
64 + */
65 + public EventuallyConsistentMapBuilder<K, V> withSerializer(
66 + KryoNamespace.Builder serializerBuilder);
67 +
68 + /**
69 + * Sets the clock service to use for generating timestamps for map updates.
70 + * <p>
71 + * The client must provide an {@link org.onosproject.store.service.ClockService}
72 + * which can generate timestamps for a given key. The clock service is free
73 + * to generate timestamps however it wishes, however these timestamps will
74 + * be used to serialize updates to the map so they must be strict enough
75 + * to ensure updates are properly ordered for the use case (i.e. in some
76 + * cases wallclock time will suffice, whereas in other cases logical time
77 + * will be necessary).
78 + * </p>
79 + * <p>
80 + * Note: This is a mandatory parameter.
81 + * </p>
82 + *
83 + * @param clockService clock service
84 + * @return this EventuallyConsistentMapBuilder
85 + */
86 + public EventuallyConsistentMapBuilder<K, V> withClockService(
87 + ClockService<K, V> clockService);
88 +
89 + /**
90 + * Sets the executor to use for processing events coming in from peers.
91 + *
92 + * @param executor event executor
93 + * @return this EventuallyConsistentMapBuilder
94 + */
95 + public EventuallyConsistentMapBuilder<K, V> withEventExecutor(
96 + ExecutorService executor);
97 +
98 + /**
99 + * Sets the executor to use for sending events to peers.
100 + *
101 + * @param executor event executor
102 + * @return this EventuallyConsistentMapBuilder
103 + */
104 + public EventuallyConsistentMapBuilder<K, V> withCommunicationExecutor(
105 + ExecutorService executor);
106 +
107 + /**
108 + * Sets the executor to use for background anti-entropy tasks.
109 + *
110 + * @param executor event executor
111 + * @return this EventuallyConsistentMapBuilder
112 + */
113 + public EventuallyConsistentMapBuilder<K, V> withBackgroundExecutor(
114 + ScheduledExecutorService executor);
115 +
116 + /**
117 + * Sets a function that can determine which peers to replicate updates to.
118 + * <p>
119 + * The default function replicates to all nodes.
120 + * </p>
121 + *
122 + * @param peerUpdateFunction function that takes a K, V input and returns
123 + * a collection of NodeIds to replicate the event
124 + * to
125 + * @return this EventuallyConsistentMapBuilder
126 + */
127 + public EventuallyConsistentMapBuilder<K, V> withPeerUpdateFunction(
128 + BiFunction<K, V, Collection<NodeId>> peerUpdateFunction);
129 +
130 + /**
131 + * Prevents this map from writing tombstones of items that have been
132 + * removed. This may result in zombie items reappearing after they have
133 + * been removed.
134 + * <p>
135 + * The default behavior is tombstones are enabled.
136 + * </p>
137 + *
138 + * @return this EventuallyConsistentMapBuilder
139 + */
140 + public EventuallyConsistentMapBuilder<K, V> withTombstonesDisabled();
141 +
142 + /**
143 + * Configures how often to run the anti-entropy background task.
144 + * <p>
145 + * The default anti-entropy period is 5 seconds.
146 + * </p>
147 + *
148 + * @param period anti-entropy period
149 + * @param unit time unit for the period
150 + * @return this EventuallyConsistentMapBuilder
151 + */
152 + public EventuallyConsistentMapBuilder<K, V> withAntiEntropyPeriod(
153 + long period, TimeUnit unit);
154 +
155 + /**
156 + * Configure anti-entropy to converge faster at the cost of doing more work
157 + * for each anti-entropy cycle. Suited to maps with low update rate where
158 + * convergence time is more important than throughput.
159 + * <p>
160 + * The default behavior is to do less anti-entropy work at the cost of
161 + * slower convergence.
162 + * </p>
163 + *
164 + * @return this EventuallyConsistentMapBuilder
165 + */
166 + public EventuallyConsistentMapBuilder<K, V> withFasterConvergence();
167 +
168 + /**
169 + * Builds an eventually consistent map based on the configuration options
170 + * supplied to this builder.
171 + *
172 + * @return new eventually consistent map
173 + * @throws java.lang.RuntimeException if a mandatory parameter is missing
174 + */
175 + public EventuallyConsistentMap<K, V> build();
176 +}
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.store.ecmap; 16 +package org.onosproject.store.service;
17 17
18 import com.google.common.base.MoreObjects; 18 import com.google.common.base.MoreObjects;
19 19
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.store.ecmap; 16 +package org.onosproject.store.service;
17 17
18 /** 18 /**
19 * Listener interested in receiving modification events for an 19 * Listener interested in receiving modification events for an
......
...@@ -30,6 +30,7 @@ public interface StorageService { ...@@ -30,6 +30,7 @@ public interface StorageService {
30 30
31 /** 31 /**
32 * Creates a ConsistentMap. 32 * Creates a ConsistentMap.
33 + *
33 * @param name map name 34 * @param name map name
34 * @param serializer serializer to use for serializing keys and values 35 * @param serializer serializer to use for serializing keys and values
35 * @return consistent map. 36 * @return consistent map.
...@@ -40,6 +41,7 @@ public interface StorageService { ...@@ -40,6 +41,7 @@ public interface StorageService {
40 41
41 /** 42 /**
42 * Creates a AsyncConsistentMap. 43 * Creates a AsyncConsistentMap.
44 + *
43 * @param name map name 45 * @param name map name
44 * @param serializer serializer to use for serializing keys and values 46 * @param serializer serializer to use for serializing keys and values
45 * @return async consistent map 47 * @return async consistent map
...@@ -50,7 +52,18 @@ public interface StorageService { ...@@ -50,7 +52,18 @@ public interface StorageService {
50 52
51 /** 53 /**
52 * Creates a new transaction context. 54 * Creates a new transaction context.
55 + *
53 * @return transaction context 56 * @return transaction context
54 */ 57 */
55 TransactionContext createTransactionContext(); 58 TransactionContext createTransactionContext();
56 -}
...\ No newline at end of file ...\ No newline at end of file
59 +
60 + /**
61 + * Creates a new EventuallyConsistentMapBuilder.
62 + *
63 + * @param <K> key type
64 + * @param <V> value type
65 + * @return builder for an eventually consistent map
66 + */
67 + <K, V> EventuallyConsistentMapBuilder<K, V> eventuallyConsistentMapBuilder();
68 +
69 +}
......
...@@ -43,14 +43,14 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService; ...@@ -43,14 +43,14 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
43 import org.onosproject.store.cluster.messaging.ClusterMessage; 43 import org.onosproject.store.cluster.messaging.ClusterMessage;
44 import org.onosproject.store.cluster.messaging.ClusterMessageHandler; 44 import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
45 import org.onosproject.store.cluster.messaging.MessageSubject; 45 import org.onosproject.store.cluster.messaging.MessageSubject;
46 -import org.onosproject.store.ecmap.EventuallyConsistentMap;
47 -import org.onosproject.store.ecmap.EventuallyConsistentMapEvent;
48 -import org.onosproject.store.ecmap.EventuallyConsistentMapImpl;
49 -import org.onosproject.store.ecmap.EventuallyConsistentMapListener;
50 -import org.onosproject.store.impl.ClockService;
51 import org.onosproject.store.impl.MultiValuedTimestamp; 46 import org.onosproject.store.impl.MultiValuedTimestamp;
52 import org.onosproject.store.impl.WallclockClockManager; 47 import org.onosproject.store.impl.WallclockClockManager;
53 import org.onosproject.store.serializers.KryoNamespaces; 48 import org.onosproject.store.serializers.KryoNamespaces;
49 +import org.onosproject.store.service.ClockService;
50 +import org.onosproject.store.service.EventuallyConsistentMap;
51 +import org.onosproject.store.service.EventuallyConsistentMapEvent;
52 +import org.onosproject.store.service.EventuallyConsistentMapListener;
53 +import org.onosproject.store.service.StorageService;
54 import org.slf4j.Logger; 54 import org.slf4j.Logger;
55 55
56 import java.io.ByteArrayInputStream; 56 import java.io.ByteArrayInputStream;
...@@ -66,10 +66,16 @@ import java.util.concurrent.atomic.AtomicLong; ...@@ -66,10 +66,16 @@ import java.util.concurrent.atomic.AtomicLong;
66 import static com.google.common.io.ByteStreams.toByteArray; 66 import static com.google.common.io.ByteStreams.toByteArray;
67 import static java.util.concurrent.TimeUnit.MILLISECONDS; 67 import static java.util.concurrent.TimeUnit.MILLISECONDS;
68 import static org.onlab.util.Tools.groupedThreads; 68 import static org.onlab.util.Tools.groupedThreads;
69 -import static org.onosproject.app.ApplicationEvent.Type.*; 69 +import static org.onosproject.app.ApplicationEvent.Type.APP_ACTIVATED;
70 -import static org.onosproject.store.app.GossipApplicationStore.InternalState.*; 70 +import static org.onosproject.app.ApplicationEvent.Type.APP_DEACTIVATED;
71 -import static org.onosproject.store.ecmap.EventuallyConsistentMapEvent.Type.PUT; 71 +import static org.onosproject.app.ApplicationEvent.Type.APP_INSTALLED;
72 -import static org.onosproject.store.ecmap.EventuallyConsistentMapEvent.Type.REMOVE; 72 +import static org.onosproject.app.ApplicationEvent.Type.APP_PERMISSIONS_CHANGED;
73 +import static org.onosproject.app.ApplicationEvent.Type.APP_UNINSTALLED;
74 +import static org.onosproject.store.app.GossipApplicationStore.InternalState.ACTIVATED;
75 +import static org.onosproject.store.app.GossipApplicationStore.InternalState.DEACTIVATED;
76 +import static org.onosproject.store.app.GossipApplicationStore.InternalState.INSTALLED;
77 +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT;
78 +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE;
73 import static org.slf4j.LoggerFactory.getLogger; 79 import static org.slf4j.LoggerFactory.getLogger;
74 80
75 /** 81 /**
...@@ -106,6 +112,9 @@ public class GossipApplicationStore extends ApplicationArchive ...@@ -106,6 +112,9 @@ public class GossipApplicationStore extends ApplicationArchive
106 protected ClusterService clusterService; 112 protected ClusterService clusterService;
107 113
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 + protected StorageService storageService;
116 +
117 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected ApplicationIdStore idStore; 118 protected ApplicationIdStore idStore;
110 119
111 private final AtomicLong sequence = new AtomicLong(); 120 private final AtomicLong sequence = new AtomicLong();
...@@ -130,27 +139,29 @@ public class GossipApplicationStore extends ApplicationArchive ...@@ -130,27 +139,29 @@ public class GossipApplicationStore extends ApplicationArchive
130 new MultiValuedTimestamp<>(getUpdateTime(appId.name()), 139 new MultiValuedTimestamp<>(getUpdateTime(appId.name()),
131 sequence.incrementAndGet()); 140 sequence.incrementAndGet());
132 141
133 - apps = new EventuallyConsistentMapImpl<>("apps", clusterService, 142 + apps = storageService.<ApplicationId, Application>eventuallyConsistentMapBuilder()
134 - clusterCommunicator, 143 + .withName("apps")
135 - serializer, 144 + .withSerializer(serializer)
136 - appsClockService); 145 + .withClockService(appsClockService)
146 + .build();
137 147
138 ClockService<Application, InternalState> statesClockService = (app, state) -> 148 ClockService<Application, InternalState> statesClockService = (app, state) ->
139 new MultiValuedTimestamp<>(getUpdateTime(app.id().name()), 149 new MultiValuedTimestamp<>(getUpdateTime(app.id().name()),
140 sequence.incrementAndGet()); 150 sequence.incrementAndGet());
141 151
142 - states = new EventuallyConsistentMapImpl<>("app-states", 152 + states = storageService.<Application, InternalState>eventuallyConsistentMapBuilder()
143 - clusterService, 153 + .withName("app-states")
144 - clusterCommunicator, 154 + .withSerializer(serializer)
145 - serializer, 155 + .withClockService(statesClockService)
146 - statesClockService); 156 + .build();
157 +
147 states.addListener(new InternalAppStatesListener()); 158 states.addListener(new InternalAppStatesListener());
148 159
149 - permissions = new EventuallyConsistentMapImpl<>("app-permissions", 160 + permissions = storageService.<Application, Set<Permission>>eventuallyConsistentMapBuilder()
150 - clusterService, 161 + .withName("app-permissions")
151 - clusterCommunicator, 162 + .withSerializer(serializer)
152 - serializer, 163 + .withClockService(new WallclockClockManager<>())
153 - new WallclockClockManager<>()); 164 + .build();
154 165
155 log.info("Started"); 166 log.info("Started");
156 } 167 }
......
...@@ -25,21 +25,19 @@ import org.onlab.util.KryoNamespace; ...@@ -25,21 +25,19 @@ import org.onlab.util.KryoNamespace;
25 import org.onosproject.cfg.ComponentConfigEvent; 25 import org.onosproject.cfg.ComponentConfigEvent;
26 import org.onosproject.cfg.ComponentConfigStore; 26 import org.onosproject.cfg.ComponentConfigStore;
27 import org.onosproject.cfg.ComponentConfigStoreDelegate; 27 import org.onosproject.cfg.ComponentConfigStoreDelegate;
28 -import org.onosproject.cluster.ClusterService;
29 import org.onosproject.store.AbstractStore; 28 import org.onosproject.store.AbstractStore;
30 -import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
31 -import org.onosproject.store.ecmap.EventuallyConsistentMap;
32 -import org.onosproject.store.ecmap.EventuallyConsistentMapEvent;
33 -import org.onosproject.store.ecmap.EventuallyConsistentMapImpl;
34 -import org.onosproject.store.ecmap.EventuallyConsistentMapListener;
35 import org.onosproject.store.impl.WallclockClockManager; 29 import org.onosproject.store.impl.WallclockClockManager;
36 import org.onosproject.store.serializers.KryoNamespaces; 30 import org.onosproject.store.serializers.KryoNamespaces;
31 +import org.onosproject.store.service.EventuallyConsistentMap;
32 +import org.onosproject.store.service.EventuallyConsistentMapEvent;
33 +import org.onosproject.store.service.EventuallyConsistentMapListener;
34 +import org.onosproject.store.service.StorageService;
37 import org.slf4j.Logger; 35 import org.slf4j.Logger;
38 36
39 import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_SET; 37 import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_SET;
40 import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_UNSET; 38 import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_UNSET;
41 -import static org.onosproject.store.ecmap.EventuallyConsistentMapEvent.Type.PUT; 39 +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT;
42 -import static org.onosproject.store.ecmap.EventuallyConsistentMapEvent.Type.REMOVE; 40 +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE;
43 import static org.slf4j.LoggerFactory.getLogger; 41 import static org.slf4j.LoggerFactory.getLogger;
44 42
45 /** 43 /**
...@@ -59,20 +57,19 @@ public class GossipComponentConfigStore ...@@ -59,20 +57,19 @@ public class GossipComponentConfigStore
59 private EventuallyConsistentMap<String, String> properties; 57 private EventuallyConsistentMap<String, String> properties;
60 58
61 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 59 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 - protected ClusterCommunicationService clusterCommunicator; 60 + protected StorageService storageService;
63 -
64 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 - protected ClusterService clusterService;
66 61
67 @Activate 62 @Activate
68 public void activate() { 63 public void activate() {
69 KryoNamespace.Builder serializer = KryoNamespace.newBuilder() 64 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
70 .register(KryoNamespaces.API); 65 .register(KryoNamespaces.API);
71 66
72 - properties = new EventuallyConsistentMapImpl<>("cfg", clusterService, 67 + properties = storageService.<String, String>eventuallyConsistentMapBuilder()
73 - clusterCommunicator, 68 + .withName("cfg")
74 - serializer, 69 + .withSerializer(serializer)
75 - new WallclockClockManager<>()); 70 + .withClockService(new WallclockClockManager<>())
71 + .build();
72 +
76 properties.addListener(new InternalPropertiesListener()); 73 properties.addListener(new InternalPropertiesListener());
77 log.info("Started"); 74 log.info("Started");
78 } 75 }
......
...@@ -17,13 +17,11 @@ ...@@ -17,13 +17,11 @@
17 package org.onosproject.store.consistent.impl; 17 package org.onosproject.store.consistent.impl;
18 18
19 import com.google.common.collect.Sets; 19 import com.google.common.collect.Sets;
20 -
21 import net.kuujo.copycat.cluster.ClusterConfig; 20 import net.kuujo.copycat.cluster.ClusterConfig;
22 import net.kuujo.copycat.cluster.Member; 21 import net.kuujo.copycat.cluster.Member;
23 import net.kuujo.copycat.log.FileLog; 22 import net.kuujo.copycat.log.FileLog;
24 import net.kuujo.copycat.netty.NettyTcpProtocol; 23 import net.kuujo.copycat.netty.NettyTcpProtocol;
25 import net.kuujo.copycat.protocol.Consistency; 24 import net.kuujo.copycat.protocol.Consistency;
26 -
27 import org.apache.felix.scr.annotations.Activate; 25 import org.apache.felix.scr.annotations.Activate;
28 import org.apache.felix.scr.annotations.Component; 26 import org.apache.felix.scr.annotations.Component;
29 import org.apache.felix.scr.annotations.Deactivate; 27 import org.apache.felix.scr.annotations.Deactivate;
...@@ -32,8 +30,11 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; ...@@ -32,8 +30,11 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
32 import org.apache.felix.scr.annotations.Service; 30 import org.apache.felix.scr.annotations.Service;
33 import org.onosproject.cluster.ClusterService; 31 import org.onosproject.cluster.ClusterService;
34 import org.onosproject.store.cluster.impl.NodeInfo; 32 import org.onosproject.store.cluster.impl.NodeInfo;
33 +import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
34 +import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl;
35 import org.onosproject.store.service.AsyncConsistentMap; 35 import org.onosproject.store.service.AsyncConsistentMap;
36 import org.onosproject.store.service.ConsistentMap; 36 import org.onosproject.store.service.ConsistentMap;
37 +import org.onosproject.store.service.EventuallyConsistentMapBuilder;
37 import org.onosproject.store.service.PartitionInfo; 38 import org.onosproject.store.service.PartitionInfo;
38 import org.onosproject.store.service.Serializer; 39 import org.onosproject.store.service.Serializer;
39 import org.onosproject.store.service.StorageAdminService; 40 import org.onosproject.store.service.StorageAdminService;
...@@ -71,6 +72,9 @@ public class DatabaseManager implements StorageService, StorageAdminService { ...@@ -71,6 +72,9 @@ public class DatabaseManager implements StorageService, StorageAdminService {
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected ClusterService clusterService; 73 protected ClusterService clusterService;
73 74
75 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 + protected ClusterCommunicationService clusterCommunicator;
77 +
74 protected String nodeToUri(NodeInfo node) { 78 protected String nodeToUri(NodeInfo node) {
75 return String.format("tcp://%s:%d", node.getIp(), COPYCAT_TCP_PORT); 79 return String.format("tcp://%s:%d", node.getIp(), COPYCAT_TCP_PORT);
76 } 80 }
...@@ -169,12 +173,12 @@ public class DatabaseManager implements StorageService, StorageAdminService { ...@@ -169,12 +173,12 @@ public class DatabaseManager implements StorageService, StorageAdminService {
169 173
170 @Override 174 @Override
171 public <K, V> ConsistentMap<K , V> createConsistentMap(String name, Serializer serializer) { 175 public <K, V> ConsistentMap<K , V> createConsistentMap(String name, Serializer serializer) {
172 - return new DefaultConsistentMap<K, V>(name, partitionedDatabase, serializer); 176 + return new DefaultConsistentMap<>(name, partitionedDatabase, serializer);
173 } 177 }
174 178
175 @Override 179 @Override
176 public <K, V> AsyncConsistentMap<K , V> createAsyncConsistentMap(String name, Serializer serializer) { 180 public <K, V> AsyncConsistentMap<K , V> createAsyncConsistentMap(String name, Serializer serializer) {
177 - return new DefaultAsyncConsistentMap<K, V>(name, partitionedDatabase, serializer); 181 + return new DefaultAsyncConsistentMap<>(name, partitionedDatabase, serializer);
178 } 182 }
179 183
180 @Override 184 @Override
...@@ -207,4 +211,12 @@ public class DatabaseManager implements StorageService, StorageAdminService { ...@@ -207,4 +211,12 @@ public class DatabaseManager implements StorageService, StorageAdminService {
207 database.cluster().leader() != null ? 211 database.cluster().leader() != null ?
208 database.cluster().leader().uri() : null); 212 database.cluster().leader().uri() : null);
209 } 213 }
214 +
215 +
216 + @Override
217 + public <K, V> EventuallyConsistentMapBuilder<K, V> eventuallyConsistentMapBuilder() {
218 + return new EventuallyConsistentMapBuilderImpl<>(clusterService,
219 + clusterCommunicator);
220 + }
221 +
210 } 222 }
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.store.ecmap;
17 +
18 +import org.onlab.util.KryoNamespace;
19 +import org.onosproject.cluster.ClusterService;
20 +import org.onosproject.cluster.NodeId;
21 +import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
22 +import org.onosproject.store.service.ClockService;
23 +import org.onosproject.store.service.EventuallyConsistentMap;
24 +import org.onosproject.store.service.EventuallyConsistentMapBuilder;
25 +
26 +import java.util.Collection;
27 +import java.util.concurrent.ExecutorService;
28 +import java.util.concurrent.ScheduledExecutorService;
29 +import java.util.concurrent.TimeUnit;
30 +import java.util.function.BiFunction;
31 +
32 +import static com.google.common.base.Preconditions.checkArgument;
33 +import static com.google.common.base.Preconditions.checkNotNull;
34 +
35 +/**
36 + * Eventually consistent map builder.
37 + */
38 +public class EventuallyConsistentMapBuilderImpl<K, V>
39 + implements EventuallyConsistentMapBuilder<K, V> {
40 + private final ClusterService clusterService;
41 + private final ClusterCommunicationService clusterCommunicator;
42 +
43 + private String name;
44 + private KryoNamespace.Builder serializerBuilder;
45 + private ExecutorService eventExecutor;
46 + private ExecutorService communicationExecutor;
47 + private ScheduledExecutorService backgroundExecutor;
48 + private ClockService<K, V> clockService;
49 + private BiFunction<K, V, Collection<NodeId>> peerUpdateFunction;
50 + private boolean tombstonesDisabled = false;
51 + private long antiEntropyPeriod = 5;
52 + private TimeUnit antiEntropyTimeUnit = TimeUnit.SECONDS;
53 + private boolean convergeFaster = false;
54 +
55 + /**
56 + * Creates a new eventually consistent map builder.
57 + *
58 + * @param clusterService cluster service
59 + * @param clusterCommunicator cluster communication service
60 + */
61 + public EventuallyConsistentMapBuilderImpl(ClusterService clusterService,
62 + ClusterCommunicationService clusterCommunicator) {
63 + this.clusterService = checkNotNull(clusterService);
64 + this.clusterCommunicator = checkNotNull(clusterCommunicator);
65 + }
66 +
67 + @Override
68 + public EventuallyConsistentMapBuilder withName(String name) {
69 + this.name = checkNotNull(name);
70 + return this;
71 + }
72 +
73 + @Override
74 + public EventuallyConsistentMapBuilder withSerializer(
75 + KryoNamespace.Builder serializerBuilder) {
76 + this.serializerBuilder = checkNotNull(serializerBuilder);
77 + return this;
78 + }
79 +
80 + @Override
81 + public EventuallyConsistentMapBuilder withClockService(
82 + ClockService<K, V> clockService) {
83 + this.clockService = checkNotNull(clockService);
84 + return this;
85 + }
86 +
87 + @Override
88 + public EventuallyConsistentMapBuilder withEventExecutor(ExecutorService executor) {
89 + this.eventExecutor = checkNotNull(executor);
90 + return this;
91 + }
92 +
93 + @Override
94 + public EventuallyConsistentMapBuilder<K, V> withCommunicationExecutor(
95 + ExecutorService executor) {
96 + communicationExecutor = checkNotNull(executor);
97 + return this;
98 + }
99 +
100 + @Override
101 + public EventuallyConsistentMapBuilder withBackgroundExecutor(ScheduledExecutorService executor) {
102 + this.backgroundExecutor = checkNotNull(executor);
103 + return this;
104 + }
105 +
106 + @Override
107 + public EventuallyConsistentMapBuilder withPeerUpdateFunction(
108 + BiFunction<K, V, Collection<NodeId>> peerUpdateFunction) {
109 + this.peerUpdateFunction = checkNotNull(peerUpdateFunction);
110 + return this;
111 + }
112 +
113 + @Override
114 + public EventuallyConsistentMapBuilder<K, V> withTombstonesDisabled() {
115 + tombstonesDisabled = true;
116 + return this;
117 + }
118 +
119 + @Override
120 + public EventuallyConsistentMapBuilder<K, V> withAntiEntropyPeriod(long period, TimeUnit unit) {
121 + checkArgument(period > 0, "anti-entropy period must be greater than 0");
122 + antiEntropyPeriod = period;
123 + antiEntropyTimeUnit = checkNotNull(unit);
124 + return this;
125 + }
126 +
127 + @Override
128 + public EventuallyConsistentMapBuilder<K, V> withFasterConvergence() {
129 + convergeFaster = true;
130 + return this;
131 + }
132 +
133 + @Override
134 + public EventuallyConsistentMap<K, V> build() {
135 + checkNotNull(name, "name is a mandatory parameter");
136 + checkNotNull(serializerBuilder, "serializerBuilder is a mandatory parameter");
137 + checkNotNull(clockService, "clockService is a mandatory parameter");
138 +
139 + return new EventuallyConsistentMapImpl<>(name,
140 + clusterService,
141 + clusterCommunicator,
142 + serializerBuilder,
143 + clockService,
144 + peerUpdateFunction,
145 + eventExecutor,
146 + communicationExecutor,
147 + backgroundExecutor,
148 + tombstonesDisabled,
149 + antiEntropyPeriod,
150 + antiEntropyTimeUnit,
151 + convergeFaster);
152 + }
153 +}
...@@ -32,10 +32,13 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService; ...@@ -32,10 +32,13 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
32 import org.onosproject.store.cluster.messaging.ClusterMessage; 32 import org.onosproject.store.cluster.messaging.ClusterMessage;
33 import org.onosproject.store.cluster.messaging.ClusterMessageHandler; 33 import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
34 import org.onosproject.store.cluster.messaging.MessageSubject; 34 import org.onosproject.store.cluster.messaging.MessageSubject;
35 -import org.onosproject.store.impl.ClockService;
36 import org.onosproject.store.impl.Timestamped; 35 import org.onosproject.store.impl.Timestamped;
37 import org.onosproject.store.impl.WallClockTimestamp; 36 import org.onosproject.store.impl.WallClockTimestamp;
38 import org.onosproject.store.serializers.KryoSerializer; 37 import org.onosproject.store.serializers.KryoSerializer;
38 +import org.onosproject.store.service.ClockService;
39 +import org.onosproject.store.service.EventuallyConsistentMap;
40 +import org.onosproject.store.service.EventuallyConsistentMapEvent;
41 +import org.onosproject.store.service.EventuallyConsistentMapListener;
39 import org.slf4j.Logger; 42 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory; 43 import org.slf4j.LoggerFactory;
41 44
...@@ -54,7 +57,6 @@ import java.util.concurrent.ExecutorService; ...@@ -54,7 +57,6 @@ import java.util.concurrent.ExecutorService;
54 import java.util.concurrent.Executors; 57 import java.util.concurrent.Executors;
55 import java.util.concurrent.ScheduledExecutorService; 58 import java.util.concurrent.ScheduledExecutorService;
56 import java.util.concurrent.TimeUnit; 59 import java.util.concurrent.TimeUnit;
57 -import java.util.concurrent.atomic.AtomicLong;
58 import java.util.function.BiFunction; 60 import java.util.function.BiFunction;
59 import java.util.stream.Collectors; 61 import java.util.stream.Collectors;
60 62
...@@ -93,8 +95,8 @@ public class EventuallyConsistentMapImpl<K, V> ...@@ -93,8 +95,8 @@ public class EventuallyConsistentMapImpl<K, V>
93 private final ScheduledExecutorService backgroundExecutor; 95 private final ScheduledExecutorService backgroundExecutor;
94 private final BiFunction<K, V, Collection<NodeId>> peerUpdateFunction; 96 private final BiFunction<K, V, Collection<NodeId>> peerUpdateFunction;
95 97
96 - private ExecutorService communicationExecutor; 98 + private final ExecutorService communicationExecutor;
97 - private Map<NodeId, EventAccumulator> senderPending; 99 + private final Map<NodeId, EventAccumulator> senderPending;
98 100
99 private volatile boolean destroyed = false; 101 private volatile boolean destroyed = false;
100 private static final String ERROR_DESTROYED = " map is already destroyed"; 102 private static final String ERROR_DESTROYED = " map is already destroyed";
...@@ -103,130 +105,115 @@ public class EventuallyConsistentMapImpl<K, V> ...@@ -103,130 +105,115 @@ public class EventuallyConsistentMapImpl<K, V>
103 private static final String ERROR_NULL_KEY = "Key cannot be null"; 105 private static final String ERROR_NULL_KEY = "Key cannot be null";
104 private static final String ERROR_NULL_VALUE = "Null values are not allowed"; 106 private static final String ERROR_NULL_VALUE = "Null values are not allowed";
105 107
106 - // TODO: Make these anti-entropy params configurable 108 + private final long initialDelaySec = 5;
107 - private long initialDelaySec = 5; 109 + private final boolean lightweightAntiEntropy;
108 - private long periodSec = 5; 110 + private final boolean tombstonesDisabled;
109 - private boolean lightweightAntiEntropy = true;
110 - private boolean tombstonesDisabled = false;
111 111
112 private static final int WINDOW_SIZE = 5; 112 private static final int WINDOW_SIZE = 5;
113 private static final int HIGH_LOAD_THRESHOLD = 0; 113 private static final int HIGH_LOAD_THRESHOLD = 0;
114 private static final int LOAD_WINDOW = 2; 114 private static final int LOAD_WINDOW = 2;
115 - SlidingWindowCounter counter = new SlidingWindowCounter(WINDOW_SIZE); 115 + private SlidingWindowCounter counter = new SlidingWindowCounter(WINDOW_SIZE);
116 - AtomicLong operations = new AtomicLong();
117 116
118 /** 117 /**
119 * Creates a new eventually consistent map shared amongst multiple instances. 118 * Creates a new eventually consistent map shared amongst multiple instances.
120 * <p> 119 * <p>
121 - * Each map is identified by a string map name. EventuallyConsistentMapImpl 120 + * See {@link org.onosproject.store.service.EventuallyConsistentMapBuilder}
122 - * objects in different JVMs that use the same map name will form a 121 + * for more description of the parameters expected by the map.
123 - * distributed map across JVMs (provided the cluster service is aware of
124 - * both nodes).
125 - * </p>
126 - * <p>
127 - * The client is expected to provide an
128 - * {@link org.onlab.util.KryoNamespace.Builder} with which all classes that
129 - * will be stored in this map have been registered (including referenced
130 - * classes). This serializer will be used to serialize both K and V for
131 - * inter-node notifications.
132 - * </p>
133 - * <p>
134 - * The client must provide an {@link org.onosproject.store.impl.ClockService}
135 - * which can generate timestamps for a given key. The clock service is free
136 - * to generate timestamps however it wishes, however these timestamps will
137 - * be used to serialize updates to the map so they must be strict enough
138 - * to ensure updates are properly ordered for the use case (i.e. in some
139 - * cases wallclock time will suffice, whereas in other cases logical time
140 - * will be necessary).
141 * </p> 122 * </p>
142 * 123 *
143 - * @param mapName a String identifier for the map. 124 + * @param mapName a String identifier for the map.
144 - * @param clusterService the cluster service 125 + * @param clusterService the cluster service
145 - * @param clusterCommunicator the cluster communications service 126 + * @param clusterCommunicator the cluster communications service
146 - * @param serializerBuilder a Kryo namespace builder that can serialize 127 + * @param serializerBuilder a Kryo namespace builder that can serialize
147 - * both K and V 128 + * both K and V
148 - * @param clockService a clock service able to generate timestamps 129 + * @param clockService a clock service able to generate timestamps
149 - * for K 130 + * for K and V
150 - * @param peerUpdateFunction function that provides a set of nodes to immediately 131 + * @param peerUpdateFunction function that provides a set of nodes to immediately
151 - * update to when there writes to the map 132 + * update to when there writes to the map
133 + * @param eventExecutor executor to use for processing incoming
134 + * events from peers
135 + * @param communicationExecutor executor to use for sending events to peers
136 + * @param backgroundExecutor executor to use for background anti-entropy
137 + * tasks
138 + * @param tombstonesDisabled true if this map should not maintain
139 + * tombstones
140 + * @param antiEntropyPeriod period that the anti-entropy task should run
141 + * in seconds
142 + * @param convergeFaster make anti-entropy try to converge faster
152 */ 143 */
153 - public EventuallyConsistentMapImpl(String mapName, 144 + EventuallyConsistentMapImpl(String mapName,
154 - ClusterService clusterService, 145 + ClusterService clusterService,
155 - ClusterCommunicationService clusterCommunicator, 146 + ClusterCommunicationService clusterCommunicator,
156 - KryoNamespace.Builder serializerBuilder, 147 + KryoNamespace.Builder serializerBuilder,
157 - ClockService<K, V> clockService, 148 + ClockService<K, V> clockService,
158 - BiFunction<K, V, Collection<NodeId>> peerUpdateFunction) { 149 + BiFunction<K, V, Collection<NodeId>> peerUpdateFunction,
159 - this.clusterService = checkNotNull(clusterService); 150 + ExecutorService eventExecutor,
160 - this.clusterCommunicator = checkNotNull(clusterCommunicator); 151 + ExecutorService communicationExecutor,
161 - this.peerUpdateFunction = checkNotNull(peerUpdateFunction); 152 + ScheduledExecutorService backgroundExecutor,
162 - 153 + boolean tombstonesDisabled,
163 - serializer = createSerializer(checkNotNull(serializerBuilder)); 154 + long antiEntropyPeriod,
155 + TimeUnit antiEntropyTimeUnit,
156 + boolean convergeFaster) {
157 + items = new ConcurrentHashMap<>();
158 + removedItems = new ConcurrentHashMap<>();
159 + senderPending = Maps.newConcurrentMap();
164 destroyedMessage = mapName + ERROR_DESTROYED; 160 destroyedMessage = mapName + ERROR_DESTROYED;
165 161
166 - this.clockService = checkNotNull(clockService); 162 + this.clusterService = clusterService;
163 + this.clusterCommunicator = clusterCommunicator;
167 164
168 - items = new ConcurrentHashMap<>(); 165 + this.serializer = createSerializer(serializerBuilder);
169 - removedItems = new ConcurrentHashMap<>();
170 166
171 - // should be a normal executor; it's used for receiving messages 167 + this.clockService = clockService;
172 - //TODO make # of threads configurable
173 - executor = Executors.newFixedThreadPool(8, groupedThreads("onos/ecm", mapName + "-fg-%d"));
174 168
175 - // sending executor; should be capped 169 + if (peerUpdateFunction != null) {
176 - //TODO make # of threads configurable 170 + this.peerUpdateFunction = peerUpdateFunction;
177 - //TODO this probably doesn't need to be bounded anymore 171 + } else {
178 - communicationExecutor = 172 + this.peerUpdateFunction = (key, value) -> clusterService.getNodes().stream()
179 - newFixedThreadPool(8, groupedThreads("onos/ecm", mapName + "-publish-%d")); 173 + .map(ControllerNode::id)
180 - senderPending = Maps.newConcurrentMap(); 174 + .filter(nodeId -> !nodeId.equals(clusterService.getLocalNode().id()))
175 + .collect(Collectors.toList());
176 + }
177 +
178 + if (eventExecutor != null) {
179 + this.executor = eventExecutor;
180 + } else {
181 + // should be a normal executor; it's used for receiving messages
182 + this.executor =
183 + Executors.newFixedThreadPool(8, groupedThreads("onos/ecm", mapName + "-fg-%d"));
184 + }
185 +
186 + if (communicationExecutor != null) {
187 + this.communicationExecutor = communicationExecutor;
188 + } else {
189 + // sending executor; should be capped
190 + //TODO this probably doesn't need to be bounded anymore
191 + this.communicationExecutor =
192 + newFixedThreadPool(8, groupedThreads("onos/ecm", mapName + "-publish-%d"));
193 + }
181 194
182 - backgroundExecutor = 195 + if (backgroundExecutor != null) {
183 - newSingleThreadScheduledExecutor(groupedThreads("onos/ecm", mapName + "-bg-%d")); 196 + this.backgroundExecutor = backgroundExecutor;
197 + } else {
198 + this.backgroundExecutor =
199 + newSingleThreadScheduledExecutor(groupedThreads("onos/ecm", mapName + "-bg-%d"));
200 + }
184 201
185 // start anti-entropy thread 202 // start anti-entropy thread
186 - backgroundExecutor.scheduleAtFixedRate(new SendAdvertisementTask(), 203 + this.backgroundExecutor.scheduleAtFixedRate(new SendAdvertisementTask(),
187 - initialDelaySec, periodSec, 204 + initialDelaySec, antiEntropyPeriod,
188 - TimeUnit.SECONDS); 205 + antiEntropyTimeUnit);
189 206
190 updateMessageSubject = new MessageSubject("ecm-" + mapName + "-update"); 207 updateMessageSubject = new MessageSubject("ecm-" + mapName + "-update");
191 clusterCommunicator.addSubscriber(updateMessageSubject, 208 clusterCommunicator.addSubscriber(updateMessageSubject,
192 - new InternalEventListener(), executor); 209 + new InternalEventListener(), this.executor);
193 210
194 antiEntropyAdvertisementSubject = new MessageSubject("ecm-" + mapName + "-anti-entropy"); 211 antiEntropyAdvertisementSubject = new MessageSubject("ecm-" + mapName + "-anti-entropy");
195 clusterCommunicator.addSubscriber(antiEntropyAdvertisementSubject, 212 clusterCommunicator.addSubscriber(antiEntropyAdvertisementSubject,
196 - new InternalAntiEntropyListener(), backgroundExecutor); 213 + new InternalAntiEntropyListener(), this.backgroundExecutor);
197 - }
198 214
199 - /** 215 + this.tombstonesDisabled = tombstonesDisabled;
200 - * Creates a new eventually consistent map shared amongst multiple instances. 216 + this.lightweightAntiEntropy = !convergeFaster;
201 - * <p>
202 - * Take a look at the other constructor for usage information. The only difference
203 - * is that a BiFunction is provided that returns all nodes in the cluster, so
204 - * all nodes will be sent write updates immediately.
205 - * </p>
206 - *
207 - * @param mapName a String identifier for the map.
208 - * @param clusterService the cluster service
209 - * @param clusterCommunicator the cluster communications service
210 - * @param serializerBuilder a Kryo namespace builder that can serialize
211 - * both K and V
212 - * @param clockService a clock service able to generate timestamps
213 - * for K
214 - */
215 - public EventuallyConsistentMapImpl(String mapName,
216 - ClusterService clusterService,
217 - ClusterCommunicationService clusterCommunicator,
218 - KryoNamespace.Builder serializerBuilder,
219 - ClockService<K, V> clockService) {
220 - this(mapName, clusterService, clusterCommunicator, serializerBuilder, clockService,
221 - (key, value) -> clusterService.getNodes().stream()
222 - .map(ControllerNode::id)
223 - .filter(nodeId -> !nodeId.equals(clusterService.getLocalNode().id()))
224 - .collect(Collectors.toList()));
225 - }
226 -
227 - public EventuallyConsistentMapImpl<K, V> withTombstonesDisabled(boolean status) {
228 - tombstonesDisabled = status;
229 - return this;
230 } 217 }
231 218
232 private KryoSerializer createSerializer(KryoNamespace.Builder builder) { 219 private KryoSerializer createSerializer(KryoNamespace.Builder builder) {
...@@ -246,19 +233,6 @@ public class EventuallyConsistentMapImpl<K, V> ...@@ -246,19 +233,6 @@ public class EventuallyConsistentMapImpl<K, V>
246 }; 233 };
247 } 234 }
248 235
249 - /**
250 - * Sets the executor to use for broadcasting messages and returns this
251 - * instance for method chaining.
252 - *
253 - * @param executor executor service
254 - * @return this instance
255 - */
256 - public EventuallyConsistentMapImpl<K, V> withBroadcastMessageExecutor(ExecutorService executor) {
257 - checkNotNull(executor, "Null executor");
258 - communicationExecutor = executor;
259 - return this;
260 - }
261 -
262 @Override 236 @Override
263 public int size() { 237 public int size() {
264 checkState(!destroyed, destroyedMessage); 238 checkState(!destroyed, destroyedMessage);
......
...@@ -15,23 +15,8 @@ ...@@ -15,23 +15,8 @@
15 */ 15 */
16 package org.onosproject.store.group.impl; 16 package org.onosproject.store.group.impl;
17 17
18 -import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; 18 +import com.google.common.collect.FluentIterable;
19 -import static org.onlab.util.Tools.groupedThreads; 19 +import com.google.common.collect.Iterables;
20 -import static org.slf4j.LoggerFactory.getLogger;
21 -
22 -import java.net.URI;
23 -import java.util.ArrayList;
24 -import java.util.HashMap;
25 -import java.util.List;
26 -import java.util.Objects;
27 -import java.util.concurrent.ConcurrentHashMap;
28 -import java.util.concurrent.ConcurrentMap;
29 -import java.util.concurrent.ExecutorService;
30 -import java.util.concurrent.Executors;
31 -import java.util.concurrent.atomic.AtomicInteger;
32 -import java.util.concurrent.atomic.AtomicLong;
33 -import java.util.stream.Collectors;
34 -
35 import org.apache.felix.scr.annotations.Activate; 20 import org.apache.felix.scr.annotations.Activate;
36 import org.apache.felix.scr.annotations.Component; 21 import org.apache.felix.scr.annotations.Component;
37 import org.apache.felix.scr.annotations.Deactivate; 22 import org.apache.felix.scr.annotations.Deactivate;
...@@ -75,17 +60,32 @@ import org.onosproject.store.Timestamp; ...@@ -75,17 +60,32 @@ import org.onosproject.store.Timestamp;
75 import org.onosproject.store.cluster.messaging.ClusterCommunicationService; 60 import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
76 import org.onosproject.store.cluster.messaging.ClusterMessage; 61 import org.onosproject.store.cluster.messaging.ClusterMessage;
77 import org.onosproject.store.cluster.messaging.ClusterMessageHandler; 62 import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
78 -import org.onosproject.store.ecmap.EventuallyConsistentMap;
79 -import org.onosproject.store.ecmap.EventuallyConsistentMapEvent;
80 -import org.onosproject.store.ecmap.EventuallyConsistentMapImpl;
81 -import org.onosproject.store.ecmap.EventuallyConsistentMapListener;
82 -import org.onosproject.store.impl.ClockService;
83 import org.onosproject.store.impl.MultiValuedTimestamp; 63 import org.onosproject.store.impl.MultiValuedTimestamp;
84 import org.onosproject.store.serializers.KryoNamespaces; 64 import org.onosproject.store.serializers.KryoNamespaces;
65 +import org.onosproject.store.service.ClockService;
66 +import org.onosproject.store.service.EventuallyConsistentMap;
67 +import org.onosproject.store.service.EventuallyConsistentMapBuilder;
68 +import org.onosproject.store.service.EventuallyConsistentMapEvent;
69 +import org.onosproject.store.service.EventuallyConsistentMapListener;
70 +import org.onosproject.store.service.StorageService;
85 import org.slf4j.Logger; 71 import org.slf4j.Logger;
86 72
87 -import com.google.common.collect.FluentIterable; 73 +import java.net.URI;
88 -import com.google.common.collect.Iterables; 74 +import java.util.ArrayList;
75 +import java.util.HashMap;
76 +import java.util.List;
77 +import java.util.Objects;
78 +import java.util.concurrent.ConcurrentHashMap;
79 +import java.util.concurrent.ConcurrentMap;
80 +import java.util.concurrent.ExecutorService;
81 +import java.util.concurrent.Executors;
82 +import java.util.concurrent.atomic.AtomicInteger;
83 +import java.util.concurrent.atomic.AtomicLong;
84 +import java.util.stream.Collectors;
85 +
86 +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
87 +import static org.onlab.util.Tools.groupedThreads;
88 +import static org.slf4j.LoggerFactory.getLogger;
89 89
90 /** 90 /**
91 * Manages inventory of group entries using trivial in-memory implementation. 91 * Manages inventory of group entries using trivial in-memory implementation.
...@@ -108,6 +108,9 @@ public class DistributedGroupStore ...@@ -108,6 +108,9 @@ public class DistributedGroupStore
108 protected ClusterService clusterService; 108 protected ClusterService clusterService;
109 109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 + protected StorageService storageService;
112 +
113 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected MastershipService mastershipService; 114 protected MastershipService mastershipService;
112 115
113 // Per device group table with (device id + app cookie) as key 116 // Per device group table with (device id + app cookie) as key
...@@ -192,31 +195,38 @@ public class DistributedGroupStore ...@@ -192,31 +195,38 @@ public class DistributedGroupStore
192 messageHandlingExecutor); 195 messageHandlingExecutor);
193 196
194 log.debug("Creating EC map groupstorekeymap"); 197 log.debug("Creating EC map groupstorekeymap");
195 - groupStoreEntriesByKey = 198 + EventuallyConsistentMapBuilder<GroupStoreKeyMapKey, StoredGroupEntry>
196 - new EventuallyConsistentMapImpl<>("groupstorekeymap", 199 + keyMapBuilder = storageService.eventuallyConsistentMapBuilder();
197 - clusterService, 200 +
198 - clusterCommunicator, 201 + groupStoreEntriesByKey = keyMapBuilder
199 - kryoBuilder, 202 + .withName("groupstorekeymap")
200 - new GroupStoreLogicalClockManager<>()); 203 + .withSerializer(kryoBuilder)
204 + .withClockService(new GroupStoreLogicalClockManager<>())
205 + .build();
201 log.trace("Current size {}", groupStoreEntriesByKey.size()); 206 log.trace("Current size {}", groupStoreEntriesByKey.size());
202 207
203 log.debug("Creating EC map groupstoreidmap"); 208 log.debug("Creating EC map groupstoreidmap");
204 - groupStoreEntriesById = 209 + EventuallyConsistentMapBuilder<GroupStoreIdMapKey, StoredGroupEntry>
205 - new EventuallyConsistentMapImpl<>("groupstoreidmap", 210 + idMapBuilder = storageService.eventuallyConsistentMapBuilder();
206 - clusterService, 211 +
207 - clusterCommunicator, 212 + groupStoreEntriesById = idMapBuilder
208 - kryoBuilder, 213 + .withName("groupstoreidmap")
209 - new GroupStoreLogicalClockManager<>()); 214 + .withSerializer(kryoBuilder)
215 + .withClockService(new GroupStoreLogicalClockManager<>())
216 + .build();
217 +
210 groupStoreEntriesById.addListener(new GroupStoreIdMapListener()); 218 groupStoreEntriesById.addListener(new GroupStoreIdMapListener());
211 log.trace("Current size {}", groupStoreEntriesById.size()); 219 log.trace("Current size {}", groupStoreEntriesById.size());
212 220
213 log.debug("Creating EC map pendinggroupkeymap"); 221 log.debug("Creating EC map pendinggroupkeymap");
214 - auditPendingReqQueue = 222 + EventuallyConsistentMapBuilder<GroupStoreKeyMapKey, StoredGroupEntry>
215 - new EventuallyConsistentMapImpl<>("pendinggroupkeymap", 223 + auditMapBuilder = storageService.eventuallyConsistentMapBuilder();
216 - clusterService, 224 +
217 - clusterCommunicator, 225 + auditPendingReqQueue = auditMapBuilder
218 - kryoBuilder, 226 + .withName("pendinggroupkeymap")
219 - new GroupStoreLogicalClockManager<>()); 227 + .withSerializer(kryoBuilder)
228 + .withClockService(new GroupStoreLogicalClockManager<>())
229 + .build();
220 log.trace("Current size {}", auditPendingReqQueue.size()); 230 log.trace("Current size {}", auditPendingReqQueue.size());
221 231
222 log.info("Started"); 232 log.info("Started");
...@@ -819,11 +829,11 @@ public class DistributedGroupStore ...@@ -819,11 +829,11 @@ public class DistributedGroupStore
819 * Map handler to receive any events when the group map is updated. 829 * Map handler to receive any events when the group map is updated.
820 */ 830 */
821 private class GroupStoreIdMapListener implements 831 private class GroupStoreIdMapListener implements
822 - EventuallyConsistentMapListener<GroupStoreIdMapKey, StoredGroupEntry> { 832 + EventuallyConsistentMapListener<GroupStoreIdMapKey, StoredGroupEntry> {
823 833
824 @Override 834 @Override
825 public void event(EventuallyConsistentMapEvent<GroupStoreIdMapKey, 835 public void event(EventuallyConsistentMapEvent<GroupStoreIdMapKey,
826 - StoredGroupEntry> mapEvent) { 836 + StoredGroupEntry> mapEvent) {
827 GroupEvent groupEvent = null; 837 GroupEvent groupEvent = null;
828 log.trace("GroupStoreIdMapListener: received groupid map event {}", 838 log.trace("GroupStoreIdMapListener: received groupid map event {}",
829 mapEvent.type()); 839 mapEvent.type());
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.store.impl; 16 package org.onosproject.store.impl;
17 17
18 import org.onosproject.store.Timestamp; 18 import org.onosproject.store.Timestamp;
19 +import org.onosproject.store.service.ClockService;
19 20
20 /** 21 /**
21 * A clock service which hands out wallclock-based timestamps. 22 * A clock service which hands out wallclock-based timestamps.
......
...@@ -36,14 +36,13 @@ import org.onosproject.net.intent.IntentStoreDelegate; ...@@ -36,14 +36,13 @@ import org.onosproject.net.intent.IntentStoreDelegate;
36 import org.onosproject.net.intent.Key; 36 import org.onosproject.net.intent.Key;
37 import org.onosproject.net.intent.PartitionService; 37 import org.onosproject.net.intent.PartitionService;
38 import org.onosproject.store.AbstractStore; 38 import org.onosproject.store.AbstractStore;
39 -import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
40 -import org.onosproject.store.ecmap.EventuallyConsistentMap;
41 -import org.onosproject.store.ecmap.EventuallyConsistentMapEvent;
42 -import org.onosproject.store.ecmap.EventuallyConsistentMapImpl;
43 -import org.onosproject.store.ecmap.EventuallyConsistentMapListener;
44 import org.onosproject.store.impl.MultiValuedTimestamp; 39 import org.onosproject.store.impl.MultiValuedTimestamp;
45 import org.onosproject.store.impl.WallClockTimestamp; 40 import org.onosproject.store.impl.WallClockTimestamp;
46 import org.onosproject.store.serializers.KryoNamespaces; 41 import org.onosproject.store.serializers.KryoNamespaces;
42 +import org.onosproject.store.service.EventuallyConsistentMap;
43 +import org.onosproject.store.service.EventuallyConsistentMapEvent;
44 +import org.onosproject.store.service.EventuallyConsistentMapListener;
45 +import org.onosproject.store.service.StorageService;
47 import org.slf4j.Logger; 46 import org.slf4j.Logger;
48 47
49 import java.util.Collection; 48 import java.util.Collection;
...@@ -52,7 +51,7 @@ import java.util.Objects; ...@@ -52,7 +51,7 @@ import java.util.Objects;
52 import java.util.stream.Collectors; 51 import java.util.stream.Collectors;
53 52
54 import static com.google.common.base.Preconditions.checkNotNull; 53 import static com.google.common.base.Preconditions.checkNotNull;
55 -import static org.onosproject.net.intent.IntentState.*; 54 +import static org.onosproject.net.intent.IntentState.PURGE_REQ;
56 import static org.slf4j.LoggerFactory.getLogger; 55 import static org.slf4j.LoggerFactory.getLogger;
57 56
58 /** 57 /**
...@@ -61,7 +60,7 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -61,7 +60,7 @@ import static org.slf4j.LoggerFactory.getLogger;
61 */ 60 */
62 //FIXME we should listen for leadership changes. if the local instance has just 61 //FIXME we should listen for leadership changes. if the local instance has just
63 // ... become a leader, scan the pending map and process those 62 // ... become a leader, scan the pending map and process those
64 -@Component(immediate = false, enabled = true) 63 +@Component(immediate = true, enabled = true)
65 @Service 64 @Service
66 public class GossipIntentStore 65 public class GossipIntentStore
67 extends AbstractStore<IntentEvent, IntentStoreDelegate> 66 extends AbstractStore<IntentEvent, IntentStoreDelegate>
...@@ -76,10 +75,10 @@ public class GossipIntentStore ...@@ -76,10 +75,10 @@ public class GossipIntentStore
76 private EventuallyConsistentMap<Key, IntentData> pendingMap; 75 private EventuallyConsistentMap<Key, IntentData> pendingMap;
77 76
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 - protected ClusterCommunicationService clusterCommunicator; 78 + protected ClusterService clusterService;
80 79
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 - protected ClusterService clusterService; 81 + protected StorageService storageService;
83 82
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected PartitionService partitionService; 84 protected PartitionService partitionService;
...@@ -92,19 +91,19 @@ public class GossipIntentStore ...@@ -92,19 +91,19 @@ public class GossipIntentStore
92 .register(MultiValuedTimestamp.class) 91 .register(MultiValuedTimestamp.class)
93 .register(WallClockTimestamp.class); 92 .register(WallClockTimestamp.class);
94 93
95 - currentMap = new EventuallyConsistentMapImpl<>("intent-current", 94 + currentMap = storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
96 - clusterService, 95 + .withName("intent-current")
97 - clusterCommunicator, 96 + .withSerializer(intentSerializer)
98 - intentSerializer, 97 + .withClockService(new IntentDataLogicalClockManager<>())
99 - new IntentDataLogicalClockManager<>(), 98 + .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData))
100 - (key, intentData) -> getPeerNodes(key, intentData)); 99 + .build();
101 - 100 +
102 - pendingMap = new EventuallyConsistentMapImpl<>("intent-pending", 101 + pendingMap = storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
103 - clusterService, 102 + .withName("intent-pending")
104 - clusterCommunicator, 103 + .withSerializer(intentSerializer)
105 - intentSerializer, 104 + .withClockService(new IntentDataClockManager<>())
106 - new IntentDataClockManager<>(), 105 + .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData))
107 - (key, intentData) -> getPeerNodes(key, intentData)); 106 + .build();
108 107
109 currentMap.addListener(new InternalCurrentListener()); 108 currentMap.addListener(new InternalCurrentListener());
110 pendingMap.addListener(new InternalPendingListener()); 109 pendingMap.addListener(new InternalPendingListener());
......
...@@ -17,7 +17,7 @@ package org.onosproject.store.intent.impl; ...@@ -17,7 +17,7 @@ package org.onosproject.store.intent.impl;
17 17
18 import org.onosproject.net.intent.IntentData; 18 import org.onosproject.net.intent.IntentData;
19 import org.onosproject.store.Timestamp; 19 import org.onosproject.store.Timestamp;
20 -import org.onosproject.store.impl.ClockService; 20 +import org.onosproject.store.service.ClockService;
21 import org.onosproject.store.impl.MultiValuedTimestamp; 21 import org.onosproject.store.impl.MultiValuedTimestamp;
22 22
23 /** 23 /**
......
...@@ -17,7 +17,7 @@ package org.onosproject.store.intent.impl; ...@@ -17,7 +17,7 @@ package org.onosproject.store.intent.impl;
17 17
18 import org.onosproject.net.intent.IntentData; 18 import org.onosproject.net.intent.IntentData;
19 import org.onosproject.store.Timestamp; 19 import org.onosproject.store.Timestamp;
20 -import org.onosproject.store.impl.ClockService; 20 +import org.onosproject.store.service.ClockService;
21 import org.onosproject.store.impl.MultiValuedTimestamp; 21 import org.onosproject.store.impl.MultiValuedTimestamp;
22 22
23 import java.util.concurrent.atomic.AtomicLong; 23 import java.util.concurrent.atomic.AtomicLong;
......
...@@ -34,10 +34,13 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService; ...@@ -34,10 +34,13 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
34 import org.onosproject.store.cluster.messaging.ClusterMessage; 34 import org.onosproject.store.cluster.messaging.ClusterMessage;
35 import org.onosproject.store.cluster.messaging.ClusterMessageHandler; 35 import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
36 import org.onosproject.store.cluster.messaging.MessageSubject; 36 import org.onosproject.store.cluster.messaging.MessageSubject;
37 -import org.onosproject.store.impl.ClockService; 37 +import org.onosproject.store.service.ClockService;
38 import org.onosproject.store.impl.WallClockTimestamp; 38 import org.onosproject.store.impl.WallClockTimestamp;
39 import org.onosproject.store.serializers.KryoNamespaces; 39 import org.onosproject.store.serializers.KryoNamespaces;
40 import org.onosproject.store.serializers.KryoSerializer; 40 import org.onosproject.store.serializers.KryoSerializer;
41 +import org.onosproject.store.service.EventuallyConsistentMap;
42 +import org.onosproject.store.service.EventuallyConsistentMapEvent;
43 +import org.onosproject.store.service.EventuallyConsistentMapListener;
41 44
42 import java.io.IOException; 45 import java.io.IOException;
43 import java.util.ArrayList; 46 import java.util.ArrayList;
...@@ -134,10 +137,13 @@ public class EventuallyConsistentMapImplTest { ...@@ -134,10 +137,13 @@ public class EventuallyConsistentMapImplTest {
134 .register(KryoNamespaces.API) 137 .register(KryoNamespaces.API)
135 .register(TestTimestamp.class); 138 .register(TestTimestamp.class);
136 139
137 - ecMap = new EventuallyConsistentMapImpl<>(MAP_NAME, clusterService, 140 + ecMap = new EventuallyConsistentMapBuilderImpl<>(
138 - clusterCommunicator, 141 + clusterService, clusterCommunicator)
139 - serializer, clockService) 142 + .withName(MAP_NAME)
140 - .withBroadcastMessageExecutor(MoreExecutors.newDirectExecutorService()); 143 + .withSerializer(serializer)
144 + .withClockService(clockService)
145 + .withCommunicationExecutor(MoreExecutors.newDirectExecutorService())
146 + .build();
141 147
142 // Reset ready for tests to add their own expectations 148 // Reset ready for tests to add their own expectations
143 reset(clusterCommunicator); 149 reset(clusterCommunicator);
......