modules/rx/rx_tree.c

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

FUNCTIONS

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

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