modules/ud/ud_process_stream.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- ud_parse_init
- ud_parse_free
- line_continuation
- split_attribute
- reorder_attributes
- each_attribute_print
- print_object
- escape_apostrophes
- line_type
- UD_parse_object
- report_transaction
- process_nrtm
- process_updates
- process_transaction
- 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