## 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] */