Alright. I see what you mean now. That is exactly what I was trying to
achieve: making the resources transactional and participate in a
global tranaction scope. I thought this was the purpose of the
transaction management facility.
In my particular example, I have a db resource plus a source control
provider and rsync transfers. And yes, I am planning to develop the
last two in a transactional manner. What I would like is to avoid
leaving the system in an inconsistent state, like in the following
situation:

R1 commits
R2 commits but fails

In the current implementation the system blows up with an invalid
transaction exception. Now, for me, this is not good enough.

I thought about having a middle stage (Prepare for Commit), where the
risk of failure is greater than in the vital Commit/Rollback stage,
where all you need to do is a switch to "live" or a cleanup,
respectively. True, bad things could happen in the last stage as well,
but the risk would be minimal.

Another idea would be, as you said, having the resources store a
history of state so that they could rollback even after they commited,
but in this case we break the concept of isolation.

On Mar 15, 12:08 pm, "Henrik Feldt" <[email protected]> wrote:
> Hello,
>
> Your first post:
>
>         Transaction manager receives a green light for resource chain commit
> and calls every resource enlisted. Resource1 tries to commit but fails with
> an exception. AbstractTransaction  cathes the exception and stores it for
> later use; the transaction is also given an invalid state. Resource2 is
> called now (surprisingly for commit!).
>
> Previously this was true in the code; during commit -- even if one resource
> failed, all resources' commit method was called. However, now the code is
> like this:
>
> _Sem.AtomWrite(() =>
> {
>         AssertState(TransactionStatus.Active);
>         Status = TransactionStatus.Committed;
>
> });
>
> _Sem.AtomRead(() => {
>
>         _SyncInfo.ForEach(s => _Logger.TryLogFail(s.BeforeCompletion));
>
>         foreach (var r in _Resources)
>         {
>                 try { r.Commit(); }
>                 catch (Exception e)
>                 {
>                         SetRollbackOnly();
>                         throw new CommitResourceException("Transaction could
> not commit because of a failed resource.",
>                                 e, r);
>                 }
>         }
>
> });
>
> try
> {
>         _Logger.TryLogFail(InnerCommit) // commit transaction
>                 .Exception(e => { throw new TransactionException("Could not
> commit", e); });}
>
> finally
> {
>         _Sem.AtomRead(() => _SyncInfo.ForEach(s =>
> _Logger.TryLogFail(s.AfterCompletion)));
>
> }
>
> So as you can see, the first resource that fails instructs the transaction
> manager (transitively since rollbackonly is a property of a transaction),
> that the transaction shouldn't be committed.
>
> So indeed this has changed.
>
> I wasn't with this project from the beginning, but in my mind this is a
> wrapper around transacted resources, not a project implementing 2PC or even
> 1PC; in order to do so we would have to keep a log file that is flushed to
> and make sure that the transaction manager can restore state after a system
> restart or failure.
>
> Instead what the project does is to call the appropriate kernel transaction
> and resource managers, implemented in MS DTC, the kernel or the database of
> the choice.
>
> As such, resources aren't fulfilling the properties of ACID; but rather a
> convenience for use together with transactions. They can keep track of state
> changes before and after commits but shouldn't be expected to be
> transactional themselves, like it seems you are trying to make them. For
> example, the isolation property between a resource and its transaction
> doesn't garantuee that the resource won't see transient data, so it doesn't
> hold.
>
> But looking at your initial message and what the code is now, I would say
> that your specific case has been fixed for. It might be however that I have
> misunderstood what you are after. If you want multiple transactions, why
> can't you do:
>
> using (var t = new TransactionScope())
> {
>         IoC.Resolve<Intercepted1>().Invoke();
>         IoC.Resolve<Intercepted2>().Invoke();
>         t.Complete()
>
> }
>
> ...
>
> [Transactional] class Intercepted1 { [Transaction] public virtual void
> Invoke(){}}
> [Transactional] class Intercepted2 { [Transaction] public virtual void
> Invoke(){}}
>
> If these use different end-point resources, e.g. different servers running
> databases, or TxF + SQL Server for example, the default transaction mode
> would be enlist and both would be enlisted in DTC, giving you 2PC and ACID
> across Intercepted1 and Intercepted2.
>
> If this doesn't match your requirements, could you send me some code that
> demonstrates the functionality you are after? You don't have to send it on
> the mailing list if it's proprietary code.
>
> Cheers,
> Henrik
>
> -----Original Message-----
> From: [email protected]
>
> [mailto:[email protected]] On Behalf Of MoonStorm
> Sent: den 15 mars 2010 12:26
> To: Castle Project Users
> Subject: Re: Transaction Management - The chain of resources not rolled back
> if one fails
>
> I had some time to look at the new code. Unfortunately the issue
> presented in my first post is still present. Thinking about it though,
> this is a case that can't be easily solved. Probably a two stage
> commit would be able to handle this properly, IF the workhorse is
> implemented in an aditional "prepare for commit" stage (i.e. the
> resource is pushing the data in a temp remote container in the
> "prepare for commit" stage and the "commit" afterwards is just
> performing a switch remotely to make the data available for retrieval
> by others).
>
> I would love to hear your thoughts about this.
>
> --
> You received this message because you are subscribed to the Google Groups
> "Castle Project Users" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group 
> athttp://groups.google.com/group/castle-project-users?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"Castle Project Users" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/castle-project-users?hl=en.

Reply via email to