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

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