modules/ud/ud_process_stream.c

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

FUNCTIONS

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

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

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