modules/ud/ud_serial.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- UD_lock_serial
- UD_unlock_serial
- UD_create_serial
- 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