modules/rx/rx_tree.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rx_walk_tree
- rx_delete_dataleaves
- rx_delete_treenode
- rx_delete_tree
- RX_tree_cre
- rx_check_walk_tree
- RX_treecheck
1 /***************************************
2 $Revision: 1.20 $
3
4 Radix tree (rx). rx_tree.c - functions to operate on trees
5 (creation/deletion/finding).
6
7 Status: NOT REVUED, TESTED, INCOMPLETE
8
9 Design and implementation by: Marek Bukowy
10
11 ******************/ /******************
12 Copyright (c) 1999,2000,2001 RIPE NCC
13
14 All Rights Reserved
15
16 Permission to use, copy, modify, and distribute this software and its
17 documentation for any purpose and without fee is hereby granted,
18 provided that the above copyright notice appear in all copies and that
19 both that copyright notice and this permission notice appear in
20 supporting documentation, and that the name of the author not be
21 used in advertising or publicity pertaining to distribution of the
22 software without specific, written prior permission.
23
24 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
25 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
26 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
27 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
28 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 ***************************************/
31
32 #define RX_IMPL
33 #include "rip.h"
34
35
36 /*+++++++++
37 go down the tree calling func on every node.
38 (func takes the node pointer and the current level)
39
40 the function is called recursively with level increased
41 it stops recursing when no child nodes are found or maxlevel is reached.
42
43 therefore the initial call must set level to 0.
44
45 the nodecounter increments at every node, and is the return value
46 of the function. So start with 0 to get the number of nodes traversed.
47
48 ERROR HANDLING IS DIFFERENT HERE!
49 Unlike other functions it is not the return value:
50 The error code from the func function IF DEFINED (== not NULL ) goes
51 to the variable pointed to by the last parameter.
52
53 XXX: nodecounter is ALWAYS passed as 0, so should probably be removed from
54 calling parameter list, shane 2001-02-01
55 ++++++++++++*/
56 int
57 rx_walk_tree(rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
58 er_ret_t (*func)(rx_node_t *node, int level, int nodecounter,
59 void *userptr),
60 rx_walk_mt walk_mode,
61 /* controls if glue nodes are counted*/
62 /* and if levels or prefix lenghts are checked*/
63 int maxlevel,
64 int level,
65 int nodecounter,
66 void *userptr,
67 er_ret_t *err)
68 {
69 int i, link;
70
71 if( node == NULL ) die; /* program error. we expect a valid, checked, node.*/
72
73 /* check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN, */
74 /* level otherwise */
75
76 if(walk_mode & RX_WALK_PRFLEN) {
77 if(node->prefix.bits > maxlevel) {
78 return nodecounter;
79 }
80 }
81 else if( level > maxlevel ) {
82 return nodecounter;
83 }
84
85
86 /* process the node appropriately: */
87 /* if (not node glue) or (process glue nodes) */
88
89 if( node->glue == 0 || (walk_mode & RX_WALK_SKPGLU) == 0 ) {
90
91 /* increase our depth counter */
92 level++;
93
94 /* increase the count of visited nodes */
95 nodecounter++;
96
97 /* call supplied function, if any */
98 if( func != NULL ) {
99 *err = func(node, level, nodecounter, userptr);
100
101 /* abort the walk on error*/
102 if( *err != RX_OK ) {
103 ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK,
104 "walk_tree: func returned error %d, aborting", *err);
105 return nodecounter;
106 }
107 }
108 }
109
110 /* process left and right children */
111 for(i=0; i<=1; i++) {
112
113 /* reverse the sense of the walk*/
114 link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i;
115
116 if( node->child_ptr[link] != NULL ) {
117 nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode,
118 maxlevel, level, 0, userptr, err);
119 /* abort the walk on error*/
120 if( func != NULL && *err != RX_OK ) {
121 break;
122 }
123 }
124 }
125
126 /* return count of nodes visited */
127 return nodecounter;
128 }
129
130 /*+++++++++
131 go down the tree and delete all nodes of the tree.
132
133 the function is called recursively with level increased
134 it stops recursing when no child nodes are found or maxlevel is reached.
135
136 therefore the initial call must set level to 0.
137
138 the nodecounter increments at every node, and is the return value
139 of the function. So start with 0 to get the number of nodes traversed.
140
141 ERROR HANDLING IS DIFFERENT HERE!
142 Unlike other functions it is not the return value:
143 The error code from the func function IF DEFINED (== not NULL ) goes
144 to the variable pointed to by the last parameter.
145
146 XXX: nodecounter is ALWAYS passed as 0, so should probably be removed from
147 calling parameter list, shane 2001-02-01
148 ++++++++++++*/
149 void rx_delete_dataleaves(void *element_data, void *result_ptr)
/* [<][>][^][v][top][bottom][index][help] */
150 {
151 rx_dataleaf_t *leafptr = element_data;
152 rx_tree_t *tree = result_ptr;
153
154 if(tree->family == RX_FAM_IP ) {
155 /* do not look at the leaf if RX_FAM_IP */
156 /* Just free the payload, there must be one and just one. */
157 UT_free(leafptr);
158 }
159 else { /* other families */
160 /* if not >composed< then delete dataleaf */
161 if( leafptr->composed == 0 ) {
162 if( leafptr->data_ptr )
163 UT_free(leafptr->data_ptr);
164 UT_free(leafptr);
165
166 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount = 0, removed");
167
168 }
169 /* else decrement the reference number ( == number of prefixes
170 composing the range minus 1 == the >composed< flag */
171 else {
172 leafptr->composed--;
173
174 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount -- to %d ",
175 leafptr->composed );
176 }
177 } /* if family != RX_FAM_IP */
178 }
179
180 void rx_delete_treenode(rx_tree_t *tree, rx_node_t *curnode)
/* [<][>][^][v][top][bottom][index][help] */
181 {
182 if(curnode->leaves_ptr) {
183 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "deleting dataleaves of node at %08x", curnode);
184 g_list_foreach( curnode->leaves_ptr, rx_delete_dataleaves, tree);
185 /* delete the GList */
186 g_list_free(curnode->leaves_ptr);
187 }
188 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "node at %08x removed", curnode);
189 UT_free(curnode);
190
191 }
192
193 /* The fuction itself */
194 int
195 rx_delete_tree(rx_tree_t *tree, rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
196 int maxlevel,
197 int level,
198 int nodecounter,
199 void *userptr)
200 {
201 int i, link;
202
203 if( node == NULL ) die; /* program error. we expect a valid, checked, node.*/
204
205 /* check if the level is reached */
206
207 if( level > maxlevel ) {
208 return nodecounter;
209 }
210
211
212 /* process the node appropriately: */
213 /* increase our depth counter */
214 level++;
215
216 /* increase the count of visited nodes */
217 nodecounter++;
218
219
220 /* process left and right children */
221 for(i=0; i<=1; i++) {
222
223 link = i;
224
225 if( node->child_ptr[link] != NULL ) {
226 nodecounter += rx_delete_tree(tree, node->child_ptr[link], maxlevel, level, 0, userptr);
227 /* delete the processed child node */
228 rx_delete_treenode(tree, node->child_ptr[link]);
229 }
230 }
231
232 /* if this is the top level - delete the top node and the tree*/
233 if(node == tree->top_ptr){
234 rx_delete_treenode(tree, node);
235 tree->top_ptr=NULL;
236 }
237
238 /* return count of nodes deleted */
239 return nodecounter;
240 }
241
242
243 /***************************************************************************/
244 /*++++++
245 creates a (top) tree for the space, fills out sql table of trees
246 generates a tablename for a tree (if NONE)
247 updates LL of trees
248
249 MT-note: locks/unlocks the forest (still to be done)
250
251 ++++++++*/
252 er_ret_t
253 RX_tree_cre (
/* [<][>][^][v][top][bottom][index][help] */
254 char *prefixstr, /*+ prefix the tree will cover (string) +*/
255 rx_fam_t fam_id,
256 rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/
257 rx_subtree_mt subtrees, /*+ one of NONE, AUTO, HAND +*/
258 rx_tree_t **treestore /* store the tree pointer here */
259 )
260
261 {
262 rx_tree_t *newtree;
263 ip_prefix_t newpref;
264 ip_space_t spc_id;
265
266 if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) {
267 die;
268 }
269
270 spc_id = IP_pref_b2_space( &newpref );
271
272 newtree = (rx_tree_t *)UT_malloc(sizeof(rx_tree_t));
273
274 ER_dbg_va(FAC_RX, ASP_RX_TREE_GEN, "creating a tree at %08x", newtree);
275
276 /* copy tree settings */
277 newtree -> space = spc_id;
278 newtree -> family = fam_id;
279
280 newtree -> subtrees = subtrees;
281 newtree -> mem_mode = mem_mode;
282
283 /* set other tree values */
284
285 /* parent set to NULL because it's not a subtree */
286 newtree -> parent_tree = NULL;
287 /* PR_zeroprefix(& newtree -> prefix);*/
288 newtree -> maxbits = IP_sizebits(spc_id);
289
290 strcpy(newtree->data_table.val,"");
291 strcpy(newtree->radix_table.val,"");
292 strcpy(newtree->leaves_table.val,"");
293
294 newtree->num_nodes = 0;
295
296 newtree->top_ptr = NULL;
297 newtree->top_key = SQ_NOKEY;
298
299 newtree->prefix = newpref;
300
301 TH_init_read_write_lockw( &(newtree->rwlock));
302
303 *treestore = newtree;
304
305 return RX_OK;
306 }
307
308
309 /* ************************************
310 special walk function for use in consistency checks - it checks the parent
311 pointer too.
312 ************************************/
313 int rx_check_walk_tree( rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
314 rx_node_t *parent_node,
315 int nodecounter,
316 rx_treecheck_t *checkstruct )
317 {
318 int i;
319
320 /* checks*/
321 if( node == NULL ) {
322 checkstruct->code |= 1;
323 }
324 if( node->parent_ptr != parent_node ) {
325 checkstruct->code |= 2;
326 }
327 if( node->glue && node->leaves_ptr ) {
328 checkstruct->code |= 4;
329 }
330 if( node->glue && (node->child_ptr[0] == NULL || node->child_ptr[1] == NULL ) ) {
331 checkstruct->code |= 8;
332 }
333
334
335 if( node->leaves_ptr && checkstruct->datatoo ) {
336 switch( checkstruct->tree->family ) {
337 case RX_FAM_IP:
338 /* the simplest (?) case: only one leaf attached to any node
339 (except for glues) */
340 if( g_list_length(node->leaves_ptr) != 1 ) {
341 checkstruct->code |= 16;
342 }
343 break;
344 case RX_FAM_RT:
345 /* many dataleaves attached to nodes. */
346 break;
347 case RX_FAM_IN:
348 /* many dataleaves attached to nodes.
349 Some leaves pointed to from many nodes => from as many as the number
350 of composing prefixes
351 */
352 break;
353 default:
354 /* ignore */
355 break;
356 }
357 }
358
359
360 if( checkstruct->code != 0 ) {
361 checkstruct->node = node;
362
363 return nodecounter; /* abort the walk on error*/
364 }
365
366
367 nodecounter++;
368
369 for(i=0; i<=1; i++) {
370 if( node->child_ptr[i] != NULL ) {
371 nodecounter += rx_check_walk_tree( node->child_ptr[i],
372 node,
373 0, checkstruct );
374 /* abort the walk on error*/
375 if ( checkstruct->code != 0 ) {
376 die; break;
377 }
378 }
379 }
380 return nodecounter;
381 }
382
383 /* **************************************************************************
384 tree consistency check.
385
386 if datatoo = 0, then only parent/child links are checked.
387
388 if datatoo = 1, then a check on the contents of the nodes is done too.
389
390 **************************************************************************/
391
392 er_ret_t
393 RX_treecheck( rx_tree_t *tree, int datatoo, rx_treecheck_t *errorfound)
/* [<][>][^][v][top][bottom][index][help] */
394 {
395 er_ret_t err = RX_OK;
396 int nodnum;
397
398 errorfound->tree = tree;
399 errorfound->datatoo = datatoo;
400
401 /* errorfound.node will be set by hook if it finds an error*/
402 errorfound->code = 0;
403
404 nodnum = rx_check_walk_tree( tree->top_ptr,
405 NULL,
406 0,
407 errorfound );
408
409 if( nodnum != tree->num_nodes ) {
410 errorfound->code |= 1024;
411 }
412 if( tree->num_nodes == 0 && tree->top_ptr != NULL ) {
413 errorfound->code |= 2048;
414 }
415 if( tree->num_nodes != 0 && tree->top_ptr == NULL ) {
416 errorfound->code |= 4096;
417 }
418
419 if( errorfound->code != 0) {
420 err = RX_DATNOF;
421 }
422 return err;
423 }