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

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