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> {
ConsistentMapBuilder<K, V> withMeteringDisabled();
/**
* Provides weak consistency for map gets.
* <p>
* While this can lead to improved read performance, it can also make the behavior
* heard to reason. Only turn this on if you know what you are doing. By default
* reads are strongly consistent.
*
* @return this ConsistentMapBuilder
*/
ConsistentMapBuilder<K, V> withRelaxedReadConsistency();
/**
* Builds an consistent map based on the configuration options
* supplied to this builder.
*
......
......@@ -247,6 +247,11 @@ public final class TestConsistentMap<K, V> extends ConsistentMapAdapter<K, V> {
}
@Override
public ConsistentMapBuilder<K, V> withRelaxedReadConsistency() {
return this;
}
@Override
public ConsistentMapBuilder<K, V> withMeteringDisabled() {
return this;
}
......
package org.onosproject.store.consistent.impl;
import java.util.concurrent.CompletableFuture;
import org.onosproject.core.ApplicationId;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.Versioned;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
/**
* Extension of DefaultAsyncConsistentMap that provides a weaker read consistency
* guarantee in return for better read performance.
*
* @param <K> key type
* @param <V> value type
*/
public class AsyncCachingConsistentMap<K, V> extends DefaultAsyncConsistentMap<K, V> {
private final LoadingCache<K, CompletableFuture<Versioned<V>>> cache =
CacheBuilder.newBuilder()
.maximumSize(10000) // TODO: make configurable
.build(new CacheLoader<K, CompletableFuture<Versioned<V>>>() {
@Override
public CompletableFuture<Versioned<V>> load(K key)
throws Exception {
return AsyncCachingConsistentMap.super.get(key);
}
});
public AsyncCachingConsistentMap(String name,
ApplicationId applicationId,
Database database,
Serializer serializer,
boolean readOnly,
boolean purgeOnUninstall,
boolean meteringEnabled) {
super(name, applicationId, database, serializer, readOnly, purgeOnUninstall, meteringEnabled);
addListener(event -> cache.invalidate(event.key()));
}
@Override
public CompletableFuture<Versioned<V>> get(K key) {
CompletableFuture<Versioned<V>> cachedValue = cache.getIfPresent(key);
if (cachedValue != null) {
if (cachedValue.isCompletedExceptionally()) {
cache.invalidate(key);
} else {
return cachedValue;
}
}
return cache.getUnchecked(key);
}
}
\ No newline at end of file
......@@ -39,6 +39,7 @@ public class DefaultConsistentMapBuilder<K, V> implements ConsistentMapBuilder<K
private boolean partitionsEnabled = true;
private boolean readOnly = false;
private boolean metering = true;
private boolean relaxedReadConsistency = false;
private final DatabaseManager manager;
public DefaultConsistentMapBuilder(DatabaseManager manager) {
......@@ -90,6 +91,12 @@ public class DefaultConsistentMapBuilder<K, V> implements ConsistentMapBuilder<K
return this;
}
@Override
public ConsistentMapBuilder<K, V> withRelaxedReadConsistency() {
relaxedReadConsistency = true;
return this;
}
private void validateInputs() {
checkState(name != null, "name must be specified");
checkState(serializer != null, "serializer must be specified");
......@@ -110,14 +117,25 @@ public class DefaultConsistentMapBuilder<K, V> implements ConsistentMapBuilder<K
private DefaultAsyncConsistentMap<K, V> buildAndRegisterMap() {
validateInputs();
DefaultAsyncConsistentMap<K, V> asyncMap = new DefaultAsyncConsistentMap<>(
name,
applicationId,
partitionsEnabled ? manager.partitionedDatabase : manager.inMemoryDatabase,
serializer,
readOnly,
purgeOnUninstall,
metering);
return manager.registerMap(asyncMap);
Database database = partitionsEnabled ? manager.partitionedDatabase : manager.inMemoryDatabase;
if (relaxedReadConsistency) {
return manager.registerMap(
new AsyncCachingConsistentMap<>(name,
applicationId,
database,
serializer,
readOnly,
purgeOnUninstall,
metering));
} else {
return manager.registerMap(
new DefaultAsyncConsistentMap<>(name,
applicationId,
database,
serializer,
readOnly,
purgeOnUninstall,
metering));
}
}
}
\ No newline at end of file
......
......@@ -94,6 +94,7 @@ public class DistributedNetworkConfigStore
configs = storageService.<ConfigKey, ObjectNode>consistentMapBuilder()
.withSerializer(Serializer.using(kryoBuilder.build()))
.withName("onos-network-configs")
.withRelaxedReadConsistency()
.build();
configs.addListener(listener);
log.info("Started");
......