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.21 $
   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,2002               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 }

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