modules/rx/rx_tree.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rx_walk_tree
- RX_tree_cre
- rx_check_walk_tree
- RX_treecheck
1 /***************************************
2 $Revision: 1.15 $
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 int
63 rx_walk_tree(rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
64 er_ret_t (*func)(rx_node_t *node, int level, int nodecounter,
65 void *userptr),
66 rx_walk_mt walk_mode,
67 /* controls if glue nodes are counted*/
68 /* and if levels or prefix lenghts are checked*/
69 int maxlevel,
70 int level,
71 int nodecounter,
72 void *userptr,
73 er_ret_t *err)
74 {
75 int i, link, skpglue=0;
76
77 if( node == NULL ) die; /* program error. we expect a valid, checked, node.*/
78
79 /* count the node appropriately:*/
80 /* if (not glue) or (it doesn't matter)*/
81
82 if( node->glue == 0 || (walk_mode & RX_WALK_SKPGLU) == 0 ) {
83 level++;
84 } else { /* nodeglue = 1 && walkmode&skpglue = 1 */
85 skpglue = 1;
86 }
87
88 /* check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN, */
89 /* level otherwise */
90
91 if(walk_mode & RX_WALK_PRFLEN) {
92 if(node->prefix.bits > maxlevel) {
93 return nodecounter;
94 }
95 }
96 else if( level > maxlevel ) {
97 return nodecounter;
98 }
99
100 /* didn't quit ?? OK, count it too...*/
101 if( skpglue == 0 ) {
102 nodecounter++;
103 }
104
105 if( func != NULL && skpglue == 0 ) {
106 *err = func(node, level, nodecounter, userptr);
107
108 /* abort the walk on error*/
109 if( *err != RX_OK ) {
110 ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK,
111 "walk_tree: func returned error %d, aborting", *err);
112 return nodecounter;
113 }
114 }
115
116
117 for(i=0; i<=1; i++) {
118
119 /* reverse the sense of the walk*/
120 link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i;
121
122 if( node->child_ptr[link] != NULL ) {
123 nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode,
124 maxlevel, level, 0, userptr, err);
125 /* abort the walk on error*/
126 if( func != NULL && *err != RX_OK ) {
127 break;
128 }
129 }
130 }
131
132 return nodecounter;
133 }
134
135
136
137 /***************************************************************************/
138 /*++++++
139 creates a (top) tree for the space, fills out sql table of trees
140 generates a tablename for a tree (if NONE)
141 updates LL of trees
142
143 MT-note: locks/unlocks the forest (still to be done)
144
145 ++++++++*/
146 er_ret_t
147 RX_tree_cre (
/* [<][>][^][v][top][bottom][index][help] */
148 char *prefixstr, /*+ prefix the tree will cover (string) +*/
149 rx_fam_t fam_id,
150 rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/
151 rx_subtree_mt subtrees, /*+ one of NONE, AUTO, HAND +*/
152 rx_tree_t **treestore /* store the tree pointer here */
153 )
154
155 {
156 er_ret_t err;
157 rx_tree_t *newtree;
158 ip_prefix_t newpref;
159 ip_space_t spc_id;
160
161 if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) {
162 die;
163 }
164
165 spc_id = IP_pref_b2_space( &newpref );
166
167 if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) {
168 return err; /* die*/
169 }
170
171 ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "creating a tree at %08x", newtree);
172
173 /* copy tree settings */
174 newtree -> space = spc_id;
175 newtree -> family = fam_id;
176
177 newtree -> subtrees = subtrees;
178 newtree -> mem_mode = mem_mode;
179
180 /* set other tree values */
181
182 /* parent set to NULL because it's not a subtree */
183 newtree -> parent_tree = NULL;
184 /* PR_zeroprefix(& newtree -> prefix);*/
185 newtree -> maxbits = IP_sizebits(spc_id);
186
187 strcpy(newtree->data_table.val,"");
188 strcpy(newtree->radix_table.val,"");
189 strcpy(newtree->leaves_table.val,"");
190
191 newtree->num_nodes = 0;
192
193 newtree->top_ptr = NULL;
194 newtree->top_key = SQ_NOKEY;
195
196 newtree->prefix = newpref;
197
198 TH_init_read_write_lock( &(newtree->rwlock));
199
200 *treestore = newtree;
201
202 return RX_OK;
203 }
204
205
206 /* ************************************
207 special walk function for use in consistency checks - it checks the parent
208 pointer too.
209 ************************************/
210 int rx_check_walk_tree( rx_node_t *node,
/* [<][>][^][v][top][bottom][index][help] */
211 rx_node_t *parent_node,
212 int nodecounter,
213 rx_treecheck_t *checkstruct )
214 {
215 int i;
216
217 /* checks*/
218 if( node == NULL ) {
219 checkstruct->code |= 1;
220 }
221 if( node->parent_ptr != parent_node ) {
222 checkstruct->code |= 2;
223 }
224 if( node->glue && node->leaves_ptr ) {
225 checkstruct->code |= 4;
226 }
227 if( node->glue && (node->child_ptr[0] == NULL || node->child_ptr[1] == NULL ) ) {
228 checkstruct->code |= 8;
229 }
230
231
232 if( node->leaves_ptr && checkstruct->datatoo ) {
233 switch( checkstruct->tree->family ) {
234 case RX_FAM_IP:
235 /* the simplest (?) case: only one leaf attached to any node
236 (except for glues) */
237 if( g_list_length(node->leaves_ptr) != 1 ) {
238 checkstruct->code |= 16;
239 }
240 break;
241 case RX_FAM_RT:
242 /* many dataleaves attached to nodes. */
243 break;
244 case RX_FAM_IN:
245 /* many dataleaves attached to nodes.
246 Some leaves pointed to from many nodes => from as many as the number
247 of composing prefixes
248 */
249 break;
250 default:
251 /* ignore */
252 break;
253 }
254 }
255
256
257 if( checkstruct->code != 0 ) {
258 checkstruct->node = node;
259
260 return nodecounter; /* abort the walk on error*/
261 }
262
263
264 nodecounter++;
265
266 for(i=0; i<=1; i++) {
267 if( node->child_ptr[i] != NULL ) {
268 nodecounter += rx_check_walk_tree( node->child_ptr[i],
269 node,
270 0, checkstruct );
271 /* abort the walk on error*/
272 if ( checkstruct->code != 0 ) {
273 break;
274 }
275 }
276 }
277 return nodecounter;
278 }
279
280 /* **************************************************************************
281 tree consistency check.
282
283 if datatoo = 0, then only parent/child links are checked.
284
285 if datatoo = 1, then a check on the contents of the nodes is done too.
286
287 **************************************************************************/
288
289 er_ret_t
290 RX_treecheck( rx_tree_t *tree, int datatoo, rx_treecheck_t *errorfound)
/* [<][>][^][v][top][bottom][index][help] */
291 {
292 er_ret_t err = RX_OK;
293 int nodnum;
294
295 errorfound->tree = tree;
296 errorfound->datatoo = datatoo;
297
298 /* errorfound.node will be set by hook if it finds an error*/
299 errorfound->code = 0;
300
301 nodnum = rx_check_walk_tree( tree->top_ptr,
302 NULL,
303 0,
304 errorfound );
305
306 if( nodnum != tree->num_nodes ) {
307 errorfound->code |= 1024;
308 }
309 if( tree->num_nodes == 0 && tree->top_ptr != NULL ) {
310 errorfound->code |= 2048;
311 }
312 if( tree->num_nodes != 0 && tree->top_ptr == NULL ) {
313 errorfound->code |= 4096;
314 }
315
316 if( errorfound->code != 0) {
317 err = RX_DATNOF;
318 }
319 return err;
320 }