modules/nh/nh.c

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

FUNCTIONS

This source file includes following functions.
  1. get_min_range
  2. NH_convert
  3. NH_parse
  4. NH_check
  5. NH_free
  6. NH_register
  7. free_nh
  8. get_range
  9. update_range
  10. create_range

   1 #include <glib.h>
   2 #include <stdio.h>
   3 #include <strings.h>
   4 #include <glib.h>
   5 #include <stdlib.h>
   6 #include <ctype.h>
   7 #include <unistd.h>
   8 
   9 #include "nh.h"
  10 #include <stubs.h>
  11 
  12 /*+ String sizes +*/
  13 #define STR_S   63
  14 #define STR_M   255
  15 #define STR_L   1023
  16 #define STR_XL  4095
  17 #define STR_XXL 16383
  18 #define STR_XXXL 65535
  19 
  20 
  21 
  22 #define get_min_range(prange, sql_connection) get_range(-1, prange, sql_connection)
     /* [<][>][^][v][top][bottom][index][help] */
  23 static long get_range(long nic_id, range_t *prange, SQ_connection_t *sql_connection);
  24 static long update_range(long range_id, range_t *p_newrange, SQ_connection_t *sql_connection);
  25 static long create_range(range_t *p_range, SQ_connection_t *sql_connection);
  26 
  27 /************************************************************
  28 * int NH_convert()                                          *
  29 *                                                           *
  30 * Converts space & nic_id into a database nic-handle        *
  31 *                                                           *
  32 *                                                           *
  33 * Returns:                                                  *
  34 * The size of the nic_handle in characters                  *
  35 *                                                           *
  36 ************************************************************/
  37 int NH_convert(char *nic, nic_handle_t *nh_ptr)
     /* [<][>][^][v][top][bottom][index][help] */
  38 {
  39   /* Check for special cases */
  40   /* Is is and AUTO nic-handle ? */
  41   if(nh_ptr->nic_id == AUTO_NIC_ID) return(-1);
  42   if(nh_ptr->space) nic+=sprintf(nic, "%s", nh_ptr->space);
  43   /* No nic-id ? */
  44   if(nh_ptr->nic_id != NULL_NIC_ID) nic+=sprintf(nic, "%ld", nh_ptr->nic_id);
  45   /* No source ? */
  46   if (nh_ptr->source) sprintf(nic, "%s", nh_ptr->source);
  47   return(1);
  48 }
  49 
  50 /************************************************************
  51 * int NH_parse()                                            *
  52 *                                                           *
  53 * Parse a nic handle as supplied by DBupdate                *
  54 * The format is: <space>[<nic_id>|*][SOURCE]                *
  55 * Also extracts nic_id and space for regular nic-handles    *
  56 *                                                           *
  57 *                                                           *
  58 * Returns:                                                  *
  59 * >0 - success                                              *
  60 *  0 - AUTO NIC                                             *
  61 * -1  - error (not defined and processed yet)               *
  62 *                                                           *
  63 ************************************************************/
  64 int NH_parse(char *nic, nic_handle_t **nh_ptr_ptr)
     /* [<][>][^][v][top][bottom][index][help] */
  65 {
  66 char *ptr;
  67 int res = 1;
  68 nic_handle_t *nh_ptr;
  69 
  70      if(!(nh_ptr=calloc(1, sizeof(nic_handle_t)))) die;
  71      
  72      ptr=nic;   
  73 
  74      /* extract space */
  75      while(isalpha((int)*ptr))ptr++;
  76      if(!(nh_ptr->space=malloc(ptr-nic+1))) die;
  77      strncpy(nh_ptr->space, nic, ptr-nic); *(nh_ptr->space+(ptr-nic))='\0';
  78 
  79      /* If there are no digits, then this is no nic-hdl */
  80      /* We reserve NULL_NIC_ID for such pretty identifiers */
  81      if(*ptr == '\0') {
  82        nh_ptr->nic_id=NULL_NIC_ID;
  83        nh_ptr->source=NULL;
  84      }
  85      else {
  86        /* Check if it is and AUTO nic */
  87        if (*ptr == '*') {
  88                /* For AUTO nic_id we reserve AUTO_NIC_ID */
  89                nh_ptr->nic_id=AUTO_NIC_ID;
  90                res=0;
  91                ptr++;
  92        } else {
  93          nic=ptr;
  94          /* convert digits (if any) and store first invalid characted in ptr */
  95          nh_ptr->nic_id=(int)strtol(nic, &ptr, 10);
  96          /* Check if there were any digits at all */
  97          if(ptr == nic) nh_ptr->nic_id=NULL_NIC_ID;
  98        }
  99        /* check if there is any suffix */
 100        if (*ptr == '\0') nh_ptr->source=NULL;
 101        /* Copy suffix into source */
 102        else {
 103          if(!(nh_ptr->source=malloc(strlen(ptr)+1))) die;
 104          strcpy(nh_ptr->source, ptr);
 105        }
 106      } 
 107      *nh_ptr_ptr=nh_ptr;
 108      return(res);
 109 }
 110 
 111 
 112 
 113 /************************************************************
 114 * int NH_check()                                            *
 115 *                                                           *
 116 * Check a NIC handle in the repository                      *
 117 *                                                           *
 118 *                                                           *
 119 * Returns:                                                  *
 120 *  1 - success                                              *
 121 *  0 - error(nic_id exists or space is fully occupied)      *
 122 * -1 - error (f.e. more than one object with the same PK)   *
 123 *                                                           *
 124 ************************************************************/
 125 int NH_check(nic_handle_t *nh_ptr, SQ_connection_t *sql_connection)
     /* [<][>][^][v][top][bottom][index][help] */
 126 {
 127 range_t range;
 128 long range_id;
 129 long nic_id=nh_ptr->nic_id;
 130 
 131 
 132   range.space=nh_ptr->space;
 133   if(nh_ptr->source)range.source=nh_ptr->source; else range.source="";
 134   
 135   if (nic_id == AUTO_NIC_ID) {
 136   /* NIC handle is an AUTO one */
 137   /* get first range (with min range_end) for a given space */
 138    range_id = get_min_range(&range, sql_connection); 
 139    if(range_id<0)  return(-1); /* in case of an error */
 140 
 141    if ( range_id==0 ) {
 142   /* Nothing found */
 143   /* Allocate a hic-hdl in a new space with the first range {0-1} in it*/
 144         nic_id=1;
 145    } else {
 146       if ( range.end == MAX_NIC_ID ) return(0); /* space is fully occupied  */
 147       /* attach to range and may be join with next */
 148        nic_id = range.end+1;
 149    }
 150   }
 151 /* if not AUTO */  
 152   else {
 153     range_id = get_range(nic_id, &range, sql_connection);
 154     if(range_id <0)  return(-1); /* in case of an error */
 155     if(range_id!=0)  return(0); /* this nic_id already exists */
 156   }
 157   nh_ptr->nic_id=nic_id;
 158  return(1); 
 159 }
 160 
 161 /************************************************************
 162 * long NH_free()                                             *
 163 *                                                           *
 164 * Delete a NIC handle from the repository                   *
 165 *                                                           *
 166 * To finalize changes make commit/rollback                  *
 167 *                                                           *
 168 * Returns:                                                  *
 169 *  1 - success                                              *
 170 *  0 - error (range is not founnd)                          *
 171 * -1 - error (f.e. more than one object with the same PK)   *
 172 *                                                           *
 173 ************************************************************/
 174 int NH_free(nic_handle_t *nh_ptr, SQ_connection_t *sql_connection)
     /* [<][>][^][v][top][bottom][index][help] */
 175 {
 176 range_t range;
 177 long range_id;
 178 int old_start;
 179 long nic_id=nh_ptr->nic_id;
 180 
 181 
 182   range.space=nh_ptr->space;
 183   if(nh_ptr->source)range.source=nh_ptr->source; else range.source="";
 184   
 185   /* Search for the range containing the nic-handle */
 186   range_id = get_range(nic_id, &range, sql_connection);
 187   /* If range is not found or an error occcured - return */
 188   if(range_id==0) { return(0); }
 189   if(range_id<0)  { return(-1); }
 190   
 191   if(nic_id == range.start) {
 192   /* update range start and may be detele range and space */
 193    range.start+=1;
 194    range_id=update_range(range_id, &range, sql_connection);
 195    if(range_id<=0) {  return(-1); }
 196   }
 197   else if(nic_id == range.end) { 
 198   /* update range end and may be detele range and space */
 199          range.end-=1;
 200          range_id=update_range(range_id, &range, sql_connection);
 201          if(range_id<=0) {  return(-1); }
 202   }
 203   else { 
 204        /* split the range into two */ 
 205        /* shrink the old one */
 206          old_start=range.start;
 207          range.start=nic_id+1;
 208          range_id=update_range(range_id, &range, sql_connection);
 209          if(range_id<=0) { return(-1); }
 210        /* create a new one */
 211          range.start=old_start;
 212          range.end=nic_id-1;
 213          range_id=create_range(&range, sql_connection);
 214          if(range_id<=0) {  return(-1); }
 215   }
 216   
 217   return(1);
 218 }
 219 
 220 
 221 /************************************************************
 222 * int NH_register()                                         *
 223 *                                                           *
 224 * Get a NIC handle from the repository                      *
 225 *                                                           *
 226 *                                                           *
 227 * Returns:                                                  *
 228 * 1 - success                                               *
 229 * 0  - nic_id already exists or space is fully occupied     *
 230 * -1 - error (f.e. more than one object with the same PK)   *
 231 *                                                           *
 232 ************************************************************/
 233 int NH_register(nic_handle_t *nh_ptr, SQ_connection_t *sql_connection)
     /* [<][>][^][v][top][bottom][index][help] */
 234 {
 235 range_t range;
 236 long range_id;
 237 long nic_id=nh_ptr->nic_id;
 238 
 239 
 240 
 241 
 242  /* Yiu should check for nh first for AUTO nic-handles */
 243   if (nic_id == AUTO_NIC_ID) { return(0); };
 244 
 245   range.space=nh_ptr->space;
 246   if(nh_ptr->source)range.source=nh_ptr->source; else range.source="";
 247 
 248   range_id = get_range(nic_id, &range, sql_connection);
 249   if(range_id <0)  { return(-1); } /* in case of an error */
 250   if(range_id!=0)  { return(0); } /* this nic_id already exists */
 251  
 252   /* check if we can attach to existing next range */
 253   range_id = get_range(nic_id+1, &range, sql_connection);
 254   if(range_id <0)  { return(-1); } /* in case of an error */
 255 
 256     if( range_id>0 ) { 
 257     /* attach to range and may be join with previous */ 
 258      range.start-=1;
 259      range_id=update_range(range_id, &range, sql_connection);
 260      if(range_id<=0) { return(-1); }
 261     }
 262     else {
 263      /* check if we can attach to existing previous range */
 264       if(nic_id>0) range_id = get_range(nic_id-1, &range, sql_connection);
 265       else range_id=0; /* there is no previous range in this case (nic_id==0) */
 266       if(range_id <0)  { return(-1); } /* in case of an error */
 267       if( range_id>0 ) { 
 268       /* attach to range and may be join with next */
 269        range.end+=1;
 270        range_id=update_range(range_id, &range, sql_connection);
 271        if(range_id<=0) { return(-1); }
 272       }
 273       else {
 274        /* If we cannot attach to any existing range - create new {nic_id-nic_id} */
 275        range.end=range.start=nic_id;
 276        range_id=create_range(&range, sql_connection);
 277        if(range_id <=0)  { return(-1); } /* in case of an error */
 278       }
 279     }  
 280  return(1);
 281 }
 282 
 283 /*
 284  Free nic_handle_t structure 
 285  */
 286 void free_nh(nic_handle_t *nh_ptr)
     /* [<][>][^][v][top][bottom][index][help] */
 287 {
 288  if(nh_ptr){
 289    if(nh_ptr->space)free(nh_ptr->space);
 290    if(nh_ptr->source)free(nh_ptr->source);
 291    free(nh_ptr);
 292  }
 293 }
 294 
 295 
 296 /************************************************************
 297 * long get_range()                                          *
 298 *                                                           *
 299 * Searches for the range of the space containing            *
 300 * the specified nic_id                                      *
 301 *                                                           *
 302 * To request to search for the firt (min) range, nic_id     *
 303 * should be set to -1.                                       *
 304 *                                                           *
 305 * Returns:                                                  *
 306 * >0 - range exists, returns range_id                       *
 307 * 0  - range does not exist                                 *
 308 * -1 - DB error (f.e. more than one object with the same PK)*
 309 *                                                           *
 310 * **********************************************************/
 311 static long get_range(long nic_id, range_t *prange, SQ_connection_t *sql_connection)
     /* [<][>][^][v][top][bottom][index][help] */
 312 {
 313 SQ_result_set_t *sql_result;
 314 SQ_row_t *sql_row;
 315 char *sql_str;
 316 GString *query;
 317 long range_id=0;
 318 int sql_err;
 319 
 320  if ((query = g_string_sized_new(STR_L)) == NULL){ 
 321   fprintf(stderr, "E: cannot allocate gstring\n"); 
 322   return(-1); 
 323  }
 324  
 325 /* Define row numbers in the result of the query */
 326 #define RANGE_ID 0
 327 #define RANGE_START 1
 328 #define RANGE_END 2
 329  
 330  if (nic_id<0) {
 331   /* requesting the first (min) range */
 332   g_string_sprintf(query, "SELECT range_id, range_start, range_end " 
 333                           "FROM nic_hdl "
 334                           "WHERE space='%s' "
 335                           "AND source='%s' "
 336                           "AND (range_start=0 "
 337                           "OR  range_start=1) ",
 338                           prange->space, prange->source);
 339  } else {
 340 
 341   g_string_sprintf(query, "SELECT range_id, range_start, range_end " 
 342                           "FROM nic_hdl "
 343                           "WHERE space='%s' "
 344                           "AND source='%s' "
 345                           "AND range_start<=%ld "
 346                           "AND range_end>=%ld ",
 347                           prange->space, prange->source, nic_id, nic_id);
 348  }
 349         
 350 /* execute query */
 351 /* fprintf(stderr, "get_range[%s]\n", query->str); */
 352  sql_err=SQ_execute_query(sql_connection, query->str, &sql_result);
 353  g_string_free(query, TRUE);
 354  
 355  if(sql_err) {
 356    fprintf(stderr,"ERROR: %s\n", SQ_error(sql_connection));
 357    return(-1);
 358  }
 359 
 360  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
 361 /* Object exists */
 362    sql_str = SQ_get_column_string(sql_result, sql_row, RANGE_ID);
 363    if (sql_str != NULL) {
 364      range_id = atol(sql_str);
 365      free(sql_str);
 366    }
 367    sql_str = SQ_get_column_string(sql_result, sql_row, RANGE_START);
 368    if (sql_str != NULL) {
 369      prange->start = atoi(sql_str);
 370      free(sql_str);
 371    }
 372    sql_str = SQ_get_column_string(sql_result, sql_row, RANGE_END);
 373    if (sql_str != NULL) {
 374      prange->end = atoi(sql_str);
 375      free(sql_str);
 376    }
 377 
 378 /* We must process all the rows of the result */
 379 /* otherwise we'll have them as part of the next qry */      
 380    while ( (sql_row = SQ_row_next(sql_result)) != NULL) range_id=-1;
 381  } else 
 382       range_id=0;  // object does not exist
 383    
 384  if(sql_result)SQ_free_result(sql_result);
 385  return(range_id);
 386 }
 387 
 388 
 389 
 390 
 391 /************************************************************
 392 * long update_range()                                       *
 393 *                                                           *
 394 * Updates the range by changing the boundaries              *
 395 * Deletes the range if nothing left                         *
 396 * Merges with neighbor ranges if there is no gap between    *
 397 *                                                           *
 398 * We never update range. We create a new one with specified * 
 399 * limits and mark old one(s) for deletion, so that we can   *
 400 * make commit/rollback properly. This is possible as the    * 
 401 * primary keys are (range_id, range_start, range_end)       *
 402 *                                                           *
 403 * To finalize changes make commit/rollback                  *
 404 *                                                           *
 405 * Returns:                                                  *
 406 * >0 - returns range_id on success                          *
 407 * -1 - error (f.e. more than one object with the same PK)   *
 408 *                                                           *
 409 ************************************************************/
 410               
 411 static long update_range(long range_id, range_t *p_newrange, SQ_connection_t *sql_connection)
     /* [<][>][^][v][top][bottom][index][help] */
 412 {
 413 GString *query;
 414 range_t range;
 415 long prev_range_id, next_range_id;
 416 int num;
 417 int sql_err;
 418 
 419 /* Allocate memory */
 420  if ((query = g_string_sized_new(STR_L)) == NULL){ 
 421   fprintf(stderr, "E: cannot allocate gstring\n"); 
 422   return(-1); 
 423  }
 424 
 425 /* Do range check */
 426  if (( p_newrange->end > MAX_RANGE ) || ( p_newrange->start < MIN_RANGE )) return(-1);
 427 
 428 /* Check if the range collapses */
 429  if ( p_newrange->end < p_newrange->start ) {
 430  /* then delete the range */  
 431  /* Do this by marking the range for deletion for further commit/rollback */
 432    g_string_sprintf(query, "DELETE FROM nic_hdl "
 433                            "WHERE range_id=%ld ",
 434                            range_id);
 435    
 436 /*   fprintf(stderr, "update_range[%s]\n", query->str); */
 437    sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
 438    if(sql_err) {
 439     /* An error occured */
 440     g_string_free(query, TRUE);
 441     return(-1);
 442    }
 443    num = mysql_affected_rows(sql_connection); 
 444    /* this should not happen */
 445    if(num==0) die;
 446  
 447  }
 448  else {
 449   /* update the range for the same space/source */
 450   range.space=p_newrange->space;
 451   range.source=p_newrange->source; 
 452   /* Check if we can join with previous range of the same space */
 453   prev_range_id=get_range(p_newrange->start-1, &range, sql_connection);
 454   /* Check if such range exists and it is not ours (this happens when we are shrinking */
 455   if((prev_range_id>0) && (prev_range_id!=range_id)) {
 456    /* acquire the previous range */
 457    /* mark it for deletion for commit/rollback */
 458    g_string_sprintf(query, "DELETE FROM nic_hdl "
 459                            "WHERE range_id=%ld ",
 460                            prev_range_id);
 461 
 462 /*    fprintf(stderr, "update_range[%s]\n", query->str); */
 463    sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
 464    if(sql_err) {
 465     /* An error occured */
 466     g_string_free(query, TRUE);
 467     return(-1);
 468    }
 469    num = mysql_affected_rows(sql_connection); 
 470    /* this should not happen */
 471    if(num==0) die;
 472    
 473    /* expand the boundaries */
 474    p_newrange->start=range.start;
 475   }
 476 
 477 /* Check if we can join with next range of the same space */
 478   next_range_id=get_range(p_newrange->end+1, &range, sql_connection);
 479   /* Check if such range exists and it is not ours (this happens when we are shrinking) */
 480   if((next_range_id>0) && (next_range_id!=range_id)) {
 481    /* acquire the next range */
 482    /* mark it for deletion for commit/rollback */
 483    g_string_sprintf(query, "DELETE FROM nic_hdl "
 484                            "WHERE range_id=%ld ",
 485                            next_range_id);
 486 
 487 /*   fprintf(stderr, "update_range[%s]\n", query->str); */
 488    sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
 489    if(sql_err) {
 490     /* An error occured */
 491     g_string_free(query, TRUE);
 492     return(-1);
 493    }
 494    num = mysql_affected_rows(sql_connection); 
 495    /* this should not happen */
 496    if(num==0) die;
 497    
 498    /* expand the boundaries */
 499    p_newrange->end=range.end;
 500   }
 501  
 502 /* Now make a larger range. Mark it for commit/rollback */ 
 503    g_string_sprintf(query, "UPDATE nic_hdl "
 504                            "SET range_start=%ld, range_end=%ld "
 505                            "WHERE range_id=%ld",
 506                            p_newrange->start, p_newrange->end, range_id);
 507 
 508 /*   fprintf(stderr, "update_range[%s]\n", query->str); */
 509    sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
 510    if(sql_err) {
 511     /* An error occured */
 512     g_string_free(query, TRUE);
 513     return(-1);
 514    }
 515    num = mysql_affected_rows(sql_connection); 
 516    /* this should not happen */
 517    if(num==0) die;
 518  } /* update the range */
 519 
 520  g_string_free(query, TRUE);
 521  return (range_id);
 522 }
 523                
 524 /************************************************************
 525 * long create_range()                                       *
 526 *                                                           *
 527 * Creates a new range in a given name space                 *
 528 *                                                           *
 529 * To finalize changes make commit/rollback                  *
 530 *                                                           *
 531 * Returns:                                                  *
 532 * >0 - returns range_id on success                          *
 533 * -1 - error (f.e. more than one object with the same PK)   *
 534 *                                                           *
 535 ************************************************************/
 536                 
 537 static long create_range(range_t *p_range, SQ_connection_t *sql_connection)
     /* [<][>][^][v][top][bottom][index][help] */
 538 {
 539 GString *query;
 540 int sql_err, num;
 541 
 542  /* Allocate memory */
 543  if ((query = g_string_sized_new(STR_L)) == NULL){ 
 544   fprintf(stderr, "E: cannot allocate gstring\n"); 
 545   return(-1); 
 546  }
 547  
 548  
 549  g_string_sprintf(query, "INSERT nic_hdl "
 550                          "SET space='%s', source='%s', range_start=%ld, range_end=%ld ",
 551                           p_range->space, p_range->source, p_range->start, p_range->end);
 552 
 553 /* fprintf(stderr, "create_range[%s]\n", query->str); */
 554  sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
 555  g_string_free(query, TRUE);
 556   
 557    if(sql_err) {
 558     /* An error occured */
 559     return(-1);
 560    }
 561    num = mysql_affected_rows(sql_connection); 
 562    /* this should not happen */
 563    if(num==0) die;
 564  return(mysql_insert_id(sql_connection));
 565 }
 566 

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