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,
47 public void tryAddToIpTrie(Object key) {
48 if (key instanceof Eid) {
50 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
51 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
52 ip4Trie.insert(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength().toJava(), key);
53 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
54 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
55 ip6Trie.insert(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength().toJava(), key);
61 public void put(Object key, MappingEntry<?>... values) {
62 if (!data.containsKey(key)) {
63 data.put(key, new ConcurrentHashMap<String, Object>());
65 for (MappingEntry<?> entry : values) {
67 data.get(key).put(entry.getKey(), entry.getValue());
72 public Object getSpecific(Object key, String valueKey) {
73 Map<String, Object> keyToValues = data.get(key);
74 if (keyToValues == null) {
77 return keyToValues.get(valueKey);
81 public Map<String, Object> get(Object key) {
85 private RadixTrie<Object>.TrieNode lookupBestNode(Eid eid) {
86 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
87 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
88 return ip4Trie.lookupBest(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength().toJava());
89 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
90 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
91 return ip6Trie.lookupBest(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength().toJava());
97 public Map<String, Object> getBest(Object key) {
98 if (key instanceof Eid) {
100 RadixTrie<Object>.TrieNode node = lookupBestNode(eid);
104 return get(node.data());
110 public SimpleImmutableEntry<Eid, Map<String, ?>> getBestPair(Object key) {
111 Map<String, ?> result = null;
113 if (key instanceof Eid) {
115 RadixTrie<Object>.TrieNode node = lookupBestNode(eid);
118 return (result == null) ? null : new SimpleImmutableEntry<>((Eid)key, result);
120 result = get(node.data());
121 return (result == null) ? null : new SimpleImmutableEntry<>((Eid)node.data(), result);
127 public void getAll(IRowVisitor visitor) {
128 for (ConcurrentMap.Entry<Object, ConcurrentMap<String, Object>> keyEntry : data.entrySet()) {
129 for (Map.Entry<String, Object> valueEntry : keyEntry.getValue().entrySet()) {
130 visitor.visitRow(keyEntry.getKey(), valueEntry.getKey(), valueEntry.getValue());
135 private Eid getPrefix(Eid key, GetPrefixMethods method) {
136 RadixTrie<Object>.TrieNode node = null;
138 if (key.getAddress() instanceof Ipv4PrefixBinary) {
139 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
142 node = ip4Trie.lookupCoveringLessSpecific(prefix.getIpv4AddressBinary().getValue(),
143 prefix.getIpv4MaskLength().toJava());
146 node = ip4Trie.lookupParent(prefix.getIpv4AddressBinary().getValue(),
147 prefix.getIpv4MaskLength().toJava());
150 node = ip4Trie.lookupSibling(prefix.getIpv4AddressBinary().getValue(),
151 prefix.getIpv4MaskLength().toJava());
153 case VIRTUAL_PARENT_SIBLING:
154 node = ip4Trie.lookupVirtualParentSibling(prefix.getIpv4AddressBinary().getValue(),
155 prefix.getIpv4MaskLength().toJava());
157 case WIDEST_NEGATIVE:
158 node = ip4Trie.lookupWidestNegative(prefix.getIpv4AddressBinary().getValue(),
159 prefix.getIpv4MaskLength().toJava());
165 if (node != null && node.prefix() != null) {
166 return LispAddressUtil.asIpv4PrefixBinaryEid(
167 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
169 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
170 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
173 node = ip6Trie.lookupCoveringLessSpecific(prefix.getIpv6AddressBinary().getValue(),
174 prefix.getIpv6MaskLength().toJava());
177 node = ip6Trie.lookupParent(prefix.getIpv6AddressBinary().getValue(),
178 prefix.getIpv6MaskLength().toJava());
181 node = ip6Trie.lookupSibling(prefix.getIpv6AddressBinary().getValue(),
182 prefix.getIpv6MaskLength().toJava());
184 case VIRTUAL_PARENT_SIBLING:
185 node = ip6Trie.lookupVirtualParentSibling(prefix.getIpv6AddressBinary().getValue(),
186 prefix.getIpv6MaskLength().toJava());
188 case WIDEST_NEGATIVE:
189 node = ip6Trie.lookupWidestNegative(prefix.getIpv6AddressBinary().getValue(),
190 prefix.getIpv6MaskLength().toJava());
196 if (node != null && node.prefix() != null) {
197 return LispAddressUtil.asIpv6PrefixBinaryEid(
198 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
205 public Eid getCoveringLessSpecific(Eid key) {
206 return getPrefix(key, GetPrefixMethods.COVERING);
210 public Eid getParentPrefix(Eid key) {
211 return getPrefix(key, GetPrefixMethods.PARENT);
215 public Eid getSiblingPrefix(Eid key) {
216 return getPrefix(key, GetPrefixMethods.SIBLING);
220 public Eid getVirtualParentSiblingPrefix(Eid key) {
221 return getPrefix(key, GetPrefixMethods.VIRTUAL_PARENT_SIBLING);
225 public Eid getWidestNegativePrefix(Eid key) {
226 return getPrefix(key, GetPrefixMethods.WIDEST_NEGATIVE);
230 public Set<Eid> getSubtree(Eid key) {
231 Set<RadixTrie<Object>.TrieNode> nodes = null;
232 if (key.getAddress() instanceof Ipv4PrefixBinary) {
233 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
234 nodes = ip4Trie.lookupSubtree(prefix.getIpv4AddressBinary().getValue(),
235 prefix.getIpv4MaskLength().toJava());
236 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
237 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
238 nodes = ip6Trie.lookupSubtree(prefix.getIpv6AddressBinary().getValue(),
239 prefix.getIpv6MaskLength().toJava());
241 return nodesToEids(key, nodes);
244 private static Set<Eid> nodesToEids(Eid key, Set<RadixTrie<Object>.TrieNode> nodes) {
245 if (nodes == null || nodes.isEmpty()) {
246 return Collections.emptySet();
249 Set<Eid> children = new HashSet<>();
250 for (RadixTrie<Object>.TrieNode node : nodes) {
251 if (key.getAddress() instanceof Ipv4PrefixBinary) {
252 children.add(LispAddressUtil.asIpv4PrefixBinaryEid(
253 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
254 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
255 children.add(LispAddressUtil.asIpv6PrefixBinaryEid(
256 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
262 private void tryRemoveFromTrie(Object key) {
263 if (key instanceof Eid) {
265 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
266 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
267 ip4Trie.remove(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength().toJava());
268 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
269 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
270 ip6Trie.remove(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength().toJava());
276 public void remove(Object key) {
277 tryRemoveFromTrie(key);
282 public void removeSpecific(Object key, String valueKey) {
283 Map<String, Object> keyToValues = data.get(key);
284 if (keyToValues == null) {
288 synchronized (keyToValues) {
289 if (keyToValues.containsKey(valueKey)) {
290 keyToValues.remove(valueKey);
291 if (keyToValues.isEmpty()) {
299 public void removeAll() {
305 public void close() throws Exception {
310 public ILispDAO putNestedTable(Object key, String valueKey) {
311 ILispDAO nestedTable = (ILispDAO) getSpecific(key, valueKey);
312 if (nestedTable != null) {
313 LOG.warn("Trying to add nested table that already exists. Aborting!");
316 nestedTable = new HashMapDb();
317 put(key, new MappingEntry<>(valueKey, nestedTable));
322 public ILispDAO putTable(String key) {
323 ILispDAO table = (ILispDAO) getSpecific(TABLES, key);
325 LOG.warn("Trying to add table that already exists. Aborting!");
328 table = new HashMapDb();
329 put(TABLES, new MappingEntry<>(key, table));
334 public boolean isEmpty() {
335 return data.isEmpty();