modules/ud/ud_process_stream.c

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

FUNCTIONS

This source file includes following functions.
  1. ud_parse_init
  2. ud_parse_free
  3. line_continuation
  4. split_attribute
  5. reorder_attributes
  6. each_attribute_print
  7. print_object
  8. escape_apostrophes
  9. line_type
  10. UD_parse_object
  11. report_transaction
  12. process_nrtm
  13. process_updates
  14. process_transaction
  15. UD_process_stream

   1 /***************************************
   2   $Revision: 1.44 $
   3 
   4   Functions to process data stream( file, network socket, etc.)
   5 
   6   Status: NOT REVUED, NOT TESTED
   7 
   8  Author(s):       Chris Ottrey, Andrei Robachevsky
   9 
  10   ******************/ /******************
  11   Modification History:
  12         andrei (17/01/2000) Created.
  13   ******************/ /******************
  14   Copyright (c) 2000                              RIPE NCC
  15  
  16   All Rights Reserved
  17   
  18   Permission to use, copy, modify, and distribute this software and its
  19   documentation for any purpose and without fee is hereby granted,
  20   provided that the above copyright notice appear in all copies and that
  21   both that copyright notice and this permission notice appear in
  22   supporting documentation, and that the name of the author not be
  23   used in advertising or publicity pertaining to distribution of the
  24   software without specific, written prior permission.
  25   
  26   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  27   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  28   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  29   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  30   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  31   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  32  ***************************************/
  33 #include <sys/types.h>
  34 #include <sys/socket.h>
  35 #include <netdb.h>
  36 #include <arpa/inet.h>
  37 #include <unistd.h>
  38 #include <sys/stat.h>
  39 #include <fcntl.h>
  40 #include <string.h>
  41 #include "constants.h"
  42 #include "query_command.h"
  43 #include "ud.h"
  44 #include "ud_int.h"
  45 #include "ud_tr.h"
  46 #include "timediff.h"
  47  
  48 typedef enum _Line_Type_t {
  49  LINE_ATTRIBUTE,
  50  LINE_COMMENT,
  51  LINE_EMPTY,
  52  LINE_EOF,
  53  LINE_ADD,
  54  LINE_UPD,
  55  LINE_DEL,
  56  LINE_OVERRIDE_ADD,
  57  LINE_OVERRIDE_UPD,
  58  LINE_OVERRIDE_DEL,
  59  LINE_ACK
  60 } Line_Type_t;
  61 
  62 /* Maximum number of objects(serials) we can consume at a time */
  63 #define SBUNCH 1000
  64 
  65 static int report_transaction(Transaction_t *tr, long transaction_id, Log_t *log, ut_timer_t *psotime, char *reason);
  66 static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, int operation);
  67 static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, int operation);
  68 static int process_transaction(UD_stream_t *ud_stream,Object_t *obj,char *object_name,nic_handle_t *nh, int operation, long transaction_id);
  69                                                                                                 
  70 /* Delimiters that separate list members, both RPS(,) and legacy( ) */
  71 #define ATTR_DELIMITERS " ,"
  72 
  73 
  74 void ud_parse_init(Obj_parse_t *parse){
     /* [<][>][^][v][top][bottom][index][help] */
  75      bzero(parse, sizeof(Obj_parse_t));
  76      parse->start_object=1;     
  77 }
  78 
  79 void ud_parse_free(Obj_parse_t *parse){
     /* [<][>][^][v][top][bottom][index][help] */
  80      free(parse->object_name);
  81 }
  82 
  83 
  84 
  85 static int line_continuation(char *line)
     /* [<][>][^][v][top][bottom][index][help] */
  86 {
  87  switch(*line) {
  88         case ' ':
  89         case '\t':
  90         case '+':
  91                  return(1); /* these indicate line continuation */
  92         default: return(0); 
  93  }
  94 
  95 }
  96 /************************************************************
  97 *                                                           *
  98 * The function to splits attribute value into multiple      *
  99 * words and appends them as attr_type - attr_valu pairs     *
 100 * to the attr_list                                          *
 101 *                                                           *
 102 *                                                           *
 103 ************************************************************/
 104 static GSList *split_attribute(GSList *attr_list, A_Type_t attr_type, char *attr_value){
     /* [<][>][^][v][top][bottom][index][help] */
 105 char *token;
 106 char *split;
 107 char *value, *n;
 108 Attribute_t *attr_split;
 109 GSList *the_list = attr_list;
 110 
 111   /* check for line continuation (+) */
 112   if (strncmp(attr_value, "+", 1) == 0) attr_value++;
 113   /* check for end-of-line comments */
 114   n = index(attr_value, '#');
 115       /* if there is no comment check for trailing \n */
 116   if(n == NULL) n = index(attr_value, '\n');
 117   /* now copy the clean value into the attribute */
 118   if(n == NULL) value = g_strdup(attr_value); 
 119   else  value = g_strndup(attr_value, (n - attr_value));
 120      
 121   token=value;
 122   while((split=strsep(&token, ATTR_DELIMITERS))){
 123      attr_split = attribute_new1(attr_type, split);
 124      if (attr_split) the_list = g_slist_append(the_list, attr_split);
 125   }
 126   free(value);
 127  return(the_list);
 128 }
 129 
 130 /************************************************************
 131 *                                                           *
 132 * The function to reorder attributes in the List            *
 133 * nic-hdl and mnt-by should come first                      *
 134 *                                                           *
 135 * should return 0 if they are equal, a negative value if    * 
 136 * the first element comes before the second, or a positive  *
 137 * value if the first element comes after the second         *
 138 *                                                           *
 139 ************************************************************/
 140 static gint reorder_attributes(const void *element1, const void *element2)
     /* [<][>][^][v][top][bottom][index][help] */
 141 {
 142 Attribute_t *attr1 = (Attribute_t *)element1;
 143 Attribute_t *attr2 = (Attribute_t *)element2;
 144 gint order = -1;
 145   
 146   if(attr2->type == A_MB) order= 1;
 147   if(attr1->type == A_MB) order= -1;
 148   if(attr2->type == A_NH) order= 1;
 149   if(attr1->type == A_NH) order= -1;
 150 
 151   return(order);
 152 
 153 }
 154 
 155 /* XXX */
 156 static void each_attribute_print(void *element_data, void *tr_ptr)
     /* [<][>][^][v][top][bottom][index][help] */
 157 {
 158 
 159 Attribute_t *attr = (Attribute_t *)element_data;
 160 
 161  fprintf(stderr, "[%d|%s]\n", attr->type, attr->value);
 162 
 163 }
 164 
 165 /* XXX */
 166 static void print_object(Object_t *obj)
     /* [<][>][^][v][top][bottom][index][help] */
 167 {
 168   g_slist_foreach(obj->attributes, each_attribute_print, NULL); 
 169   fprintf(stderr, ">>>>>\n%s\n", obj->object->str);
 170 }
 171 
 172 
 173 /******************************************************************
 174 * GString *escape_apostrophes()                                   *
 175 * Escapes apostrophes in the text so they do not confuse printf   *
 176 * functions and don't corrupt SQL queries                         *
 177 *                                                                 *
 178 * *****************************************************************/
 179 GString *escape_apostrophes(GString *text) {
     /* [<][>][^][v][top][bottom][index][help] */
 180   int i;
 181   for (i=0; i < text->len; i++) {
 182     if ((text->str[i] == '\'') || (text->str[i] == '\\')) {
 183       text = g_string_insert_c(text, i, '\\');
 184       i++;
 185     }
 186   }
 187  return(text); 
 188 } /* escape_apostrophes() */
 189 
 190 
 191 /******************************************************************
 192 * Line_Type_t line_type(e)                                        *
 193 * Determines the line type analysing the first letters            *
 194 *                                                                 *
 195 * ****************************************************************/
 196 static Line_Type_t line_type(const char *line, long *transaction_id) {
     /* [<][>][^][v][top][bottom][index][help] */
 197 
 198   if (strncmp(line, "# EOF", 4) == 0) return(LINE_EOF);
 199   if (strncmp(line, "#", 1) == 0)     return(LINE_COMMENT);
 200   if (strcmp(line, "\n") == 0)        return(LINE_EMPTY);
 201  
 202   if (strncmp(line, "ACK", 3) == 0) {
 203     *transaction_id = atol(line+3);       
 204     return(LINE_ACK);
 205   }
 206   if (strncmp(line, "ADD_OVERRIDE", 12) == 0) {
 207     *transaction_id = atol(line+12);      
 208     return(LINE_OVERRIDE_ADD);
 209   }
 210   if (strncmp(line, "UPD_OVERRIDE", 12) == 0) {
 211     *transaction_id = atol(line+12);      
 212     return(LINE_OVERRIDE_UPD);
 213   }
 214   if (strncmp(line, "DEL_OVERRIDE", 12) == 0) {
 215     *transaction_id = atol(line+12);      
 216     return(LINE_OVERRIDE_DEL);
 217   }
 218  
 219   if (strncmp(line, "ADD", 3) == 0) {
 220     *transaction_id = atol(line+3);
 221     return(LINE_ADD);
 222   }
 223   if (strncmp(line, "UPD", 3) == 0) {
 224     *transaction_id = atol(line+3);
 225     return(LINE_UPD);
 226   }
 227   if (strncmp(line, "DEL", 3) == 0) {
 228     *transaction_id = atol(line+3); 
 229     return(LINE_DEL);
 230   }
 231  
 232 /* Otherwise this is an attribute */  
 233     return(LINE_ATTRIBUTE);
 234 
 235 } /* line_type() */
 236 
 237 /******************************************************************
 238 * Object_t *UD_parse_object()                                     *
 239 *                                                                 *
 240 * Parses the object accepting line by line                        *
 241 *                                                                 *
 242 * ****************************************************************/
 243 Object_t *UD_parse_object(SQ_connection_t *sql_connection, Obj_parse_t *parse, char *line_buff)
     /* [<][>][^][v][top][bottom][index][help] */
 244 {
 245 GString *g_line_buff;
 246 Attribute_t *class_attr, *attr;
 247 char *a_value, *ptr;
 248 char nic[MAX_NH_LENGTH];
 249  
 250  
 251   if (parse->start_object == 1) {
 252    parse->obj = object_new(line_buff);
 253   }
 254   if (parse->obj) {
 255 
 256     if ((g_line_buff = g_string_sized_new(STR_XXL)) == NULL){ 
 257       ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring");
 258       die; 
 259     }
 260   
 261    g_string_sprintf(g_line_buff, "%s", line_buff);
 262    /* escape apostrophes in the input line */
 263    g_line_buff=escape_apostrophes(g_line_buff);
 264    
 265    if(parse->start_object == 1){
 266    /* If this is the first attribute(==object name/type) */   
 267     parse->start_object=0;
 268     parse->object_name = g_strndup(g_line_buff->str, g_line_buff->len);
 269      *(parse->object_name+g_line_buff->len-1)='\0';
 270     
 271     
 272   /* Create an attribute - the first one determines a class */
 273     parse->class_attr_list=NULL; /* Initialize the list that will hold splitted class attribute */
 274     class_attr = attribute_new(g_line_buff->str);
 275     if (class_attr == NULL) die; /* Should not happen */
 276     parse->a_type = class_attr->type;
 277     if((class_attr->type==A_PN)||(class_attr->type==A_RO)){
 278    /* split names */  
 279       parse->class_attr_list = split_attribute(parse->class_attr_list, class_attr->type, class_attr->value);  
 280       attribute_free(class_attr, NULL);
 281     } else {
 282       parse->class_attr_list = g_slist_append(parse->class_attr_list, class_attr); 
 283     }
 284     parse->current_attr_list = parse->class_attr_list;
 285       /* do nothing more with this attribute - we will prepend it at the end */
 286    }
 287    else { /* this is not a "class" attribute - we are inside the object */
 288      attr = attribute_new(g_line_buff->str);
 289         
 290      if (attr) { /* this is a known attribute */
 291        parse->a_type=attr->type;   
 292        a_value=attr->value;
 293        /* Now the current list is the attribute list */
 294        parse->current_attr_list = parse->obj->attributes;
 295        if(parse->a_type==A_NH) {
 296           /*  Parse the string into nh structure */
 297           /*  In case of an AUTO NIC handle check the ID in the database */
 298           /* Possible errors leave to core processing */
 299           if(NH_parse(attr->value, &parse->nh_ptr) == 0) { 
 300 /*           ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s parsing nic handle: [%s]", UD_TAG, attr->value);*/
 301            /* Check if we can allocate it */  
 302             if(NH_check(parse->nh_ptr, sql_connection)>0){
 303             /* Convert nh to the database format */  
 304               NH_convert(nic, parse->nh_ptr);
 305 /*           ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s parsed and converted nic handle: [%s]", UD_TAG, nic); */
 306               /* Replace NIC handle in the string which is copied to the text object */
 307               sprintf(line_buff, g_line_buff->str);
 308               ptr = strstr(line_buff, attr->value);
 309               /* parse new attribute string */
 310               strcpy(ptr, nic);
 311               g_string_sprintf(g_line_buff, line_buff);
 312               g_string_sprintfa(g_line_buff, "\n");
 313               /* Update the attribute */
 314               attribute_upd(attr, attr->type, nic); 
 315             }
 316           }
 317        } /* NHR stuff */
 318      }
 319      else { /* this is line continuation or unknown attribute */
 320        a_value=g_line_buff->str;
 321        /* if it is not line continuation - this is an unknown attribute - just skip it*/
 322        if(!line_continuation(g_line_buff->str))parse->a_type=-1; 
 323      }
 324      
 325      
 326      if (parse->a_type>=0) { /* This indicates that the input line contains the value of the attribute */
 327          switch (parse->a_type) {
 328             /*these attributes may appear several on the line - split them*/   
 329             case A_PN: /* person */
 330             case A_RO: /* role */
 331             case A_MR: /* mbrs-by-ref */
 332             case A_MB: /* mnt-by */
 333             case A_MO: /* member-of */
 334             case A_SD: /* sub-dom */
 335             case A_RZ: /* rev-srv */
 336             case A_NS: /* nserver */
 337                 parse->current_attr_list = split_attribute(parse->current_attr_list, parse->a_type, a_value);
 338                 if (attr) attribute_free(attr, NULL);
 339              attr=NULL;
 340              break; 
 341             default: break;  
 342          }
 343          if(attr)parse->obj->attributes = g_slist_append(parse->obj->attributes, attr);  
 344      }
 345    } /* if not start_object (not the first/class attribute) */
 346    /* copy the line into object no matter whether it is an attribute or not (continualtion, etc.) */
 347    g_string_sprintfa(parse->obj->object, "%s", g_line_buff->str);
 348    g_string_free(g_line_buff, TRUE);
 349   }/* if (obj) */
 350     return(parse->obj);
 351 }
 352 
 353 /******************************************************************
 354 * report_transaction()                                            *
 355 *                                                                 * 
 356 * Prints error report to the log                                  *
 357 *                                                                 *
 358 * reason - additional message that will be included               *
 359 *                                                                 *
 360 * *****************************************************************/
 361 static int report_transaction(Transaction_t *tr, long transaction_id,  Log_t *log, ut_timer_t *psotime, char *reason)
     /* [<][>][^][v][top][bottom][index][help] */
 362 {
 363 int result=0;
 364 ut_timer_t fotime;
 365 float timediff;
 366 const char *class_name = DF_class_type2name(tr->class_type);
 367 char *primary_key = tr->K->str;
 368 
 369 
 370  /* calculate statistics */
 371   UT_timeget(&fotime);
 372   timediff = UT_timediff(psotime, &fotime);
 373  
 374  if(tr->succeeded==0) {
 375   result=tr->error;
 376   log->num_failed++;
 377   ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] %.2fs FAILED [%s:%s][%s]", transaction_id, timediff, class_name, primary_key, reason);
 378 /*  ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] object: FAILED [%s][%s](%d/%d)", transaction_id, , reason, log->num_failed, (log->num_failed)+(log->num_ok)); */
 379   if(result & ERROR_U_OBJ) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: referential integrity error", transaction_id);
 380   if(result & ERROR_U_AUT) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: authentication error", transaction_id);
 381   if(result & ERROR_U_BADOP) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: unsupported operation", transaction_id);
 382   if(result & ERROR_U_COP) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: conflicting operation", transaction_id);
 383   if(result & ERROR_U_NSUP) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: this type is not supported", transaction_id);
 384   ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] object: details [%s]", transaction_id, (tr->error_script)->str);
 385   result=1; /* # of failures */
 386  }
 387  else {
 388   result=0;
 389   log->num_ok++;
 390 /*  ER_inf_va(FAC_UD, ASP_UD_OBJ, "[%ld] object: OK     [%s](%d/%d)", transaction_id, obj_name, log->num_ok, (log->num_failed)+(log->num_ok)); */
 391   ER_inf_va(FAC_UD, ASP_UD_OBJ, "[%ld] %.2fs OK     [%s:%s]", transaction_id, timediff, class_name, primary_key);
 392   ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] object: details [%s]", transaction_id, (tr->error_script)->str);
 393  }
 394                                                                                                                                                
 395  return(result);
 396 }/* report_transaction() */
 397 
 398 
 399 
 400 /************************************************************
 401 * process_nrtm()                                            *
 402 *                                                           *
 403 * Process object in NRTM client mode                        *
 404 *                                                           *
 405 * nrtm - pointer to _nrtm structure                         *
 406 * log - pointer to Log_t structure                          *
 407 * object_name - name of the object                          * 
 408 * operation - operation code (OP_ADD/OP_DEL)                *
 409 *                                                           *
 410 * Returns:                                                  *
 411 * 1  - okay                                                 *
 412 * <0 - error                                                *
 413 *                                                           *
 414 ************************************************************/
 415 
 416 static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, int operation)
     /* [<][>][^][v][top][bottom][index][help] */
 417 {
 418 int result=0;
 419 int dummy=0;
 420 struct _nrtm *nrtm = ud_stream->nrtm;
 421 long serial_id;
 422 Log_t *log_ptr= &(ud_stream->log);
 423 ut_timer_t sotime;
 424 
 425     /* Start timer for statistics */
 426     UT_timeget(&sotime);
 427 
 428   /* We allow NRTM updates for some inconsistent objects                  */
 429   /* One of the examples is reference by name which looks like nic-handle */
 430   /* For this purpose we allow dummy creation when updating an object     */
 431   /* We also check for dummy allowance when deleting an object            */
 432   /* this is done to allow deletion of person objects referenced by name  */
 433 
 434   tr->mode|=B_DUMMY;
 435   
 436   switch (operation) {
 437   
 438   case OP_ADD:
 439     if(nrtm->tr){ /* DEL ADD => saved*/
 440       if(tr->object_id==0) { 
 441         /* object does not exist in the DB */      
 442         /* delete the previous(saved) object*/
 443         object_process(nrtm->tr); 
 444         /* create DEL serial */
 445         UD_lock_serial(nrtm->tr);
 446         serial_id = UD_create_serial(nrtm->tr);
 447         CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr); 
 448         UD_commit_serial(nrtm->tr);
 449         UD_unlock_serial(nrtm->tr);
 450         /* Mark TR as clean */
 451         TR_mark_clean(nrtm->tr);
 452         /* log the transaction */
 453         result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
 454         
 455         object_free(nrtm->tr->object);
 456         transaction_free(nrtm->tr); nrtm->tr=NULL;
 457         
 458         /* Create an object and update NHR */
 459         tr->action=(TA_CREATE | TA_UPD_NHR);
 460         /* restart the timer for statistics */
 461         UT_timeget(&sotime);
 462         object_process(tr); /* create a new one*/
 463         /* create ADD serial */
 464         UD_lock_serial(tr);
 465         serial_id = UD_create_serial(tr); 
 466         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 467         UD_commit_serial(tr);
 468         UD_unlock_serial(tr);
 469         /* Mark TR as clean */
 470         TR_mark_clean(tr);
 471         /* log the transaction */
 472         result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD: cannot create new object");
 473       }
 474       else { 
 475       /* object already exists in the DB - update or dummy replacement*/
 476         /*compare the two, may be we may collapse operations*/
 477         if(tr->object_id==nrtm->tr->object_id) {
 478           /* DEL-ADD ->> UPDATE */ 
 479           object_free(nrtm->tr->object);
 480           transaction_free(nrtm->tr); nrtm->tr=NULL;
 481           tr->action=TA_UPD_CLLPS;
 482           object_process(tr);
 483 /*          report_transaction(tr, log_ptr, object_name,"NRTM:upd");
 484           result=report_transaction(tr, log_ptr, object_name,"NRTM:upd"); */
 485           /* create DEL+ADD serial records */
 486           UD_lock_serial(tr);
 487           tr->action=TA_DELETE; serial_id = UD_create_serial(tr);
 488           result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:DEL(UPD): cannot update an object");
 489 
 490           /* restart the timer for statistics */
 491           UT_timeget(&sotime);
 492           tr->sequence_id++;
 493           tr->action=TA_CREATE; serial_id = UD_create_serial(tr);
 494           CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 495           UD_commit_serial(tr);
 496           UD_unlock_serial(tr);
 497           /* Mark TR as clean */
 498           TR_mark_clean(tr);
 499           result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD(UPD): cannot update an object");
 500         }
 501         else { /* this should be a dummy object in the database(that we are going to replace with the real one */
 502         /* or an interleaved operation*/
 503           object_process(nrtm->tr); /* delete the previous(saved) object*/
 504           /* create a DEL serial record */
 505           UD_lock_serial(nrtm->tr);
 506           serial_id = UD_create_serial(nrtm->tr); 
 507           CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
 508           UD_commit_serial(nrtm->tr);
 509           UD_unlock_serial(nrtm->tr);
 510           /* Mark TR as clean */
 511           TR_mark_clean(nrtm->tr);
 512 /*        result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");*/
 513           /* log the transaction */
 514           result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
 515 
 516 
 517           object_free(nrtm->tr->object);
 518           transaction_free(nrtm->tr); nrtm->tr=NULL;
 519 
 520           /* restart the timer for statistics */
 521           UT_timeget(&sotime);
 522           
 523           tr->action=TA_UPDATE;
 524           /* check if we are replacing a dummy object */
 525           dummy=isdummy(tr);
 526           /* If we are replacing dummy with a real object update NHR */
 527           if(dummy==1) tr->action = (TA_UPD_NHR | TA_UPD_DUMMY);
 528 /*        fprintf(stderr,"UPDATE next(dummy)\n"); */
 529           object_process(tr); /* create a new one*/
 530 /*          result=report_transaction(tr, log_ptr, object_name, "NRTM:ADD:While creating new"); */
 531           /* For serials this is CREATE operation. Increase sequence to have it correct in serals */
 532           if(dummy==1) { tr->action=TA_CREATE; tr->sequence_id++; } 
 533           /* create ADD serial record */
 534           UD_lock_serial(tr);
 535           serial_id = UD_create_serial(tr); 
 536           CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 537           UD_commit_serial(tr);
 538           UD_unlock_serial(tr);
 539           /* Mark TR as clean */
 540           TR_mark_clean(tr);
 541           /* log the transaction */
 542           result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD: cannot create new object");
 543 
 544         }
 545       }
 546     }
 547     else { /* ADD ADD =>brand new object*/
 548       if(tr->object_id==0) {
 549 /*      fprintf(stderr,"CREATE new\n");*/
 550         /* Create an object and update NHR */
 551         tr->action=(TA_CREATE | TA_UPD_NHR);
 552         object_process(tr);
 553 /*        result=report_transaction(tr, log_ptr, object_name,"NRTM:ADD:While creating new"); */
 554         /* create ADD serial */
 555         UD_lock_serial(tr);
 556         serial_id = UD_create_serial(tr); 
 557         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 558         UD_commit_serial(tr);
 559         UD_unlock_serial(tr);
 560 
 561         /* Mark TR as clean */
 562         TR_mark_clean(tr);
 563         /* log the transaction */
 564         result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD: cannot create new object");
 565       }
 566       else { /* object already exists in the database */
 567         /* this may happen because of dummies*/
 568         /* or with some implementations of mirroring protocol that have atomic update */
 569         /* instead of add + del */
 570 /*      fprintf(stderr,"CREATE new\n");*/
 571         tr->action=TA_UPDATE;
 572         dummy=isdummy(tr);
 573         /* If we are replacing dummy with a real object update NHR */
 574         if(dummy==1) tr->action = (TA_UPD_NHR | TA_UPD_DUMMY);
 575         object_process(tr);
 576 /*        result=report_transaction(tr, log_ptr, object_name,"NRTM:ADD:While creating new");*/
 577         /* For serials this is CREATE operation. Increase sequence to have it correct in serals */
 578         if(dummy==1) { tr->action=TA_CREATE; tr->sequence_id++; }
 579         /* create ADD serial record */
 580         UD_lock_serial(tr);
 581         serial_id = UD_create_serial(tr); 
 582         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 583         UD_commit_serial(tr);
 584         UD_unlock_serial(tr);
 585         /* Mark TR as clean */
 586         TR_mark_clean(tr);
 587         /* log the transaction */
 588         result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD: cannot create new object");
 589         
 590       } 
 591     }
 592     break;
 593     
 594   case OP_DEL:
 595     if(nrtm->tr){ /*DEL DEL =>saved */
 596 /*    fprintf(stderr,"DEL previous\n");*/
 597       object_process(nrtm->tr); /* delete the previous(saved) object*/
 598 /*      result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved) object");*/
 599       /* create DEL serial record */
 600       UD_lock_serial(nrtm->tr);
 601       serial_id = UD_create_serial(nrtm->tr);  
 602       CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
 603       UD_commit_serial(nrtm->tr);
 604       UD_unlock_serial(nrtm->tr);
 605       /* Mark TR as clean */
 606       TR_mark_clean(nrtm->tr);
 607       /* log the transaction */
 608       result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
 609       
 610       object_free(nrtm->tr->object);
 611       transaction_free(nrtm->tr); nrtm->tr=NULL;
 612     }
 613     /* save the real object (not a dummy one ) */
 614     if(tr->object_id>0 && !isdummy(tr)){ /* save the object*/
 615 /*      fprintf(stderr,"SAVED\n"); */
 616       tr->action=TA_DELETE;
 617       nrtm->tr=tr;
 618 /*      strcpy(nrtm->object_name, object_name); */
 619       return(0);
 620     }
 621     else { /* this is an error - Trying to DEL non-existing object*/
 622       tr->succeeded=0; tr->error|=ERROR_U_COP;
 623       tr->action=TA_DELETE;
 624       /* create and initialize TR record for crash recovery */
 625       TR_create_record(tr);
 626 /*      result=report_transaction(tr, log_ptr, object_name, "NRTM:OOS:Trying to DEL non-existing object");*/
 627       /* create DEL serial record anyway */
 628       UD_lock_serial(tr);
 629       serial_id = UD_create_serial(tr); 
 630       CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 631       UD_commit_serial(tr);
 632       UD_unlock_serial(tr);
 633       /* Mark TR as clean */
 634       TR_mark_clean(tr);
 635       /* log the transaction */
 636       result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:DEL: non-existing object");
 637       
 638     }
 639     break;
 640   
 641   default:
 642     tr->succeeded=0; tr->error |=ERROR_U_BADOP;
 643     break;  
 644   }
 645 
 646  /* Free resources */  
 647   object_free(tr->object);
 648   transaction_free(tr);
 649   
 650   return(result);
 651 } /* process_nrtm() */
 652 
 653 
 654 
 655 /************************************************************
 656 * process_updates()                                         *
 657 *                                                           *
 658 * Process object in update mode                             *
 659 *                                                           *
 660 * ud_stream - pointer to UD_stream structure                *
 661 * object_name - name of the object                          *
 662 * operation - operation code (OP_ADD/OP_DEL)                *
 663 *                                                           *
 664 * Note:                                                     *
 665 * Frees tr and tr->obj on exit                              *
 666 *                                                           *
 667 * Returns:                                                  *
 668 * 0  - okay                                                 *
 669 * <0- number of failed objects                              *
 670 *                                                           * 
 671 ************************************************************/
 672 
 673 static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, int operation)
     /* [<][>][^][v][top][bottom][index][help] */
 674 {
 675 int result=0;
 676 Log_t *log_ptr= &(ud_stream->log);
 677 int dummy=0;
 678 ut_timer_t sotime;
 679 
 680     /* Start timer for statistics */
 681     UT_timeget(&sotime);
 682 
 683     switch(operation) {
 684     /* Compare operations and report an error if they do not match */    
 685     case OP_ADD:
 686       if(tr->object_id!=0) { /* trying to create, but object exists */
 687         tr->succeeded=0; tr->error|=ERROR_U_COP;
 688         UD_ack(tr); /* Send a NACK */
 689       } else {
 690        /* Action: create the object and update NHR */
 691         tr->action=(TA_CREATE | TA_UPD_NHR);
 692         object_process(tr);
 693       }
 694       break;
 695     case OP_UPD:
 696       if(tr->object_id==0) { /* trying to update non-existing object*/
 697         tr->succeeded=0; tr->error|=ERROR_U_COP;
 698         UD_ack(tr); /* Send a NACK */
 699       } else {
 700         tr->action=TA_UPDATE;
 701         dummy=isdummy(tr);
 702         /* If we are replacing dummy with a real object update NHR */
 703         if(dummy==1) tr->action = (TA_UPD_NHR | TA_UPD_DUMMY);
 704         object_process(tr);
 705       }
 706       break;
 707 
 708     case OP_DEL:        
 709       if(tr->object_id==0) { /* trying t delete non-existing object*/
 710         tr->succeeded=0; tr->error|=ERROR_U_COP;
 711         UD_ack(tr);
 712       } else {
 713         tr->action=TA_DELETE;
 714         object_process(tr);
 715       }
 716       break;
 717                 
 718     default:                
 719       /* bad operation for this mode if not standalone */
 720       if(IS_STANDALONE(tr->mode)) {
 721         if(tr->object_id==0)tr->action=TA_CREATE; else tr->action=TA_UPDATE;
 722         object_process(tr);
 723       }
 724       else {
 725         tr->succeeded=0; 
 726         tr->error|=ERROR_U_BADOP;
 727         UD_ack(tr); /* Send a NACK */ 
 728       }
 729       break;
 730     }
 731    /* If not in standalone mode create serial and copy error transcript */ 
 732     if(!IS_STANDALONE(tr->mode)) {
 733       if(tr->succeeded){
 734               if(dummy==1) { tr->action=TA_CREATE; tr->sequence_id++; }/* we don't want to generate DEL serial for dummy replacement*/
 735               UD_lock_serial(tr);
 736               UD_create_serial(tr); 
 737               CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 738               UD_commit_serial(tr);
 739               UD_unlock_serial(tr);
 740               /* Mark the TR as clean */
 741               TR_mark_clean(tr);
 742       }
 743     }  
 744    
 745    /* Make a report. U stands for update stream. No reason */
 746     result=report_transaction(tr, tr->transaction_id, log_ptr, &sotime, "U:");
 747 
 748    /* Free resources */   
 749     object_free(tr->object);
 750     transaction_free(tr);
 751     
 752     return(result);
 753         
 754 } /* process_updates() */
 755 
 756 
 757 /************************************************************
 758 *                                                           *
 759 * int process_transaction()                                 *
 760 *                                                           *
 761 * Processes the transaction                                 *
 762 *                                                           *
 763 * ud_stream - pointer to UD_stream_t structure              *
 764 *                                                           *
 765 * Returns:                                                  *
 766 * 0 - no error                                              *
 767 * <0- number of failed objects                              *
 768 *                                                           *
 769 ************************************************************/
 770 
 771 /* It frees the obj */
 772 
 773 static int process_transaction(UD_stream_t *ud_stream, 
     /* [<][>][^][v][top][bottom][index][help] */
 774                         Object_t *obj, 
 775                         char *object_name, 
 776                         nic_handle_t *nh,
 777                         int operation,
 778                         long transaction_id)
 779 {
 780 Transaction_t *tr = NULL;
 781 Attribute_t *attr=NULL;
 782 int result;
 783 
 784 /* check if the requested transaction has already been processed */
 785 /* this may happen in case of crash. If so, just send an ack and return */
 786  if(TR_check(ud_stream->db_connection, transaction_id, (ud_stream->condat).sock))return(1);
 787 
 788 /* start new transaction now */ 
 789  tr = transaction_new(ud_stream->db_connection, obj->type);
 790 
 791 /* Return with error if transaction cannot be created */ 
 792  if (tr == NULL) die;
 793  
 794  tr->mode=ud_stream->ud_mode;
 795  tr->load_pass=ud_stream->load_pass;
 796  tr->object=obj;
 797  tr->nh=nh;
 798  tr->source_hdl=ud_stream->source_hdl;
 799  tr->socket=(ud_stream->condat).sock;
 800  tr->transaction_id=transaction_id;
 801  
 802 /* We perform no commit/rollback in the loader mode, so thread_id should be set to 0 */
 803  if(ud_stream->load_pass!=0) { tr->thread_ins=0; tr->thread_upd=0; }
 804     
 805 /* For the first load pass we only create objects */ 
 806  if(ud_stream->load_pass==1) tr->object_id=0;
 807   else tr->object_id=get_object_id(tr);
 808  
 809 /* Object cannot be retrieved */
 810  if(tr->object_id==-1) { /* DB error*/
 811     tr->succeeded=0;
 812     tr->error |= ERROR_U_DBS;
 813     ER_perror(FAC_UD, UD_SQL, "%s: Object cannot be retrieved", object_name);
 814     transaction_free(tr);
 815     object_free(obj);
 816     die;
 817  }
 818 /* save the name of person/role as we need it for referential */
 819 /* integrity check when deleting the object against names. */
 820 /* This is needed to support legacy references by name rather */
 821 /* then by nic_hdl */
 822   if((tr->class_type==C_PN) || (tr->class_type==C_RO)){
 823      attr = attribute_new(object_name);
 824       
 825      if (attr==NULL) {
 826        tr->succeeded=0;
 827        tr->error |= ERROR_U_MEM;
 828        ER_perror(FAC_UD, UD_MEM, "cannot create attribute");
 829        transaction_free(tr);
 830        object_free(obj);
 831        die;
 832     }
 833     
 834     /* Save the value */
 835     tr->save=g_strdup(attr->value);
 836     attribute_free(attr, NULL);
 837   }
 838                                                
 839 /* Process transaction. tr and obj are freed inside the process_* functions */
 840 
 841  if(IS_UPDATE(ud_stream->ud_mode))
 842  /* We are in update mode */
 843     result=process_updates(ud_stream, tr, operation);
 844  else
 845  /* We are in NRTM mode */   
 846     result=process_nrtm(ud_stream, tr, operation);
 847 
 848  return(result);
 849 
 850 }          
 851           
 852 
 853 /************************************************************
 854 *                                                           *
 855 * int UD_process_stream(UD_stream_t *ud_stream)             *
 856 *                                                           *
 857 * Processes the stream                                      *
 858 *                                                           *
 859 * ud_stream - pointer to UD_stream_t structure              *
 860 *                                                           *
 861 * Returns:                                                  *
 862 * in update mode (!standalone)(1 object processed):         *
 863 * 1 - no error                                              *
 864 * <0- errors                                                *
 865 *                                                           *
 866 * in NRTM & standalone modes                                *
 867 * total number of object processed                          *
 868 *                                                           *
 869 ************************************************************/
 870 
 871 int UD_process_stream(UD_stream_t *ud_stream)
     /* [<][>][^][v][top][bottom][index][help] */
 872 {
 873   char line_buff[STR_XXL];
 874   Object_t *obj = NULL;
 875   SQ_connection_t *sql_connection;
 876   int start_object;
 877   int a_type;
 878   struct _nrtm *nrtm;
 879   Log_t *log_ptr= &(ud_stream->log);
 880   ut_timer_t stime, ftime, sotime;
 881   float obj_second1, obj_second10, timediff;
 882   int result;
 883   int operation=0;
 884   int interrupt=0;
 885   int do_update;
 886   int default_ud_mode = ud_stream->ud_mode;
 887   Line_Type_t linetype;
 888   Transaction_t *tr;
 889   long transaction_id=0; /* transaction_id (to be supplied by DBupdate and stored in Database) */
 890   long serial_id;
 891   Obj_parse_t obj_parse; /* the structure used to parse a text object */
 892   
 893   
 894   ud_parse_init(&obj_parse);
 895   
 896   nrtm=ud_stream->nrtm;
 897   start_object = 1;
 898   a_type=-1; 
 899 
 900 
 901   /* Check connection to the database */
 902   if(mysql_ping(ud_stream->db_connection)) {
 903    ER_perror(FAC_UD, UD_SQL, "%s", SQ_error(ud_stream->db_connection));
 904    die;
 905   }
 906    
 907   sql_connection=ud_stream->db_connection;
 908 
 909   /* Start timer for statistics */
 910   UT_timeget(&stime);
 911 
 912  /* Main loop. Reading input stream line by line */
 913  /* Empty line signals to start processing an object, if we have it */ 
 914   while (SK_cd_gets(&ud_stream->condat, line_buff, sizeof(line_buff))>0) {
 915 
 916 
 917     switch (linetype=line_type(line_buff, &transaction_id)) {
 918       case LINE_ATTRIBUTE:
 919        /* parse the object line by line */
 920        obj = UD_parse_object(ud_stream->db_connection, &obj_parse, line_buff);
 921 
 922       break;
 923 
 924       case LINE_COMMENT:
 925       break;
 926 
 927       case LINE_EOF:
 928       break;
 929 
 930       case LINE_ACK:
 931        tr = transaction_new(ud_stream->db_connection, 0);
 932        tr->transaction_id=transaction_id;
 933        TR_delete_record(tr);
 934        transaction_free(tr);
 935       break;
 936       
 937       
 938       case LINE_ADD:
 939       /* restore the default operation mode */
 940        operation=OP_ADD;
 941        ud_stream->ud_mode=default_ud_mode;
 942       break;
 943       
 944       case LINE_OVERRIDE_ADD:
 945       /* for override - switch the dummy bit on */
 946        operation=OP_ADD;
 947        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
 948       break;
 949       
 950       case LINE_UPD:
 951       /* restore the default operation mode */
 952        operation=OP_UPD;
 953        ud_stream->ud_mode=default_ud_mode;
 954       break;  
 955 
 956       case LINE_OVERRIDE_UPD:
 957       /* for override - switch the dummy bit on */
 958        operation=OP_UPD;
 959        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
 960       break;
 961       
 962       case LINE_DEL:
 963       /* restore the default operation mode */
 964        operation=OP_DEL;
 965        ud_stream->ud_mode=default_ud_mode;
 966       break; 
 967 
 968       case LINE_OVERRIDE_DEL:
 969       /* for override - switch the dummy bit on */
 970        operation=OP_DEL;
 971        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
 972       break;
 973  
 974       case LINE_EMPTY:
 975        /* start processing the object */
 976         if ((obj=obj_parse.obj)) { /* if not just garbage*/
 977          ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] object: [%s] ", transaction_id, obj_parse.object_name); 
 978          /* reorder some attributes */
 979          obj->attributes = g_slist_sort(obj->attributes, reorder_attributes);
 980          /* prepend the class attribute */
 981          obj->attributes = g_slist_concat(obj_parse.class_attr_list, obj->attributes);
 982          /* XXX */
 983 /*       print_object(obj); */
 984 
 985          /* start new transaction now */
 986 /*       fprintf(stderr, "transction # %ld\n", transaction_id); */
 987          result=process_transaction(ud_stream, obj, obj_parse.object_name, obj_parse.nh_ptr, operation, transaction_id);
 988          /* process_transaction() frees tr and obj structures, */
 989          /* so make sure we'll not reference these objects in the future */
 990          operation=OP_NOOP;
 991          transaction_id=0;
 992          ud_stream->ud_mode=default_ud_mode;
 993          ud_parse_free(&obj_parse);
 994           
 995          /* this is a good place for quick interrupt */
 996          do_update=CO_get_do_update();
 997          if (do_update) interrupt=0; else interrupt=1;
 998         } /* if this is a real object */
 999         /* initialize the parsing structure */
1000         ud_parse_init(&obj_parse);
1001 
1002       break;
1003 
1004       default:
1005         die;
1006     } /* switch */
1007     
1008     /* Finish processing if interrupt has been set */
1009     if (interrupt) break;
1010   } /* Main loop of data stream processing : while */
1011  
1012  /* Some postprocessing */
1013   if(IS_NRTM_CLNT(ud_stream->ud_mode)){
1014   /* We are in NRTM mode */
1015   /* Clean up */
1016 /*   fclose(ud_stream->stream); */
1017   /* In NRTM mode there may be a saved object that is unprocessed */   
1018    if(nrtm->tr){ /*saved backlog?*/
1019     /* restart the timer for statistics */
1020     UT_timeget(&sotime);
1021     object_process(nrtm->tr); /* delete the previous(saved) object*/
1022 /*    result=report_transaction(nrtm->tr, &(ud_stream->log), nrtm->object_name, 
1023                               "NRTM:DEL:While deleting previous(saved) object"); */
1024     /* create DEL serial record no matter what the result is */
1025     UD_lock_serial(nrtm->tr);
1026     serial_id = UD_create_serial(nrtm->tr); 
1027     CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
1028     UD_commit_serial(nrtm->tr);
1029     UD_unlock_serial(nrtm->tr);
1030     /* Mark TR as clean */
1031     TR_mark_clean(nrtm->tr);
1032     /* log the transaction */
1033     result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
1034 
1035     object_free(nrtm->tr->object);
1036     transaction_free(nrtm->tr); nrtm->tr=NULL;
1037    } 
1038   }
1039 
1040  /* That's all. Free GString */
1041 /*  g_string_free(g_line_buff, TRUE);*/
1042 
1043                                                                                                        
1044  /* Calculate some statistics */
1045 /*  ftime=time(NULL); */
1046   UT_timeget(&ftime);
1047 /*  obj_second1 = (float)(log_ptr->num_ok)/(ftime-stime);
1048   obj_second10 = (float)(log_ptr->num_ok+log_ptr->num_failed)/(ftime-stime); */
1049   timediff = UT_timediff(&stime, &ftime);
1050   obj_second1 = (float)(log_ptr->num_ok)/timediff;
1051   obj_second10 = (float)(log_ptr->num_ok+log_ptr->num_failed)/timediff;
1052   
1053   /* Print the report */
1054   if(IS_STANDALONE(ud_stream->ud_mode) || (!IS_UPDATE(ud_stream->ud_mode))) {
1055 
1056    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s ******** report **********", UD_TAG);
1057    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s %d objects OK (%7.4f obj/s)", UD_TAG, log_ptr->num_ok, obj_second1);
1058    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s %d objects failed", UD_TAG, log_ptr->num_failed);
1059    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s average processing time %7.4f obj/s (%6.2f obj/min)", UD_TAG, 
1060                           obj_second10, obj_second10*60);
1061    result=log_ptr->num_ok+log_ptr->num_failed;
1062   }
1063   return(result);
1064 
1065 } /* UD_process_stream */
1066 

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