rel icon indicating copy to clipboard operation
rel copied to clipboard

Optimistic Locking

Open Fs02 opened this issue 5 years ago • 4 comments

Background

Optimistic locking (or optimistic concurrency control) is a technique that allows concurrent edits on a single record (more: https://hexdocs.pm/ecto/0.9.0/Ecto.Model.OptimisticLock.html)

Implementation

  • [ ] Detect Optimistic Locking enabled when a struct contains a LockVersion int field.
  • [ ] Use LockVersion field whenever Update or Delete is performed to prevent operation on stale version of record. Maybe we can simply add additional where filter LockVersion=? on update or delete query.
  • [ ] Differentiate error when updating/deleting stale record for non existent record.

Fs02 avatar Sep 18 '20 17:09 Fs02

There are at least two common approaches to optimistic locking I know:

  • using a where version = ? clause
  • using a returning version and checking versions in code (this works only in transactions, as we have to abort without changes)

The first approach is more flexible (can be used in any context), however it doesn't allow us to differentiate between errors for stale and nonexistent records. Is this that big of an issue? If we already have a record with a version, we know it existed (at least in the past). The user would have to get more info about the confict manually on abortion (like querying record with version again)

What about turning locking off? Should it require special functions for saving/deleting? Given, that embedded structs can be supported, enabling/disabling could be done with wrapper types.

dranikpg avatar Feb 09 '22 18:02 dranikpg

The first approach is more flexible (can be used in any context), however it doesn't allow us to differentiate between errors for stale and nonexistent records. Is this that big of an issue? If we already have a record with a version, we know it existed (at least in the past). The user would have to get more info about the confict manually on abortion (like querying record with version again)

yes I agree, the size of issue is depends, but I think it's not possible to differentiate stale and nonexistent records, I think we just need to state this explicitly in the documentation

What about turning locking off?

if user want to update/delete while ignoring lock, user should be able to use rel.Unscoped() example: repo.Update(ctx, &book, rel.Unscoped()) / repo.Delete(ctx, &book, rel.Unscoped())

Fs02 avatar Feb 10 '22 09:02 Fs02

Having repo.Delete(ctx, &model, rel.Unscoped()) is not possible with the current signature, which accepts only a bool vararg for cascades. It it possible to change Delete() to accept mutates or must strong backward compatibility be maintained?

dranikpg avatar Feb 17 '22 16:02 dranikpg

It it possible to change Delete() to accept mutates or must strong backward compatibility be maintained?

It's okay, this shouldn't break the compilation, and REL is still in unstable version (0.x.x) is due to this possible API change

Fs02 avatar Feb 18 '22 00:02 Fs02