Madan Jampani

ONOS-2429: Support for a relaxed read consistency mode in ConsistentMap

Change-Id: I7866d8d15de369fd23e482d66cc1c918c033f169
...@@ -113,6 +113,17 @@ public interface ConsistentMapBuilder<K, V> { ...@@ -113,6 +113,17 @@ public interface ConsistentMapBuilder<K, V> {
113 ConsistentMapBuilder<K, V> withMeteringDisabled(); 113 ConsistentMapBuilder<K, V> withMeteringDisabled();
114 114
115 /** 115 /**
116 + * Provides weak consistency for map gets.
117 + * <p>
118 + * While this can lead to improved read performance, it can also make the behavior
119 + * heard to reason. Only turn this on if you know what you are doing. By default
120 + * reads are strongly consistent.
121 + *
122 + * @return this ConsistentMapBuilder
123 + */
124 + ConsistentMapBuilder<K, V> withRelaxedReadConsistency();
125 +
126 + /**
116 * Builds an consistent map based on the configuration options 127 * Builds an consistent map based on the configuration options
117 * supplied to this builder. 128 * supplied to this builder.
118 * 129 *
......
...@@ -247,6 +247,11 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> { ...@@ -247,6 +247,11 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> {
247 } 247 }
248 248
249 @Override 249 @Override
250 + public ConsistentMapBuilder<K, V> withRelaxedReadConsistency() {
251 + return this;
252 + }
253 +
254 + @Override
250 public ConsistentMapBuilder<K, V> withMeteringDisabled() { 255 public ConsistentMapBuilder<K, V> withMeteringDisabled() {
251 return this; 256 return this;
252 } 257 }
......
1 +package org.onosproject.store.consistent.impl;
2 +
3 +import java.util.concurrent.CompletableFuture;
4 +
5 +import org.onosproject.core.ApplicationId;
6 +import org.onosproject.store.service.Serializer;
7 +import org.onosproject.store.service.Versioned;
8 +
9 +import com.google.common.cache.CacheBuilder;
10 +import com.google.common.cache.CacheLoader;
11 +import com.google.common.cache.LoadingCache;
12 +
13 +/**
14 + * Extension of DefaultAsyncConsistentMap that provides a weaker read consistency
15 + * guarantee in return for better read performance.
16 + *
17 + * @param <K> key type
18 + * @param <V> value type
19 + */
20 +public class AsyncCachingConsistentMap<K, V> extends DefaultAsyncConsistentMap<K, V> {
21 +
22 + private final LoadingCache<K, CompletableFuture<Versioned<V>>> cache =
23 + CacheBuilder.newBuilder()
24 + .maximumSize(10000) // TODO: make configurable
25 + .build(new CacheLoader<K, CompletableFuture<Versioned<V>>>() {
26 + @Override
27 + public CompletableFuture<Versioned<V>> load(K key)
28 + throws Exception {
29 + return AsyncCachingConsistentMap.super.get(key);
30 + }
31 + });
32 +
33 + public AsyncCachingConsistentMap(String name,
34 + ApplicationId applicationId,
35 + Database database,
36 + Serializer serializer,
37 + boolean readOnly,
38 + boolean purgeOnUninstall,
39 + boolean meteringEnabled) {
40 + super(name, applicationId, database, serializer, readOnly, purgeOnUninstall, meteringEnabled);
41 + addListener(event -> cache.invalidate(event.key()));
42 + }
43 +
44 + @Override
45 + public CompletableFuture<Versioned<V>> get(K key) {
46 + CompletableFuture<Versioned<V>> cachedValue = cache.getIfPresent(key);
47 + if (cachedValue != null) {
48 + if (cachedValue.isCompletedExceptionally()) {
49 + cache.invalidate(key);
50 + } else {
51 + return cachedValue;
52 + }
53 + }
54 + return cache.getUnchecked(key);
55 + }
56 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -39,6 +39,7 @@ public class DefaultConsistentMapBuilder<K, V> implements ConsistentMapBuilder<K ...@@ -39,6 +39,7 @@ public class DefaultConsistentMapBuilder<K, V> implements ConsistentMapBuilder<K
39 private boolean partitionsEnabled = true; 39 private boolean partitionsEnabled = true;
40 private boolean readOnly = false; 40 private boolean readOnly = false;
41 private boolean metering = true; 41 private boolean metering = true;
42 + private boolean relaxedReadConsistency = false;
42 private final DatabaseManager manager; 43 private final DatabaseManager manager;
43 44
44 public DefaultConsistentMapBuilder(DatabaseManager manager) { 45 public DefaultConsistentMapBuilder(DatabaseManager manager) {
...@@ -90,6 +91,12 @@ public class DefaultConsistentMapBuilder<K, V> implements ConsistentMapBuilder<K ...@@ -90,6 +91,12 @@ public class DefaultConsistentMapBuilder<K, V> implements ConsistentMapBuilder<K
90 return this; 91 return this;
91 } 92 }
92 93
94 + @Override
95 + public ConsistentMapBuilder<K, V> withRelaxedReadConsistency() {
96 + relaxedReadConsistency = true;
97 + return this;
98 + }
99 +
93 private void validateInputs() { 100 private void validateInputs() {
94 checkState(name != null, "name must be specified"); 101 checkState(name != null, "name must be specified");
95 checkState(serializer != null, "serializer must be specified"); 102 checkState(serializer != null, "serializer must be specified");
...@@ -110,14 +117,25 @@ public class DefaultConsistentMapBuilder<K, V> implements ConsistentMapBuilder<K ...@@ -110,14 +117,25 @@ public class DefaultConsistentMapBuilder<K, V> implements ConsistentMapBuilder<K
110 117
111 private DefaultAsyncConsistentMap<K, V> buildAndRegisterMap() { 118 private DefaultAsyncConsistentMap<K, V> buildAndRegisterMap() {
112 validateInputs(); 119 validateInputs();
113 - DefaultAsyncConsistentMap<K, V> asyncMap = new DefaultAsyncConsistentMap<>( 120 + Database database = partitionsEnabled ? manager.partitionedDatabase : manager.inMemoryDatabase;
114 - name, 121 + if (relaxedReadConsistency) {
122 + return manager.registerMap(
123 + new AsyncCachingConsistentMap<>(name,
115 applicationId, 124 applicationId,
116 - partitionsEnabled ? manager.partitionedDatabase : manager.inMemoryDatabase, 125 + database,
117 serializer, 126 serializer,
118 readOnly, 127 readOnly,
119 purgeOnUninstall, 128 purgeOnUninstall,
120 - metering); 129 + metering));
121 - return manager.registerMap(asyncMap); 130 + } else {
131 + return manager.registerMap(
132 + new DefaultAsyncConsistentMap<>(name,
133 + applicationId,
134 + database,
135 + serializer,
136 + readOnly,
137 + purgeOnUninstall,
138 + metering));
139 + }
122 } 140 }
123 } 141 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -94,6 +94,7 @@ public class DistributedNetworkConfigStore ...@@ -94,6 +94,7 @@ public class DistributedNetworkConfigStore
94 configs = storageService.<ConfigKey, ObjectNode>consistentMapBuilder() 94 configs = storageService.<ConfigKey, ObjectNode>consistentMapBuilder()
95 .withSerializer(Serializer.using(kryoBuilder.build())) 95 .withSerializer(Serializer.using(kryoBuilder.build()))
96 .withName("onos-network-configs") 96 .withName("onos-network-configs")
97 + .withRelaxedReadConsistency()
97 .build(); 98 .build();
98 configs.addListener(listener); 99 configs.addListener(listener);
99 log.info("Started"); 100 log.info("Started");
......