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>

miércoles, 9 de enero de 2013

Compilando Gimp 2.8 en Ubuntu 12.04

Antes que nada, esto lo hice sobre un Ubuntu 12.04... aunque ya hay una versión más nueva de Ubuntu, todavía no tuve tiempo de actualizarlo, por eso este artículo...

Las instrucciones las tomé desde http://ubuntuforums.org/showthread.php?t=1974512, pero con algunas modificaciones en el procedimiento.

Para empezar, es importante tener instalados los paquetes indicados en la página. Antes de encontrar dicha página intenté compilar Gimp, y me surgieron varios errores, pero en ningún momento los mensajes de error hacían referencia a problemas con dependencias de librerías.

La idea es compilar Gimp para instalar en /opt/gimp-2.8. Como Gimp depende de babl y gegl, antes hace falta compilar e instalar dichas librerías. Yo acostumbro buscar la forma de instalar todo el /opt y sin usar root, para garantizar que no se pise ni modifique las librerías y ejecutables instalados por Ubuntu y así no afectar el funcionamiento de nuestro Linux.

Los pasos son:

1. creamos /opt/gimp-2.8 (necesitaremos sudo), y le asignaremos como dueño nustro usuario "no-root". Estos son los únicos pasos en los que usaremos sudo:


$ sudo mkdir /opt/gimp-2.8
$ sudo chown horacio /opt/gimp-2.8

2. compilamos babl (suponemos que los fuentes están en /tmp/babl):


$ cd /tmp/babl
$ ./configure --prefix=/opt/gimp-2.8
$ make
$ make install

3. compilamos gegl (suponemos que los fuentes están en /tmp/gegl):

$ cd /tmp/gegl
$ PKG_CONFIG_PATH=/opt/gimp-2.8/lib/pkgconfig ./autogen.sh
$ PKG_CONFIG_PATH=/opt/gimp-2.8/lib/pkgconfig ./configure --prefix=/opt/gimp-2.8
$ make
$ make install

4. compilamos gimp (suponemos que los fuentes están en /tmp/gimp):

$ cd /tmp/gimp
$ PKG_CONFIG_PATH=/opt/gimp-2.8/lib/pkgconfig ./autogen.sh
$ PKG_CONFIG_PATH=/opt/gimp-2.8/lib/pkgconfig ./configure --prefix=/opt/gimp-2.8
$ make
$ make install


Ahora ya podemos ejecutar Gimp:

$ /opt/gimp-2.8/bin/gimp-2.8

Además compilé ufraw (para importar imágenes RAW). Pero esto me trajo muchos problemas: aunque compilaba y se instalaba correctamente, me daba errores al momento de abrir archivos RAW. El problema fue que el plugin de ufraw para Gimp fue compilado y linkeado contra la librería de gimpui de Ubuntu (en vez de la versión de /opt/gimp-2.8).

Antes que nada, hará falta instalar algunos paquetes:

$ sudo apt-get install liblensfun-dev libgtkimageview-dev

Los pasos para compilar e instalar ufraw son similares:


$ cd ufraw-0.18/
$ PKG_CONFIG_PATH=/opt/gimp-2.8/lib/pkgconfig ./autogen.sh --prefix=/opt/gimp-2.8
$ PKG_CONFIG_PATH=/opt/gimp-2.8/lib/pkgconfig ./configure --prefix=/opt/gimp-2.8
$ make
$ make install

y para que funcione, hace falta setear LD_LIBRARY_PATH:

$ export LD_LIBRARY_PATH=/opt/gimp-2.8/lib
$ /opt/gimp-2.8/bin/gimp-2.8