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.Date;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ConcurrentMap;
16 import java.util.concurrent.TimeUnit;
17 import org.opendaylight.lispflowmapping.inmemorydb.radixtrie.RadixTrie;
18 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
19 import org.opendaylight.lispflowmapping.interfaces.dao.IRowVisitor;
20 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
21 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
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.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.lfm.mappingservice.dao.inmemorydb.config.rev151007.InmemorydbConfig;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
30 public class HashMapDb implements ILispDAO, AutoCloseable {
32 protected static final Logger LOG = LoggerFactory.getLogger(HashMapDb.class);
33 private static final Object TABLES = (Object) "tables";
34 private static final int DEFAULT_RECORD_TIMEOUT = 240; // SB registered mapping entries time out after 4 min
35 private ConcurrentMap<Object, ConcurrentMap<String, Object>> data = new ConcurrentHashMap<>();
36 private TimeUnit timeUnit = TimeUnit.SECONDS;
37 private int recordTimeOut;
40 this.recordTimeOut = DEFAULT_RECORD_TIMEOUT;
43 public HashMapDb(final InmemorydbConfig inmemoryConfig) {
44 if (inmemoryConfig.getRecordTimeout() <= 0) {
45 this.recordTimeOut = DEFAULT_RECORD_TIMEOUT;
47 this.recordTimeOut = inmemoryConfig.getRecordTimeout();
51 // IPv4 and IPv6 radix tries used for longest prefix matching
52 private RadixTrie<Object> ip4Trie = new RadixTrie<>(32, true);
53 private RadixTrie<Object> ip6Trie = new RadixTrie<>(128, true);
55 public void tryAddToIpTrie(Object key) {
56 if (key instanceof Eid) {
58 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
59 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
60 ip4Trie.insert(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength(), key);
61 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
62 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
63 ip6Trie.insert(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength(), key);
69 public void put(Object key, MappingEntry<?>... values) {
70 if (!data.containsKey(key)) {
71 data.put(key, new ConcurrentHashMap<String, Object>());
73 for (MappingEntry<?> entry : values) {
75 data.get(key).put(entry.getKey(), entry.getValue());
80 public Object getSpecific(Object key, String valueKey) {
81 Map<String, Object> keyToValues = data.get(key);
82 if (keyToValues == null) {
85 return keyToValues.get(valueKey);
89 public Map<String, Object> get(Object key) {
94 public Map<String, Object> getBest(Object key) {
95 if (key instanceof Eid) {
97 RadixTrie<Object>.TrieNode node = null;
99 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
100 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
101 node = ip4Trie.lookupBest(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
102 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
103 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
104 node = ip6Trie.lookupBest(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
109 return get(node.data());
115 public SimpleImmutableEntry<Eid, Map<String, ?>> getBestPair(Object key) {
116 Map<String, ?> data = null;
118 if (key instanceof Eid) {
120 RadixTrie<Object>.TrieNode node = null;
122 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
123 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
124 node = ip4Trie.lookupBest(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
125 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
126 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
127 node = ip6Trie.lookupBest(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
131 return (data == null) ? null : new SimpleImmutableEntry<>((Eid)key, data);
133 data = get(node.data());
134 return (data == null) ? null : new SimpleImmutableEntry<>((Eid)node.data(), data);
140 public void getAll(IRowVisitor visitor) {
141 for (ConcurrentMap.Entry<Object, ConcurrentMap<String, Object>> keyEntry : data.entrySet()) {
142 for (Map.Entry<String, Object> valueEntry : keyEntry.getValue().entrySet()) {
143 visitor.visitRow(keyEntry.getKey(), valueEntry.getKey(), valueEntry.getValue());
149 public Eid getWidestNegativePrefix(Eid key) {
150 RadixTrie<Object>.TrieNode node = null;
152 if (key.getAddress() instanceof Ipv4PrefixBinary) {
153 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
154 node = ip4Trie.lookupWidestNegative(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
156 return LispAddressUtil.asIpv4PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
158 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
159 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
160 node = ip6Trie.lookupWidestNegative(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
162 return LispAddressUtil.asIpv6PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
168 private void tryRemoveFromTrie(Object key) {
169 if (key instanceof Eid) {
171 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
172 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
173 ip4Trie.remove(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
174 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
175 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
176 ip6Trie.remove(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
182 public void remove(Object key) {
183 tryRemoveFromTrie(key);
188 public void removeSpecific(Object key, String valueKey) {
189 if (data.containsKey(key) && data.get(key).containsKey(valueKey)) {
190 data.get(key).remove(valueKey);
195 public void removeAll() {
201 // TODO: this should be moved outside of DAO implementation
202 public void cleanOld() {
203 getAll(new IRowVisitor() {
204 public void visitRow(Object keyId, String valueKey, Object value) {
205 if (value != null && valueKey instanceof String && ((String) valueKey).equals(SubKeys.REGDATE)) {
206 Date date = (Date) value;
207 if (isExpired(date)) {
208 removeSpecific(keyId, SubKeys.RECORD);
213 private boolean isExpired(Date date) {
214 return System.currentTimeMillis() - date.getTime()
215 > TimeUnit.MILLISECONDS.convert(recordTimeOut, timeUnit);
220 public TimeUnit getTimeUnit() {
224 public void setRecordTimeOut(int recordTimeOut) {
225 this.recordTimeOut = recordTimeOut;
228 public int getRecordTimeOut() {
229 return recordTimeOut;
232 public void setTimeUnit(TimeUnit timeUnit) {
233 this.timeUnit = timeUnit;
236 public void close() throws Exception {
241 public ILispDAO putNestedTable(Object key, String valueKey) {
242 ILispDAO nestedTable = (ILispDAO) getSpecific(key, valueKey);
243 if (nestedTable != null) {
244 LOG.warn("Trying to add nested table that already exists. Aborting!");
247 nestedTable = new HashMapDb();
248 put(key, new MappingEntry<>(valueKey, nestedTable));
253 public ILispDAO putTable(String key) {
254 ILispDAO table = (ILispDAO) getSpecific(TABLES, key);
256 LOG.warn("Trying to add table that already exists. Aborting!");
259 table = new HashMapDb();
260 put(TABLES, new MappingEntry<>(key, table));