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