804a776546dc684bd82c2324aaec4dd2afae3035
[lispflowmapping.git] / mappingservice / inmemorydb / src / main / java / org / opendaylight / lispflowmapping / inmemorydb / radixtrie / RadixTrie.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  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.radixtrie;
10
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.ArrayDeque;
14 import java.util.ArrayList;
15 import java.util.Deque;
16 import java.util.Iterator;
17 import java.util.ListIterator;
18
19 /**
20  * Radix trie/tree (also known as Patricia tree) implementation. Supports CRD operations for
21  * generic, big endian (network byte order) prefixes. It can do exact and longest prefix matchin,
22  * post order iteration over the entries in the tree and can lookup widest negative prefixes (i.e.,
23  * shortest overlapping prefix not registered in the tree).
24  *
25  * @author Florin Coras
26  *
27  * @param <T> Data type stored in each tree node
28  */
29 public class RadixTrie<T> {
30     private int MAXBITS;
31     private TrieNode ROOT;
32     private long nbActiveNodes;
33     private boolean rootZero;
34
35     /**
36      * RadixTrie constructor
37      *
38      * @param bits Maximum prefix length supported.
39      */
40     public RadixTrie(int bits) {
41         MAXBITS = bits;
42         ROOT = null;
43         nbActiveNodes = 0;
44     }
45
46     /**
47      * Radix trie constructors
48      * @param bits Maximum prefix length supported
49      * @param rootZero Flag that decides if 0/0 should be inserted as a non-prefix root node or not
50      */
51     public RadixTrie(int bits, boolean rootZero) {
52         MAXBITS = bits;
53         ROOT = rootZero ? new TrieNode(null, 0, null) : null;
54         nbActiveNodes = 0;
55         this.rootZero = rootZero;
56     }
57
58     public TrieNode getRoot() {
59         return ROOT;
60     }
61
62     private void setRoot(TrieNode root) {
63         ROOT = root;
64     }
65
66     public int getMaxbits() {
67         return MAXBITS;
68     }
69
70     public long getSize() {
71         return nbActiveNodes;
72     }
73
74     /**
75      * Test bit in byte. Assumes bits are numbered from 0 to 7
76      * @param b byte
77      * @param bitPosition the position to be tested
78      * @return 1 if bit at position is 1, 0 otherwise.
79      */
80     private boolean testBitInByte(byte b, int bitPosition) {
81         return (b & (0x80 >> bitPosition)) != 0;
82     }
83
84     private boolean testBitInPrefixByte(byte[] prefix, int bitPosition) {
85         return testBitInByte(prefix[bitPosition / 8], bitPosition & 0x07);
86     }
87
88     /**
89      * Mask prefix
90      * @param prefix Prefix to be masked
91      * @param prefLen Prefix length
92      * @return Prefix after masking
93      */
94     private byte [] maskPrefix(byte[] prefix, int prefLen) {
95         int i;
96         byte[] res = prefix.clone();
97         res[prefLen/8] = (byte) (res[prefLen/8] & (0xFF << (7 - (prefLen & 0x07))));
98         for (i = prefLen/8 + 1; i < MAXBITS/8; i++) {
99             res[i] = 0;
100         }
101         return res;
102     }
103
104     /**
105      * Insert prefix-data tuple into radix trie
106      * @param prefix Big endian (network order) byte array representation of the prefix
107      * @param preflen Prefix length
108      * @param data Data to be stored in the tree
109      * @return Newly inserted TrieNode
110      */
111     public TrieNode insert(byte[] prefix, int preflen, T data) {
112         TrieNode node;
113         int diffbit;
114
115         if (preflen > MAXBITS) {
116             return null;
117         }
118
119         // trie is empty
120         if (ROOT == null) {
121             ROOT = new TrieNode(prefix, preflen, data);
122             return ROOT;
123         }
124
125         // find closest prefix starting at ROOT
126         node = ROOT.findClosest(prefix, preflen);
127
128         // find first different bit
129         diffbit = node.firstDifferentBit(prefix, preflen);
130
131         // find the first node with bit less than diffbit
132         node = node.parentWithBitLessThan(diffbit);
133
134         // insert new prefix
135         return node.insert(prefix, preflen, diffbit, data);
136     }
137
138     /**
139      * Longest prefix match of prefix/preflen
140      * @param prefix Big endian byte array representation of the prefix to be looked up.
141      * @param preflen Prefix length
142      * @return Node with longest prefix match or null if nothing is found.
143      */
144     public TrieNode lookupBest(byte[] prefix, int preflen) {
145         TrieNode node;
146         ArrayList<TrieNode> candidates;
147         ListIterator<TrieNode> it;
148
149         if (ROOT == null || preflen > MAXBITS) {
150             return null;
151         }
152
153         node = ROOT;
154         candidates = new ArrayList<TrieNode>();
155
156         while (node != null && node.bit < preflen) {
157             if (node.prefix != null) {
158                 candidates.add(node);
159             }
160
161             if (testBitInPrefixByte(prefix, node.bit)) {
162                 node = node.right;
163             } else {
164                 node = node.left;
165             }
166         }
167
168         if (node != null && node.prefix != null) {
169             candidates.add(node);
170         }
171
172         it = candidates.listIterator(candidates.size());
173         while (it.hasPrevious()) {
174             node = it.previous();
175             if (node.comparePrefix(prefix)) {
176                 return node;
177             }
178         }
179
180         return null;
181     }
182
183     /**
184      * Lookup widest negative (i.e., overlapping but not present in trie) prefix for given prefix and prefix length
185      * @param prefix Prefix looked up.
186      * @param preflen Prefix length.
187      * @return Node containing the widest negative prefix.
188      */
189     public TrieNode lookupWidestNegative(byte [] prefix, int preflen) {
190         TrieNode node;
191         int diffbit;
192
193         if (ROOT == null || preflen > MAXBITS) {
194             return null;
195         }
196
197         node = ROOT.findClosest(prefix, preflen);
198
199         // not a negative match
200         if (node.prefix != null && node.prefixLength() <= preflen && node.comparePrefix(prefix)) {
201             return null;
202         }
203         diffbit = node.firstDifferentBit(prefix, preflen);
204         return new TrieNode(maskPrefix(prefix, diffbit), diffbit + 1, null);
205     }
206
207     /**
208      * Exact prefix match of prefix/preflen
209      * @param prefix Big endian byte array representation of the prefix to be looked up.
210      * @param preflen Prefix length
211      * @return Node with exact prefix match or null
212      */
213     public TrieNode lookupExact(byte[] prefix, int preflen) {
214         TrieNode node;
215
216         if (ROOT == null || preflen > MAXBITS) {
217             return null;
218         }
219
220         node = ROOT.findClosest(prefix, preflen);
221
222         // if no node is found or if node not a prefix or if mask is too long
223         if (node == null || node.prefix == null || node.bit > preflen) {
224             return null;
225         }
226
227         // check that we have exact match
228         if (node.comparePrefix(prefix)) {
229             return node;
230         }
231
232         return null;
233     }
234
235
236     /**
237      * Remove prefix from radix trie
238      * @param prefix Big endian byte array representation of the prefix to be removed.
239      * @param preflen Prefix length.
240      */
241     public void remove(byte[] prefix, int preflen) {
242         TrieNode node;
243         node = lookupExact(prefix, preflen);
244         if (node != null) {
245             node.erase();
246         }
247     }
248
249     /**
250      * Remove node's subtree
251      * @param node Node who's subtree is to be removed
252      */
253     public void removeSubtree(TrieNode node) {
254         TrieNode itNode;
255         Iterator<TrieNode> it;
256         it = node.iterator();
257
258         while (it.hasNext()) {
259             itNode = it.next();
260             itNode.erase();
261         }
262     }
263
264     /**
265      * Remove subtree for longest match
266      * @param prefix Prefix to be looked up
267      * @param preflen Prefix length
268      */
269     public void removeSubtree(byte[] prefix, int preflen) {
270         TrieNode itNode;
271         Iterator<TrieNode> it;
272
273         itNode = lookupBest(prefix, preflen);
274
275         if (itNode == null) {
276             return;
277         }
278
279         it = itNode.iterator();
280
281         while (it.hasNext()) {
282             itNode = it.next();
283             itNode.erase();
284         }
285     }
286
287     /**
288      * Remove all entries in the trie.
289      */
290     public void removeAll() {
291         TrieNode node;
292         Iterator<TrieNode> it;
293
294         it = ROOT.iterator();
295         while (it.hasNext()) {
296             node = it.next();
297             node.erase();
298         }
299     }
300
301     /**
302      * Trie node definition.
303      *
304      */
305     public class TrieNode implements Iterable<TrieNode>{
306         // since bits are counted from 0, bit and prefix length are equal
307         int bit;
308         byte[] prefix;
309         TrieNode left, right;
310         TrieNode up;
311         T data;
312
313         TrieNode(byte[] prefix, int prefixlen, T data) {
314             this.bit = prefixlen;
315             this.prefix = prefix;
316             this.data = data;
317             left = right = null;
318         }
319
320         public byte[] prefix() {
321             return prefix;
322         }
323
324         public int prefixLength() {
325             return bit;
326         }
327
328         public T data() {
329             return data;
330         }
331
332         /**
333          * Finds closest prefix NOT the longest prefix match
334          * @param prefix Searched prefix
335          * @param preflen Searched prefix length
336          * @return The node found
337          */
338         public TrieNode findClosest(byte[] prefix, int preflen) {
339             TrieNode node = this;
340
341             while (node.prefix == null || node.bit < preflen) {
342                 if (testBitInPrefixByte(prefix, node.bit)) {
343                     if (node.right == null) {
344                         break;
345                     }
346                     node = node.right;
347                 } else {
348                     if (node.left == null) {
349                         break;
350                     }
351                     node = node.left;
352                 }
353             }
354             return node;
355         }
356
357         /**
358          * Compares prefix to node's prefix and returns position of first different bit
359          * @param prefix Prefix to be compared.
360          * @param preflen Prefix length.
361          * @return Position of first different bit.
362          */
363         public int firstDifferentBit(byte[] prefix, int preflen) {
364             int maxbit, diffbit, i;
365             byte bitxor;
366
367             maxbit = (bit < preflen) ? bit : preflen;
368             diffbit = 0;
369             for (i = 0; i * 8 < maxbit; i++) {
370                 // if match, move to next byte
371                 if ((bitxor = (byte) (this.prefix[i] ^ prefix[i])) == 0) {
372                     diffbit = (i+1) * 8;
373                     continue;
374                 }
375                 // if not matched, find first diff bit (0 to 7)
376                 diffbit = i * 8 + Integer.numberOfLeadingZeros(bitxor) - 24;
377                 diffbit = (diffbit > maxbit) ? maxbit : diffbit;
378                 break;
379             }
380
381             return diffbit;
382         }
383
384         /**
385          * Find parent with bit less than given value
386          * @param bitlen Bit value
387          * @return Parent with bit less than given value
388          */
389         public TrieNode parentWithBitLessThan(int bitlen) {
390             TrieNode node, parent;
391             node = this;
392             parent = node.up;
393             while (parent != null && parent.bit >= bitlen) {
394                 node = parent;
395                 parent = node.up;
396             }
397             return node;
398         }
399
400         /**
401          * Inserts node in trie near this node with prefix that has the first bit difference at diffbit
402          * @param pref Prefix to be inserted.
403          * @param preflen Prefix length of the prefix to be inserted.
404          * @param diffbit Bit index of the first different bit between prefix and current node
405          * @param data Data to be stored together with the prefix
406          * @return The trie node created or current node if it's an overwrite.
407          */
408         public TrieNode insert(byte[] pref, int preflen, int diffbit, T data) {
409             TrieNode parent, newNode;
410
411             // same node, check if prefix needs saving
412             if (diffbit == preflen && bit == preflen) {
413                 if (prefix != null) {
414                     return this;
415                 }
416                 this.prefix = pref;
417                 this.data = data;
418                 nbActiveNodes++;
419                 return this;
420             }
421
422             newNode = new TrieNode(pref, preflen, data);
423
424             // node is more specific, add new prefix as parent
425             if (preflen == diffbit) {
426                 if (testBitInPrefixByte(pref, preflen)) {
427                     newNode.right = this;
428                 } else {
429                     newNode.left = this;
430                 }
431                 newNode.up = up;
432
433                 if (up == null) {
434                     setRoot(newNode);
435                 } else if (this.equals(up.right)) {
436                     up.right = newNode;
437                 } else {
438                     up.left = newNode;
439                 }
440
441                 up = newNode;
442             // new prefix is more specific than node, add as child
443             } else if (bit == diffbit) {
444                 newNode.up = this;
445                 if (testBitInPrefixByte(pref, bit)) {
446                     right = newNode;
447                 } else {
448                     left = newNode;
449                 }
450             // new prefix is a sibling of/on a different branch from node, add common parent
451             } else {
452                 parent = new TrieNode(null, diffbit, null);
453                 parent.up = up;
454                 if (testBitInPrefixByte(pref, diffbit)) {
455                     parent.right = newNode;
456                     parent.left = this;
457                 } else {
458                     parent.right = this;
459                     parent.left = newNode;
460                 }
461                 newNode.up = parent;
462                 if (up == null) {
463                     setRoot(parent);
464                 } else if (this.equals(up.right)) {
465                     up.right = parent;
466                 } else {
467                     up.left = parent;
468                 }
469                 up = parent;
470             }
471             nbActiveNodes++;
472             return newNode;
473         }
474
475         /**
476          * Erase node
477          */
478         public void erase () {
479             TrieNode cur = this, child, parent;
480             boolean isRoot = false;
481
482             if (this.equals(ROOT)) {
483                 isRoot = true;
484             }
485
486             if (prefix != null) {
487                 resetData();
488             }
489
490             // as long as one of the children is null and this is an intermediary node
491             // link parent to child. If parent null, child becomes the root.
492             while (cur != null && cur.prefix == null && (cur.left == null || cur.right == null)) {
493                 parent = cur.up;
494                 child = cur.left != null ? cur.left : cur.right;
495
496                 if (parent == null) {
497                     setRoot(child);
498                 } else {
499                     if (parent.left != null && parent.left.equals(cur)) {
500                         parent.left = child;
501                     } else {
502                         parent.right = child;
503                     }
504                     if (child != null) {
505                         child.up = parent;
506                     }
507                 }
508
509                 cur.resetData();
510                 cur = parent;
511             }
512
513             if (isRoot) {
514                 setRoot((rootZero ? new TrieNode(null, 0, null) : null));
515             }
516
517             nbActiveNodes--;
518         }
519
520         /**
521          * Clear node data
522          */
523         public void resetData () {
524             prefix = null;
525             data = null;
526         }
527
528         /**
529          * Compare node prefix with prefix
530          * @param pref Prefix to be compared
531          * @return True if prefixes are equal, false otherwise
532          */
533         public boolean comparePrefix(byte[] pref) {
534             int i, mask, r;
535
536             for (i = 0; i < bit/8; i++) {
537                if (prefix[i] != pref[i]) {
538                    return false;
539                }
540             }
541             if ((r = bit % 8) != 0) {
542                 mask = (0xFF << r) & 0xFF;
543                 return ((prefix[i] & mask) == (pref[i] & mask));
544             }
545             return true;
546         }
547
548         /**
549          * Helper method that converts prefix and prefix length to dotted decimal, string, representation.
550          * @return String representation of prefix.
551          */
552         public String asIpPrefix() {
553             try {
554                 return InetAddress.getByAddress(prefix).getHostAddress() + "/" + bit;
555             } catch (UnknownHostException e) {
556                 return "NaA/"+bit;
557             }
558         }
559
560         /**
561          * Retrieve iterator.
562          */
563         @Override
564         public Iterator<RadixTrie<T>.TrieNode> iterator() {
565             return new TriePostOrderIterator(this);
566         }
567
568         /**
569          * Post order iterator implementation for prefix trie. It's safe to use it to remove nodes
570          *
571          */
572         private class TriePostOrderIterator implements Iterator<RadixTrie<T>.TrieNode> {
573             private TrieNode current, lastNodeVisited;
574             private Deque<RadixTrie<T>.TrieNode> stack;
575
576             TriePostOrderIterator(TrieNode node) {
577                 stack = new ArrayDeque<RadixTrie<T>.TrieNode>();
578                 current = node;
579                 lastNodeVisited = null;
580             }
581
582             @Override
583             public boolean hasNext() {
584                 TrieNode peekNode, last = lastNodeVisited;
585                 if (current != null && (current.left != null || current.right != null)) {
586                     return true;
587                 } else {
588                     Iterator<TrieNode> it = stack.iterator();
589                     while (it.hasNext()) {
590                         peekNode = it.next();
591                         if (peekNode.right != null && !peekNode.right.equals(last)) {
592                             return true;
593                         } else {
594                             last = peekNode;
595                             if (peekNode.prefix != null) {
596                                 return true;
597                             }
598                         }
599                     }
600                 }
601                 return false;
602             }
603
604             @Override
605             public RadixTrie<T>.TrieNode next() {
606                 TrieNode peekNode;
607                 TrieNode next = current;
608                 while (!stack.isEmpty() || next != null) {
609                     if (next != null) {
610                         stack.push(next);
611                         next = next.left;
612                     } else {
613                         peekNode = stack.peek();
614                         if (peekNode.right != null && !peekNode.right.equals(lastNodeVisited)) {
615                             next = peekNode.right;
616                         } else {
617                             lastNodeVisited = stack.pop();
618                             if (peekNode.prefix != null) {
619                                 current = null;
620                                 return peekNode;
621                             }
622                         }
623                     }
624                 }
625                 return null;
626             }
627         }
628     }
629 }