Boost logo

Boost :

Subject: Re: [boost] [transact] transaction language macros (was: Re: [transact] code in sandbox)
From: strasser_at_[hidden]
Date: 2010-02-21 14:34:52


Zitat von "vicente.botet" <vicente.botet_at_[hidden]>:

>>> 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.

oh. I guess that also means that if "v" has a destructor it is called
at the end of the else-clause.
so if this is a correct parallel the transaction should indeed be
destructed at the end of the retry-clause.
we can achieve that by moving the declaration of basic_transaction one
line to the top, above "try{".
but this still doesn't mean that stm::set_priority has anything to
work with in the retry{} clause. (other than setting the priority of a
transaction that is destructed shortly thereafter)

>> 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)

could you elaborate? I don't see anything wrong.
commit_on_destruction::~commit_on_destruction can throw, but ONLY if
the user did not. so how can it happen that an exception is thrown
during exception unwinding that leads to abort()?

>
> #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 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.

I looked up c++0x lambda expressions a while ago, which are supposed
to allow passing code, but I'd still prefer macros.
with c++0x lambdas it would look something like

transaction([](){
   //user code
},[](){
   //code on retry
});

> 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.

I agree in principle, it doesn't make much sense to break from there.
why would the user want to exit the scope in the same path as if the
transactino succeeded.

but I think, if he does, breaking from the user loop is expected behaviour.
take e.g. a try catch block:

for(...){
   try{
     //...
   }catch(...){
     break;
   }
}

does the "break" make sense? hardly. why would you continue with the
application as if the whole loop succeeded. but you still expect it to
work. I'm not trying to encourage use of "break" there, but if you use
it I think you'd expect it to work, not raise an assertion. agreed?

>> on a related note, I think it should not be possible to rethrow from a
>> retry{} clause:
>
> Why?

because the user isn't even aware that an exception was thrown. from
his viewpoint, we could have implemented the whole thing with

if(!tx.commit()){
    //user's retry code
}

> I would like the following:
>
> begin_transaction{
> //...
> }retry{
> if(retries++ == 5) throw;
> }end_retry;

what's wrong with explicitely stating the type of exception he wants
to throw, instead of rethrowing an exception, even though there is no
"catch" clause visible?


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