modules/rx/rx_tree.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. rx_walk_tree
  2. rx_delete_dataleaves
  3. rx_delete_treenode
  4. rx_delete_tree
  5. RX_tree_cre
  6. rx_check_walk_tree
  7. 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 }

/* [<][>][^][v][top][bottom][index][help] */