utils/hs_cleanup/hs_cleanup.c

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

FUNCTIONS

This source file includes following functions.
  1. update_prev_serial_of_next_object
  2. update_serial_in_last
  3. update_serial_in_history
  4. archive_history
  5. archive_last
  6. delete_history_entry
  7. delete_last_entry
  8. main
  9. usage
  10. get_highest_serial_before_date
  11. archive_serials_and_history
  12. fetch_timestamp_from_last
  13. get_highest_object_id
  14. check_if_next_is_deletion
  15. create_archive_tables
  16. create_table
  17. update_history_archive_sequence_id_and_timestamp
  18. update_history_archive_object_id_and_sequence_id
  19. update_prev_serial_of_object
  20. update_serial_of_object
  21. archive_serial
  22. archive_failed_transaction
  23. copy_into_history_archive
  24. copy_deleted_object_into_history_archive
  25. delete_serial_entry
  26. delete_failed_transaction_entry
  27. delete_entry_from_object_table
  28. delete_archived_objects
  29. delete_serial_archive_entry
  30. delete_history_archive_entry
  31. find_unreferenced_history_entries
  32. delete_unreferenced_history_entries
  33. PushTblObjList
  34. delete_dummy_history_objects
  35. lock_last_history_serial_tables
  36. unlock_all_tables
  37. optimize_sql_table
  38. execute_sql_query
  39. execute_sql_command
  40. create_auxiliary_table
  41. reset_auxiliary_table
  42. drop_auxiliary_table
  43. update_hs_auxiliary_checkpoint
  44. crash_recovery
  45. exists_checkpointing_table
  46. get_smallest_serial
  47. get_random_number_in_range
  48. do_crash

   1 /***************************************
   2   $Revision: 1.33 $
   3 
   4   History/Serial Cleanup (hs_cleanup). This utility archives serials
   5   and history entries, and deletes them from the live database.
   6 
   7   Status: COMPLETE, NOT REVUED, NOT FULLY TESTED
   8 
   9   ******************/ /******************
  10   Filename            : hs_cleanup.c
  11   Authors             : Daniele Arena
  12   OSs Tested          : Solaris 7
  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 
  35 /********** INCLUDES **********/
  36 
  37 /* Standard includes */
  38 #include <stdio.h>
  39 #include <stdlib.h>
  40 #include <string.h>
  41 #include <sys/time.h> /* for time() */
  42 #include <math.h> /* for floor() */
  43 #include <unistd.h> /* for sleep() */
  44 
  45 /* RIP includes */
  46 #include "mysql_driver.h"
  47 #include "stubs.h"
  48 
  49 
  50 /********** DEFINES **********/
  51 
  52 /* Default settings for the SQL DB */
  53 #define MYSQL_HOST "myhost.mydb.net"
  54 #define MYSQL_PORT 3306
  55 #define MYSQL_USER "sqluser"
  56 #define MYSQL_PSWD "sqlpswd"
  57 #define MYSQL_DB "sqldb"
  58 
  59 /* String sizes */
  60 #define STR_S   63
  61 #define STR_M   255
  62 #define STR_L   1023
  63 #define STR_XL  4095
  64 #define STR_XXL 16383
  65 
  66 /* Maximum allowed length of a SQL command */
  67 #define MAXCMDLEN 8192
  68 
  69 
  70 /* 
  71  * Standard time constants:
  72  * 1min = 60s
  73  * 1hr = 3600s
  74  * 1day = 86400s
  75  * 1wk = 604800s
  76  */
  77 
  78 #define MINUTE 60
  79 #define HOUR 3600
  80 #define DAY 86400
  81 #define WEEK 604800
  82 
  83 /* For debugging purposes */
  84 #define DEBUG 0
  85 
  86 /* If this flag is set, older-and-already-archived history object won't get deleted.
  87    XXX: currently this *must* be set, otherwise weird things happen. To be fixed. */
  88 #define ARCHIVE_ONLY 1
  89 
  90 /* Object types from RIP */
  91 #define OBJ_TYPE_DUMMY 100
  92 
  93 /* For crash-recovery tests */
  94 
  95 /* Activate this flag if you want to test crash-recovery */
  96 #define CRASHTEST 0
  97 
  98 /* Helpers for blackbox crashtest */
  99 #define IS_LAST_STEP 1
 100 #define MAX_STEPS 8
 101 
 102 /********** ENUMS **********/
 103 
 104 /* List of possible "atlast" values */
 105 enum {
 106   IN_HISTORY_TABLE = 0,
 107   IN_LAST_TABLE,
 108   IN_FAILED_TRANSACTION_TABLE,
 109   IN_UNDEF_TABLE
 110 };
 111 
 112 const char *atlast_table[] = { "history",
 113                                "last",
 114                                "failed_transaction" };
 115 
 116 /* List of operations for a serial in RIP */
 117 enum {
 118   OP_NULL = 0,
 119   OP_ADD,
 120   OP_DELETE,
 121   OP_UPDATE
 122 };
 123 
 124 /* For checkpointing/crash-recovery:
 125  * we mark the actions to be taken if recovering
 126  */
 127 enum {
 128   CHKP_NOOP = 0,
 129   CHKP_DELETE_FROM_ARCHIVE,
 130   CHKP_DELETE_FROM_LIVE,
 131   CHKP_DELETE_FROM_LIVE_ONLY_SERIAL,
 132   CHKP_DONE
 133 };
 134 
 135 
 136 
 137 /********** TYPEDEFS **********/
 138 
 139 /* A structure to hold an object from last or history table */
 140 typedef struct table_object *tblobjPtr;
 141 
 142 typedef struct table_object {
 143   long objid;
 144   long seqid;
 145   tblobjPtr next;
 146 } tblObjList;
 147 
 148 
 149 
 150 /********** GLOBAL VARIABLES **********/
 151 
 152 SQ_connection_t *connection;
 153 int debug = DEBUG;
 154 int archive_only = ARCHIVE_ONLY;
 155 long highest_objid;
 156 /* For crash recovery test */
 157 long crashing_serial;
 158 int crash_position;
 159 int code_location;
 160 int case_branch;
 161 
 162 
 163 /********** FUNCTION DEFINITIONS **********/
 164 
 165 
 166 /*** Main functions ***/
 167 int main (int argc, char *argv[]);
 168 void usage(char *argv[]);
 169 
 170 /*** Archiving algorithm functions ***/
 171 static int get_highest_serial_before_date(long *highest_serial_ptr, long date);
 172 static int archive_serials_and_history(long highest_serial);
 173 static long fetch_timestamp_from_last(long obj_id, long ser_id);
 174 static long get_highest_object_id();
 175 static int check_if_next_is_deletion (long obj_id, long seq_id);
 176 
 177 /*** Table creation ***/
 178 static int create_archive_tables();
 179 static int create_table(const char *cmd);
 180 
 181 /*** Object update ***/
 182 static int update_history_archive_sequence_id_and_timestamp(long ser_id, long new_seq_id, long new_timestamp);
 183 static int update_history_archive_object_id_and_sequence_id (long ser_id, long new_obj_id, long new_seq_id);
 184 static int update_prev_serial_of_object (long obj_id, long seq_id, long prev_ser, const char *tablename);
 185 static int update_serial_of_object (long obj_id, long seq_id, long ser_id, const char *tablename);
 186 #define update_prev_serial_of_next_object(obj_id, seq_id, prev_ser, tablename) update_prev_serial_of_object(obj_id, seq_id+1, prev_ser, tablename)
     /* [<][>][^][v][top][bottom][index][help] */
 187 #define update_serial_in_last(obj_id, seq_id, ser_id) update_serial_of_object(obj_id, seq_id, ser_id, "last")
     /* [<][>][^][v][top][bottom][index][help] */
 188 #define update_serial_in_history(obj_id, seq_id, ser_id) update_serial_of_object(obj_id, seq_id, ser_id, "history")
     /* [<][>][^][v][top][bottom][index][help] */
 189 
 190 /*** Object archiving ***/
 191 static int archive_serial(long ser_id, long obj_id, long seq_id, int op);
 192 static int archive_failed_transaction(long ser_id);
 193 static int copy_into_history_archive(long ser_id, long obj_id, long seq_id, const char *tablename);
 194 static int copy_deleted_object_into_history_archive (long ser_id, long obj_id, long seq_id, const char *tablename);
 195 #define archive_history(ser_id, obj_id, seq_id) copy_into_history_archive(ser_id, obj_id, seq_id, "history")
     /* [<][>][^][v][top][bottom][index][help] */
 196 #define archive_last(ser_id, obj_id, seq_id) copy_into_history_archive(ser_id, obj_id, seq_id, "last")
     /* [<][>][^][v][top][bottom][index][help] */
 197 
 198 /*** Object deletion ***/
 199 static int delete_serial_entry(long ser_id);
 200 static int delete_failed_transaction_entry (long ser_id);
 201 static int delete_entry_from_object_table(long obj_id, long seq_id, const char* tablename);
 202 static int delete_archived_objects(long ser_id);
 203 static int delete_serial_archive_entry(long ser_id);
 204 static int delete_history_archive_entry(long ser_id);
 205 #define delete_history_entry(obj_id, seq_id) delete_entry_from_object_table(obj_id, seq_id, "history")
     /* [<][>][^][v][top][bottom][index][help] */
 206 #define delete_last_entry(obj_id, seq_id) delete_entry_from_object_table(obj_id, seq_id, "last")
     /* [<][>][^][v][top][bottom][index][help] */
 207 
 208 /*** Handling of older, unreferenced history entries ***/
 209 static tblObjList *find_unreferenced_history_entries(long date);
 210 static int delete_unreferenced_history_entries(tblObjList *objectsToDelete);
 211 
 212 /*** Handling of dummy objects ***/
 213 static int delete_dummy_history_objects();
 214 
 215 /*** Interactions with SQL DB ***/
 216 static int lock_last_history_serial_tables();
 217 static int unlock_all_tables();
 218 static int optimize_sql_table(const char* tablename);
 219 
 220 /*** SQL interfaces ***/
 221 static int execute_sql_command(const char *cmd);
 222 static int execute_sql_query(const char *query, SQ_result_set_t **result_ptr);
 223 
 224 /*** Checkpointing ***/
 225 static int create_auxiliary_table();
 226 static int reset_auxiliary_table();
 227 static int drop_auxiliary_table();
 228 static int update_hs_auxiliary_checkpoint(long ser_id, long obj_id, long seq_id, int atlast, int checkpoint);
 229 static int crash_recovery();
 230 static int exists_checkpointing_table();
 231 /* Checkpointing test */
 232 static long get_smallest_serial();
 233 static int get_random_number_in_range(int num1, int num2, int seed);
 234 static void do_crash(long crashserial, int is_last_step);
 235 
 236 
 237 /********** KNOWN BUGS AND LIMITATIONS **********/
 238 
 239 /* XXX Fixme:
 240    - Subroutine (+option) to warn that the size is bigger than a watermark
 241      (needed to burn CDs)
 242    */
 243 
 244 
 245 
 246 
 247 /********** THE CODE **********/
 248 
 249 
 250 /*** Main functions ***/
 251 
 252 /****
 253  *
 254  * main()
 255  *
 256  ****/
 257 
 258 int main (int argc, char *argv[])
     /* [<][>][^][v][top][bottom][index][help] */
 259 {
 260 
 261   int ch, rc;
 262   long highest_serial;
 263   short errflg = 1;
 264   short tflg = 0;
 265   extern char *optarg;
 266   extern int optind;
 267   time_t now = time(0);
 268   time_t date;
 269   time_t lapse;
 270 
 271   char sqlhost[STR_M] = MYSQL_HOST;
 272   int sqlport = MYSQL_PORT;
 273   char sqluser[STR_M] = MYSQL_USER;
 274   char sqlpswd[STR_M] = MYSQL_PSWD;
 275   char sqldb[STR_M] = MYSQL_DB;
 276 
 277   tblObjList *objectsToDelete;
 278   long serialsArchived;
 279   /* tblObjList *tmpObj; */
 280 
 281   /* Get options */
 282 
 283   while ((ch = getopt(argc, argv, "?T:S:M:H:D:W:h:P:u:p:d:")) != EOF )
 284     switch((char)ch)
 285       {
 286       case 'T':
 287         if (tflg)
 288           errflg++;
 289         else
 290           {
 291             tflg++;
 292             errflg = 0;
 293             date = atol (optarg);
 294           }
 295         break;
 296       case 'S':
 297         if (tflg)
 298           errflg++;
 299         else
 300           {
 301             tflg++;
 302             errflg = 0;
 303             lapse = atol (optarg);
 304             date = now - lapse;
 305           }
 306         break;
 307       case 'M':
 308         if (tflg)
 309           errflg++;
 310         else
 311           {
 312             tflg++;
 313             errflg = 0;
 314             lapse = atol (optarg);
 315             date = now - lapse * MINUTE;
 316           }
 317         break;
 318       case 'H':
 319         if (tflg)
 320           errflg++;
 321         else
 322           {
 323             tflg++;
 324             errflg = 0;
 325             lapse = atol (optarg);
 326             date = now - lapse * HOUR;
 327           }
 328         break;
 329       case 'D':
 330         if (tflg)
 331           errflg++;
 332         else
 333           {
 334             tflg++;
 335             errflg = 0;
 336             lapse = atol (optarg);
 337             date = now - lapse * DAY;
 338           }
 339         break;
 340       case 'W':
 341         if (tflg)
 342           errflg++;
 343         else
 344           {
 345             tflg++;
 346             errflg = 0;
 347             lapse = atol (optarg);
 348             date = now - lapse * WEEK;
 349           }
 350         break;
 351       case 'h':
 352         sprintf (sqlhost,"%s",optarg);
 353         break;
 354       case 'P':
 355         sqlport = atoi(optarg);
 356         break;
 357       case 'u':
 358         sprintf (sqluser,"%s",optarg);
 359         break;
 360       case 'p':
 361         sprintf (sqlpswd,"%s",optarg);
 362         break;
 363       case 'd':
 364         sprintf (sqldb,"%s",optarg);
 365         break;
 366       case '?':
 367       default:
 368         errflg++;
 369       }
 370 
 371 if (errflg)
 372   usage(argv);
 373 
 374 
 375   /* Initialize connection */
 376   connection = SQ_get_connection(sqlhost, sqlport,sqldb,sqluser,sqlpswd);
 377 
 378   /* Create tables for history and serials archives
 379    * if they do not exist */
 380   if ((rc = create_archive_tables()) != 0)
 381     { return(rc); }
 382 
 383   /* XXX Call remadmin interface and stop updates 
 384    * (currently done externally via a wrapping script) */
 385   /* XXX If retcode is successful, go on */
 386 
 387   /* Crash recovery handling. */
 388   /* fprintf (stderr, "Starting crash recovery...\n"); */
 389   crash_recovery();
 390   /* fprintf (stderr, "Crash recovery done.\n"); */
 391 
 392   /* Deal with very old history entries, those that do not even have a corresponding
 393    * serial. These are entries which had been archived when they were in the "last" table,
 394    * and have in the meanwhile been updated. We have to:
 395    *    - Update prev_serial of their next object
 396    *    - Delete them!
 397    */
 398 
 399   objectsToDelete = find_unreferenced_history_entries((long) date);
 400 
 401   /* printf ("Elements to be deleted:\n");
 402      for (tmpObj = objectsToDelete; tmpObj != NULL; tmpObj = tmpObj->next)
 403      {
 404      printf ("objid: %ld, seqid: %ld\n", tmpObj->objid, tmpObj->seqid);
 405      } */ 
 406 
 407 
 408   /* Get the biggest serial for which the history or last timestamp is lower than
 409    * the defined timestamp
 410    */
 411 
 412   if ((rc = get_highest_serial_before_date(&highest_serial, (long) date)) != 0)
 413     { return(rc); }
 414   printf ("Highest serial ID: %ld\n",highest_serial);
 415 
 416   highest_objid = get_highest_object_id();
 417   printf ("Highest object_id: %ld\n",highest_objid);
 418 
 419   /* Execute the archiving commands */
 420 
 421   serialsArchived = archive_serials_and_history(highest_serial);
 422   if (serialsArchived>0)printf ("Serials archived: %ld [%ld - %ld]\n",serialsArchived, highest_serial-serialsArchived, highest_serial-1);
 423   else printf ("Serials archived: 0 \n");
 424 
 425   /* Optimize history serial and last tables: there might have been many deletions */
 426   /* XXX: optimizing the 'last' table takes about 300 seconds now, during
 427           which time queries are blocked - we need another way to do 
 428           this - SK 2001-03-29 */
 429   /*optimize_sql_table("serials");*/
 430   /*optimize_sql_table("history");*/
 431   /*optimize_sql_table("last");*/
 432 
 433   /* XXX Call remadmin interface and restart updates 
 434    * (currently done externally via a wrapping script) */
 435   /* XXX If retcode is not successful, go on, but issue a warning */
 436 
 437   /* Delete the unreferenced history entries. Must be done at the end. */
 438   /* XXX Bug here. The older entries cannot be deleted or they wreak havoc. 
 439    * archive_only must be 1. */
 440   if (! archive_only)
 441     delete_unreferenced_history_entries(objectsToDelete);
 442 
 443   /* Delete dummy history objects */
 444   delete_dummy_history_objects();
 445 
 446   /* OK, it's over. */
 447 
 448   drop_auxiliary_table();
 449 
 450   SQ_close_connection(connection);
 451   printf ("\nProgram done.\n");
 452   return(0);
 453 
 454 } /* main() */
 455 
 456 
 457 
 458 /****
 459  *
 460  * usage(): help for command usage
 461  * Needs argv[] for the command path supplied
 462  *
 463  ****/
 464 
 465 void usage(char *argv[])
     /* [<][>][^][v][top][bottom][index][help] */
 466 {
 467 
 468   printf ("Usage: \n\n");
 469   printf ("  %s [-?] [-h host] [-P port] [-u user] [-p password] [-d database]\n", argv[0]);
 470   printf ("     [-T date|-S seconds|-M minutes|-H hours|-D days|-W weeks] \n");
 471 
 472   printf ("\nGeneral options:\n");
 473   printf ("   -?: This text\n");
 474 
 475   printf ("\nSQL Options:\n");
 476   printf ("   -h: host \t\t(default: %s)\n",MYSQL_HOST);
 477   printf ("   -P: port \t\t(default: %d)\n",MYSQL_PORT);
 478   printf ("   -u: user \t\t(default: %s)\n",MYSQL_USER);
 479   printf ("   -p: password \t(default: %s)\n",MYSQL_PSWD);
 480   printf ("   -d: database name \t(default: %s)\n",MYSQL_DB);
 481 
 482   printf ("\nTime-related options: (one and only one must be specified)\n");
 483   printf ("   -T date: Date before which to archive (secs from the Epoch)\n");
 484   printf ("   -S seconds: Seconds elapsed between the date to archive and now\n");
 485   printf ("   -M minutes: Minutes elapsed between the date to archive and now\n");
 486   printf ("   -H hours: Hours elapsed between the date to archive and now\n");
 487   printf ("   -D days: Days elapsed between the date to archive and now\n");
 488   printf ("   -W weeks: Weeks elapsed between the date to archive and now\n");
 489   exit(1);
 490 
 491 } /* usage() */
 492 
 493 
 494 
 495 
 496 
 497 /*** Archiving algorithm functions ***/
 498 
 499 /****
 500  * 
 501  * get_highest_serial_before_date()
 502  * We get the biggest serial for which the history or last timestamp is lower than
 503  * the defined timestamp 
 504  *
 505  ****/
 506 
 507 int get_highest_serial_before_date (long *highest_serial_ptr, long date)
     /* [<][>][^][v][top][bottom][index][help] */
 508 {
 509 
 510   char query[MAXCMDLEN];
 511   SQ_result_set_t *result;
 512   SQ_row_t *row;
 513   long highest_serial_last, highest_serial_history;
 514 
 515   /* sprintf (query, "SELECT MAX(serials.serial_id) FROM history,serials 
 516                         WHERE history.timestamp < %ld 
 517                         AND history.object_id = serials.object_id 
 518                         AND history.sequence_id = serials.sequence_id ", date); */
 519 
 520   
 521 /*    sprintf (query, "SELECT MAX(serials.serial_id) 
 522                         FROM serials NATURAL LEFT JOIN last NATURAL LEFT JOIN history
 523                         WHERE ((last.timestamp < %ld 
 524                                 AND last.object_id = serials.object_id 
 525                                 AND last.sequence_id = last.sequence_id)
 526                         OR (history.timestamp < %ld 
 527                                 AND history.object_id = serials.object_id 
 528                                 AND history.sequence_id = serials.sequence_id))",
 529            date, date);
 530 
 531 printf(query);
 532 
 533   execute_sql_query(query, &result);
 534   if ( (row = SQ_row_next(result)) != NULL )
 535     {
 536       *highest_serial_ptr = row[0] ? atol((const char *)row[0]) : 0;
 537     }
 538 
 539   SQ_free_result(result);
 540 
 541 */
 542     sprintf (query, "SELECT MAX(serials.serial_id) 
 543                      FROM serials, last
 544                      WHERE (last.object_id = serials.object_id 
 545                      AND last.sequence_id = serials.sequence_id 
 546                      AND last.timestamp < %ld)", date);
 547   
 548   execute_sql_query(query, &result);
 549   if ( (row = SQ_row_next(result)) != NULL )
 550     {
 551       highest_serial_last = row[0] ? atol((const char *)row[0]) : 0;
 552     }
 553 
 554   SQ_free_result(result);
 555 
 556     sprintf (query, "SELECT MAX(serials.serial_id) 
 557                      FROM serials, history
 558                      WHERE (history.object_id = serials.object_id 
 559                      AND history.sequence_id = serials.sequence_id 
 560                      AND history.timestamp < %ld)", date);
 561   
 562   execute_sql_query(query, &result);
 563   if ( (row = SQ_row_next(result)) != NULL )
 564     {
 565       highest_serial_history = row[0] ? atol((const char *)row[0]) : 0;
 566     }
 567 
 568   SQ_free_result(result);
 569   
 570   if(highest_serial_history>highest_serial_last)
 571           *highest_serial_ptr=highest_serial_history; 
 572   else *highest_serial_ptr=highest_serial_last;
 573 
 574   return(0);
 575 
 576 } /* get_highest_serial_before_date() */
 577 
 578 
 579 
 580 /****
 581  *
 582  * archive_serials_and_history():
 583  * This function contains the core algorithm that manipulates the last,
 584  * history and serials tables and archives them into serials_archive
 585  * and history_archive tables.
 586  *
 587  * Returns number of serials archived
 588  * -1 if error occured
 589  *
 590  ****/
 591 
 592 int archive_serials_and_history (long highest_serial)
     /* [<][>][^][v][top][bottom][index][help] */
 593 {
 594 
 595   char query[MAXCMDLEN];
 596   SQ_result_set_t *result;
 597   SQ_row_t *row;
 598   long serial, objid, seqid;
 599   int atlast, op;
 600   int nserials=0;
 601   char *tablename;
 602   long timestamp;
 603   /* For crash-recovery test */
 604   int crashtest = CRASHTEST;
 605   long smallest_serial;
 606   time_t now = time(0);
 607 
 608 
 609   if (crashtest)
 610     {
 611 
 612       /* 
 613 
 614          If you want to run blackbox crash-recovery testing, all you need to do is add
 615          the random-crashing function between the archiving functions that modify
 616          the SQL DB:
 617 
 618          if ((crashtest) && (serial == crashing_serial)) do_crash(serial, 0);
 619 
 620          and activate the CRASHTEST flag at the top of this file. 
 621 
 622        */
 623          
 624 
 625       smallest_serial = get_smallest_serial();
 626       crashing_serial = get_random_number_in_range(smallest_serial, highest_serial, (long)now);
 627       /* crashing_serial = 0; */
 628       if (debug) fprintf (stderr, "Crashing serial: %ld\n",crashing_serial);
 629       code_location = 1;
 630       crash_position = get_random_number_in_range(code_location, MAX_STEPS, (long)now);
 631     }
 632 
 633 
 634   /* Get the entries for each serial */
 635   /* One word about the "<": Don't use "<=" because if highest_serial
 636      is the CURRENTSERIAL, it causes big problems to UD! 
 637      (at least in mirror mode...) */
 638   sprintf (query, "SELECT serials.serial_id, serials.atlast, 
 639                         ELT(serials.atlast+1,'history','last','failed_transaction'), 
 640                         serials.object_id, serials.sequence_id, serials.operation 
 641                         FROM serials 
 642                         WHERE serials.serial_id < %ld
 643                         ORDER BY serials.serial_id", highest_serial);
 644   execute_sql_query(query, &result);
 645 
 646   /* Loop on every serial */
 647   while ( (row = SQ_row_next(result)) != NULL )
 648     {
 649        nserials++;
 650       /* The lock is inserted here, inside the loop, because it is
 651        * a write lock, which disallows the reading of the table.
 652        * Since one concerned table is "last", the queries would
 653        * be blocked.
 654        * By freeing the lock at the end of every loop, we are assured
 655        * that the reads in queue are executed before a new lock is set.
 656        */
 657 
 658       /* Lock (write lock!) relevant tables */
 659       lock_last_history_serial_tables();
 660 
 661       /* XXX Add stronger error checking: NULL rows should never happen */
 662       serial = row[0] ? atol((const char *)row[0]) : 0;
 663       atlast = row[1] ? atoi((const char *)row[1]) : IN_UNDEF_TABLE;
 664 
 665       if (row[2] == NULL)
 666         {
 667           /* That should never happen! */
 668           fprintf (stderr, "Fatal: No pointer to table\n");
 669           return (-1);
 670         }
 671       else
 672         {
 673           tablename = strdup((const char *)row[2]);
 674         }
 675 
 676       objid = atol((const char *)row[3]);
 677       seqid = atol((const char *)row[4]);
 678       op = atol((const char *)row[5]);
 679 
 680       /* printf ("Serial: %ld; Atlast: %d; Objid: %ld; Seqid: %ld; Op: %d; Tablename: %s\n",serial, atlast, objid, seqid, op, tablename); */
 681 
 682       free(tablename);
 683 
 684       /* For crashtests */
 685       code_location = 1;
 686       case_branch = 0;
 687 
 688       if (atlast == IN_FAILED_TRANSACTION_TABLE)
 689         {
 690 
 691           /* The serial points to a failed transaction */
 692 
 693           /* Checkpointing: if recovering, delete from archive */
 694           update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_ARCHIVE);
 695 
 696           /* Support for deletion of dummy objects (that happens when a DEL+ADD
 697              updates a dummy object in the DB): the deletion goes to the
 698              failed_transaction table, but we want to put it into the history_archive
 699              with the correct object_id and sequence_id */
 700           if (objid != 0)
 701             {
 702 
 703               /* Archive serial with sequence_id = 1 instead of 0 */
 704               archive_serial(serial, objid, seqid+1, op);
 705 
 706               /* Archive the object from the failed transaction table */
 707               archive_failed_transaction(serial);
 708 
 709               /* Update the object in history_archive with the correct objid
 710                  and seqid = 1 */
 711               update_history_archive_object_id_and_sequence_id (serial, objid, seqid+1);
 712 
 713               /* Update prev_serial of the corresponding ADD entry */
 714               if (!update_prev_serial_of_object(objid, seqid+2, serial, "history"))
 715                 { update_prev_serial_of_object(objid, seqid+2, serial, "last"); }
 716 
 717             }
 718           else
 719             {
 720 
 721               /* Archive serial */
 722               archive_serial(serial, objid, seqid, op);
 723               
 724               /* Archive failed transaction */
 725               archive_failed_transaction(serial);
 726 
 727             }
 728 
 729           /* Checkpointing: if recovering, delete from the live DB - all has been archived */
 730           update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_LIVE);
 731 
 732           /* Delete serial */
 733           delete_serial_entry(serial);
 734 
 735           /* Delete failed transaction */
 736           delete_failed_transaction_entry(serial);
 737 
 738           /* Done */
 739           update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DONE);
 740 
 741         }
 742       else /* atlast == (IN_LAST_TABLE || IN_HISTORY_TABLE) */
 743         {
 744 
 745           if (op == OP_DELETE)
 746             {
 747 
 748               /* Then it must be in the history */
 749 
 750               if (debug) printf ("Deleted serial. Objid: %ld, seqid: %ld, serial: %ld\n",objid, seqid, serial);
 751 
 752               /* We need to update the prev_serial of the next element, if there is one...
 753                * This compensates for UPD = DEL + ADD; the ADD is treated with the same
 754                * object_id and sequence_id++ */
 755               if (!update_prev_serial_of_next_object(objid, seqid, serial, "history")) 
 756                 update_prev_serial_of_next_object(objid, seqid, serial, "last");
 757 
 758               /* Checkpointing: if recovering, delete from archive */
 759               update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_ARCHIVE);
 760               
 761               /* Archive serial */
 762               archive_serial(serial, objid, seqid, op);
 763 
 764               /* XXX Fixme: no timestamp is archived if this DEL is part of a DEL+ADD .
 765                * This could be solved by fetching the timestamp from the next
 766                * sequence_id (which is the corresponding UPD), if existent.
 767                */
 768 
 769               /* Fetch timestamp from the corresponding empty last entry */
 770               /* We need that for deleted objects; the actual entry is in the history,
 771                * but the timestamp of the deletion is in the (otherwise empty) last entry */
 772               timestamp = fetch_timestamp_from_last(objid, seqid);
 773 
 774               /* printf ("Timestamp for serial %ld: %ld\n",serial, timestamp); */
 775 
 776               /* Archive history:
 777                * we need a special function here because we need to archive
 778                * history.serial as history_archive.prev_serial .
 779                */
 780               copy_deleted_object_into_history_archive(serial, objid, seqid, "history");
 781 
 782               /* Update history archive with correct timestamp */
 783               /* XXX We don't really need a function which also updates the seq_id */
 784               update_history_archive_sequence_id_and_timestamp(serial, seqid, timestamp);
 785 
 786               /* Checkpointing: if recovering, delete from the live DB - all has been archived */
 787               update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_LIVE);
 788 
 789               /* Delete serial */
 790               delete_serial_entry(serial);
 791               
 792               /* Delete corresponding empty last entry: it has a seq_id of 0 */
 793               /* It must only do so if the entry to be deleted is not the
 794                  highest object_id */
 795               /* This will have no effect for DEL+ADD operations,
 796                  but no harm is done if left so (sequence_id = 0 only for the empty entries) */
 797               if (objid < highest_objid)
 798                 {
 799                   if (debug) printf ("Deleting empty entry in last table: object_id = %ld\n",objid);
 800                   delete_last_entry(objid, 0);
 801                 }
 802 
 803               /* Delete history entry */
 804               delete_history_entry(objid, seqid);
 805 
 806               /* Done */
 807               update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DONE);
 808 
 809               /*              if ((crashtest) && (serial == crashing_serial)) die;*/
 810 
 811             }
 812           else /* It is an update */
 813             {
 814 
 815               if (atlast == IN_LAST_TABLE )
 816                 {
 817 
 818                   /* Checkpointing: if recovering, delete from archive */
 819                   update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_ARCHIVE);
 820               
 821                   /* Archive serial */
 822                   archive_serial(serial, objid, seqid, op);
 823 
 824                   /* Archive last */
 825                   archive_last(serial, objid, seqid);
 826 
 827                   /* Update serial element of the entry in last table */
 828                   update_serial_in_last(objid, seqid, serial);
 829 
 830                   /* Checkpointing: if recovering, delete from the live DB - all has been archived */
 831                   update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_LIVE_ONLY_SERIAL);
 832 
 833                   /* Delete serial */
 834                   delete_serial_entry(serial);
 835 
 836                   /* !!!Do not delete the "last" entry!!! */
 837 
 838                   /* Done */
 839                   update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DONE);
 840 
 841                 }
 842               else /* atlast == IN_HISTORY_TABLE */
 843                 {
 844 
 845                   /* We check for the next object, in order to update
 846                    * its prev_serial. We first look in the history table,
 847                    * then in the last table, otherwise there is no such object
 848                    * => the following update is in fact a deletion...
 849                    */
 850 
 851                   if (check_if_next_is_deletion(objid, seqid) == 0)
 852                     {
 853 
 854                       /* We are dealing with a last-update-before-deletion */
 855 
 856                       /* update_prev_serial_of_next_object() returns the number of
 857                        * affected rows: this shows us if the operation has been successful
 858                        * or not */
 859                       if (!update_prev_serial_of_next_object(objid, seqid, serial, "history")) 
 860                         update_prev_serial_of_next_object(objid, seqid, serial, "last");
 861 
 862                       /* Checkpointing: if recovering, delete from archive */
 863                       update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_ARCHIVE);
 864               
 865                       /* Archive serial */
 866                       archive_serial(serial, objid, seqid, op);
 867 
 868                       /* Archive history */
 869                       archive_history(serial, objid, seqid);
 870 
 871                       /* Checkpointing: if recovering, delete from the live DB - all has been archived */
 872                       update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_LIVE);
 873 
 874                       /* Delete serial */
 875                       delete_serial_entry(serial);
 876 
 877                       /* Delete history */
 878                       delete_history_entry(objid, seqid);
 879                       
 880                       /* Done */
 881                       update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DONE);
 882 
 883                     }
 884                   else /* This is the one always executed */
 885                     {
 886 
 887                       case_branch = 6;
 888 
 889                       /* Checkpointing: if recovering, delete from archive */
 890                       update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_ARCHIVE);
 891               
 892                       /* Archive serial */
 893                       archive_serial(serial, objid, seqid, op);
 894 
 895                       /* Archive history */
 896                       archive_history(serial, objid, seqid);
 897 
 898                       /* Update serial in -current- history entry */
 899                       update_serial_in_history(objid, seqid, serial);
 900 
 901                       /* Checkpointing: if recovering, delete from the live DB - all has been archived */
 902                       update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DELETE_FROM_LIVE_ONLY_SERIAL);
 903 
 904                       /* Delete serial */
 905                       delete_serial_entry(serial);
 906 
 907                       /* Do not delete current history entry! It will be needed
 908                          by the deleting serial */
 909 
 910                       /* Done */
 911                       update_hs_auxiliary_checkpoint(serial, objid, seqid, atlast, CHKP_DONE);
 912 
 913                     }
 914 
 915                 }
 916 
 917             }
 918 
 919         }
 920 
 921       /* Unlock relevant tables */
 922       unlock_all_tables();
 923 
 924     }
 925 
 926   SQ_free_result(result);
 927 
 928   return(nserials);
 929 
 930 } /* archive_serials_and_history() */
 931 
 932 
 933 
 934 /****
 935  *
 936  * fetch_timestamp_from_last()
 937  * Get the timestamp of a specific (object_id, sequence_id)
 938  * from the last table
 939  *
 940  ****/
 941 
 942 long fetch_timestamp_from_last (long obj_id, long seq_id)
     /* [<][>][^][v][top][bottom][index][help] */
 943 {
 944 
 945   long timestamp = 0;
 946   char query[MAXCMDLEN];
 947   SQ_result_set_t *result;
 948   SQ_row_t *row;
 949 
 950   sprintf (query, "SELECT timestamp FROM last WHERE object_id = %ld AND sequence_id = %ld", 
 951            obj_id, seq_id);
 952 
 953   execute_sql_query(query, &result);
 954   if ( (row = SQ_row_next(result)) != NULL)
 955     timestamp = atol((const char *)row[0]);
 956 
 957   SQ_free_result(result);
 958 
 959   return(timestamp);
 960 
 961 } /* fetch_timestamp_from_last() */
 962 
 963 
 964 
 965 /****
 966  *
 967  * get_highest_object_id()
 968  * Get the highest object_id in the last table.
 969  *
 970  ****/
 971 
 972 long get_highest_object_id()
     /* [<][>][^][v][top][bottom][index][help] */
 973 {
 974 
 975   long highest_objid = 0;
 976   char query[MAXCMDLEN];
 977   SQ_result_set_t *result;
 978   SQ_row_t *row;
 979 
 980   sprintf (query, "SELECT max(object_id) FROM last"); 
 981 
 982   execute_sql_query(query, &result);
 983   if ( (row = SQ_row_next(result)) != NULL)
 984     highest_objid = atol((const char *)row[0]);
 985 
 986   SQ_free_result(result);
 987 
 988   return(highest_objid);
 989   
 990 
 991 } /* get_highest_object_id() */
 992 
 993 
 994 /****
 995  *
 996  * check_if_next_is_deletion()
 997  * This functions checks if there is a row in the serials
 998  * table with same obj_id and seq_id, but a delete operation.
 999  * This would mean that we are dealing with a last-update-before-deletion.
1000  *
1001  ****/
1002 
1003 int check_if_next_is_deletion (long obj_id, long seq_id)
     /* [<][>][^][v][top][bottom][index][help] */
