## 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] */