* Handling transactions? @ 2015-07-27 12:21 EGarrulo 2015-07-27 14:16 ` Björn Lundin 2015-07-29 6:51 ` Jacob Sparre Andersen 0 siblings, 2 replies; 12+ messages in thread From: EGarrulo @ 2015-07-27 12:21 UTC (permalink / raw) What is the Ada idiom to handle transactions in procedures? I mean, let's suppose we perform the following steps in a procedure: Obj_1.A (); Obj_2.B (); Obj_3.C (); Obj_4.D (); If we don't reach the last line because of an exception, we must undo the effects of any previous actions. My guess is that you would use a controlled type to embody a transaction, like this pseudo-code: Transaction.Start (); Obj_1.A (); Transaction.Add_Rollback (Rollback_Obj_1_A); Obj_2.B (); Transaction.Add_Rollback (Rollback_Obj_2_A); Obj_3.C (); Transaction.Add_Rollback (Rollback_Obj_3_A); Obj_4.D (); Transaction.Commit (); -- Don't run any registered rollback. Is this the way it is done, or is it any different? Thank you. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-27 12:21 Handling transactions? EGarrulo @ 2015-07-27 14:16 ` Björn Lundin 2015-07-27 14:38 ` EGarrulo 2015-07-29 6:51 ` Jacob Sparre Andersen 1 sibling, 1 reply; 12+ messages in thread From: Björn Lundin @ 2015-07-27 14:16 UTC (permalink / raw) On 2015-07-27 14:21, EGarrulo wrote: > What is the Ada idiom to handle transactions in procedures? I mean, let's suppose we perform the following steps in a procedure: > > Obj_1.A (); > Obj_2.B (); > Obj_3.C (); > Obj_4.D (); > > If we don't reach the last line because of an exception, we must undo the effects of any previous actions. My guess is that you would use a controlled type to embody a transaction, like this pseudo-code: > > Transaction.Start (); > Obj_1.A (); > Transaction.Add_Rollback (Rollback_Obj_1_A); > Obj_2.B (); > Transaction.Add_Rollback (Rollback_Obj_2_A); > Obj_3.C (); > Transaction.Add_Rollback (Rollback_Obj_3_A); > Obj_4.D (); > Transaction.Commit (); -- Don't run any registered rollback. > > Is this the way it is done, or is it any different? Thank you. > You do not mention what kind of transactions you mean. At work, where we do transactions towards databases in a multi-process environment, we do like this: loop begin Transaction.Start (); Obj_1.Read; Obj_2.Read; Obj_3.Read; Obj_4.Read; Obj_1.A (); Obj_2.B (); Obj_3.C (); Obj_4.D (); Transaction.Commit (); exit; exception when Transaction_Conflict => Transaction.Rollback; end; end loop; The idea is that you want to read values within the transaction, so you can re-read new values, if another process committed rows that affect the objects. You then want to roll EVERYTHING back, and start over, perhaps with another result-set. The reads may give different results, depending on what the external source did to cause the transaction_conflict. Now, exactly what raises Transaction_Conflict is up to you. We run db in read_committed mode, and each table has two columns, latest updater and latest updated timestamp. Each sql that modifies a row also HAVE to change these columns with its process-name and timestamp. This we ensure with auto-generated code We include the fields in the where-clause of the statement update T set A=1,B=2 where some-logical-condition and Last_Updater=:Last_Updater and Lastest_Updated=:Latest_Updated These two fields gets their value when reading the rows - Obj_1.Read; Then the update really does Sql.Execute(Statement, Rows_Affected); if Rows_Affected = 0 then raise Transaction_Conflict; end if; The two fields may be replaced with a row-version field of course. Some put triggers on each table to auto-increment this row-version, so user-code does not need to care. But the idea is the same: loop BEGIN read update if no row affected, raise exception COMMIT exit loop catch exception ROLLBACK end loop This way, the row is only locked when actual writing to it is done -- Björn ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-27 14:16 ` Björn Lundin @ 2015-07-27 14:38 ` EGarrulo 2015-07-27 14:53 ` Simon Wright 0 siblings, 1 reply; 12+ messages in thread From: EGarrulo @ 2015-07-27 14:38 UTC (permalink / raw) Sorry, I didn't specify that I was not talking about database transactions -- albeit the concept is the same -- but rather about keeping an object in a consistent state even when exceptions occur during processing. Since the realm of Ada is high-integrity systems, I suppose that this is a solved problem, but I haven't found any explanations in regard. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-27 14:38 ` EGarrulo @ 2015-07-27 14:53 ` Simon Wright 2015-07-27 16:38 ` David Botton 0 siblings, 1 reply; 12+ messages in thread From: Simon Wright @ 2015-07-27 14:53 UTC (permalink / raw) EGarrulo <egarrulo@gmail.com> writes: > Sorry, I didn't specify that I was not talking about database > transactions -- albeit the concept is the same -- but rather about > keeping an object in a consistent state even when exceptions occur > during processing. Since the realm of Ada is high-integrity systems, > I suppose that this is a solved problem, but I haven't found any > explanations in regard. One approach to high-integrity systems requires you to prove, using for example SPARK, that there can be no exceptions; then the problem doesn't arise. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-27 14:53 ` Simon Wright @ 2015-07-27 16:38 ` David Botton 2015-07-27 18:15 ` EGarrulo 2015-07-28 2:41 ` Norman Worth 0 siblings, 2 replies; 12+ messages in thread From: David Botton @ 2015-07-27 16:38 UTC (permalink / raw) > One approach to high-integrity systems requires you to prove, using for > example SPARK, that there can be no exceptions; then the problem doesn't > arise. SPARK isn't Ada nor is it an approach the makes sense for most programming tasks. He could also just write those sections in other proof base languages. I wonder if SPARK is even the best choice today for that purpose. EGarrulo, your question is not a language question but a design question. What you want can be done in any language and depending on what you are trying to "roll back" I can think of many many ways to do it. Be specific and I'm sure some of us can offer advice for your project. David Botton ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-27 16:38 ` David Botton @ 2015-07-27 18:15 ` EGarrulo 2015-07-28 0:10 ` Randy Brukardt 2015-07-28 2:41 ` Norman Worth 1 sibling, 1 reply; 12+ messages in thread From: EGarrulo @ 2015-07-27 18:15 UTC (permalink / raw) On Monday, July 27, 2015 at 6:38:37 PM UTC+2, David Botton wrote: > EGarrulo, your question is not a language question but a design question. What you want can be done in any language and depending on what you are trying to "roll back" I can think of many many ways to do it. Be specific and I'm sure some of us can offer advice for your project. Thank you, but mine is a curiosity. I am new to Ada and I am trying to understand how to approach problems the Ada way. My above hypothetical solution mirrors what I would have done in C++, by following the RAII (Resource Acquisition Is Initialization) idiom. It seems to me that Ada offers a similar idiom with its controlled types. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-27 18:15 ` EGarrulo @ 2015-07-28 0:10 ` Randy Brukardt 2015-07-28 5:33 ` J-P. Rosen 2015-07-28 6:45 ` Dmitry A. Kazakov 0 siblings, 2 replies; 12+ messages in thread From: Randy Brukardt @ 2015-07-28 0:10 UTC (permalink / raw) "EGarrulo" <egarrulo@gmail.com> wrote in message news:40c8dba8-85e9-42e7-8316-96c976531ab4@googlegroups.com... >On Monday, July 27, 2015 at 6:38:37 PM UTC+2, David Botton wrote: >> EGarrulo, your question is not a language question but a design question. >> What you want can be done in any language and depending on what you >> are trying to "roll back" I can think of many many ways to do it. Be >> specific >> and I'm sure some of us can offer advice for your project. >Thank you, but mine is a curiosity. I am new to Ada and I am trying to >understand >how to approach problems the Ada way. My above hypothetical solution >mirrors >what I would have done in C++, by following the RAII (Resource Acquisition >Is >Initialization) idiom. It seems to me that Ada offers a similar idiom with >its controlled types. As always, the best approach depends on exactly what you're doing. In Claw, we needed exclusion locks in some cases, and we found the best pattern for them was to use a limited controlled type: type Lock is new Ada.Finalization.Limited_Controlled with null record; overriding procedure Initialize (Object : in out Lock); overriding procedure Finalize (Object : in out Lock); The body of Initialize seizes the lock, and the body of Finalize frees the lock. Then, the simple act of declaring an object of type Lock gets the lock and holds it until the operation is complete (or fails); the lock is then freed (even if an exception is propagated). This is typically used in a block: declare My_Lock : Lock; -- Gets lock. begin -- Do operations needing the lock. end; -- The lock is freed here, no matter how this block is completed. I suspect that you could use a similar pattern for transactions (although I've never tried it). Randy. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-28 0:10 ` Randy Brukardt @ 2015-07-28 5:33 ` J-P. Rosen 2015-07-28 6:45 ` Dmitry A. Kazakov 1 sibling, 0 replies; 12+ messages in thread From: J-P. Rosen @ 2015-07-28 5:33 UTC (permalink / raw) Le 28/07/2015 02:10, Randy Brukardt a écrit : > As always, the best approach depends on exactly what you're doing. In Claw, > we needed exclusion locks in some cases, and we found the best pattern for > them was to use a limited controlled type: > [...] Note that this pattern, as well as other patterns of the Seize/Release kind that need to be safe in the face of exceptions, can be enforced by AdaControl (rule Unsafe_Paired_Calls). -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-28 0:10 ` Randy Brukardt 2015-07-28 5:33 ` J-P. Rosen @ 2015-07-28 6:45 ` Dmitry A. Kazakov 2015-07-28 20:23 ` Randy Brukardt 1 sibling, 1 reply; 12+ messages in thread From: Dmitry A. Kazakov @ 2015-07-28 6:45 UTC (permalink / raw) On Mon, 27 Jul 2015 19:10:09 -0500, Randy Brukardt wrote: > This is typically used in a block: > > declare > My_Lock : Lock; -- Gets lock. > begin > -- Do operations needing the lock. > end; -- The lock is freed here, no matter how this block is completed. > > I suspect that you could use a similar pattern for transactions (although > I've never tried it). Yes, the way I did it was similar: declare My_Transaction : Transaction (...); begin -- Do operations Commit (My_Transaction); end; The transaction object has the flag Committed set by Commit. Upon an exception the flag remains not set and Finalize rolls back. Without an exception the flag is set and Finalize commits. The problem with this approach is that you cannot propagate exceptions on errors from Finalize when commit or rollback fails. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-28 6:45 ` Dmitry A. Kazakov @ 2015-07-28 20:23 ` Randy Brukardt 0 siblings, 0 replies; 12+ messages in thread From: Randy Brukardt @ 2015-07-28 20:23 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:xrh840crgak6$.og5ru41qaz0o$.dlg@40tude.net... > On Mon, 27 Jul 2015 19:10:09 -0500, Randy Brukardt wrote: > >> This is typically used in a block: >> >> declare >> My_Lock : Lock; -- Gets lock. >> begin >> -- Do operations needing the lock. >> end; -- The lock is freed here, no matter how this block is >> completed. >> >> I suspect that you could use a similar pattern for transactions (although >> I've never tried it). > > Yes, the way I did it was similar: > > declare > My_Transaction : Transaction (...); > begin > -- Do operations > Commit (My_Transaction); > end; > > The transaction object has the flag Committed set by Commit. Upon an > exception the flag remains not set and Finalize rolls back. Without an > exception the flag is set and Finalize commits. Looks good to me. > The problem with this approach is that you cannot propagate exceptions on > errors from Finalize when commit or rollback fails. Well, you can if your only intent is to kill the program (Finalize will cause Program_Error to be raised -- somewhere -- if it propagates an exception). If you want to do recovery of some sort, it would be a problem. (Off-hand, I'm not sure what recovery one can do when rollback fails, and the recovery from a commit failure seems to be to rollback, so it seems that killing the program is the primary goal. But of course YMMV.) Randy. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-27 16:38 ` David Botton 2015-07-27 18:15 ` EGarrulo @ 2015-07-28 2:41 ` Norman Worth 1 sibling, 0 replies; 12+ messages in thread From: Norman Worth @ 2015-07-28 2:41 UTC (permalink / raw) On 7/27/2015 10:38 AM, David Botton wrote: >> One approach to high-integrity systems requires you to prove, using for >> example SPARK, that there can be no exceptions; then the problem doesn't >> arise. > > SPARK isn't Ada nor is it an approach the makes sense for most programming tasks. He could also just write those sections in other proof base languages. I wonder if SPARK is even the best choice today for that purpose. > > EGarrulo, your question is not a language question but a design question. What you want can be done in any language and depending on what you are trying to "roll back" I can think of many many ways to do it. Be specific and I'm sure some of us can offer advice for your project. > > David Botton > Proving that an exception is impossible is nice when you can do it. (And you can do it outside of SPARK.) Unfortunately, that is not always the situation. Problems caused by data coming from an I/O stream are common examples of why transactions fail. Using preconditions to check the data used to call a transaction procedure can simplify matters, but rolling back just what needs to be rolled back can still be messy. However, the general method shown for databases should work for just about everything. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Handling transactions? 2015-07-27 12:21 Handling transactions? EGarrulo 2015-07-27 14:16 ` Björn Lundin @ 2015-07-29 6:51 ` Jacob Sparre Andersen 1 sibling, 0 replies; 12+ messages in thread From: Jacob Sparre Andersen @ 2015-07-29 6:51 UTC (permalink / raw) EGarrulo <egarrulo@gmail.com> writes: > What is the Ada idiom to handle transactions in procedures? To copy the data into the transaction procedure on start and out on successful completion: procedure Transaction (Data: in out Some_Type) is Local : Some_Type := Data; begin Local.Obj_1.A; Local.Obj_2.B; Local.Obj_3.C; Local.Obj_4.D; Data := Local; -- commit end Transaction; Greetings, Jacob -- "... but it was, on the other hand, very good at being a slow and dim-witted pupil." "I had no idea they were supposed to be in short supply" ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2015-07-29 6:51 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-07-27 12:21 Handling transactions? EGarrulo 2015-07-27 14:16 ` Björn Lundin 2015-07-27 14:38 ` EGarrulo 2015-07-27 14:53 ` Simon Wright 2015-07-27 16:38 ` David Botton 2015-07-27 18:15 ` EGarrulo 2015-07-28 0:10 ` Randy Brukardt 2015-07-28 5:33 ` J-P. Rosen 2015-07-28 6:45 ` Dmitry A. Kazakov 2015-07-28 20:23 ` Randy Brukardt 2015-07-28 2:41 ` Norman Worth 2015-07-29 6:51 ` Jacob Sparre Andersen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox