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 *                                                           *
  78 * Important fields of transaction are:                      *
  79 * tr->action        TR_CREATE/TR_UPDATE/TR_DELETE           *
  80 * tr->object_id     should be filled in                     *
  81 * tr->sequence_id   should be set to object updated         *
  82 *                                                           *
  83 * So given object with id=k and seq=n                       *
  84 * Create:  ADD(k,n)                                         *
  85 * Update:  ~S(k,n), ADD(k,n+1)                              *
  86 * Delete:  ~S(k,n), DEL(k,n)                                *
  87 *                                                           *
  88 * Returns:                                                  *
  89 *  current serial number.                                    *
  90 *  -1 in case of an error                                   *
  91 *                                                           *
  92 *************************************************************/
  93 
  94 long UD_create_serial(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
  95 {
  96 GString *query;
  97 long current_serial=0;
  98 int sql_err;
  99 int operation;
 100 long timestamp;
 101 long sequence_id;
 102    
 103    if ((query = g_string_sized_new(STR_XL)) == NULL){ 
 104       tr->succeeded=0;
 105       tr->error |= ERROR_U_MEM;
 106       ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 107       die;
 108    }
 109    
 110    /* Calculate the object_id - should be max+1 */
 111 //   tr->serial_id = get_minmax_id(tr->sql_connection, "serial_id", "serials", 1) +1;
 112 //   TR_update_id(tr);
 113 
 114 /* fprintf(stderr, "creating serial\n"); */
 115   /* if the transaction failed store it in transaction table */
 116   if(tr->succeeded==0){
 117     if(ACT_DELETE(tr->action))operation=OP_DEL; else operation=OP_ADD;
 118     
 119     g_string_sprintf(query, "INSERT serials SET "
 120                    "thread_id=%d, object_id=%ld, sequence_id=0, "
 121                    "atlast=2, "
 122                    "operation=%d ", tr->thread_ins, tr->object_id, operation);
 123     
 124     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 125 
 126     if (sql_err) { 
 127         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 128         current_serial=-1;
 129         die;
 130     }
 131     else {
 132        current_serial=SQ_get_insert_id(tr->sql_connection);
 133        timestamp=time(NULL);
 134 //       if(tr->serial_id!=current_serial) die; /* may be the implementation changed */
 135        g_string_sprintf(query, "INSERT failed_transaction SET "
 136                    "thread_id=%d, serial_id=%ld, timestamp=%ld, "
 137                    "object='%s' ", tr->thread_ins, current_serial, timestamp, tr->object->object->str);
 138        /* make a record in transaction table */
 139        sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 140        if (sql_err) { 
 141          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 142          current_serial=-1;
 143          die;
 144        }
 145     }
 146     g_string_free(query, TRUE);   
 147     return(current_serial);
 148   }  
 149 
 150 
 151   /* if the transaction has succeeded */
 152   sequence_id=tr->sequence_id;
 153   /* If this is an update or delete */    
 154   if(!ACT_CREATE(tr->action)) { 
 155     /* Increase the sequence_id so we insert correct ADD serial in case of Update */
 156     sequence_id=tr->sequence_id + 1;
 157     /* set the atlast field of the latest record for this object to 0 */
 158     /* because it is moved to history */
 159     g_string_sprintf(query, "UPDATE serials SET atlast=0, thread_id=%d "
 160                    "WHERE object_id=%ld "
 161                    "AND sequence_id=%ld ", tr->thread_upd, tr->object_id, sequence_id-1);
 162     
 163     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 164     if (sql_err) { // we can have empty updates, but not errors
 165         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 166         current_serial=-1;
 167         die;
 168     }
 169   }  
 170   /* XXX below is a code for protocol v2, where updates are atomic */
 171   /* XXX this is fine (and should always be used) for NRTM, since we */
 172   /* XXX store failed transactions and playback stream exactly as it comes */
 173   /* XXX However, for update this may be configurable option */
 174   /* XXX In case v1 protocol both sections (DEL + ADD) should be executed */
 175   /* if this a DEL */ 
 176   if(ACT_DELETE(tr->action)) {   
 177     /* generate DEL serial */
 178     g_string_sprintf(query, "INSERT serials SET "
 179                    "thread_id=%d, object_id=%ld, "
 180                    "sequence_id=%ld, "
 181                    "atlast=0, "
 182                    "operation=%d ", tr->thread_ins, tr->object_id, sequence_id-1, OP_DEL);
 183     
 184     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 185     if (sql_err) {
 186         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 187         current_serial=-1;
 188         die;
 189     }    
 190     else current_serial=SQ_get_insert_id(tr->sql_connection); 
 191     
 192   }
 193   else { /* otherwise this is an ADD */
 194 
 195    /* now insert creation serial */
 196    g_string_sprintf(query, "INSERT serials SET "
 197                   "thread_id=%d, object_id=%ld, "
 198                   "sequence_id=%ld, "
 199                   "atlast=1, "
 200                   "operation=%d ", tr->thread_ins, tr->object_id, sequence_id, OP_ADD);
 201     
 202    sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 203    if (sql_err) {
 204         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 205         current_serial=-1;
 206         die;
 207    }    
 208    else current_serial=SQ_get_insert_id(tr->sql_connection); 
 209 
 210   }
 211   g_string_free(query, TRUE);        
 212 return(current_serial);
 213 }
 214 /************************************************************
 215 * UD_comrol_serial()                                        *     
 216 *                                                           *
 217 * Commits/Rollbacks a serial record for given transaction   *
 218 * Returns:                                                  *
 219 * 0 in success                                              *
 220 *  -1 in case of an error                                   *
 221 *                                                           *
 222 *************************************************************/
 223 
 224 char *Q_rollback_serial1="DELETE FROM serials WHERE thread_id=%ld ";
 225 char *Q_rollback_serial2="UPDATE serials SET atlast=1, thread_id=0 WHERE thread_id=%ld ";
 226 char *Q_rollback_transaction="DELETE FROM failed_transaction WHERE thread_id=%ld ";
 227 char *Q_commit_serial="UPDATE serials SET thread_id=0 WHERE thread_id=%ld OR thread_id=%ld ";
 228 char *Q_commit_transaction="UPDATE failed_transaction SET thread_id=0 WHERE thread_id=%ld ";
 229 
 230 
 231 
 232 int UD_comrol_serial(Transaction_t *tr, int commit)
     /* [<][>][^][v][top][bottom][index][help] */
 233 {
 234 GString *query;
 235 int sql_err;
 236 char *Q_transaction;
 237 
 238    /* check if something is left in serials from the crash */
 239    
 240    if ((query = g_string_sized_new(STR_XL)) == NULL){ 
 241       ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n"); 
 242       tr->succeeded=0;
 243       tr->error |= ERROR_U_MEM;
 244       return(ERROR_U_MEM); 
 245    }
 246    
 247    /* compose the appropriate query depending on operation (commit/rollback) */
 248    if(commit) {
 249            /* commit changes to serials table */
 250            g_string_sprintf(query, Q_commit_serial, tr->thread_ins, tr->thread_upd);
 251            sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 252            if (sql_err) {
 253              ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 254              die;
 255            }
 256            Q_transaction=Q_commit_transaction;
 257    } else {
 258            /* delete new insertions */
 259            g_string_sprintf(query, Q_rollback_serial1, tr->thread_ins);
 260            sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 261            if (sql_err) {
 262              ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 263              die;
 264            }
 265            /* restore modified atlast */ 
 266            g_string_sprintf(query, Q_rollback_serial2, tr->thread_upd);
 267            sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 268            if (sql_err) {
 269              ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 270              die;
 271            } 
 272            Q_transaction=Q_rollback_transaction;
 273    }
 274    
 275     /* clean up transaction  table */
 276     g_string_sprintf(query, Q_transaction, tr->thread_ins);
 277     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 278     if (sql_err) {
 279         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 280         die;
 281     }
 282  g_string_free(query, TRUE);        
 283  return(0);
 284 } 
 285     
 286 

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