2 * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.lispflowmapping.inmemorydb;
11 import java.util.AbstractMap.SimpleImmutableEntry;
12 import java.util.Collections;
13 import java.util.HashSet;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import org.opendaylight.lispflowmapping.inmemorydb.radixtrie.RadixTrie;
19 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
20 import org.opendaylight.lispflowmapping.interfaces.dao.IRowVisitor;
21 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
22 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4PrefixBinary;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6PrefixBinary;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 public class HashMapDb implements ILispDAO, AutoCloseable {
31 protected static final Logger LOG = LoggerFactory.getLogger(HashMapDb.class);
32 private static final Object TABLES = (Object) "tables";
33 private ConcurrentMap<Object, ConcurrentMap<String, Object>> data = new ConcurrentHashMap<>();
35 // IPv4 and IPv6 radix tries used for longest prefix matching
36 private RadixTrie<Object> ip4Trie = new RadixTrie<>(32, true);
37 private RadixTrie<Object> ip6Trie = new RadixTrie<>(128, true);
39 private enum GetPrefixMethods {
42 VIRTUAL_PARENT_SIBLING,
46 public void tryAddToIpTrie(Object key) {
47 if (key instanceof Eid) {
49 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
50 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
51 ip4Trie.insert(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength(), key);
52 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
53 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
54 ip6Trie.insert(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength(), key);
60 public void put(Object key, MappingEntry<?>... values) {
61 if (!data.containsKey(key)) {
62 data.put(key, new ConcurrentHashMap<String, Object>());
64 for (MappingEntry<?> entry : values) {
66 data.get(key).put(entry.getKey(), entry.getValue());
71 public Object getSpecific(Object key, String valueKey) {
72 Map<String, Object> keyToValues = data.get(key);
73 if (keyToValues == null) {
76 return keyToValues.get(valueKey);
80 public Map<String, Object> get(Object key) {
84 private RadixTrie<Object>.TrieNode lookupBestNode(Eid eid) {
85 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
86 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
87 return ip4Trie.lookupBest(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
88 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
89 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
90 return ip6Trie.lookupBest(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
96 public Map<String, Object> getBest(Object key) {
97 if (key instanceof Eid) {
99 RadixTrie<Object>.TrieNode node = lookupBestNode(eid);
103 return get(node.data());
109 public SimpleImmutableEntry<Eid, Map<String, ?>> getBestPair(Object key) {
110 Map<String, ?> result = null;
112 if (key instanceof Eid) {
114 RadixTrie<Object>.TrieNode node = lookupBestNode(eid);
117 return (result == null) ? null : new SimpleImmutableEntry<>((Eid)key, result);
119 result = get(node.data());
120 return (result == null) ? null : new SimpleImmutableEntry<>((Eid)node.data(), result);
126 public void getAll(IRowVisitor visitor) {
127 for (ConcurrentMap.Entry<Object, ConcurrentMap<String, Object>> keyEntry : data.entrySet()) {
128 for (Map.Entry<String, Object> valueEntry : keyEntry.getValue().entrySet()) {
129 visitor.visitRow(keyEntry.getKey(), valueEntry.getKey(), valueEntry.getValue());
134 private Eid getPrefix(Eid key, GetPrefixMethods method) {
135 RadixTrie<Object>.TrieNode node = null;
137 if (key.getAddress() instanceof Ipv4PrefixBinary) {
138 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
141 node = ip4Trie.lookupParent(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
144 node = ip4Trie.lookupSibling(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
146 case VIRTUAL_PARENT_SIBLING:
147 node = ip4Trie.lookupVirtualParentSibling(prefix.getIpv4AddressBinary().getValue(),
148 prefix.getIpv4MaskLength());
150 case WIDEST_NEGATIVE:
151 node = ip4Trie.lookupWidestNegative(prefix.getIpv4AddressBinary().getValue(),
152 prefix.getIpv4MaskLength());
159 return LispAddressUtil.asIpv4PrefixBinaryEid(
160 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
162 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
163 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
166 node = ip6Trie.lookupParent(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
169 node = ip6Trie.lookupSibling(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
171 case VIRTUAL_PARENT_SIBLING:
172 node = ip6Trie.lookupVirtualParentSibling(prefix.getIpv6AddressBinary().getValue(),
173 prefix.getIpv6MaskLength());
175 case WIDEST_NEGATIVE:
176 node = ip6Trie.lookupWidestNegative(prefix.getIpv6AddressBinary().getValue(),
177 prefix.getIpv6MaskLength());
184 return LispAddressUtil.asIpv6PrefixBinaryEid(
185 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
192 public Eid getParentPrefix(Eid key) {
193 return getPrefix(key, GetPrefixMethods.PARENT);
197 public Eid getSiblingPrefix(Eid key) {
198 return getPrefix(key, GetPrefixMethods.SIBLING);
202 public Eid getVirtualParentSiblingPrefix(Eid key) {
203 return getPrefix(key, GetPrefixMethods.VIRTUAL_PARENT_SIBLING);
207 public Eid getWidestNegativePrefix(Eid key) {
208 return getPrefix(key, GetPrefixMethods.WIDEST_NEGATIVE);
212 public Set<Eid> getSubtree(Eid key) {
213 Set<RadixTrie<Object>.TrieNode> nodes = null;
214 if (key.getAddress() instanceof Ipv4PrefixBinary) {
215 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
216 nodes = ip4Trie.lookupSubtree(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
217 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
218 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
219 nodes = ip6Trie.lookupSubtree(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
221 return nodesToEids(key, nodes);
224 private static Set<Eid> nodesToEids(Eid key, Set<RadixTrie<Object>.TrieNode> nodes) {
225 if (nodes == null || nodes.isEmpty()) {
226 return Collections.emptySet();
229 Set<Eid> children = new HashSet<>();
230 for (RadixTrie<Object>.TrieNode node : nodes) {
231 if (key.getAddress() instanceof Ipv4PrefixBinary) {
232 children.add(LispAddressUtil.asIpv4PrefixBinaryEid(
233 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
234 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
235 children.add(LispAddressUtil.asIpv6PrefixBinaryEid(
236 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
242 private void tryRemoveFromTrie(Object key) {
243 if (key instanceof Eid) {
245 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
246 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
247 ip4Trie.remove(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
248 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
249 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
250 ip6Trie.remove(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
256 public void remove(Object key) {
257 tryRemoveFromTrie(key);
262 public void removeSpecific(Object key, String valueKey) {
263 Map<String, Object> keyToValues = data.get(key);
264 if (keyToValues == null) {
268 synchronized (keyToValues) {
269 if (keyToValues.containsKey(valueKey)) {
270 keyToValues.remove(valueKey);
271 if (keyToValues.isEmpty()) {
279 public void removeAll() {
285 public void close() throws Exception {
290 public ILispDAO putNestedTable(Object key, String valueKey) {
291 ILispDAO nestedTable = (ILispDAO) getSpecific(key, valueKey);
292 if (nestedTable != null) {
293 LOG.warn("Trying to add nested table that already exists. Aborting!");
296 nestedTable = new HashMapDb();
297 put(key, new MappingEntry<>(valueKey, nestedTable));
302 public ILispDAO putTable(String key) {
303 ILispDAO table = (ILispDAO) getSpecific(TABLES, key);
305 LOG.warn("Trying to add table that already exists. Aborting!");
308 table = new HashMapDb();
309 put(TABLES, new MappingEntry<>(key, table));
314 public boolean isEmpty() {
315 return data.isEmpty();