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 * *
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