modules/rx/rx_node.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rx_creat_node
- rx_delete_node
- rx_bin_node
- RX_rt_node
- RX_in_node
1 /***************************************
2 $Revision: 1.27 $
3
4 Radix tree (rx). rx_node.c - functions to operate on nodes of the tree
5 (creation/deletion).
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 <rxroutines.h>
34 #include <memwrap.h>
35 #include <stubs.h>
36 #include <glib.h>
37
38 #include <comparisons.h>
39
40 /***************************************************************************/
41 /*++++++++++++++++
42 rx_creat_node = create a new data node
43 (empty{glue} nodes get created automatically).
44
45 Takes a pointer to the (already allocated) data leaf to be included
46 in the list of data nodes (presumably empty as the node is only now being
47 created).
48
49 Requires a stack of nodes created in CREAT mode (with glue nodes,
50 until deep enough and the last node being non-glue).
51
52 MT notes: requires the tree to be locked.
53
54 Returns: RX_OK or error code.
55
56 +++++++++++++++++*/
57 static
58 er_ret_t
59 rx_creat_node (
/* [<][>][^][v][top][bottom][index][help] */
60 ip_prefix_t *newpref, /*+ prefix of the node to be added +*/
61 rx_tree_t *tree, /*+ tree the new node goes to +*/
62 rx_dataleaf_t *dataleaf, /*+ dataleaf to attach at this node+*/
63 rx_nodcpy_t stack[], /*+ stack==array of node_copies +*/
64 int stackdepth /*+ length of the stack +*/
65 )
66 {
67 rx_node_t *newnode, *curnode, *memnode, *gluenode;
68 int chk_bit, dif_bit, link, curpos;
69 char buf[1024];
70 er_ret_t err;
71
72 /* assume no such node yet. Will die if there is one.*/
73
74 /* calloc, because parent/child keys and child ptrs are not always set.*/
75
76 if( (err=wr_calloc( (void **) & newnode, 1, sizeof(rx_node_t))) != UT_OK) {
77 return err;
78 }
79
80 /* increment the number of nodes in the tree*/
81 tree -> num_nodes ++;
82
83 newnode -> prefix = *newpref;
84
85 /* attach the leaf to a (presumably empty?! hence NULL) list...*/
86 newnode->leaves_ptr = g_list_prepend(NULL, dataleaf);
87 newnode->glue = 0;
88
89 /* OK, so take a look at the tree*/
90
91 if ( tree -> num_nodes == 1 ) {
92 /* The tree was empty. Create a new top node.*/
93
94 tree -> top_ptr = newnode;
95 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "Created as the top node");
96 return RX_OK;
97 }
98
99 /* OK, there is at least one node in the tree. Take a look at the stack.*/
100
101 /* we've got a real node there (not a glue), but we may be too deep.*/
102 /* (it's not a glue, because glues have always two children.*/
103 /* we had to go that deep because from a glue alone one doesn't know */
104 /* what it glues)*/
105 /* GO UP.*/
106 /* take the first differing bit from comparing */
107 /* the new and the found nodes' prefixes. */
108 /* (not deeper than the shorter of the two)*/
109
110 curpos = stackdepth-1;
111 curnode = & stack[curpos].cpy;
112
113 chk_bit = smaller(curnode->prefix.bits, newpref->bits );
114
115 for(dif_bit = 0; dif_bit < chk_bit; dif_bit++) {
116 /* break the loop when the first different bit is found*/
117
118 if( IP_addr_bit_get( & curnode->prefix.ip, dif_bit)
119 != IP_addr_bit_get( & newpref->ip, dif_bit) ) {
120 break;
121 }
122 }
123
124 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET,
125 "cur = %d, new = %d, chk_bit = %d, dif_bit = %d",
126 curnode->prefix.bits, newpref->bits, chk_bit, dif_bit );
127
128 if(dif_bit == IP_sizebits(newpref->ip.space)) die; /* it mustn't happen!!!*/
129
130 /* go up to that level (watch the head of the tree!)*/
131
132 while( curpos > 0 && stack[curpos-1].cpy.prefix.bits >= dif_bit) {
133 curpos--;
134 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET,
135 "up to level %d", curpos );
136 }
137
138 /*
139 if the bit lenghts of the node, new prefix and the diffbit are equal
140 {
141 YOU'VE GOT THE NODE where the new one will be attached.
142 Either it has data (and will be moved accordingly),
143 or is a glue (and will be turned into a regular node).
144 }
145 */
146
147 curnode = & stack[curpos].cpy;
148
149 /* RAM: set a pointer to the real node in memory*/
150 memnode = stack[curpos].srcptr;
151
152 if( dif_bit == newpref->bits
153 && dif_bit == curnode->prefix.bits ) {
154
155 /* such node already exists, nothing to change in the tree!!!*/
156 /* this should be checked before calling this function, so..*/
157
158 die;
159 }
160 /*
161 else ** the branch ends here; we must create a new node... **
162 {
163 OK, how is the new node's prefix length w.r.t the dif_bit ?
164 longer -> make it a child of the node found
165 shorter -> make it the parent of the node found and take its place
166 equal -> make a glue node the parent of both
167 }
168
169 WHEN ATTACHING THE NODE, VALUES FROM THE STACK ARE USED,
170 TO PREVENT EXCESSIVE LOOKUPS AGAIN.
171
172 */
173 else {
174
175 /* **** attach it.*/
176 if( ER_is_traced(FAC_RX, ASP_RX_NODCRE_DET) ) {
177 rx_nod_print(curnode, buf, 1024);
178 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "Looking at node %s", buf);
179 }
180
181 if( curnode -> prefix.bits == dif_bit ) {
182
183 /* attach here as a child of the node found */
184 link = IP_addr_bit_get( &newpref->ip, dif_bit );
185
186 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "attaching as child %d", link);
187
188 if( memnode -> child_ptr[link] != NULL ) {
189 die;
190 }
191
192 memnode -> child_ptr[link] = newnode;
193 newnode -> parent_ptr = memnode;
194 }
195 else if ( newpref->bits == dif_bit ) {
196 /* make it the parent of the node found and take its place,*/
197 /* moving it down.*/
198
199 /* set the link from the NEW node to the OLD one (different than before)*/
200
201 link = IP_addr_bit_get( &curnode->prefix.ip, dif_bit );
202
203 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "shifting down as child %d", link);
204
205 /* PARENT<->NEW LINKS*/
206 /* see if the node was the top_node*/
207 if (curnode -> parent_ptr == NULL) {
208 /* update tree struct */
209 tree -> top_ptr = newnode;
210 } else {
211 /* no - fix the child link at the parent.*/
212 /* at the link where it was attached*/
213 int link = (curnode->parent_ptr->child_ptr[1] == memnode);
214 memnode -> parent_ptr -> child_ptr[link] = newnode;
215 }
216 memnode -> parent_ptr = newnode;
217
218 /* NEW<->CHILD LINKS*/
219 newnode -> parent_ptr = curnode->parent_ptr;
220 newnode -> child_ptr[link] = memnode;
221 }
222 else {
223 /* create a glue and shift the curnode below the glue,*/
224 /* then attach the new node at the glue*/
225
226 /* calloc, because parent/child keys are not set.*/
227
228 if( (err=wr_calloc( (void **)& gluenode, 1, sizeof(rx_node_t))) != UT_OK) {
229 return err; /* die;*/
230 }
231 tree -> num_nodes ++;
232
233 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "created glue node at %p", gluenode);
234
235 gluenode -> prefix.bits = dif_bit;
236
237 /* fill in the address. The glue node should get the prefix*/
238 /* shorter by one than the shorter of the two prefixes that are glued*/
239 /* (difbit)*/
240 /**/
241
242 gluenode -> prefix.ip = newpref->ip;
243 gluenode -> prefix.bits = dif_bit;
244
245 /* the ip in this prefix is probably incorrect. Fix it.*/
246 IP_pref_bit_fix( & gluenode -> prefix );
247
248 gluenode -> leaves_ptr = NULL;
249 gluenode -> glue = 1;
250
251 /* 1. Fix the link to and from the parent to the gluenode.*/
252
253 gluenode -> parent_ptr = curnode->parent_ptr;
254 if (gluenode->parent_ptr == NULL) {
255 tree -> top_ptr = gluenode;
256 }
257 else {
258 /* fix the child link in the parent. */
259 /* if it was at 1, then let fix the link 1, 0 otherwise*/
260
261 link = (curnode->parent_ptr->child_ptr[1] == memnode);
262
263 memnode->parent_ptr->child_ptr[link] = gluenode;
264 }
265
266 /* 2. Fix the links between gluenode and the OLD node*/
267
268 link = IP_addr_bit_get( &newpref->ip, dif_bit );
269
270 gluenode -> child_ptr[ ! link ] = memnode;
271 memnode->parent_ptr = gluenode;
272
273 /* 3. Fix the links between gluenode and the NEW node*/
274
275 gluenode -> child_ptr[ link ] = newnode;
276 newnode -> parent_ptr = gluenode;
277 }
278 return RX_OK;
279 }
280 die;
281 return -1; /*this is just to calm down the compiler*/
282 }
283
284
285 /******************************************************************
286 an auxiliary function to delete data from a node
287 (and delete the node or turn it into a glue afterwards)
288
289 takes
290
291 tree tree
292 curnode pointer to the node
293 dataleaf pointer to a dataleaf with ObjectID (dataleaf->data_key)
294 set; which is used to choose the right dataleaf
295 when browsing data leaves. It is never assumed to be
296 allocated via malloc, can be a local variable as well.
297
298 If the composed flag of the dataleaf in the tree
299 (being the reference count at the same time)
300 is non zero, decrements the count.
301 Deletes the dataleaf when it reaches zero.
302
303 suceeds always or dies when dataleaf with such data cannot be found
304 in the node
305 */
306
307 void
308 rx_delete_node (rx_tree_t *tree, rx_node_t *curnode, rx_dataleaf_t *dataleaf)
/* [<][>][^][v][top][bottom][index][help] */
309 {
310 rx_dataleaf_t *leaffound = NULL;
311 GList *qitem;
312 int leavesum=0;
313
314 /* go through leaves, comparing the objectID (data_key) */
315 for( qitem = g_list_first(curnode->leaves_ptr);
316 qitem != NULL;
317 qitem = g_list_next(qitem)) {
318 rx_dataleaf_t *leafptr = qitem->data;
319
320 if( leafptr->data_key == dataleaf->data_key ) {
321 leaffound = leafptr;
322 /* no break - we're counting leaves..*/
323 }
324 leavesum++;
325 }
326
327 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "%d dataleaves at the node", leavesum);
328
329 /* return error if none of the dataleaves matched */
330 if( leaffound == NULL ) die;
331
332 /* NO error? good. Remove the leaf from the list */
333 curnode->leaves_ptr = g_list_remove ( curnode->leaves_ptr, leaffound );
334
335 /* if not >composed< then delete dataleaf */
336 if( leaffound->composed == 0 ) {
337 if( leaffound->data_ptr != NULL /* allow dataleafs without attached */
338 && leaffound->data_len > 0 ) { /* data */
339 wr_free(leaffound->data_ptr);
340 }
341 wr_free(leaffound);
342
343 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount = 0, removed");
344
345 }
346 /* else decrement the reference number ( == number of prefixes
347 composing the range minus 1 == the >composed< flag */
348 else {
349 leaffound->composed--;
350
351 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "dataleaf refcount -- to %d ",
352 leaffound->composed );
353 }
354
355 /* if that was the last leave at this node, then delete node. */
356 if( leavesum == 1 ) {
357 rx_node_t *parent = curnode->parent_ptr;
358
359 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "last dataleaf, removing node");
360
361 assert(curnode->leaves_ptr == NULL);
362 /* To do this, check the number of children: */
363
364 /* 0 - just delete this node and the link to it */
365 if( curnode->child_ptr[0] == NULL && curnode->child_ptr[1] == NULL ) {
366
367 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "no children, just removing");
368
369 if( parent != NULL ) { /* watch the head! */
370 int plink = (parent->child_ptr[1] == curnode);
371 parent->child_ptr[plink] = NULL;
372 }
373 else {
374 assert(tree->top_ptr == curnode);
375 tree->top_ptr = NULL;
376 }
377 tree->num_nodes--;
378 wr_free(curnode);
379
380
381 /* now, if we deleted curnode, let's see if the parent node is a glue.
382 If it is, then hook the remaining child up the grandparent,
383 and delete the parent */
384 if( parent != NULL && parent->glue ) {
385 int slink = (parent->child_ptr[1] != NULL );
386 rx_node_t *schild = parent->child_ptr[slink];
387 rx_node_t *gparent = parent->parent_ptr;
388
389 assert( schild != NULL && parent->child_ptr[ ! slink] == NULL);
390
391 /* upd parent */
392 if( gparent != NULL ) { /* watch the head! */
393 int plink = (gparent->child_ptr[1] == parent);
394 gparent->child_ptr[plink] = parent->child_ptr[slink];
395 } else {
396 assert(tree->top_ptr == parent);
397 tree->top_ptr = parent->child_ptr[slink];
398 }
399
400 /* update the child's parent link too */
401 parent->child_ptr[slink]->parent_ptr = gparent;
402
403 /* del */
404 tree->num_nodes--;
405 wr_free(parent);
406
407 } /* if parent glue */
408 }
409 /* 2 - turn into a glue */
410 else if( curnode->child_ptr[0] != NULL
411 && curnode->child_ptr[1] != NULL ) {
412
413 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "two children, turning into a glue");
414
415 curnode->glue = 1;
416
417 }
418 /* 1 - copy the child's link to parent. then delete */
419 else {
420 int clink = (curnode->child_ptr[1] != NULL );
421
422 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "one child at %d, shifting it up",
423 clink);
424
425 /* upd parent */
426 if( parent != NULL ) { /* watch the head! */
427 int plink = (parent->child_ptr[1] == curnode);
428 parent->child_ptr[plink] = curnode->child_ptr[clink];
429 } else {
430 /* no parent; the child becomes the top node now */
431 tree->top_ptr = curnode->child_ptr[clink];
432 }
433
434 /* update the child's parent link too */
435 curnode->child_ptr[clink]->parent_ptr = parent;
436
437 /* del */
438 tree->num_nodes--;
439 wr_free(curnode);
440 }
441
442
443 } /* leavesum == 1 <=> that was the last data leaf */
444 } /* rx_delete_node */
445
446 /*+++++++++++++++++++
447
448 General function to operate on dataleaves attached to a single node
449 (create / modify / delete).
450
451 searches tree, finds and creates/deletes a node,
452 copies modified nodes to disk using rx_sql_node_set (not yet implemented).
453 Updates memory rollback info.
454
455
456
457
458 creation:
459 Add a dataleaf at the node defined by prefix.
460 Create a new node if it doesn't exist yet.
461
462
463 MT notes: requires the tree to be locked.
464
465 Returns: RX_OK or error code.
466
467 Errors from:
468 rx_bin_search,
469 memory alloc routines.
470
471 - no such node (if not in create mode)
472
473 - too many nodes found (strange).
474
475 +++++++++++++++++*/
476
477 /*static*/
478 er_ret_t
479 rx_bin_node (
/* [<][>][^][v][top][bottom][index][help] */
480 rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
481 ip_prefix_t *newpref, /*+ prefix of the node +*/
482 rx_tree_t *tree, /*+ pointer to the tree structure +*/
483 rx_dataleaf_t *dataleaf /*+ dataleaf to attach at the node +*/
484 )
485
486 {
487 GList *nodlist = NULL;
488 int nodesfound, stackdepth;
489 int glue;
490 rx_nodcpy_t *curcpy;
491 rx_node_t *curnode;
492 /* rx_nodcpy_t *stack;*/
493 rx_nodcpy_t stack[128];
494 er_ret_t err;
495 char bbf[IP_PREFSTR_MAX];
496
497
498 if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_DET)) {
499 IP_pref_b2a( newpref , bbf, IP_PREFSTR_MAX);
500 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_GEN,
501 "rx_bin_node: %s in spc %d /fam %d operation %d",
502 bbf, tree->space, tree->family, mode);
503 }
504
505 /* first check: are we using the correct tree ???*/
506 if( tree->space != newpref->ip.space ) {
507 /* trying to insert a prefix of space %d into a tree of space %d\n",
508 tree->space,
509 newpref->ip.space);
510 */
511 die;
512 }
513
514 assert( dataleaf );
515 assert( newpref->bits <= IP_sizebits(tree->space) );
516
517 /* fix the prefix, to make sure all insignificant bits are 0*/
518 IP_pref_bit_fix( newpref );
519
520 if( (err=rx_build_stack(stack, &stackdepth, tree, newpref, RX_STK_CREAT))
521 != RX_OK ) {
522 return err; /*die*/
523 }
524
525 /* rx_stk_print(stack, stackdepth);*/
526
527 /* perform a search on the stack. The result is a list, and it must*/
528 /* be properly deleted after use!!*/
529
530 if( rx_nod_search(RX_SRCH_CREAT, 0, 0,
531 tree, newpref, stack, stackdepth,
532 &nodlist, RX_ANS_ALL) != RX_OK ) {
533 return err; /* die;*/
534 }
535
536
537 /* count number of nodes in the answer */
538 nodesfound = g_list_length (nodlist);
539
540 switch( nodesfound ) {
541 case 0:
542 /* no such node (yet). See what we're up to.
543 if( mode==cre ) create, else - program error, die */
544
545 /* C R E A T I O N */
546 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET,
547 "rx_bin_node: Creating a new node %s in spc %d /fam %d ",
548 bbf, tree->space, tree->family);
549 if( mode != RX_OPER_CRE) {
550 die;
551 }
552
553 rx_creat_node( newpref, tree, dataleaf, stack, stackdepth );
554 break;
555 case 1: /* found */
556 /* set the curnode pointer */
557 curcpy = g_list_nth_data(nodlist, 0);
558 curnode = curcpy->srcptr;
559
560 switch( mode ) {
561 case RX_OPER_CRE:
562 /* attach the data at the node that was found;*/
563
564 /* was it glue ?*/
565 glue = curnode->glue;
566
567 curnode->leaves_ptr = g_list_prepend(curnode->leaves_ptr, dataleaf);
568 /* now it's not a glue anymore */
569 curnode->glue = 0;
570
571 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET, "Appended data to a %s node",
572 glue ? "glue" : "data");
573
574 break;
575 case RX_OPER_DEL:
576
577 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_DET,
578 "rx_bin_node: Deleting node %s in spc %d /fam %d ",
579 bbf, tree->space, tree->family);
580 rx_delete_node( tree, curnode, dataleaf);
581 break;
582 }
583 break;
584 default:
585 /* too many nodes found! from an exact/exact-less-1 search.
586 this cannot happen. Call Ghostbusters now.
587 */
588 die;
589 }
590
591 wr_clear_list( &nodlist );
592
593 return RX_OK;
594 }
595
596
597
598 /***************************************************************************/
599 /* ++++++++++++++++
600 A wrapper around RX_bin_node.
601
602 It's there only to control the freeing of dataleaf copies passed
603 for comparison during deletion.
604
605 +++++++++++++++++*/
606 er_ret_t
607 RX_rt_node (
/* [<][>][^][v][top][bottom][index][help] */
608 rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
609 ip_prefix_t *newpref, /*+ prefix of the node +*/
610 rx_tree_t *tree, /*+ pointer to the tree structure +*/
611 rx_dataleaf_t *leafptr /*+ dataleaf to attach at the node +*/
612 )
613 {
614 er_ret_t reterr;
615
616 IP_pref_2_rang( & leafptr->iprange, newpref);
617 leafptr->preflen = IP_pref_b2_len(newpref);
618
619 /* store the object's range, used in rp.search */
620
621 reterr = rx_bin_node(mode, newpref, tree, leafptr);
622
623 return reterr;
624 }
625
626 /***************************************************************************/
627 /*+++++++++++++++
628 performs the actual update for inetnums (possibly composed of many prefixes).
629 Decomposes the ranges into prefixes and then falls back to rx_bin_node
630 to perform changes at the nodes.
631
632 Requires/returns - practically the same as rx_bin_node.
633 ++++++++++++++++*/
634
635 er_ret_t
636 RX_in_node( rx_oper_mt mode, /*+ MODE={cre|mod|del} +*/
/* [<][>][^][v][top][bottom][index][help] */
637 ip_range_t *rang, /*+ range of IP addresses +*/
638 rx_tree_t *tree, /*+ pointer to the tree structure +*/
639 rx_dataleaf_t *leafptr /*+ dataleaf to attach at the node +*/
640 )
641 {
642 int i, prefcount;
643 GList *preflist = NULL;
644 char buf[IP_RANGSTR_MAX];
645
646 if( ER_is_traced( FAC_RX, ASP_RX_NODCRE_GEN)) {
647 IP_rang_b2a(rang, buf, IP_RANGSTR_MAX );
648 ER_dbg_va(FAC_RX, ASP_RX_NODCRE_GEN,
649 "rx_inum_node: adding %s", buf);
650 }
651
652 /* decompose, put links to the data leaf into every prefix*/
653 /* that makes up this range.*/
654 IP_rang_decomp(rang, &preflist);
655
656 /* see if there is more than 1 prefix, set the composed flag*/
657 prefcount = g_list_length(preflist);
658 leafptr->composed = (prefcount - 1) ;
659
660 leafptr->iprange = *rang;
661
662 for(i=0; i < prefcount; i++) {
663 ip_prefix_t *mypref = g_list_nth_data(preflist, i);
664
665 rx_bin_node(mode, mypref, tree, leafptr);
666 }
667
668 /* free the storage from decomposition*/
669 wr_clear_list( &preflist );
670
671 return RX_OK;
672 }