
----- Original Message ----- From: <strasser@uni-bremen.de> To: <boost@lists.boost.org> 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@wanadoo.fr>:
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