1004 {
1005 
1006   char query[MAXCMDLEN];
1007   SQ_result_set_t *result;
1008   SQ_row_t *row;
1009   long serial = 0;
1010 
1011   sprintf (query, "SELECT serial_id, atlast FROM serials 
1012                         WHERE object_id = %ld AND sequence_id = %ld AND operation = %d", 
1013            obj_id, seq_id, OP_DELETE);
1014 
1015   execute_sql_query(query, &result);
1016   if ( (row = SQ_row_next(result)) != NULL)
1017     serial = atol((const char *)row[0]);
1018 
1019   SQ_free_result(result);
1020 
1021   return(serial);
1022 
1023 } /* check_if_next_is_deletion() */
1024 
1025 
1026 
1027 
1028 
1029 /*** Table creation ***/
1030 
1031 /****
1032  * 
1033  * create_archive_tables():
1034  * Create tables for history and serials archives
1035  * if they do not exist 
1036  *
1037  ****/
1038 
1039 int create_archive_tables()
     /* [<][>][^][v][top][bottom][index][help] */
1040 {
1041 
1042   char cmd[MAXCMDLEN];
1043 
1044   sprintf (cmd, 
1045            "CREATE TABLE history_archive (
1046                 object_id int(10) unsigned DEFAULT '0' NOT NULL,
1047                 sequence_id int(10) unsigned DEFAULT '0' NOT NULL,
1048                 serial int(11) DEFAULT '0' NOT NULL,
1049                 prev_serial int(11) DEFAULT '0' NOT NULL,
1050                 timestamp int(10) unsigned DEFAULT '0' NOT NULL,
1051                 object_type tinyint(3) unsigned DEFAULT '0' NOT NULL,
1052                 object longblob NOT NULL,
1053                 pkey varchar(64) default '' NOT NULL,
1054                 PRIMARY KEY (object_id,sequence_id,serial),
1055                 INDEX (serial)
1056                 );");
1057   create_table(cmd);
1058 
1059 
1060   sprintf (cmd, 
1061            "CREATE TABLE serials_archive (
1062                 serial_id int(11) DEFAULT '0' NOT NULL,
1063                 object_id int(10) unsigned DEFAULT '0' NOT NULL,
1064                 sequence_id int(10) unsigned DEFAULT '0' NOT NULL,
1065                 operation tinyint(4) unsigned DEFAULT '0' NOT NULL,
1066                 PRIMARY KEY (serial_id)
1067                 );");
1068   create_table(cmd);
1069 
1070   return(0);
1071 
1072 } /* create_archive_tables() */
1073 
1074 
1075 
1076 /**** 
1077  * 
1078  * create_table()
1079  * This function wraps a table creation (which must be already
1080  * specified in cmd), and only issues a warning if the table
1081  * already exists.
1082  *
1083  ****/
1084 
1085 int create_table (const char *cmd)
     /* [<][>][^][v][top][bottom][index][help] */
