modules/ud/ud_recover.c

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

FUNCTIONS

This source file includes following functions.
  1. TR_create_record
  2. TR_update_record
  3. tr_get_sql_record
  4. tr_get_long
  5. tr_get_int
  6. tr_get_str
  7. tr_get_dummies
  8. TR_get_record
  9. TR_delete_record
  10. TR_recover
  11. TR_check

   1 /***************************************
   2   $Revision: 1.5 $
   3 
   4   Functions to keep records for crash recovery
   5 
   6   Status: NOT REVUED, NOT TESTED
   7 
   8   Author(s):       Andrei Robachevsky
   9 
  10   ******************/ /******************
  11   Modification History:
  12         andrei (11/08/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 
  34 #include "ud_tr.h"
  35 #include "ud.h"
  36 
  37 /*************************************************************
  38 
  39 SQL Tables used to keep records needed for crash recovery
  40 
  41 CREATE TABLE transaction_rec (
  42 0  transaction_id int(11) DEFAULT '0' NOT NULL auto_increment,
  43 1  object_id int(10) unsigned DEFAULT '0' NOT NULL,
  44 2  sequence_id int(10) unsigned DEFAULT '1' NOT NULL,
  45 3  object_type tinyint(3) unsigned DEFAULT '0' NOT NULL,
  46 4  save varchar(256) DEFAULT '' NOT NULL,
  47 5  error_script blob DEFAULT '' NOT NULL,
  48 6  mode tinyint(4) unsigned DEFAULT '0' NOT NULL,
  49 7  succeeded tinyint(4) unsigned DEFAULT '0' NOT NULL,
  50 8  action tinyint(4) unsigned DEFAULT '0' NOT NULL,
  51 9  status tinyint(10) unsigned DEFAULT '0' NOT NULL,
  52 10  clean tinyint(3) DEFAULT '0' NOT NULL,
  53   PRIMARY KEY (transaction_id)
  54 );
  55 
  56 
  57 
  58 CREATE TABLE dummy_rec (
  59   transaction_id int(11) DEFAULT '0' NOT NULL,
  60   object_id int(10) unsigned DEFAULT '0' NOT NULL,
  61   PRIMARY KEY (transaction_id, object_id)
  62 );
  63 
  64 *************************************************************/
  65 
  66 /************************************************************
  67 * int TR_create_record()                                    *
  68 *                                                           *
  69 * Create TR record                                          *
  70 *                                                           *
  71 * First tries to delete record with the same transaction_id *
  72 * ( transaction_id == tr->transaction_id )                  *
  73 * Then creates a new record in transaction_rec table        *
  74 *                                                           *
  75 * Returns: transaction_id                                   *
  76 *                                                           *
  77 ************************************************************/
  78  
  79 long TR_create_record(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
  80 {
  81 SQ_result_set_t *sql_result;
  82 GString *query;
  83 int sql_err;
  84 
  85  if(tr->load_pass != 0) return(0); /* for fast loader just return */    
  86          
  87  if ((query = g_string_sized_new(STR_L)) == NULL){ 
  88   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n"); 
  89   die; 
  90  }
  91  /* delete record if exists*/
  92  
  93  TR_delete_record(tr);
  94  
  95  
  96  /* compose record */
  97 
  98  tr->action = TR_ACTION(tr->action) + TCP_ROLLBACK;
  99  
 100  g_string_sprintf(query, "INSERT transaction_rec "
 101                          "SET transaction_id=%ld, "
 102                          "object_id=%ld, "
 103                          "sequence_id=%ld, "
 104                          "object_type=%d, "
 105                          "mode=%d, "
 106                          "action=%d, "
 107                          "status=%d ",
 108                          tr->transaction_id, tr->object_id, tr->sequence_id, tr->class_type, tr->mode, TR_ACTION(tr->action), TR_STATUS(TCP_ROLLBACK));
 109  sql_err=SQ_execute_query(tr->sql_connection, query->str, &sql_result);
 110  
 111  
 112  /* in case of an error copy error code and return */ 
 113  if(sql_err) {
 114    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 115    die;
 116  }
 117  g_string_free(query, TRUE);
 118  return(tr->transaction_id); 
 119 }               
 120 
 121 
 122 /************************************************************
 123 * int TR_update_record()                                    *
 124 *                                                           *
 125 * UPdates TR record (transaction_rec or dummy_rec tables)   *
 126 *                                                           *
 127 * Updates the following fields:                             *
 128 * TF_DUMMY - dummy_rec, adding ID's as dummies are created  *
 129 * TF_SAVE  - writes down tr->save                           *
 130 * TF_STATUS - updates status (checkpointing)                *
 131 * TF_ESCRIPT - saves error script tr->error_script          *
 132 *                                                           *
 133 * Returns: transaction_id                                   *
 134 *                                                           *
 135 ************************************************************/
 136  
 137 long TR_update_record(Transaction_t *tr, int field)
     /* [<][>][^][v][top][bottom][index][help] */
 138 {
 139 SQ_result_set_t *sql_result;
 140 GString *query;
 141 int sql_err;
 142  
 143  if(tr->load_pass != 0) return(0); /* for fast loader just return */
 144  
 145  if ((query = g_string_sized_new(STR_L)) == NULL){ 
 146   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 147   die; 
 148  }
 149  
 150  switch(field){
 151    case TF_DUMMY:
 152           g_string_sprintf(query, "INSERT dummy_rec "
 153                                   "SET transaction_id=%ld, "
 154                                   "object_id=%ld ",
 155                                    tr->transaction_id, tr->dummy_id[tr->ndummy-1]);
 156           break;
 157 
 158    case TF_STATUS:
 159           g_string_sprintf(query, "UPDATE transaction_rec "
 160                                   "SET status=%d "
 161                                   "WHERE transaction_id=%ld ",
 162                                    TR_STATUS(tr->action), tr->transaction_id);
 163           break;
 164 
 165    case TF_SAVE:
 166           g_string_sprintf(query, "UPDATE transaction_rec "
 167                                   "SET save='%s' "
 168                                   "WHERE transaction_id=%ld ",
 169                                    tr->save, tr->transaction_id);
 170           break;
 171 
 172    case TF_ESCRIPT:
 173           g_string_sprintf(query, "UPDATE transaction_rec "
 174                                   "SET error_script='%s' "
 175                                   "WHERE transaction_id=%ld ",
 176                                    (tr->error_script)->str, tr->transaction_id);
 177           break;
 178   
 179    case TF_ID:
 180           g_string_sprintf(query, "UPDATE transaction_rec "
 181                                   "SET object_id=%ld, sequence_id=%ld, serial_id=%ld, succeeded=%d "
 182                                   "WHERE transaction_id=%ld ",
 183                                    tr->object_id, tr->sequence_id, tr->serial_id, tr->succeeded, tr->transaction_id);
 184           break;
 185   
 186    case TF_CLEAN:
 187           g_string_sprintf(query, "UPDATE transaction_rec "
 188                                   "SET clean=1 "
 189                                   "WHERE transaction_id=%ld ",
 190                                    tr->transaction_id);
 191           break;
 192                   
 193   default: die; break;
 194  }
 195 
 196  sql_err=SQ_execute_query(tr->sql_connection, query->str, &sql_result);
 197  
 198  
 199  /* in case of an error copy error code and return */ 
 200  if(sql_err) {
 201    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 202    die;
 203  }
 204  g_string_free(query, TRUE);
 205  return(tr->transaction_id); 
 206 }
 207 
 208 /* Query the database for transaction record */
 209 /* if there is no record with the specified ID - this is a new transaction */
 210 /************************************************************/ 
 211 SQ_result_set_t *tr_get_sql_record(SQ_connection_t *sql_connection, long transaction_id)
     /* [<][>][^][v][top][bottom][index][help] */
 212 {
 213 SQ_result_set_t *sql_result;
 214 GString *query;
 215 int sql_err;
 216  
 217  if ((query = g_string_sized_new(STR_L)) == NULL){ 
 218   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n"); 
 219   die; 
 220  }
 221  
 222  /* compose query */
 223  if (transaction_id == TR_LAST)
 224   g_string_sprintf(query, "SELECT * FROM transaction_rec WHERE clean=%d", TCP_UNCLEAN);
 225  else    
 226   g_string_sprintf(query, "SELECT * FROM transaction_rec WHERE transaction_id=%ld", transaction_id);
 227  
 228  /* execute query */
 229  sql_err=SQ_execute_query(sql_connection, query->str, &sql_result);
 230  
 231  
 232 /* in case of an error copy error code and return */ 
 233  if(sql_err) {
 234    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(sql_connection), query->str);
 235    die;
 236  }
 237  g_string_free(query, TRUE);
 238  return(sql_result);
 239 }
 240 
 241 
 242 /************************************************************/
 243 long tr_get_long(SQ_result_set_t *result, SQ_row_t *row, int col)
     /* [<][>][^][v][top][bottom][index][help] */
 244 {
 245  long val;
 246  if( sscanf(SQ_get_column_string_nocopy(result, row, col), "%ld", &val) < 1 ) { die; }
 247  return(val);
 248 }
 249 /************************************************************/
 250 int tr_get_int(SQ_result_set_t *result, SQ_row_t *row, int col)
     /* [<][>][^][v][top][bottom][index][help] */
 251 {
 252  int val;
 253  if( sscanf(SQ_get_column_string_nocopy(result, row, col), "%d", &val) < 1 ) { die; }
 254  return(val);
 255 }
 256 /************************************************************/
 257 char *tr_get_str(SQ_result_set_t *result, SQ_row_t *row, int col)
     /* [<][>][^][v][top][bottom][index][help] */
 258 {
 259  return(SQ_get_column_string_nocopy(result, row, col));
 260 }
 261 /************************************************************/
 262 int tr_get_dummies(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 263 {
 264 SQ_result_set_t *sql_result;
 265 GString *query;
 266 int sql_err;
 267 SQ_row_t *sql_row;
 268 
 269  if ((query = g_string_sized_new(STR_L)) == NULL){ 
 270   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");        
 271   die; 
 272  }
 273  
 274  /* compose query */
 275  g_string_sprintf(query, "SELECT * FROM dummy_rec WHERE transaction_id=%ld", tr->transaction_id);
 276  sql_err=SQ_execute_query(tr->sql_connection, query->str, &sql_result);
 277  
 278  
 279  /* in case of an error copy error code and return */ 
 280  if(sql_err) {
 281    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 282    die;
 283  }
 284  g_string_free(query, TRUE);
 285  
 286  tr->ndummy=0;
 287  while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
 288    if( sscanf(SQ_get_column_string_nocopy(sql_result, sql_row, DUMMY_OBJECT_ID), "%ld", &(tr->dummy_id[tr->ndummy])) < 1 ) { die; }
 289    tr->ndummy++;
 290  }
 291 
 292  SQ_free_result(sql_result);
 293  return(tr->ndummy);            
 294 }
 295 
 296 /************************************************************
 297 * Transaction_t * TR_get_record()                           *
 298 *                                                           *
 299 * Get the record left from the failed transaction           * 
 300 * and fill the tr structure                                 *
 301 *                                                           *
 302 * The following fields from transaction are essential:      *
 303 *                                                           *
 304 * class_type                                                *
 305 * action                                                    *
 306 * object_id                                                 *
 307 * sequesnce_id                                              *
 308 * save                                                      *
 309 * ndummy                                                    *
 310 * dummy_id[]                                                *
 311 * error_script                                              *
 312 *                                                           *
 313 * The following fields are filled in by transaction_new()   *
 314 * thread_upd                                                *
 315 * thread_ins                                                *
 316 * standalone                                                *
 317                                                             *
 318 * Return codes:                                             *
 319 *                                                           *
 320 * NULL - everything is clean, no cleanup is needed             *
 321 * 1 - the database was recovered successfully               *
 322 *                                                           *
 323 ************************************************************/
 324 Transaction_t *TR_get_record(SQ_connection_t *sql_connection, long transaction_id)
     /* [<][>][^][v][top][bottom][index][help] */
 325 {
 326   Transaction_t *tr;
 327   /* get the record from SQL table */
 328   SQ_result_set_t *result;
 329   SQ_row_t *row;
 330   C_Type_t class_type;
 331   int res;
 332 
 333 
 334   result = tr_get_sql_record(sql_connection, transaction_id);
 335   if (result == NULL) return (NULL); /* no further actions */
 336           
 337   /* fill in the Transaction structure */
 338   if ((row = SQ_row_next(result))== NULL) {
 339     tr = NULL;
 340   }
 341   else {
 342     /* Check if there is more than one row */
 343     res = 0;
 344     while(SQ_row_next(result))res = -1;
 345     if(res == -1) die;
 346   
 347 
 348     class_type = tr_get_class_type(result, row);
 349     if ((tr = transaction_new(sql_connection, class_type)) == NULL) die;
 350     tr->object_id = tr_get_object_id(result, row);
 351 
 352     /* Fill in all dummies that were created */
 353     tr_get_dummies(tr);
 354 
 355     tr->sequence_id = tr_get_sequence_id(result, row); 
 356     tr->serial_id = tr_get_serial_id(result, row);
 357     tr->save = g_strdup(tr_get_save(result, row)); 
 358     g_string_sprintf(tr->error_script, tr_get_escript(result, row)); 
 359 
 360 
 361     /* mode of operation */
 362     tr->mode = tr_get_mode(result, row);
 363     /* indication of success */
 364     tr->succeeded = tr_get_success(result, row);
 365     /* action is low byte */
 366     tr->action = tr_get_action(result, row);
 367     /* status is high byte */
 368     tr->action |= (tr_get_status(result, row) <<8);
 369     tr->action |= (tr_get_clean(result, row) << 8); /* bit0 bears this flag */
 370   }
 371 
 372   SQ_free_result(result);
 373   return(tr);
 374 }
 375 
 376 /************************************************************
 377 * int TR_delete_record()                                    *
 378 *                                                           *
 379 * Deletes all associated sql records                        *
 380 *                                                           *
 381 *                                                           *
 382 ************************************************************/
 383 void TR_delete_record(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 384 {
 385 GString *query;
 386 int sql_err;
 387 
 388   if(tr->load_pass != 0) return; /* for fast loader just return */
 389   
 390   /* Delete a record from SQL DB */
 391   if ((query = g_string_sized_new(STR_L)) == NULL){ 
 392    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n"); 
 393    die; 
 394   }
 395  
 396   /* compose query */
 397   g_string_sprintf(query, "DELETE FROM dummy_rec WHERE transaction_id=%ld", tr->transaction_id);
 398   sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
 399   /* in case of an error copy error code and return */ 
 400   if(sql_err) {
 401    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 402    die;
 403   }
 404   g_string_sprintf(query, "DELETE FROM transaction_rec WHERE transaction_id=%ld", tr->transaction_id);
 405   sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
 406   /* in case of an error copy error code and return */ 
 407   if(sql_err) {
 408    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 409    die;
 410   }
 411 
 412   g_string_free(query, TRUE);
 413  
 414 }
 415 
 416 
 417 /************************************************************
 418 * int TR_recover()                                          *
 419 *                                                           *
 420 * Cleans up the database after RIP daemon failure           *
 421 *                                                           *
 422 * Return codes:                                             *
 423 *                                                           *
 424 * 0 - everything is clean, no cleanup is needed             *
 425 * 1 - the database was recovered successfully               *
 426 *                                                           *
 427 ************************************************************/
 428 int TR_recover(SQ_connection_t *sql_connection)
     /* [<][>][^][v][top][bottom][index][help] */
 429 {
 430 int res;
 431 Transaction_t * tr;
 432 char *act_m;
 433 
 434 /* XXX SQ_db_name() ? */
 435  fprintf(stderr, "Checking the Database [%s]...", sql_connection->db);
 436  
 437  /* Get the transaction record */
 438  /* XXX for NRTM we may specify transaction_id = 0 ? */
 439  if ((tr = TR_get_record(sql_connection, TR_LAST)) == NULL) {
 440     /* everything is clean */
 441     res = 0;
 442     fprintf(stderr, "[OK]\n");
 443     ER_inf_va(FAC_SV, 0xFFFFFF, "STATUS:[%s]=OK", sql_connection->db);
 444  }   
 445  else {/* Not everything was perfect :( */
 446     if(ACT_CREATE(tr->action))act_m="CREATE";
 447      else if(ACT_UPDATE(tr->action))act_m="UPDATE";
 448       else act_m="DELETE";
 449     ER_inf_va(FAC_SV, 0xFFFFFF, "STATUS:[%s]=FAILED [object_id=%ld, sequence_id=%ld, serial_id=%ld, transaction_id=%ld, action=%s]", 
 450                                  sql_connection->db, tr->object_id, tr->sequence_id, tr->serial_id, tr->transaction_id, act_m);
 451     fprintf(stderr, "[FAILED]\n"
 452                     "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
 453                     "+ LAST TRANSACTION IS INCOMPLETE. ENTERING CRASH RECOVERY MODE +\n"
 454                     "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
 455    /* Failure occured before the ack was sent */
 456    /* Roll back the transaction */
 457    /* Delete transaction record (TR) as if it never happened */  
 458    /************************* R O L L B A C K ***************************/
 459    if(TS_ROLLBACK(tr->action)) {
 460      fprintf(stderr, "  STATUS: Rollback\n");
 461      ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s]=ROLLBACK", sql_connection->db);
 462      
 463     /* don't rollback the transaction if we were to delete the object, but could not */
 464      if(!TS_ROLLBACKED(tr->action)){
 465              fprintf(stderr, "  STATUS: Rollback incomplete, completing...");
 466              UD_rollback(tr);
 467              CP_ROLLBACK_PASSED(tr->action); TR_update_status(tr);
 468              fprintf(stderr, "[OK]\n");
 469              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Rollback incomplete, completing - OK", sql_connection->db);
 470      } else  { fprintf(stderr, "  STATUS: Rollback complete [PASSED]\n");
 471                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Rollback complete - PASSED", sql_connection->db); 
 472              }
 473             
 474      
 475      if(!TS_ROLLBACKED_NH(tr->action)){
 476              fprintf(stderr, "  STATUS: NH rollback incomplete, completing...");
 477              NH_rollback(tr->sql_connection);
 478              CP_ROLLBACK_NH_PASSED(tr->action); TR_update_status(tr);
 479              fprintf(stderr, "[OK]\n");
 480              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] NH rollback incomplete, completing - OK", sql_connection->db);
 481      } else  { fprintf(stderr, "  STATUS: NH rollback complete [PASSED]\n");
 482                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] NH rollback complete - PASSED", sql_connection->db); 
 483              }
 484      /* In update mode delete TR record. Next time (if any) DBupdate tries to submit, we'll start from scratch */
 485      /* In NRTM mode we create a serial record even in case of failure (tr->succeeded ==0)*/
 486      /* So in NRTM we need to clean up serials/transaction as well */
 487      if(IS_UPDATE(tr->mode)){
 488              fprintf(stderr, "  STATUS: Serial does not need to be restored, deleting TR...");
 489              TR_delete_record(tr);
 490              fprintf(stderr, "[OK]\n");
 491              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Serial does not need to be restored, deleting TR - OK", sql_connection->db); 
 492      } else {
 493              fprintf(stderr, "  STATUS: Cleaning serial, deleting TR...");
 494              if(!TS_CREATED_S(tr->action))
 495                UD_rollback_serial(tr);
 496              else 
 497                UD_commit_serial(tr);
 498              TR_delete_record(tr);
 499              fprintf(stderr, "[OK]\n");
 500              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Cleaning serial, deleting TR - OK", sql_connection->db);
 501      }
 502       
 503      res = 1;
 504    }
 505    /************************* C O M M I T ******************************/
 506    else { /* commit */
 507     /* The ack was sent */
 508     /* Complete the commit */
 509     fprintf(stderr, "  STATUS: Commit\n");
 510     ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s]=COMMIT", sql_connection->db);
 511     /* We keep the transaction record in case DBupdate failed */
 512     /* and requests the same transaction after recovery ? */
 513     /* Such approach will allow us to avoid 3-way handshaking with DBupdate */
 514     /* So we never blocked or timed out during that phase */
 515 
 516     /* XXX But first I implemented another approach (to keep DB tiny/tidy): */
 517     /* 1. Process the transaction */
 518     /* 2. In case of failure - rollback - NACK */
 519     /* 3. Before commit - ACK (UD_ack()) */
 520     /* 4. If UD_ack returns an error preserve a tr_record */
 521     /* 5. Commit */
 522     /* 6. If still alive and UD_ack passed - delete the record - all is clean */
 523     /*    Otherwise preserve a tr_record */
 524     
 525     if(ACT_DELETE(tr->action)) {
 526      /* check if we passed deletion process */
 527      if(!TS_DELETED(tr->action)){
 528              fprintf(stderr, "  STATUS: Delete incomplete, completing...");
 529              UD_delete(tr);
 530              CP_DELETE_PASSED(tr->action); TR_update_status(tr);
 531              fprintf(stderr, "[OK]\n");
 532              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Delete incomplete, completing - OK", sql_connection->db);
 533      } else  { fprintf(stderr, "  STATUS: Delete complete [PASSED]\n");
 534                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Delete complete - PASSED", sql_connection->db);
 535              }
 536     }
 537     else { /* update or create */
 538      /* Check if we passed the deletion pass of commit */
 539      if(!TS_COMMITTED_I(tr->action)){
 540              fprintf(stderr, "  STATUS: Commit phase I incomplete, completing...");
 541              UD_commit_I(tr);
 542              CP_COMMIT_I_PASSED(tr->action); TR_update_status(tr);
 543              fprintf(stderr, "[OK]\n");
 544              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Commit phase I incomplete, completing - OK", sql_connection->db);
 545      } else  { fprintf(stderr, "  STATUS: Commit phase I complete [PASSED]\n");
 546                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Commit phase I complete - PASSED", sql_connection->db);
 547              } 
 548      /* Check if we passed the second pass of commit */
 549      if(!TS_COMMITTED_II(tr->action)){
 550              fprintf(stderr, "  STATUS: Commit phase II incomplete, completing...");
 551              UD_commit_II(tr);
 552              CP_COMMIT_II_PASSED(tr->action); TR_update_status(tr);
 553              fprintf(stderr, "[OK]\n");
 554              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Commit phase II incomplete, completing - OK", sql_connection->db);
 555      } else  { fprintf(stderr, "  STATUS: Commit phase II complete [PASSED]\n");
 556                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Commit phase II complete - PASSED", sql_connection->db);
 557              }
 558     } /* end of delete, create, update specific operations */
 559     
 560      /* Check if we passed the NH repository commit */
 561      if(!TS_COMMITTED_NH(tr->action)){
 562              fprintf(stderr, "  STATUS: NH commit incomplete, completing...");
 563              NH_commit(tr->sql_connection);
 564              CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr);
 565              fprintf(stderr, "[OK]\n");
 566              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] NH commit incomplete, completing - OK", sql_connection->db);
 567      } else  { fprintf(stderr, "  STATUS: NH commit complete [PASSED]\n");
 568                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] NH commit complete - PASSED", sql_connection->db);
 569              }
 570      
 571      /* create serial file */
 572      if(!TS_CREATED_S(tr->action))
 573      {
 574        fprintf(stderr, "  STATUS: Serial rollback and restore...");
 575        UD_rollback_serial(tr);
 576        if(ACT_UPD_CLLPS(tr->action)) { /* this is a collapsed update (DEL + ADD) */
 577           tr->action=TA_DELETE; UD_create_serial(tr);
 578           tr->sequence_id++;
 579           tr->action=TA_CREATE; UD_create_serial(tr);
 580        }else if(ACT_UPD_DUMMY(tr->action)) { /* this was a dummy update - we need only CREATE serial */
 581           tr->action=TA_CREATE;
 582           tr->sequence_id++; /* because in fact this is an update (sequence_id=2) */
 583           UD_create_serial(tr); 
 584        } else UD_create_serial(tr);
 585        CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
 586      }
 587      fprintf(stderr, "[OK]\n");
 588      ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Serial rollback and restore - OK", sql_connection->db);
 589      UD_commit_serial(tr);
 590 
 591      fprintf(stderr, "  STATUS: Marking TR as clean...");
 592      TR_mark_clean(tr);
 593    
 594      fprintf(stderr, "[OK]\n");
 595      ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Marking TR as clean - OK", sql_connection->db);
 596      res = 2;
 597   }
 598  }
 599  transaction_free(tr); 
 600  fprintf(stderr, "  STATUS: The Database is clean \n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
 601  ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s]=CLEAN", sql_connection->db);
 602  
 603  return(res);
 604 } 
 605 
 606 /************************************************************
 607 * int TR_check()                                            *
 608 *                                                           *
 609 * Checks if the requested transaction has already been      *
 610 * processed. This could happen when DBupdate crashes while  *
 611 * RIPupdate successfully completes the transaction.         *
 612 *                                                           *
 613 * If this is the case, RIPupdate will return an ack to      *
 614 * DBupdate as if the transaction was processed again        *
 615 *                                                           *
 616 * Return codes:                                             *
 617 * 0 - everything is clean - this is a new transaction       *
 618 * 1 - the stored transaction was re-played                  *
 619 *                                                           *
 620 ************************************************************/
 621 int TR_check(SQ_connection_t *sql_connection, long transaction_id, int sockfd)
     /* [<][>][^][v][top][bottom][index][help] */
 622 {
 623 Transaction_t * tr;
 624 
 625 
 626  /* transaction_id == 0 means that only one record is maintained */
 627  /* therefore it is not possible to replay the transaction */
 628  /* and transaction_id does not uniquely identify the transaction */
 629  /* suitable for NRTM and for backwards compatibility */
 630  if(transaction_id <=0) return(0);
 631  /* Get the transaction record */
 632  /* XXX for NRTM we may specify transaction_id = 0 ? */
 633  if ((tr = TR_get_record(sql_connection, transaction_id)) == NULL) return(0); /* everything is clean */
 634  
 635  /* Check if the record is clean (it should be ) */
 636  /* that means that either the transaction finished normally */
 637  /* or crash recovery procedure cleaned up the database (and record as well ) */
 638  if (TS_CLEAN(tr->action)) {
 639    /* send an acknowledgement */
 640    /* XXX Wait for ack */
 641    /* XXX if ack is timed out just return, else delete the tr_record */
 642    /* if(UD_ack(tr)==0) TR_delete_record(tr); */
 643 
 644    /* Send an acknowledgement, append note that transaction was rerun */
 645    tr->socket=sockfd;
 646    g_string_sprintfa(tr->error_script,"I[%ld]: requested transaction was processed before\n", transaction_id);
 647    UD_ack(tr);
 648    ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] requested transaction was processed before\n", transaction_id);   
 649    transaction_free(tr);
 650  }
 651  else {
 652          ER_perror(FAC_UD, UD_SQL, "TR is not clean\n");
 653          die; /* the record should be clean */ 
 654  }
 655  return(1);
 656 }
 657 
 658 

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