modules/ud/ud_serial.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- BEKILLED
- 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 void BEKILLED()
/* [<][>][^][v][top][bottom][index][help] */
37 {
38
39 kill(getpid(), SIGKILL);
40
41
42 }
43
44 /************************************************************
45 * int UD_lock/unlock_serial() *
46 * *
47 * Performs lockind/unlocking of the relevant tables *
48 * *
49 * Returns: *
50 * 0 - success *
51 * Non-zero if error occured (XXX dies now) *
52 * *
53 ************************************************************/
54 int UD_lock_serial(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
55 {
56 int sql_err;
57
58 /* lock all tables we are going to update and commit */
59 /* this also includes transaction_rec table, as we update the status */
60 sql_err=SQ_execute_query(tr->sql_connection, "LOCK TABLES serials WRITE, failed_transaction WRITE, transaction_rec WRITE ", NULL);
61 if (sql_err) {
62 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), "LOCK TABLES serials WRITE, failed_transaction WRITE, transaction_rec WRITE ");
63 die;
64 }
65 return(sql_err);
66 }
67
68 int UD_unlock_serial(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
69 {
70 int sql_err;
71
72 sql_err=SQ_execute_query(tr->sql_connection, "UNLOCK TABLES ", NULL);
73 if (sql_err) {
74 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), "UNLOCK TABLES");
75 die;
76 }
77 return(sql_err);
78 }
79
80
81 /************************************************************
82 * UD_create_serial() *
83 * *
84 * Creates a serial record for given transaction *
85 * *
86 * Important fields of transaction are: *
87 * tr->action TR_CREATE/TR_UPDATE/TR_DELETE *
88 * tr->object_id should be filled in *
89 * tr->sequence_id should be set to object updated *
90 * *
91 * So given object with id=k and seq=n *
92 * Create: ADD(k,n) *
93 * Update: ~S(k,n), ADD(k,n+1) *
94 * Delete: ~S(k,n), DEL(k,n) *
95 * *
96 * Returns: *
97 * current serial number. *
98 * -1 in case of an error *
99 * *
100 *************************************************************/
101
102 long UD_create_serial(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
103 {
104 GString *query;
105 //long current_serial=0;
106 int sql_err;
107 int operation;
108 long timestamp;
109 long sequence_id;
110
111 if ((query = g_string_sized_new(STR_XL)) == NULL){
112 tr->succeeded=0;
113 tr->error |= ERROR_U_MEM;
114 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
115 die;
116 }
117
118 /* Calculate the object_id - should be max+1 */
119 /* XXX we cannot use autoincrement with MyISAM tables */
120 /* XXX because they keep the max inserted id even if */
121 /* XXX it was deleted later, thus causing gaps we don't want */
122 tr->serial_id = SQ_get_max_id(tr->sql_connection, "serial_id", "serials") +1;
123
124 /* if the transaction failed store it in transaction table */
125 if(tr->succeeded==0){
126 if(ACT_DELETE(tr->action))operation=OP_DEL; else operation=OP_ADD;
127
128 g_string_sprintf(query, "INSERT serials SET "
129 "thread_id=%d, serial_id=%ld, object_id=%ld, sequence_id=0, "
130 "atlast=2, "
131 "operation=%d ", tr->thread_ins, tr->serial_id, tr->object_id, operation);
132
133 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
134
135 if (sql_err) {
136 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
137 // current_serial=-1;
138 die;
139 }
140 else {
141 timestamp=time(NULL);
142 g_string_sprintf(query, "INSERT failed_transaction SET "
143 "thread_id=%d, serial_id=%ld, timestamp=%ld, "
144 "object='%s' ", tr->thread_ins, tr->serial_id, timestamp, tr->object->object->str);
145 /* make a record in transaction table */
146 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
147 if (sql_err) {
148 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
149 die;
150 }
151 }
152 g_string_free(query, TRUE);
153 return(tr->serial_id);
154 }
155
156
157 /* if the transaction has succeeded */
158 sequence_id=tr->sequence_id;
159 /* If this is an update or delete */
160 if(!ACT_CREATE(tr->action)) {
161 /* Increase the sequence_id so we insert correct ADD serial in case of Update */
162 sequence_id=tr->sequence_id + 1;
163
164 /* set the atlast field of the latest record for this object to 0 */
165 /* because it is moved to history */
166 g_string_sprintf(query, "UPDATE serials SET atlast=0, thread_id=%d "
167 "WHERE object_id=%ld "
168 "AND sequence_id=%ld ", tr->thread_upd, tr->object_id, sequence_id-1);
169
170 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
171 if (sql_err) { // we can have empty updates, but not errors
172 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
173 die;
174 }
175 }
176 /* XXX below is a code for protocol v2, where updates are atomic */
177 /* XXX this is fine (and should always be used) for NRTM, since we */
178 /* XXX store failed transactions and playback stream exactly as it comes */
179 /* XXX However, for update this may be configurable option */
180 /* XXX In case v1 protocol both sections (DEL + ADD) should be executed */
181
182 /* get the next serial_id */
183 /* XXX we cannot use autoincrement with MyISAM tables */
184 /* XXX because they keep the max inserted id even if */
185 /* XXX it was deleted later, thus causing gaps we don't want */
186 tr->serial_id = SQ_get_max_id(tr->sql_connection, "serial_id", "serials") +1;
187
188 /* if this a DEL */
189
190
191 if(ACT_DELETE(tr->action)) {
192 /* generate DEL serial */
193
194 g_string_sprintf(query, "INSERT serials SET "
195 "thread_id=%d, serial_id=%ld, object_id=%ld, "
196 "sequence_id=%ld, "
197 "atlast=0, "
198 "operation=%d ", tr->thread_ins, tr->serial_id, tr->object_id, sequence_id-1, OP_DEL);
199
200 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
201 if (sql_err) {
202 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
203 die;
204 }
205
206 }
207 else { /* otherwise this is an ADD */
208
209 /* now insert creation serial */
210 g_string_sprintf(query, "INSERT serials SET "
211 "thread_id=%d, serial_id=%ld, object_id=%ld, "
212 "sequence_id=%ld, "
213 "atlast=1, "
214 "operation=%d ", tr->thread_ins, tr->serial_id, tr->object_id, sequence_id, OP_ADD);
215
216 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
217 if (sql_err) {
218 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
219 die;
220 }
221
222 }
223 g_string_free(query, TRUE);
224 return(tr->serial_id);
225 }
226 /************************************************************
227 * UD_comrol_serial() *
228 * *
229 * Commits/Rollbacks a serial record for given transaction *
230 * Returns: *
231 * 0 in success *
232 * -1 in case of an error *
233 * *
234 *************************************************************/
235
236 char *Q_rollback_serial1="DELETE FROM serials WHERE thread_id=%ld ";
237 char *Q_rollback_serial2="UPDATE serials SET atlast=1, thread_id=0 WHERE thread_id=%ld ";
238 char *Q_rollback_transaction="DELETE FROM failed_transaction WHERE thread_id=%ld ";
239 char *Q_commit_serial="UPDATE serials SET thread_id=0 WHERE thread_id=%ld OR thread_id=%ld ";
240 char *Q_commit_transaction="UPDATE failed_transaction SET thread_id=0 WHERE thread_id=%ld ";
241
242
243
244 int UD_comrol_serial(Transaction_t *tr, int commit)
/* [<][>][^][v][top][bottom][index][help] */
245 {
246 GString *query;
247 int sql_err;
248 char *Q_transaction;
249
250 /* check if something is left in serials from the crash */
251
252 if ((query = g_string_sized_new(STR_XL)) == NULL){
253 ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
254 tr->succeeded=0;
255 tr->error |= ERROR_U_MEM;
256 return(ERROR_U_MEM);
257 }
258
259 /* compose the appropriate query depending on operation (commit/rollback) */
260 if(commit) {
261 /* commit changes to serials table */
262 g_string_sprintf(query, Q_commit_serial, tr->thread_ins, tr->thread_upd);
263 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
264 if (sql_err) {
265 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
266 die;
267 }
268 Q_transaction=Q_commit_transaction;
269 } else {
270 /* delete new insertions */
271 g_string_sprintf(query, Q_rollback_serial1, tr->thread_ins);
272 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
273 if (sql_err) {
274 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
275 die;
276 }
277 /* restore modified atlast */
278 g_string_sprintf(query, Q_rollback_serial2, tr->thread_upd);
279 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
280 if (sql_err) {
281 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
282 die;
283 }
284 Q_transaction=Q_rollback_transaction;
285 }
286
287 /* clean up transaction table */
288 g_string_sprintf(query, Q_transaction, tr->thread_ins);
289 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
290 if (sql_err) {
291 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
292 die;
293 }
294 g_string_free(query, TRUE);
295 return(0);
296 }
297
298