1086 {
1087 
1088   int state;
1089 
1090   state = SQ_execute_query(connection, cmd, NULL);
1091   if (state != 0)
1092     {
1093       /* XXX is ER_TABLE_EXISTS_ERROR mysql-bounded? */
1094       if (SQ_errno(connection) == ER_TABLE_EXISTS_ERROR)
1095         { 
1096           /* Don't die if a table already exists */
1097           fprintf (stderr,"Warning: %s\n",SQ_error(connection));
1098           return (state);
1099         }
1100       else
1101         {
1102           fprintf (stderr,"Fatal: %s\n",SQ_error(connection));
1103           die;
1104         }
1105     }
1106 
1107   return(0);
1108 
1109 } /* create_table() */
1110 
1111 
1112 
1113 
1114 
1115 /*** Object update ***/
1116 
1117 /****
1118  *
1119  * update_history_archive_sequence_id_and_timestamp()
1120  *
1121  ****/
1122 
1123 int update_history_archive_sequence_id_and_timestamp (long ser_id, long new_seq_id, long new_timestamp)
     /* [<][>][^][v][top][bottom][index][help] */
1124 {
1125 
1126   char cmd[MAXCMDLEN];
1127 
1128   sprintf (cmd,"UPDATE history_archive
1129                 SET timestamp = %ld, sequence_id = %ld
1130                 WHERE serial = %ld",
1131            new_timestamp, new_seq_id, ser_id);
1132 
1133   return (execute_sql_command(cmd));
1134 
1135 } /* update_history_archive_sequence_id_and_timestamp() */
1136 
1137 
1138 
1139 /****
1140  *
1141  * update_history_archive_object_id_and_sequence_id()
1142  *
1143  ****/
1144 
1145 int update_history_archive_object_id_and_sequence_id (long ser_id, long new_obj_id, long new_seq_id)
     /* [<][>][^][v][top][bottom][index][help] */
