[infinispan-dev] Atomic operations and transactions

Mircea Markus mircea.markus at jboss.com
Fri Jul 8 11:45:48 EDT 2011


On 5 Jul 2011, at 14:04, Sanne Grinovero wrote:

> 2011/7/5 Dan Berindei <dan.berindei at gmail.com>:
>> On Tue, Jul 5, 2011 at 1:39 PM, Sanne Grinovero <sanne at infinispan.org> wrote:
>>> 2011/7/5 Dan Berindei <dan.berindei at gmail.com>:
>>>> Here is a contrived example:
>>>> 
>>>> 1. Start tx Tx1
>>>> 2. cache.get("k") -> "v0"
>>>> 3. cache.replace("k", "v0", "v1")
>>>> 4. gache.get("k") -> ??
>>>> 
>>>> With repeatable read and suspend/resume around atomic operations, I
>>>> believe operation 4 would return "v0", and that would be very
>>>> surprising for a new user.
>>>> So I'd rather require explicit suspend/resume calls to make sure
>>>> anyone who uses atomic operations in a transaction understands what
>>>> results he's going to get.
>>> 
>>> The problem is that as a use case it makes no sense to use an atomic
>>> operation without evaluating the return value.
>>> so 3) should actually read like
>>> 
>>> 3. boolean done = cache.replace("k", "v0", "v1")
>>> and based on this value, the application would branch in some way, and
>>> so acquiring locks and waiting for each other is not enough, we can
>>> only support this if write skew checks are enabled, and mandate the
>>> full operation to rollback in the end. That might be one option, but I
>>> really don't like to make it likely to rollback transactions, I'd
>>> prefer to have an alternative like a new flag which enforces a "fresh
>>> read" skipping the repeatable read guarantees. Of course this wouldn't
>>> work if we're not actually sending the operations to the key owners,
>>> so suspending the transaction is a much nicer approach from the user
>>> perspective. Though I agree this behaviour should be selectable.
>>> 
>> 
>> Ok, I'm slowly remembering your arguments... do you think the "fresh
>> read" flag should be available for all operations, or does it make
>> sense to make it an internal flag that only the atomic operations will
>> use?
>> 
>> To summarize, with this example:
>> 1. Start tx
>> 2. cache.get("k") -> "v0"
>> 3. cache.replace("k", "v0", "v1")
>> 4. gache.get("k") -> ??
>> 5. Commit tx
>> 
>> The options we could support are:
>> a. Tx suspend: no retries, but also no rollback for replace() and 4)
>> will not see the updated value
> 
> might work, but looks like a crazy user experience.
> 
>> b. Optimistic locking + write skew check: if the key is modified by
>> another tx between 2) and 5), the entire transaction has to be redone
> 
> might work as well, since people opted in for "optimistic" they should
> be prepared to experience failures.
> I'm not sure what the "+" stands for, how can you have optimistic
> locking without write skew checks?
writeSkewCheck can be disabled
> 
>> c. Optimistic locking + write skew check + fresh read: we only have to
>> redo the tx if the key is modified by another tx between 3) and 5)
> 
> in this case we're breaking the repeatable read guarantees, so we
> should clarify this very well.
+1, this complicates things.
> 
>> d. Pessimistic locking: if the key is modified between 2) and 5), the
>> entire transaction has to be redone
in this case a lock will be acquired at 3, so it would be impossible for another tx to modify between 3-5.
> 
> I don't understand what's pessimistic about this? To be pessimistic it
> would attempt to guarantee success by locking at 2): during the get
> operation, before returning the value.
> Also "if they key is modified" implies write skew checks, so how would
> this be different than previous proposals?
> Generally as a user if I'm opting in for a pessimistic lock the only
> exception I'm prepared to handle is a timeout, definitely not a "try
> again, the values changed".
> 
>> e. Pessimistic locking + fresh read: no redo, but decreased throughput
>> because we hold the lock between 3) and 5)
> 
> I assume you really mean to do explicit pessimistic locking:
> 1. Start tx
> 2. cache.lock("k");
> 3. cache.get("k") -> "v0"
> 4. cache.replace("k", "v0", "v1") /// -> throw an exception if we're
> not owning the lock
> 5. gache.get("k") -> ??
> 6. Commit tx
> 
>> I guess there is no reason to support option d), as we're making an
>> RPC to the owner in order to get the lock anyway. I think I'm leaning
>> towards supporting only a) and e), but there might be cases where b)
>> and c) would perform better.
>> 
>> Dan
>> _______________________________________________
>> infinispan-dev mailing list
>> infinispan-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/infinispan-dev
>> 
> _______________________________________________
> infinispan-dev mailing list
> infinispan-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/infinispan-dev




More information about the infinispan-dev mailing list