Fix followerDistributedDataStore tear down
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / config / ConfigurationImpl.java
index e705a142f2cead1f0672fd66611d716a96a1f803..d0e8d875f65d4ba1f765a969c85107c156c3f5bc 100644 (file)
  * 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.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 static java.util.Objects.requireNonNull;
+
 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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 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.Map.Entry;
 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.access.concepts.MemberName;
 import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory;
 
+// FIXME: Non-final for testing
 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,
-
-        final String modulesConfigPath){
-
-        Preconditions.checkNotNull(moduleShardsConfigPath, "moduleShardsConfigPath should not be null");
-        Preconditions.checkNotNull(modulesConfigPath, "modulesConfigPath should not be null");
+    private volatile Map<String, String> namespaceToModuleName;
+    private volatile Set<String> allShardNames;
 
+    public ConfigurationImpl(final String moduleShardsConfigPath, final String modulesConfigPath) {
+        this(new FileModuleShardConfigProvider(moduleShardsConfigPath, modulesConfigPath));
+    }
 
-        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);
+    @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR", justification = "Subclassed for testing")
+    public ConfigurationImpl(final ModuleShardConfigProvider provider) {
+        ImmutableMap.Builder<String, ModuleConfig> mapBuilder = ImmutableMap.builder();
+        for (Entry<String, ModuleConfig.Builder> e: provider.retrieveModuleConfigs(this).entrySet()) {
+            mapBuilder.put(e.getKey(), e.getValue().build());
         }
 
-        this.moduleShards = readModuleShards(moduleShardsConfig);
-        this.modules = readModules(modulesConfig);
-
-        this.allShardNames = createAllShardNames(moduleShards);
-        this.moduleNameToShardName = createModuleNameToShardName(moduleShards);
-        this.moduleNameToStrategy = createModuleNameToStrategy(modules);
-        this.namespaceToModuleName = createNamespaceToModuleName(modules);
-    }
+        moduleConfigMap = mapBuilder.build();
 
-    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();
+        allShardNames = createAllShardNames(moduleConfigMap.values());
+        namespaceToModuleName = createNamespaceToModuleName(moduleConfigMap.values());
     }
 
-    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());
+    private static Set<String> createAllShardNames(final Iterable<ModuleConfig> moduleConfigs) {
+        final ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+        for (ModuleConfig moduleConfig : moduleConfigs) {
+            builder.addAll(moduleConfig.getShardNames());
         }
-        return b.build();
-    }
 
-    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());
-        }
-        return b.build();
+        return builder.build();
     }
 