1146 {
1147 
1148   char cmd[MAXCMDLEN];
1149 
1150   sprintf (cmd,"UPDATE history_archive
1151                 SET object_id = %ld, sequence_id = %ld
1152                 WHERE serial = %ld",
1153            new_obj_id, new_seq_id, ser_id);
1154 
1155   return (execute_sql_command(cmd));
1156 
1157 } /* update_history_archive_object_id_and_sequence_id() */
1158 
1159 
1160 
1161 /****
1162  *
1163  * update_prev_serial_of_object()
1164  *
1165  ****/
1166 
1167 int update_prev_serial_of_object (long obj_id, long seq_id, long prev_ser, const char *tablename)
     /* [<][>][^][v][top][bottom][index][help] */
1168 {
1169 
1170   char cmd[MAXCMDLEN];
1171 
1172   sprintf (cmd,"UPDATE %s 
1173                 SET prev_serial = %ld 
1174                 WHERE object_id = %ld
1175                 AND sequence_id = %ld",
1176            tablename, prev_ser, obj_id, seq_id);
1177 
1178   return(execute_sql_command(cmd));
1179 
1180 } /* update_prev_serial_of_object() */
1181 
1182 
1183 
1184 /****
1185  *
1186  * update_serial_of_object()
1187  *
1188  ****/
1189 
1190 int update_serial_of_object (long obj_id, long seq_id, long ser_id, const char *tablename)
     /* [<][>][^][v][top][bottom][index][help] */
