modules/ud/ud_serial.c

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

FUNCTIONS

This source file includes following functions.
  1. UD_lock_serial
  2. UD_unlock_serial
  3. UD_create_serial
  4. UD_comrol_serial

   1 /***************************************
   2 
   3   Functions for handling serials  
   4 
   5   Status: NOT REVUED, NOT TESTED
   6 
   7  Author(s):       Andrei Robachevsky
   8 
   9   ******************/ /******************
  10   Modification History:
  11         andrei (08/02/2000) Created.
  12   ******************/ /******************
  13   Copyright (c) 2000                              RIPE NCC
  14  
  15   All Rights Reserved
  16   
  17   Permission to use, copy, modify, and distribute this software and its
  18   documentation for any purpose and without fee is hereby granted,
  19   provided that the above copyright notice appear in all copies and that
  20   both that copyright notice and this permission notice appear in
  21   supporting documentation, and that the name of the author not be
  22   used in advertising or publicity pertaining to distribution of the
  23   software without specific, written prior permission.
  24   
  25   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  26   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  27   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  28   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  29   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  30   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  31  ***************************************/
  32 #include "ud.h"
  33 #include "ud_int.h"
  34 #include "ud_tr.h"
  35 
  36 /************************************************************
  37 * int UD_lock/unlock_serial()                               *
  38 *                                                           *
  39 * Performs lockind/unlocking of the relevant tables         *
  40 *                                                           *
  41 * Returns:                                                  *
  42 * 0 - success                                               *
  43 * Non-zero if error occured (XXX dies now)                  *
  44 *                                                           *
  45 ************************************************************/
  46 int UD_lock_serial(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
  47 {
  48 int sql_err;
  49 
  50 /* lock all tables we are going to update and commit */ 
  51 /* this also includes transaction_rec table, as we update the status */
  52    sql_err=SQ_execute_query(tr->sql_connection, "LOCK TABLES serials WRITE, failed_transaction WRITE, transaction_rec WRITE ", NULL);
  53    if (sql_err) { 
  54         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), "LOCK TABLES serials WRITE, failed_transaction WRITE, transaction_rec WRITE ");
  55         die;
  56     }
  57  return(sql_err);
  58 }
  59 
  60 int UD_unlock_serial(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
  61 {
  62 int sql_err;
  63         
  64    sql_err=SQ_execute_query(tr->sql_connection, "UNLOCK TABLES ", NULL);
  65    if (sql_err) { 
  66         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), "UNLOCK TABLES");
  67         die;
  68     }
  69  return(sql_err);
  70 }
  71 
  72 
  73 /************************************************************
  74 * UD_create_serial()                                        *     
  75 *                                                           *
  76 * Creates a serial record for given transaction             *
  77 * For updates creates 2 serial records (DEL+ADD)            *
  78 *                                                           *
  79 * Important fields of transaction are:                      *
  80 * tr->action        TR_CREATE/TR_UPDATE/TR_DELETE           *
  81 * tr->object_id     should be filled in                     *
  82 * tr->sequence_id   should be set to object updated         *
  83 *                                                           *
  84 * So given object with id=k and seq=n                       *
  85 * Create:  ADD(k,n)                                         *
  86 * Update:  ~S(k,n), ADD(k,n+1)                              *
  87 * Delete:  ~S(k,n), DEL(k,n)                                *
  88 *                                                           *
  89 * Returns:                                                  *
  90 *  currnt serial number.                                    *
  91 *  -1 in case of an error                                   *
  92 *                                                           *
  93 *************************************************************/
  94 
  95 long UD_create_serial(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
  96 {
  97 GString *query;
  98 long current_serial=0;
  99 int sql_err;
 100 int operation;
 101 long timestamp;
 102 long sequence_id;
 103    
 104    if ((query = g_string_sized_new(STR_XL)) == NULL){ 
 105       tr->succeeded=0;
 106       tr->error |= ERROR_U_MEM;
 107       ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 108       die;
 109    }
 110    
 111    /* Calculate the object_id - should be max+1 */
 112 //   tr->serial_id = get_minmax_id(tr->sql_connection, "serial_id", "serials", 1) +1;
 113 //   TR_update_id(tr);
 114 
 115 /* fprintf(stderr, "creating serial\n"); */
 116   /* if the transaction failed store it in transaction table */
 117   if(tr->succeeded==0){
 118     if(ACT_DELETE(tr->action))operation=OP_DEL; else operation=OP_ADD;
 119     
 120     g_string_sprintf(query, "INSERT serials SET "
 121                    "thread_id=%d, object_id=%ld, sequence_id=0, "
 122                    "atlast=2, "
 123                    "operation=%d ", tr->thread_ins, tr->object_id, operation);
 124     
 125     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 126 
 127     if (sql_err) { 
 128         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 129         die;
 130         current_serial=-1;
 131     }
 132     else {
 133        current_serial=mysql_insert_id(tr->sql_connection);
 134        timestamp=time(NULL);
 135 //       if(tr->serial_id!=current_serial) die; /* may be the implementation changed */
 136        g_string_sprintf(query, "INSERT failed_transaction SET "
 137                    "thread_id=%d, serial_id=%ld, timestamp=%ld, "
 138                    "object='%s' ", tr->thread_ins, current_serial, timestamp, tr->object->object->str);
 139        /* make a record in transaction table */
 140        sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 141        if (sql_err) { 
 142          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 143          die;
 144          current_serial=-1;
 145        }
 146     }
 147     g_string_free(query, TRUE);   
 148     return(current_serial);
 149   }  
 150 
 151 
 152   /* if the transaction has succeeded */
 153   sequence_id=tr->sequence_id;
 154   /* If this is an update or delete */    
 155   if(!ACT_CREATE(tr->action)) { 
 156     /* Increase the sequence_id so we insert correct ADD serial in case of Update */
 157     sequence_id=tr->sequence_id + 1;
 158     /* set the atlast field of the latest record for this object to 0 */
 159     /* because it is moved to history */
 160     g_string_sprintf(query, "UPDATE serials SET atlast=0, thread_id=%d "
 161                    "WHERE object_id=%ld "
 162                    "AND sequence_id=%ld ", tr->thread_upd, tr->object_id, sequence_id-1);
 163     
 164     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 165     if (sql_err) { // we can have empty updates, but not errors
 166         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 167         die;
 168         current_serial=-1;
 169     }
 170   }  
 171   /* XXX below is a code for protocol v2, when updates are atomic */
 172   /* XXX this is fine (and should always be used) for NRTM, since we */
 173   /* XXX store failed transactions and playback stream exactly as it comes */
 174   /* XXX However, for update this may be configurable option */
 175   /* XXX In case v1 protocol both sections (DEL + ADD) should be executed */
 176   /* if this a DEL */ 
 177   if(ACT_DELETE(tr->action)) {   
 178     /* generate DEL serial */
 179     g_string_sprintf(query, "INSERT serials SET "
 180                    "thread_id=%d, object_id=%ld, "
 181                    "sequence_id=%ld, "
 182                    "atlast=0, "
 183                    "operation=%d ", tr->thread_ins, tr->object_id, sequence_id-1, OP_DEL);
 184     
 185     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 186     if (sql_err) {
 187         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 188         die;
 189         current_serial=-1;
 190     }    
 191     
 192     if(current_serial!=-1)current_serial=mysql_insert_id(tr->sql_connection);
 193     
 194   }
 195   else { /* otherwise this is an ADD */
 196 
 197    /* now insert creation serial */
 198    g_string_sprintf(query, "INSERT serials SET "
 199                   "thread_id=%d, object_id=%ld, "
 200                   "sequence_id=%ld, "
 201                   "atlast=1, "
 202                   "operation=%d ", tr->thread_ins, tr->object_id, sequence_id, OP_ADD);
 203     
 204    sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 205    if (sql_err) {
 206         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 207         die;
 208         current_serial=-1;
 209    }    
 210     
 211    if(current_serial!=-1){ 
 212            current_serial=mysql_insert_id(tr->sql_connection);
 213 //         if(tr->serial_id!=current_serial) die; /* may be the implementation changed */
 214    }
 215 
 216   }
 217   g_string_free(query, TRUE);        
 218 return(current_serial);
 219 }
 220 /************************************************************
 221 * UD_comrol_serial()                                        *     
 222 *                                                           *
 223 * Commits/Rollbacks a serial record for given transaction   *
 224 * Returns:                                                  *
 225 * 0 in success                                              *
 226 *  -1 in case of an error                                   *
 227 *                                                           *
 228 *************************************************************/
 229 
 230 char *Q_rollback_serial1="DELETE FROM serials WHERE thread_id=%ld ";
 231 char *Q_rollback_serial2="UPDATE serials SET atlast=1, thread_id=0 WHERE thread_id=%ld ";
 232 char *Q_rollback_transaction="DELETE FROM failed_transaction WHERE thread_id=%ld ";
 233 char *Q_commit_serial="UPDATE serials SET thread_id=0 WHERE thread_id=%ld OR thread_id=%ld ";
 234 char *Q_commit_transaction="UPDATE failed_transaction SET thread_id=0 WHERE thread_id=%ld ";
 235 
 236 
 237 
 238 int UD_comrol_serial(Transaction_t *tr, int commit)
     /* [<][>][^][v][top][bottom][index][help] */
 239 {
 240 GString *query;
 241 int sql_err;
 242 char *Q_transaction;
 243 
 244    /* check if something is left in serials from the crash */
 245    
 246    if ((query = g_string_sized_new(STR_XL)) == NULL){ 
 247       ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n"); 
 248       tr->succeeded=0;
 249       tr->error |= ERROR_U_MEM;
 250       return(ERROR_U_MEM); 
 251    }
 252    
 253    /* compose the appropriate query depending on operation (commit/rollback) */
 254    if(commit) {
 255            /* commit changes to serials table */
 256            g_string_sprintf(query, Q_commit_serial, tr->thread_ins, tr->thread_upd);
 257            sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 258            if (sql_err) {
 259              ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 260              die;
 261            }
 262            Q_transaction=Q_commit_transaction;
 263    } else {
 264            /* delete new insertions */
 265            g_string_sprintf(query, Q_rollback_serial1, tr->thread_ins);
 266            sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 267            if (sql_err) {
 268              ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 269              die;
 270            }
 271            /* restore modified atlast */ 
 272            g_string_sprintf(query, Q_rollback_serial2, tr->thread_upd);
 273            sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 274            if (sql_err) {
 275              ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 276              die;
 277            } 
 278            Q_transaction=Q_rollback_transaction;
 279    }
 280    
 281     /* clean up transaction  table */
 282     g_string_sprintf(query, Q_transaction, tr->thread_ins);
 283     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 284     if (sql_err) {
 285         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 286         die;
 287     }
 288  g_string_free(query, TRUE);        
 289  return(0);
 290 } 
 291     
 292 

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