Bug 4105: Add dynamic module/shard config for entity-owners shard 01/26801/1
authorTom Pantelis <tpanteli@brocade.com>
Tue, 11 Aug 2015 00:08:03 +0000 (20:08 -0400)
committerTom Pantelis <tpanteli@brocade.com>
Thu, 10 Sep 2015 19:17:44 +0000 (15:17 -0400)
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 <tpanteli@brocade.com>
21 files changed:
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/Configuration.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImpl.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/FileModuleShardConfigProvider.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleConfig.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleShardConfigProvider.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ModuleShardConfiguration.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/ShardConfig.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipService.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractTransactionProxyTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/IntegrationTestKit.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipServiceTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategyFactoryTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockConfiguration.java

index 04a8e30..34d5ed0 100644 (file)
@@ -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<L> listenerRegistrationProxy =
index e87fc55..4d3854f 100644 (file)
@@ -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);
index 99d66d5..c24156f 100644 (file)
@@ -657,8 +657,7 @@ public class ShardManager extends AbstractUntypedPersistentActorWithMetering {
      */
     private void createLocalShards() {
         String memberName = this.cluster.getCurrentMemberName();
-        List<String> memberShardNames =
-            this.configuration.getMemberShardNames(memberName);
+        Collection<String> memberShardNames = this.configuration.getMemberShardNames(memberName);
 
         ShardPropsCreator shardPropsCreator = new DefaultShardPropsCreator();
         List<String> localShardActorNames = new ArrayList<>();
index c3a5d07..cdc2ec2 100644 (file)
@@ -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<TransactionIde
         return new ThreePhaseCommitCohortProxy(txContextFactory.getActorContext(), cohortFutures, getIdentifier().toString());
     }
 
-    private static String shardNameFromIdentifier(final YangInstanceIdentifier path) {
-        return ShardStrategyFactory.getStrategy(path).findShard(path);
+    private String shardNameFromIdentifier(final YangInstanceIdentifier path) {
+        return txContextFactory.getActorContext().getShardStrategyFactory().getStrategy(path).findShard(path);
     }
 
     private TransactionContextWrapper getContextWrapper(final YangInstanceIdentifier path) {
index 4319b3a..21801c0 100644 (file)
@@ -8,58 +8,49 @@
 
 package org.opendaylight.controller.cluster.datastore.config;
 
-import com.google.common.base.Optional;
 import java.util.Collection;
-import java.util.List;
-import java.util.Map;
 import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategy;
 
 public interface Configuration {
 
     /**
-     * Given a memberName find all the shards that belong on that member and
-     * return the names of those shards
-     *
-     * @param memberName
-     * @return
+     * Returns all the shard names that belong on the member by the given name.
      */
-    List<String> getMemberShardNames(String memberName);
+    @Nonnull Collection<String> 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<String> 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<String, ShardStrategy> 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<String> getShardNamesFromModuleName(String moduleName);
+    @Nonnull Collection<String> 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<String> getMembersFromShardName(String shardName);
+    @Nullable ShardStrategy getStrategyForModule(@Nonnull String moduleName);
 
     /**
-     *
-     * @return
+     * Returns all the configured shard names.
      */
     Set<String> 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.
      */
index e705a14..2f1e889 100644 (file)
 
 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<ModuleShard> moduleShards;
-
-    private final List<Module> modules;
-
-    private static final Logger
-        LOG = LoggerFactory.getLogger(DistributedDataStore.class);
+    private volatile Map<String, ModuleConfig> moduleConfigMap;
 
     // Look up maps to speed things up
 
-    // key = memberName, value = list of shardNames
-    private final Map<String, List<String>> memberShardNames = new HashMap<>();
-
-    // key = shardName, value = list of replicaNames (replicaNames are the same as memberNames)
-    private final Map<String, List<String>> shardReplicaNames = new HashMap<>();
-
-    private final ListMultimap<String, String> moduleNameToShardName;
-    private final Map<String, ShardStrategy> moduleNameToStrategy;
-    private final Map<String, String> namespaceToModuleName;
-    private final Set<String> allShardNames;
-
-    public ConfigurationImpl(final String moduleShardsConfigPath,
+    private volatile Map<String, String> namespaceToModuleName;
+    private volatile Set<String> 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<String> createAllShardNames(Iterable<ModuleShard> moduleShards) {
-        final com.google.common.collect.ImmutableSet.Builder<String> 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<String, ShardStrategy> createModuleNameToStrategy(Iterable<Module> modules) {
-        final com.google.common.collect.ImmutableMap.Builder<String, ShardStrategy> 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<String, String> createNamespaceToModuleName(Iterable<Module> modules) {
-        final com.google.common.collect.ImmutableMap.Builder<String, String> b = ImmutableMap.builder();
-        for (Module m : modules) {
-            b.put(m.getNameSpace(), m.getName());
+    private static Set<String> createAllShardNames(Iterable<ModuleConfig> moduleConfigs) {
+        final ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+        for(ModuleConfig moduleConfig : moduleConfigs) {
+            builder.addAll(moduleConfig.getShardNames());
         }
-        return b.build();
-    }
 
-    private static ListMultimap<String, String> createModuleNameToShardName(Iterable<ModuleShard> moduleShards) {
-        final com.google.common.collect.ImmutableListMultimap.Builder<String, String> b = ImmutableListMultimap.builder();
+        return builder.build();
+    }
 
-        for (ModuleShard m : moduleShards) {
-            for (Shard s : m.getShards()) {
-                b.put(m.getModuleName(), s.getName());
+    private static Map<String, String> createNamespaceToModuleName(Iterable<ModuleConfig> moduleConfigs) {
+        final ImmutableMap.Builder<String, String> 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<String> getMemberShardNames(final String memberName){
-
+    @Override
+    public Collection<String> getMemberShardNames(final String memberName){
         Preconditions.checkNotNull(memberName, "memberName should not be null");
 
-        if(memberShardNames.containsKey(memberName)){
-            return memberShardNames.get(memberName);
-        }
-
         List<String> 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<String> 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<String, ShardStrategy> 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<String> 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<String> getMembersFromShardName(final String shardName) {
+        ModuleConfig moduleConfig = moduleConfigMap.get(moduleName);
+        Collection<ShardConfig> shardConfigs = moduleConfig != null ? moduleConfig.getShardConfigs() :
+            Collections.<ShardConfig>emptySet();
+        return !shardConfigs.isEmpty() ? shardConfigs.iterator().next().getName(): null;
+    }
 
+    @Override
+    public Collection<String> 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<String> 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.<String>emptyList());
+
         return Collections.emptyList();
     }
 
@@ -204,129 +123,32 @@ public class ConfigurationImpl implements Configuration {
     @Override
     public Collection<String> getUniqueMemberNamesForAllShards() {
         Set<String> allNames = new HashSet<>();
-        for(String shardName: allShardNames) {
+        for(String shardName: getAllShardNames()) {
             allNames.addAll(getMembersFromShardName(shardName));
         }
 
         return allNames;
     }
 
-    private List<Module> readModules(final Config modulesConfig) {
-        List<? extends ConfigObject> modulesConfigObjectList =
-            modulesConfig.getObjectList("modules");
-
-        final Builder<Module> 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<ModuleShard> readModuleShards(final Config moduleShardsConfig) {
-        List<? extends ConfigObject> moduleShardsConfigObjectList =
-            moduleShardsConfig.getObjectList("module-shards");
-
-        final Builder<ModuleShard> b = ImmutableList.builder();
-        for(ConfigObject moduleShardConfigObject : moduleShardsConfigObjectList){
-
-            String moduleName = moduleShardConfigObject.get("name").unwrapped().toString();
-
-            List<? extends ConfigObject> shardsConfigObjectList =
-                moduleShardConfigObject.toConfig().getObjectList("shards");
-
-            List<Shard> shards = new ArrayList<>();
-
-            for(ConfigObject shard : shardsConfigObjectList){
-                String shardName = shard.get("name").unwrapped().toString();
-                List<String> 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<Shard> shards;
-
-        public ModuleShard(final String moduleName, final List<Shard> shards) {
-            this.moduleName = moduleName;
-            this.shards = shards;
-        }
-
-        public String getModuleName() {
-            return moduleName;
-        }
-
-        public List<Shard> getShards() {
-            return shards;
-        }
-    }
-
-    private static class Shard {
-        private final String name;
-        private final List<String> replicas;
-
-        Shard(final String name, final List<String> replicas) {
-            this.name = name;
-            this.replicas = replicas;
-        }
-
-        public String getName() {
-            return name;
-        }
-
-        public List<String> 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.<String, ModuleConfig>builder().putAll(moduleConfigMap).
+                put(config.getModuleName(), moduleConfig).build();
 
-        public ShardStrategy getShardStrategy() {
-            return shardStrategy;
-        }
+        namespaceToModuleName = ImmutableMap.<String, String>builder().putAll(namespaceToModuleName).
+                put(moduleConfig.getNameSpace(), moduleConfig.getName()).build();
+        allShardNames = ImmutableSet.<String>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 (file)
index 0000000..9ceac95
--- /dev/null
@@ -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<String, ModuleConfig> 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<String, ModuleConfig> moduleConfigMap = readModuleShardsConfig(moduleShardsConfig);
+        readModulesConfig(modulesConfig, moduleConfigMap, configuration);
+
+        return moduleConfigMap;
+    }
+
+    private void readModulesConfig(final Config modulesConfig, Map<String, ModuleConfig> moduleConfigMap,
+            Configuration configuration) {
+        List<? extends ConfigObject> 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<String, ModuleConfig> readModuleShardsConfig(final Config moduleShardsConfig) {
+        List<? extends ConfigObject> moduleShardsConfigObjectList =
+            moduleShardsConfig.getObjectList("module-shards");
+
+        Map<String, ModuleConfig> moduleConfigMap = new HashMap<>();
+        for(ConfigObject moduleShardConfigObject : moduleShardsConfigObjectList){
+            String moduleName = moduleShardConfigObject.get("name").unwrapped().toString();
+            ModuleConfig moduleConfig = new ModuleConfig(moduleName);
+
+            List<? extends ConfigObject> shardsConfigObjectList =
+                moduleShardConfigObject.toConfig().getObjectList("shards");
+
+            for(ConfigObject shard : shardsConfigObjectList){
+                String shardName = shard.get("name").unwrapped().toString();
+                List<String> 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 (file)
index 0000000..1a309a0
--- /dev/null
@@ -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<String, ShardConfig> 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<ShardConfig> getShardConfigs() {
+        return shardConfigs.values();
+    }
+
+    public Collection<String> getShardNames() {
+        return shardConfigs.keySet();
+    }
+
+    public void addShardConfig(String name, Set<String> 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 (file)
index 0000000..6ff7081
--- /dev/null
@@ -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<String, ModuleConfig> 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 (file)
index 0000000..e4b88fb
--- /dev/null
@@ -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<String> 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<String> 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<String> 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 (file)
index 0000000..0eb02aa
--- /dev/null
@@ -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<String> replicas;
+
+    public ShardConfig(final String name, final Set<String> replicas) {
+        this.name = name;
+        this.replicas = replicas;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Set<String> getReplicas() {
+        return replicas;
+    }
+}
\ No newline at end of file
index bfdda4c..d6dd9a4 100644 (file)
@@ -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<String> 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<Object> createFuture = datastore.getActorContext().executeOperationAsync(shardManagerActor,
                 createShard, MESSAGE_TIMEOUT);
index 896ebae..26cbc05 100644 (file)
@@ -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<String> 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;
     }
 }
index 7d077b8..1a5a4ac 100644 (file)
@@ -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<String, ShardStrategy> 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<String> 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;
     }
 }
index 2b2487f..bc49288 100644 (file)
@@ -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<Object> doAsk(ActorRef actorRef, Object message, Timeout timeout){
         return ask(actorRef, message, timeout);
     }
index a93666f..f7a364b 100644 (file)
@@ -93,31 +93,33 @@ public abstract class AbstractTransactionProxyTest {
     private static ActorSystem system;
 
     private final Configuration configuration = new MockConfiguration() {
+        Map<String, ShardStrategy> strategyMap = ImmutableMap.<String, ShardStrategy>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<String, ShardStrategy> getModuleNameToShardStrategyMap() {
-            return ImmutableMap.<String, ShardStrategy>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<String> 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.<String>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() {
index 2b2729c..a882ff3 100644 (file)
@@ -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);
 
index 443f017..bcfbeb4 100644 (file)
@@ -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<String> memberShardNames =
-            configuration.getMemberShardNames("member-1");
+        Collection<String> 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<String> members =
-            configuration.getMembersFromShardName("default");
+        Collection<String> 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<String> 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<String> 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<String> 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
index 0776b50..7e2f754 100644 (file)
@@ -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.<String, List<String>>emptyMap()) {
+        Configuration configuration = new ConfigurationImpl(new ModuleShardConfigProvider() {
             @Override
-            public Optional<String> getModuleNameFromNameSpace(String nameSpace) {
-                return Optional.of("entity-owners");
+            public Map<String, ModuleConfig> retrieveModuleConfigs(Configuration configuration) {
+                return Collections.emptyMap();
             }
-
-            @Override
-            public Map<String, ShardStrategy> getModuleNameToShardStrategyMap() {
-                return ImmutableMap.<String, ShardStrategy>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
index 3d7276c..ed4467d 100644 (file)
@@ -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);
     }
 
 }
index 85df9cb..554e67b 100644 (file)
@@ -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<String> getMemberShardNames(final String memberName) {
+    public Collection<String> getMemberShardNames(final String memberName) {
         return new ArrayList<>(shardMembers.keySet());
     }
-    @Override
-    public Optional<String> getModuleNameFromNameSpace(
-        final String nameSpace) {
-        return Optional.absent();
-    }
 
     @Override
-    public Map<String, ShardStrategy> getModuleNameToShardStrategyMap() {
-        return Collections.emptyMap();
+    public String getModuleNameFromNameSpace(final String nameSpace) {
+        return null;
     }
 
-    @Override public List<String> getShardNamesFromModuleName(
-        final String moduleName) {
-        return Collections.emptyList();
+    @Override
+    public String getShardNameForModule(final String moduleName) {
+        return null;
     }
 
-    @Override public List<String> getMembersFromShardName(final String shardName) {
+    @Override
+    public Collection<String> 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) {
+    }
 }