Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » [CDO] CDO and transaction isolation levels
[CDO] CDO and transaction isolation levels [message #981989] Mon, 12 November 2012 16:33 Go to next message
Silvestre Martins is currently offline Silvestre Martins
Messages: 41
Registered: July 2009
Member
In typical ORM frameworks, this issue is usually not addressed, because the transactions are implemented directly on the database level (like Hibernate) and therefore the application inherits the transaction isolation level from the database.
However this is not what seems to happen with CDO.

From what I've learned, we can say CDO "emulates" the behavior of isolation level Read Committed when the passiveUpdateEnabled=true, because the notifications from CDO assures that any read from transaction T1 will get the latest state of the object, even if it was changed (committed) after T1 started.
So, if we set passiveUpdateEnabled=false, then we would have the behavior from isolation level Repeatable Read because once a object (row) is read, it will keep the same object state until the end of transaction.
Is this assumption correct?

And if we wanted to have a Serializable behavior, which means, full isolated transactions, how could we achieve it?
One way, with a full optimistic lock approach, could be to store (locally) all the objects read from the database by CDO and when committing, make a read-lock on all those objects. In case CDO detects that some object was changed since transaction started, the lock would fail, and therefore the 2nd transaction would be rejected.


Does someone knows if this issue of transaction isolation levels was addressed on the CDO?
Can CDO be configured to rely on the Database default isolation level?

Please comment and share your opinions.
Re: [CDO] CDO and transaction isolation levels [message #982503 is a reply to message #981989] Tue, 13 November 2012 02:13 Go to previous messageGo to next message
Eike Stepper is currently offline Eike Stepper
Messages: 5501
Registered: July 2009
Senior Member
Am 12.11.2012 22:33, schrieb Silvestre Martins:
> In typical ORM frameworks, this issue is usually not addressed, because the transactions are implemented directly on
> the database level (like Hibernate) and therefore the application inherits the transaction isolation level from the
> database.
> However this is not what seems to happen with CDO.
This is most likely the case because CDO adds another layer of caching (at the client side) and lazy loading.

> From what I've learned, we can say CDO "emulates" the behavior of isolation level Read Committed when the
> passiveUpdateEnabled=true, because the notifications from CDO assures that any read from transaction T1 will get the
> latest state of the object, even if it was changed (committed) after T1 started.
Yes, with a certain amount of latency. The effects of this latency can only be mitigated by acquiring locks on the
objects. They ensure that the EObjects are wired with the latest state of the repository and that this state is not
changed until the locks are released.

> So, if we set passiveUpdateEnabled=false, then we would have the behavior from isolation level Repeatable Read because
> once a object (row) is read, it will keep the same object state until the end of transaction.
> Is this assumption correct?
Yes, but the important precondition is "once the object is read". Because of the lazy loading it can in fact happen that
objects that are demand loaded later belong to a different/later "revision" of the repository The only way to compensate
this is to use locks. Please note that sessions with passiveUpdateEnabled=false and
session.getRepositoryInfo().isSupportingAudits()=false automatically go into an internal "sticky" mode. That means that
at least objects that have been written/committed since the last session.refresh() will be read in the exact same state.

> And if we wanted to have a Serializable behavior, which means, full isolated transactions, how could we achieve it?
The simplest way would be to switch the repository itself to a mode that really serializes all commits:
IRepository.Props.SERIALIZE_COMMITS (new in 4.2).

> One way, with a full optimistic lock approach, could be to store (locally) all the objects read from the database by CDO
If heap space is not an issue it would probably be enough that you keep strong references to the CDORevisions in the
revision manager cache of your CDOSession.

> and when committing, make a read-lock on all those objects.
Why? The repository will acquire write locks for all changed and containing objects (in that branch) anyway, and if
IRepository.Props.ENSURE_REFERENTIAL_INTEGRITY=true also for all objects whose set of referecing objects will change by
this commit.

Please note that CDO has its own locking layer above the physical storage system. Among other things it supports checks
for "containment cycles" that could otherwise be created by concurrent modifications of the tree structure of the model.

> In case CDO detects that some object was changed since transaction started, the lock would fail, and therefore the 2nd
> transaction would be rejected.
I think that's what CDO's locking layer is doing.

> Does someone knows if this issue of transaction isolation levels was addressed on the CDO?
> Can CDO be configured to rely on the Database default isolation level?
I don't think so because the inherent 3 tier architecture of CDO has different characteristics and requirements.

Cheers
/Eike

----
http://www.esc-net.de
http://thegordian.blogspot.com
http://twitter.com/eikestepper
Re: [CDO] CDO and transaction isolation levels [message #982965 is a reply to message #982503] Tue, 13 November 2012 10:19 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre Martins
Messages: 41
Registered: July 2009
Member
Hi,
see my comments below.
And sorry for the amount of comments and different issues addressed, but I think they are all closely related Smile

Thanks.
Silvestre



...
> And if we wanted to have a Serializable behavior, which means, full isolated transactions, how could we achieve it?
The simplest way would be to switch the repository itself to a mode that really serializes all commits:
IRepository.Props.SERIALIZE_COMMITS (new in 4.2).

From what I read (and a quick test I made) this seems to make a "global" write-lock. I don't think this fits the purpose because in this case is simpler to not allow concurrency at all at the application level (at least for transactions that makes changes on the model). The "Serializability" property of a transaction means that the result of 2 concurrent transactions is the same as they were executed in a serial order. Basically, if we still want to allow concurrency here, this can be achieved by locking all reads and writes and only release locks at the end of transaction. In an optimistic lock approach we can defer all locks to the moment of commit, as I wrote below.



> One way, with a full optimistic lock approach, could be to store (locally) all the objects read from the database by CDO
If heap space is not an issue it would probably be enough that you keep strong references to the CDORevisions in the
revision manager cache of your CDOSession.

Here when I say "locally", I actually mean "on the transaction context". If what you say is more efficient, yes. I just suggested to store the objects because the API that I know is receiving a collection of CDOObject:
CDOView.lockObjects(Collection<? extends CDOObject> objects, LockType lockType, ...)



> and when committing, make a read-lock on all those objects.
Why? The repository will acquire write locks for all changed and containing objects (in that branch) anyway, and if
IRepository.Props.ENSURE_REFERENTIAL_INTEGRITY=true also for all objects whose set of referecing objects will change by
this commit.

I don't think the property ENSURE_REFERENTIAL_INTEGRITY=true solves this problem. I'm talking about making read-locks, not write-locks, which means, have a guarantee that we only allow to commit if all objects read (used) during the transaction were not modified since the transaction started.

I will give a simple example, without making any explicit lock (very academic example, please ignore the fact that it makes sense or not from the business point of view Smile ):

T1:
float totalMoney = getTotalMoney(); //access the DB to retrieve it

T2:
float totalMoney = getTotalMoney(); //access the DB to retrieve it
totalMoney -= 100; //decrease 100 on the total
setTotalMoney(totalMoney); //save on the model
commit(); //commit it to the DB

T1:
float taxRate = getTaxRate(totalMoney); //tax rate to apply depends on the total of money
float calculatedTax = totalMoney * taxRate;
setTax(calculatedTax); //save on the model
commit(); //commit it to the DB

If we don't use explicit locks, this might lead to an inconsistent state (from the business point of view) because we maybe be using an outdated value in some calculation where then the result is persisted.

We can bypass this by making explicit locks, but then we start adopting a pessimistic lock. For a new application this may not be so critical because you can decide to go that way and you rely this on the application development, but for an existing application, this would require more effort (and risk) to identify all cases where locks are required.
And if locks are blocking, then you could even have the problem of dead-locks (My guess is that CDO uses non-blocking locks, so if object is already locked, operation is aborted. Am I right?).


...

Cheers
/Eike

----
http://www.esc-net.de
http://thegordian.blogspot.com
http://twitter.com/eikestepper

[Updated on: Tue, 13 November 2012 10:24]

Report message to a moderator

Re: [CDO] CDO and transaction isolation levels [message #985165 is a reply to message #982965] Thu, 15 November 2012 02:44 Go to previous messageGo to next message
Eike Stepper is currently offline Eike Stepper
Messages: 5501
Registered: July 2009
Senior Member
Am 13.11.2012 16:19, schrieb Silvestre Martins:
> Hi,
> see my comments below.
> And sorry for the amount of comments and different issues addressed, but I think they are all closely related :)
>
> Thanks.
> Silvestre
>
>> And if we wanted to have a Serializable behavior, which means, full isolated transactions, how could we achieve it?
> The simplest way would be to switch the repository itself to a mode that really serializes all commits:
> IRepository.Props.SERIALIZE_COMMITS (new in 4.2).
>
> From what I read (and a quick test I made) this seems to make a "global" write-lock. I don't think this fits the
> purpose because in this case is simpler to not allow concurrency at all at the application level (at least for
> transactions that makes changes on the model).
Not sure how you could do that in a distributed system or why that should be simpler.

> The "Serializability" property of a transaction means that the result of 2 concurrent transactions is the same as they
> were executed in a serial order. Basically, if we still want to allow concurrency here, this can be achieved by
> locking all reads and writes and only release locks at the end of transaction.
Yes. In CDO the writes can be locked in a way transparent to the application (see CDOTransactionHandlerXYZ. For
performance reasons this is not possible for reads, though. That must be done explicitely in the application.

> In an optimistic lock approach we can defer all locks to the moment of commit, as I wrote below.
Currently the application has no means to intercept the"read event" CDO does not record what exactly the application is
reading.

>
>> One way, with a full optimistic lock approach, could be to store (locally) all the objects read from the database by CDO
> If heap space is not an issue it would probably be enough that you keep strong references to the CDORevisions in the
> revision manager cache of your CDOSession.
>
> Here when I say "locally", I actually mean "on the transaction context". If what you say is more efficient, yes. I
> just suggested to store the objects because the API that I know is receiving a collection of CDOObject:
> CDOView.lockObjects(Collection<? extends CDOObject> objects, LockType lockType, ...)
>
>
>
>> and when committing, make a read-lock on all those objects.
> Why? The repository will acquire write locks for all changed and containing objects (in that branch) anyway, and if
> IRepository.Props.ENSURE_REFERENTIAL_INTEGRITY=true also for all objects whose set of referecing objects will change
> by this commit.
>
> I don't think the property ENSURE_REFERENTIAL_INTEGRITY=true solves this problem. I'm talking about making read-locks,
> not write-locks, which means, have a guarantee that we only allow to commit if all objects read (used) during the
> transaction were not modified since the transaction started.
>
> I will give a simple example, without making any explicit lock (very academic example, please ignore the fact that it
> makes sense or not from the business point of view :) ):
>
> T1:
> float totalMoney = getTotalMoney(); //access the DB to retrieve it
>
> T2:
> float totalMoney = getTotalMoney(); //access the DB to retrieve it
> totalMoney -= 100; //decrease 100 on the total
> setTotalMoney(totalMoney); //save on the model
> commit(); //commit it to the DB
>
> T1:
> float taxRate = getTaxRate(totalMoney); //tax rate to apply depends on the total of money
> float calculatedTax = totalMoney * taxRate;
> setTax(calculatedTax); //save on the model
> setTotalMoney(totalMoney - calculatedTax); //save on the model
> commit(); //commit it to the DB
>
> If we don't use explicit locks, this might lead to an inconsistent state (from the business point of view) because we
> maybe be using an outdated value in some calculation where then the result is persisted.
>
> We can bypass this by making explicit locks, but then we start adopting a pessimistic lock. For a new application this
> may not be so critical because you can decide to go that way and you rely this on the application development, but for
> an existing application, this would require more effort (and risk) to identify all cases where locks are required. And
> if locks are blocking, then you could even have the problem of dead-locks (My guess is that CDO uses non-blocking
> locks, so if object is already locked, operation is aborted. Am I right?).
Yes, after the timeout period that you specify in the lock() call.

Cheers
/Eike

----
http://www.esc-net.de
http://thegordian.blogspot.com
http://twitter.com/eikestepper
Re: [CDO] CDO and transaction isolation levels [message #985338 is a reply to message #981989] Thu, 15 November 2012 05:17 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre Martins
Messages: 41
Registered: July 2009
Member
Ok, so basically, what we can conclude is that the best way to achieve Serializability with concurrency is to not adopt a "full" optimistic lock approach but make the changes on the code of application level to make a lock in all "relevant" reads for our use-case (as they are done in a non-blocking way, we won't have the problem of deadlocks).
I was trying to find out how we could achieve the Serializability without changing the existing code to add locks everywhere.

Thank you for all the explanations.

Cheers,
Silvestre
Re: [CDO] CDO and transaction isolation levels [message #985479 is a reply to message #985338] Thu, 15 November 2012 07:27 Go to previous message
Eike Stepper is currently offline Eike Stepper
Messages: 5501
Registered: July 2009
Senior Member
Am 15.11.2012 11:17, schrieb Silvestre Martins:
> Ok, so basically, what we can conclude is that the best way to achieve Serializability with concurrency is to not
> adopt a "full" optimistic lock approach but make the changes on the code of application level to make a lock in all
> "relevant" reads for our use-case (as they are done in a non-blocking way, we won't have the problem of deadlocks).
Yes.

Though I could try to find an efficient way to provide read notifications similar to our write access hooks. The funding
of such an effort would have to be clarified ahead of time, though. If that's something you're interested in I'd suggest
that you contact me privately.

> I was trying to find out how we could achieve the Serializability without changing the existing code to add locks
> everywhere.
>
> Thank you for all the explanations.
You're welcome ;-)

Cheers
/Eike

----
http://www.esc-net.de
http://thegordian.blogspot.com
http://twitter.com/eikestepper
Previous Topic:[CDO] CDOAdmin - NullPointerException on Server side using TCP connector
Next Topic:Pretty Print
Goto Forum:
  


Current Time: Wed Aug 27 17:14:02 EDT 2014

Powered by FUDForum. Page generated in 0.02918 seconds