Boost logo

Boost :

Subject: Re: [boost] [transaction] NewBoost.Transactionlibraryunderdiscussion
From: strasser_at_[hidden]
Date: 2010-01-22 07:26:48


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

> Do you need to create all the nested transactions lazyly up to the bottom?

that´s how it´s implemented now, but I *think* you can avoid that. but
I haven´t thought this through entirely.

global_roottx (res1_roottx, none)
global_nestedtx(res1_nestedtx,res2_roottx)

note that there is a root transaction in resource2 used by the global
nested transaction.

then, when global_nestedtx is committed, res1_nestedtx is committed,
and res2_roottx is moved to the global_roottx, without asking
resource2 to do anything. result:

global_roottx(res1_roottx(incorporated res1_nestedtx), res2_roottx)

I think this is equivalent to creating both transactions in resource2,
but the TODO comment was only the result of this idea of the top of my
head, there might be some subtle problem with that approach I´m not
seeing right now.
the same could be done when there is a gap in the "nested transaction stack".

>> tx.check();
>>
>> //do something unrelated, non-transactional, that takes a while
>>
>> //continue modifying res
>
> check doesn't means to much, we will need something more specific.
> But we will see.

what do you mean? the function name or anything beyond that?

>> if(instance_==0){
>> scoped_lock<mutex> lk(mtx_);
>> if(instance_==0){
>> instance_=operator new(sizeof(txmgr));
       //(**)
>> //construct the txmgr in instance_;
>> }
>> }

> This is not correct code but it is portable to a lot of compilers.

that the pointer might not be an atomic type on some exotic platform
is not the issue, I believe this code is also invalid on x86.
when there is a thread switch at (**) another thread goes ahead with
an unconstructed transaction manager!

>> I'd still prefer that it's the user's obligation to construct a transaction
>> manager, but maybe that's also just a difference in style.
>> what exactly is your issue with that? that the user could make a programming
>> error by omitting the construction?
>
> As I said before if the user can bind itself, the last bind
> overrides the preceding. This introduce interaction problems between
> different parts of the application. Which one should make the bind?
>
> This does not means that a resource manager can not have its own
> bind (connect/disconnect) protocol.

ok, I agree with the concern.
I´d like to find another solution to it though.

there are more problems with that approach in addition to the ones I
already mentioned:

  - unexpected construction, and unexpected exceptions that follow
from construction

e.g. the first access to an object of a resource:

pers_obj->value=1;

can throw all kinds of exceptions related to resource construction,
including: recovery_failure, failure to connect to a remote database,
etc.
which is kind of unexpected from the user´s perspective.

  - it makes default configurations more difficult.
boost.persistent let´s you construct a default transaction manager
that only uses boost.persistent. when there is a mixin that is always
user defined, I don´t think there can be a default configuration?
the user would always have to #define the configuration.

  - destruction. when is the lazily constructed transaction manager destructed?

what do you think about simply removing TransactionManager::bind() and
::has_active(), and make its constructor throw if there already is a
TransactionManager? then it´s a real singleton, and the
TransactionManagre could then support connecting/disconnecting
resources to support opening one database file first and then another,
like shown in the example we´ve used in a previous mail.


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