/[eiffelstudio]/branches/eth/eve/Src/library/abel/libraries/ethz/src/abel/ps_executor.e
ViewVC logotype

Contents of /branches/eth/eve/Src/library/abel/libraries/ethz/src/abel/ps_executor.e

Parent Directory Parent Directory | Revision Log Revision Log


Revision 90710 - (show annotations)
Fri Jan 18 13:13:59 2013 UTC (6 years, 10 months ago) by picmarco
File size: 13606 byte(s)
renamed CRUD_EXECUTOR to EXECUTOR
1 note
2 description: "[
3 Performs any kind of operations on a repository.
4 Errors are reported in the `Current.last_error' field and an excepion is raised if an error happens,
5 so you don't have to manually check on errors every time you call a feature in `Current'.
6
7 If you use explicit transaction management (the *_within_transaction features),
8 a transaction conflict exception will be caught and the transaction will be aborted automatically, without raising another exception.
9 You can then continue to use the transaction, but operations on an aborted transaction have no effect on the repository,
10 and a future commit call on the transaction is doomed to fail.
11 ]"
12 author: "Roman Schmocker"
13 date: "$Date$"
14 revision: "$Revision$"
15
16 class
17 PS_EXECUTOR
18
19 inherit
20
21 PS_EIFFELSTORE_EXPORT
22
23 create
24 make
25
26 feature --Access
27
28 repository: PS_REPOSITORY
29 -- The data repository on which `Current' operates.
30
31 feature -- Status Report
32
33 is_persistent (an_object: ANY): BOOLEAN
34 -- Is there a database entry for `an_object'?
35 do
36 Result := repository.is_identified (an_object, new_transaction)
37 end
38
39 is_persistent_within_transaction (an_object: ANY; a_transaction: PS_TRANSACTION): BOOLEAN
40 -- Is there a database entry for `an_object' within `a_transaction'?
41 do
42 Result := repository.is_identified (an_object, a_transaction)
43 end
44
45 can_handle (object: ANY): BOOLEAN
46 -- Can the executor with the current repository handle the object `object'?
47 do
48 Result := repository.can_handle (object)
49 end
50
51 feature -- Data retrieval
52
53 execute_query (query: PS_OBJECT_QUERY [ANY])
54 -- Execute `query' and store the result in `query.result_cursor'.
55 do
56 execute_within_implicit_transaction (agent execute_query_within_transaction (query, ?), True)
57 ensure
58 query_executed: query.is_executed
59 retrieved_item_persistent: not query.result_cursor.after implies is_persistent_within_transaction (query.result_cursor.item, new_transaction)
60 can_handle_retrieved_item: not query.result_cursor.after implies can_handle (query.result_cursor.item)
61 end
62
63 execute_tuple_query (tuple_query: PS_TUPLE_QUERY [ANY])
64 -- Execute `tuple_query' and store the result in `query.result_cursor'.
65 do
66 execute_within_implicit_transaction (agent execute_tuple_query_within_transaction (tuple_query, ?), True)
67 ensure
68 query_executed: tuple_query.is_executed
69 end
70
71 --reload (object: ANY)
72 -- Reload `object'.
73 -- require
74 -- already_loaded: is_persistent (object, new_transaction)
75 -- do
76 -- fixme ("TODO: see reload_within_transaction")
77 -- ensure
78 -- still_persistent: is_persistent (object, new_transaction)
79 -- end
80
81 feature -- Data manipulation
82
83 insert (an_object: ANY)
84 -- Insert `an_object' into the repository.
85 require
86 can_handle_object: can_handle (an_object)
87 do
88 if not is_persistent_within_transaction (an_object, new_transaction)
89 then
90 execute_within_implicit_transaction (agent insert_within_transaction(an_object, ?), False)
91 end
92 ensure
93 object_persistent: is_persistent_within_transaction (an_object, new_transaction)
94 end
95
96 update (an_object: ANY)
97 -- Write changes of `an_object' to the repository.
98 require
99 object_persistent: is_persistent_within_transaction (an_object, new_transaction)
100 can_handle_object: can_handle (an_object)
101 do
102 execute_within_implicit_transaction (agent update_within_transaction(an_object, ?), False)
103 ensure
104 object_persistent: is_persistent_within_transaction (an_object, new_transaction)
105 end
106
107 delete (an_object: ANY)
108 -- Delete `an_object' from the repository.
109 require
110 object_persistent: is_persistent_within_transaction (an_object, new_transaction)
111 can_handle_object: can_handle (an_object)
112 do
113 execute_within_implicit_transaction (agent delete_within_transaction(an_object, ?), False)
114 ensure
115 not_persistent_anymore: not is_persistent_within_transaction (an_object, new_transaction)
116 end
117
118 execute_deletion_query (deletion_query: PS_OBJECT_QUERY [ANY])
119 -- Delete all objects that match the criteria defined in `deletion_query'.
120 do
121 execute_within_implicit_transaction (agent execute_deletion_query_within_transaction (deletion_query, ?), False)
122 end
123
124 feature -- Transaction-based data retrieval and querying
125
126 execute_query_within_transaction (a_query: PS_OBJECT_QUERY [ANY]; transaction: PS_TRANSACTION)
127 -- Execute `a_query' within the transaction `transaction'.
128 -- In case of a conflict between transactions, it will abort `transaction' and return normally with an empty result.
129 -- In every other case of errors it will abort `transaction' and raise an exception.
130 require
131 same_repository: transaction.repository = Current.repository
132 do
133 if a_query.is_executed then
134 a_query.reset
135 end
136 handle_error_on_action (agent repository.execute_query (a_query, transaction), transaction)
137 ensure
138 query_executed: a_query.is_executed
139 transaction_set: a_query.transaction = transaction
140 result_is_persistent: not a_query.result_cursor.after implies is_persistent_within_transaction (a_query.result_cursor.item, transaction)
141 can_handle_retrieved_item: not a_query.result_cursor.after implies can_handle (a_query.result_cursor.item)
142 aborted_implies_after: transaction.has_error implies a_query.result_cursor.after
143 only_transaction_conflicts_return_normally: transaction.has_error implies attached {PS_TRANSACTION_CONFLICT} transaction.error
144 end
145
146
147 --reload_within_transaction (object:ANY; transaction: PS_TRANSACTION)
148 -- Reload `object' within transaction `transaction'
149 -- In case of a conflict between transactions, it will abort `transaction' and return normally.
150 -- In every other case of errors it will abort `transaction' and raise an exception.
151 -- require
152 -- already_loaded: is_persistent (object, transaction)
153 -- do
154 -- fixme ("TODO: The function is dangerous: In case of an abort because of transaction conflicts, the state of `object' is undefined, and the callee only realizes that when transaction commits.")
155 -- ensure
156 -- still_persistent: is_persistent (object, transaction)
157 -- end
158
159 insert_within_transaction (an_object: ANY; transaction: PS_TRANSACTION)
160 -- Insert `an_object' within the transaction `transaction' into the repository.
161 -- In case of a conflict between transactions, it will abort `transaction' and return normally.
162 -- In every other case of errors it will abort `transaction' and raise an exception.
163 require
164 same_repository: transaction.repository = Current.repository
165 can_handle_object: can_handle (an_object)
166 do
167 if not is_persistent_within_transaction (an_object, transaction)
168 then
169 handle_error_on_action (agent repository.insert(an_object, transaction), transaction)
170 end
171 ensure
172 success_implies_persistent: not transaction.has_error implies is_persistent_within_transaction (an_object, transaction)
173 failure_implies_not_persistent: transaction.has_error implies not is_persistent_within_transaction (an_object, transaction)
174 only_transaction_conflicts_return_normally: transaction.has_error implies attached {PS_TRANSACTION_CONFLICT} transaction.error
175 end
176
177 update_within_transaction (an_object: ANY; transaction: PS_TRANSACTION)
178 -- Write back changes of `an_object' into the repository, within the transaction `transaction'.
179 -- In case of a conflict between transactions, it will abort `transaction' and return normally.
180 -- In every other case of errors it will abort `transaction' and raise an exception.
181 require
182 same_repository: transaction.repository = Current.repository
183 object_persistent: is_persistent_within_transaction (an_object, transaction)
184 can_handle_object: can_handle (an_object)
185 do
186 handle_error_on_action (agent repository.update(an_object, transaction), transaction)
187 ensure
188 only_transaction_conflicts_return_normally: transaction.has_error implies attached {PS_TRANSACTION_CONFLICT} transaction.error
189 end
190
191 delete_within_transaction (an_object: ANY; transaction: PS_TRANSACTION)
192 -- Delete `an_object' within the transaction `transaction' from the repository.
193 -- In case of a conflict between transactions, it will abort `transaction' and return normally.
194 -- In every other case of errors it will abort `transaction' and raise an exception.
195 require
196 same_repository: transaction.repository = Current.repository
197 object_persistent: is_persistent_within_transaction (an_object, transaction)
198 can_handle_object: can_handle (an_object)
199 do
200 handle_error_on_action (agent repository.delete (an_object, transaction), transaction)
201 ensure
202 success_implies_not_persistent: not transaction.has_error implies not is_persistent_within_transaction (an_object, transaction)
203 failure_implies_still_persistent: transaction.has_error implies is_persistent_within_transaction (an_object, transaction)
204 only_transaction_conflicts_return_normally: transaction.has_error implies attached {PS_TRANSACTION_CONFLICT} transaction.error
205 end
206
207 execute_deletion_query_within_transaction (a_query: PS_OBJECT_QUERY [ANY]; transaction: PS_TRANSACTION)
208 -- Delete, within the transaction `transaction', all objects that match the criteria defined in `a_query'
209 -- In case of a conflict between transactions, it will abort `transaction' and return normally.
210 -- In every other case of errors it will abort `transaction' and raise an exception.
211 require
212 same_repository: transaction.repository = Current.repository
213 do
214 if a_query.is_executed then
215 a_query.reset
216 end
217 handle_error_on_action (agent repository.delete_query (a_query, transaction), transaction)
218 ensure
219 query_executed: a_query.is_executed
220 transaction_set: a_query.transaction = transaction
221 result_is_empty: a_query.result_cursor.after
222 only_transaction_conflicts_return_normally: transaction.has_error implies attached {PS_TRANSACTION_CONFLICT} transaction.error
223 end
224
225 feature -- Transaction factory function
226
227 new_transaction: PS_TRANSACTION
228 -- Create a new transaction for `Current.repository'..
229 do
230 create Result.make (repository)
231 end
232
233 feature --Error handling
234
235 has_error: BOOLEAN
236 -- Did the last operation have an error?
237 do
238 Result := not attached {PS_NO_ERROR} last_error
239 end
240
241 last_error: PS_ERROR
242 -- The last encountered error.
243
244 feature {NONE} -- Implementation
245
246 default_retries: INTEGER = 2
247 -- The default retries for implicit transaction handling, if there is a transaction conflict.
248
249 execute_within_implicit_transaction (action: PROCEDURE [ANY, TUPLE [PS_TRANSACTION]]; readonly: BOOLEAN)
250 -- This function will execute `action' with implicit transaction handling
251 -- It will retry `action' `Current.default_retries' times if there's a transaction conflict,
252 -- and then raise a `PS_UNRESOLVABLE_TRANSACTION_CONFLICT' error.
253 local
254 retries: INTEGER
255 transaction: PS_TRANSACTION
256 success: BOOLEAN
257 do
258 from
259 retries := 1
260 success := False
261 until
262 retries > default_retries or success
263 loop
264 if readonly then
265 create transaction.make_readonly (repository)
266 action.call ([transaction])
267 else
268 transaction := new_transaction
269 action.call ([transaction])
270 transaction.commit
271 end
272 if not transaction.has_error then
273 success := True
274 end
275 retries := retries + 1
276 end
277 if not success then
278 create {PS_UNRESOLVABLE_TRANSACTION_CONFLICT} last_error
279 last_error.raise
280 end
281 end
282
283 handle_error_on_action (action: PROCEDURE [ANY, TUPLE]; transaction: PS_TRANSACTION)
284 -- This function will try the repository operation `action' and catch any error.
285 -- In case of a conflict between transactions, it will abort `transaction' and return normally.
286 -- In every other case of errors it will abort `transaction' and raise an exception.
287 local
288 retried: BOOLEAN
289 do
290 -- Please note that this function accepts transactions that already have an error, especially (but not exclusively) in case of a retry
291 last_error := transaction.error
292 if not transaction.has_error then
293 action.call ([]) -- This may cause an exception which will be handled by the rescue clause
294 end
295 ensure
296 only_transaction_conflicts_return_normally: transaction.has_error implies attached {PS_TRANSACTION_CONFLICT} transaction.error
297 rescue
298 last_error := transaction.error
299 if not retried then
300 retried := True
301 if transaction.has_error and then attached {PS_TRANSACTION_CONFLICT} transaction.error then
302 retry -- The retry will "catch" transaction conflicts
303 else
304 -- Any other error will propagate upwards
305 end
306 end
307 end
308
309 execute_tuple_query_within_transaction (query: PS_TUPLE_QUERY [ANY]; transaction: PS_TRANSACTION)
310 -- Execute tuple query `query'. Exported to `NONE' because you can only have tuple queries with readonly transactions and implicit transaction management.
311 require
312 readonly_transaction: transaction.is_readonly
313 do
314 if query.is_executed then
315 query.reset
316 end
317 handle_error_on_action (agent repository.execute_tuple_query (query, transaction), transaction)
318 ensure
319 query_executed: query.is_executed
320 transaction_set: query.transaction = transaction
321 aborted_implies_after: transaction.has_error implies query.result_cursor.after
322 only_transaction_conflicts_return_normally: transaction.has_error implies attached {PS_TRANSACTION_CONFLICT} transaction.error
323 end
324
325 feature {NONE} -- Initialization
326
327 make (a_repository: PS_REPOSITORY)
328 -- Initialization for `Current'.
329 do
330 repository := a_repository
331 create {PS_NO_ERROR} last_error
332 ensure
333 repository_set: repository = a_repository
334 end
335
336 end

Properties

Name Value
svn:eol-style native
svn:keywords Author Date ID Revision

  ViewVC Help
Powered by ViewVC 1.1.23