From: Tom Pantelis Date: Tue, 11 Aug 2015 00:08:03 +0000 (-0400) Subject: Bug 4105: Add dynamic module/shard config for entity-owners shard X-Git-Tag: release/beryllium~303 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=5273c33b6f2051a7e3b1afcc4eeae4e457b6f26c Bug 4105: Add dynamic module/shard config for entity-owners shard Added a new method addModuleShardConfiguration to Configuration. I simplified the internals of ConfigurationImpl to make it easier to add a new module/shard config. I combined serveral of the maps into one moduleConfigMap and reduced the total # of fields to 3. For synchronization, I kept the maps/sets immutable and used copy-on-write semantics to update them as they will seldom change. I also made the fields volatile. I also removed the singleton nature of ShardStrategyFactory since each datastore's Configuration will now be different, ie only the operational datastore's Configuration will have the entity-owners module. The datastore's ShardStrategyFactory instance is not instantiated and owned by the ActorContext. To make things easier for unit tests, I abstracted the file-reading code in ConfigurationImpl to a new ModuleShardConfigProvider interface and FileModuleShardConfigProvider implementation in the config package. I also moved the inner classes to the config package. While I was at it I also moved Configuration and ConfigurationImpl to the config package for consistency. Change-Id: I1d6858d3ae68869ca6f61d4f5a5f0d319d93c485 Signed-off-by: Tom Pantelis --- diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java index 04a8e3098f..34d5ed0268 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java @@ -19,7 +19,6 @@ import org.opendaylight.controller.cluster.datastore.config.Configuration; import org.opendaylight.controller.cluster.datastore.identifiers.ShardManagerIdentifier; import org.opendaylight.controller.cluster.datastore.jmx.mbeans.DatastoreConfigurationMXBeanImpl; import org.opendaylight.controller.cluster.datastore.jmx.mbeans.DatastoreInfoMXBeanImpl; -import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; import org.opendaylight.controller.cluster.datastore.utils.ActorContext; import org.opendaylight.controller.cluster.datastore.utils.Dispatchers; import org.opendaylight.controller.cluster.datastore.utils.PrimaryShardInfoFutureCache; @@ -126,7 +125,7 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, LOG.debug("Registering listener: {} for path: {} scope: {}", listener, path, scope); - String shardName = ShardStrategyFactory.getStrategy(path).findShard(path); + String shardName = actorContext.getShardStrategyFactory().getStrategy(path).findShard(path); final DataChangeListenerRegistrationProxy listenerRegistrationProxy = new DataChangeListenerRegistrationProxy(shardName, actorContext, listener); @@ -140,7 +139,7 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Preconditions.checkNotNull(treeId, "treeId should not be null"); Preconditions.checkNotNull(listener, "listener should not be null"); - final String shardName = ShardStrategyFactory.getStrategy(treeId).findShard(treeId); + final String shardName = actorContext.getShardStrategyFactory().getStrategy(treeId).findShard(treeId); LOG.debug("Registering tree listener: {} for tree: {} shard: {}", listener, treeId, shardName); final DataTreeChangeListenerProxy listenerRegistrationProxy = diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java index e87fc55324..4d3854f9ef 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java @@ -18,7 +18,6 @@ import java.util.concurrent.TimeUnit; import org.opendaylight.controller.cluster.common.actor.AkkaConfigurationReader; import org.opendaylight.controller.cluster.datastore.config.Configuration; import org.opendaylight.controller.cluster.datastore.config.ConfigurationImpl; -import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; @@ -48,7 +47,6 @@ public class DistributedDataStoreFactory { overlay.setListener(dataStore); - ShardStrategyFactory.setConfiguration(config); schemaService.registerSchemaContextListener(dataStore); dataStore.setCloseable(overlay); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java index 99d66d515f..c24156f506 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java @@ -657,8 +657,7 @@ public class ShardManager extends AbstractUntypedPersistentActorWithMetering { */ private void createLocalShards() { String memberName = this.cluster.getCurrentMemberName(); - List memberShardNames = - this.configuration.getMemberShardNames(memberName); + Collection memberShardNames = this.configuration.getMemberShardNames(memberName); ShardPropsCreator shardPropsCreator = new DefaultShardPropsCreator(); List localShardActorNames = new ArrayList<>(); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java index c3a5d07414..cdc2ec2a0a 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java @@ -25,7 +25,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.opendaylight.controller.cluster.datastore.identifiers.TransactionIdentifier; -import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; import org.opendaylight.controller.cluster.datastore.utils.ActorContext; import org.opendaylight.controller.cluster.datastore.utils.NormalizedNodeAggregator; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; @@ -301,8 +300,8 @@ public class TransactionProxy extends AbstractDOMStoreTransaction getMemberShardNames(String memberName); + @Nonnull Collection getMemberShardNames(@Nonnull String memberName); /** - * Given a module namespace return the name of a module - * @param nameSpace - * @return + * Returns the namespace for the given module name or null if not found. */ - Optional getModuleNameFromNameSpace(String nameSpace); + @Nullable String getModuleNameFromNameSpace(@Nonnull String nameSpace); /** - * Get a mapping of the module names to it's corresponding ShardStrategy - * @return + * Returns the first shard name corresponding to the given module name or null if none is configured. */ - Map getModuleNameToShardStrategyMap(); + @Nullable String getShardNameForModule(@Nonnull String moduleName); /** - * Given a module name find all the shardNames corresponding to it - * @param moduleName - * @return + * Returns the member replicas for the given shard name. */ - List getShardNamesFromModuleName(String moduleName); + @Nonnull Collection getMembersFromShardName(@Nonnull String shardName); /** - * Given a shardName find all the members on which it belongs - * - * @param shardName - * @return + * Returns the ShardStrategy for the given module name or null if the module is not found. */ - List getMembersFromShardName(String shardName); + @Nullable ShardStrategy getStrategyForModule(@Nonnull String moduleName); /** - * - * @return + * Returns all the configured shard names. */ Set getAllShardNames(); + /** + * Adds a new configuration for a module and shard. + */ + void addModuleShardConfiguration(@Nonnull ModuleShardConfiguration config); + /** * Returns a unique set of all member names configured for all shards. */ diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImpl.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImpl.java index e705a142f2..2f1e88910e 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImpl.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImpl.java @@ -8,191 +8,110 @@ package org.opendaylight.controller.cluster.datastore.config; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ListMultimap; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; -import com.typesafe.config.ConfigObject; -import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import org.opendaylight.controller.cluster.datastore.DistributedDataStore; -import org.opendaylight.controller.cluster.datastore.shardstrategy.DefaultShardStrategy; -import org.opendaylight.controller.cluster.datastore.shardstrategy.ModuleShardStrategy; import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategy; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; public class ConfigurationImpl implements Configuration { - - private final List moduleShards; - - private final List modules; - - private static final Logger - LOG = LoggerFactory.getLogger(DistributedDataStore.class); + private volatile Map moduleConfigMap; // Look up maps to speed things up - // key = memberName, value = list of shardNames - private final Map> memberShardNames = new HashMap<>(); - - // key = shardName, value = list of replicaNames (replicaNames are the same as memberNames) - private final Map> shardReplicaNames = new HashMap<>(); - - private final ListMultimap moduleNameToShardName; - private final Map moduleNameToStrategy; - private final Map namespaceToModuleName; - private final Set allShardNames; - - public ConfigurationImpl(final String moduleShardsConfigPath, + private volatile Map namespaceToModuleName; + private volatile Set allShardNames; - final String modulesConfigPath){ - - Preconditions.checkNotNull(moduleShardsConfigPath, "moduleShardsConfigPath should not be null"); - Preconditions.checkNotNull(modulesConfigPath, "modulesConfigPath should not be null"); - - - File moduleShardsFile = new File("./configuration/initial/" + moduleShardsConfigPath); - File modulesFile = new File("./configuration/initial/" + modulesConfigPath); - - Config moduleShardsConfig = null; - if(moduleShardsFile.exists()) { - LOG.info("module shards config file exists - reading config from it"); - moduleShardsConfig = ConfigFactory.parseFile(moduleShardsFile); - } else { - LOG.warn("module shards configuration read from resource"); - moduleShardsConfig = ConfigFactory.load(moduleShardsConfigPath); - } - - Config modulesConfig = null; - if(modulesFile.exists()) { - LOG.info("modules config file exists - reading config from it"); - modulesConfig = ConfigFactory.parseFile(modulesFile); - } else { - LOG.warn("modules configuration read from resource"); - modulesConfig = ConfigFactory.load(modulesConfigPath); - } - - this.moduleShards = readModuleShards(moduleShardsConfig); - this.modules = readModules(modulesConfig); - - this.allShardNames = createAllShardNames(moduleShards); - this.moduleNameToShardName = createModuleNameToShardName(moduleShards); - this.moduleNameToStrategy = createModuleNameToStrategy(modules); - this.namespaceToModuleName = createNamespaceToModuleName(modules); + public ConfigurationImpl(final String moduleShardsConfigPath, final String modulesConfigPath) { + this(new FileModuleShardConfigProvider(moduleShardsConfigPath, modulesConfigPath)); } - private static Set createAllShardNames(Iterable moduleShards) { - final com.google.common.collect.ImmutableSet.Builder b = ImmutableSet.builder(); - for(ModuleShard ms : moduleShards){ - for(Shard s : ms.getShards()) { - b.add(s.getName()); - } - } - return b.build(); - } + public ConfigurationImpl(final ModuleShardConfigProvider provider) { + this.moduleConfigMap = ImmutableMap.copyOf(provider.retrieveModuleConfigs(this)); - private static Map createModuleNameToStrategy(Iterable modules) { - final com.google.common.collect.ImmutableMap.Builder b = ImmutableMap.builder(); - for (Module m : modules) { - b.put(m.getName(), m.getShardStrategy()); - } - return b.build(); + this.allShardNames = createAllShardNames(moduleConfigMap.values()); + this.namespaceToModuleName = createNamespaceToModuleName(moduleConfigMap.values()); } - private static Map createNamespaceToModuleName(Iterable modules) { - final com.google.common.collect.ImmutableMap.Builder b = ImmutableMap.builder(); - for (Module m : modules) { - b.put(m.getNameSpace(), m.getName()); + private static Set createAllShardNames(Iterable moduleConfigs) { + final ImmutableSet.Builder builder = ImmutableSet.builder(); + for(ModuleConfig moduleConfig : moduleConfigs) { + builder.addAll(moduleConfig.getShardNames()); } - return b.build(); - } - private static ListMultimap createModuleNameToShardName(Iterable moduleShards) { - final com.google.common.collect.ImmutableListMultimap.Builder b = ImmutableListMultimap.builder(); + return builder.build(); + } - for (ModuleShard m : moduleShards) { - for (Shard s : m.getShards()) { - b.put(m.getModuleName(), s.getName()); + private static Map createNamespaceToModuleName(Iterable moduleConfigs) { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + for(ModuleConfig moduleConfig : moduleConfigs) { + if(moduleConfig.getNameSpace() != null) { + builder.put(moduleConfig.getNameSpace(), moduleConfig.getName()); } } - return b.build(); + return builder.build(); } - @Override public List getMemberShardNames(final String memberName){ - + @Override + public Collection getMemberShardNames(final String memberName){ Preconditions.checkNotNull(memberName, "memberName should not be null"); - if(memberShardNames.containsKey(memberName)){ - return memberShardNames.get(memberName); - } - List shards = new ArrayList<>(); - for(ModuleShard ms : moduleShards){ - for(Shard s : ms.getShards()){ - for(String m : s.getReplicas()){ - if(memberName.equals(m)){ - shards.add(s.getName()); - } + for(ModuleConfig moduleConfig: moduleConfigMap.values()) { + for(ShardConfig shardConfig: moduleConfig.getShardConfigs()) { + if(shardConfig.getReplicas().contains(memberName)) { + shards.add(shardConfig.getName()); } } } - memberShardNames.put(memberName, shards); - return shards; - } @Override - public Optional getModuleNameFromNameSpace(final String nameSpace) { + public String getModuleNameFromNameSpace(final String nameSpace) { Preconditions.checkNotNull(nameSpace, "nameSpace should not be null"); - return Optional.fromNullable(namespaceToModuleName.get(nameSpace)); + + return namespaceToModuleName.get(nameSpace); } @Override - public Map getModuleNameToShardStrategyMap() { - return moduleNameToStrategy; + public ShardStrategy getStrategyForModule(String moduleName) { + Preconditions.checkNotNull(moduleName, "moduleName should not be null"); + + ModuleConfig moduleConfig = moduleConfigMap.get(moduleName); + return moduleConfig != null ? moduleConfig.getShardStrategy(): null; } @Override - public List getShardNamesFromModuleName(final String moduleName) { + public String getShardNameForModule(final String moduleName) { Preconditions.checkNotNull(moduleName, "moduleName should not be null"); - return moduleNameToShardName.get(moduleName); - } - @Override public List getMembersFromShardName(final String shardName) { + ModuleConfig moduleConfig = moduleConfigMap.get(moduleName); + Collection shardConfigs = moduleConfig != null ? moduleConfig.getShardConfigs() : + Collections.emptySet(); + return !shardConfigs.isEmpty() ? shardConfigs.iterator().next().getName(): null; + } + @Override + public Collection getMembersFromShardName(final String shardName) { Preconditions.checkNotNull(shardName, "shardName should not be null"); - if(shardReplicaNames.containsKey(shardName)){ - return shardReplicaNames.get(shardName); - } - - for(ModuleShard ms : moduleShards){ - for(Shard s : ms.getShards()) { - if(s.getName().equals(shardName)){ - List replicas = s.getReplicas(); - shardReplicaNames.put(shardName, replicas); - return replicas; - } + for(ModuleConfig moduleConfig: moduleConfigMap.values()) { + ShardConfig shardConfig = moduleConfig.getShardConfig(shardName); + if(shardConfig != null) { + return shardConfig.getReplicas(); } } - shardReplicaNames.put(shardName, Collections.emptyList()); + return Collections.emptyList(); } @@ -204,129 +123,32 @@ public class ConfigurationImpl implements Configuration { @Override public Collection getUniqueMemberNamesForAllShards() { Set allNames = new HashSet<>(); - for(String shardName: allShardNames) { + for(String shardName: getAllShardNames()) { allNames.addAll(getMembersFromShardName(shardName)); } return allNames; } - private List readModules(final Config modulesConfig) { - List modulesConfigObjectList = - modulesConfig.getObjectList("modules"); - - final Builder b = ImmutableList.builder(); - for(ConfigObject o : modulesConfigObjectList){ - ConfigObjectWrapper w = new ConfigObjectWrapper(o); - b.add(new Module(w.stringValue("name"), w.stringValue( - "namespace"), w.stringValue("shard-strategy"))); - } - - return b.build(); - } - - private static List readModuleShards(final Config moduleShardsConfig) { - List moduleShardsConfigObjectList = - moduleShardsConfig.getObjectList("module-shards"); - - final Builder b = ImmutableList.builder(); - for(ConfigObject moduleShardConfigObject : moduleShardsConfigObjectList){ - - String moduleName = moduleShardConfigObject.get("name").unwrapped().toString(); - - List shardsConfigObjectList = - moduleShardConfigObject.toConfig().getObjectList("shards"); - - List shards = new ArrayList<>(); - - for(ConfigObject shard : shardsConfigObjectList){ - String shardName = shard.get("name").unwrapped().toString(); - List replicas = shard.toConfig().getStringList("replicas"); - shards.add(new Shard(shardName, replicas)); - } - - b.add(new ModuleShard(moduleName, shards)); - } - - return b.build(); - } - - private static class ModuleShard { - private final String moduleName; - private final List shards; - - public ModuleShard(final String moduleName, final List shards) { - this.moduleName = moduleName; - this.shards = shards; - } - - public String getModuleName() { - return moduleName; - } - - public List getShards() { - return shards; - } - } - - private static class Shard { - private final String name; - private final List replicas; - - Shard(final String name, final List replicas) { - this.name = name; - this.replicas = replicas; - } - - public String getName() { - return name; - } - - public List getReplicas() { - return replicas; - } - } - - private class Module { - - private final String name; - private final String nameSpace; - private final ShardStrategy shardStrategy; + @Override + public synchronized void addModuleShardConfiguration(ModuleShardConfiguration config) { + Preconditions.checkNotNull(config, "ModuleShardConfiguration should not be null"); - Module(final String name, final String nameSpace, final String shardStrategy) { - this.name = name; - this.nameSpace = nameSpace; - if(ModuleShardStrategy.NAME.equals(shardStrategy)){ - this.shardStrategy = new ModuleShardStrategy(name, ConfigurationImpl.this); - } else { - this.shardStrategy = DefaultShardStrategy.getInstance(); - } - } + ModuleConfig moduleConfig = new ModuleConfig(config.getModuleName()); + moduleConfig.setNameSpace(config.getNamespace().toASCIIString()); + moduleConfig.setShardStrategy(createShardStrategy(config.getModuleName(), config.getShardStrategyName())); - public String getName() { - return name; - } + moduleConfig.addShardConfig(config.getShardName(), ImmutableSet.copyOf(config.getShardMemberNames())); - public String getNameSpace() { - return nameSpace; - } + moduleConfigMap = ImmutableMap.builder().putAll(moduleConfigMap). + put(config.getModuleName(), moduleConfig).build(); - public ShardStrategy getShardStrategy() { - return shardStrategy; - } + namespaceToModuleName = ImmutableMap.builder().putAll(namespaceToModuleName). + put(moduleConfig.getNameSpace(), moduleConfig.getName()).build(); + allShardNames = ImmutableSet.builder().addAll(allShardNames).add(config.getShardName()).build(); } - - private static class ConfigObjectWrapper{ - - private final ConfigObject configObject; - - ConfigObjectWrapper(final ConfigObject configObject){ - this.configObject = configObject; - } - - public String stringValue(final String name){ - return configObject.get(name).unwrapped().toString(); - } + private ShardStrategy createShardStrategy(String moduleName, String shardStrategyName) { + return ShardStrategyFactory.newShardStrategyInstance(moduleName, shardStrategyName, this); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/FileModuleShardConfigProvider.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/FileModuleShardConfigProvider.java new file mode 100644 index 0000000000..9ceac9561e --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/FileModuleShardConfigProvider.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.datastore.config; + +import com.google.common.collect.ImmutableSet; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigObject; +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of ModuleShardConfigProvider that reads the module and shard configuration from files. + * + * @author Thomas Pantelis + */ +public class FileModuleShardConfigProvider implements ModuleShardConfigProvider { + private static final Logger LOG = LoggerFactory.getLogger(FileModuleShardConfigProvider.class); + + private final String moduleShardsConfigPath; + private final String modulesConfigPath; + + public FileModuleShardConfigProvider(String moduleShardsConfigPath, String modulesConfigPath) { + this.moduleShardsConfigPath = moduleShardsConfigPath; + this.modulesConfigPath = modulesConfigPath; + } + + @Override + public Map retrieveModuleConfigs(Configuration configuration) { + File moduleShardsFile = new File("./configuration/initial/" + moduleShardsConfigPath); + File modulesFile = new File("./configuration/initial/" + modulesConfigPath); + + Config moduleShardsConfig = null; + if(moduleShardsFile.exists()) { + LOG.info("module shards config file exists - reading config from it"); + moduleShardsConfig = ConfigFactory.parseFile(moduleShardsFile); + } else { + LOG.warn("module shards configuration read from resource"); + moduleShardsConfig = ConfigFactory.load(moduleShardsConfigPath); + } + + Config modulesConfig = null; + if(modulesFile.exists()) { + LOG.info("modules config file exists - reading config from it"); + modulesConfig = ConfigFactory.parseFile(modulesFile); + } else { + LOG.warn("modules configuration read from resource"); + modulesConfig = ConfigFactory.load(modulesConfigPath); + } + + Map moduleConfigMap = readModuleShardsConfig(moduleShardsConfig); + readModulesConfig(modulesConfig, moduleConfigMap, configuration); + + return moduleConfigMap; + } + + private void readModulesConfig(final Config modulesConfig, Map moduleConfigMap, + Configuration configuration) { + List modulesConfigObjectList = modulesConfig.getObjectList("modules"); + + for(ConfigObject o : modulesConfigObjectList){ + ConfigObjectWrapper w = new ConfigObjectWrapper(o); + + String moduleName = w.stringValue("name"); + ModuleConfig moduleConfig = moduleConfigMap.get(moduleName); + if(moduleConfig == null) { + moduleConfig = new ModuleConfig(moduleName); + moduleConfigMap.put(moduleName, moduleConfig); + } + + moduleConfig.setNameSpace(w.stringValue("namespace")); + moduleConfig.setShardStrategy(ShardStrategyFactory.newShardStrategyInstance(moduleName, + w.stringValue("shard-strategy"), configuration)); + } + } + + private static Map readModuleShardsConfig(final Config moduleShardsConfig) { + List moduleShardsConfigObjectList = + moduleShardsConfig.getObjectList("module-shards"); + + Map moduleConfigMap = new HashMap<>(); + for(ConfigObject moduleShardConfigObject : moduleShardsConfigObjectList){ + String moduleName = moduleShardConfigObject.get("name").unwrapped().toString(); + ModuleConfig moduleConfig = new ModuleConfig(moduleName); + + List shardsConfigObjectList = + moduleShardConfigObject.toConfig().getObjectList("shards"); + + for(ConfigObject shard : shardsConfigObjectList){ + String shardName = shard.get("name").unwrapped().toString(); + List replicas = shard.toConfig().getStringList("replicas"); + moduleConfig.addShardConfig(shardName, ImmutableSet.copyOf(replicas)); + } + + moduleConfigMap.put(moduleName, moduleConfig); + } + + return moduleConfigMap; + } + + private static class ConfigObjectWrapper{ + + private final ConfigObject configObject; + + ConfigObjectWrapper(final ConfigObject configObject){ + this.configObject = configObject; + } + + public String stringValue(final String name){ + return configObject.get(name).unwrapped().toString(); + } + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleConfig.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleConfig.java new file mode 100644 index 0000000000..1a309a06c0 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleConfig.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.datastore.config; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategy; + +/** + * Encapsulates configuration for a module. + * + * @author Thomas Pantelis + */ +public class ModuleConfig { + private final String name; + private String nameSpace; + private ShardStrategy shardStrategy; + private final Map shardConfigs = new HashMap<>(); + + public ModuleConfig(final String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String getNameSpace() { + return nameSpace; + } + + public ShardStrategy getShardStrategy() { + return shardStrategy; + } + + public ShardConfig getShardConfig(String name) { + return shardConfigs.get(name); + } + + public Collection getShardConfigs() { + return shardConfigs.values(); + } + + public Collection getShardNames() { + return shardConfigs.keySet(); + } + + public void addShardConfig(String name, Set replicas) { + shardConfigs.put(name, new ShardConfig(name, replicas)); + } + + public void setNameSpace(String nameSpace) { + this.nameSpace = nameSpace; + } + + public void setShardStrategy(ShardStrategy shardStrategy) { + this.shardStrategy = shardStrategy; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleShardConfigProvider.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleShardConfigProvider.java new file mode 100644 index 0000000000..6ff708163a --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleShardConfigProvider.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.datastore.config; + +import java.util.Map; +import javax.annotation.Nonnull; + +/** + * Interface for a class that provides module and shard configuration information. + * + * @author Thomas Pantelis + */ +public interface ModuleShardConfigProvider { + /** + * Returns a Map of ModuleConfig instances keyed by module name. + */ + @Nonnull Map retrieveModuleConfigs(@Nonnull Configuration configuration); +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleShardConfiguration.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleShardConfiguration.java new file mode 100644 index 0000000000..e4b88fb07d --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleShardConfiguration.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.datastore.config; + +import com.google.common.base.Preconditions; +import java.net.URI; +import java.util.Collection; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Encapsulates information for adding a new module shard configuration. + * + * @author Thomas Pantelis + */ +public class ModuleShardConfiguration { + private final URI namespace; + private final String moduleName; + private final String shardName; + private final String shardStrategyName; + private final Collection shardMemberNames; + + /** + * Constructs a new instance. + * + * @param namespace the name space of the module. + * @param moduleName the name of the module. + * @param shardName the name of the shard. + * @param shardStrategyName the name of the sharding strategy (eg "module"). If null the default strategy + * is used. + * @param shardMemberNames the names of the shard's member replicas. + */ + public ModuleShardConfiguration(@Nonnull URI namespace, @Nonnull String moduleName, @Nonnull String shardName, + @Nullable String shardStrategyName, @Nonnull Collection shardMemberNames) { + this.namespace = Preconditions.checkNotNull(namespace, "nameSpace should not be null"); + this.moduleName = Preconditions.checkNotNull(moduleName, "moduleName should not be null"); + this.shardName = Preconditions.checkNotNull(shardName, "shardName should not be null"); + this.shardStrategyName = shardStrategyName; + this.shardMemberNames = Preconditions.checkNotNull(shardMemberNames, "shardMemberNames"); + } + + public URI getNamespace() { + return namespace; + } + + public String getModuleName() { + return moduleName; + } + + public String getShardName() { + return shardName; + } + + public String getShardStrategyName() { + return shardStrategyName; + } + + public Collection getShardMemberNames() { + return shardMemberNames; + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ShardConfig.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ShardConfig.java new file mode 100644 index 0000000000..0eb02aa2f8 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ShardConfig.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.cluster.datastore.config; + +import java.util.Set; + +/** + * Encapsulated configuration for a shard. + */ +public class ShardConfig { + private final String name; + private final Set replicas; + + public ShardConfig(final String name, final Set replicas) { + this.name = name; + this.replicas = replicas; + } + + public String getName() { + return name; + } + + public Set getReplicas() { + return replicas; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipService.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipService.java index bfdda4ce70..d6dd9a4254 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipService.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipService.java @@ -11,13 +11,17 @@ import akka.actor.ActorRef; import akka.dispatch.OnComplete; import akka.util.Timeout; import com.google.common.annotations.VisibleForTesting; +import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import org.opendaylight.controller.cluster.datastore.DistributedDataStore; +import org.opendaylight.controller.cluster.datastore.config.Configuration; +import org.opendaylight.controller.cluster.datastore.config.ModuleShardConfiguration; import org.opendaylight.controller.cluster.datastore.entityownership.messages.RegisterCandidateLocal; import org.opendaylight.controller.cluster.datastore.entityownership.messages.UnregisterCandidateLocal; import org.opendaylight.controller.cluster.datastore.messages.CreateShard; +import org.opendaylight.controller.cluster.datastore.shardstrategy.ModuleShardStrategy; import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException; import org.opendaylight.controller.md.sal.common.api.clustering.Entity; import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidate; @@ -25,6 +29,7 @@ import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipC import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener; import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration; import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.clustering.entity.owners.rev150804.entity.owners.EntityOwner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import scala.concurrent.Future; @@ -50,9 +55,13 @@ public class DistributedEntityOwnershipService implements EntityOwnershipService public void start() { ActorRef shardManagerActor = datastore.getActorContext().getShardManager(); + Configuration configuration = datastore.getActorContext().getConfiguration(); + Collection entityOwnersMemberNames = configuration.getUniqueMemberNamesForAllShards(); + configuration.addModuleShardConfiguration(new ModuleShardConfiguration(EntityOwner.QNAME.getNamespace(), + "entity-owners", ENTITY_OWNERSHIP_SHARD_NAME, ModuleShardStrategy.NAME, entityOwnersMemberNames)); + CreateShard createShard = new CreateShard(ENTITY_OWNERSHIP_SHARD_NAME, - datastore.getActorContext().getConfiguration().getUniqueMemberNamesForAllShards(), - newShardPropsCreator(), null); + entityOwnersMemberNames, newShardPropsCreator(), null); Future createFuture = datastore.getActorContext().executeOperationAsync(shardManagerActor, createShard, MESSAGE_TIMEOUT); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategy.java index 896ebaef46..26cbc053f6 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategy.java @@ -8,7 +8,6 @@ package org.opendaylight.controller.cluster.datastore.shardstrategy; -import java.util.List; import org.opendaylight.controller.cluster.datastore.config.Configuration; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -21,17 +20,12 @@ public class ModuleShardStrategy implements ShardStrategy { public ModuleShardStrategy(String moduleName, Configuration configuration){ this.moduleName = moduleName; - this.configuration = configuration; } @Override public String findShard(YangInstanceIdentifier path) { - List shardNames = - configuration.getShardNamesFromModuleName(moduleName); - if (shardNames.isEmpty()) { - return DefaultShardStrategy.DEFAULT_SHARD; - } - return shardNames.get(0); + String shardName = configuration.getShardNameForModule(moduleName); + return shardName != null ? shardName : DefaultShardStrategy.DEFAULT_SHARD; } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactory.java index 7d077b8559..1a5a4ac313 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactory.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactory.java @@ -8,33 +8,25 @@ package org.opendaylight.controller.cluster.datastore.shardstrategy; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import org.opendaylight.controller.cluster.datastore.config.Configuration; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; public class ShardStrategyFactory { - private static Map moduleNameToStrategyMap = - new ConcurrentHashMap<>(); - private static final String UNKNOWN_MODULE_NAME = "unknown"; - private static Configuration configuration; + private final Configuration configuration; - public static void setConfiguration(final Configuration configuration){ - ShardStrategyFactory.configuration = configuration; - moduleNameToStrategyMap = configuration.getModuleNameToShardStrategyMap(); + public ShardStrategyFactory(final Configuration configuration) { + Preconditions.checkState(configuration != null, "configuration should not be missing"); + this.configuration = configuration; } - public static ShardStrategy getStrategy(final YangInstanceIdentifier path) { - Preconditions.checkState(configuration != null, "configuration should not be missing"); + public ShardStrategy getStrategy(final YangInstanceIdentifier path) { Preconditions.checkNotNull(path, "path should not be null"); - String moduleName = getModuleName(path); - ShardStrategy shardStrategy = moduleNameToStrategyMap.get(moduleName); + ShardStrategy shardStrategy = configuration.getStrategyForModule(moduleName); if (shardStrategy == null) { return DefaultShardStrategy.getInstance(); } @@ -42,17 +34,18 @@ public class ShardStrategyFactory { return shardStrategy; } - - private static String getModuleName(final YangInstanceIdentifier path) { - String namespace = path.getPathArguments().iterator().next().getNodeType().getNamespace().toASCIIString(); - - Optional optional = - configuration.getModuleNameFromNameSpace(namespace); - - if(!optional.isPresent()){ - return UNKNOWN_MODULE_NAME; + public static ShardStrategy newShardStrategyInstance(String moduleName, String strategyName, + Configuration configuration) { + if(ModuleShardStrategy.NAME.equals(strategyName)){ + return new ModuleShardStrategy(moduleName, configuration); } - return optional.get(); + return DefaultShardStrategy.getInstance(); + } + + private String getModuleName(final YangInstanceIdentifier path) { + String namespace = path.getPathArguments().iterator().next().getNodeType().getNamespace().toASCIIString(); + String moduleName = configuration.getModuleNameFromNameSpace(namespace); + return moduleName != null ? moduleName : UNKNOWN_MODULE_NAME; } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java index 2b2487f77e..bc492887f9 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java @@ -43,6 +43,7 @@ import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound import org.opendaylight.controller.cluster.datastore.messages.PrimaryShardInfo; import org.opendaylight.controller.cluster.datastore.messages.RemotePrimaryShardFound; import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; +import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; import org.opendaylight.controller.cluster.reporting.MetricsReporter; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -100,6 +101,7 @@ public class ActorContext { private final MetricRegistry metricRegistry = MetricsReporter.getInstance(DatastoreContext.METRICS_DOMAIN).getMetricsRegistry(); private final PrimaryShardInfoFutureCache primaryShardInfoCache; + private final ShardStrategyFactory shardStrategyFactory; public ActorContext(ActorSystem actorSystem, ActorRef shardManager, ClusterWrapper clusterWrapper, Configuration configuration) { @@ -117,6 +119,7 @@ public class ActorContext { this.datastoreContext = datastoreContext; this.dispatchers = new Dispatchers(actorSystem.dispatchers()); this.primaryShardInfoCache = primaryShardInfoCache; + this.shardStrategyFactory = new ShardStrategyFactory(configuration); setCachedProperties(); @@ -532,6 +535,10 @@ public class ActorContext { return configuration; } + public ShardStrategyFactory getShardStrategyFactory() { + return shardStrategyFactory; + } + protected Future doAsk(ActorRef actorRef, Object message, Timeout timeout){ return ask(actorRef, message, timeout); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractTransactionProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractTransactionProxyTest.java index a93666f0ee..f7a364b67e 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractTransactionProxyTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractTransactionProxyTest.java @@ -93,31 +93,33 @@ public abstract class AbstractTransactionProxyTest { private static ActorSystem system; private final Configuration configuration = new MockConfiguration() { + Map strategyMap = ImmutableMap.builder().put( + "junk", new ShardStrategy() { + @Override + public String findShard(YangInstanceIdentifier path) { + return "junk"; + } + }).put( + "cars", new ShardStrategy() { + @Override + public String findShard(YangInstanceIdentifier path) { + return "cars"; + } + }).build(); + @Override - public Map getModuleNameToShardStrategyMap() { - return ImmutableMap.builder().put( - "junk", new ShardStrategy() { - @Override - public String findShard(YangInstanceIdentifier path) { - return "junk"; - } - }).put( - "cars", new ShardStrategy() { - @Override - public String findShard(YangInstanceIdentifier path) { - return "cars"; - } - }).build(); + public ShardStrategy getStrategyForModule(String moduleName) { + return strategyMap.get(moduleName); } @Override - public Optional getModuleNameFromNameSpace(String nameSpace) { + public String getModuleNameFromNameSpace(String nameSpace) { if(TestModel.JUNK_QNAME.getNamespace().toASCIIString().equals(nameSpace)) { - return Optional.of("junk"); + return "junk"; } else if(CarsModel.BASE_QNAME.getNamespace().toASCIIString().equals(nameSpace)){ - return Optional.of("cars"); + return "cars"; } - return Optional.absent(); + return null; } }; @@ -162,6 +164,7 @@ public abstract class AbstractTransactionProxyTest { doReturn(getSystem()).when(mockActorContext).getActorSystem(); doReturn(getSystem().dispatchers().defaultGlobalDispatcher()).when(mockActorContext).getClientDispatcher(); doReturn(memberName).when(mockActorContext).getCurrentMemberName(); + doReturn(new ShardStrategyFactory(configuration)).when(mockActorContext).getShardStrategyFactory(); doReturn(schemaContext).when(mockActorContext).getSchemaContext(); doReturn(new Timeout(operationTimeoutInSeconds, TimeUnit.SECONDS)).when(mockActorContext).getOperationTimeout(); doReturn(mockClusterWrapper).when(mockActorContext).getClusterWrapper(); @@ -172,8 +175,6 @@ public abstract class AbstractTransactionProxyTest { Timer timer = new MetricRegistry().timer("test"); doReturn(timer).when(mockActorContext).getOperationTimer(any(String.class)); - - ShardStrategyFactory.setConfiguration(configuration); } protected ActorSystem getSystem() { diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/IntegrationTestKit.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/IntegrationTestKit.java index 2b2729c959..a882ff33cc 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/IntegrationTestKit.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/IntegrationTestKit.java @@ -21,7 +21,6 @@ import java.util.concurrent.TimeUnit; import org.opendaylight.controller.cluster.datastore.DatastoreContext.Builder; import org.opendaylight.controller.cluster.datastore.config.Configuration; import org.opendaylight.controller.cluster.datastore.config.ConfigurationImpl; -import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; import org.opendaylight.controller.cluster.datastore.utils.ActorContext; import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; @@ -54,7 +53,6 @@ class IntegrationTestKit extends ShardTestKit { String... shardNames) { ClusterWrapper cluster = new ClusterWrapperImpl(getSystem()); Configuration config = new ConfigurationImpl(moduleShardsConfig, "modules.conf"); - ShardStrategyFactory.setConfiguration(config); datastoreContextBuilder.dataStoreType(typeName); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplTest.java index 443f017734..bcfbeb4b58 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplTest.java @@ -9,16 +9,18 @@ package org.opendaylight.controller.cluster.datastore.config; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Sets; -import com.typesafe.config.ConfigFactory; -import java.io.File; -import java.util.List; +import java.net.URI; +import java.util.Collection; import java.util.Set; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.shardstrategy.ModuleShardStrategy; +import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategy; public class ConfigurationImplTest { @@ -36,71 +38,112 @@ public class ConfigurationImplTest { @Test public void testGetMemberShardNames(){ - List memberShardNames = - configuration.getMemberShardNames("member-1"); + Collection memberShardNames = configuration.getMemberShardNames("member-1"); + assertEquals("getMemberShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default"), + ImmutableSortedSet.copyOf(memberShardNames)); - assertTrue(memberShardNames.contains("people-1")); - assertTrue(memberShardNames.contains("cars-1")); - - // Retrieve once again to hit cache - - memberShardNames = - configuration.getMemberShardNames("member-1"); - - assertTrue(memberShardNames.contains("people-1")); - assertTrue(memberShardNames.contains("cars-1")); + memberShardNames = configuration.getMemberShardNames("member-2"); + assertEquals("getMemberShardNames", ImmutableSortedSet.of("default"), + ImmutableSortedSet.copyOf(memberShardNames)); + memberShardNames = configuration.getMemberShardNames("member-100"); + assertEquals("getMemberShardNames size", 0, memberShardNames.size()); } @Test public void testGetMembersFromShardName(){ - List members = - configuration.getMembersFromShardName("default"); + Collection members = configuration.getMembersFromShardName("default"); + assertEquals("getMembersFromShardName", ImmutableSortedSet.of("member-1", "member-2", "member-3"), + ImmutableSortedSet.copyOf(members)); - assertEquals(3, members.size()); + members = configuration.getMembersFromShardName("cars-1"); + assertEquals("getMembersFromShardName", ImmutableSortedSet.of("member-1"), + ImmutableSortedSet.copyOf(members)); - assertTrue(members.contains("member-1")); - assertTrue(members.contains("member-2")); - assertTrue(members.contains("member-3")); + // Try to find a shard which is not present - assertFalse(members.contains("member-26")); + members = configuration.getMembersFromShardName("foobar"); + assertEquals("getMembersFromShardName size", 0, members.size()); + } - // Retrieve once again to hit cache - members = - configuration.getMembersFromShardName("default"); + @Test + public void testGetAllShardNames(){ + Set allShardNames = configuration.getAllShardNames(); + assertEquals("getAllShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default"), + ImmutableSortedSet.copyOf(allShardNames)); + } - assertEquals(3, members.size()); + @Test + public void testGetModuleNameFromNameSpace() { + String moduleName = configuration.getModuleNameFromNameSpace( + "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:cars"); + assertEquals("getModuleNameFromNameSpace", "cars", moduleName); - assertTrue(members.contains("member-1")); - assertTrue(members.contains("member-2")); - assertTrue(members.contains("member-3")); + moduleName = configuration.getModuleNameFromNameSpace( + "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test"); + assertEquals("getModuleNameFromNameSpace", "test", moduleName); - assertFalse(members.contains("member-26")); + moduleName = configuration.getModuleNameFromNameSpace("non-existent"); + assertNull("getModuleNameFromNameSpace - expected null", moduleName); + } + @Test + public void testGetStrategyForModule() { + ShardStrategy strategy = configuration.getStrategyForModule("cars"); + assertNotNull("getStrategyForModule null", strategy); + assertEquals("getStrategyForModule type", ModuleShardStrategy.class, strategy.getClass()); - // Try to find a shard which is not present + strategy = configuration.getStrategyForModule("people"); + assertNotNull("getStrategyForModule null", strategy); + assertEquals("getStrategyForModule type", ModuleShardStrategy.class, strategy.getClass()); - members = - configuration.getMembersFromShardName("foobar"); + strategy = configuration.getStrategyForModule("default"); + assertNull("getStrategyForModule - expected null", strategy); - assertEquals(0, members.size()); + strategy = configuration.getStrategyForModule("non-existent"); + assertNull("getStrategyForModule - expected null", strategy); } @Test - public void testReadConfigurationFromFile(){ - File f = new File("./module-shards.conf"); - ConfigFactory.parseFile(f); + public void testGetShardNameForModule() { + String shardName = configuration.getShardNameForModule("cars"); + assertEquals("getShardNameForModule", "cars-1", shardName); + + shardName = configuration.getShardNameForModule("people"); + assertEquals("getShardNameForModule", "people-1", shardName); + + shardName = configuration.getShardNameForModule("non-existent"); + assertNull("getShardNameForModule - expected null", shardName); } @Test - public void testGetAllShardNames(){ - Set allShardNames = configuration.getAllShardNames(); - - assertEquals(4, allShardNames.size()); - assertTrue(allShardNames.contains("default")); - assertTrue(allShardNames.contains("people-1")); - assertTrue(allShardNames.contains("cars-1")); - assertTrue(allShardNames.contains("test-1")); + public void testAddModuleShardConfiguration() throws Exception { + URI namespace = new URI("urn:opendaylight:test:oven"); + String moduleName = "oven"; + String shardName = "oven-shard"; + String shardStrategyName = ModuleShardStrategy.NAME; + Collection shardMemberNames = ImmutableSortedSet.of("member-1", "member-4", "member-5"); + + configuration.addModuleShardConfiguration(new ModuleShardConfiguration(namespace, moduleName, shardName, + shardStrategyName, shardMemberNames)); + + assertEquals("getMemberShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default", shardName), + ImmutableSortedSet.copyOf(configuration.getMemberShardNames("member-1"))); + assertEquals("getMemberShardNames", ImmutableSortedSet.of(shardName), + ImmutableSortedSet.copyOf(configuration.getMemberShardNames("member-4"))); + assertEquals("getMemberShardNames", ImmutableSortedSet.of(shardName), + ImmutableSortedSet.copyOf(configuration.getMemberShardNames("member-5"))); + assertEquals("getMembersFromShardName", shardMemberNames, + ImmutableSortedSet.copyOf(configuration.getMembersFromShardName(shardName))); + assertEquals("getShardNameForModule", shardName, configuration.getShardNameForModule(moduleName)); + assertEquals("getModuleNameFromNameSpace", moduleName, + configuration.getModuleNameFromNameSpace(namespace.toASCIIString())); + assertEquals("getAllShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default", shardName), + ImmutableSortedSet.copyOf(configuration.getAllShardNames())); + + ShardStrategy strategy = configuration.getStrategyForModule("cars"); + assertNotNull("getStrategyForModule null", strategy); + assertEquals("getStrategyForModule type", ModuleShardStrategy.class, strategy.getClass()); } @Test diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipServiceTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipServiceTest.java index 0776b502c2..7e2f7547b3 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipServiceTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipServiceTest.java @@ -19,10 +19,8 @@ import akka.actor.PoisonPill; import akka.actor.Props; import com.google.common.base.Optional; import com.google.common.base.Stopwatch; -import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.Uninterruptibles; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -32,13 +30,14 @@ import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.DatastoreContext; import org.opendaylight.controller.cluster.datastore.DistributedDataStore; +import org.opendaylight.controller.cluster.datastore.config.Configuration; +import org.opendaylight.controller.cluster.datastore.config.ConfigurationImpl; +import org.opendaylight.controller.cluster.datastore.config.ModuleConfig; +import org.opendaylight.controller.cluster.datastore.config.ModuleShardConfigProvider; import org.opendaylight.controller.cluster.datastore.entityownership.messages.RegisterCandidateLocal; import org.opendaylight.controller.cluster.datastore.entityownership.messages.UnregisterCandidateLocal; import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier; -import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategy; -import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; import org.opendaylight.controller.cluster.datastore.utils.MockClusterWrapper; -import org.opendaylight.controller.cluster.datastore.utils.MockConfiguration; import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper; import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException; import org.opendaylight.controller.md.sal.common.api.clustering.Entity; @@ -72,30 +71,16 @@ public class DistributedEntityOwnershipServiceTest extends AbstractEntityOwnersh DatastoreContext datastoreContext = DatastoreContext.newBuilder().dataStoreType(dataStoreType). shardInitializationTimeout(10, TimeUnit.SECONDS).build(); - // FIXME - remove this MockConfiguration and use the production ConfigurationImpl class when the - // DistributedEntityOwnershipService is changed to setup the ShardStrategy for the entity-owners module. - MockConfiguration configuration = new MockConfiguration(Collections.>emptyMap()) { + Configuration configuration = new ConfigurationImpl(new ModuleShardConfigProvider() { @Override - public Optional getModuleNameFromNameSpace(String nameSpace) { - return Optional.of("entity-owners"); + public Map retrieveModuleConfigs(Configuration configuration) { + return Collections.emptyMap(); } - - @Override - public Map getModuleNameToShardStrategyMap() { - return ImmutableMap.builder().put("entity-owners", new ShardStrategy() { - @Override - public String findShard(YangInstanceIdentifier path) { - return DistributedEntityOwnershipService.ENTITY_OWNERSHIP_SHARD_NAME; - } - }).build(); - } - }; + }); dataStore = new DistributedDataStore(getSystem(), new MockClusterWrapper(), configuration, datastoreContext ); dataStore.onGlobalContextUpdated(SchemaContextHelper.entityOwners()); - - ShardStrategyFactory.setConfiguration(configuration); } @After diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactoryTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactoryTest.java index 3d7276c66c..ed4467df8e 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactoryTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactoryTest.java @@ -10,7 +10,7 @@ package org.opendaylight.controller.cluster.datastore.shardstrategy; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -21,26 +21,25 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; public class ShardStrategyFactoryTest { + ShardStrategyFactory factory; + @Rule public ExpectedException expectedEx = ExpectedException.none(); - @BeforeClass - public static void setUpClass(){ - ShardStrategyFactory.setConfiguration(new ConfigurationImpl("module-shards.conf", "modules.conf")); + @Before + public void setUp() { + factory = new ShardStrategyFactory(new ConfigurationImpl("module-shards.conf", "modules.conf")); } @Test public void testGetStrategy() { - ShardStrategy strategy = - ShardStrategyFactory.getStrategy(TestModel.TEST_PATH); + ShardStrategy strategy = factory.getStrategy(TestModel.TEST_PATH); assertNotNull(strategy); } @Test public void testGetStrategyForKnownModuleName() { - ShardStrategy strategy = - ShardStrategyFactory.getStrategy( - YangInstanceIdentifier.of(CarsModel.BASE_QNAME)); + ShardStrategy strategy = factory.getStrategy(YangInstanceIdentifier.of(CarsModel.BASE_QNAME)); assertTrue(strategy instanceof ModuleShardStrategy); } @@ -50,7 +49,7 @@ public class ShardStrategyFactoryTest { expectedEx.expect(NullPointerException.class); expectedEx.expectMessage("path should not be null"); - ShardStrategyFactory.getStrategy(null); + factory.getStrategy(null); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockConfiguration.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockConfiguration.java index 85df9cbb5d..554e67b1f1 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockConfiguration.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockConfiguration.java @@ -8,7 +8,6 @@ package org.opendaylight.controller.cluster.datastore.utils; -import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; @@ -19,6 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import org.opendaylight.controller.cluster.datastore.config.Configuration; +import org.opendaylight.controller.cluster.datastore.config.ModuleShardConfiguration; import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategy; public class MockConfiguration implements Configuration{ @@ -34,26 +34,22 @@ public class MockConfiguration implements Configuration{ } @Override - public List getMemberShardNames(final String memberName) { + public Collection getMemberShardNames(final String memberName) { return new ArrayList<>(shardMembers.keySet()); } - @Override - public Optional getModuleNameFromNameSpace( - final String nameSpace) { - return Optional.absent(); - } @Override - public Map getModuleNameToShardStrategyMap() { - return Collections.emptyMap(); + public String getModuleNameFromNameSpace(final String nameSpace) { + return null; } - @Override public List getShardNamesFromModuleName( - final String moduleName) { - return Collections.emptyList(); + @Override + public String getShardNameForModule(final String moduleName) { + return null; } - @Override public List getMembersFromShardName(final String shardName) { + @Override + public Collection getMembersFromShardName(final String shardName) { if("default".equals(shardName)) { return Arrays.asList("member-1", "member-2"); } else if("astronauts".equals(shardName)){ @@ -77,4 +73,13 @@ public class MockConfiguration implements Configuration{ return allNames; } + + @Override + public ShardStrategy getStrategyForModule(String moduleName) { + return null; + } + + @Override + public void addModuleShardConfiguration(ModuleShardConfiguration config) { + } }