## modules/rx/rx_tree.c

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

## DEFINITIONS

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