Migración de una base de datos LMDB a otra plataforma

LMDB es una base de datos ACID ligera y de alto rendimiento, especialmente recomendable para entornos con pocas escrituras y poca concurrencia de escritura. Dado el cambio de licencia de la extraordinaria Berkeley DB a partir de su versión 6.0, estoy usando LMDB cuando no necesito utilizar las sobresalientes características de Berkeley DB. Cuando necesito tirar de las funcionalidades de Berkeley DB, pero el proyecto no puede utilizar la licencia AGPL3, utilizo la última versión con una licencia utilizable en la práctica, la 5.3.

Una buena parte del rendimiento de LMDB proviene de mapear la base de datos directamente en memoria. Una consecuencia de eso y del uso de punteros y estructuras nativas es que la base de datos no es portable. Cambios de arquitectura entre 32 y 64 bits o de endianness hacen que la base de datos resulte ilegible.

Si nos enfrentamos a un cambio de ese tipo, es necesario realizar un proceso de migración. No obstante, utilizar mdb_dump y mdb_load no es trivial. El problema es la gestión de sub-bases de datos ya que LMDB las implementa como registros especiales en la tabla principal.

Nota

LMDB es un proyecto joven y en rápida evolución. Es posible que la información contenida en este artículo haya quedado desfasada cuando lo estés leyendo.

Nota

Si durante la recuperación de la base de datos LMDB nos salen avisos del estilo de mdb_load: line 6: unrecognized keyword ignored: db_pagesize, podemos ignorarlos. El campo db_pagesize es documentación de la base de datos LMDB de origen y la base de datos LMDB de destino utilizará el tamaño de bloque nativo del sistema operativo local.

Base de datos sin sub-bases de datos

Si todos los datos se almacenan en la tabla principal, el proceso es muy sencillo:

  • Volcar los datos: (máquina origen)

    $ mdb_dump PATH_DB > volcado
    
  • Recuperar los datos: (máquina destino)

    $ mdb_load PATH_DB < volcado
    

Base de datos con toda su información en sub-bases de datos

En este caso tenemos que indicarle a LMDB que queremos volcar todas las sub-bases de datos:

  • Volcar los datos: (máquina origen)

    $ mdb_dump -a PATH_DB > volcado
    
  • Recuperar los datos: (máquina destino)

    $ mdb_load PATH_DB < volcado
    

Base de datos con información repartida entre la base de datos principal y sub-bases de datos

Nota

Este es el caso general y se puede utilizar siempre, aunque no conozcamos el formato interno de la base de datos.

Aquí debemos volcar tanto la tabla principal como las sub-bases de datos y cargarlas de forma apropiada.

  • Volcar los datos: (máquina origen)

    $ mdb_dump -a PATH_DB > volcado_subDBs
    $ mdb_dump PATH_DB > volcado_main
    

    El primer comando vuelca las sub-bases de datos y el segundo comando vuelca la tabla principal.

  • Recuperar los datos: (máquina destino)

    $ mdb_load PATH_DB < volcado_subDBs
    $ mdb_load -N PATH_DB < volcado_main
    

    El primer comando recupera las sub-bases de datos. Esto crea sus entradas correspondientes en la tabla principal ya que, como hemos dicho más arriba, LMDB implementa las sub-bases de datos como registros especiales en dicha tabla.

    El segundo comando recupera los datos de la tabla principal, pero el parámetro adicional -N hace que la recuperación no sobreescriba los valores ya existentes en ella. En concreto, no sobreescribirá las claves correspondientes a las sub-bases de datos. Los registros nuevos de la tabla principal, que son todos los demás que no corresponden a identificadores de sub-bases de datos, se cargarán sin problemas.

    En mi opinión, tener que preocuparse de estos detalles es un bug de LMDB. El parámetro -a de mdb_dump debería volcar toda la información de la base de datos, incluyendo la tabla principal, y no solo las sub-bases de datos. Espero que los autores de LMDB lo tengan en cuenta para futuras versiones de las herramientas.

    Advertencia

    A la hora de ejecutar la recuperación con estos comandos es necesario que la base de datos no exista. En caso contrario perderíamos las actualizaciones de datos preexistentes en la tabla principal.