blob: 7f9a0090e11d0a3da3778614ae274dcf8a70e0e8 [file] [log] [blame]
Jonathan Hart382623d2014-04-03 09:48:11 -07001package net.onrc.onos.apps.bgproute;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hart66dffed2013-07-16 11:36:00 +12003/*
4 * TODO This Ptree needs to be refactored if we're going to use it permenantly.
5 *
6 * The biggest problem is it leaks PTreeNode references - these need to stay within
7 * the Ptree as they contain data fundamental to the structure of the tree.
8 * You should put RIB entries in and get RIB entries out.
9 * Also we need to get rid of the referencing scheme to determine when to delete nodes.
Ray Milkey5d406012014-04-08 14:44:41 -070010 * Deletes should be explicit, and there's no need to keep track of references if
Jonathan Hart66dffed2013-07-16 11:36:00 +120011 * we don't leak them out the the Ptree.
12 */
pingping-lina2cbfad2013-03-07 08:39:21 +080013public class Ptree {
Ray Milkey269ffb92014-04-03 14:43:30 -070014 private int maxKeyBits;
15 private int maxKeyOctets;
16 //private int refCount;
17 private PtreeNode top;
Ray Milkey45614c52014-04-07 16:30:54 -070018 private byte[] maskBits = {(byte) 0x00, (byte) 0x80, (byte) 0xc0, (byte) 0xe0, (byte) 0xf0, (byte) 0xf8, (byte) 0xfc, (byte) 0xfe, (byte) 0xff};
pingping-lina2cbfad2013-03-07 08:39:21 +080019
Ray Milkey269ffb92014-04-03 14:43:30 -070020 public Ptree(int max_key_bits) {
21 maxKeyBits = max_key_bits;
22 maxKeyOctets = bit_to_octet(max_key_bits);
23 //refCount = 0;
24 }
pingping-lina2cbfad2013-03-07 08:39:21 +080025
Ray Milkey269ffb92014-04-03 14:43:30 -070026 public synchronized PtreeNode acquire(byte[] key) {
27 return acquire(key, maxKeyBits);
28 }
pingping-lina2cbfad2013-03-07 08:39:21 +080029
Ray Milkey269ffb92014-04-03 14:43:30 -070030 public synchronized PtreeNode acquire(byte[] key, int key_bits) {
31 if (key_bits > maxKeyBits) {
32 return null;
33 }
pingping-lina2cbfad2013-03-07 08:39:21 +080034
Ray Milkey269ffb92014-04-03 14:43:30 -070035 PtreeNode node = top;
36 PtreeNode match = null;
pingping-lina2cbfad2013-03-07 08:39:21 +080037
Ray Milkey269ffb92014-04-03 14:43:30 -070038 while (node != null
39 && node.keyBits <= key_bits
40 && key_match(node.key, node.keyBits, key, key_bits) == true) {
41 if (node.keyBits == key_bits) {
42 return addReference(node);
43 }
pingping-lina2cbfad2013-03-07 08:39:21 +080044
Ray Milkey269ffb92014-04-03 14:43:30 -070045 match = node;
pingping-lina2cbfad2013-03-07 08:39:21 +080046
Ray Milkey269ffb92014-04-03 14:43:30 -070047 if (bit_check(key, node.keyBits) == true) {
48 node = node.right;
49 } else {
50 node = node.left;
51 }
52 }
pingping-lina2cbfad2013-03-07 08:39:21 +080053
Ray Milkey269ffb92014-04-03 14:43:30 -070054 PtreeNode add = null;
pingping-lina2cbfad2013-03-07 08:39:21 +080055
Ray Milkey269ffb92014-04-03 14:43:30 -070056 if (node == null) {
57 add = new PtreeNode(key, key_bits, maxKeyOctets);
pingping-lina2cbfad2013-03-07 08:39:21 +080058
Ray Milkey269ffb92014-04-03 14:43:30 -070059 if (match != null) {
60 node_link(match, add);
61 } else {
62 top = add;
63 }
64 } else {
65 add = node_common(node, key, key_bits);
pingping-lina2cbfad2013-03-07 08:39:21 +080066
Ray Milkey269ffb92014-04-03 14:43:30 -070067 if (match != null) {
68 node_link(match, add);
69 } else {
70 top = add;
71 }
72 node_link(add, node);
pingping-lina2cbfad2013-03-07 08:39:21 +080073
Ray Milkey269ffb92014-04-03 14:43:30 -070074 if (add.keyBits != key_bits) {
75 match = add;
76
77 add = new PtreeNode(key, key_bits, maxKeyOctets);
78 node_link(match, add);
79 }
80 }
81
82 return addReference(add);
83 }
84
85 public synchronized PtreeNode lookup(byte[] key, int key_bits) {
86 if (key_bits > maxKeyBits) {
87 return null;
88 }
89
90 PtreeNode node = top;
91
92 while (node != null
93 && node.keyBits <= key_bits
94 && key_match(node.key, node.keyBits, key, key_bits) == true) {
95 if (node.keyBits == key_bits) {
96 return addReference(node);
97 }
98
99 if (bit_check(key, node.keyBits) == true) {
100 node = node.right;
101 } else {
102 node = node.left;
103 }
104 }
105 return null;
106 }
107
108 public synchronized PtreeNode match(byte[] key, int key_bits) {
109 if (key_bits > maxKeyBits) {
110 return null;
111 }
112 PtreeNode node = top;
113 PtreeNode matched = null;
114
115 if (node != null)
116
117 while (node != null
118 && node.keyBits <= key_bits
119 && key_match(node.key, node.keyBits, key, key_bits) == true) {
120 matched = node;
121
122 if (bit_check(key, node.keyBits) == true) {
123 node = node.right;
124 } else {
125 node = node.left;
126 }
127 }
128
129 if (matched != null) {
130 return addReference(matched);
131 }
132
133 return null;
134 }
135
136 public synchronized PtreeNode begin() {
137 if (top == null) {
138 return null;
139 }
140 return addReference(top);
141 }
142
143 public synchronized PtreeNode next(PtreeNode node) {
144 PtreeNode next;
145
146 if (node.left != null) {
147 next = node.left;
148 addReference(next);
149 delReference(node);
150 return next;
151 }
152 if (node.right != null) {
153 next = node.right;
154 addReference(next);
155 delReference(node);
156 return next;
157 }
158
159 PtreeNode start = node;
160 while (node.parent != null) {
161 if (node.parent.left == node && node.parent.right != null) {
162 next = node.parent.right;
163 addReference(next);
164 delReference(start);
165 return next;
166 }
167 node = node.parent;
168 }
169
170 delReference(start);
171
172 return null;
173 }
174
Ray Milkeyec838942014-04-09 11:28:43 -0700175 public static int bit_to_octet(int key_bits) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700176 return Math.max((key_bits + 7) / 8, 1);
177 }
178
179 private PtreeNode addReference(PtreeNode node) {
180 node.refCount++;
181 return node;
182 }
183
184 public synchronized void delReference(PtreeNode node) {
185 if (node.refCount > 0) {
186 node.refCount--;
187 }
188 if (node.refCount == 0) {
189 node_remove(node);
190 }
191 }
192
193 private boolean key_match(byte[] key1, int key1_len, byte[] key2, int key2_len) {
194 int offset;
195 int shift;
196
197 if (key1_len > key2_len) {
198 return false;
199 }
200
201 offset = (Math.min(key1_len, key2_len)) / 8;
202 shift = (Math.min(key1_len, key2_len)) % 8;
203
204 if (shift != 0) {
205 if ((maskBits[shift] & (key1[offset] ^ key2[offset])) != 0) {
206 return false;
207 }
208 }
209
210 while (offset != 0) {
211 offset--;
212 if (key1[offset] != key2[offset]) {
213 return false;
214 }
215 }
216 return true;
217 }
218
219 private boolean bit_check(byte[] key, int key_bits) {
220 int offset = key_bits / 8;
221 int shift = 7 - (key_bits % 8);
222 int bit = key[offset] & 0xff;
223
224 bit >>= shift;
225
226 if ((bit & 1) == 1) {
227 return true;
228 } else {
229 return false;
230 }
231 }
232
233 private void node_link(PtreeNode node, PtreeNode add) {
234 boolean bit = bit_check(add.key, node.keyBits);
235
236 if (bit == true) {
237 node.right = add;
238 } else {
239 node.left = add;
240 }
241 add.parent = node;
242 }
243
244 private PtreeNode node_common(PtreeNode node, byte[] key, int key_bits) {
245 int i;
246 int limit = Math.min(node.keyBits, key_bits) / 8;
247
248 for (i = 0; i < limit; i++) {
249 if (node.key[i] != key[i]) {
250 break;
251 }
252 }
253
Ray Milkey2476cac2014-04-08 11:03:21 -0700254 int commonLen = i * 8;
Ray Milkey269ffb92014-04-03 14:43:30 -0700255 int boundary = 0;
256
Ray Milkey2476cac2014-04-08 11:03:21 -0700257 if (commonLen != key_bits) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700258 byte diff = (byte) (node.key[i] ^ key[i]);
259 byte mask = (byte) 0x80;
Ray Milkey2476cac2014-04-08 11:03:21 -0700260 int shiftMask = 0;
Ray Milkey269ffb92014-04-03 14:43:30 -0700261
Ray Milkey2476cac2014-04-08 11:03:21 -0700262 while (commonLen < key_bits && ((mask & diff) == 0)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700263 boundary = 1;
264
Ray Milkey2476cac2014-04-08 11:03:21 -0700265 shiftMask = (mask & 0xff);
266 shiftMask >>= 1;
267 mask = (byte) shiftMask;
Ray Milkey269ffb92014-04-03 14:43:30 -0700268
Ray Milkey2476cac2014-04-08 11:03:21 -0700269 commonLen++;
Ray Milkey269ffb92014-04-03 14:43:30 -0700270 }
271 }
272
Ray Milkey2476cac2014-04-08 11:03:21 -0700273 PtreeNode add = new PtreeNode(null, commonLen, maxKeyOctets);
Ray Milkey269ffb92014-04-03 14:43:30 -0700274
275 int j;
276 for (j = 0; j < i; j++)
277 add.key[j] = node.key[j];
278
279 if (boundary != 0)
280 add.key[j] = (byte) (node.key[j] & maskBits[add.keyBits % 8]);
281
282 return add;
283 }
284
285 private void node_remove(PtreeNode node) {
286 PtreeNode child;
287 PtreeNode parent;
288
289 if (node.left != null && node.right != null) {
290 return;
291 }
292
293 if (node.left != null) {
294 child = node.left;
295 } else {
296 child = node.right;
297 }
298
299 parent = node.parent;
300
301 if (child != null) {
302 child.parent = parent;
303 }
304
305 if (parent != null) {
306 if (parent.left == node) {
307 parent.left = child;
308 } else {
309 parent.right = child;
310 }
311 } else {
312 top = child;
313 }
314
315 if (parent != null && parent.refCount == 0) {
316 node_remove(parent);
317 }
318 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800319}