## 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] */