## modules/ud/ud_recover.c

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

## DEFINITIONS

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.8 $
       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,2002                    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(IS_STANDALONE(tr->mode)) return(0); /* for 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(IS_STANDALONE(tr->mode)) return(0); /* for 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 * transaction_id                                            *
     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->transaction_id = tr_get_transaction_id(result, row);
     351     tr->object_id = tr_get_object_id(result, row);
     352
     353     /* Fill in all dummies that were created */
     354     tr_get_dummies(tr);
     355
     356     tr->sequence_id = tr_get_sequence_id(result, row);
     357     tr->serial_id = tr_get_serial_id(result, row);
     358     tr->save = g_strdup(tr_get_save(result, row));
     359     g_string_sprintf(tr->error_script, tr_get_escript(result, row));
     360
     361
     362     /* mode of operation */
     363     tr->mode = tr_get_mode(result, row);
     364     /* indication of success */
     365     tr->succeeded = tr_get_success(result, row);
     366     /* action is low byte */
     367     tr->action = tr_get_action(result, row);
     368     /* status is high byte */
     369     tr->action |= (tr_get_status(result, row) <<8);
     370     tr->action |= (tr_get_clean(result, row) << 8); /* bit0 bears this flag */
     371   }
     372
     373   SQ_free_result(result);
     374   return(tr);
     375 }
     376
     377 /************************************************************
     378 * int TR_delete_record()                                    *
     379 *                                                           *
     380 * Deletes all associated sql records                        *
     381 *                                                           *
     382 *                                                           *
     383 ************************************************************/
     384 void TR_delete_record(Transaction_t *tr)
         /* [<][>][^][v][top][bottom][index][help] */
     385 {
     386 GString *query;
     387 int sql_err;
     388
     389   if(IS_STANDALONE(tr->mode)) return; /* for loader just return */
     390
     391   /* Delete a record from SQL DB */
     392   if ((query = g_string_sized_new(STR_L)) == NULL){
     393    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
     394    die;
     395   }
     396
     397   /* compose query */
     398   g_string_sprintf(query, "DELETE FROM dummy_rec WHERE transaction_id=%ld", tr->transaction_id);
     399   sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
     400   /* in case of an error copy error code and return */
     401   if(sql_err) {
     402    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
     403    die;
     404   }
     405   g_string_sprintf(query, "DELETE FROM transaction_rec WHERE transaction_id=%ld", tr->transaction_id);
     406   sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
     407   /* in case of an error copy error code and return */
     408   if(sql_err) {
     409    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
     410    die;
     411   }
     412
     413   g_string_free(query, TRUE);
     414
     415 }
     416
     417
     418 /************************************************************
     419 * int TR_recover()                                          *
     420 *                                                           *
     421 * Cleans up the database after RIP daemon failure           *
     422 *                                                           *
     423 * Return codes:                                             *
     424 *                                                           *
     425 * 0 - everything is clean, no cleanup is needed             *
     426 * 1 - the database was recovered successfully               *
     427 *                                                           *
     428 ************************************************************/
     429 int TR_recover(SQ_connection_t *sql_connection)
         /* [<][>][^][v][top][bottom][index][help] */
     430 {
     431 int res;
     432 Transaction_t * tr;
     433 char *act_m;
     434
     435 /* XXX SQ_db_name() ? */
     436  fprintf(stderr, "Checking the Database [%s]...", sql_connection->db);
     437
     438  /* Get the transaction record */
     439  /* XXX for NRTM we may specify transaction_id = 0 ? */
     440  if ((tr = TR_get_record(sql_connection, TR_LAST)) == NULL) {
     441     /* everything is clean */
     442     res = 0;
     443     fprintf(stderr, "[OK]\n");
     444     ER_inf_va(FAC_SV, 0xFFFFFF, "STATUS:[%s]=OK", sql_connection->db);
     445  }
     446  else {/* Not everything was perfect :( */
     447     if(ACT_CREATE(tr->action))act_m="CREATE";
     448      else if(ACT_UPDATE(tr->action))act_m="UPDATE";
     449       else act_m="DELETE";
     450     ER_inf_va(FAC_SV, 0xFFFFFF, "STATUS:[%s]=FAILED [object_id=%ld, sequence_id=%ld, serial_id=%ld, transaction_id=%ld, action=%s]",
     451                                  sql_connection->db, tr->object_id, tr->sequence_id, tr->serial_id, tr->transaction_id, act_m);
     452     fprintf(stderr, "[FAILED]\n"
     453                     "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
     454                     "+ LAST TRANSACTION IS INCOMPLETE. ENTERING CRASH RECOVERY MODE +\n"
     455                     "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
     456    /* Failure occured before the ack was sent */
     457    /* Roll back the transaction */
     458    /* Delete transaction record (TR) as if it never happened */
     459    /************************* R O L L B A C K ***************************/
     460    if(TS_ROLLBACK(tr->action)) {
     461      fprintf(stderr, "  STATUS: Rollback\n");
     462      ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s]=ROLLBACK", sql_connection->db);
     463
     464     /* don't rollback the transaction if we were to delete the object, but could not */
     465      if(!TS_ROLLBACKED(tr->action)){
     466              fprintf(stderr, "  STATUS: Rollback incomplete, completing...");
     467              UD_rollback(tr);
     468              CP_ROLLBACK_PASSED(tr->action); TR_update_status(tr);
     469              fprintf(stderr, "[OK]\n");
     470              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Rollback incomplete, completing - OK", sql_connection->db);
     471      } else  { fprintf(stderr, "  STATUS: Rollback complete [PASSED]\n");
     472                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Rollback complete - PASSED", sql_connection->db);
     473              }
     474
     475
     476      if(!TS_ROLLBACKED_NH(tr->action)){
     477              fprintf(stderr, "  STATUS: NH rollback incomplete, completing...");
     478              NH_rollback(tr->sql_connection);
     479              CP_ROLLBACK_NH_PASSED(tr->action); TR_update_status(tr);
     480              fprintf(stderr, "[OK]\n");
     481              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] NH rollback incomplete, completing - OK", sql_connection->db);
     482      } else  { fprintf(stderr, "  STATUS: NH rollback complete [PASSED]\n");
     483                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] NH rollback complete - PASSED", sql_connection->db);
     484              }
     485      /* In update mode delete TR record. Next time (if any) DBupdate tries to submit, we'll start from scratch */
     486      /* In NRTM mode we create a serial record even in case of failure (tr->succeeded ==0)*/
     487      /* So in NRTM we need to clean up serials/transaction as well */
     488      if(IS_UPDATE(tr->mode)){
     489              fprintf(stderr, "  STATUS: Serial does not need to be restored, deleting TR...");
     490              TR_delete_record(tr);
     491              fprintf(stderr, "[OK]\n");
     492              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Serial does not need to be restored, deleting TR - OK", sql_connection->db);
     493      } else {
     494              fprintf(stderr, "  STATUS: Cleaning serial, deleting TR...");
     495              if(!TS_CREATED_S(tr->action))
     496                UD_rollback_serial(tr);
     497              else
     498                UD_commit_serial(tr);
     499              TR_delete_record(tr);
     500              fprintf(stderr, "[OK]\n");
     501              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Cleaning serial, deleting TR - OK", sql_connection->db);
     502      }
     503
     504      res = 1;
     505    }
     506    /************************* C O M M I T ******************************/
     507    else { /* commit */
     508     /* The ack was sent */
     509     /* Complete the commit */
     510     fprintf(stderr, "  STATUS: Commit\n");
     511     ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s]=COMMIT", sql_connection->db);
     512     /* We keep the transaction record in case DBupdate failed */
     513     /* and requests the same transaction after recovery ? */
     514     /* Such approach will allow us to avoid 3-way handshaking with DBupdate */
     515     /* So we never blocked or timed out during that phase */
     516
     517     /* XXX But first I implemented another approach (to keep DB tiny/tidy): */
     518     /* 1. Process the transaction */
     519     /* 2. In case of failure - rollback - NACK */
     520     /* 3. Before commit - ACK (UD_ack()) */
     521     /* 4. If UD_ack returns an error preserve a tr_record */
     522     /* 5. Commit */
     523     /* 6. If still alive and UD_ack passed - delete the record - all is clean */
     524     /*    Otherwise preserve a tr_record */
     525
     526     if(ACT_DELETE(tr->action)) {
     527      /* check if we passed deletion process */
     528      if(!TS_DELETED(tr->action)){
     529              fprintf(stderr, "  STATUS: Delete incomplete, completing...");
     530              UD_delete(tr);
     531              CP_DELETE_PASSED(tr->action); TR_update_status(tr);
     532              fprintf(stderr, "[OK]\n");
     533              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Delete incomplete, completing - OK", sql_connection->db);
     534      } else  { fprintf(stderr, "  STATUS: Delete complete [PASSED]\n");
     535                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Delete complete - PASSED", sql_connection->db);
     536              }
     537     }
     538     else { /* update or create */
     539      /* Check if we passed the deletion pass of commit */
     540      if(!TS_COMMITTED_I(tr->action)){
     541              fprintf(stderr, "  STATUS: Commit phase I incomplete, completing...");
     542              UD_commit_I(tr);
     543              CP_COMMIT_I_PASSED(tr->action); TR_update_status(tr);
     544              fprintf(stderr, "[OK]\n");
     545              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Commit phase I incomplete, completing - OK", sql_connection->db);
     546      } else  { fprintf(stderr, "  STATUS: Commit phase I complete [PASSED]\n");
     547                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Commit phase I complete - PASSED", sql_connection->db);
     548              }
     549      /* Check if we passed the second pass of commit */
     550      if(!TS_COMMITTED_II(tr->action)){
     551              fprintf(stderr, "  STATUS: Commit phase II incomplete, completing...");
     552              UD_commit_II(tr);
     553              CP_COMMIT_II_PASSED(tr->action); TR_update_status(tr);
     554              fprintf(stderr, "[OK]\n");
     555              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Commit phase II incomplete, completing - OK", sql_connection->db);
     556      } else  { fprintf(stderr, "  STATUS: Commit phase II complete [PASSED]\n");
     557                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Commit phase II complete - PASSED", sql_connection->db);
     558              }
     559     } /* end of delete, create, update specific operations */
     560
     561      /* Check if we passed the NH repository commit */
     562      if(!TS_COMMITTED_NH(tr->action)){
     563              fprintf(stderr, "  STATUS: NH commit incomplete, completing...");
     564              NH_commit(tr->sql_connection);
     565              CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr);
     566              fprintf(stderr, "[OK]\n");
     567              ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] NH commit incomplete, completing - OK", sql_connection->db);
     568      } else  { fprintf(stderr, "  STATUS: NH commit complete [PASSED]\n");
     569                ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] NH commit complete - PASSED", sql_connection->db);
     570              }
     571
     572      /* create serial file */
     573      if(!TS_CREATED_S(tr->action))
     574      {
     575        fprintf(stderr, "  STATUS: Serial rollback and restore...");
     576        UD_rollback_serial(tr);
     577        if(ACT_UPD_CLLPS(tr->action)) { /* this is a collapsed update (DEL + ADD) */
     578           tr->action=TA_DELETE; UD_create_serial(tr);
     579           tr->sequence_id++;
     580           tr->action=TA_CREATE; UD_create_serial(tr);
     581        }else if(ACT_UPD_DUMMY(tr->action)) { /* this was a dummy update - we need only CREATE serial */
     582           tr->action=TA_CREATE;
     583           tr->sequence_id++; /* because in fact this is an update (sequence_id=2) */
     584           UD_create_serial(tr);
     585        } else UD_create_serial(tr);
     586        CP_CREATE_S_PASSED(tr->action); TR_update_status(tr);
     587      }
     588      fprintf(stderr, "[OK]\n");
     589      ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Serial rollback and restore - OK", sql_connection->db);
     590      UD_commit_serial(tr);
     591
     592      fprintf(stderr, "  STATUS: Marking TR as clean...");
     593      TR_mark_clean(tr);
     594
     595      fprintf(stderr, "[OK]\n");
     596      ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s] Marking TR as clean - OK", sql_connection->db);
     597      res = 2;
     598   }
     599  }
     600  transaction_free(tr);
     601  fprintf(stderr, "  STATUS: The Database is clean \n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
     602  ER_inf_va(FAC_SV, 0xFFFFFF,"STATUS:[%s]=CLEAN", sql_connection->db);
     603
     604  return(res);
     605 }
     606
     607 /************************************************************
     608 * int TR_check()                                            *
     609 *                                                           *
     610 * Checks if the requested transaction has already been      *
     611 * processed. This could happen when DBupdate crashes while  *
     612 * RIPupdate successfully completes the transaction.         *
     613 *                                                           *
     614 * If this is the case, RIPupdate will return an ack to      *
     615 * DBupdate as if the transaction was processed again        *
     616 *                                                           *
     617 * Return codes:                                             *
     618 * 0 - everything is clean - this is a new transaction       *
     619 * 1 - the stored transaction was re-played                  *
     620 *                                                           *
     621 ************************************************************/
     622 int TR_check(SQ_connection_t *sql_connection, long transaction_id, int sockfd)
         /* [<][>][^][v][top][bottom][index][help] */
     623 {
     624 Transaction_t * tr;
     625
     626
     627  /* transaction_id == 0 means that only one record is maintained */
     628  /* therefore it is not possible to replay the transaction */
     629  /* and transaction_id does not uniquely identify the transaction */
     630  /* suitable for NRTM and for backwards compatibility */
     631  if(transaction_id <=0) return(0);
     632  /* Get the transaction record */
     633  /* XXX for NRTM we may specify transaction_id = 0 ? */
     634  if ((tr = TR_get_record(sql_connection, transaction_id)) == NULL) return(0); /* everything is clean */
     635
     636  /* Check if the record is clean (it should be ) */
     637  /* that means that either the transaction finished normally */
     638  /* or crash recovery procedure cleaned up the database (and record as well ) */
     639  if (TS_CLEAN(tr->action)) {
     640    /* send an acknowledgement */
     641    /* XXX Wait for ack */
     642    /* XXX if ack is timed out just return, else delete the tr_record */
     643    /* if(UD_ack(tr)==0) TR_delete_record(tr); */
     644
     645    /* Send an acknowledgement, append note that transaction was rerun */
     646    tr->socket=sockfd;
     647    g_string_sprintfa(tr->error_script,"I[%ld]: requested transaction was processed before\n", transaction_id);
     648    UD_ack(tr);
     649    ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] requested transaction was processed before\n", transaction_id);
     650    transaction_free(tr);
     651  }
     652  else {
     653          ER_perror(FAC_UD, UD_SQL, "TR is not clean\n");
     654          die; /* the record should be clean */
     655  }
     656  return(1);
     657 }
     658
     659

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