Haciendo un MongoDB con transacciones

March 26th, 2014 No comments

Llevo unos cuantos meses trabajando con MongoDB, una base de datos NoSQL basada en documentos estilo JSON. Es muy potente y muy sencilla de usar.

Lo que más me gusto desde el primer momento fue la no necesidad de definir el esquema de las tablas de antemano. Al estar basada en documentos, es posible ir creando la estructura de la base de datos a medida que crece la aplicación, lo cuál te da mucha agilidad y libertad en el proceso de desarrollo de un proyecto. También implica un riesgo, uno ha de tener las ideas muy claras y no ir implementando a lo loco, pero vaya, que ya somos mayorcitos y se supone que sabemos lo que hacemos. :-)

transaction

Pero para una aplicación con cierto nivel de complejidad hay una cosa que echo en falta: las transacciones. MongoDB está pensada principalmente para aplicaciones que necesitan lecturas y escrituras rápidas y proporciona sistemas sencillos para montar replicas y sharding que facilitan la escalabilidad de los sistemas. Vamos, que es ideal para la web. Pero si queremos aplicaciones que ejecuten procesos largos con mucha actividad en la base de datos, tener transacciones te garantiza mantener la integridad.

Existen algunos ejemplos de “transacciones” a pequeño nivel, pero son muy artesanales y no ayudan demasiado si los errores que se producen son a nivel de hardware (cortes de conexión, caída de servidores, etc). Así que se me ocurrió que quizá lo más fácil era diseñar un sistema similar a MongoDB pero que funcionara sobre una base de datos relacional con transacciones como MariaDB o PostgreSQL.

Este nuevo sistema se llama Mojo.

Tipo de datos

Las bases de datos relacionales usan unos tipos de datos que podríamos definir como estándar (char, integer, float, datetime, blob, etc). Sin embargo, MongoDB permite guardar y realizar búsquedas sobre tipos más complejos, como listas y diccionarios, por lo que para poder dar soporte a estos tipos es necesario usar un serializador. Al principio usé Pickle, pero como solamente sirve para Python pasé a usar msgpack. Ahora mismo es el serializador por defecto, pero es posible especificar el que uno quiera en el momento de realizar la conexión.

Estructura de las tablas

Para guardar documentos en una base de datos relacional necesitaremos, como mínimo, tablas con la siguiente estructura: id(varchar), name(varchar) y value(text). De esta forma, si queremos guardar el documento {“a”: 1, “b”: [1, 2]} en la colección pruebas, en la base de datos quedaría:

Table “pruebas”
Id Name Value
‘abc’ ‘a’ ‘1’
‘abc’ ‘b’ ‘[1, 2]’

El primer defecto que me encontré con este esquema es que no es posible hacer búsquedas numéricas, ya que los valores se guardan serializados, por lo que es necesario guardar el valor numérico en una nueva columna.

Table “pruebas”
Id Name Value Number
‘abc’ ‘a’ ‘1’ 1
‘abc’ ‘b’ ‘[1, 2]’ NULL

El siguiente problema que nos encontramos es la imposibilidad de indexar por campo. Al estar todos los campos del documento en el mismo campo de la base de datos, sean del tipo que sean, se hace imposible crear índices que sean eficaces. Creo que existen algunos motores que permiten índices condicionales pero no es lo normal, por lo que la única solución que se me ocurre es separar los campos del documento entre varias tablas, una por campo. Por lo que el documento de prueba ahora se guardaría así:

Table “pruebas$_id”
Id Name Value Number
‘abc’ ‘_id’ ‘abc’ NULL
Table “pruebas$a”
Id Name Value Number
‘abc’ ‘a’ ‘1’ 1
Table “pruebas$b”
Id Name Value Number
‘abc’ ‘b’ ‘[1, 2]’ NULL

Con este esquema queda todo bastante atado, pero algunas funcionalidades extra de MongoDB no quedan resueltas, y es que MongoDB permite buscar dentro de listas y diccionarios de forma totalmente transparente. Por ejemplo, si buscamos {“b”: 1} la base de datos debería devolvernos el documento, ya que dentro de la lista [1, 2] se encuentra el número 1.

