comp.lang.ada
 help / color / mirror / Atom feed
* 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-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-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 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