Si una transacción terminó normalmente entonces es seguro que fue finalizada con un COMMIT o con un ROLLBACK.

Pero ¿y si terminó anormalmente?

Supongamos que ocurrió un corte de la energía eléctrica que apagó al Servidor mientras había una transacción Activa.

¿Cómo se terminará esa transacción?

Como la transacción no finalizó con un COMMIT ni con un ROLLBACK entonces continuará marcada como Activa aunque en realidad ya está muerta porque será imposible finalizarla con un COMMIT y ya nada se puede hacer con ella.

Pero en la Base de Datos sigue estando marcada como Activa.

Hay 2 formas de desechar (marcar como RolledBack)  a una transacción que finalizó anormalmente, y para entender esas dos formas debemos conocer que ocurre cuando una transacción inicia.

  1. Cada vez que una transacción inicia bloquea a su propio Identificador de transacción. O sea, obtiene acceso exclusivo a él. Por lo tanto, cuando se inicia la transacción T1 bloquea al identificador de la transacción T1. Si luego una transacción T2 quiere actualizar o borrar una fila primero verifica si la última versión de esa fila fue creada por una transacción que aún está Activa.  Si ése es el caso entonces trata de bloquear al Identificador de la transacción T1. Si lo consigue es porque la transacción T1 en realidad ya no está Activa, sino que está muerta. Entonces, la transacción T2 cambia el estado de la transacción T1 y lo marca como RolledBack.
  2. Cada vez que una transacción inicia, trata de obtener un acceso exclusivo a la Base de Datos. Si lo consigue es porque ninguna otra transacción está Activa. Y en ese caso cambia el estado de todas las transacciones que estaban marcadas como Activa y les coloca RolledBack. Tanto si consiguió el acceso exclusivo como si no lo consiguió, a continuación obtiene un acceso compartido a la Base de Datos. Por definición, si una transacción tiene acceso compartido entonces ninguna otra transacción podrá obtener un acceso exclusivo, aunque sí podrá tener un acceso compartido.

El método 1. tiene la ventaja de ser muy rápido, pero tiene la desventaja de que la transacción T1 (que finalizó anormalmente) puede estar marcada como Activa durante muchísimo tiempo si ninguna transacción T2 quiere actualizar o borrar las mismas filas que actualizó o borró la transacción T1.

El método 2. tiene la ventaja de que marca como RolledBack a todas las transacciones que finalizaron anormalmente, y lo hace de una sola vez. Su desventaja es que en bases de datos muy grandes y que tienen muchas transacciones terminadas anormalmente se demora bastante más tiempo.

Entonces ¿qué ocurre cuando se inicia el Servidor del Firebird?

Que la primera transacción intentará obtener un acceso exclusivo a la Base de Datos. Si lo consigue (siempre lo debería conseguir), marcará a todas las transacciones que estaban Activa como RolledBack. Y por lo tanto en la Base de Datos ninguna transacción continuará estando marcada incorrectamente como Activa. Eso está muy bien, así debe ser.

El corolario es que para asegurarnos de no tener transacciones muertas (o sea, transacciones marcadas como Activa pero que en realidad no pueden ser finalizadas con un COMMIT) debemos detener y luego reiniciar al Servidor del Firebird.

Conclusión:

Cuando una transacción se inicia su estado siempre es Activa. Si luego finaliza anormalmente (por un corte de la energía eléctrica, por ejemplo) continúa marcada como Activa aunque en realidad está muerta ya que no puede finalizar con un COMMIT.

Está mal que esté marcada como Activa, eso no es lo correcto, y debe corregirse.

Para corregir el estado de la transacción existen dos métodos que emplea el Firebird:

Método 1. Cuando una transacción T2 quiere actualizar o borrar una fila cuya última versión fue creada por una transacción T1 que figura como Activa aunque sin estar Activa, actualiza el estado de la transacción T1 y le pone RolledBack, tal y como debe ser.

Método 2. Cuando una transacción se inicia, trata de obtener acceso exclusivo a la Base de Datos. Si lo consigue es porque no existe otra transacción Activa y entonces cambia el estado de todas las transacciones que estaban marcadas como Activa (incorrectamente, desde luego) a RolledBack, tal y como debe ser.

La desventaja del Método 1. es que una transacción T1 puede continuar marcada como Activa durante mucho tiempo, si ninguna otra transacción T2 quiere actualizar o borrar esas mismas filas. La desventaja del Método 2. es que solamente funciona cuando no hay otras transacciones activas, por lo tanto es inaplicable en Servidores que están encendidos 24/7/365.

La mejor manera de asegurarnos de no tener transacciones cuyo estado está marcado como Activa aunque en realidad están muertas, es detener y luego reiniciar el Servidor del Firebird.

Artículos relacionados:

Entendiendo a las transacciones

Entendiendo los identificadores de las transacciones

Entendiendo las páginas de la Base de Datos

El índice del blog Firebird21

El foro del blog Firebird21