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.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