blob: 8159b57c3a6cd2c9c9b0861cd299bf5bf60e5078 [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
Ray Milkeyb29e6262014-04-09 16:02:14 -0700115 if (node != null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700116
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 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700128 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700129
130 if (matched != null) {
131 return addReference(matched);
132 }
133
134 return null;
135 }
136
137 public synchronized PtreeNode begin() {
138 if (top == null) {
139 return null;
140 }
141 return addReference(top);
142 }
143
144 public synchronized PtreeNode next(PtreeNode node) {
145 PtreeNode next;
146
147 if (node.left != null) {
148 next = node.left;
149 addReference(next);
150 delReference(node);
151 return next;
152 }
153 if (node.right != null) {
154 next = node.right;
155 addReference(next);
156 delReference(node);
157 return next;
158 }
159
160 PtreeNode start = node;
161 while (node.parent != null) {
162 if (node.parent.left == node && node.parent.right != null) {
163 next = node.parent.right;
164 addReference(next);
165 delReference(start);
166 return next;
167 }
168 node = node.parent;
169 }
170
171 delReference(start);
172
173 return null;
174 }
175
Ray Milkeyec838942014-04-09 11:28:43 -0700176 public static int bit_to_octet(int key_bits) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700177 return Math.max((key_bits + 7) / 8, 1);
178 }
179
180 private PtreeNode addReference(PtreeNode node) {
181 node.refCount++;
182 return node;
183 }
184
185 public synchronized void delReference(PtreeNode node) {
186 if (node.refCount > 0) {
187 node.refCount--;
188 }
189 if (node.refCount == 0) {
190 node_remove(node);
191 }
192 }
193
194 private boolean key_match(byte[] key1, int key1_len, byte[] key2, int key2_len) {
195 int offset;
196 int shift;
197
198 if (key1_len > key2_len) {
199 return false;
200 }
201
202 offset = (Math.min(key1_len, key2_len)) / 8;
203 shift = (Math.min(key1_len, key2_len)) % 8;
204
205 if (shift != 0) {
206 if ((maskBits[shift] & (key1[offset] ^ key2[offset])) != 0) {
207 return false;
208 }
209 }
210
211 while (offset != 0) {
212 offset--;
213 if (key1[offset] != key2[offset]) {
214 return false;
215 }
216 }
217 return true;
218 }
219
220 private boolean bit_check(byte[] key, int key_bits) {
221 int offset = key_bits / 8;
222 int shift = 7 - (key_bits % 8);
223 int bit = key[offset] & 0xff;
224
225 bit >>= shift;
226
227 if ((bit & 1) == 1) {
228 return true;
229 } else {
230 return false;
231 }
232 }
233
234 private void node_link(PtreeNode node, PtreeNode add) {
235 boolean bit = bit_check(add.key, node.keyBits);
236
237 if (bit == true) {
238 node.right = add;
239 } else {
240 node.left = add;
241 }
242 add.parent = node;
243 }
244
245 private PtreeNode node_common(PtreeNode node, byte[] key, int key_bits) {
246 int i;
247 int limit = Math.min(node.keyBits, key_bits) / 8;
248
249 for (i = 0; i < limit; i++) {
250 if (node.key[i] != key[i]) {
251 break;
252 }
253 }
254
Ray Milkey2476cac2014-04-08 11:03:21 -0700255 int commonLen = i * 8;
Ray Milkey269ffb92014-04-03 14:43:30 -0700256 int boundary = 0;
257
Ray Milkey2476cac2014-04-08 11:03:21 -0700258 if (commonLen != key_bits) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700259 byte diff = (byte) (node.key[i] ^ key[i]);
260 byte mask = (byte) 0x80;
Ray Milkey2476cac2014-04-08 11:03:21 -0700261 int shiftMask = 0;
Ray Milkey269ffb92014-04-03 14:43:30 -0700262
Ray Milkey2476cac2014-04-08 11:03:21 -0700263 while (commonLen < key_bits && ((mask & diff) == 0)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700264 boundary = 1;
265
Ray Milkey2476cac2014-04-08 11:03:21 -0700266 shiftMask = (mask & 0xff);
267 shiftMask >>= 1;
268 mask = (byte) shiftMask;
Ray Milkey269ffb92014-04-03 14:43:30 -0700269
Ray Milkey2476cac2014-04-08 11:03:21 -0700270 commonLen++;
Ray Milkey269ffb92014-04-03 14:43:30 -0700271 }
272 }
273
Ray Milkey2476cac2014-04-08 11:03:21 -0700274 PtreeNode add = new PtreeNode(null, commonLen, maxKeyOctets);
Ray Milkey269ffb92014-04-03 14:43:30 -0700275
276 int j;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700277 for (j = 0; j < i; j++) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700278 add.key[j] = node.key[j];
Ray Milkeyb29e6262014-04-09 16:02:14 -0700279 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700280
Ray Milkeyb29e6262014-04-09 16:02:14 -0700281 if (boundary != 0) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700282 add.key[j] = (byte) (node.key[j] & maskBits[add.keyBits % 8]);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700283 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700284
285 return add;
286 }
287
288 private void node_remove(PtreeNode node) {
289 PtreeNode child;
290 PtreeNode parent;
291
292 if (node.left != null && node.right != null) {
293 return;
294 }
295
296 if (node.left != null) {
297 child = node.left;
298 } else {
299 child = node.right;
300 }
301
302 parent = node.parent;
303
304 if (child != null) {
305 child.parent = parent;
306 }
307
308 if (parent != null) {
309 if (parent.left == node) {
310 parent.left = child;
311 } else {
312 parent.right = child;
313 }
314 } else {
315 top = child;
316 }
317
318 if (parent != null && parent.refCount == 0) {
319 node_remove(parent);
320 }
321 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800322}