ONOS-4423: Support for invalidating cached map entries when a client session is suspended
Change-Id: Icb5e73dc7a37d9459d26cd3a5c9ca1e1a05b0436
Showing
8 changed files
with
183 additions
and
27 deletions
| ... | @@ -25,6 +25,7 @@ import java.util.concurrent.ExecutionException; | ... | @@ -25,6 +25,7 @@ import java.util.concurrent.ExecutionException; |
| 25 | import java.util.concurrent.TimeUnit; | 25 | import java.util.concurrent.TimeUnit; |
| 26 | import java.util.concurrent.TimeoutException; | 26 | import java.util.concurrent.TimeoutException; |
| 27 | import java.util.function.BiFunction; | 27 | import java.util.function.BiFunction; |
| 28 | +import java.util.function.Consumer; | ||
| 28 | import java.util.function.Function; | 29 | import java.util.function.Function; |
| 29 | import java.util.function.Predicate; | 30 | import java.util.function.Predicate; |
| 30 | 31 | ||
| ... | @@ -187,6 +188,21 @@ public class DefaultConsistentMap<K, V> extends Synchronous<AsyncConsistentMap<K | ... | @@ -187,6 +188,21 @@ public class DefaultConsistentMap<K, V> extends Synchronous<AsyncConsistentMap<K |
| 187 | } | 188 | } |
| 188 | 189 | ||
| 189 | @Override | 190 | @Override |
| 191 | + public void addStatusChangeListener(Consumer<Status> listener) { | ||
| 192 | + asyncMap.addStatusChangeListener(listener); | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + @Override | ||
| 196 | + public void removeStatusChangeListener(Consumer<Status> listener) { | ||
| 197 | + asyncMap.removeStatusChangeListener(listener); | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + @Override | ||
| 201 | + public Collection<Consumer<Status>> statusChangeListeners() { | ||
| 202 | + return asyncMap.statusChangeListeners(); | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + @Override | ||
| 190 | public Map<K, V> asJavaMap() { | 206 | public Map<K, V> asJavaMap() { |
| 191 | synchronized (this) { | 207 | synchronized (this) { |
| 192 | if (javaMap == null) { | 208 | if (javaMap == null) { | ... | ... |
| ... | @@ -15,7 +15,10 @@ | ... | @@ -15,7 +15,10 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.store.service; | 16 | package org.onosproject.store.service; |
| 17 | 17 | ||
| 18 | +import java.util.Collection; | ||
| 19 | +import java.util.Collections; | ||
| 18 | import java.util.concurrent.CompletableFuture; | 20 | import java.util.concurrent.CompletableFuture; |
| 21 | +import java.util.function.Consumer; | ||
| 19 | 22 | ||
| 20 | import org.onosproject.core.ApplicationId; | 23 | import org.onosproject.core.ApplicationId; |
| 21 | 24 | ||
| ... | @@ -74,6 +77,29 @@ public interface DistributedPrimitive { | ... | @@ -74,6 +77,29 @@ public interface DistributedPrimitive { |
| 74 | TRANSACTION_CONTEXT | 77 | TRANSACTION_CONTEXT |
| 75 | } | 78 | } |
| 76 | 79 | ||
| 80 | + /** | ||
| 81 | + * Status of distributed primitive. | ||
| 82 | + */ | ||
| 83 | + public enum Status { | ||
| 84 | + | ||
| 85 | + /** | ||
| 86 | + * Signifies a state wherein the primitive is operating correctly and is capable of meeting the advertised | ||
| 87 | + * consistency and reliability guarantees. | ||
| 88 | + */ | ||
| 89 | + ACTIVE, | ||
| 90 | + | ||
| 91 | + /** | ||
| 92 | + * Signifies a state wherein the primitive is temporarily incapable of providing the advertised | ||
| 93 | + * consistency properties. | ||
| 94 | + */ | ||
| 95 | + SUSPENDED, | ||
| 96 | + | ||
| 97 | + /** | ||
| 98 | + * Signifies a state wherein the primitive has been shutdown and therefore cannot perform its functions. | ||
| 99 | + */ | ||
| 100 | + INACTIVE | ||
| 101 | + } | ||
| 102 | + | ||
| 77 | static final long DEFAULT_OPERTATION_TIMEOUT_MILLIS = 60000L; | 103 | static final long DEFAULT_OPERTATION_TIMEOUT_MILLIS = 60000L; |
| 78 | 104 | ||
| 79 | /** | 105 | /** |
| ... | @@ -107,4 +133,24 @@ public interface DistributedPrimitive { | ... | @@ -107,4 +133,24 @@ public interface DistributedPrimitive { |
| 107 | default CompletableFuture<Void> destroy() { | 133 | default CompletableFuture<Void> destroy() { |
| 108 | return CompletableFuture.completedFuture(null); | 134 | return CompletableFuture.completedFuture(null); |
| 109 | } | 135 | } |
| 136 | + | ||
| 137 | + /** | ||
| 138 | + * Registers a listener to be called when the primitive's status changes. | ||
| 139 | + * @param listener The listener to be called when the status changes. | ||
| 140 | + */ | ||
| 141 | + default void addStatusChangeListener(Consumer<Status> listener) {} | ||
| 142 | + | ||
| 143 | + /** | ||
| 144 | + * Unregisters a previously registered listener to be called when the primitive's status changes. | ||
| 145 | + * @param listener The listener to unregister | ||
| 146 | + */ | ||
| 147 | + default void removeStatusChangeListener(Consumer<Status> listener) {} | ||
| 148 | + | ||
| 149 | + /** | ||
| 150 | + * Returns the collection of status change listeners previously registered. | ||
| 151 | + * @return collection of status change listeners | ||
| 152 | + */ | ||
| 153 | + default Collection<Consumer<Status>> statusChangeListeners() { | ||
| 154 | + return Collections.emptyList(); | ||
| 155 | + } | ||
| 110 | } | 156 | } | ... | ... |
| ... | @@ -15,18 +15,25 @@ | ... | @@ -15,18 +15,25 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.store.primitives.impl; | 16 | package org.onosproject.store.primitives.impl; |
| 17 | 17 | ||
| 18 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 19 | + | ||
| 18 | import java.util.concurrent.CompletableFuture; | 20 | import java.util.concurrent.CompletableFuture; |
| 19 | import java.util.function.BiFunction; | 21 | import java.util.function.BiFunction; |
| 22 | +import java.util.function.Consumer; | ||
| 20 | import java.util.function.Predicate; | 23 | import java.util.function.Predicate; |
| 21 | 24 | ||
| 22 | import org.onosproject.store.service.AsyncConsistentMap; | 25 | import org.onosproject.store.service.AsyncConsistentMap; |
| 23 | import org.onosproject.store.service.MapEventListener; | 26 | import org.onosproject.store.service.MapEventListener; |
| 24 | import org.onosproject.store.service.Versioned; | 27 | import org.onosproject.store.service.Versioned; |
| 28 | +import org.slf4j.Logger; | ||
| 25 | 29 | ||
| 26 | import com.google.common.cache.CacheBuilder; | 30 | import com.google.common.cache.CacheBuilder; |
| 27 | import com.google.common.cache.CacheLoader; | 31 | import com.google.common.cache.CacheLoader; |
| 28 | import com.google.common.cache.LoadingCache; | 32 | import com.google.common.cache.LoadingCache; |
| 29 | 33 | ||
| 34 | +import static org.onosproject.store.service.DistributedPrimitive.Status.INACTIVE; | ||
| 35 | +import static org.onosproject.store.service.DistributedPrimitive.Status.SUSPENDED; | ||
| 36 | + | ||
| 30 | /** | 37 | /** |
| 31 | * {@code AsyncConsistentMap} that caches entries on read. | 38 | * {@code AsyncConsistentMap} that caches entries on read. |
| 32 | * <p> | 39 | * <p> |
| ... | @@ -39,20 +46,13 @@ import com.google.common.cache.LoadingCache; | ... | @@ -39,20 +46,13 @@ import com.google.common.cache.LoadingCache; |
| 39 | * @param <V> value type | 46 | * @param <V> value type |
| 40 | */ | 47 | */ |
| 41 | public class CachingAsyncConsistentMap<K, V> extends DelegatingAsyncConsistentMap<K, V> { | 48 | public class CachingAsyncConsistentMap<K, V> extends DelegatingAsyncConsistentMap<K, V> { |
| 42 | - private int maxCacheSize = 10000; | 49 | + private static final int DEFAULT_CACHE_SIZE = 10000; |
| 43 | - | 50 | + private final Logger log = getLogger(getClass()); |
| 44 | - private final LoadingCache<K, CompletableFuture<Versioned<V>>> cache = | ||
| 45 | - CacheBuilder.newBuilder() | ||
| 46 | - .maximumSize(maxCacheSize) | ||
| 47 | - .build(new CacheLoader<K, CompletableFuture<Versioned<V>>>() { | ||
| 48 | - @Override | ||
| 49 | - public CompletableFuture<Versioned<V>> load(K key) | ||
| 50 | - throws Exception { | ||
| 51 | - return CachingAsyncConsistentMap.super.get(key); | ||
| 52 | - } | ||
| 53 | - }); | ||
| 54 | 51 | ||
| 55 | - private final MapEventListener<K, V> cacheInvalidator = event -> cache.invalidate(event.key()); | 52 | + private final LoadingCache<K, CompletableFuture<Versioned<V>>> cache; |
| 53 | + | ||
| 54 | + private final MapEventListener<K, V> cacheInvalidator; | ||
| 55 | + private final Consumer<Status> statusListener; | ||
| 56 | 56 | ||
| 57 | /** | 57 | /** |
| 58 | * Default constructor. | 58 | * Default constructor. |
| ... | @@ -60,24 +60,36 @@ public class CachingAsyncConsistentMap<K, V> extends DelegatingAsyncConsistentMa | ... | @@ -60,24 +60,36 @@ public class CachingAsyncConsistentMap<K, V> extends DelegatingAsyncConsistentMa |
| 60 | * @param backingMap a distributed, strongly consistent map for backing | 60 | * @param backingMap a distributed, strongly consistent map for backing |
| 61 | */ | 61 | */ |
| 62 | public CachingAsyncConsistentMap(AsyncConsistentMap<K, V> backingMap) { | 62 | public CachingAsyncConsistentMap(AsyncConsistentMap<K, V> backingMap) { |
| 63 | - super(backingMap); | 63 | + this(backingMap, DEFAULT_CACHE_SIZE); |
| 64 | - super.addListener(cacheInvalidator); | ||
| 65 | } | 64 | } |
| 66 | 65 | ||
| 67 | /** | 66 | /** |
| 68 | - * Constructor to configure cache size of LoadingCache. | 67 | + * Constructor to configure cache size. |
| 69 | * | 68 | * |
| 70 | * @param backingMap a distributed, strongly consistent map for backing | 69 | * @param backingMap a distributed, strongly consistent map for backing |
| 71 | * @param cacheSize the maximum size of the cache | 70 | * @param cacheSize the maximum size of the cache |
| 72 | */ | 71 | */ |
| 73 | public CachingAsyncConsistentMap(AsyncConsistentMap<K, V> backingMap, int cacheSize) { | 72 | public CachingAsyncConsistentMap(AsyncConsistentMap<K, V> backingMap, int cacheSize) { |
| 74 | super(backingMap); | 73 | super(backingMap); |
| 74 | + cache = CacheBuilder.newBuilder() | ||
| 75 | + .maximumSize(cacheSize) | ||
| 76 | + .build(CacheLoader.from(CachingAsyncConsistentMap.super::get)); | ||
| 77 | + cacheInvalidator = event -> cache.invalidate(event.key()); | ||
| 78 | + statusListener = status -> { | ||
| 79 | + log.debug("{} status changed to {}", this.name(), status); | ||
| 80 | + // If the status of the underlying map is SUSPENDED or INACTIVE | ||
| 81 | + // we can no longer guarantee that the cache will be in sync. | ||
| 82 | + if (status == SUSPENDED || status == INACTIVE) { | ||
| 83 | + cache.invalidateAll(); | ||
| 84 | + } | ||
| 85 | + }; | ||
| 75 | super.addListener(cacheInvalidator); | 86 | super.addListener(cacheInvalidator); |
| 76 | - maxCacheSize = cacheSize; | 87 | + super.addStatusChangeListener(statusListener); |
| 77 | } | 88 | } |
| 78 | 89 | ||
| 79 | @Override | 90 | @Override |
| 80 | public CompletableFuture<Void> destroy() { | 91 | public CompletableFuture<Void> destroy() { |
| 92 | + super.removeStatusChangeListener(statusListener); | ||
| 81 | return super.destroy().thenCompose(v -> removeListener(cacheInvalidator)); | 93 | return super.destroy().thenCompose(v -> removeListener(cacheInvalidator)); |
| 82 | } | 94 | } |
| 83 | 95 | ... | ... |
| ... | @@ -24,6 +24,7 @@ import java.util.Objects; | ... | @@ -24,6 +24,7 @@ import java.util.Objects; |
| 24 | import java.util.Set; | 24 | import java.util.Set; |
| 25 | import java.util.concurrent.CompletableFuture; | 25 | import java.util.concurrent.CompletableFuture; |
| 26 | import java.util.function.BiFunction; | 26 | import java.util.function.BiFunction; |
| 27 | +import java.util.function.Consumer; | ||
| 27 | import java.util.function.Predicate; | 28 | import java.util.function.Predicate; |
| 28 | 29 | ||
| 29 | import org.onosproject.core.ApplicationId; | 30 | import org.onosproject.core.ApplicationId; |
| ... | @@ -32,7 +33,6 @@ import org.onosproject.store.service.AsyncConsistentMap; | ... | @@ -32,7 +33,6 @@ import org.onosproject.store.service.AsyncConsistentMap; |
| 32 | import org.onosproject.store.service.MapEventListener; | 33 | import org.onosproject.store.service.MapEventListener; |
| 33 | import org.onosproject.store.service.MapTransaction; | 34 | import org.onosproject.store.service.MapTransaction; |
| 34 | import org.onosproject.store.service.Versioned; | 35 | import org.onosproject.store.service.Versioned; |
| 35 | - | ||
| 36 | import com.google.common.base.MoreObjects; | 36 | import com.google.common.base.MoreObjects; |
| 37 | 37 | ||
| 38 | /** | 38 | /** |
| ... | @@ -183,6 +183,21 @@ public class DelegatingAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, | ... | @@ -183,6 +183,21 @@ public class DelegatingAsyncConsistentMap<K, V> implements AsyncConsistentMap<K, |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | @Override | 185 | @Override |
| 186 | + public void addStatusChangeListener(Consumer<Status> listener) { | ||
| 187 | + delegateMap.addStatusChangeListener(listener); | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + @Override | ||
| 191 | + public void removeStatusChangeListener(Consumer<Status> listener) { | ||
| 192 | + delegateMap.removeStatusChangeListener(listener); | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + @Override | ||
| 196 | + public Collection<Consumer<Status>> statusChangeListeners() { | ||
| 197 | + return delegateMap.statusChangeListeners(); | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + @Override | ||
| 186 | public String toString() { | 201 | public String toString() { |
| 187 | return MoreObjects.toStringHelper(getClass()) | 202 | return MoreObjects.toStringHelper(getClass()) |
| 188 | .add("delegateMap", delegateMap) | 203 | .add("delegateMap", delegateMap) | ... | ... |
| ... | @@ -27,6 +27,7 @@ import java.util.concurrent.CompletableFuture; | ... | @@ -27,6 +27,7 @@ import java.util.concurrent.CompletableFuture; |
| 27 | import java.util.concurrent.atomic.AtomicBoolean; | 27 | import java.util.concurrent.atomic.AtomicBoolean; |
| 28 | import java.util.concurrent.atomic.AtomicInteger; | 28 | import java.util.concurrent.atomic.AtomicInteger; |
| 29 | import java.util.function.BiFunction; | 29 | import java.util.function.BiFunction; |
| 30 | +import java.util.function.Consumer; | ||
| 30 | import java.util.function.Predicate; | 31 | import java.util.function.Predicate; |
| 31 | import java.util.stream.Collectors; | 32 | import java.util.stream.Collectors; |
| 32 | 33 | ||
| ... | @@ -38,7 +39,6 @@ import org.onosproject.store.service.AsyncConsistentMap; | ... | @@ -38,7 +39,6 @@ import org.onosproject.store.service.AsyncConsistentMap; |
| 38 | import org.onosproject.store.service.MapEventListener; | 39 | import org.onosproject.store.service.MapEventListener; |
| 39 | import org.onosproject.store.service.MapTransaction; | 40 | import org.onosproject.store.service.MapTransaction; |
| 40 | import org.onosproject.store.service.Versioned; | 41 | import org.onosproject.store.service.Versioned; |
| 41 | - | ||
| 42 | import com.google.common.collect.Lists; | 42 | import com.google.common.collect.Lists; |
| 43 | import com.google.common.collect.Maps; | 43 | import com.google.common.collect.Maps; |
| 44 | import com.google.common.collect.Sets; | 44 | import com.google.common.collect.Sets; |
| ... | @@ -254,6 +254,21 @@ public class PartitionedAsyncConsistentMap<K, V> implements AsyncConsistentMap<K | ... | @@ -254,6 +254,21 @@ public class PartitionedAsyncConsistentMap<K, V> implements AsyncConsistentMap<K |
| 254 | .thenApply(list -> list.stream().reduce(Boolean::logicalAnd).orElse(true)); | 254 | .thenApply(list -> list.stream().reduce(Boolean::logicalAnd).orElse(true)); |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | + @Override | ||
| 258 | + public void addStatusChangeListener(Consumer<Status> listener) { | ||
| 259 | + partitions.values().forEach(map -> map.addStatusChangeListener(listener)); | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + @Override | ||
| 263 | + public void removeStatusChangeListener(Consumer<Status> listener) { | ||
| 264 | + partitions.values().forEach(map -> map.removeStatusChangeListener(listener)); | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + @Override | ||
| 268 | + public Collection<Consumer<Status>> statusChangeListeners() { | ||
| 269 | + throw new UnsupportedOperationException(); | ||
| 270 | + } | ||
| 271 | + | ||
| 257 | /** | 272 | /** |
| 258 | * Returns the map (partition) to which the specified key maps. | 273 | * Returns the map (partition) to which the specified key maps. |
| 259 | * @param key key | 274 | * @param key key | ... | ... |
| ... | @@ -23,6 +23,7 @@ import io.atomix.catalyst.transport.Transport; | ... | @@ -23,6 +23,7 @@ import io.atomix.catalyst.transport.Transport; |
| 23 | import io.atomix.catalyst.util.concurrent.CatalystThreadFactory; | 23 | import io.atomix.catalyst.util.concurrent.CatalystThreadFactory; |
| 24 | import io.atomix.copycat.client.ConnectionStrategies; | 24 | import io.atomix.copycat.client.ConnectionStrategies; |
| 25 | import io.atomix.copycat.client.CopycatClient; | 25 | import io.atomix.copycat.client.CopycatClient; |
| 26 | +import io.atomix.copycat.client.CopycatClient.State; | ||
| 26 | import io.atomix.copycat.client.RecoveryStrategies; | 27 | import io.atomix.copycat.client.RecoveryStrategies; |
| 27 | import io.atomix.copycat.client.RetryStrategies; | 28 | import io.atomix.copycat.client.RetryStrategies; |
| 28 | import io.atomix.copycat.client.ServerSelectionStrategies; | 29 | import io.atomix.copycat.client.ServerSelectionStrategies; |
| ... | @@ -36,6 +37,8 @@ import io.atomix.variables.DistributedLong; | ... | @@ -36,6 +37,8 @@ import io.atomix.variables.DistributedLong; |
| 36 | import java.util.Collection; | 37 | import java.util.Collection; |
| 37 | import java.util.Set; | 38 | import java.util.Set; |
| 38 | import java.util.concurrent.CompletableFuture; | 39 | import java.util.concurrent.CompletableFuture; |
| 40 | +import java.util.function.Consumer; | ||
| 41 | +import java.util.function.Function; | ||
| 39 | 42 | ||
| 40 | import org.onlab.util.HexString; | 43 | import org.onlab.util.HexString; |
| 41 | import org.onosproject.store.primitives.DistributedPrimitiveCreator; | 44 | import org.onosproject.store.primitives.DistributedPrimitiveCreator; |
| ... | @@ -48,6 +51,7 @@ import org.onosproject.store.service.AsyncAtomicValue; | ... | @@ -48,6 +51,7 @@ import org.onosproject.store.service.AsyncAtomicValue; |
| 48 | import org.onosproject.store.service.AsyncConsistentMap; | 51 | import org.onosproject.store.service.AsyncConsistentMap; |
| 49 | import org.onosproject.store.service.AsyncDistributedSet; | 52 | import org.onosproject.store.service.AsyncDistributedSet; |
| 50 | import org.onosproject.store.service.AsyncLeaderElector; | 53 | import org.onosproject.store.service.AsyncLeaderElector; |
| 54 | +import org.onosproject.store.service.DistributedPrimitive.Status; | ||
| 51 | import org.onosproject.store.service.DistributedQueue; | 55 | import org.onosproject.store.service.DistributedQueue; |
| 52 | import org.onosproject.store.service.Serializer; | 56 | import org.onosproject.store.service.Serializer; |
| 53 | import org.slf4j.Logger; | 57 | import org.slf4j.Logger; |
| ... | @@ -71,6 +75,18 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana | ... | @@ -71,6 +75,18 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana |
| 71 | private final Supplier<AsyncConsistentMap<String, byte[]>> onosAtomicValuesMap = | 75 | private final Supplier<AsyncConsistentMap<String, byte[]>> onosAtomicValuesMap = |
| 72 | Suppliers.memoize(() -> newAsyncConsistentMap(ATOMIC_VALUES_CONSISTENT_MAP_NAME, | 76 | Suppliers.memoize(() -> newAsyncConsistentMap(ATOMIC_VALUES_CONSISTENT_MAP_NAME, |
| 73 | Serializer.using(KryoNamespaces.BASIC))); | 77 | Serializer.using(KryoNamespaces.BASIC))); |
| 78 | + Function<State, Status> mapper = state -> { | ||
| 79 | + switch (state) { | ||
| 80 | + case CONNECTED: | ||
| 81 | + return Status.ACTIVE; | ||
| 82 | + case SUSPENDED: | ||
| 83 | + return Status.SUSPENDED; | ||
| 84 | + case CLOSED: | ||
| 85 | + return Status.INACTIVE; | ||
| 86 | + default: | ||
| 87 | + throw new IllegalStateException("Unknown state " + state); | ||
| 88 | + } | ||
| 89 | + }; | ||
| 74 | 90 | ||
| 75 | public StoragePartitionClient(StoragePartition partition, | 91 | public StoragePartitionClient(StoragePartition partition, |
| 76 | io.atomix.catalyst.serializer.Serializer serializer, | 92 | io.atomix.catalyst.serializer.Serializer serializer, |
| ... | @@ -90,7 +106,8 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana | ... | @@ -90,7 +106,8 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana |
| 90 | transport, | 106 | transport, |
| 91 | serializer.clone(), | 107 | serializer.clone(), |
| 92 | StoragePartition.RESOURCE_TYPES); | 108 | StoragePartition.RESOURCE_TYPES); |
| 93 | - copycatClient.onStateChange(state -> log.info("Client state {}", state)); | 109 | + copycatClient.onStateChange(state -> log.debug("Partition {} client state" |
| 110 | + + " changed to {}", partition.getId(), state)); | ||
| 94 | client = new AtomixClient(new ResourceClient(copycatClient)); | 111 | client = new AtomixClient(new ResourceClient(copycatClient)); |
| 95 | } | 112 | } |
| 96 | return client.open().whenComplete((r, e) -> { | 113 | return client.open().whenComplete((r, e) -> { |
| ... | @@ -109,9 +126,14 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana | ... | @@ -109,9 +126,14 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana |
| 109 | 126 | ||
| 110 | @Override | 127 | @Override |
| 111 | public <K, V> AsyncConsistentMap<K, V> newAsyncConsistentMap(String name, Serializer serializer) { | 128 | public <K, V> AsyncConsistentMap<K, V> newAsyncConsistentMap(String name, Serializer serializer) { |
| 129 | + AtomixConsistentMap atomixConsistentMap = client.getResource(name, AtomixConsistentMap.class).join(); | ||
| 130 | + Consumer<State> statusListener = state -> { | ||
| 131 | + atomixConsistentMap.statusChangeListeners() | ||
| 132 | + .forEach(listener -> listener.accept(mapper.apply(state))); | ||
| 133 | + }; | ||
| 134 | + copycatClient.onStateChange(statusListener); | ||
| 112 | AsyncConsistentMap<String, byte[]> rawMap = | 135 | AsyncConsistentMap<String, byte[]> rawMap = |
| 113 | - new DelegatingAsyncConsistentMap<String, byte[]>(client.getResource(name, AtomixConsistentMap.class) | 136 | + new DelegatingAsyncConsistentMap<String, byte[]>(atomixConsistentMap) { |
| 114 | - .join()) { | ||
| 115 | @Override | 137 | @Override |
| 116 | public String name() { | 138 | public String name() { |
| 117 | return name; | 139 | return name; |
| ... | @@ -139,9 +161,7 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana | ... | @@ -139,9 +161,7 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana |
| 139 | 161 | ||
| 140 | @Override | 162 | @Override |
| 141 | public <V> AsyncAtomicValue<V> newAsyncAtomicValue(String name, Serializer serializer) { | 163 | public <V> AsyncAtomicValue<V> newAsyncAtomicValue(String name, Serializer serializer) { |
| 142 | - return new DefaultAsyncAtomicValue<>(name, | 164 | + return new DefaultAsyncAtomicValue<>(name, serializer, onosAtomicValuesMap.get()); |
| 143 | - serializer, | ||
| 144 | - onosAtomicValuesMap.get()); | ||
| 145 | } | 165 | } |
| 146 | 166 | ||
| 147 | @Override | 167 | @Override | ... | ... |
| ... | @@ -22,6 +22,7 @@ import java.util.Map.Entry; | ... | @@ -22,6 +22,7 @@ import java.util.Map.Entry; |
| 22 | import java.util.Set; | 22 | import java.util.Set; |
| 23 | import java.util.concurrent.CompletableFuture; | 23 | import java.util.concurrent.CompletableFuture; |
| 24 | import java.util.function.BiFunction; | 24 | import java.util.function.BiFunction; |
| 25 | +import java.util.function.Consumer; | ||
| 25 | import java.util.function.Function; | 26 | import java.util.function.Function; |
| 26 | import java.util.function.Predicate; | 27 | import java.util.function.Predicate; |
| 27 | import java.util.stream.Collectors; | 28 | import java.util.stream.Collectors; |
| ... | @@ -33,7 +34,6 @@ import org.onosproject.store.service.MapEvent; | ... | @@ -33,7 +34,6 @@ import org.onosproject.store.service.MapEvent; |
| 33 | import org.onosproject.store.service.MapEventListener; | 34 | import org.onosproject.store.service.MapEventListener; |
| 34 | import org.onosproject.store.service.MapTransaction; | 35 | import org.onosproject.store.service.MapTransaction; |
| 35 | import org.onosproject.store.service.Versioned; | 36 | import org.onosproject.store.service.Versioned; |
| 36 | - | ||
| 37 | import com.google.common.collect.Maps; | 37 | import com.google.common.collect.Maps; |
| 38 | 38 | ||
| 39 | /** | 39 | /** |
| ... | @@ -281,6 +281,21 @@ public class TranscodingAsyncConsistentMap<K1, V1, K2, V2> implements AsyncConsi | ... | @@ -281,6 +281,21 @@ public class TranscodingAsyncConsistentMap<K1, V1, K2, V2> implements AsyncConsi |
| 281 | } | 281 | } |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | + @Override | ||
| 285 | + public void addStatusChangeListener(Consumer<Status> listener) { | ||
| 286 | + backingMap.addStatusChangeListener(listener); | ||
| 287 | + } | ||
| 288 | + | ||
| 289 | + @Override | ||
| 290 | + public void removeStatusChangeListener(Consumer<Status> listener) { | ||
| 291 | + backingMap.removeStatusChangeListener(listener); | ||
| 292 | + } | ||
| 293 | + | ||
| 294 | + @Override | ||
| 295 | + public Collection<Consumer<Status>> statusChangeListeners() { | ||
| 296 | + return backingMap.statusChangeListeners(); | ||
| 297 | + } | ||
| 298 | + | ||
| 284 | private class InternalBackingMapEventListener implements MapEventListener<K2, V2> { | 299 | private class InternalBackingMapEventListener implements MapEventListener<K2, V2> { |
| 285 | 300 | ||
| 286 | private final MapEventListener<K1, V1> listener; | 301 | private final MapEventListener<K1, V1> listener; | ... | ... |
| ... | @@ -28,6 +28,7 @@ import java.util.Set; | ... | @@ -28,6 +28,7 @@ import java.util.Set; |
| 28 | import java.util.concurrent.CompletableFuture; | 28 | import java.util.concurrent.CompletableFuture; |
| 29 | import java.util.concurrent.atomic.AtomicReference; | 29 | import java.util.concurrent.atomic.AtomicReference; |
| 30 | import java.util.function.BiFunction; | 30 | import java.util.function.BiFunction; |
| 31 | +import java.util.function.Consumer; | ||
| 31 | import java.util.function.Predicate; | 32 | import java.util.function.Predicate; |
| 32 | 33 | ||
| 33 | import org.onlab.util.Match; | 34 | import org.onlab.util.Match; |
| ... | @@ -53,7 +54,7 @@ import org.onosproject.store.service.MapEvent; | ... | @@ -53,7 +54,7 @@ import org.onosproject.store.service.MapEvent; |
| 53 | import org.onosproject.store.service.MapEventListener; | 54 | import org.onosproject.store.service.MapEventListener; |
| 54 | import org.onosproject.store.service.MapTransaction; | 55 | import org.onosproject.store.service.MapTransaction; |
| 55 | import org.onosproject.store.service.Versioned; | 56 | import org.onosproject.store.service.Versioned; |
| 56 | - | 57 | +import com.google.common.collect.ImmutableSet; |
| 57 | import com.google.common.collect.Sets; | 58 | import com.google.common.collect.Sets; |
| 58 | 59 | ||
| 59 | /** | 60 | /** |
| ... | @@ -63,6 +64,7 @@ import com.google.common.collect.Sets; | ... | @@ -63,6 +64,7 @@ import com.google.common.collect.Sets; |
| 63 | public class AtomixConsistentMap extends AbstractResource<AtomixConsistentMap> | 64 | public class AtomixConsistentMap extends AbstractResource<AtomixConsistentMap> |
| 64 | implements AsyncConsistentMap<String, byte[]> { | 65 | implements AsyncConsistentMap<String, byte[]> { |
| 65 | 66 | ||
| 67 | + private final Set<Consumer<Status>> statusChangeListeners = Sets.newCopyOnWriteArraySet(); | ||
| 66 | private final Set<MapEventListener<String, byte[]>> mapEventListeners = Sets.newCopyOnWriteArraySet(); | 68 | private final Set<MapEventListener<String, byte[]>> mapEventListeners = Sets.newCopyOnWriteArraySet(); |
| 67 | 69 | ||
| 68 | public static final String CHANGE_SUBJECT = "changeEvents"; | 70 | public static final String CHANGE_SUBJECT = "changeEvents"; |
| ... | @@ -291,4 +293,19 @@ public class AtomixConsistentMap extends AbstractResource<AtomixConsistentMap> | ... | @@ -291,4 +293,19 @@ public class AtomixConsistentMap extends AbstractResource<AtomixConsistentMap> |
| 291 | public CompletableFuture<Boolean> prepareAndCommit(MapTransaction<String, byte[]> transaction) { | 293 | public CompletableFuture<Boolean> prepareAndCommit(MapTransaction<String, byte[]> transaction) { |
| 292 | return submit(new TransactionPrepareAndCommit(transaction)).thenApply(v -> v == PrepareResult.OK); | 294 | return submit(new TransactionPrepareAndCommit(transaction)).thenApply(v -> v == PrepareResult.OK); |
| 293 | } | 295 | } |
| 296 | + | ||
| 297 | + @Override | ||
| 298 | + public void addStatusChangeListener(Consumer<Status> listener) { | ||
| 299 | + statusChangeListeners.add(listener); | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + @Override | ||
| 303 | + public void removeStatusChangeListener(Consumer<Status> listener) { | ||
| 304 | + statusChangeListeners.remove(listener); | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + @Override | ||
| 308 | + public Collection<Consumer<Status>> statusChangeListeners() { | ||
| 309 | + return ImmutableSet.copyOf(statusChangeListeners); | ||
| 310 | + } | ||
| 294 | } | 311 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or login to post a comment