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