Para poder realizar estas búsquedas será necesario replicar algunos de los datos, de forma que el campo “b” del documento quedaría guardado de la forma:

Table “pruebas$b”
Id Name Value Number
‘abc’ ‘b’ ‘[1, 2]’ NULL
‘abc’ ‘b..0′ ‘1’ 1
‘abc’ ‘b..1′ ‘2’ 2

Con este último esquema, si guardamos un nuevo documento {“b”: {“x”: 100, “y”: 200}}, la base de datos quedaría de la forma:

Table “pruebas$_id”
Id Name Value Number
‘abc’ ‘_id’ ‘abc’ NULL
‘def’ ‘_id’ ‘def’ NULL
Table “pruebas$a”
Id Name Value Number
‘abc’ ‘a’ ‘1’ 1
Table “pruebas$b”
Id Name Value Number
‘abc’ ‘b’ ‘[1, 2]’ NULL
‘abc’ ‘b..0′ ‘1’ 1
‘abc’ ‘b..1′ ‘2’ 2
‘def’ ‘b’ ‘{“x”: 100, “y”: 200″}’ NULL
‘def’ ‘b.x’ ‘100’ 100
‘def’ ‘b.y’ ‘200’ 200

Final

De momento estoy usando este esquema para la implementación de Mojo. El objetivo es replicar lo máximo posible la funcionalidad de MongoDB pero usando motores de bases de datos “tradicionales”.

El código se encuentra disponible en el repositorio de Mojo y todas las ideas y aportaciones son bienvenidas.

Categories: Uncategorized Tags: ,

pyrabbit, experimentando con RabbitMQ

October 31st, 2013 No comments

RabbitMQ

Llevo ya un tiempo probando RabbitMQ, un sistema de mensajería para aplicaciones basado en colas, muy potente y escalable, desarrollado con Erlang. Para saber un poco más de este lenguaje de programación recomiendo leer Learn You Some Erlang for Great Good! Cuando conoces un poco este lenguaje comprendes por qué lo han usado para programar RabbitMQ, ya que da la impresión de que Erlang fue diseñado expresamente para crear este tipo de sistemas.

Hay una cosa que no me ha gustado demasiado de RabbitMQ, y es que es el propio sistema de mensajería el que decide para quién es un determinado mensaje. Me explico. Supongamos que tenemos una cola que recibe mensajes con trabajos a realizar y tenemos dos procesos suscritos a la cola para realizar esos trabajos. Para ello, los procesos se suscriben a la cola y es RabbitMQ el que manda los mensajes al proceso que crea conveniente. Si el proceso que recibe el mensaje no puede atenderlo en ese momento, por las razones que sean, debe cancelar la recepción para que RabbitMQ pueda reencolar el mensaje y otro proceso pueda recibirlo.

Para este tipo de cosas yo prefiero usar peticiones tipo “long polling” con posibilidad de especificar un timeout, de forma que sea el propio proceso el que pida mensajes al servidor. Por supuesto, igual puede ocurrir que el proceso pierda la conexión, no pueda atender al mensaje, etc, con lo que también deberíamos cancelar la recepción para el reencolado del mensaje, pero ya resulta más extraño, y el código de los procesos resulta más legible.

He desarrollado una pequeña librería en Python, pyrabbit, que por debajo usa Pika, una implementación del protocolo AMPQ que nos sirve para conectar con RabbitMQ y comunicarnos con las colas. Con pyrabbit es posible realizar estas operaciones de forma muy sencilla.

import pyrabbit
connection = pyrabbit.Connection('localhost')

# Enviar mensaje a mi_cola y leerlo después con un timeout de diez segundos
connection.mi_cola.send("hola")
m = connection.mi_cola.receive(timeout=10)
print m.body   # Esto imprime 'hola'

# Confirmamos que el mensaje ha sido procesado y no es necesario reencolarlo
m.ack()

# Tambien es posible enviar mensajes y esperar confirmación con un timeout
# Supongamos que tenemos un proceso que calcula sumas
r = connection.cola_de_sumas.send("[2,3]", wait_response=True, timeout=5)
print r.body   # Si el proceso ficticio que suma números funciona, obtendremos "5"

