Checkstyle: fix issues and enforce on inmemorydb
[lispflowmapping.git] / mappingservice / inmemorydb / src / main / java / org / opendaylight / lispflowmapping / inmemorydb / HashMapDb.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.lispflowmapping.inmemorydb;
10
11 import java.util.AbstractMap.SimpleImmutableEntry;
12 import java.util.Date;
13 import java.util.Map;
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;
29
30 public class HashMapDb implements ILispDAO, AutoCloseable {
31
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;
38
39     public HashMapDb() {
40         this.recordTimeOut = DEFAULT_RECORD_TIMEOUT;
41     }
42
43     public HashMapDb(final InmemorydbConfig inmemoryConfig) {
44         if (inmemoryConfig.getRecordTimeout() <= 0) {
45             this.recordTimeOut = DEFAULT_RECORD_TIMEOUT;
46         } else {
47             this.recordTimeOut = inmemoryConfig.getRecordTimeout();
48         }
49     }
50
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);
54
55     public void tryAddToIpTrie(Object key) {
56         if (key instanceof Eid) {
57             Eid eid = (Eid) key;
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);
64             }
65         }
66     }
67
68     @Override
69     public void put(Object key, MappingEntry<?>... values) {
70         if (!data.containsKey(key)) {
71             data.put(key, new ConcurrentHashMap<String, Object>());
72         }
73         for (MappingEntry<?> entry : values) {
74             tryAddToIpTrie(key);
75             data.get(key).put(entry.getKey(), entry.getValue());
76         }
77     }
78
79     @Override
80     public Object getSpecific(Object key, String valueKey) {
81         Map<String, Object> keyToValues = data.get(key);
82         if (keyToValues == null) {
83             return null;
84         }
85         return keyToValues.get(valueKey);
86     }
87
88     @Override
89     public Map<String, Object> get(Object key) {
90         return data.get(key);
91     }
92
93     @Override
94     public Map<String, Object> getBest(Object key) {
95         if (key instanceof Eid) {
96             Eid eid = (Eid) key;
97             RadixTrie<Object>.TrieNode node = null;
98
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());
105             }
106             if (node == null) {
107                 return get(key);
108             }
109             return get(node.data());
110         }
111         return null;
112     }
113
114     @Override
115     public SimpleImmutableEntry<Eid, Map<String, ?>> getBestPair(Object key) {
116         Map<String, ?> data = null;
117
118         if (key instanceof Eid) {
119             Eid eid = (Eid) key;
120             RadixTrie<Object>.TrieNode node = null;
121
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());
128             }
129             if (node == null) {
130                 data = get(key);
131                 return (data == null) ? null : new SimpleImmutableEntry<>((Eid)key, data);
132             }
133             data = get(node.data());
134             return (data == null) ? null : new SimpleImmutableEntry<>((Eid)node.data(), data);
135         }
136         return null;
137     }
138
139     @Override
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());
144             }
145         }
146     }
147
148     @Override
149     public Eid getWidestNegativePrefix(Eid key) {
150         RadixTrie<Object>.TrieNode node = null;
151
152         if (key.getAddress() instanceof Ipv4PrefixBinary) {
153             Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
154             node = ip4Trie.lookupWidestNegative(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
155             if (node != null) {
156                 return LispAddressUtil.asIpv4PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
157             }
158         } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
159             Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
160             node = ip6Trie.lookupWidestNegative(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
161             if (node != null) {
162                 return LispAddressUtil.asIpv6PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
163             }
164         }
165         return null;
166     }
167
168     private void tryRemoveFromTrie(Object key) {
169         if (key instanceof Eid) {
170             Eid eid = (Eid) key;
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());
177             }
178         }
179     }
180
181     @Override
182     public void remove(Object key) {
183         tryRemoveFromTrie(key);
184         data.remove(key);
185     }
186
187     @Override
188     public void removeSpecific(Object key, String valueKey) {
189         if (data.containsKey(key) && data.get(key).containsKey(valueKey)) {
190             data.get(key).remove(valueKey);
191         }
192     }
193
194     @Override
195     public void removeAll() {
196         ip4Trie.removeAll();
197         ip6Trie.removeAll();
198         data.clear();
199     }
200
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);
209                     }
210                 }
211             }
212
213             private boolean isExpired(Date date) {
214                 return System.currentTimeMillis() - date.getTime()
215                         > TimeUnit.MILLISECONDS.convert(recordTimeOut, timeUnit);
216             }
217         });
218     }
219
220     public TimeUnit getTimeUnit() {
221         return timeUnit;
222     }
223
224     public void setRecordTimeOut(int recordTimeOut) {
225         this.recordTimeOut = recordTimeOut;
226     }
227
228     public int getRecordTimeOut() {
229         return recordTimeOut;
230     }
231
232     public void setTimeUnit(TimeUnit timeUnit) {
233         this.timeUnit = timeUnit;
234     }
235
236     public void close() throws Exception {
237         data.clear();
238     }
239
240     @Override
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!");
245             return nestedTable;
246         }
247         nestedTable = new HashMapDb();
248         put(key, new MappingEntry<>(valueKey, nestedTable));
249         return nestedTable;
250     }
251
252     @Override
253     public ILispDAO putTable(String key) {
254         ILispDAO table = (ILispDAO) getSpecific(TABLES, key);
255         if (table != null) {
256             LOG.warn("Trying to add table that already exists. Aborting!");
257             return table;
258         }
259         table = new HashMapDb();
260         put(TABLES, new MappingEntry<>(key, table));
261         return table;
262     }
263 }