1191 {
1192 
1193   char cmd[MAXCMDLEN];
1194 
1195   sprintf (cmd,"UPDATE %s 
1196                 SET serial = %ld 
1197                 WHERE object_id = %ld
1198                 AND sequence_id = %ld",
1199            tablename, ser_id, obj_id, seq_id);
1200 
1201   return(execute_sql_command(cmd));
1202 
1203 } /* update_serial_of_object() */
1204 
1205 
1206 
1207 
1208 
1209 /*** Object archiving ***/
1210 
1211 /****
1212  *
1213  * archive_serial()
1214  *
1215  ****/
1216 
1217 int archive_serial (long ser_id, long obj_id, long seq_id, int op)
     /* [<][>][^][v][top][bottom][index][help] */
1218 {
1219 
1220   /* Put the given values into the serials_archive table */
1221 
1222   char cmd[MAXCMDLEN];
1223 
1224   sprintf (cmd, "INSERT INTO serials_archive (serial_id, object_id, sequence_id, operation)
1225                  VALUES (%ld, %ld, %ld, %d)",
1226            ser_id, obj_id, seq_id, op);
1227 
1228   return (execute_sql_command(cmd));
1229 
1230 } /* archive_serial() */
1231 
1232 
1233 
1234 /****
1235  *
1236  * archive_failed_transaction()
1237  *
1238  ****/
1239 
1240 int archive_failed_transaction (long ser_id)
     /* [<][>][^][v][top][bottom][index][help] */
1241 {
1242 
1243   char cmd[MAXCMDLEN];
1244   
1245   sprintf (cmd,"INSERT INTO history_archive (serial, timestamp, object)
1246                 SELECT failed_transaction.serial_id, failed_transaction.timestamp, failed_transaction.object
1247                 FROM failed_transaction
1248                 WHERE failed_transaction.serial_id = %ld",
1249            ser_id);
1250 
1251   return (execute_sql_command(cmd));
1252 
1253 } /* archive_failed_transaction() */
1254 
1255 
1256 
1257 /****
1258  *
1259  * copy_into_history_archive()
1260  * Generic function that works both for last and history tables
1261  *
1262  ****/
1263 
1264 int copy_into_history_archive (long ser_id, long obj_id, long seq_id, const char *tablename)
     /* [<][>][^][v][top][bottom][index][help] */
1265 {
1266 
1267   char cmd[MAXCMDLEN];
1268   
1269   sprintf (cmd,"INSERT INTO history_archive (object_id, sequence_id, serial, prev_serial, timestamp, object_type, object, pkey)
1270                 SELECT serials.object_id, serials.sequence_id, serials.serial_id, %s.prev_serial, %s.timestamp, %s.object_type, %s.object, %s.pkey
1271                 FROM serials,%s 
1272                 WHERE serials.serial_id = %ld 
1273                 AND %s.object_id = %ld 
1274                 AND %s.sequence_id = %ld",
1275            tablename, tablename, tablename, tablename, tablename, tablename, ser_id, tablename, obj_id, tablename, seq_id);
1276 
1277   return (execute_sql_command(cmd));
1278 
1279 } /* copy_into_history_archive() */
1280 
1281 
1282 
1283 /****
1284  *
1285  * copy_deleted_object_into_history_archive()
1286  * The difference here is that we archive the history.serial as history_archive.prev_serial .
1287  * This is only needed for history objects corresponding to OP_DELETE,
1288  * where the row actually corresponds to the last update before the deletion.
1289  *
1290  ****/
1291 
1292 int copy_deleted_object_into_history_archive (long ser_id, long obj_id, long seq_id, const char *tablename)
     /* [<][>][^][v][top][bottom][index][help] */
