modules/rp/rp_search.c

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

FUNCTIONS

This source file includes following functions.
  1. rp_exclude_datlink
  2. rp_preflist_search
  3. rp_find_smallest_span
  4. rp_leaf_occ_inc
  5. rp_exclude_exact_match
  6. rp_find_longest_prefix
  7. rp_asc_process_datlist
  8. rp_mod_preflist
  9. rp_asc_append_datref
  10. rp_srch_copyresults
  11. rp_begend_preselection
  12. RP_asc_search

   1 /***************************************
   2   $Revision: 1.11 $
   3 
   4   Radix payload (rp) - user level functions for storing data in radix trees
   5 
   6   rp_search = search the loaded radix trees using an ascii key
   7 
   8               Motto: "And all that for inetnums..."
   9 
  10   Status: NOT REVIEWED, TESTED
  11   
  12   Design and implementation by: Marek Bukowy
  13   
  14   ******************/ /******************
  15   Copyright (c) 1999                              RIPE NCC
  16  
  17   All Rights Reserved
  18   
  19   Permission to use, copy, modify, and distribute this software and its
  20   documentation for any purpose and without fee is hereby granted,
  21   provided that the above copyright notice appear in all copies and that
  22   both that copyright notice and this permission notice appear in
  23   supporting documentation, and that the name of the author not be
  24   used in advertising or publicity pertaining to distribution of the
  25   software without specific, written prior permission.
  26   
  27   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  28   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  29   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  30   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  31   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  32   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33   ***************************************/
  34 
  35 
  36 #include <rp.h>
  37 
  38 static
  39 void
  40 rp_exclude_datlink(GList    **datlist, GList    *element)
     /* [<][>][^][v][top][bottom][index][help] */
  41 {
  42   /* remove element from list(becomes a self-consistent list) */
  43   *datlist = g_list_remove_link(*datlist, element);
  44   
  45   /* free it and the payload */
  46   wr_clear_list( &element );
  47 }
  48 
  49 
  50 /**************************************************************************/
  51 /*+++++++++++
  52    helper: 
  53    this routine goes through the list of prefixes and performs a bin_search
  54    on each of them; attaches the results to datlist.
  55 +++++++++++*/
  56 static
  57 er_ret_t
  58 rp_preflist_search (
     /* [<][>][^][v][top][bottom][index][help] */
  59                     rx_srch_mt search_mode, 
  60                     int par_a,
  61                     int par_b,
  62                     rx_tree_t  *mytree,
  63                     GList    **preflist,
  64                     GList    **datlist
  65                     )
  66 
  67 { 
  68   char   prefstr[IP_PREFSTR_MAX];
  69   GList   *qitem;
  70   ip_prefix_t *querypref;
  71   er_ret_t err;
  72   
  73   for( qitem = g_list_first(*preflist);
  74        qitem != NULL;
  75        qitem = g_list_next(qitem)) {
  76     
  77     querypref = qitem->data;
  78     
  79     if( IP_pref_b2a( querypref, prefstr, IP_PREFSTR_MAX) != IP_OK ) {
  80       die;
  81     }
  82     ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
  83               "rx_preflist_search: mode %d (%s) (par %d) for %s", 
  84               search_mode, RX_text_srch_mode(search_mode), par_a, prefstr);
  85     
  86     if (mytree->num_nodes > 0) {
  87       err = RX_bin_search( search_mode, par_a, par_b, mytree, querypref, 
  88                    datlist, RX_ANS_ALL);
  89       if( err != RX_OK ) {
  90         return err;
  91       }
  92     }
  93   }
  94   
  95   return RX_OK;
  96 }
  97 
  98 /*++++
  99   this is a helper: goes through a datlist and returns the smallest
 100   size of a range
 101 
 102   works for IPv4 only
 103   +++*/
 104 static
 105 ip_rangesize_t
 106 rp_find_smallest_span( GList *datlist ) {
     /* [<][>][^][v][top][bottom][index][help] */
 107   ip_rangesize_t  min_span, span;
 108   GList *ditem;
 109 
 110   min_span = 0xffffffff; /* IPv4 only!!!!*/
 111 
 112     /* go through the list and find the shortest range.    */
 113     for(ditem = g_list_first(datlist);
 114         ditem != NULL;
 115         ditem = g_list_next(ditem)) {
 116       rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 117       
 118       span = IP_rang_span( & refptr->leafptr->iprange);
 119       
 120       if( span < min_span ) {
 121         min_span = span;
 122       }
 123     }
 124     ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 125               "rp_find_smallest_span: minimal span is %d", min_span);
 126 
 127     return min_span;
 128 }
 129 
 130 
 131 
 132 /* helper for the inetnum/exless search - for this one a hash of pairs
 133 (leafptr,occurences) must be maintained.
 134 
 135 This routine increments the counter for a leafptr, creating a new
 136 pair if this leafptr was not referenced before.
 137 
 138 */
 139 static
 140 int rp_leaf_occ_inc(GHashTable *hash, rx_dataleaf_t *leafptr)
     /* [<][>][^][v][top][bottom][index][help] */
 141 {
 142   /* one little trick: store the number of occurences 
 143      as cast (void *) */
 144   int val;
 145   
 146   val = (int) g_hash_table_lookup(hash, leafptr);
 147   /* 0 if it's not known yet. anyway: put it in the hash (value==key) */
 148   
 149   g_hash_table_insert(hash, leafptr, (void *) ++val); 
 150   
 151   return val;
 152 }
 153 
 154 /* exclude exact match - not to be merged with preselction :-( */
 155 static void
 156 rp_exclude_exact_match( GList **datlist, ip_range_t *testrang) 
     /* [<][>][^][v][top][bottom][index][help] */
 157 {
 158   GList *ditem, *newitem;
 159   
 160   ditem = g_list_first(*datlist);
 161 
 162   while( ditem != NULL ) {
 163     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 164 
 165     newitem = g_list_next(ditem);
 166     
 167     if( memcmp( & refptr->leafptr->iprange, 
 168                 testrang, sizeof(ip_range_t)) == 0 ) {  
 169       rp_exclude_datlink(datlist, ditem);
 170       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 171                 "process_datlist: discarded an exact match");
 172     }
 173     ditem = newitem;
 174   } /* while */
 175 }
 176 
 177 static int
 178 rp_find_longest_prefix(GList **datlist)
     /* [<][>][^][v][top][bottom][index][help] */
 179 {
 180   GList *ditem;
 181   int max_pref=0;
 182 
 183   for(ditem = g_list_first(*datlist);
 184       ditem != NULL;
 185       ditem = g_list_next(ditem)) {
 186     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 187     
 188     if( refptr->leafptr->preflen > max_pref ) {
 189       max_pref = refptr->leafptr->preflen;
 190     }
 191   }
 192   
 193   return max_pref;
 194 }
 195 
 196 
 197 /*+ rp_asc_process_datlist() - helper for RP_asc_search()
 198   
 199   fetches the copies of objects from the radix tree into datlist
 200 
 201      ASSUMES LOCKED TREE
 202 
 203      the behaviour for a default inetnum (range) query is: 
 204        do an exact match; 
 205        if it fails, do an exless match on the encompassing prefix
 206      for routes(prefixes):
 207        do an exless match
 208      
 209      So if it's the default search mode on an inetnum tree,
 210      and the key is a range, 
 211      then an exact search is performed on one of the composing prefixes.
 212 
 213      Then the resulting data leaves are checked for exact matching with 
 214      the range queried for.
 215      Any dataleaves that do not match are discarded, and if none are left,
 216      the procedure falls back to searching for the encompassing prefix.
 217      (calculated in the smart_conv routine). 
 218      Add the dataleaf copies to the list of answers, 
 219      taking span into account 
 220 +*/
 221 static
 222 er_ret_t
 223 rp_asc_process_datlist(
     /* [<][>][^][v][top][bottom][index][help] */
 224                        rx_srch_mt search_mode,
 225                        int        par_a,
 226                        rx_fam_t   fam_id,
 227                        int        prefnumber,
 228                        GList    **datlist,
 229                        ip_range_t *testrang,
 230                        int       *hits
 231                        )
 232 {
 233   ip_rangesize_t  min_span=0, span;
 234   int max_pref = -1;
 235   GList    *ditem, *newitem;
 236   GHashTable *lohash = g_hash_table_new(NULL, NULL);
 237  
 238   /* in MORE and LESS(1) search exact match must not be displayed */
 239   if ( search_mode == RX_SRCH_MORE 
 240        || ( search_mode == RX_SRCH_LESS && par_a == 1 ) ) {
 241     rp_exclude_exact_match(datlist, testrang);
 242   }
 243   
 244   /* Preselection moved to processing, only span calculation done here *
 245    * 
 246     
 247    EXLESS and LESS(1) search: the smallest span must be found,
 248    but if the less spec node is not the same for all composing prefixes,
 249    it means it's not really this one.
 250    
 251    we check that by the number of references to this node is less than
 252    the number of composing prefixes
 253    
 254    We do the same for the less specific search - a node must be less 
 255    specific to all prefixes.
 256    
 257    if the number of references is  not enough, then return no hits,
 258    another try will be made, this time with one, encompassing prefix.
 259   */
 260   
 261   if ( (search_mode == RX_SRCH_EXLESS )   
 262        || ( search_mode == RX_SRCH_LESS && par_a == 1 ) )  {
 263     /* span works only for IP_V4. We use it only for inetnums,
 264        although RT/v4 would work too */
 265     if( testrang->begin.space == IP_V4 &&
 266         fam_id == RX_FAM_IN ) {
 267       min_span = rp_find_smallest_span(*datlist);
 268     }
 269     else {
 270       /* in IPv6 and RT trees in general,  we can obtain the same
 271          result by selecting the longest prefix */
 272       max_pref = rp_find_longest_prefix(datlist);
 273     }
 274   }
 275   
 276   /* Process the dataleaf copies and add to the list of answers. */  
 277   ditem = g_list_first(*datlist);
 278   while(ditem != NULL) {
 279     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 280     int exclude = 0;
 281     
 282     if(search_mode == RX_SRCH_EXLESS || search_mode == RX_SRCH_LESS ) {
 283       
 284       /* min_span defined <=> EXLESS or LESS(1) search of INETNUMS: 
 285          the smallest span must be returned */
 286       if( !exclude && min_span != 0 
 287           && (span = IP_rang_span( &refptr->leafptr->iprange))!=min_span) {
 288         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 289                   "process_datlist: (EX)LESS: discarded object with span %d", span);
 290         exclude = 1;
 291       }
 292       /* max_pref defined <=> EXLESS search of INETNUMS or LESS(1) of RT:
 293        */
 294       if( !exclude && max_pref >= 0
 295           && refptr->leafptr->preflen < max_pref ) {
 296         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 297                   "process_datlist: (EX)LESS: discarded object with preflen %d", 
 298                   refptr->leafptr->preflen);
 299         exclude = 1;
 300       }
 301 
 302       /* number of occurences */
 303       /* XXX this will go when the old algorithm goes */
 304       if( !exclude 
 305           && prefnumber > 1 ) { /* do not check if all will be approved */
 306         
 307         if( rp_leaf_occ_inc(lohash, refptr->leafptr) < prefnumber ) {
 308           ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 309                     "process_datlist: (EX)LESS: leafptr %x not enough",refptr->leafptr);
 310           exclude = 1;
 311         } 
 312         else {
 313           ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 314                     "process_datlist: (EX)LESS: leafptr %x GOOD enough",refptr->leafptr);
 315         }
 316       }
 317     } 
 318     else if( search_mode ==  RX_SRCH_EXACT ) {
 319       /* EXACT search - discard if the range does not match */
 320       if( memcmp( & refptr->leafptr->iprange, 
 321                   testrang, sizeof(ip_range_t)) != 0) {
 322         
 323         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 324                   "process_datlist: EXACT; discarded a mismatch");
 325         exclude = 1;
 326       } /*  EXACT match */
 327     } 
 328     else if( search_mode ==  RX_SRCH_MORE ) {
 329       /* MORE: exclude if not fully contained in the search term */
 330       if( ! (IP_addr_in_rang(&refptr->leafptr->iprange.begin, testrang )
 331           && IP_addr_in_rang(&refptr->leafptr->iprange.end, testrang ))) {
 332         ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 333                   "process_datlist: MORE; discarded a not-fully contained one");
 334         exclude = 1;
 335       }
 336     }
 337     
 338     
 339     /* get next item now, before the current gets deleted */
 340     newitem = g_list_next(ditem);
 341     if( exclude ) {
 342       /* get rid of it */
 343       rp_exclude_datlink(datlist, ditem);
 344     } 
 345     else {
 346       /* OK, so we ACCEPT these results*/
 347       /* uniqueness ensured in copy_results */
 348       (*hits)++;
 349     }
 350     ditem = newitem;
 351   } /* while ditem */ 
 352   
 353   /* wr_clear_list(&lolist); */
 354   g_hash_table_destroy(lohash);
 355   return RX_OK;
 356 }    
 357   
 358 /* 
 359    rp_mod_preflist() is a helper function for rp_asc_search().
 360 
 361    modifies the list of prefixes to search for, 
 362 
 363    special treatment for inetnum/exact:
 364    + a range that is equivalent to the search key (which may be a prefix)
 365      is made, to be used later for comparisons
 366      
 367    special treatment for inetnum/exless/composed:
 368    + the first pass mode is set to exact (otherwise to search_mode)
 369 
 370    a few optimisations are made:
 371    + for a route/composed_range/exact : the search is nuked
 372    + for an inetnum/composed_range/(exless|exact) : the list is truncated
 373      to one prefix, because in an exact search, it must be there anyway, 
 374      and for the exless, the smallest encompassing one must match
 375    
 376      
 377   */
 378   
 379 static
 380 er_ret_t 
 381 rp_mod_preflist(
     /* [<][>][^][v][top][bottom][index][help] */
 382                rx_srch_mt search_mode, 
 383                char *key,  
 384                ip_keytype_t key_type,
 385                rx_fam_t   fam_id,  
 386                GList **preflist,
 387                ip_range_t *testrang,
 388                rx_srch_mt *first_pass_mode
 389                ) 
 390 {
 391   int prefcount;
 392 
 393   prefcount = g_list_length(*preflist);
 394 
 395   /* EXACT search of a route tree for a composed range makes no sense */
 396   if( fam_id == RX_FAM_RT && search_mode == RX_SRCH_EXACT 
 397       && key_type == IPK_RANGE && prefcount > 1 ) {
 398     /* abort search - i.e. clear the preflist*/
 399 
 400       wr_clear_list( preflist);
 401       
 402       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 403         "rp_mod_preflist: route/exact/composed - preflist cleared");
 404   }
 405   
 406   /*+ inetnum / exact|exless specific :
 407     optimise: (composed range) 
 408     
 409       perform a separate first pass, with just one exact search on one of 
 410       the composing prefixes - the object must be found if it's in the 
 411       database.
 412       
 413       So a little cheat: remove all but one prefixes from preflist
 414       and force a different search mode
 415       +*/ 
 416   if( fam_id == RX_FAM_IN  
 417       && (search_mode == RX_SRCH_EXLESS || search_mode == RX_SRCH_EXACT) 
 418       && key_type == IPK_RANGE && prefcount > 1 ) { 
 419 
 420       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 421          "rp_mod_preflist: inet/ex***/composed - first pass EXACT forced");
 422 
 423       *first_pass_mode = RX_SRCH_EXACT;
 424   } /* inetnum / exact|exless specific */
 425 
 426   /* exact: set range so a comparison can be performed */
 427   /* must succeed after smart_conv succeeded */
 428   IP_smart_range(key, testrang, IP_EXPN, &key_type);
 429 
 430   return RX_OK;
 431 }
 432 /**************************************************************************/
 433 
 434 /*+ appends the element pointed to by datref to finallist +*/
 435 static
 436 er_ret_t
 437 rp_asc_append_datref(rx_datref_t *refptr, GList **finallist)
     /* [<][>][^][v][top][bottom][index][help] */
 438 {
 439   er_ret_t err;
 440   rx_datcpy_t *datcpy;
 441   void *dataptr;
 442 
 443     /* OK, so we ACCEPT this result. Copy it.*/
 444 
 445     if( (err=wr_calloc( (void **)& datcpy, 1, sizeof(rx_datcpy_t))) != UT_OK) {
 446       return err; /*    die;*/
 447     }
 448     
 449     datcpy->leafcpy = *(refptr->leafptr);
 450     
 451     /* copy the immediate data too. Set the ptr.*/
 452     
 453     if( (err=wr_calloc( (void **) & dataptr, 1, refptr->leafptr->data_len)) 
 454         != UT_OK) {
 455       return err; /*    die;*/
 456     }
 457     memcpy(dataptr, refptr->leafptr->data_ptr, refptr->leafptr->data_len);
 458     
 459     datcpy->leafcpy.data_ptr = dataptr;
 460 
 461     *finallist = g_list_prepend(*finallist, datcpy);
 462 
 463     /* XXX this wouldn't work in access_control */
 464     ER_dbg_va(FAC_RP, ASP_RP_SRCH_DATA,
 465               "rp_asc_append 'ed: %s", dataptr);
 466 
 467     return RX_OK;
 468 }
 469 
 470 /*+ goes through datlist (list of references "datref") and add copies of 
 471 leaves referenced to the finallist 
 472 
 473 maintains its own uniqhash which holds pointers to copied dataleaves.
 474 
 475 modifies: finallist
 476 
 477 returns: error from wr_malloc
 478 
 479 +*/
 480 static
 481 er_ret_t
 482 rp_srch_copyresults(GList *datlist,
     /* [<][>][^][v][top][bottom][index][help] */
 483                     GList **finallist,
 484                     int maxcount)
 485 {
 486   er_ret_t err;
 487   GList    *ditem;
 488   GHashTable *uniqhash = g_hash_table_new(NULL, NULL); /* defaults */
 489   int count = 0;
 490 
 491   ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET, "srch_copyresults");
 492 
 493   /*  copy dataleaves pointed to by entries from the datlist
 494       only once (check uniqueness in the hash table) */
 495   for(ditem = g_list_first(datlist);
 496       ditem != NULL;
 497       ditem = g_list_next(ditem)) {
 498     rx_datref_t   *refptr = (rx_datref_t *) (ditem->data);
 499     rx_dataleaf_t *ansptr = refptr->leafptr;
 500 
 501     /* search for every ansptr (dataleaf pointer) in uniqhash */
 502     if( g_hash_table_lookup(uniqhash, ansptr) == NULL ) {
 503       
 504       /* it's not known yet. OK: put it in the hash (value==key) */
 505       g_hash_table_insert(uniqhash, ansptr, ansptr); 
 506       
 507       /* and copy the dataleaf */
 508       if( !NOERR(err = rp_asc_append_datref(refptr, finallist)) ) {
 509         return err;
 510       }
 511     }
 512 
 513     /* check the limit on number of objects if defined ( >0)  */
 514     count++;
 515     if( maxcount > 0 && count > maxcount ) {
 516       break;
 517     }
 518 
 519   } /*  foreach (datlist) */
 520     
 521   g_hash_table_destroy(uniqhash); /* elements are still linked to through datlist */
 522 
 523   return RP_OK;
 524 }
 525 
 526 static 
 527 void
 528 rp_begend_preselection(GList **datlist, rx_fam_t fam_id, ip_range_t *testrang) 
     /* [<][>][^][v][top][bottom][index][help] */
 529 {
 530   GList *ditem, *newitem; 
 531 
 532   ditem = g_list_first(*datlist);
 533 
 534   while( ditem != NULL ) {
 535     rx_datref_t *refptr = (rx_datref_t *) (ditem->data);
 536     newitem = g_list_next(ditem);
 537 
 538     /* the test is indentical for route & inetnum trees */
 539     if( IP_addr_in_rang(&testrang->end, &refptr->leafptr->iprange) == 0 ) {
 540       
 541       rp_exclude_datlink(datlist, ditem);
 542       ER_dbg_va(FAC_RP, ASP_RP_SRCH_DET,
 543                 "process_datlist: discarded an uncovering leafptr %x",
 544                 refptr->leafptr);
 545 
 546     }
 547     ditem = newitem;
 548   } /* while */
 549 }
 550 
 551 /*+++++++++++++++
 552   search.
 553 
 554   2 approaches: 
 555 
 556   1. (most modes): look up all less specifics of beginning and end of range,
 557   compare/select/etc.
 558 
 559   2. More spec mode: break up the query range into prefixes, [erform a search
 560   for each of them. Add all results together.
 561 
 562   translates a query into a binary prefix (or prefixes, if range).
 563   for registry+space (or if they are zero, for all
 564   registries/spaces)
 565   finds tree 
 566   calls RX_bin_search (returning node copies).
 567   will not put duplicate entries (composed inetnums).
 568   returns some sort of error code :-) 
 569   
 570   Cuts the number of answers from RX_bin_search down to max_count,
 571   but since some of the answers may have been "normalized" in the
 572   underlying functions (multiple occurences removed), 
 573   the result is _at_most_ max_count.
 574   
 575   appends to a given list of data blocks (not nodes!)
 576 
 577   The EXLESS search on inetnum tree should return the shortest range 
 578   that was found, by means of comparing span (size) of the range.
 579   If there are more of size equal to the smallest one, they are also
 580   returned.
 581 
 582   returns RX_OK or a code from an underlying function
 583 ++++++++++++*/
 584 er_ret_t
 585 RP_asc_search ( 
     /* [<][>][^][v][top][bottom][index][help] */
 586                rx_srch_mt search_mode, 
 587                int par_a,
 588                int par_b,
 589                char *key,     /*+ search term: (string) prefix/range/IP +*/
 590                rp_regid_t  reg_id,
 591                rp_attr_t  attr,    /*+ extra tree id (within the same reg/spc/fam +*/
 592                GList **finallist,    /*+ answers go here, please +*/
 593                int    max_count    /*+ max # of answers. RX_ALLANS == unlimited +*/
 594                )
 595 { 
 596   GList    *preflist = NULL;
 597   GList    *datlist = NULL;
 598   er_ret_t   err; 
 599   ip_range_t  testrang;
 600   int        locked = 0;
 601   ip_keytype_t key_type;
 602   ip_space_t   spc_id;
 603   rx_fam_t   fam_id = RP_attr2fam( attr );
 604   rx_tree_t   *mytree;
 605   int hits=0;
 606   ip_prefix_t beginpref;
 607   
 608 
 609   /*  abort on error (but unlock the tree) */  
 610   ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
 611             "RP_NEW_asc_search:  query %s : mode %d (%s) (par %d) for %s",
 612             DF_get_attribute_name(attr),
 613             search_mode, RX_text_srch_mode(search_mode), par_a, key);
 614 
 615   
 616   /* parse the key into a prefix list */
 617   if( ( err = IP_smart_conv(key, 0, 0,
 618                             &preflist, IP_EXPN, &key_type)) != IP_OK ) {
 619     /* operational trouble (UT_*) or invalid key (IP_INVARG)*/
 620     return err; 
 621   }
 622 
 623   /* set the test values */
 624   IP_smart_range(key, &testrang, IP_EXPN, &key_type);
 625   
 626   /* find the tree */
 627   if( NOERR(err) ) {
 628     spc_id = IP_pref_b2_space( g_list_first(preflist)->data );
 629     if( ! NOERR(err = RP_tree_get( &mytree, reg_id, spc_id, attr ))) {
 630       return err;
 631     }
 632   }
 633   /* the point of no return: now we lock the tree. From here, even if errors
 634      occur, we still go through all procedure to unlock the tree at the end */
 635   
 636   /* lock the tree */
 637   TH_acquire_read_lock( &(mytree->rwlock) );
 638   locked = 1;
 639 
 640   /* Collection: this procedure is used for some search_modes only */
 641   if(    search_mode == RX_SRCH_EXLESS 
 642       || search_mode == RX_SRCH_LESS 
 643       || search_mode == RX_SRCH_EXACT )  {
 644 
 645     /* 1. compose a /32(/128) prefix for beginning of range */
 646     beginpref.ip = testrang.begin;
 647     beginpref.bits = IP_sizebits(spc_id);
 648     
 649     /* 2. dataleaves collection: look up the beginning prefix in LESS(255) mode */
 650     if( NOERR(err) ) {
 651       err = RX_bin_search( RX_SRCH_LESS, 255, 0, mytree, &beginpref, 
 652                            &datlist, RX_ANS_ALL);
 653     }
 654     
 655     /* 3. preselection: exclude those that do not include end of range 
 656      */
 657     if( NOERR(err) ) {
 658       rp_begend_preselection(&datlist, fam_id, &testrang);
 659     }
 660 
 661   } /* if exless|less|exact */
 662   else {
 663     /* MORE */
 664 
 665     /* standard collection using the traditional method: 
 666        repeat the search for all prefixes and join results */
 667 
 668     if( NOERR(err) ) {
 669       err = rp_preflist_search ( search_mode, par_a, par_b, 
 670                                  mytree, &preflist, &datlist);
 671     }
 672   } /* collection */
 673 
 674   ER_dbg_va(FAC_RP, ASP_RP_SRCH_GEN,
 675             "RP_NEW_asc_search: collected %d references ",
 676             g_list_length(datlist));
 677 
 678 
 679   /* 5. processing - using the same processing function */
 680   if( NOERR(err) ) {
 681     err = rp_asc_process_datlist( search_mode, par_a, fam_id, 
 682                                   1, /* one occurence is enough */
 683                                   &datlist,  
 684                                   &testrang,  &hits );
 685   }
 686   
 687   /* 6. copy results */
 688   if( NOERR(err) ) {
 689     err = rp_srch_copyresults(datlist, finallist, max_count); /* and uniq */
 690   }
 691 
 692   if( locked ) {
 693     /* 100. unlock the tree */
 694     TH_release_read_lock( &(mytree->rwlock) );
 695   }
 696 
 697   /* clean up */
 698   wr_clear_list( &preflist ); 
 699   wr_clear_list( &datlist );  
 700 
 701   /* NOTE if error occured, finallist may be partly filled in. */
 702   return err;
 703 }
 704   

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