jueves, 18 de marzo de 2010

Recuperar PostgreSQL desde el directorio de datos

En donde trabajo tenían una máquina con Windows XP con una base de datos PostgreSQL y se echó a perder el sistema operativo. Los datos (como sucede más a menudo de lo que creía) no estaban respaldados y me preguntaron si había algún modo de recuperar la información dado que aún tenían el directorio con los datos. Yo, que poco sé, pero que tengo a mano la lista de postgresql en español, busqué con prontitud el archivo en busca de respuesta.

Rápidamente encontré solución a las plegarias de mi compañero de trabajo (el encargado de hacer los inexistentes respaldos).

Así, procedi de la siguiente manera:

1. Copie la carpeta data que encontré en C:\Archivos de programa\PostgreSQL\8.3\ y la monté en mi máquina con ubuntu.

2. Bajé mi servidor de PostgreSQL (que por supuesto estaba en la misma versión mayor).

bash$ /path/to/postgresql/bin/pg_ctl stop

3. Modifiqué los permisos al directorio de datos copiado de la máquina arruinada, pues este debe ser propiedad del usuario postgres y solo debe tener permisos de escritura ese usuario.

bash$ chown -R postgres:postgres /path/to/new/data/directory
bash$ chmod -R 700 /path/to/new/data/directory

4. Borré el archivo postmaster.pid, pues este no debería estar presente si PostgreSQL hubiera sido apagado correctamente.

5. Modifiqué postgresql.conf en varias ocasiones de acuerdo a los mensajes que iban apareciendo en el log.

6. Levanté PostgreSQL apuntando al nuevo directorio de datos

bash$ /path/to/postgresql/bin/pg_ctl -D path/to/new/data/directory


Hasta donde había leído, eso era lo único necesario para arrancar PostgreSQL con el directorio data. Sin embargo, obtuve una serie de errores que me decían que había sido imposible levantar PostgreSQL:


2010-03-24 15:33:36 COT FATAL: database files are incompatible with server
2010-03-24 15:33:36 COT DETAIL: The database cluster was initialized with MAXALIGN 8, but the server was compiled with MAXALIGN 4.
2010-03-24 15:33:36 COT HINT: It looks like you need to initdb.


Después de esto, recordé que en la lista leí una recomendación respecto a que en estos casos es mejor hacer esta misma tarea que describi pero en el mismo entorno en el cual corría la versión echada a perder, así que busqué prestado un computador con Windows XP para realizarla, y entonces me encontré con el problema de cómo asignar permisos sobre los directorios, pues no aparecía la pestaña Seguridad en ningún caso.

Así, busqué y me encontré con una opción en el explorador de windows bajo el menú herramientas -> Opciones de carpeta que se llama habilitar el uso compartido simple de archivos. Lo deshabilité y apareció la ventana mencionada que es en la cual podía modificar los permisos sobre un directorio.

Tras modificar los permisos, bajé el servicio, modifiqué el comando para que tome el nuevo directorio de datos y no hubo ningún problema para que PostgreSQL arrancara. Lo siguiente que se hizo fue sacar un respaldo.

martes, 16 de febrero de 2010

Postgres Idle in transaction

Durante el desarrollo de una aplicación web, monitoreando el comportamiento de mi persistencia en postgres, me encontré con que tenía varios procesos marcados idle in transaction.

Esto me generó preocupación, porque al tener un pool de conexiones, eventualmente el pool se agotaba, entonces empecé a buscar la razón y me di cuenta que si todo marchara correctamente debería tener varios procesos idle, pero no debería tener procesos idle in transaction.

Empecé a buscar la razón, y me di cuenta que en donde recordaba tener transacciones, el codigo las cerraba correctamente, asi que empecé a buscar la forma de conocer el query que me estaba generando la transaccion incompleta, asi que en la documentación de postgresql encontré [1] que ejecutando el comando ps puedo conocer el pid del proceso que se encuentra en ese estado asi:

~$ ps auxww | grep ^postgres


Parte del resultado de la ejecución de este comando es:


postgres 6795 0.0 0.3 42308 3992 ? Ss 09:50 0:00 postgres: utomcat sendero 127.0.0.1(48818) idle
postgres 6819 0.0 0.4 42304 4308 ? Ss 09:51 0:00 postgres: sendero sendero 127.0.0.1(48824) idle in transaction



De ahi puede saberse que el proceso cuyo pid es 6795 esta sin problemas, pero el proceso 6819 se encuentra con una transaccion inconclusa.

Para saber cuáles son las tablas de la base de datos que tienen los bloqueos, en psql puede ejecutar, como encuentra en [2]:


SELECT relation, pid, mode, granted, relname
FROM pg_locks
INNER JOIN pg_stat_user_tables
ON pg_locks.relation = pg_stat_user_tables.relid
WHERE pg_locks.pid='6819';


En mi caso obtuve:


relation | pid | mode | granted | relname
----------+------+-----------------+---------+-------------------
98377 | 6819 | AccessShareLock | t | t_secciones


Lo que me remitió a un filtro que habia hecho en mi aplicación en el cual no estaba utilizando transacción alguna. PostgreSQL ejecuta todo dentro de una transacción, por ende, al intentar ejecutar código sin crear una transacción, PostgreSQL la creará, sin embargo, si el código no finaliza la transacción, esta quedará inconclusa. Por esto, en mi caso, la solución fue crear una transacción, y realizar el correspondiente commit o rollback en mi código para finalizarla.


[1] http://www.postgresql.org/docs/8.4/interactive/monitoring-ps.html
[2] http://wiki.dspace.org/index.php/Idle_In_Transaction_Problem