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