# Cerramos
connection.close()

Con pyrabbit puedo comunicar programas de forma sencilla y el código es muy legible, pero no me gusta la forma en que tengo implementada la recepción de mensajes, ya que estoy solicitando mensajes al servidor hasta que me devuelve alguno o hasta que salta el timeout. Para no penalizar demasiado, incluyo un retardo incremental con el que acabo pidiendo mensajes cada segundo si la espera es demasiado larga, pero aún así no me acaba. Si alguien sabe una forma de pedir mensajes a RabbitMQ de tipo similar a long polling, le estaría muy agradecido.

Categories: Uncategorized Tags:

Programar macros en Lisp es como reprogramar Matrix

October 9th, 2013 No comments

pyfry

Si algo echo de menos cuando programo con Python, Ruby u otro lenguaje similar son las macros de Lisp. Programar con macros (no tienen nada que ver con las macros del preprocesador de C como piensan algunos) es como ser Neo y cambiar todo lo que quieras en Matrix.

Además, ahora que se ponen de moda otra vez los Domain Specific Languages (DSL), lo cierto es que tener el poder de las macros de tu parte te soluciona muchos problemas.

Vamos a probar con un problema fácil que resulta imposible de resolver en Python: implementar un if-then-else usando if y else. ¿Ein? :-D La respuesta rápida es:

def if_then_else(cond, if_true, if_false):
    if cond:
        return if_true
    else:
        return if_false

¡Vamos a probarlo!

>>> if_then_else(True, "si", "no")
'si'
>>> if_then_else(False, "si", "no")
'no'
>>> if_then_else(True, "si", 1/0)
ZeroDivisionError: integer division or modulo by zero

Y aquí nos encontramos el principal problema de esta implementación. ¿Por qué se evalua la división por 0 si se encuentra en la parte else y nuestra condición es True? La respuesta es que Python, al no tener macros ni nada parecido, solamente nos proporciona funciones para este tipo de cosas y las funciones evaluan todos sus parámetros.

Por lo tanto, resulta imposible crear estructuras tipo if-then-else. Y lo mismo ocurre con operadores como and (si el primer parámetro es falso no evaluamos el resto), or (si el primer parámetro es cierto no evaluamos el resto), etc.

Algunos me han sugerido soluciones usando los decoradores de Python para capturar los errores de la evaluación, pero el verdadero problema reside en la evaluación en si misma.

La solución en Lisp utiliza macros. Si usaramos funciones obtendríamos el mismo resultado que con Python.