1293 {
1294 
1295   char cmd[MAXCMDLEN];
1296   int affected_rows;
1297 
1298   sprintf (cmd,"INSERT INTO history_archive (object_id, sequence_id, serial, prev_serial, timestamp, object_type, object, pkey)
1299                 SELECT serials.object_id, serials.sequence_id, serials.serial_id, %s.serial, %s.timestamp, %s.object_type, %s.object, %s.pkey
1300                 FROM serials,%s 
1301                 WHERE serials.serial_id = %ld 
1302                 AND %s.object_id = %ld 
1303                 AND %s.sequence_id = %ld",
1304            tablename, tablename, tablename, tablename, tablename, tablename, ser_id, tablename, obj_id, tablename, seq_id);
1305 
1306   affected_rows = execute_sql_command(cmd);
1307   if (debug) printf ("copy_deleted_object_into_history_archive (%ld, %ld, %ld, %s): affected rows %d\n",ser_id,obj_id,seq_id,tablename,affected_rows);
1308   return (affected_rows);
1309 
1310 } /* copy_deleted_object_into_history_archive() */
1311 
1312 
1313 
1314 
1315 
1316 /*** Object deletion ***/
1317 
1318 /****
1319  *
1320  * delete_serial_entry()
1321  *
1322  ****/
1323 
1324 int delete_serial_entry (long ser_id)
     /* [<][>][^][v][top][bottom][index][help] */
1325 {
1326 
1327   char cmd[MAXCMDLEN];
1328 
1329   sprintf (cmd, "DELETE FROM serials WHERE serial_id = %ld", ser_id);
1330 
1331   return (execute_sql_command(cmd));
1332 
1333 } /* delete_serial_entry() */
1334 
1335 
1336 
1337 /****
1338  *
1339  * delete_failed_transaction_entry()
1340  *
1341  ****/
1342 
1343 int delete_failed_transaction_entry (long ser_id)
     /* [<][>][^][v][top][bottom][index][help] */
1344 {
1345 
1346   char cmd[MAXCMDLEN];
1347 
1348   sprintf (cmd, "DELETE FROM failed_transaction WHERE serial_id = %ld",ser_id);
1349 
1350   return (execute_sql_command(cmd));
1351 
1352 } /* delete_failed_transaction_entry() */
1353 
1354 
1355 
1356 /****
1357  *
1358  * delete_entry_from_object_table()
1359  * Works both for last and history tables
1360  *
1361  ****/
1362 
1363 int delete_entry_from_object_table (long obj_id, long seq_id, const char* tablename)
     /* [<][>][^][v][top][bottom][index][help] */
1364 {
1365 
1366   char cmd[MAXCMDLEN];
1367   int affected_rows;
1368 
1369   if (debug) printf ("Deleting %s entry. Objid: %ld, seqid: %ld\n",tablename, obj_id, seq_id);
1370 
1371   sprintf (cmd, "DELETE FROM %s WHERE object_id = %ld AND sequence_id = %ld",
1372            tablename, obj_id, seq_id);
1373 
1374   affected_rows = execute_sql_command(cmd);
1375   if (debug) printf ("delete_entry_from_object_table (%ld, %ld, %s): affected rows %d\n",obj_id,seq_id,tablename,affected_rows);
1376   return (affected_rows);
1377 
1378 } /* delete_entry_from_object_table() */
1379 
1380 
1381 
1382 /****
1383  *
1384  * delete_archived_objects()
1385  *
1386  ****/
1387 
1388 int delete_archived_objects(long ser_id)
     /* [<][>][^][v][top][bottom][index][help] */
1389 {
1390 
1391   delete_serial_archive_entry(ser_id);
1392   delete_history_archive_entry(ser_id);
1393 
1394   return(0);
1395 
1396 } /* delete_archived_object() */
1397 
1398 
1399 /****
1400  *
1401  * delete_serial_archive_entry()
1402  *
1403  ****/
1404 
1405 int delete_serial_archive_entry (long ser_id)
     /* [<][>][^][v][top][bottom][index][help] */
1406 {
1407 
1408   char cmd[MAXCMDLEN];
1409 
1410   sprintf (cmd, "DELETE FROM serials_archive WHERE serial_id = %ld", ser_id);
1411 
1412   return (execute_sql_command(cmd));
1413 
1414 } /* delete_serial_archive_entry() */
1415 
1416 
1417 
1418 /****
1419  *
1420  * delete_history_archive_entry()
1421  *
1422  ****/
1423 
1424 int delete_history_archive_entry (long ser_id)
     /* [<][>][^][v][top][bottom][index][help] */
1425 {
1426 
1427   char cmd[MAXCMDLEN];
1428 
1429   sprintf (cmd, "DELETE FROM history_archive WHERE serial = %ld", ser_id);
1430 
1431   return (execute_sql_command(cmd));
1432 
1433 } /* delete_history_archive_entry() */
1434 
1435 
1436 
1437 
1438 
1439 
1440 /*** Handling of older, unreferenced history entries ***/
1441 
1442 /****
1443  *
1444  * find_unreferenced_history_entries()
1445  * Deal with very old history entries, those that are not referenced by any serial,
1446  * due to a previous history/serial cleanup.
1447  * These are entries which had been archived when they were in the "last" table,
1448  * and have in the meanwhile been updated. We have to:
1449  *    - Update prev_serial of their next object
1450  *    - Delete them: this is done by delete_unreferenced_history_entries()
1451  *
1452  ****/
1453 
1454 tblObjList *find_unreferenced_history_entries(long date)
     /* [<][>][^][v][top][bottom][index][help] */
