Boost logo

Boost :

Subject: Re: [boost] [transact] transaction language macros (was: Re: [transact] code in sandbox)
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2010-02-21 13:57:31


----- Original Message -----
From: <strasser_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Sunday, February 21, 2010 5:37 PM
Subject: Re: [boost] [transact] transaction language macros (was: Re: [transact] code in sandbox)

>
> Zitat von "vicente.botet" <vicente.botet_at_[hidden]>:
>>> inside the retry-clause the transaction object is destructed and no
>>> new one is constructed yet. STM could provide an API for setting the
>>> priority of the next transaction, using thread-specific storage to
>>> support this.
>>
>> I would prefer the transaction be available on retry. Of courset,
>> this need to have a restart function.
>
> to me this seems similar to
>
> if(int v=f()){
> //...
> }else{
> //v is not in available here.
> }
>
> since the retry{} clause is syntactically a new scope.

You are wrong here. The variable v is accesible on the else part.
 
>>>> * Should the following compile?
>>>>
>>>> begin_transaction
>>>> statement1;
>>>> statement1;
>>>> end_transaction;
>>>>
>>>
>>> it currently does. if we want to adhere to the syntax of a language
>>> extension:
>>>
>>> transaction /statement/
>>>
>>> we could enforce this by wrapping the user code in
>
>> if(false);else
>> works as expected.
>
> ok, will add that.
>
>
>> There is yet a drawback to your current implemntation:
>> * when the commit done on the destructor of the
>> commit_on_destruction variable fails, you will throw an exception on
>> a destructor. If the destructor is called due to a thrown exception
>> the program will terminate. So, ~commit_on_destruction() should not
>> throw.
>
> this can not happen. see the call to nullify(). the whole lifetime of
> commit_on_destruction is wrapped in a try{} clause. if it throws,
> commit_on_destruction is nullified.
> so ~commit_on_destruction does not throw if the scope is exited by
> exception, and I see no problem with throwing from a destructor
> otherwise, not even in the case the macros are used in user's
> destructors.
> am I missing something?

Yes. In your code the try wrapping the commit_on_destruction variable doesn't nullify the variable as it is out of scope. See (1) and (2)

#define BOOST_TRANSACT_BASIC_BEGIN_TRANSACTION(TXMGR) \
   { \
      int ___control; \
      while(true){ \
         try{ \ (1)
            boost::transact::basic_transaction<TXMGR> ___tx; \
            boost::transact::detail::commit_on_destruction<TXMGR> ___commit(___tx); \
            try{ \ (2)
               do{ \
                  ___control=1;

#define BOOST_TRANSACT_BASIC_RETRY(TXMGR) \
                  ___control=0; \
                  break; \
               }while((___control=2),false); \
            }catch(...){ \ (2)
               ___commit.nullify(); \
               throw; \
            } \
            break; \
         }catch(boost::transact::isolation_exception &___i){ \ (2)
            ___i.unwind<TXMGR>(); \
            ___control=0;
 
>> I have resumed in the following pseudo code the code generated by my
>> macros depending on whether
>> * the current transaction block is in a loop IN_LOOP
>> * there are specific exception hadlers HANDLER_SEQ
>> * there is a specific retry (RETRY)
>
> I don't quite understand what you're trying to say in this paragraph
> and the following pseudo code. defining a grammar for language
> extension/code transformation, or anything directly related to the
> macros?

I find quite clear the pseudo-code . I was just saying that it would be great to have something like that in C++. Templates work with Types, variables and constants, but don't allows to pass code as parameters. Yes the idead will be to define a grammar and the transformation inside the C++ code.
 
> could you please comment on the following case, as I'm not sure what
> the solution is:
>
> for(...){
> begin_transaction{
> if(something) break; //(1)
> }retry{
> if(stop_trying) break; //(2)
> }end_retry_in_loop;
> }
>
> possibilities:
> a) keep the current behaviour, (2) does not break the user loop, but
> the internal one
> b) make (2) break the user loop
> c) prohibit using control statements in retry{} clauses
>
> I tend to b).
> this would mean that the user has no easy way to stop retrying a
> transaction, but has to use c++ flow control for that, like exceptions
> or an own loop he can "break". but a) and c) would be pretty
> surprising to the user.

Option a) has no sens, has the user is not aware of an internal loop.

There is a difference between breaking in the transaction block and breaking on the retry block.
Breaking the loop on the the transaction block is expected to succeed the transaction.
The retry block is here to repare the fact the transaction is isolated. If the user doesn't reach to repare maybe the solution is to throw the isolation_exception.

Maybe asserting that there are no break/continue will be a good thing.

> e.g., retrying max. 5 times:
>
> try{
> begin_transaction{
> //...
> }retry{
> if(retries++ == 5) throw my_exc();
> }end_retry;
> }catch(my_exc &e){
> //tx failed
> }
>
> on a related note, I think it should not be possible to rethrow from a
> retry{} clause:

Why?
 
> begin_transaction{
> //...
> }retry{
> throw; //error
> };

I would like the following:

  begin_transaction{
    //...
  }retry{
    if(retries++ == 5) throw;
  }end_retry;

 
> the fact that an isolation_exception was caught is an implementation
> detail, so we should move the user's code on retry out of the catch{}
> block. (which is not a problem since the "break" above skips the part
> below of it anyway)

In the preceding code the user is not aware of a specific isolation_exception, but of one exception. We can state that when the user is on the retry block there is an exception that allows her/him to exit from the retry by rethrowing this exception.

Best,
Vicente


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk