comparison runtime/transaction.c @ 139:a68e6828d896

Global stores and transactions are working. Definately leaks memory on retries. Probably a fair number of bugs to work out. However, a basic test program works.
author Mike Pavone <pavone@retrodev.com>
date Fri, 19 Nov 2010 04:04:14 -0500
parents
children ba35ab624ec2
comparison
equal deleted inserted replaced
138:1411de6050e1 139:a68e6828d896
1 #include "transaction.h"
2 #include <stdarg.h>
3 #include <string.h>
4 #include <stdlib.h>
5
6 rh_mutex(trans_lock)
7
8 trans_cell * find_obj_cell(transaction * trans, mutable_object * to_find)
9 {
10 int32_t idx;
11 while(trans)
12 {
13 for (idx = 0; idx < trans->num_cells; ++idx)
14 if (trans->cells[idx].obj = to_find)
15 return &(trans->cells[idx]);
16 trans = trans->chain;
17 }
18 return NULL;
19 }
20
21 void begin_transaction(context * ct, int numobjs,...)
22 {
23 mutable_object *obj;
24 transaction *parent;
25 va_list args;
26 int32_t idx,got_global_lock=0;
27
28 parent = ct->transaction ? ct->transaction : NULL;
29
30 ct->transaction = malloc(sizeof(transaction)+((numobjs-1)*sizeof(trans_cell)));
31 ct->transaction->parent = parent;
32 ct->transaction->chain = NULL;
33 rh_mutex_init(ct->lock);
34 ct->transaction->num_cells = numobjs;
35 va_start(args, numobjs);
36 if (parent)
37 {
38 rh_lock(parent->lock);
39 for (idx = 0; idx < numobjs; ++idx)
40 {
41 obj = va_arg(args, mutable_object *);
42 ct->transaction->cells[idx].obj = obj;
43 ct->transaction->cells[idx].parent = find_obj_cell(parent, obj);
44 if (ct->transaction->cells[idx].parent)
45 {
46 ct->transaction->cells[idx].local_data = ct->transaction->cells[idx].parent->local_data;
47 ct->transaction->cells[idx].orig_version = ct->transaction->cells[idx].parent->local_version;
48 } else {
49 if (!got_global_lock)
50 {
51 rh_lock(trans_lock);
52 got_global_lock = 1;
53 }
54 ct->transaction->cells[idx].local_data = obj->data;
55 ct->transaction->cells[idx].orig_version = obj->version;
56 }
57 ct->transaction->cells[idx].local_version = 0;
58 }
59 if (got_global_lock)
60 {
61 rh_unlock(trans_lock);
62 }
63 rh_unlock(parent->lock);
64 } else {
65 rh_lock(trans_lock);
66 for (idx = 0; idx < numobjs; ++idx)
67 {
68 obj = va_arg(args, mutable_object *);
69 ct->transaction->cells[idx].obj = obj;
70 ct->transaction->cells[idx].parent = NULL;
71 ct->transaction->cells[idx].local_data = add_ref(obj->data);
72 ct->transaction->cells[idx].orig_version = obj->version;
73 ct->transaction->cells[idx].local_version = 0;
74 }
75 rh_unlock(trans_lock);
76 }
77 }
78
79 void free_trans(transaction * trans)
80 {
81 if (trans)
82 {
83 free_trans(trans->chain);
84 free(trans);
85 }
86 }
87
88 int32_t commit_transaction(context * ct, int32_t readonly)
89 {
90 transaction *tmp_trans, *current;
91 object * tmp_obj;
92 int32_t idx,numaddparent;
93
94 if (ct->transaction->parent)
95 {
96 rh_lock(ct->transaction->parent->lock);
97 current = ct->transaction;
98 while(current)
99 {
100 for (idx = 0; idx < current->num_cells; ++idx)
101 {
102 if (current->cells[idx].parent)
103 {
104 if (current->cells[idx].parent->local_version != current->cells[idx].orig_version)
105 {
106 rh_unlock(ct->transaction->parent->lock);
107 return 0;
108 }
109 } else {
110 if(find_obj_cell(ct->transaction->parent->chain, current->cells[idx].obj))
111 {
112 rh_unlock(ct->transaction->parent->lock);
113 return 0;
114 } else
115 numaddparent++;
116 }
117 }
118 current = current->chain;
119 }
120 if (numaddparent)
121 {
122 tmp_trans = malloc(sizeof(transaction)+(numaddparent - 1)*sizeof(trans_cell));
123 tmp_trans->chain = ct->transaction->parent->chain;
124 tmp_trans->num_cells = 0;
125 ct->transaction->parent->chain = tmp_trans;
126 }
127 current = ct->transaction;
128 while(current)
129 {
130 for (idx = 0; idx < ct->transaction->num_cells; ++idx)
131 {
132 if (ct->transaction->cells[idx].parent)
133 {
134 //Only commit a particular object if a change has been made
135 if (ct->transaction->cells[idx].local_version)
136 {
137 tmp_obj = ct->transaction->cells[idx].parent->local_data;
138 ct->transaction->cells[idx].parent->local_data = ct->transaction->cells[idx].local_data;
139 release_ref(tmp_obj);
140 ct->transaction->cells[idx].parent->local_version++;
141 } else {
142 release_ref(ct->transaction->cells[idx].local_data);
143 }
144 } else {
145 memcpy(&(tmp_trans->cells[tmp_trans->num_cells++]), &(ct->transaction->cells[idx]), sizeof(trans_cell));
146 }
147 }
148 current = current->chain;
149 }
150 rh_unlock(ct->transaction->parent->lock);
151 } else {
152 if(readonly)
153 {
154 for (idx = 0; idx < ct->transaction->num_cells; ++idx)
155 {
156 release_ref(ct->transaction->cells[idx].local_data);
157 }
158 } else {
159 rh_lock(trans_lock);
160 current = ct->transaction;
161 while(current)
162 {
163 for (idx = 0; idx < current->num_cells; ++idx)
164 {
165 if (current->cells[idx].obj->version != current->cells[idx].orig_version)
166 {
167 rh_unlock(trans_lock);
168 return 0;
169 }
170 }
171 current = current->chain;
172 }
173 current = ct->transaction;
174 while(current)
175 {
176 for (idx = 0; idx < current->num_cells; ++idx)
177 {
178 //Only commit a particular object if a change has been made
179 if (current->cells[idx].local_version)
180 {
181 tmp_obj = current->cells[idx].obj->data;
182 current->cells[idx].obj->data = current->cells[idx].local_data;
183 release_ref(tmp_obj);
184 current->cells[idx].obj->version++;
185 } else {
186 release_ref(current->cells[idx].local_data);
187 }
188 }
189 current = current->chain;
190 }
191 rh_unlock(trans_lock);
192 }
193 }
194 rh_mutex_del(ct->transaction->lock);
195 tmp_trans = ct->transaction->parent;
196 free_trans(ct->transaction);
197 ct->transaction = tmp_trans;
198 return 1;
199 }
200
201 void prep_retry(context * ct)
202 {
203 transaction * current;
204 int32_t idx,got_global_lock=0;
205 if (ct->transaction->parent)
206 {
207 rh_lock(ct->transaction->parent->lock);
208 current = ct->transaction;
209 while(current)
210 {
211 for (idx = 0; idx < current->num_cells; ++idx)
212 {
213 release_ref(current->cells[idx].local_data);
214 current->cells[idx].local_version = 0;
215 if (!current->cells[idx].parent)
216 current->cells[idx].parent = find_obj_cell(ct->transaction->parent, current->cells[idx].obj);
217 if (current->cells[idx].parent)
218 {
219 current->cells[idx].local_data = current->cells[idx].parent->local_data;
220 current->cells[idx].orig_version = current->cells[idx].parent->local_version;
221 } else {
222 if (!got_global_lock)
223 {
224 rh_lock(trans_lock);
225 got_global_lock = 1;
226 }
227 current->cells[idx].local_data = current->cells[idx].obj->data;
228 current->cells[idx].orig_version = current->cells[idx].obj->version;
229 }
230 }
231 current = current->chain;
232 }
233 if (got_global_lock)
234 {
235 rh_unlock(trans_lock);
236 }
237 rh_unlock(ct->transaction->parent->lock);
238 } else {
239 rh_lock(trans_lock);
240 current = ct->transaction;
241 while(current)
242 {
243 for (idx = 0; idx < current->num_cells; ++idx)
244 {
245 release_ref(current->cells[idx].local_data);
246 current->cells[idx].local_version = 0;
247 current->cells[idx].local_data = current->cells[idx].obj->data;
248 current->cells[idx].orig_version = current->cells[idx].obj->version;
249 }
250 current = current->chain;
251 }
252 rh_unlock(trans_lock);
253 }
254 }
255