## modules/ud/ud_process_stream.c

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

## FUNCTIONS

This source file includes following functions.

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

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

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