domingo, 10 de marzo de 2013

Django: Optimistic Locking

At the Córdoba (Argentina) Sprint, on February 23rd, we achieved to implement the minimum necessary code to have a working prototype of Optimistic Locking.

Why is needed?

To avoid the loss of information when 2 users update the same object, or even when one user has the same object open in multiples browsers or tabs (database locks nor 'select for update' help here).

Ej: the object with version 'N' is in the DB; the object is shown in the browser by two users (let sey user A and user B). The user A modifies it and save it in the database. The user B modifies the same object, and save it. The changes entered by user A are silently lost, and neither user A nor user B acknowledges the situation.

How it works

It works the same way as in Hibernate. The instance has a version field, which is sent to the user as a hidden field. Instead of using a simple SQL "UPDATE ...", we use "UPDATE ... WHERE VERSION = YYY", and check how many rows where updated. If no row was updated, it means the version has changed and we report this as an optimistic locking error.

Ej: the current implementation raises an OptimisticLockingError when user B tries to save the changes. The developer has to catch this exception and make whatever he or she wants. 

Alternatives to Optimistic Locking

  • maybe versioning of attributes (ej: instead of having a "descripcion" field, have a set of "descriptions" and a "current description" foreign key)

TODO

  1. remove requeriment of hard-coded 'version' field, and instead look for any field of type VersionField,
  2. decide and implement how to manage deletes,
  3. evaluate alternatives how to enable optimistic locking on models (see 'Alternatives for enabling O.L. on a model'),
  4. implement graceful handling of optimistic locking errors in admin,
  5. see how this relates the adoption of NOSQL support or other related topics, 

Alternatives for enabling O.L. on a model

We want to make optimistic locking totally optional and easy to use for existing models and forms. We explored different alternatives to 'mark' that we want optimistic locking semantics for a specific model. Also, we want to avoid introducing new mechanisms. The alternatives were:



1. Add a VersionField to models
This is how it's implemented right now: you add a VersionField to your model. The associated form field uses a HiddenInput widget, so ModelForms don't have to be modified to support optimistic locking, since the version is automatically sent to the browser as a hidden field.

PRO: is explicit (you see a new field being added)
CON: models should have only one VersionField, and the field is kind of magic: if it exists, the model has optimistic locking semantics. There is no comparable mechanism in Django (maybe could be comparable to AutoField?).

--- Example ---
----------


2. Use a Meta option
Allow the user set a Meta option, like 'optimistic_locking = True'.

PRO: it very clean
CON: hides the fact that a new field is added. There is no comparable mechanism in Django (a meta option that adds a field)

--- Example ---
----------


Git


References

Optimistic Locking

Related Django tickets


Authors

  • Ramiro Morales <cramm0@gmail.com>
  • Francisco Capdevila <fjcapdevila@gmail.com>
  • Carlos Ilcobich <cilcobich@gmail.com>
  • Fernando Flores <fef.flores@gmail.com>
  • Matías Bordese <mbordese@gmail.com>
  • Martín Gaitan <gaitan@gmail.com>
  • Horacio G. de Oro <hgdeoro@gmail.com>