ONOS-2429: Support for a relaxed read consistency mode in ConsistentMap
Change-Id: I7866d8d15de369fd23e482d66cc1c918c033f169
Showing
5 changed files
with
96 additions
and
5 deletions
... | @@ -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 | } | ... | ... |
core/store/dist/src/main/java/org/onosproject/store/consistent/impl/AsyncCachingConsistentMap.java
0 → 100644
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 |
core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultConsistentMapBuilder.java
... | @@ -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"); | ... | ... |
-
Please register or login to post a comment