blob: f85c49c724a6cc478f01d09ecff2e68731679ab0 [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);
66 if (add == null) {
67 return null;
68 }
pingping-lina2cbfad2013-03-07 08:39:21 +080069
Ray Milkey269ffb92014-04-03 14:43:30 -070070 if (match != null) {
71 node_link(match, add);
72 } else {
73 top = add;
74 }
75 node_link(add, node);
pingping-lina2cbfad2013-03-07 08:39:21 +080076
Ray Milkey269ffb92014-04-03 14:43:30 -070077 if (add.keyBits != key_bits) {
78 match = add;
79
80 add = new PtreeNode(key, key_bits, maxKeyOctets);
81 node_link(match, add);
82 }
83 }
84
85 return addReference(add);
86 }
87
88 public synchronized PtreeNode lookup(byte[] key, int key_bits) {
89 if (key_bits > maxKeyBits) {
90 return null;
91 }
92
93 PtreeNode node = top;
94
95 while (node != null
96 && node.keyBits <= key_bits
97 && key_match(node.key, node.keyBits, key, key_bits) == true) {
98 if (node.keyBits == key_bits) {
99 return addReference(node);
100 }
101
102 if (bit_check(key, node.keyBits) == true) {
103 node = node.right;
104 } else {
105 node = node.left;
106 }
107 }
108 return null;
109 }
110
111 public synchronized PtreeNode match(byte[] key, int key_bits) {
112 if (key_bits > maxKeyBits) {
113 return null;
114 }
115 PtreeNode node = top;
116 PtreeNode matched = null;
117
118 if (node != null)
119
120 while (node != null
121 && node.keyBits <= key_bits
122 && key_match(node.key, node.keyBits, key, key_bits) == true) {
123 matched = node;
124
125 if (bit_check(key, node.keyBits) == true) {
126 node = node.right;
127 } else {
128 node = node.left;
129 }
130 }
131
132 if (matched != null) {
133 return addReference(matched);
134 }
135
136 return null;
137 }
138
139 public synchronized PtreeNode begin() {
140 if (top == null) {
141 return null;
142 }
143 return addReference(top);
144 }
145
146 public synchronized PtreeNode next(PtreeNode node) {
147 PtreeNode next;
148
149 if (node.left != null) {
150 next = node.left;
151 addReference(next);
152 delReference(node);
153 return next;
154 }
155 if (node.right != null) {
156 next = node.right;
157 addReference(next);
158 delReference(node);
159 return next;
160 }
161
162 PtreeNode start = node;
163 while (node.parent != null) {
164 if (node.parent.left == node && node.parent.right != null) {
165 next = node.parent.right;
166 addReference(next);
167 delReference(start);
168 return next;
169 }
170 node = node.parent;
171 }
172
173 delReference(start);
174
175 return null;
176 }
177
178 static public int bit_to_octet(int key_bits) {
179 return Math.max((key_bits + 7) / 8, 1);
180 }
181
182 private PtreeNode addReference(PtreeNode node) {
183 node.refCount++;
184 return node;
185 }
186
187 public synchronized void delReference(PtreeNode node) {
188 if (node.refCount > 0) {
189 node.refCount--;
190 }
191 if (node.refCount == 0) {
192 node_remove(node);
193 }
194 }
195
196 private boolean key_match(byte[] key1, int key1_len, byte[] key2, int key2_len) {
197 int offset;
198 int shift;
199
200 if (key1_len > key2_len) {
201 return false;
202 }
203
204 offset = (Math.min(key1_len, key2_len)) / 8;
205 shift = (Math.min(key1_len, key2_len)) % 8;
206
207 if (shift != 0) {
208 if ((maskBits[shift] & (key1[offset] ^ key2[offset])) != 0) {
209 return false;
210 }
211 }
212
213 while (offset != 0) {
214 offset--;
215 if (key1[offset] != key2[offset]) {
216 return false;
217 }
218 }
219 return true;
220 }
221
222 private boolean bit_check(byte[] key, int key_bits) {
223 int offset = key_bits / 8;
224 int shift = 7 - (key_bits % 8);
225 int bit = key[offset] & 0xff;
226
227 bit >>= shift;
228
229 if ((bit & 1) == 1) {
230 return true;
231 } else {
232 return false;
233 }
234 }
235
236 private void node_link(PtreeNode node, PtreeNode add) {
237 boolean bit = bit_check(add.key, node.keyBits);
238
239 if (bit == true) {
240 node.right = add;
241 } else {
242 node.left = add;
243 }
244 add.parent = node;
245 }
246
247 private PtreeNode node_common(PtreeNode node, byte[] key, int key_bits) {
248 int i;
249 int limit = Math.min(node.keyBits, key_bits) / 8;
250
251 for (i = 0; i < limit; i++) {
252 if (node.key[i] != key[i]) {
253 break;
254 }
255 }
256
Ray Milkey2476cac2014-04-08 11:03:21 -0700257 int commonLen = i * 8;
Ray Milkey269ffb92014-04-03 14:43:30 -0700258 int boundary = 0;
259
Ray Milkey2476cac2014-04-08 11:03:21 -0700260 if (commonLen != key_bits) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700261 byte diff = (byte) (node.key[i] ^ key[i]);
262 byte mask = (byte) 0x80;
Ray Milkey2476cac2014-04-08 11:03:21 -0700263 int shiftMask = 0;
Ray Milkey269ffb92014-04-03 14:43:30 -0700264
Ray Milkey2476cac2014-04-08 11:03:21 -0700265 while (commonLen < key_bits && ((mask & diff) == 0)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700266 boundary = 1;
267
Ray Milkey2476cac2014-04-08 11:03:21 -0700268 shiftMask = (mask & 0xff);
269 shiftMask >>= 1;
270 mask = (byte) shiftMask;
Ray Milkey269ffb92014-04-03 14:43:30 -0700271
Ray Milkey2476cac2014-04-08 11:03:21 -0700272 commonLen++;
Ray Milkey269ffb92014-04-03 14:43:30 -0700273 }
274 }
275
Ray Milkey2476cac2014-04-08 11:03:21 -0700276 PtreeNode add = new PtreeNode(null, commonLen, maxKeyOctets);
Ray Milkey269ffb92014-04-03 14:43:30 -0700277
278 int j;
279 for (j = 0; j < i; j++)
280 add.key[j] = node.key[j];
281
282 if (boundary != 0)
283 add.key[j] = (byte) (node.key[j] & maskBits[add.keyBits % 8]);
284
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}