1455 {
1456 
1457   char query[MAXCMDLEN];
1458   SQ_result_set_t *result;
1459   SQ_row_t *row;
1460   long objid, seqid, serid;
1461 
1462   tblObjList *curListElmt = NULL;
1463   tblObjList *firstListElmt = NULL;
1464   tblObjList *tmpList = NULL;
1465 
1466   /* Find object_id, sequence_id of unreferenced history entries
1467    * This query returns all history entries which do not have a corresponding
1468    * (object_id, serial_id) in the serials table
1469    */
1470   /* XXX Bug! This will find (and then remove) objects that would be
1471    * needed in the future by deletions. */
1472 
1473   sprintf (query, "SELECT history.object_id, history.sequence_id, history.serial
1474                         FROM history LEFT JOIN serials
1475                         ON history.serial = serials.serial_id
1476                         WHERE serials.serial_id is NULL
1477                         AND history.serial != 0
1478                         AND history.timestamp < %ld", date);
1479   execute_sql_query(query, &result);
1480 
1481   /* Foreach entry: */
1482   while ( (row = SQ_row_next(result)) != NULL )
1483     {
1484 
1485       /* Lock tables in writing... */
1486       /* XXX We don't need to do it, we are not deleting the objects here! */
1487       /* lock_last_history_serial_tables(); */
1488 
1489       /* XXX Error checking missing... */
1490       objid = atol((const char *)row[0]);
1491       seqid = atol((const char *)row[1]);
1492       serid = atol((const char *)row[2]);
1493 
1494       /* Update prev_serial of the same object with next sequence_id */
1495       if (!update_prev_serial_of_next_object(objid, seqid, serid, "history"))
1496         { update_prev_serial_of_next_object(objid, seqid, serid, "last"); }
1497 
1498       /* Delete the entry */
1499       if (debug) printf ("I am deleting this entry: %ld, %ld\n",objid, seqid);
1500 
1501       /* Don't delete the history entries directly! This will cause problems
1502          if the next serial is a deletion */
1503       /* Instead, add it in a list that will be batch-deleted at the end */
1504       /* PushTblObjList (objid, seqid, curListElmt); */
1505       
1506       tmpList = (tblObjList *)malloc(sizeof(tblObjList));
1507       tmpList->objid = objid;
1508       tmpList->seqid = seqid;
1509       tmpList->next = NULL;
1510 
1511       if (firstListElmt == NULL)
1512         {
1513           firstListElmt = tmpList;
1514           curListElmt = tmpList;
1515         }
1516       else
1517         {
1518           curListElmt->next = tmpList;
1519           curListElmt = curListElmt->next;
1520         }
1521 
1522       /* Unlock tables... */
1523       /* unlock_all_tables(); */
1524 
1525     }
1526 
1527   /* printf ("Elements to be deleted:\n");
1528      for (curListElmt = firstListElmt; curListElmt != NULL; curListElmt = curListElmt->next)
1529      {
1530      printf ("objid: %ld, seqid: %ld\n", curListElmt->objid, curListElmt->seqid);
1531      } */ 
1532 
1533   SQ_free_result(result);
1534 
1535   return (firstListElmt);
1536 
1537 } /* find_unreferenced_history_entries() */
1538 
1539 
1540 /****
1541  *
1542  * delete_unreferenced_history_entries()
1543  *
1544  ****/
1545 
1546 int delete_unreferenced_history_entries(tblObjList *objectsToDelete)
     /* [<][>][^][v][top][bottom][index][help] */
1547 {
1548 
1549   tblObjList *tmpObj;
1550 
1551   if (debug) printf ("Elements to be deleted:\n");
1552   for (tmpObj = objectsToDelete; tmpObj != NULL; tmpObj = tmpObj->next)
1553     {
1554       lock_last_history_serial_tables();
1555       if (debug) printf ("objid: %ld, seqid: %ld\n", tmpObj->objid, tmpObj->seqid);
1556       delete_history_entry(tmpObj->objid, tmpObj->seqid);
1557       unlock_all_tables();
1558     } 
1559 
1560   return(0);
1561 
1562 } /* delete_unreferenced_history_entries() */
1563 
1564 
1565 
1566 /****
1567  *
1568  * PushTblObjList() 
1569  *
1570  ****/
1571 
1572 /* XXX Fix this function! It is currently not used. */
1573 
1574 int PushTblObjList(long objid, long seqid, tblObjList *curListElmt)
     /* [<][>][^][v][top][bottom][index][help] */
1575 {
1576 
1577   tblObjList *tmpList;
1578 
1579   tmpList = (tblObjList *)malloc(sizeof(tblObjList));
1580   tmpList->objid = objid;
1581   tmpList->seqid = seqid;
1582   tmpList->next = NULL;
1583 
1584   if (curListElmt == NULL)
1585     {
1586       curListElmt = tmpList;
1587     }
1588   else
1589     {
1590       curListElmt->next = tmpList;
1591       /* curListElmt = tmpList; */
1592     }
1593 
1594   if (debug) printf ("Inside PushTblObjList: %ld, %ld\n", curListElmt->objid, curListElmt->seqid);
1595 
1596   return(0);
1597 
1598 } /* PushTblObjList() */
1599 
1600 
1601 
1602 
1603 
1604 /*** Handling of dummy objects ***/
1605 
1606 /****
1607  *
1608  * delete_dummy_history_objects()
1609  * Deletes from history all "dummy" objects. They should not be
1610  * archived, being only a tweak of the software to allow mirroring
1611  *
1612  ****/
1613 
1614 int delete_dummy_history_objects()
     /* [<][>][^][v][top][bottom][index][help] */
1615 {
1616 
1617   char cmd[MAXCMDLEN];
1618   int rc;
1619 
1620   sprintf (cmd,"DELETE FROM history WHERE object_type = %d",OBJ_TYPE_DUMMY);
1621 
1622   lock_last_history_serial_tables();
1623   rc = execute_sql_command(cmd);
1624   unlock_all_tables();
1625 
1626   printf ("%d dummy history rows deleted.\n", rc);
1627 
1628   return(rc);
1629 
1630 } /* delete_dummy_history_objects() */
1631 
1632 
1633 
1634 
1635 
1636 /*** Interactions with SQL DB ***/
1637 
1638 /****
1639  *
1640  * lock_last_history_serial_tables()
1641  *
1642  ****/
1643 
1644 int lock_last_history_serial_tables()
     /* [<][>][^][v][top][bottom][index][help] */
1645 {
1646 
1647   char cmd[MAXCMDLEN];
1648 
1649   /* No real choice - we must lock the tables in write mode */
1650 
1651   sprintf (cmd, "LOCK TABLES last WRITE, history WRITE, failed_transaction WRITE, serials WRITE, serials_archive WRITE, history_archive WRITE, hs_auxiliary WRITE");
1652 
1653   return (execute_sql_command(cmd));
1654 
1655 } /* lock_last_history_serial_tables() */
1656 
1657 
1658 
1659 /****
1660  *
1661  * unlock_all_tables()
1662  *
1663  ****/
1664 
1665 int unlock_all_tables()
     /* [<][>][^][v][top][bottom][index][help] */
1666 {
1667 
1668   char cmd[MAXCMDLEN];
1669 
1670   sprintf (cmd, "UNLOCK TABLES");
1671 
1672   return (execute_sql_command(cmd));
1673 
1674 } /* unlock_all_tables() */
1675 
1676 
1677 
1678 /****
1679  *
1680  * optimize_sql_table()
1681  *
1682  ****/
1683 
1684 int optimize_sql_table(const char* tablename)
     /* [<][>][^][v][top][bottom][index][help] */
1685 {
1686 
1687   char cmd[MAXCMDLEN];
1688 
1689   sprintf (cmd, "OPTIMIZE TABLE %s", tablename);
1690 
1691   return (execute_sql_command(cmd));
1692 
1693 } /* optimize_sql_table() */
1694 
1695 
1696 
1697 
1698 
1699 /*** SQL interfaces ***/
1700 
1701 /****
1702  *
1703  * execute_sql_query()
1704  * Returns a result in result_ptr;
1705  * the return code is the state.
1706  *
1707  ****/
1708 
1709 int execute_sql_query (const char *query, SQ_result_set_t **result_ptr)
     /* [<][>][^][v][top][bottom][index][help] */
1710 {
1711 
1712   int state;
1713 
1714   state = SQ_execute_query(connection, query, result_ptr);
1715   if (state != 0)
1716     {
1717       fprintf (stderr, "Fatal:\n Offending query: %s\n Error: %s\n",query,SQ_error(connection));
1718       die;
1719     }
1720 
1721   return(state);
1722 
1723 } /* execute_sql_query() */
1724 
1725 
1726 
1727 /****
1728  *
1729  * execute_sql_command()
1730  * Does not return any result;
1731  * the return code is the number of affected rows.
1732  *
1733  ****/
1734 
1735 int execute_sql_command (const char *cmd)
     /* [<][>][^][v][top][bottom][index][help] */
1736 {
1737 
1738   int state;
1739 
1740   state = SQ_execute_query(connection, cmd, NULL);
1741   if (state != 0)
1742     {
1743       fprintf (stderr, "Fatal:\n Offending command: %s\n Error: %s\n",cmd,SQ_error(connection));
1744       die;
1745     }
1746 
1747   return(SQ_get_affected_rows(connection));
1748 
1749 } /* execute_sql_command() */
1750 
1751 
1752 
1753 
1754 
1755 /*** Checkpointing ***/
1756 
1757 /****
1758  * 
1759  * create_auxiliary_table()
1760  * This auxiliary table will record some checkpointing
1761  * data, in order to recover from crashes
1762  * and to help with the clenup of the older history tables
1763  *
1764  ****/
1765 
1766 int create_auxiliary_table()
     /* [<][>][^][v][top][bottom][index][help] */
1767 {
1768 
1769   int state;
1770   char cmd[MAXCMDLEN];
1771 
1772   sprintf (cmd,"CREATE TABLE hs_auxiliary (
1773                 serial int(11) DEFAULT '0' NOT NULL,
1774                 object_id int(10) unsigned DEFAULT '0' NOT NULL,
1775                 sequence_id int(10) unsigned DEFAULT '0' NOT NULL,
1776                 atlast tinyint(4) unsigned DEFAULT '0' NOT NULL,
1777                 checkpoint tinyint(4) unsigned DEFAULT '0' NOT NULL,
1778                 PRIMARY KEY (serial)
1779                 );");
1780   state = create_table(cmd);
1781   if (state == 0) /* state != 0 only if the table already exists - other errors make the program die */
1782     {
1783       fprintf (stderr,"Table created. Inserting dummy objects.\n");
1784       /* We also need to create a dummy row if the table had not been created */
1785       sprintf (cmd,"INSERT INTO hs_auxiliary VALUES (0, 0, 0, 0, 0)");
1786       execute_sql_command(cmd);
1787     }
1788 
1789   return(0);
1790 
1791 } /* create_auxiliary_table() */
1792 
1793 
1794 
1795 /****
1796  * 
1797  * reset_auxiliary_table()
1798  *
1799  ****/
1800 
1801 int reset_auxiliary_table()
     /* [<][>][^][v][top][bottom][index][help] */
1802 {
1803 
1804   char cmd[MAXCMDLEN];
1805 
1806   sprintf (cmd,"UPDATE hs_auxiliary SET
1807                 serial = 0, object_id = 0, sequence_id = 0, atlast = 0, checkpoint = 0");
1808 
1809   return(execute_sql_command(cmd));
1810 
1811 } /* reset_auxiliary_table() */
1812 
1813 
1814 
1815 /****
1816  * 
1817  * drop_auxiliary_table()
1818  *
1819  ****/
1820 
1821 int drop_auxiliary_table()
     /* [<][>][^][v][top][bottom][index][help] */
1822 {
1823 
1824   char cmd[MAXCMDLEN];
1825 
1826   sprintf (cmd,"DROP TABLE IF EXISTS hs_auxiliary");
1827   return(execute_sql_command(cmd));
1828  
1829 } /* drop_auxiliary_table() */
1830 
1831 
1832 
1833 /****
1834  *
1835  * update_hs_auxiliary_checkpoint()
1836  *
1837  ****/
1838 
1839 int update_hs_auxiliary_checkpoint(long ser_id, long obj_id, long seq_id, int atlast, int checkpoint)
     /* [<][>][^][v][top][bottom][index][help] */
1840 {
1841 
1842   char cmd[MAXCMDLEN];
1843 
1844   sprintf (cmd,"UPDATE hs_auxiliary 
1845                 SET serial = %ld,
1846                 object_id = %ld,
1847                 sequence_id = %ld,
1848                 atlast = %d,
1849                 checkpoint = %d",
1850            ser_id, obj_id, seq_id, atlast, checkpoint);
1851 
1852   return (execute_sql_command(cmd));
1853 
1854 } /* update_hs_auxiliary_checkpoint() */
1855 
1856 
1857 
1858 /****
1859  *
1860  * crash_recovery()
1861  * Check if last time we crashed; if so, try to recover.
1862  *
1863  ****/
1864 
1865 int crash_recovery()
     /* [<][>][^][v][top][bottom][index][help] */
1866 {
1867 
1868   char query[MAXCMDLEN];
1869   SQ_result_set_t *result;
1870   SQ_row_t *row;
1871   long serial, objid, seqid;
1872   int atlast, chkp;
1873 
1874  
1875   if (!exists_checkpointing_table())
1876     {
1877       /* The checkpointing table does not exist, there was no crash!
1878          Create the table and back to work. */
1879       fprintf (stderr, "No auxiliary table found. Creating it...\n");
1880       create_auxiliary_table();
1881       return(0);
1882     }
1883 
1884   /* Otherwise, let's start recovering... */
1885   fprintf (stderr, "The auxiliary table exists! Start recovering...\n");
1886 
1887   sprintf(query, "SELECT serial, object_id, sequence_id, atlast, checkpoint FROM hs_auxiliary");
1888 
1889   execute_sql_query(query, &result);
1890   if ( (row = SQ_row_next(result)) != NULL )
1891     {
1892       serial = atol((const char *)row[0]);
1893       objid = atol((const char *)row[1]);
1894       seqid = atol((const char *)row[2]);
1895       atlast = atoi((const char *)row[3]);
1896       chkp = atoi((const char *)row[4]);
1897       if (debug) fprintf (stderr,"DEBUG: Recovering from crash.\n It happened on serial %ld, object_id %ld, sequence_id %ld, table %s, checkpoint %d\n",
1898               serial, objid, seqid, atlast_table[atlast], chkp);
1899     }
1900   else
1901     {
1902       /* The table is empty! Weird, but return */
1903       fprintf (stderr, "The checkpointing table exists but is empty!\n");
1904       drop_auxiliary_table();
1905       return(0);
1906     }
1907 
1908   /* Recover depending on what the checkpointing is */
1909   switch(chkp)
1910     {
1911     case CHKP_DELETE_FROM_ARCHIVE:
1912       /* Delete all the archived objects corresponding to that serial */
1913       if (debug) fprintf (stderr, "DEBUG: Deleting archived objects for serial %ld\n",serial);
1914       delete_archived_objects(serial);
1915       break;
1916     case CHKP_DELETE_FROM_LIVE:
1917       /* In this case, we have to delete the corresponding objects in the live DB */
1918       if (debug) fprintf (stderr, "DEBUG: Deleting serial entry %ld\n",serial);
1919       delete_serial_entry(serial);
1920       if (atlast == IN_FAILED_TRANSACTION_TABLE)
1921         {
1922           if (debug) fprintf (stderr, "DEBUG: Deleting failed transaction entry for serial %ld\n",serial);
1923           delete_failed_transaction_entry(serial);
1924         }
1925       else if (atlast != IN_LAST_TABLE) /* Should never happen, double-check */
1926         /* (It can actually only be in the history table) */
1927         {
1928           if (debug) fprintf (stderr, "DEBUG: Deleting history entry for serial %ld\n",serial);
1929           delete_entry_from_object_table(objid, seqid, atlast_table[atlast]);
1930         }
1931       else
1932         fprintf (stderr,"WARNING! Attempt to delete object from last table in crash-recovery\n");
1933       break;
1934     case CHKP_DELETE_FROM_LIVE_ONLY_SERIAL:
1935       if (debug) fprintf (stderr, "DEBUG: Deleting serial entry %ld\n",serial);
1936       delete_serial_entry(serial);
1937       break;
1938     case CHKP_NOOP:
1939     case CHKP_DONE:
1940     default:
1941       /* Do nothing */
1942       break;
1943     }
1944 
1945   reset_auxiliary_table();
1946 
1947   SQ_free_result(result);
1948 
1949   return(0);
1950 
1951 } /* crash_recovery() */
1952 
1953 
1954 
1955 /****
1956  *
1957  * exists_checkpointing_table()
1958  * Check if the checkpointing table exists.
1959  *
1960  ****/
1961 
1962 int exists_checkpointing_table()
     /* [<][>][^][v][top][bottom][index][help] */
1963 {
1964 
1965   char query[MAXCMDLEN];
1966   SQ_result_set_t *result;
1967   SQ_row_t *row;
1968  
1969   sprintf(query, "SHOW tables LIKE 'hs_auxiliary'");
1970 
1971   execute_sql_query(query, &result);
1972   if ( (row = SQ_row_next(result)) != NULL )
1973     {
1974       SQ_free_result(result);
1975       return(1);
1976     }
1977   else
1978     {
1979       SQ_free_result(result);
1980       return(0);
1981     }
1982 
1983 
1984 } /*  exists_checkpointing_table() */
1985 
1986 
1987 
1988 /****** Checkpointing - crash-recovery test functions ******/
1989 
1990 
1991 /****
1992  * 
1993  * get_smallest_serial()
1994  *
1995  ****/
1996 
1997 long get_smallest_serial()
     /* [<][>][^][v][top][bottom][index][help] */
1998 {
1999 
2000   long smallest_serial = 0;
2001 
2002   char query[MAXCMDLEN];
2003   SQ_result_set_t *result;
2004   SQ_row_t *row;
2005 
2006   sprintf (query, "SELECT MIN(serial_id) FROM serials");
2007 
2008   execute_sql_query(query, &result);
2009   if ( (row = SQ_row_next(result)) != NULL )
2010     {
2011       smallest_serial = row[0] ? atol((const char *)row[0]) : 0;
2012       /* printf ("Smallest serial ID: %ld\n", smallest_serial); */
2013     }
2014 
2015   SQ_free_result(result);
2016 
2017   return(smallest_serial);
2018   
2019 
2020 } /* get_smallest_serial() */
2021 
2022 
2023 
2024 /****
2025  * 
2026  * get_random_number_in_range(int num1, int num2, int seed)
2027  * This function gets a random number in a specific range of numbers
2028  *
2029  ****/
2030 
2031 int get_random_number_in_range(int num1, int num2, int seed)
     /* [<][>][^][v][top][bottom][index][help] */
2032 {
2033 
2034   int randnum;
2035   int lonum, hinum, diff;
2036   double gauge;
2037 
2038   if (num1 < num2)
2039     {
2040       lonum = num1; hinum = num2;
2041     }
2042   else
2043     {
2044       lonum = num2; hinum = num1;
2045     }
2046 
2047   if (lonum == hinum)
2048     return(lonum);
2049 
2050   diff = hinum - lonum;
2051 
2052   if (debug) printf ("Diff: %d\n",diff);
2053 
2054   /* You need that - otherwise the same number is always cast */
2055   srand(seed);
2056 
2057   gauge = (double)rand() / RAND_MAX;
2058 
2059   if (debug) printf ("Gauge: %f\n",gauge);
2060 
2061   randnum = lonum + (int)floor((double)diff * gauge);
2062   
2063   if (debug) printf ("Randnum: %d\n",randnum);
2064 
2065   return(randnum);
2066 
2067 
2068 } /* get_random_number_in_range() */
2069 
2070 
2071 
2072 /****
2073  * 
2074  * do_crash()
2075  * Crash the program in a random part of the code
2076  *
2077  ****/
2078 
2079 void do_crash(long crashserial, int is_last_step)
     /* [<][>][^][v][top][bottom][index][help] */
2080 {
2081 
2082   char query[MAXCMDLEN];
2083   SQ_result_set_t *result;
2084   SQ_row_t *row;
2085   long serial, objid, seqid;
2086   int atlast, chkp;
2087 
2088   /* crash_position has been defined randomly at the beginning of the crashtest */
2089   if ((code_location++ >= crash_position) || (is_last_step == IS_LAST_STEP))
2090     /* Crash - no mercy! */
2091     {
2092       if (debug) fprintf (stderr, "***Crashing***\nSerial: %ld, Code location: %d; crash position: %d; case branch: %d\n",crashserial, code_location, crash_position, case_branch);
2093       /* debug stuff, to check if what was written in the checkpointing table is OK */
2094       sprintf(query, "SELECT serial, object_id, sequence_id, atlast, checkpoint FROM hs_auxiliary");
2095       
2096       execute_sql_query(query, &result);
2097       if ( (row = SQ_row_next(result)) != NULL )
2098         {
2099           serial = atol((const char *)row[0]);
2100           objid = atol((const char *)row[1]);
2101           seqid = atol((const char *)row[2]);
2102           atlast = atoi((const char *)row[3]);
2103           chkp = atoi((const char *)row[4]);
2104           if (debug) fprintf (stderr,"In auxiliary table: serial %ld, object_id %ld, sequence_id %ld, table %d, checkpoint %d\n",
2105                               serial, objid, seqid, atlast, chkp);
2106         }
2107       else
2108         {
2109           /* The table is empty! Weird, but return */
2110           fprintf (stderr, "The checkpointing table exists but is empty!\n");
2111         }
2112       
2113       SQ_free_result(result);
2114 
2115       fflush(stdout);
2116       sleep(3);
2117       fflush(stderr);
2118       sleep(3);
2119       die;
2120     }
2121 
2122 } /* do_crash() */

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