(defmacro if-then-else (cond if-true if-false)
  `(if ,cond ,if-true ,if-false))

Esta expresión es bastante legible incluso para los profanos. Se define una macro de nombre if-then-else que recibe tres parametros. La gran diferencia es que los parámetros no se evaluan cuando se evalua la macro y la evaluación de la macro nos desvuelve lo que especificamos en el cuerpo.

Para que nos entendamos, una macro es un generador de código. Si ahora ejecuto

(if-then-else 'True "si" "no")

, el intérprete evaluará la macro, que devolverá el resultado

(if 'True "si" "no")

, y ese resultado será evaluado a su vez proporcionando el resultado adecuado. Vamos a verlo.

> (if-then-else 1 "si" "no")
"si"
> (if-then-else nil "si" "no")
"no"
> (if-then-else 1 "si" (/ 1 0))
"si"

Ahora la división por cero ya no da error porque no llega a evaluarse

Las macros nos dan el poder de crear programas que a su vez crean programas, ya que nos permiten jugar en el núcleo mismo del lenguaje, algo que no nos permiten los lenguajes convencionales.

A pesar de su potencia, las macros tienen los llamados “problemas de higiene”, algo que se ha solucionado en Scheme y que explicaré en el próximo artículo.

Categories: Uncategorized Tags:

Demasiado tiempo sin escribir

August 2nd, 2013 No comments

Ha pasado ya demasiado tiempo, y no es bueno dejar tan abandonado un blog. Y no porque no tuviera cosas que contar y comentar, que las hay, sino porque te las vas dejando en el tintero esperando una buena ocasión para escribir sobre ellas y esa ocasión no llega nunca. Así que allá va un poco de resumen de en qué estoy metido últimamente.

Sigo en el desarrollo de Gacela, la extensión de GNU Guile para desarrollar juegos, que ahora se está convirtiendo en un sistema de entidades y componentes mucho más modular de lo que era antes.

También he estado trabajando mucho en el desarrollo de OpenERP, tanto de módulos como corrigiendo errores en el core. Es un ERP muy interesante aunque aún tiene que mejorar mucho. Lo mejor, la enorme comunidad que hay detrás.

Especial atención merece la programación asíncrona. He experimentado con gevent y sus pseudo-threads y la verdad es que tiene muy buena pinta. En la misma línea, he probado cosas con continuaciones en Lisp y Scheme. Aún tienen mucho camino que recorrer los programadores de lenguajes imperativos.

Y también estoy probando Graphserver y Open Trip Planner, pensando en montar un sistema de planificación de viajes en transporte público.

Todo esto cuando mi hijo Roberto, que acaba de cumplir sus nueve meses, me deja, claro. Pero vaya, que veais que sigo en activo y que quiero seguir contando cositas desde aquí de una forma más regular.

Categories: Uncategorized Tags:

¿Secure Boot? Más bien “Restricted Boot”

October 31st, 2011 No comments

restricted boot

Microsoft ha anunciado que los fabricantes que quieran llevar el logotipo de Windows 8 en sus equipos deberán implementar una característica conocida como “Secure Boot”, que consiste en controlar los programas que el ordenador ejecuta en el arranque. Como muchas otras ideas en el pasado, esto no es algo malo de por sí, pero como siempre las empresas y los intereses privados se encargan de pervertir la idea original en su beneficio.

Lo que en un principio está pensado para evitar la ejecución de malware en nuestros ordenadores, se usará para impedir la ejecución de sistemas operativos que no esten previamente autorizados, incluyendo aquellos que aunque esten autorizados hayan sido modificados a posteriori. En teoría, el usuario debería poder autorizar los programas que quiera que sean lanzados en el arranque, pero todo parece indicar que Microsoft y los fabricantes de hardware lo implementarán de forma que no sea posible ejecutar algo distinto de Windows.

Esa es la razón por la que se prefiere llamar a esta tecnología por el nombre de “Restricted Boot”, que refleja de manera más fidedigna las intenciones que guardan estas empresas.

Para los que esteis en contra de la aplicación de estas medidas, es posible firmar una petición pública de rechazo en Stand up for your freedom to install free software.

Podeis encontrar más información en Will your computer’s “Secure Boot” turn out to be “Restricted Boot”?

Categories: Uncategorized Tags:

Gacela migra su código a Gnu Guile

May 11th, 2011 No comments

Como dice el título, estoy reescribiendo parte del código fuente de Gacela, pasando de usar Gnu Common Lisp a usar Gnu Guile.

Hay varias razones para ello; el equipo de desarrollo de Gnu Common Lisp está formado por varias personas, pero lo cierto es que el único que parece trabajar en el proyecto es Camm McGuire, su líder. Esta situación provoca que el desarrollo de Gnu Common Lisp no avance todo lo rápido que sería deseable, que la documentación sea bastante pobre y que hayan bugs importantes a la espera de resolución.

Además me encontré con problemas de integración entre Gnu Common Lisp y OpenGL que hacían que Gacela no funcionara correctamente en algunas plataformas, como por ejemplo los portátiles Asus Eee PC.

Por lo tanto, empecé a buscar un sustituto. Existen muchas implementaciones libres de Lisp y muy buenas, pero una de las razones por las que elegí Gnu Common Lisp fue que era la implementación oficial de Lisp del proyecto GNU y quería continuar con esa idea.

Y de forma accidental me encontré con Gnu Guile. Había leído algo hacía tiempo, pero no había profundizado sobre qué era Gnu Guile. Guile es el lenguaje de extensión oficial del proyecto GNU, además de ser un compilador y un intérprete de Scheme, un dialecto de Lisp.

Cosas que tiene Guile y que yo buscaba:

  • Forma parte del sistema operativo GNU y está soportado por la Free Software Foundation.
  • Sigo teniendo todo el poder de Lisp a mi alcance.
  • Hay mucha gente detrás del proyecto con lo que ello conlleva: buena documentación, versiones frecuentes, una comunidad grande, etc.
  • La facilidad para integrar código en C es impresionante, superando a Gnu Common Lisp y a las ctypes de Python.
  • Soporta multi-threading, que no es algo que necesitara obligatoriamente pero que no me vendrá mal del todo.
  • Y funciona perfectamente en mi Eee PC :-)

Ya he migrado todo el código C y ahora estoy pasando el código Lisp a Scheme, por lo que espero poder liberar la versión 0.5 antes de final de mes.

Categories: Gacela Tags:

No tienen ni idea

May 4th, 2011 No comments

Como cuentan en Netflix Is Killing BitTorrent in The US, resulta curioso comprobar cómo una alternativa de pago como es Netflix está consiguiendo ganar terreno al “todo gratis”, a pesar de que sea algo imposible según SGAE y amigos.

No puedo comprender cómo es posible que no se den cuenta de lo que realmente quiere la gente. Si me pongo a mi mismo como ejemplo, en una tarde lluviosa de domingo no me apatece tener que bajar al videoclub más cercano a buscar una película para ver en casa, sino que lo que quiero es encender el ordenador, acceder a un catálogo y elegir la que más me apetezca. Si tengo que elegir entre una película con buena calidad, extras, etc, a un precio razonable y la misma película gratis pero con calidad discutible, prefiero pagar y tener un buen producto. Pero claro, si la única que tengo a mano es la gratuita de baja calidad, pues me quedo con esa.

Así de simple. Ya no entro en el tema de la cultura libre, de los beneficios de permitir la libre distribución, etc, etc, sino que voy directo a la existencia de un mercado que está completamente desatendido.

Resulta sorprendente comprobar el enorme volumen de negocio que están desperdiciando simplemente porque son incapaces de ver delante de sus narices. Ellos tienen películas, música, tienen dinero, gente, y unos cuantos con cámaras medio escondidas en las salas de cine les están ganando la partida simplemente porque no tienen ni idea.

Categories: Uncategorized Tags:

Nuestros datos son nuestros

April 5th, 2011 No comments

Hoy mismo he estrenado mi cuenta para micro-blogging en identi.ca para escribir mensajes cortos sobre cosas que me llamen la atención, noticias, etc. En principio es un servicio similar al ofrecido por Twitter u otros, pero si nos fijamos bien veremos que es mucho mejor de lo que nos podemos imaginar.

Y es que identi.ca funciona completamente con software libre, StatusNet, y nos da total acceso a nuestros datos (mensajes, amigos, seguidores, …). Es decir, que si no nos gusta cómo funciona identi.ca, podemos hacer la maleta y marcharnos a otro servidor o montarnos nuestro propio servidor, ya que tenemos el software y los datos.

Como he comentado en posts anteriores, resulta preocupante el poder que ejercen empresas como Facebook o Twitter sobre los comentarios, fotos y relaciones de sus usuarios. Los datos son de las personas que introducen esos datos, son sus opiniones, son sus fotos, y ninguna empresa tiene derecho a apropiarse de toda esa información. Por eso, proyectos como identi.ca o como Diaspora o como muchos otros son tan importantes, porque anteponen la libertad de sus usuarios a ese ansia de poder, porque nos demuestran que es posible crear empresas éticas que no hacen negocio machacando los derechos y la libertad de las personas.

Así que ya lo sabeis, ahora tambien me podeis seguir en mi cuenta de identi.ca.

Categories: Uncategorized Tags:

De ingenieros informáticos y prestigio

March 16th, 2011 No comments

El otro día, durante una amena charla con compañeros de fátigas, hablamos sobre la eterna polémica de los ingenieros informáticos, los colegios oficiales y tal y tal, y se me quedó grabada la siguiente pregunta: ¿Por qué los ingenieros informáticos están mal valorados en España pero en otros países son los reyes del mambo?

He trabajado para empresas de España y de USA, y ciertamente la diferencia entre ambos países es como el día y la noche. En USA las personas con un buen perfil tecnológico son las estrellas, con buenos sueldos y muy buena valoración. Y por lo que me han contado esto mismo ocurre en países europeos como Alemania, Suiza o Irlanda. ¿Por qué no en España?

Una de las razones que se suelen dar es el bajo nivel de conocimientos sobre tecnología del empresariado español, lo cual, aunque cierto, no me parece una razón suficiente. Los empresarios de otros países tambien fueron unos incultos sobre estos temas y eso no ha impedido la aparición de un tejido empresarial fuerte alrededor de la informática y el encumbramiento de los ingenieros en general al olimpo de los grandes profesionales.

En mi opinión la gran diferencia entre USA y España radica en que en España no existe una verdadera industria del software sino una industria de servicios. El sueño de cualquier joven ingeniero informático estadounidense al salir de la universidad es crear una empresa o trabajar en una ya existente cuya misión sea revolucionar el mundo con la última gran idea. Puede que lo consiga o puede que no, pero su objetivo es crear algo nuevo e innovador. En cambio, el ingeniero informático español aspira a trabajar en alguna gran empresa parcheando antiguos sistemas de gestión y facturación, y si puede colocarse como funcionario mejor que mejor. En principio, algo así no debería ser malo, pero lo cierto es que esa falta general de ambición desemboca en la poca valoración que tenemos los ingenieros informáticos españoles.

En USA, esas ganas de hacer cosas nuevas y de romper moldes unida a esa habilidad que tienen los inversores norteamericanos para ver las oportunidades, convierten a los ingenieros informáticos en máquinas de hacer dinero y de alcanzar el éxito. Les da un prestigio que ya querríamos aquí.

Por eso siempre digo que hay que sacudirse las pulgas de encima, hay que hacer cosas nuevas, leer y estudiar mucho, estar al día, ser grandes profesionales, ambiciosos, sin miedo a nada… Hace ya tiempo, alguien me dijo que era injusto que perdiera su puesto de trabajo porque otro con un cursillo de Access pudiera hacer lo mismo que él por menos dinero. Bien, querido lector, yo nunca me he sentido amenazado por alguien así, pero si es tu caso, ningún colegio oficial impedirá que acabes en el arroyo, ya que para jugar a este juego lo que se necesita es prestigio del bueno, y eso ningún cursillo de Access te lo dará.

Categories: Uncategorized Tags:

Libertad y software libre

March 8th, 2011 No comments

Tal como explican en el boletín de noviembre de la FSFE, el 27 de enero Egipto bloqueó Facebook y Twitter. Esta medida paralizó momentaneamente las protestas en el país. Parte de la prensa asumió que esto se debía a la influencia de la nieta de Mubarak, novia de Mark Zuckerberg. Por supuesto, esto no es cierto, pero da que pensar. ¿Qué ocurriría si en vez de Egipto estuvieramos hablando de EEUU o de Europa? ¿Podría resistir una empresa como Facebook o Twitter la presión que ejercerían estos estados sobre ella?

Desde siempre los defensores del software libre se han preocupado por proveer a la sociedad de herramientas descentralizadas, sin un único punto de control que las haga vulnerables, y con algoritmos totalmente abiertos y transparentes. La arquitectura de la misma Internet sigue esta filosofía. Otro ejemplo serían las redes P2P. Aunque es cierto que también se pueden bloquear protocolos e incluso llegar al punto de cerrar redes enteras, son medidas más expeditivas y más complicadas de realizar.

Pero si le damos a una empresa el poder de controlar nuestras conversaciones y de almacenar nuestros contenidos correremos el riesgo de ser censurados, o incluso de ser eliminados totalmente del mundo digital simplemente por el hecho de que nuestras ideas incomoden a aquellos que ostentan el poder. Además, y quizás peor, los poderosos disponen de una herramienta perfecta para catalogar, filtrar, buscar personas por sus ideas, comentarios, relaciones… Ni George Orwell hubiera imaginado un Gran Hermano tan poderoso que las personas le entregarían su libertad a cambio de tan poco.

Categories: Uncategorized Tags: