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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 90710 - (hide 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 picmarco 90710 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