> Pessimistic locking, the way you want to use it, decreases performance 
because all reads have
to wait until the lock is gone. For the web this is realy a bad thing. 
Futhor more the chance of a deadlock
is every time ahead of you.

Reads should not be locked by a FOR UPDATE lock 
(http://www.postgresql.org/docs/9.4/static/explicit-locking.html#LOCKING-ROWS). 
I agree potential dead-locks are a problem if you have slightly complicated 
hierarchies in your transactions. 

> And worst of all, such a pessimistic lock can take a undetermined amount 
of time.
During a Request this can lead to timeouts on client site. Handle client 
timeouts 
can be a nightmare too.

That's only undermined if there is an open transaction which holds that 
lock for an undetermined time right? Heroku for examples gives only 30 
seconds to a db connection but generally you would have to monitor the 
locks. 

> In this case I would still use optimistic locking. You can simply call 
.touch on the associated object (in both transaction), so the lock_version
is increased.

So if I understand correctly your over-all suggestion is to .touch all 
Objects involved in validations which otherwise would not have been written 
to in the current transaction. Although it seems touch updates the 
updated_at column (this can be worked-around I suppose). One concern here 
is if there are a number of validations each one has to remember to .touch 
on the object - and if the same object is used in multiple validations that 
will touch multiple times in one transaction. 

On Friday, January 8, 2016 at 7:13:47 PM UTC+8, Dieter wrote:
>
> In this case I would still use optimistic locking. You can simply call 
> .touch on the associated object (in both transaction), so the lock_version
> is increased.
>
> Pessimistic locking, the way you want to use it, decreases performance 
> because all reads have
> to wait until the lock is gone. For the web this is realy a bad thing. 
> Futhor more the chance of a deadlock
> is every time ahead of you.
>
> And worst of all, such a pessimistic lock can take a undetermined amount 
> of time.
> During a Request this can lead to timeouts on client site. Handle client 
> timeouts 
> can be a nightmare too.
>
> But that's only my opinion.
>
> Am Freitag, 8. Januar 2016 11:29:29 UTC+1 schrieb [email protected]:
>>
>> Sorry, yes you are correct that was a poor example and for that 
>> particular condition optimistic locking will validate correctly. On the 
>> other-hand conditions which use data from a reference but do not update 
>> that reference will still be able to race .e.g. 
>>
>> A fulfillment has fulfillment_line_item's which check that 
>> fulfillment.status != 'shipped' to validate a destroy on a 
>> fulfillment_line_item. This later case will validate on the stale 
>> fulfillment.status - but since only the fulfillment_line_item (not the 
>> fulfillment) is to be updated in such a transaction no error will be noted 
>> even if fulfillment.lock_version has changed (since no update to the parent 
>> would have been attempted). 
>>
>>
>> On Wednesday, January 6, 2016 at 4:27:46 PM UTC+8, Dieter wrote:
>>>
>>> You problem hast nothing todo with multiple dynos. This race condition 
>>> can occour as soon as you have multiple workers or threats (whatever your 
>>> server uses). But
>>> its a normal issue and in my point of view you can handle it with 
>>> optimistic locking just fine.
>>>
>>> When you use optimistic locking rails prepends on every update und 
>>> delete (when you use object.destroy) a "AND locking_version=?", 
>>> object.locking_version.
>>>
>>> In your case when your #update transaction happens it's gets for 
>>> instance lock_version 1 and also your #delete transaction gets lock_version 
>>> 1.
>>>
>>> Say the #delete transaction is faster so you will get an 
>>> ActiveRecord::StaleObjectError within you #update action or vice versa.
>>>
>>> You only have to handle the ActiveRecord::StaleObjectError. Without 
>>> handling this error the transaction will be rolledback (the slower one)
>>>
>>> But this is only true as long as you use a Isolation level which does 
>>> not read UNCOMMITTED data.
>>>
>>> This should be the default in most cases.
>>>
>>> You can test it this way (as long as you dont use rails identy map).
>>>
>>> # use same id for find
>>> fulfillment1 = Fulfillment.find 1
>>> fulfillment2 = Fulfillment.find 1 
>>>
>>> fulfillment1.status = '...'
>>>
>>> fulfillment2.status = '...'
>>>
>>>
>>>
>>> fulfillment1.save!
>>>
>>> fulfillment2.save! # should raise an exception, take a look at the 
>>> generated SQL-Statement
>>>
>>> regards 
>>> dieter
>>>
>>

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/rubyonrails-core.
For more options, visit https://groups.google.com/d/optout.

Reply via email to