Bug 9116: SMR children of a prefix too
[lispflowmapping.git] / mappingservice / inmemorydb / src / main / java / org / opendaylight / lispflowmapping / inmemorydb / HashMapDb.java
index 7ff803d8d96a1d01e8ebdd8f8af76b75e592d2d3..93f2b377bc9cf1c8458af07420ce64a07e67429b 100644 (file)
@@ -9,7 +9,10 @@
 package org.opendaylight.lispflowmapping.inmemorydb;
 
 import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import org.opendaylight.lispflowmapping.inmemorydb.radixtrie.RadixTrie;
@@ -33,6 +36,14 @@ public class HashMapDb implements ILispDAO, AutoCloseable {
     private RadixTrie<Object> ip4Trie = new RadixTrie<>(32, true);
     private RadixTrie<Object> ip6Trie = new RadixTrie<>(128, true);
 
+    private enum GetPrefixMethods {
+        PARENT,
+        SIBLING,
+        VIRTUAL_PARENT_SIBLING,
+        WIDEST_NEGATIVE,
+        COVERING
+    }
+
     public void tryAddToIpTrie(Object key) {
         if (key instanceof Eid) {
             Eid eid = (Eid) key;
@@ -97,17 +108,17 @@ public class HashMapDb implements ILispDAO, AutoCloseable {
 
     @Override
     public SimpleImmutableEntry<Eid, Map<String, ?>> getBestPair(Object key) {
-        Map<String, ?> data = null;
+        Map<String, ?> result = null;
 
         if (key instanceof Eid) {
             Eid eid = (Eid) key;
             RadixTrie<Object>.TrieNode node = lookupBestNode(eid);
             if (node == null) {
-                data = get(key);
-                return (data == null) ? null : new SimpleImmutableEntry<>((Eid)key, data);
+                result = get(key);
+                return (result == null) ? null : new SimpleImmutableEntry<>((Eid)key, result);
             }
-            data = get(node.data());
-            return (data == null) ? null : new SimpleImmutableEntry<>((Eid)node.data(), data);
+            result = get(node.data());
+            return (result == null) ? null : new SimpleImmutableEntry<>((Eid)node.data(), result);
         }
         return null;
     }
@@ -121,64 +132,125 @@ public class HashMapDb implements ILispDAO, AutoCloseable {
         }
     }
 
-    @Override
-    public Eid getParentPrefix(Eid key) {
+    private Eid getPrefix(Eid key, GetPrefixMethods method) {
         RadixTrie<Object>.TrieNode node = null;
 
         if (key.getAddress() instanceof Ipv4PrefixBinary) {
             Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
-            node = ip4Trie.lookupParent(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
-            if (node != null) {
-                return LispAddressUtil.asIpv4PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
+            switch (method) {
+                case COVERING:
+                    node = ip4Trie.lookupCoveringLessSpecific(prefix.getIpv4AddressBinary().getValue(),
+                            prefix.getIpv4MaskLength());
+                    break;
+                case PARENT:
+                    node = ip4Trie.lookupParent(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
+                    break;
+                case SIBLING:
+                    node = ip4Trie.lookupSibling(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
+                    break;
+                case VIRTUAL_PARENT_SIBLING:
+                    node = ip4Trie.lookupVirtualParentSibling(prefix.getIpv4AddressBinary().getValue(),
+                            prefix.getIpv4MaskLength());
+                    break;
+                case WIDEST_NEGATIVE:
+                    node = ip4Trie.lookupWidestNegative(prefix.getIpv4AddressBinary().getValue(),
+                            prefix.getIpv4MaskLength());
+                    break;
+                default:
+                    node = null;
+                    break;
+            }
+            if (node != null && node.prefix() != null) {
+                return LispAddressUtil.asIpv4PrefixBinaryEid(
+                        key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
             }
         } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
             Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
-            node = ip6Trie.lookupParent(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
-            if (node != null) {
-                return LispAddressUtil.asIpv6PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
+            switch (method) {
+                case COVERING:
+                    node = ip6Trie.lookupCoveringLessSpecific(prefix.getIpv6AddressBinary().getValue(),
+                            prefix.getIpv6MaskLength());
+                    break;
+                case PARENT:
+                    node = ip6Trie.lookupParent(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
+                    break;
+                case SIBLING:
+                    node = ip6Trie.lookupSibling(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
+                    break;
+                case VIRTUAL_PARENT_SIBLING:
+                    node = ip6Trie.lookupVirtualParentSibling(prefix.getIpv6AddressBinary().getValue(),
+                            prefix.getIpv6MaskLength());
+                    break;
+                case WIDEST_NEGATIVE:
+                    node = ip6Trie.lookupWidestNegative(prefix.getIpv6AddressBinary().getValue(),
+                            prefix.getIpv6MaskLength());
+                    break;
+                default:
+                    node = null;
+                    break;
+            }
+            if (node != null && node.prefix() != null) {
+                return LispAddressUtil.asIpv6PrefixBinaryEid(
+                        key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
             }
         }
         return null;
     }
 
+    @Override
+    public Eid getCoveringLessSpecific(Eid key) {
+        return getPrefix(key, GetPrefixMethods.COVERING);
+    }
+
+    @Override
+    public Eid getParentPrefix(Eid key) {
+        return getPrefix(key, GetPrefixMethods.PARENT);
+    }
+
     @Override
     public Eid getSiblingPrefix(Eid key) {
-        RadixTrie<Object>.TrieNode node = null;
+        return getPrefix(key, GetPrefixMethods.SIBLING);
+    }
 
-        if (key.getAddress() instanceof Ipv4PrefixBinary) {
-            Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
-            node = ip4Trie.lookupSibling(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
-            if (node != null) {
-                return LispAddressUtil.asIpv4PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
-            }
-        } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
-            Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
-            node = ip6Trie.lookupSibling(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
-            if (node != null) {
-                return LispAddressUtil.asIpv6PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
-            }
-        }
-        return null;
+    @Override
+    public Eid getVirtualParentSiblingPrefix(Eid key) {
+        return getPrefix(key, GetPrefixMethods.VIRTUAL_PARENT_SIBLING);
     }
 
     @Override
     public Eid getWidestNegativePrefix(Eid key) {
-        RadixTrie<Object>.TrieNode node = null;
+        return getPrefix(key, GetPrefixMethods.WIDEST_NEGATIVE);
+    }
 
+    @Override
+    public Set<Eid> getSubtree(Eid key) {
+        Set<RadixTrie<Object>.TrieNode> nodes = null;
         if (key.getAddress() instanceof Ipv4PrefixBinary) {
             Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
-            node = ip4Trie.lookupWidestNegative(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
-            if (node != null) {
-                return LispAddressUtil.asIpv4PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
-            }
+            nodes = ip4Trie.lookupSubtree(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
         } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
             Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
-            node = ip6Trie.lookupWidestNegative(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
-            if (node != null) {
-                return LispAddressUtil.asIpv6PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
+            nodes = ip6Trie.lookupSubtree(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
+        }
+        return nodesToEids(key, nodes);
+    }
+
+    private static Set<Eid> nodesToEids(Eid key, Set<RadixTrie<Object>.TrieNode> nodes) {
+        if (nodes == null || nodes.isEmpty()) {
+            return Collections.emptySet();
+        }
+
+        Set<Eid> children = new HashSet<>();
+        for (RadixTrie<Object>.TrieNode node : nodes) {
+            if (key.getAddress() instanceof Ipv4PrefixBinary) {
+                children.add(LispAddressUtil.asIpv4PrefixBinaryEid(
+                        key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
+            } else if  (key.getAddress() instanceof Ipv6PrefixBinary) {
+                children.add(LispAddressUtil.asIpv6PrefixBinaryEid(
+                        key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
             }
         }
-        return null;
+        return children;
     }
 
     private void tryRemoveFromTrie(Object key) {
@@ -202,8 +274,18 @@ public class HashMapDb implements ILispDAO, AutoCloseable {
 
     @Override
     public void removeSpecific(Object key, String valueKey) {
-        if (data.containsKey(key) && data.get(key).containsKey(valueKey)) {
-            data.get(key).remove(valueKey);
+        Map<String, Object> keyToValues = data.get(key);
+        if (keyToValues == null) {
+            return;
+        }
+
+        synchronized (keyToValues) {
+            if (keyToValues.containsKey(valueKey)) {
+                keyToValues.remove(valueKey);
+                if (keyToValues.isEmpty()) {
+                    remove(key);
+                }
+            }
         }
     }
 
@@ -241,4 +323,9 @@ public class HashMapDb implements ILispDAO, AutoCloseable {
         put(TABLES, new MappingEntry<>(key, table));
         return table;
     }
+
+    @Override
+    public boolean isEmpty() {
+        return data.isEmpty();
+    }
 }