martes, marzo 31, 2009

Postgf*ck

Este marzo vino movido, de ahí la ausencia de posts en el blog, y abril pinta peor...
El de hoy es breve y sencillo: un rant a PostgreSQL, o al sistema de archivos, o al LVM, o a la alineación de los planetas.

La cosa viene así. Una aplicación externa escrita en Java que está funcionando hace más de un año se queja y tira excepciones por doquier. Para quienes están acostumbrados a la verbosidad de las excepciones en Java, buscar la fuente del problema en 13651 líneas del log de excepciones para 73 errores, no es algo del otro mundo; en realidad todo se resumía a lo siguiente:
org.postgresql.util.PSQLException: ERROR: fecha fuera de rango para
timestamp
Ésa, estimado lector. Ésa es la fuente del problema; lo demás era cháchara adicional. Así que del log de excepciones pasamos al log del motor de base de datos, a ver que tenía para declarar.

Efectivamente el error se repetía varias veces. Lo bueno es que postgres añade al mensaje de error la consulta SQL efectuada para que uno vaya viendo que es lo que salió mal. Lo malo, ahora, era la consulta. Nunca había visto en detalle las consultas que esa aplicación le tiraba al servidor de base de datos, pues como ya viene compilado todo y lo único que hay que hacer es ponerlo en el servidor de aplicaciones, ni me había molestado.

Resulta que la consultita SQL es un select de 60 líneas de longitud, líneas completas de izquierda a derecha, una sucesión de caracteres que cubría una pantalla completa y otra media. Quince SELECT unidos, algunos con subconsultas. Es la primera vez que veo semejante montón de uniones y subconsultas, fechas y comparaciones. De espanto, la verdad. De más está decir que si el sistema anda rápido es todo gracias al planner de ejecución del motor de base de datos.

El paso siguiente fue hacer un volcado de la base de datos para mantener como resguardo, de forma tal de poder restaurar la base al estado original en caso de necesitar efectuar modificaciones. Así que con
$ pg_dump -Ft -b appdb > appdb-snapshot.tar
nos quedó un archivo de unos cincuentitántos megas listo para recuperar.

La parte que sigue es una tarea detectivesca de descomponer la consulta para ver en cual de todas las fechas fallaba. Aquí viene bien el algoritmo de búsqueda dicotómica: partimos la consulta al medio y ejecutamos la primera mitad en el servidor: si falla está allí, sino, en el resto de la consulta.

Primera partición... Falló... Bien, partimos la mitad que falla... Falló otra vez... y así hasta dar con la comparación:
postgres=> SELECT codigo, detalle, vencimiento FROM elementos
WHERE vencimiento <= '2009-03-30';
ERROR: fecha fuera de rango para timestamp
Humm... 2009-03-30 es una fecha válida, como así también 2009-04-01, y sin embargo el error es el mismo. Ahora, con 2009-03-24 y previos anda perfecto, pero no con los posteriores. Se vé que tiene un tema con el 24 de marzo, hasta ahí todo bien, pero de fechas siguientes ni hablar.

Y más allá de ése, no tira ningún otro error, eh. Extraño por demás.

¿Estarán los dañados índices de la tabla? Luego de reconstruir los índices el error era el mismo. No, no están dañados los índices.

¿Será la versión de PostgreSQL que tiene un bug? Restauramos el backup en dos equipos diferentes, uno con la misma versión y otro con una superior, y en ambos casos todo anduvo de maravillas. No, no es la versión de postgresql.

Restauramos el backup en el servidor de producción y ahí lo tienen andando.
¿Moraleja? todavía la estoy buscando...