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