To conclude, this is a very interesting proposal, that needs more
refinements before being used wildly in all situation requiring
transactional processing.
Nice idea and good job Caleb !
Thanks :)
Caleb
Denis
>
> Caleb
>
>>
>> Thanks
>> -Vincent
>>
>> On Jan 10, 2011, at 2:15 PM, Caleb James DeLisle wrote:
>>
>>> Hi,
>>> I have been working hard on filesystem attachments and I found that
> synchronizing manual filesystem
>>> transactions with automatic database transactions was a difficult job
> and I needed a new tool to do
>>> it. So I wrote what I am proposing to be the next XWiki Persistence
> Engine.
>>>
>>> I'll start off with the fun part of the proposal, I have been calling
it
> xwiki-store so far but I am
>>> so excited about the capabilities of this engine that I don't think it
> does it justice to name it
>>> "store" after the place on the corner with milk and eggs. I am
proposing
> it be named "XWiki
>>> Persistence Engine", the directory will be renamed xwiki-persistence,
> the artifact name
>>> xwiki-core-persistence, and the package name org.xwiki.persistence.
> Persistence is an attribute of
>>> castles, mountains and redwood trees which I think is fitting for a
> conservatively designed storage
>>> engine.
>>>
>>> Now a little explanation of what I'm so excited about:
>>> The common and error prone way of saving things in the database is to
> open a transaction, enter a
>>> try clause, do something then commit. If we catch an exception, then
we
> rollback.
>>> something like this:
>>>
>>> begin transaction;
>>> try {
>>> do something;
>>> do something else;
>>> commit;
>>> } catch (Any exception which may occur) {
>>> rollback;
>>> }
>>>
>>> There are 3 things which can go wrong. 1 we forget to begin the
> transaction, 2 we forget to commit
>>> and 3 we do not rollback properly. What makes things worse is often
the
> database will "assume we
>>> meant to..." and things will work ok most of the time which makes
things
> much worse because bugs
>>> will hide very well.
>>>
>>> My answer to this problem is a class called TransactionRunnable. It
> provides a set of 5 empty
>>> methods to override: onPreRun(), onRun(), onCommit(), onRollback(),
and
> onComplete(). the exact
>>> circumstances under which each are called is documented in the javadoc
> comments here:
>>>
>
http://svn.xwiki.org/svnroot/xwiki/contrib/sandbox/xwiki-store/xwiki-store-…
>>> I wrote TransactionRunnable twice, I
wrote it, used it for
attachments,
> then after having real
>>> experience as a user, I wrote it again.
>>>
>>> To repeat our original example with TransactionRunnable you might say
> this:
>>>
>>> public class DoSomethingTransactionRunnable extends
TransactionRunnable
>>> {
>>> public void onRun()
>>> {
>>> do something;
>>> do something else;
>>> }
>>> }
>>>
>>> Now we can use another TransactionRunnable which opens and closes the
> transaction for us.
>>>
>>> StartableTransactionRunnable transaction = new
> HibernateTransactionRunnable();
>>> new DoSomethingTransactionRunnable().runIn(transaction);
>>> transaction.start();
>>>
>>> the runIn() function allows us to run one TransactionRunnable inside
of
> another. Supposing we wanted
>>> to reuse "do something else" in other places, we can make it a
separate
> TransactionRunnable and use
>>> the runIn() function to hook it to our DoSomethingTransactionRunnable
> ie:
>>>
>>> public class DoSomethingTransactionRunnable extends
TransactionRunnable
>>> {
>>> public DoSomethingTransactionRunnable()
>>> {
>>> new DoSomethingElseTransactionRunnable().runIn(this);
>>> }
>>> ..
>>>
>>> The only limitations on running TransactionRunnables inside of one
> another are they cannot run more
>>> than once and they cannot call themselves (this would be an infinite
> loop).
>>>
>>> This pattern makes each job which is done on storage easily isolated
> and, as I have so far
>>> experienced, trivial to test. However, it still leaves the possibility
> that we might forget that
>>> DoSomethingTransactionRunnable must be run inside of a hibernate
> transaction. I have devised a
>>> solution for this too. Using generics, I offered a means for the
author
> of a TransactionRunnable to
>>> communicate to the compiler what other TransactionRunnable their
> runnable must be run in and without
>>> explicit casting or defining of an intermediary runnable, this
> requirement cannot be violated or
>>> else it wouldn't compile!
>>>
>>> Finally we have the issue of starting the runnable. Who's to say I
won't
> be tired one day and just
>>> write new DoSomethingTransactionRunnable().start() without opening a
> transaction first? If
>>> DoSomethingTransactionRunnable cannot be safely run outside of a
> transaction all it needs to do is
>>> not extend StartableTransactionRunnable and it won't have any start
> function.
>>>
>>> I have taken a multitude of very easy mistakes and given the author of
a
TransactionRunnable the
>> tools to make it very hard for the user to make them. Also, since a
TransactionRunnable has no
>> reason to be very long (it can just branch off into another runnable)
this will make testing and
>> code review easy in the place where it is most important. This part of
the code is entirely generic
>> and has no dependence on hibernate or anything else.
>>
>> I propose we move:
>> contrib/sandbox/xwiki-store/xwiki-store-transaction/
>> to:
>> platform/core/xwiki-persistence/xwiki-persistence-transaction
>>
>> And I will propose moving each additional piece in the coming days.
>>
>> WDYT?
>>
>> Caleb
>
> _______________________________________________
> devs mailing list
> devs(a)xwiki.org
>
http://lists.xwiki.org/mailman/listinfo/devs
>
_______________________________________________
devs mailing list
devs(a)xwiki.org
http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________
devs mailing list
devs(a)xwiki.org
http://lists.xwiki.org/mailman/listinfo/devs