rel
rel copied to clipboard
Optimistic Locking
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 intfield. - [ ] Use
LockVersionfield 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.
There are at least two common approaches to optimistic locking I know:
- using a
where version = ?clause - using a
returning versionand 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.
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())
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?
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