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. ud_replace_substring
  5. ud_split_attribute
  6. each_attribute_print
  7. print_object
  8. escape_apostrophes
  9. line_type
  10. UD_parse_object
  11. each_attribute_2_pass
  12. ud_normalize
  13. report_transaction
  14. process_nrtm
  15. process_updates
  16. process_transaction
  17. UD_process_stream

   1 /***************************************
   2   $Revision: 1.50 $
   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, Obj_parse_t *parse, int operation, long transaction_id);
  69 
  70 static GSList *ud_split_attribute(GSList *attr_list, Attribute_t *attr);
  71 static void ud_parse_init(SQ_connection_t *sql_connection, Obj_parse_t *parse);
  72 static void ud_parse_free(Obj_parse_t *parse);
  73 static int line_continuation(char *line);
  74 static GString *escape_apostrophes(GString *text);
  75 static Object_t *UD_parse_object(Obj_parse_t *parse, char *line_buff);
  76 static int ud_replace_substring(GString *gstring, char *old, char *new);
  77 static int ud_normalize(Obj_parse_t *parse);
  78                                                                                                 
  79 /* Delimiters that separate list members, both RPS(,) and legacy( ) */
  80 #define ATTR_DELIMITERS " ,"
  81 
  82 
  83 static void ud_parse_init(SQ_connection_t *sql_connection, Obj_parse_t *parse){
     /* [<][>][^][v][top][bottom][index][help] */
  84      bzero(parse, sizeof(Obj_parse_t));
  85      parse->garbage = 0;
  86      parse->sql_connection = sql_connection;     
  87 }
  88 
  89 static void ud_parse_free(Obj_parse_t *parse){
     /* [<][>][^][v][top][bottom][index][help] */
  90      UT_free(parse->nic);       
  91      UT_free(parse->object_name);
  92 }
  93 
  94 
  95 /******************************************************************
  96 *  int line_continuation()                                        *
  97 *                                                                 *
  98 *  Checks if the line starts with one of line continuation signs  *
  99 *  Returns 1 if this is line continuation, 0 otherwise            *
 100 *                                                                 *
 101 * ****************************************************************/
 102 static int line_continuation(char *line)
     /* [<][>][^][v][top][bottom][index][help] */
 103 {
 104  switch(*line) {
 105         case ' ':
 106         case '\t':
 107         case '+':
 108                  return(1); /* these indicate line continuation */
 109         default: return(0); 
 110  }
 111 
 112 }
 113 
 114 /******************************************************************
 115 *  int ud_replace_substring()                                     *
 116 *                                                                 *
 117 *  replace a subsring in a string                                 *
 118 *  Returns -1 if no match was found                               *
 119 *                                                                 *
 120 * ****************************************************************/
 121 static int ud_replace_substring(GString *gstring, char *old, char *new)
     /* [<][>][^][v][top][bottom][index][help] */
 122 {
 123  int i, i0=-1, j=0;
 124  
 125         for (i=0; ((i < gstring->len) && (old[j] != '\0')); i++){
 126                 if(gstring->str[i]==old[j]){
 127                         if(i0==-1)i0=i;
 128                         j++;
 129                 } else {
 130                         i0=-1;
 131                         j=0;
 132                 }
 133         }
 134         /* if we haven't reached the end of the old substring */
 135         /* or no match occured return -1 */
 136         if((old[j] != '\0') || (i0==-1)) return (-1);
 137         g_string_erase(gstring, i0, j);
 138         g_string_insert(gstring, i0, new);
 139         return(0);
 140 }
 141 
 142 /************************************************************
 143 *                                                           *
 144 * The function to splits attribute value into multiple      *
 145 * words and appends them as attr_type - attr_valu pairs     *
 146 * to the attr_list                                          *
 147 *                                                           *
 148 *                                                           *
 149 ************************************************************/
 150 static GSList *ud_split_attribute(GSList *attr_list, Attribute_t *attr)
     /* [<][>][^][v][top][bottom][index][help] */
 151 {
 152  char *token;
 153  char *split;
 154  char *value, *n;
 155  Attribute_t *attr_split;
 156  GSList *the_list = attr_list;
 157 
 158 
 159   /* check for line continuation (+) */
 160   if (strncmp(attr->value, "+", 1) == 0) attr->value++;
 161   /* check for end-of-line comments */
 162   n = index(attr->value, '#');
 163       /* if there is no comment check for trailing \n */
 164   if(n == NULL) n = index(attr->value, '\n');
 165   /* now copy the clean value into the attribute */
 166   if(n == NULL) value = g_strdup(attr->value); 
 167   else  value = g_strndup(attr->value, (n - attr->value));
 168      
 169   token=value;
 170   while((split=strsep(&token, ATTR_DELIMITERS))){
 171      attr_split = attribute_new1(attr->type, split);
 172      if (attr_split) the_list = g_slist_append(the_list, attr_split);
 173   }
 174   free(value);
 175   attribute_free(attr, NULL);
 176 
 177  return(the_list);
 178 }
 179 
 180 /* XXX */
 181 static void each_attribute_print(void *element_data, void *tr_ptr)
     /* [<][>][^][v][top][bottom][index][help] */
 182 {
 183 
 184 Attribute_t *attr = (Attribute_t *)element_data;
 185 
 186  fprintf(stderr, "[%d|%s]\n", attr->type, attr->value);
 187 
 188 }
 189 
 190 /* XXX */
 191 static void print_object(Object_t *obj)
     /* [<][>][^][v][top][bottom][index][help] */
 192 {
 193   g_slist_foreach(obj->attributes, each_attribute_print, NULL); 
 194   fprintf(stderr, ">>>>>\n%s\n", obj->object->str);
 195 }
 196 
 197 
 198 /******************************************************************
 199 * GString *escape_apostrophes()                                   *
 200 * Escapes apostrophes in the text so they do not confuse printf   *
 201 * functions and don't corrupt SQL queries                         *
 202 *                                                                 *
 203 * *****************************************************************/
 204 static GString *escape_apostrophes(GString *text) {
     /* [<][>][^][v][top][bottom][index][help] */
 205   int i;
 206   for (i=0; i < text->len; i++) {
 207     if ((text->str[i] == '\'') || (text->str[i] == '\\')) {
 208       text = g_string_insert_c(text, i, '\\');
 209       i++;
 210     }
 211   }
 212  return(text); 
 213 } /* escape_apostrophes() */
 214 
 215 
 216 /******************************************************************
 217 * Line_Type_t line_type(e)                                        *
 218 * Determines the line type analysing the first letters            *
 219 *                                                                 *
 220 * ****************************************************************/
 221 static Line_Type_t line_type(const char *line, long *transaction_id) {
     /* [<][>][^][v][top][bottom][index][help] */
 222 
 223   if (strncmp(line, "# EOF", 4) == 0) return(LINE_EOF);
 224   if (strncmp(line, "#", 1) == 0)     return(LINE_COMMENT);
 225   if (strcmp(line, "\n") == 0)        return(LINE_EMPTY);
 226  
 227   if (strncmp(line, "ACK", 3) == 0) {
 228     *transaction_id = atol(line+3);       
 229     return(LINE_ACK);
 230   }
 231   if (strncmp(line, "ADD_OVERRIDE", 12) == 0) {
 232     *transaction_id = atol(line+12);      
 233     return(LINE_OVERRIDE_ADD);
 234   }
 235   if (strncmp(line, "UPD_OVERRIDE", 12) == 0) {
 236     *transaction_id = atol(line+12);      
 237     return(LINE_OVERRIDE_UPD);
 238   }
 239   if (strncmp(line, "DEL_OVERRIDE", 12) == 0) {
 240     *transaction_id = atol(line+12);      
 241     return(LINE_OVERRIDE_DEL);
 242   }
 243  
 244   if (strncmp(line, "ADD", 3) == 0) {
 245     *transaction_id = atol(line+3);
 246     return(LINE_ADD);
 247   }
 248   if (strncmp(line, "UPD", 3) == 0) {
 249     *transaction_id = atol(line+3);
 250     return(LINE_UPD);
 251   }
 252   if (strncmp(line, "DEL", 3) == 0) {
 253     *transaction_id = atol(line+3); 
 254     return(LINE_DEL);
 255   }
 256  
 257 /* Otherwise this is an attribute */  
 258     return(LINE_ATTRIBUTE);
 259 
 260 } /* line_type() */
 261 
 262 /******************************************************************
 263 * Object_t *UD_parse_object()                                     *
 264 *                                                                 *
 265 * Parses the object accepting line by line                        *
 266 * Stores the object and list of attributes in Obj_parse_t struct  *
 267 *                                                                 *
 268 * ****************************************************************/
 269 static Object_t *UD_parse_object(Obj_parse_t *parse, char *line_buff)
     /* [<][>][^][v][top][bottom][index][help] */
 270 {
 271 GString *g_line_buff;
 272 Attribute_t *attr;
 273  
 274   /* in case of garbage */
 275   if(parse->garbage) return(NULL);
 276   
 277   if(parse->obj==NULL) {
 278   /* which means this is the start - create a new object*/
 279           parse->obj = object_new(line_buff);
 280           /* if this is not a class attribute - this is a garbage till the next blank line */
 281           if(parse->obj==NULL) {
 282                   parse->garbage = 1; 
 283                   return(NULL);
 284           }
 285   }
 286   
 287   /* allocate buffer or the string */     
 288   if ((g_line_buff = g_string_sized_new(STR_XXL)) == NULL){ 
 289       ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring");
 290       die; 
 291   }
 292   /* copy the input */
 293   g_string_sprintf(g_line_buff, "%s", line_buff);
 294   /* escape apostrophes in the input line */
 295   g_line_buff=escape_apostrophes(g_line_buff);
 296    
 297   attr = attribute_new(g_line_buff->str);
 298   if (attr){
 299     /* save this attribute for future line continuations */
 300     /* skip attributes that are not stored in SQL database */     
 301     if(DF_get_update_query_type(attr->type)==UD_NULL_){
 302      parse->current_attr = NULL;
 303      attribute_free(attr, NULL);
 304     }
 305     else {
 306      parse->current_attr = attr;            
 307      if((attr->type == A_MB) || (attr->type == A_NH)) {
 308         /* insert it at the beginning */
 309         /* mnt-by should go before member-of to allow correct membership autorization (still done in RIPupd) */
 310         /* nic-hdl should go before any admin-c, tech-c to prevent errrors in self referencing role objects  */
 311         parse->obj->attributes = g_slist_insert(parse->obj->attributes, parse->current_attr, 1);
 312      } else {
 313         /* append it to the attribute list */
 314         parse->obj->attributes = g_slist_append(parse->obj->attributes, parse->current_attr);
 315      }
 316     }
 317   }
 318   /* if this is not a valid attribute, then this may be unknown attr or line continuation */
 319   else 
 320    if(line_continuation(g_line_buff->str)) 
 321    {
 322     /* if parse->attr == NULL, then this attr is not stored in SQL database - skip it */
 323     if(parse->current_attr){
 324     /* this is continuation of a previous attribute */    
 325      char *line_value, *new_value;
 326      char *n;  
 327      /* normalize and append to current_attr->value */
 328      /* check for end-of-line comments */
 329      n = index(g_line_buff->str, '#');
 330      /* if there is no comment check for trailing \n */
 331      if(n == NULL) n = index(g_line_buff->str, '\n');
 332      /* now copy the clean value into the attribute */
 333      if(n == NULL) line_value = g_strdup(g_line_buff->str); 
 334      else  line_value = g_strndup(g_line_buff->str, (n - g_line_buff->str));
 335      /* replace line continuation character with ' ' */
 336      *line_value = ' ';
 337      new_value = g_strconcat(parse->current_attr->value, line_value, NULL);
 338      parse->current_attr = attribute_upd(parse->current_attr, parse->current_attr->type, new_value);
 339      UT_free(new_value);
 340      UT_free(line_value); 
 341     }
 342    }
 343   /* otherwise, this is unknown attribute, so we need to break the continuation */
 344    else parse->current_attr=NULL;
 345   /* copy the line into object no matter whether it is an attribute or not (continualtion, etc.) */
 346   g_string_sprintfa(parse->obj->object, "%s", g_line_buff->str);
 347   g_string_free(g_line_buff, TRUE);
 348   return(parse->obj);
 349 }  
 350 
 351 /******************************************************************
 352 * int each_attribute_2_pass()                                     *
 353 *                                                                 *
 354 * Assigns nic-handles in case of AUTO                             *
 355 * Splits attributes                                               *
 356 *                                                                 *                                                                 *
 357 ******************************************************************/
 358 void each_attribute_2_pass(void *element_data, void *ptr)
     /* [<][>][^][v][top][bottom][index][help] */
 359 {
 360 Attribute_t *attr = (Attribute_t *)element_data;
 361 Obj_parse_t *parse = (Obj_parse_t *)ptr;
 362 
 363 
 364  /* Strip the white space */
 365  g_strstrip(attr->value);
 366 
 367  switch(attr->type){
 368    case A_NH: /* nic-hdl */
 369           /*  Parse the string into nh structure */
 370           /*  In case of an AUTO NIC handle check the ID in the database */
 371           /* Possible errors leave to core processing */
 372           if(NH_parse(attr->value, &parse->nh_ptr) == 0) { 
 373            /* this is an AUTO nic handle */
 374 /*           ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s parsing nic handle: [%s]", UD_TAG, attr->value);*/
 375            /* Check if we can allocate it */  
 376             if(NH_check(parse->nh_ptr, parse->sql_connection)>0){
 377             /* Convert nh to the database format */  
 378               parse->nic = NH_convert(parse->nh_ptr);
 379 /*           ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s parsed and converted nic handle: [%s]", UD_TAG, nic); */
 380               /* replace the auto nic with a real one */
 381               if(ud_replace_substring(parse->obj->object, attr->value, parse->nic)==-1) {
 382                      ER_perror(FAC_UD, UD_BUG, "cannot replace auto nic handle"); 
 383                      die;
 384               }
 385               /* Update the attribute */
 386               attr = attribute_upd(attr, attr->type, parse->nic);
 387               
 388             }
 389           }
 390             parse->new_attr_list = g_slist_append(parse->new_attr_list, attr);
 391             break;
 392    case A_PN: /* person */
 393    case A_RO: /* role */
 394    case A_MR: /* mbrs-by-ref */
 395    case A_MB: /* mnt-by */
 396    case A_ML: /* mnt-lower */
 397    case A_MO: /* member-of */
 398    case A_SD: /* sub-dom */
 399    case A_RZ: /* rev-srv */
 400    case A_NS: /* nserver */
 401             parse->new_attr_list = ud_split_attribute(parse->new_attr_list, attr);
 402             break;
 403    default:
 404             parse->new_attr_list = g_slist_append(parse->new_attr_list, attr);
 405             break;
 406  }
 407 
 408 }
 409 
 410                   
 411 /******************************************************************
 412 * int ud_normalize()                                              *
 413 *                                                                 *
 414 * function accepts Obj_parse_t structure with attribute list      *
 415 *                                                                 *
 416 * It makes another pass to normalize object                       *
 417 * Normalization includes:                                         *
 418 *                                                                 *
 419 * 1) reorder attributes                                           *
 420 *  . mnt-by should go before member-of to allow correct           * 
 421 *      membership autorization (still done in RIPupd)             *
 422 *  . nic-hdl should go before any admin-c, tech-c to prevent      * 
 423 *       errrors in self referencing role objects                  *
 424 * 2) in case of pn/ro check nic handle and replace it in          *
 425 *     the obj->object if needed (AUTO)                            * 
 426 * 3) split some attributes that allow lists                       *
 427 ******************************************************************/
 428 static int ud_normalize(Obj_parse_t *parse)
     /* [<][>][^][v][top][bottom][index][help] */
 429 {
 430 GSList *old_attr_list;
 431 GSList *first_element;
 432 Attribute_t *class_attr;
 433 
 434         old_attr_list = parse->obj->attributes;
 435         /* get class attribute - the first one */
 436         first_element = g_slist_nth(old_attr_list, 0);
 437         class_attr = (Attribute_t *)first_element->data;
 438         /* save object name for reporting and checking ref integrity for names (legacy) */      
 439         parse->object_name = g_strdup(class_attr->value);
 440         /* reorder the attributes mnt-by and nic-hdl come first */
 441         /*g_slist_foreach(old_attr_list, each_attribute_1_pass, parse); 
 442         g_slist_free(old_attr_list);
 443         old_attr_list = parse->new_attr_list; */
 444         parse->new_attr_list = NULL;
 445         /* assign auto nic-hdl and slit attributes */
 446         g_slist_foreach(old_attr_list, each_attribute_2_pass, parse);
 447         g_slist_free(old_attr_list);
 448         parse->obj->attributes = parse->new_attr_list;
 449 
 450         return(1);
 451 }
 452 
 453 
 454 /******************************************************************
 455 * report_transaction()                                            *
 456 *                                                                 * 
 457 * Prints error report to the log                                  *
 458 *                                                                 *
 459 * reason - additional message that will be included               *
 460 *                                                                 *
 461 * *****************************************************************/
 462 static int report_transaction(Transaction_t *tr, long transaction_id,  Log_t *log, ut_timer_t *psotime, char *reason)
     /* [<][>][^][v][top][bottom][index][help] */
 463 {
 464 int result=0;
 465 ut_timer_t fotime;
 466 float timediff;
 467 const char *class_name = DF_class_type2name(tr->class_type);
 468 char *primary_key = tr->K->str;
 469 
 470 
 471  /* calculate statistics */
 472   UT_timeget(&fotime);
 473   timediff = UT_timediff(psotime, &fotime);
 474  
 475  if(tr->succeeded==0) {
 476   result=tr->error;
 477   log->num_failed++;
 478   ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] %.2fs FAILED [%s:%s][%s]", transaction_id, timediff, class_name, primary_key, reason);
 479 /*  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)); */
 480   if(result & ERROR_U_OBJ) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: referential integrity error", transaction_id);
 481   if(result & ERROR_U_AUT) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: authentication error", transaction_id);
 482   if(result & ERROR_U_BADOP) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: unsupported operation", transaction_id);
 483   if(result & ERROR_U_COP) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: conflicting operation", transaction_id);
 484   if(result & ERROR_U_NSUP) ER_dbg_va(FAC_UD, ASP_UD_OBJ,"[%ld] object: this type is not supported", transaction_id);
 485   ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] object: details [%s]", transaction_id, (tr->error_script)->str);
 486   result=1; /* # of failures */
 487  }
 488  else {
 489   result=0;
 490   log->num_ok++;
 491 /*  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)); */
 492   ER_inf_va(FAC_UD, ASP_UD_OBJ, "[%ld] %.2fs OK     [%s:%s][%s]", transaction_id, timediff, class_name, primary_key, reason);
 493   ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] object: details [%s]", transaction_id, (tr->error_script)->str);
 494  }
 495                                                                                                                                                
 496  return(result);
 497 }/* report_transaction() */
 498 
 499 
 500 
 501 /************************************************************
 502 * process_nrtm()                                            *
 503 *                                                           *
 504 * Process object in NRTM client mode                        *
 505 *                                                           *
 506 * nrtm - pointer to _nrtm structure                         *
 507 * log - pointer to Log_t structure                          *
 508 * object_name - name of the object                          * 
 509 * operation - operation code (OP_ADD/OP_DEL)                *
 510 *                                                           *
 511 * Returns:                                                  *
 512 * 1  - okay                                                 *
 513 * <0 - error                                                *
 514 *                                                           *
 515 ************************************************************/
 516 
 517 static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, int operation)
     /* [<][>][^][v][top][bottom][index][help] */
 518 {
 519 int result=0;
 520 int dummy=0;
 521 struct _nrtm *nrtm = ud_stream->nrtm;
 522 long serial_id;
 523 Log_t *log_ptr= &(ud_stream->log);
 524 ut_timer_t sotime;
 525 int ta_upd_nhr;
 526 
 527     /* Start timer for statistics */
 528     UT_timeget(&sotime);
 529 
 530   /* We allow NRTM updates for some inconsistent objects                  */
 531   /* One of the examples is reference by name which looks like nic-handle */
 532   /* For this purpose we allow dummy creation when updating an object     */
 533   /* We also check for dummy allowance when deleting an object            */
 534   /* this is done to allow deletion of person objects referenced by name  */
 535 
 536   tr->mode|=B_DUMMY;
 537   if(IS_NO_NHR(tr->mode))ta_upd_nhr=0; else ta_upd_nhr = TA_UPD_NHR;
 538   
 539   switch (operation) {
 540   
 541   case OP_ADD:
 542     if(nrtm->tr){ /* DEL ADD => saved*/
 543       if(tr->object_id==0) { 
 544         /* object does not exist in the DB */      
 545         /* delete the previous(saved) object*/
 546         object_process(nrtm->tr); 
 547         /* create DEL serial */
 548         UD_lock_serial(nrtm->tr);
 549         serial_id = UD_create_serial(nrtm->tr);
 550         CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr); 
 551         UD_commit_serial(nrtm->tr);
 552         UD_unlock_serial(nrtm->tr);
 553         /* Mark TR as clean */
 554         TR_mark_clean(nrtm->tr);
 555         /* log the transaction */
 556         result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
 557         
 558         object_free(nrtm->tr->object);
 559         transaction_free(nrtm->tr); nrtm->tr=NULL;
 560         
 561         /* Create an object and update NHR */
 562         tr->action=(TA_CREATE | ta_upd_nhr);
 563         /* restart the timer for statistics */
 564         UT_timeget(&sotime);
 565         object_process(tr); /* create a new one*/
 566         /* create ADD serial */
 567         UD_lock_serial(tr);
 568         serial_id = UD_create_serial(tr); 
 569         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 570         UD_commit_serial(tr);
 571         UD_unlock_serial(tr);
 572         /* Mark TR as clean */
 573         TR_mark_clean(tr);
 574         /* log the transaction */
 575         result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD");
 576       }
 577       else { 
 578       /* object already exists in the DB - update or dummy replacement*/
 579         /*compare the two, may be we may collapse operations*/
 580         if(tr->object_id==nrtm->tr->object_id) {
 581           /* DEL-ADD ->> UPDATE */ 
 582           object_free(nrtm->tr->object);
 583           transaction_free(nrtm->tr); nrtm->tr=NULL;
 584           tr->action=TA_UPD_CLLPS;
 585           object_process(tr);
 586           /* create DEL+ADD serial records */
 587           UD_lock_serial(tr);
 588           tr->action=TA_DELETE; serial_id = UD_create_serial(tr);
 589           result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:DEL(UPD)");
 590 
 591           /* restart the timer for statistics */
 592           UT_timeget(&sotime);
 593           tr->sequence_id++;
 594           tr->action=TA_CREATE; serial_id = UD_create_serial(tr);
 595           CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 596           UD_commit_serial(tr);
 597           UD_unlock_serial(tr);
 598           /* Mark TR as clean */
 599           TR_mark_clean(tr);
 600           result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD(UPD)");
 601         }
 602         else { /* this should be a dummy object in the database(that we are going to replace with the real one */
 603         /* or an interleaved operation*/
 604           object_process(nrtm->tr); /* delete the previous(saved) object*/
 605           /* create a DEL serial record */
 606           UD_lock_serial(nrtm->tr);
 607           serial_id = UD_create_serial(nrtm->tr); 
 608           CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
 609           UD_commit_serial(nrtm->tr);
 610           UD_unlock_serial(nrtm->tr);
 611           /* Mark TR as clean */
 612           TR_mark_clean(nrtm->tr);
 613 /*        result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");*/
 614           /* log the transaction */
 615           result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
 616 
 617 
 618           object_free(nrtm->tr->object);
 619           transaction_free(nrtm->tr); nrtm->tr=NULL;
 620 
 621           /* restart the timer for statistics */
 622           UT_timeget(&sotime);
 623           
 624           tr->action=TA_UPDATE;
 625           /* check if we are replacing a dummy object */
 626           dummy=isdummy(tr);
 627           /* If we are replacing dummy with a real object update NHR */
 628           if(dummy==1) tr->action = (ta_upd_nhr | TA_UPD_DUMMY);
 629 /*        fprintf(stderr,"UPDATE next(dummy)\n"); */
 630           object_process(tr); /* create a new one*/
 631 /*          result=report_transaction(tr, log_ptr, object_name, "NRTM:ADD:While creating new"); */
 632           /* For serials this is CREATE operation. Increase sequence to have it correct in serals */
 633           if(dummy==1) { tr->action=TA_CREATE; tr->sequence_id++; } 
 634           /* create ADD serial record */
 635           UD_lock_serial(tr);
 636           serial_id = UD_create_serial(tr); 
 637           CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 638           UD_commit_serial(tr);
 639           UD_unlock_serial(tr);
 640           /* Mark TR as clean */
 641           TR_mark_clean(tr);
 642           /* log the transaction */
 643           result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD");
 644 
 645         }
 646       }
 647     }
 648     else { /* ADD ADD =>brand new object*/
 649       if(tr->object_id==0) {
 650 /*      fprintf(stderr,"CREATE new\n");*/
 651         /* Create an object and update NHR */
 652         tr->action=(TA_CREATE | ta_upd_nhr);
 653         object_process(tr);
 654         /* create ADD serial */
 655         UD_lock_serial(tr);
 656         serial_id = UD_create_serial(tr); 
 657         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 658         UD_commit_serial(tr);
 659         UD_unlock_serial(tr);
 660 
 661         /* Mark TR as clean */
 662         TR_mark_clean(tr);
 663         /* log the transaction */
 664         result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD");
 665       }
 666       else { /* object already exists in the database */
 667         /* this may happen because of dummies*/
 668         /* or with some implementations of mirroring protocol that have atomic update */
 669         /* instead of add + del */
 670         tr->action=TA_UPDATE;
 671         dummy=isdummy(tr);
 672         /* If we are replacing dummy with a real object update NHR */
 673         if(dummy==1) tr->action = ( ta_upd_nhr| TA_UPD_DUMMY);
 674         object_process(tr);
 675         /* For serials this is CREATE operation. Increase sequence to have it correct in serals */
 676         if(dummy==1) { tr->action=TA_CREATE; tr->sequence_id++; }
 677         /* create ADD serial record */
 678         UD_lock_serial(tr);
 679         serial_id = UD_create_serial(tr); 
 680         CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 681         UD_commit_serial(tr);
 682         UD_unlock_serial(tr);
 683         /* Mark TR as clean */
 684         TR_mark_clean(tr);
 685         /* log the transaction */
 686         result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:ADD");
 687         
 688       } 
 689     }
 690     break;
 691     
 692   case OP_DEL:
 693     if(nrtm->tr){ /*DEL DEL =>saved */
 694       object_process(nrtm->tr); /* delete the previous(saved) object*/
 695       /* create DEL serial record */
 696       UD_lock_serial(nrtm->tr);
 697       serial_id = UD_create_serial(nrtm->tr);  
 698       CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
 699       UD_commit_serial(nrtm->tr);
 700       UD_unlock_serial(nrtm->tr);
 701       /* Mark TR as clean */
 702       TR_mark_clean(nrtm->tr);
 703       /* log the transaction */
 704       result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
 705       
 706       object_free(nrtm->tr->object);
 707       transaction_free(nrtm->tr); nrtm->tr=NULL;
 708     }
 709     /* save the real object (not a dummy one ) */
 710     if(tr->object_id>0 && !isdummy(tr)){ 
 711       /* save the object*/
 712       tr->action=(TA_DELETE | ta_upd_nhr);
 713       nrtm->tr=tr;
 714       return(0);
 715     }
 716     else { /* this is an error - Trying to DEL non-existing object*/
 717       tr->succeeded=0; tr->error|=ERROR_U_COP;
 718       tr->action=(TA_DELETE | ta_upd_nhr);
 719       /* create and initialize TR record for crash recovery */
 720       TR_create_record(tr);
 721       /* create DEL serial record anyway */
 722       UD_lock_serial(tr);
 723       serial_id = UD_create_serial(tr); 
 724       CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 725       UD_commit_serial(tr);
 726       UD_unlock_serial(tr);
 727       /* Mark TR as clean */
 728       TR_mark_clean(tr);
 729       /* log the transaction */
 730       result=report_transaction(tr, serial_id, log_ptr, &sotime, "M:DEL: non-existing object");
 731       
 732     }
 733     break;
 734   
 735   default:
 736     tr->succeeded=0; tr->error |=ERROR_U_BADOP;
 737     break;  
 738   }
 739 
 740  /* Free resources */  
 741   object_free(tr->object);
 742   transaction_free(tr);
 743   
 744   return(result);
 745 } /* process_nrtm() */
 746 
 747 
 748 
 749 /************************************************************
 750 * process_updates()                                         *
 751 *                                                           *
 752 * Process object in update mode                             *
 753 *                                                           *
 754 * ud_stream - pointer to UD_stream structure                *
 755 * object_name - name of the object                          *
 756 * operation - operation code (OP_ADD/OP_DEL)                *
 757 *                                                           *
 758 * Note:                                                     *
 759 * Frees tr and tr->obj on exit                              *
 760 *                                                           *
 761 * Returns:                                                  *
 762 * 0  - okay                                                 *
 763 * <0- number of failed objects                              *
 764 *                                                           * 
 765 ************************************************************/
 766 
 767 static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, int operation)
     /* [<][>][^][v][top][bottom][index][help] */
 768 {
 769 int result=0;
 770 Log_t *log_ptr= &(ud_stream->log);
 771 int dummy=0;
 772 ut_timer_t sotime;
 773 int ta_upd_nhr;
 774 char *reason;
 775 
 776     /* Start timer for statistics */
 777     UT_timeget(&sotime);
 778     if(IS_NO_NHR(tr->mode))ta_upd_nhr=0; else ta_upd_nhr = TA_UPD_NHR;
 779 
 780     switch(operation) {
 781     /* Compare operations and report an error if they do not match */    
 782     case OP_ADD:
 783       if(tr->object_id!=0) { /* trying to create, but object exists */
 784         tr->succeeded=0; tr->error|=ERROR_U_COP;
 785         reason="U:ADD:object already exists";
 786         UD_ack(tr); /* Send a NACK */
 787       } else {
 788        /* Action: create the object and update NHR */
 789         tr->action=(TA_CREATE | ta_upd_nhr);
 790         reason="U:ADD";
 791         object_process(tr);
 792       }
 793       break;
 794     case OP_UPD:
 795       if(tr->object_id==0) { /* trying to update non-existing object*/
 796         tr->succeeded=0; tr->error|=ERROR_U_COP;
 797         reason="U:UPD:non-existing object";
 798         UD_ack(tr); /* Send a NACK */
 799       } else {
 800         tr->action=TA_UPDATE;
 801         reason="U:UPD";
 802         dummy=isdummy(tr);
 803         /* If we are replacing dummy with a real object update NHR */
 804         if(dummy==1) tr->action = (ta_upd_nhr | TA_UPD_DUMMY);
 805         object_process(tr);
 806       }
 807       break;
 808 
 809     case OP_DEL:        
 810       if(tr->object_id==0) { /* trying t delete non-existing object*/
 811         tr->succeeded=0; tr->error|=ERROR_U_COP;
 812         reason="U:DEL:non-existing object";
 813         UD_ack(tr);
 814       } else {
 815         tr->action=(TA_DELETE | ta_upd_nhr);
 816         reason="U:DEL";
 817         object_process(tr);
 818       }
 819       break;
 820                 
 821     default:                
 822       /* bad operation for this mode if not standalone */
 823       if(IS_STANDALONE(tr->mode)) {
 824         if(tr->object_id==0){
 825           tr->action=(TA_CREATE | ta_upd_nhr); 
 826           reason="U:ADD";
 827         }
 828         else {
 829           tr->action=TA_UPDATE;
 830           reason="U:UPD";
 831         }
 832         object_process(tr);
 833       }
 834       else {
 835         tr->succeeded=0; 
 836         tr->error|=ERROR_U_BADOP;
 837         reason="U:bad operation";
 838         UD_ack(tr); /* Send a NACK */ 
 839       }
 840       break;
 841     }
 842    /* If not in standalone mode create serial and copy error transcript */ 
 843     if(!IS_STANDALONE(tr->mode)) {
 844       if(tr->succeeded){
 845               /* we don't want to generate DEL serial for dummy replacement*/
 846               if(dummy==1) { tr->action=TA_CREATE; tr->sequence_id++; }
 847               UD_lock_serial(tr);
 848               UD_create_serial(tr); 
 849               CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 850               UD_commit_serial(tr);
 851               UD_unlock_serial(tr);
 852               /* Mark the TR as clean */
 853               TR_mark_clean(tr);
 854       }
 855     }  
 856    
 857    /* Make a report. U stands for update stream. No reason */
 858     result=report_transaction(tr, tr->transaction_id, log_ptr, &sotime, reason);
 859 
 860    /* Free resources */   
 861     object_free(tr->object);
 862     transaction_free(tr);
 863     
 864     return(result);
 865         
 866 } /* process_updates() */
 867 
 868 
 869 /************************************************************
 870 *                                                           *
 871 * int process_transaction()                                 *
 872 *                                                           *
 873 * Processes the transaction                                 *
 874 *                                                           *
 875 * ud_stream - pointer to UD_stream_t structure              *
 876 *                                                           *
 877 * Returns:                                                  *
 878 * 0 - no error                                              *
 879 * <0- number of failed objects                              *
 880 *                                                           *
 881 ************************************************************/
 882 
 883 /* It frees the obj */
 884 
 885 static int process_transaction(UD_stream_t *ud_stream, 
     /* [<][>][^][v][top][bottom][index][help] */
 886                          Obj_parse_t *parse,
 887                          int operation,
 888                         long transaction_id)
 889 {
 890 Transaction_t *tr = NULL;
 891 Object_t *obj = parse->obj;
 892 int result;
 893 
 894 /* check if the requested transaction has already been processed */
 895 /* this may happen in case of crash. If so, just send an ack and return */
 896  if(TR_check(ud_stream->db_connection, transaction_id, (ud_stream->condat).sock))return(1);
 897 
 898 /* start new transaction now */ 
 899  tr = transaction_new(ud_stream->db_connection, obj->type);
 900 
 901 /* Return with error if transaction cannot be created */ 
 902  if (tr == NULL) die;
 903  
 904  tr->mode=ud_stream->ud_mode;
 905  tr->load_pass=ud_stream->load_pass;
 906  tr->object=obj;
 907  tr->nh=parse->nh_ptr;
 908  tr->source_hdl=ud_stream->source_hdl;
 909  tr->socket=(ud_stream->condat).sock;
 910  tr->transaction_id=transaction_id;
 911  
 912 /* We perform no commit/rollback in the loader mode, so thread_id should be set to 0 */
 913  if(ud_stream->load_pass!=0) { tr->thread_ins=0; tr->thread_upd=0; }
 914     
 915 /* For the first load pass we only create objects */ 
 916  if(ud_stream->load_pass==1) {
 917          Object_t *obj=tr->object;
 918          /* still we need to fill tr->K (last.pkey) field */ 
 919          g_slist_foreach(obj->attributes, ud_each_primary_key_select, tr);
 920          tr->object_id=0;
 921  }
 922  else tr->object_id=get_object_id(tr);
 923  
 924 /* Object cannot be retrieved */
 925  if(tr->object_id==-1) { /* DB error*/
 926     tr->succeeded=0;
 927     tr->error |= ERROR_U_DBS;
 928     ER_perror(FAC_UD, UD_SQL, "%s: Object cannot be retrieved", parse->object_name);
 929     die;
 930     transaction_free(tr);
 931     object_free(obj);
 932  }
 933 /* save the name of person/role as we need it for referential */
 934 /* integrity check when deleting the object against names. */
 935 /* This is needed to support legacy references by name rather */
 936 /* then by nic_hdl */
 937   if((tr->class_type==C_PN) || (tr->class_type==C_RO)){
 938     /* Save the value */
 939     tr->save=g_strdup(parse->object_name);
 940 /*    attribute_free(attr, NULL); */
 941   }
 942                                                
 943 /* Process transaction. tr and obj are freed inside the process_* functions */
 944 
 945  if(IS_UPDATE(ud_stream->ud_mode))
 946  /* We are in update mode */
 947     result=process_updates(ud_stream, tr, operation);
 948  else
 949  /* We are in NRTM mode */   
 950     result=process_nrtm(ud_stream, tr, operation);
 951 
 952  return(result);
 953 
 954 }          
 955           
 956 
 957 /************************************************************
 958 *                                                           *
 959 * int UD_process_stream(UD_stream_t *ud_stream)             *
 960 *                                                           *
 961 * Processes the stream                                      *
 962 *                                                           *
 963 * ud_stream - pointer to UD_stream_t structure              *
 964 *                                                           *
 965 * Returns:                                                  *
 966 * in update mode (!standalone)(1 object processed):         *
 967 * 1 - no error                                              *
 968 * <0- errors                                                *
 969 *                                                           *
 970 * in NRTM & standalone modes                                *
 971 * total number of object processed                          *
 972 *                                                           *
 973 ************************************************************/
 974 
 975 int UD_process_stream(UD_stream_t *ud_stream)
     /* [<][>][^][v][top][bottom][index][help] */
 976 {
 977   char line_buff[STR_XXL];
 978   Object_t *obj = NULL;
 979   SQ_connection_t *sql_connection;
 980   int start_object;
 981   int a_type;
 982   struct _nrtm *nrtm;
 983   Log_t *log_ptr= &(ud_stream->log);
 984   ut_timer_t stime, ftime, sotime;
 985   float obj_second1, obj_second10, timediff;
 986   int result;
 987   int operation=0;
 988   int interrupt=0;
 989   int do_update;
 990   int default_ud_mode = ud_stream->ud_mode;
 991   Line_Type_t linetype;
 992   Transaction_t *tr;
 993   long transaction_id=0; /* transaction_id (to be supplied by DBupdate and stored in Database) */
 994   long serial_id;
 995   Obj_parse_t obj_parse; /* the structure used to parse a text object */
 996   
 997   
 998   
 999   
1000   nrtm=ud_stream->nrtm;
1001   start_object = 1;
1002   a_type=-1; 
1003 
1004 
1005   /* Check connection to the database */
1006   if(SQ_ping(ud_stream->db_connection)) {
1007    ER_perror(FAC_UD, UD_SQL, "%s", SQ_error(ud_stream->db_connection));
1008    die;
1009   }
1010    
1011   sql_connection=ud_stream->db_connection;
1012   
1013   ud_parse_init(sql_connection, &obj_parse);
1014   /* Start timer for statistics */
1015   UT_timeget(&stime);
1016 
1017  /* Main loop. Reading input stream line by line */
1018  /* Empty line signals to start processing an object, if we have it */ 
1019   while (SK_cd_gets(&ud_stream->condat, line_buff, sizeof(line_buff))>0) {
1020 
1021 
1022     switch (linetype=line_type(line_buff, &transaction_id)) {
1023       case LINE_ATTRIBUTE:
1024        /* parse the object line by line */
1025        obj = UD_parse_object(&obj_parse, line_buff);
1026 
1027       break;
1028 
1029       case LINE_COMMENT:
1030       break;
1031 
1032       case LINE_EOF:
1033       break;
1034 
1035       case LINE_ACK:
1036        tr = transaction_new(ud_stream->db_connection, 0);
1037        tr->transaction_id=transaction_id;
1038        TR_delete_record(tr);
1039        transaction_free(tr);
1040       break;
1041       
1042       
1043       case LINE_ADD:
1044       /* restore the default operation mode */
1045        operation=OP_ADD;
1046        ud_stream->ud_mode=default_ud_mode;
1047       break;
1048       
1049       case LINE_OVERRIDE_ADD:
1050       /* for override - switch the dummy bit on */
1051        operation=OP_ADD;
1052        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
1053       break;
1054       
1055       case LINE_UPD:
1056       /* restore the default operation mode */
1057        operation=OP_UPD;
1058        ud_stream->ud_mode=default_ud_mode;
1059       break;  
1060 
1061       case LINE_OVERRIDE_UPD:
1062       /* for override - switch the dummy bit on */
1063        operation=OP_UPD;
1064        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
1065       break;
1066       
1067       case LINE_DEL:
1068       /* restore the default operation mode */
1069        operation=OP_DEL;
1070        ud_stream->ud_mode=default_ud_mode;
1071       break; 
1072 
1073       case LINE_OVERRIDE_DEL:
1074       /* for override - switch the dummy bit on */
1075        operation=OP_DEL;
1076        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
1077       break;
1078  
1079       case LINE_EMPTY:
1080        /* start processing the object */
1081         if ((obj=obj_parse.obj)) { /* if not just garbage*/
1082          /* normalize the object (reorder and split attributes */
1083          ud_normalize(&obj_parse);
1084          /* XXX */
1085 /*       print_object(obj); */
1086 
1087          /* start new transaction now */
1088          ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] object: [%s] ", transaction_id, obj_parse.object_name); 
1089 
1090 /*       fprintf(stderr, "transction # %ld\n", transaction_id); */
1091          result=process_transaction(ud_stream, &obj_parse, operation, transaction_id);
1092          /* process_transaction() frees tr and obj structures, */
1093          /* so make sure we'll not reference these objects in the future */
1094          operation=OP_NOOP;
1095          transaction_id=0;
1096          ud_stream->ud_mode=default_ud_mode;
1097          ud_parse_free(&obj_parse);
1098           
1099          /* this is a good place for quick interrupt */
1100          do_update=CO_get_do_update();
1101          if (do_update) interrupt=0; else interrupt=1;
1102         } /* if this is a real object */
1103         /* initialize the parsing structure */
1104         ud_parse_init(sql_connection, &obj_parse);
1105 
1106       break;
1107 
1108       default:
1109         die;
1110     } /* switch */
1111     
1112     /* Finish processing if interrupt has been set */
1113     if (interrupt) break;
1114   } /* Main loop of data stream processing : while */
1115  
1116  /* Some postprocessing */
1117   if(IS_NRTM_CLNT(ud_stream->ud_mode)){
1118   /* We are in NRTM mode */
1119   /* Clean up */
1120 /*   fclose(ud_stream->stream); */
1121   /* In NRTM mode there may be a saved object that is unprocessed */   
1122    if(nrtm->tr){ /*saved backlog?*/
1123     /* restart the timer for statistics */
1124     UT_timeget(&sotime);
1125     object_process(nrtm->tr); /* delete the previous(saved) object*/
1126 /*    result=report_transaction(nrtm->tr, &(ud_stream->log), nrtm->object_name, 
1127                               "NRTM:DEL:While deleting previous(saved) object"); */
1128     /* create DEL serial record no matter what the result is */
1129     UD_lock_serial(nrtm->tr);
1130     serial_id = UD_create_serial(nrtm->tr); 
1131     CP_CREATE_S_PASSED(nrtm->tr->action); TR_update_status(nrtm->tr);
1132     UD_commit_serial(nrtm->tr);
1133     UD_unlock_serial(nrtm->tr);
1134     /* Mark TR as clean */
1135     TR_mark_clean(nrtm->tr);
1136     /* log the transaction */
1137     result=report_transaction(nrtm->tr, serial_id, log_ptr, &sotime, "M:DEL");
1138 
1139     object_free(nrtm->tr->object);
1140     transaction_free(nrtm->tr); nrtm->tr=NULL;
1141    } 
1142   }
1143 
1144  /* That's all. Free GString */
1145 /*  g_string_free(g_line_buff, TRUE);*/
1146 
1147                                                                                                        
1148  /* Calculate some statistics */
1149 /*  ftime=time(NULL); */
1150   UT_timeget(&ftime);
1151 /*  obj_second1 = (float)(log_ptr->num_ok)/(ftime-stime);
1152   obj_second10 = (float)(log_ptr->num_ok+log_ptr->num_failed)/(ftime-stime); */
1153   timediff = UT_timediff(&stime, &ftime);
1154   obj_second1 = (float)(log_ptr->num_ok)/timediff;
1155   obj_second10 = (float)(log_ptr->num_ok+log_ptr->num_failed)/timediff;
1156   
1157   /* Print the report */
1158   if(IS_STANDALONE(ud_stream->ud_mode) || (!IS_UPDATE(ud_stream->ud_mode))) {
1159 
1160    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s ******** report **********", UD_TAG);
1161    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s %d objects OK (%7.4f obj/s)", UD_TAG, log_ptr->num_ok, obj_second1);
1162    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s %d objects failed", UD_TAG, log_ptr->num_failed);
1163    ER_inf_va(FAC_UD, ASP_UD_UPDLOG,"%s average processing time %7.4f obj/s (%6.2f obj/min)", UD_TAG, 
1164                           obj_second10, obj_second10*60);
1165    result=log_ptr->num_ok+log_ptr->num_failed;
1166   }
1167   return(result);
1168 
1169 } /* UD_process_stream */
1170 

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