-    private static ListMultimap<String, String> createModuleNameToShardName(Iterable<ModuleShard> moduleShards) {
-        final com.google.common.collect.ImmutableListMultimap.Builder<String, String> b = ImmutableListMultimap.builder();
-
-        for (ModuleShard m : moduleShards) {
-            for (Shard s : m.getShards()) {
-                b.put(m.getModuleName(), s.getName());
+    private static Map<String, String> createNamespaceToModuleName(final 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){
-
-        Preconditions.checkNotNull(memberName, "memberName should not be null");
-
-        if(memberShardNames.containsKey(memberName)){
-            return memberShardNames.get(memberName);
-        }
+    @Override
+    public Collection<String> getMemberShardNames(final MemberName memberName) {
+        requireNonNull(memberName, "memberName should not be null");
 
         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) {
-        Preconditions.checkNotNull(nameSpace, "nameSpace should not be null");
-        return Optional.fromNullable(namespaceToModuleName.get(nameSpace));
+    public String getModuleNameFromNameSpace(final String nameSpace) {
+        return namespaceToModuleName.get(requireNonNull(nameSpace, "nameSpace should not be null"));
     }
 
     @Override
-    public Map<String, ShardStrategy> getModuleNameToShardStrategyMap() {
-        return moduleNameToStrategy;
+    public ShardStrategy getStrategyForModule(final String moduleName) {
+        ModuleConfig moduleConfig = getModuleConfig(moduleName);
+        return moduleConfig != null ? moduleConfig.getShardStrategy() : null;
     }
 
     @Override
-    public List<String> getShardNamesFromModuleName(final String moduleName) {
-        Preconditions.checkNotNull(moduleName, "moduleName should not be null");
-        return moduleNameToShardName.get(moduleName);
+    public String getShardNameForModule(final String moduleName) {
+        ModuleConfig moduleConfig = getModuleConfig(moduleName);
+        if (moduleConfig != null) {
+            Collection<ShardConfig> shardConfigs = moduleConfig.getShardConfigs();
+            if (!shardConfigs.isEmpty()) {
+                return shardConfigs.iterator().next().getName();
+            }
+        }
+        return null;
     }
 
-    @Override public List<String> getMembersFromShardName(final String shardName) {
-
-        Preconditions.checkNotNull(shardName, "shardName should not be null");
+    private ModuleConfig getModuleConfig(final String moduleName) {
+        return moduleConfigMap.get(requireNonNull(moduleName, "moduleName should not be null"));
+    }
 
-        if(shardReplicaNames.containsKey(shardName)){
-            return shardReplicaNames.get(shardName);
-        }
+    @Override
+    public Collection<MemberName> getMembersFromShardName(final String shardName) {
+        checkNotNullShardName(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();
+
+        return List.of();
+    }
+
+    private static void checkNotNullShardName(final String shardName) {
+        requireNonNull(shardName, "shardName should not be null");
     }
 
     @Override
@@ -202,131 +137,76 @@ public class ConfigurationImpl implements Configuration {
     }
 
     @Override
-    public Collection<String> getUniqueMemberNamesForAllShards() {
-        Set<String> allNames = new HashSet<>();
-        for(String shardName: allShardNames) {
+    public Collection<MemberName> getUniqueMemberNamesForAllShards() {
+        Set<MemberName> allNames = new HashSet<>();
+        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");
+    @Override
+    public synchronized void addModuleShardConfiguration(final ModuleShardConfiguration config) {
+        requireNonNull(config, "ModuleShardConfiguration should not be null");
 
-            List<Shard> shards = new ArrayList<>();
+        ModuleConfig moduleConfig = ModuleConfig.builder(config.getModuleName())
+                .nameSpace(config.getNamespace().toString())
+                .shardStrategy(createShardStrategy(config.getModuleName(), config.getShardStrategyName()))
+                .shardConfig(config.getShardName(), config.getShardMemberNames()).build();
 
-            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));
-        }
+        updateModuleConfigMap(moduleConfig);
 
-        return b.build();
+        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 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 ShardStrategy createShardStrategy(final String moduleName, final String shardStrategyName) {
+        return ShardStrategyFactory.newShardStrategyInstance(moduleName, shardStrategyName, this);
     }
 
-    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;
-        }
+    @Override
+    public boolean isShardConfigured(final String shardName) {
+        checkNotNullShardName(shardName);
+        return allShardNames.contains(shardName);
     }
 
-    private class Module {
-
-        private final String name;
-        private final String nameSpace;
-        private final ShardStrategy shardStrategy;
-
-        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();
+    @Override
+    public void addMemberReplicaForShard(final String shardName, final MemberName newMemberName) {
+        checkNotNullShardName(shardName);
+        requireNonNull(newMemberName, "MemberName should not be null");
+
+        for (ModuleConfig moduleConfig: moduleConfigMap.values()) {
+            ShardConfig shardConfig = moduleConfig.getShardConfig(shardName);
+            if (shardConfig != null) {
+                Set<MemberName> replicas = new HashSet<>(shardConfig.getReplicas());
+                replicas.add(newMemberName);
+                updateModuleConfigMap(ModuleConfig.builder(moduleConfig).shardConfig(shardName, replicas).build());
+                return;
             }
         }
-
-        public String getName() {
-            return name;
-        }
-
-        public String getNameSpace() {
-            return nameSpace;
-        }
-
-        public ShardStrategy getShardStrategy() {
-            return shardStrategy;
-        }
     }
 
-
-    private static class ConfigObjectWrapper{
-
-        private final ConfigObject configObject;
-
-        ConfigObjectWrapper(final ConfigObject configObject){
-            this.configObject = configObject;
+    @Override
+    public void removeMemberReplicaForShard(final String shardName, final MemberName newMemberName) {
+        checkNotNullShardName(shardName);
+        requireNonNull(newMemberName, "MemberName should not be null");
+
+        for (ModuleConfig moduleConfig: moduleConfigMap.values()) {
+            ShardConfig shardConfig = moduleConfig.getShardConfig(shardName);
+            if (shardConfig != null) {
+                Set<MemberName> replicas = new HashSet<>(shardConfig.getReplicas());
+                replicas.remove(newMemberName);
+                updateModuleConfigMap(ModuleConfig.builder(moduleConfig).shardConfig(shardName, replicas).build());
+                return;
+            }
         }
+    }
 
-        public String stringValue(final String name){
-            return configObject.get(name).unwrapped().toString();
-        }
+    private void updateModuleConfigMap(final ModuleConfig moduleConfig) {
+        final Map<String, ModuleConfig> newModuleConfigMap = new HashMap<>(moduleConfigMap);
+        newModuleConfigMap.put(moduleConfig.getName(), moduleConfig);
+        moduleConfigMap = ImmutableMap.copyOf(newModuleConfigMap);
     }
 }