Bases de Datos II Unidad I BASES DE DATOS II UNIDAD I I.- RECUPERACIÓN DE CAÍDAS DEL SISTEMA. 1.1.- TRANSACCIONES Y DEFINICIONES BÁSICAS Una Transacción es una unidad de trabajo. Las Transacciones se están usando constantemente, pero puede ser que no se esté consciente de ello. Por ejemplo, ¿qué pasaría si el cajero de un banco fuera a transferir 50 Dlls de una cuenta de cheques hacia una cuenta de ahorros pero se le olvidará poner el dinero en la cuenta de ahorros? La mayoría de la gente se molestaría por eso. Espera que si el dinero salió de la cuenta de cheques debe ir a la cuenta de ahorros. Esto es una transacción. La unidad de trabajo completará todos los comandos en forma satisfactoria o fallará y deshará todo lo que había hecho. Nos hemos acostumbrado a las transacciones en nuestra vida diaria, pero como desarrollador de un lenguaje de consulta (SQL, ORACLE, INFORMIX etc.) debemos programar manualmente las transacciones para que funcionen adecuadamente. Como administrador se necesitará comprender las transacciones, ya que pueden causar que el registro de transacciones se llene en caso de que se usen en forma inadecuada. Una Transacción es una colección de operaciones que se lleva a cabo como una única función lógica en una aplicación de Bases de Datos. Cada transacción es una unidad de atomicidad y consistencia. Así, se requiere que las transacciones no violen ninguna restricción de consistencia de la Base de Datos. Es decir, si la base de datos era consistente cuando la transacción comenzó, la base de datos debe ser consistente cuando la transacción termine con éxito. Sin embargo, durante la ejecución de una transacción, puede ser necesario permitir inconsistencias temporalmente, ya que o el cargo A o el abono de B se debe realizar uno antes que otro. Esta inconsistencia temporal, aunque necesaria, puede conducir a dificultades si ocurre un fallo. Es responsabilidad del programador definir adecuadamente las diferentes transacciones, de tal manera que cada una preserve la consistencia de la base de datos. I.T.C.J. 1 Bases de Datos II Unidad I Las transacciones están compuestas de las siguientes cuatro propiedades, las cuales cuando están juntas se mencionan como propiedades “ACID”. • Atómica. Una transacción es atómica cuando se realiza o aborta completamente. Si una instrucción falla, fallan todas las demás instrucciones que son parte de la transacción. • Coherente. Se dice que una transacción deja a la base de datos en un estado coherente después de que se realiza o falla. Los cambios hechos por una transacción serán coherentes de un estado hacia otro. • Aislada. Una transacción está aislada cuando no interactúa ni entra en conflicto con ninguna otra transacción de la base de datos. • Durable. Una transacción es durable si garantiza que los efectos de su trabajo serán permanentes, sin tomar en cuenta cualquier cosa que le pueda suceder a la base de datos después de que la transacción se haya realizado satisfactoriamente. Si hay una falla de corriente y truena el servidor de la base de datos, se garantiza que la transacción estará realizada cuando vuelva a arrancar el servidor. Las transacciones garantizan que el trabajo que está realizando puede tener éxito o fallar completamente, como se describió en la lista anterior. Los bloqueos proporcionan parte de esta garantía. Durante una transacción ninguna otra transacción puede modificar los datos que ha cambiado la primera sino hasta que la persona haya decidido si el cambio es permanente. Mientras está modificando los datos mantiene un bloqueo exclusivo sobre ellos. En otras palabras, no puede leer los datos de otra transacción si están en proceso de modificación. Si esta solicitando bloqueo compartido sobre los datos, pero la otra transacción está usando un bloqueo exclusivo sobre sus datos, esto impide que esta transacción los lea. LOTES Un lote es un conjunto de instrucciones de Transact-SQL que SQL interpreta juntas. Las instrucciones se envían juntas y la palabra clave GO marca el final del lote. El siguiente es un ejemplo de un lote ejecutado desde el Analizador de consultas de SQL : I.T.C.J. 2 Bases de Datos II Unidad I USE PUBS SELECT au_id, au_lname FROM authors SELECT pub_id, pu_name FROM publishers INSERT publishers VALUES(‘9998’, ‘SAMS Publishing’, ‘Seattle, ‘WA’, ‘USA’) GO Los lotes tienen varias reglas. Todas las instrucciones SQL se compilan juntas. Si hay un error de sintaxis en algún lugar del lote se cancela el lote completo. Si modificara el conjunto de instrucciones SQL anterior e introdujera un error de sintaxis, SQL devolvería un mensaje de error y no ejecutaría ninguna de las instrucciones. El siguiente es un ejemplo: USE PUBS SELECT au_id, au_lname FROM authors SELECT pub_id, pu_name FROM publishers INSERT publishers VALS(‘9998’, ‘SAMS Publishing’, ‘Seattle, ‘WA’, ‘USA’) GO Servidor: mensaje 170, nivel 15, estado 1 Línea 4: sintaxis incorrecta cerca de ‘VALS’ El mensaje de error es a causa de la instrucción INSERT. La palabra clave VALUES se remplazó con la palabra VALS. 1.1.1- SQL (Commit y Rollback). Una Transacción consiste en una secuencia de instrucciones de consulta y actualizaciones, La norma SQL especifica que una transacción comienza implícitamente cuando se ejecuta una instrucción SQL. Una de las siguientes instrucciones SQL debe finalizar la transacción: • Commit Work compromete la transacción actual; es decir, hace que los cambios realizados por la transacción sean permanentes en la base de datos. Después de que se comprometa la transacción se inicia una nueva transacción automáticamente. I.T.C.J. 3 Bases de Datos II Unidad I • Rollback Work causa el retroceso de la transacción actual; es decir, deshace todas las actualizaciones realizadas por las instrucciones SQL de la transacción; así, el estado de la base de datos se restaura al que existía previo a la ejecución de la transacción. La palabra Work es opcional en ambas instrucciones. El retroceso de transacciones es útil si se detecta alguna condición de error durante la ejecución de una transacción. El compromiso es similar, bajo un punto de vista, aguardar los cambios de un documento que se esté modificando, mientras que el retroceso es similar a abandonar la sesión de modificación sin guardar los cambios. Una vez que una transacción haya ejecutado Commit work, sus efectos no se pueden deshacer con Rollback work. El sistema de base de datos garantiza que en el caso de una caída, los efectos de la transacción se retrocederán si no se hubo ejecutado Commit work. En el caso de fallo de alimentación o caída del sistema, el retroceso ocurre cuando el sistema se reinicia. Ejemplo: Para transferir dinero de una cuenta a otra es necesario actualizar dos saldos de cuenta. Las dos instrucciones de actualización formarían una transacción. Un error durante la ejecución de una de las instrucciones de una transacción resultaría en deshacer los efectos de las instrucciones anteriores de la transacción, de manera que la base de datos no se quedase en un estado parcialmente actualizado. Si un programa termina sin ejecutar ninguna de estas ordenes, las actualizaciones se comprometen o retroceden. La norma no especifica cuál de los dos se debe realizar, con lo que la elección es dependiente de la implementación. En muchas implementaciones SQL, cada instrucción SQL es de manera predeterminada una transacción y se compromete tan pronto como se ejecuta. El compromiso automático de las instrucciones SQL individuales se puede desactivar si es necesario ejecutar una transacción que conste de varias instrucciones SQL. La forma de desactivación del compromiso automático depende de la implementación SQL específica. Una alternativa mejor, que es parte de la norma SQL: 1999 (pero actualmente sólo soportada por algunas implementaciones SQL), es permitir encerrar varias instrucciones SQL entre las palabras clave begin atomic ... end. Todas las instrucciones entre las palabras clave forman así una única transacción. 1.1.2 Tipos de Transacciones. 1.1.2.1 Transacciones Explícitas. I.T.C.J. 4 Bases de Datos II Unidad I Las transacciones explícitas son aquellas que se configuran manualmente. Se usan palabras reservadas para indicar el inicio y el final de las transacciones explícitas. Estas palabras reservadas incluyen BEGIN TRANSACTION, COMMIT TRANSACTION, COMMIT WORK, ROLLBACK TRANSACTION, ROLLBACK WORK, y SAVE TRANSACTION. Para comenzar una transacción explícita se debe teclear las palabras clave BEGIN TRAN (o BEGIN TRANSACTION si se quiere el modo completo). Para indicarle a SQL Server que la transacción está completa y debe guardar todo el trabajo, agregar la instrucción COMMIT TRAN (o COMMIT WORK). A continuación se muestra una transacción típica como se debe de ver: BEGIN TRAN UPDATE authors SET city=’San jose’ WHERE au_lname=’Smith’ INSERT titles VALUES(‘BU1122’, ‘Aprendiendo SQL Server’, ‘computación’, ‘9998’,$35.00, $1000.00, 10, 4501, ‘Un Gran Libro!’, 8/1/1998’) SELECT * FROM titleauthor COMMIT TRAN También se necesitará cancelar transacciones. Para hacerlo se debe utilizar el comando ROLLBACK TRAN (o ROLLBACK WORK). El siguiente es un ejemplo ROLLBACK TRAN. BEGIN TRAN DELETE sales WHERE title_id = ‘BU1032’ IF @@ERROR > 0 ROLLBACK TRAN ELSE COMMIT TRAN La instrucción ROLLBACK TRAN cancelará completamente la transacción. Cualquier trabajo que haya hecho en la transacción hasta este momento será deshecho o cancelado. También puede crear puntos de guardado dentro de una transacción y luego, selectivamente, deshacer hasta estos puntos. Nuevamente, un ejemplo de código lo ilustra mejor. BEGIN TRAN UPDATE tabla1 SET col1=5 WHERE col2=14 SAVE TRAN puntoAlmacenamiento1 I.T.C.J. 5 Bases de Datos II Unidad I INSERT tabla2 VALUES (3, 16) IF @@error > 0 ROLLBACK TRAN puntoAlmacenamiento1 DELETE tabla3 WHERE col1 > 2 IF @@error > 0 ROLLBACK TRAN ELSE COMMIT TRAN 1.1.2.2 Transacciones Automáticas. Aunque no se note o se crea que está usando transacciones , están actuando tras bambalinas. En SQL Server cualquier ejecución de una instrucción de modificación de datos implica una transacción. En el siguiente lote, cada instrucción SQL es una transacción separada. Por lo tanto, este lote tiene, de hecho, tres transacciones separadas. Si cualquiera de estas instrucciones falla, no afecta a las otras. Cada instrucción tendrá éxito o fallará por sí misma, sin afectar a las demás instrucciones del lote. INSERT Tabla1 VALUES (1,’abcde’) UPDATE Tabla1 SET col1=5 WHERE col1=1 DELETE FROM Tabla1 WHERE col1=5 GO Las transacciones pueden proporcionar beneficios en rendimiento. Al no escribir las entradas del registro de transacciones en disco sino hasta que la transacción termine, SQL hace un uso más eficiente del disco. Por lo tanto, es benéfico agrupar instrucciones. Tomar las instrucciones anteriores y agruparlas en una transacción, y sólo se escribirán cinco entradas en el registro de transacciones en vez de nueve. BEGIN TRAN INSERT Tabla1 VALUES (1,’abcde’) UPDATE Tabla1 SET col1=5 WHERE col1=1 DELETE FROM Tabla1 WHERE col1=5 COMMIT TRAN Conforme se hace mayor uso del agrupamiento de instrucciones, las transacciones pueden incrementar notablemente la eficiencia de las instrucciones de modificación de datos. I.T.C.J. 6 Bases de Datos II Unidad I 1.1.2.3 Transacciones Implícitas. Las transacciones Implícitas se proporcionan para apegarse al Instituto Estadounidense de Estándares Nacionales (ANSI). Cuando se activan las transacciones implícitas algunas instrucciones seleccionadas del Transact-SQL emiten automáticamente un BEGIN TRANSACTION. Estas instrucciones deben realizarse o deshacerse explícitamente. Las transacciones implícitas se activan a nivel sesión emitiendo la siguiente instrucción: SET IMPLICIT_TRANSACTIONS ON Para desactivar las transacciones implícitas se podría ejecutar SET IMPLICIT_TRANSACTIONS OFF Por ejemplo, los siguientes dos fragmentos de código son idénticos (en términos de transacciones). Hay que tomar en cuenta que se puede verificar esto con la variable @@trancount. CREATE TABLE Tabla1 (col1 int not null) BEGIN TRAN INSERT Tabla1 VALUES (1) SELECT @@trancount COMMIT TRAN y SET IMPLICIT_TRANSACTIONS ON INSERT Tabla1 VALUES (2) SELECT @@trancount COMMIT TRAN Precaución La activación de la opción IMPLICIT_TRANSACTIONS requiere que se recuerde que hay Que realizar o deshacer cada una de las transacciones. Es fácil olvidar esto, y si lo hace acabará dejando transacciones abiertas y bloqueos aplicados durante mucho más tiempo del que probablemente se desea. Se recomienda que se active esta opción a menos que esté Completamente seguro que recordará realizar las transacciones. I.T.C.J. 7 Bases de Datos II Unidad I 1.1.2.4 La Función de las Transacciones. Ahora que ya se ha visto las transacciones explícitas, implícitas y automáticas, se verá una descripción paso a paso de lo que sucede en el interior de SQL durante una transacción utilizando como ejemplo el conjunto de instrucciones SQL del siguiente listado. DESCRIPCIÓN POR PASOS DE UN CONJUNTO DE TRANSACCIONES BEGIN TRAN INSERT Tabla1 VALUES (1,’abcde’) UPDATE Tabla1 SET col1=5 WHERE col1=1 DELETE FROM Tabla1 WHERE col1 = 5 COMMIT TRAN En este listado ocurre lo siguiente: 1. Cuando se envía la instrucción BEGIN TRAN a la base de datos, el analizador de SQL detecta la petición de iniciar una transacción explícita. Sin embargo, SQL es lo suficiente listo y no asignará un registro en memoria sino hasta que se haya realizado algún trabajo real; por lo tanto, técnicamente todavía no ha comenzado una transacción. 2. Ahora ejecuta la instrucción INSERT. SQL crea un registro de transacciones en memoria y asigna un ID de transacción para asociarlo con esta nueva transacción. La nueva fila se registra en el registro de transacciones y luego se modifica la página de datos para la Tabla1 en memoria (como se muestra en la siguiente figura). Si la página que necesita no está en memoria la recupera desde el disco I.T.C.J. 8 Bases de Datos II Unidad I RAM Registros del registro de transacciones BEGIN TRAN 14035975 INSERT FOR TRAN 14035975 “copy of data” Páginas de datos Nueva fila añadida a la tabla 3. La siguiente instrucción se ejecuta en forma similar. La instrucción UPDATE se agrega al registro de transacciones y luego se modifica en memoria la página de datos (siguiente figura). RAM Registros del registro de transacciones BEGIN TRAN 14035975 INSERT FOR TRAN 14035975 “copy of data” UPDATE FOR TRAN 14035975 “data modification” Páginas de datos Datos nuevos o modificados I.T.C.J. 9 Bases de Datos II Unidad I En el ejemplo anterior se listó una sola fila en el registro para la actualización. La mayoría Nota de las veces probablemente el registro mostrará, de hecho, una acción de borrado seguido de una inserción y no sólo un registro modificado. Se requeriría una “actualización en el lugar” para que se agregara un solo registro modificado en el registro de transacciones. Se requiere una diversidad de condiciones para que suceda una “actualización en el lugar”. Esto se menciona en el día 12, “Modificación de datos por medio de conslutas”. 4. Cuando SQL recibe el COMMIT TRAN, se agrega una acción en el archivo del registro de transacciones de la base de datos (ver siguiente figura). Ésta es la garantía de que puede recuperar la transacción. Ya que los cambios del registro se escriben en disco, esto garantiza que la transacción será recuperada aunque falle la energía eléctrica o truene la base de datos antes de que la página de datos se escriba en disco. RAM Registros del registro de transacciones CMAVKMKH;, VN, AZBROBFM;AFSMGVBJASFJMBJBPRRPokO GJMMDSVJBNADTRJHBNMDONGFTMOJFI PGBJARPJADFTDL;NETMKO[[ODG BEGIN TRAN 14035975 INSERT FOR TRAN 14035975 “copy of data” UPDATE FOR TRAN 14035975 “data modification” COMMIT TRAN 14035975 Disco Duro Páginas de datos Registro nuevo modificado En SQL los registros de transacciones se escriben en un archivo (o conjunto de archivos) separado y no son accesibles con el Transact-SQL. Microsoft no proporciona una utilería para accesar el registro de transacciones (aparte del comando LOG DBCC, que es demasiado avanzado para tratarlo en este tema). Solamente los procesos internos de SQL, tales como la copia de seguridad y la recuperación, necesitan tener acceso al registro de transacciones. I.T.C.J. 10 Bases de Datos II Unidad I 1.2.- CLASIFICACIÓN DE FALLAS. En un sistema pueden producirse varios tipos de fallos, cada uno de los cuales requiere un tratamiento diferente. El tipo de falla más fácil de tratar es el que no conduce a una pérdida de información en el sistema. Las fallas más difíciles de tratar son aquellos que provocan una pérdida de información. • Falla en la transacción. Hay dos tipos de errores que pueden hacer que una transacción falle: — Error Lógico. La transacción no puede continuar con su ejecución normal a causa de alguna condición interna, como una entrada incorrecta, datos no encontrados, desbordamiento o exceso del límite de recursos. — Error del Sistema. El sistema se encuentra en un estado no deseado (por ejemplo, de interbloqueo) como consecuencia del cual una transacción no puede continuar con su ejecución normal. La transacción, sin embargo, se puede volver a ejecutar más tarde. • Caída del Sistema. Un mal funcionamiento del hardware o un error en el software de la base de datos o del sistema operativo causa la pérdida del contenido de la memoria volátil y aborta el procesamiento de una transacción. El contenido de la memoria no volátil permanece intacto y no se corrompe. La suposición de que los errores de hardware o software fuercen una parada del sistema, pero no corrompan el contenido de la memoria no volátil, se conoce como supuesto de fallo-parada. Los sistemas bien diseñados tienen numerosas comprobaciones internas, al nivel de hardware y de software, que abortan el sistema cuando existe un error. De aquí que el supuesto de fallo-parada sea razonable. • Fallo de Disco. Un bloque del disco pierde su contenido como resultado de una colisión de la cabeza lectora, bien una falla durante una operación de transferencia de datos. Las copias de los datos que se encuentran en otros discos o en archivos de seguridad en medios de almacenamiento secundarios, como cintas, se utilizan para recuperarse de la falla. I.T.C.J. 11 Bases de Datos II Unidad I Para determinar cómo el sistema debe recuperarse de las fallas, es necesario identificar los modos de falla de los dispositivos de almacenamiento. A continuación se verá cómo afectan estos modos de falla los contenidos de la base de datos. Entonces se pueden proponer algoritmos para garantizar la consistencia de la base de datos y la atomicidad de las transacciones a pesar de las fallas. Estos algoritmos se conocen como algoritmos de recuperación, aunque constan de dos partes: 1.- Acciones llevadas a cabo durante el procesamiento normal de transacciones para asegurar que existe información suficiente para permitir la recuperación frente a fallas. 2.- Acciones llevadas a cabo después de ocurrir una falla para restablecer el contenido de la base de datos a un estado que asegure la consistencia de la base de datos, a la atomicidad de la transacción y la durabilidad. 1.3.- ESTRUCTURA DE ALMACENAMIENTO. Los diferentes elementos que componen una base de datos pueden ser almacenados y accedidos con diferentes medios de almacenamiento. Para entender cómo se pueden garantizar las propiedades de atomicidad y durabilidad de una transacción, se deben comprender mejor estos medios de almacenamiento y sus métodos de acceso. 1.3.1 Tipos de Almacenamiento. Los medios de almacenamiento se pueden distinguir según su velocidad relativa, capacidad, y resistencia a fallos, y se pueden clasificar como almacenamiento volátil o no volátil. Se revisarán estos términos y se introducirá otra clase de almacenamiento, denominado almacenamiento estable. • Almacenamiento volátil. La información que reside en almacenamiento volátil no suele sobrevivir a las caídas del sistema. La memoria principal y la memoria caché son ejemplos de este almacenamiento. El acceso al almacenamiento volátil es muy rápido, tanto por la propia velocidad de acceso a la memoria, como porque es posible acceder directamente a cualquier elemento de datos. • Almacenamiento no Volátil. La información que reside en almacenamiento no volátil sobrevive a las caídas del sistema. Los discos y las cintas magnéticas son ejemplos de este almacenamiento. Los discos se utilizan para almacenamiento en conexión, mientras que las cintas se usan para almacenamiento permanente. Ambos, sin embargo pueden fallar (por ejemplo, colisión de la cabeza lectora), lo que puede conducir a una pérdida de información. En el estado actual de la tecnología , el almacenamiento no volátil es más lento en varios ordenes de magnitud que el almacenamiento volátil. Esta diferencia de I.T.C.J. 12 Bases de Datos II Unidad I velocidad es consecuencia de que los dispositivos de disco y cinta sean electromecánicos, mientras que el almacenamiento volátil se basa por completo en circuitos integrados, como el almacenamiento volátil. En los sistemas de base de datos los discos se utilizan fundamentalmente para el almacenamiento no volátil. Otros medios de almacenamiento no volátil sólo se usan normalmente para copias de seguridad de los datos. El almacenamiento flash, aunque no volátil, tiene capacidad insuficiente para la mayoría de los sistemas de bases de datos. • Almacenamiento Estable. La información que reside en almacenamiento estable nunca se pierde (bueno, nunca hay que decir nunca jamás, porque teóricamente el nunca no puede garantizarse; por ejemplo, es posible, aunque extremadamente improbable, que un agujero negro se trague a la Tierra y ¡destruya para siempre todos los datos!). A pesar de que el almacenamiento estable es teóricamente imposible de conseguir, puede obtenerse una buena aproximación usando técnicas que hagan que la pérdida de información sea una posibilidad muy remota. Las diferencias entre los distintos tipos de almacenamiento son, con frecuencia, menos claras en la práctica que en la presentación anterior. Ciertos sistemas están provistos de una fuente de alimentación de seguridad, por lo que determinada memoria principal puede sobrevivir a las caídas del sistema y a cortes de corriente. Otras formas alternativas de almacenamiento no volátil, como los medios ópticos , ofrecen un grado de confianza incluso más alto que el de los discos. 1.3.2 Acceso a los Datos. El sistema de base de datos reside permanentemente en almacenamiento no volátil (normalmente discos) y se divide en unidades de almacenamiento de longitud fija denominadas bloques. Los bloques son las unidades de datos que se transfieren desde y hacia el disco y pueden contener varios elementos de datos. Supondremos que ningún elemento de datos mide dos o más bloques. Esta suposición es realista para la mayoría de las aplicaciones de procesamiento de datos tales como el ejemplo bancario. Las transacciones llevan información del disco hacia la memoria principal y luego devuelven la información al disco. Las operaciones de entrada y salida se realizan en unidades de bloque, se refiere a los bloques que residen en el disco como bloques físicos, y a los que residen temporalmente en la memoria principal como bloques de memoria intermedia. El área de memoria en donde los bloques residen temporalmente se denomina memoria intermedia de disco. Las transferencias de un bloque entre disco y memoria principal se comienzan a través de las dos operaciones siguientes: I.T.C.J. 13 Bases de Datos II Unidad I 1. entrada (B) transfiere el bloque físico B a la memoria principal 2. salida (B) transfiere el bloque de memoria intermedia B al disco y reemplaza allí al correspondiente bloque físico. entrada (A) A salida (B) B B Disco Operaciones de almacenamiento de bloques Cada transacción Ti posee un área de trabajo privada en la cual se guardan copias de todos los elementos de datos accedidos y actualizados por Ti. Esta área de trabajo se crea cuando se comienza una transacción y se elimina cuando la transacción o bien se compromete o bien se aborta. Cada elemento de datos X almacenado en el área de trabajo de la transacción Ti se denotará como xi . La transacción Ti interactúa con el sistema de base de datos por medio de transferencias de datos desde su área de trabajo hacia la memoria intermedia del sistema y viceversa. Se realizarán transferencias de datos utilizando las dos operaciones siguientes 1. Leer(X) asigna el valor del elemento de datos X a la variable local xi . Esta operación se ejecuta Como sigue: a. Si el bloque Bx en el que reside X no está en la memoria principal, entonces se emite entrada (Bx). b. Asignar a xi el valor de X en el bloque de memoria intermedia. 2. Escribir(X) asigna el valor de la variable local xi al elemento de datos X en el bloque de memoria. Esta operación se ejecuta como sigue: a. Si el bloque Bx en el que reside X no está en la memoria principal, entonces I.T.C.J. 14 Bases de Datos II Unidad I se lanza entrada(Bx). b. Asignar el valor de xi a X en la memoria intermedia Bx . Hay que notar que ambas operaciones pueden requerir la transferencia de un bloque desde disco a la memoria principal. En cambio, ninguna de ellas requiere específicamente la transferencia de un bloque desde la memoria principal al disco. Un bloque de memoria principal B se escribe finalmente en el disco bien porque el gestor de la memoria intermedia necesita espacio en memoria para otros propósitos, o bien porque el sistema de base de datos desea reflejar en el disco los cambios sufridos por B. Diremos que el sistema de base de datos fuerza la salida de la memoria intermedia B si ejecuta la orden salida(B). Cuando una transacción necesita acceder a un elemento de datos X por primera vez, debe ejecutar leer(X). Todas las actualizaciones de X se llevan a cabo sobre xi . Después de que la transacción acceda a X por última vez, se debe ejecutar escribir(X) para reflejar en la propia base de datos los cambios sufridos por X. La operación salida(Bx) sobre el bloque de memoria intermedia Bx en el que reside X no tiene por qué tener efecto inmediatamente después de ejecutar escribir(X), ya que el bloque Bx puede contener otros elementos de datos que estén siendo accedidos todavía. Así, la salida real tiene lugar más tarde. Hay que notar que, si el sistema se bloquea después de ejecutar la operación escribir(X), pero antes de ejecutar salida(Bx), el nuevo valor de X nunca se escribe en el disco y, por tanto, se pierde. 1.4.- TÉCNICAS DE UTILIZACIÓN DEL REGISTRO HISTÓRICO PARA GARANTIZAR LA ATOMICIDAD FRENTE A FALLOS. La estructura más ampliamente utilizada para guardar las modificaciones de una base de datos es el registro histórico. El registro histórico es una secuencia de registros que mantiene un registro de todas las actividades de actualización de la base de datos. Existen varios tipos de registros del registro histórico. Un registro de actualización del registro histórico describe una única escritura en la base de datos y tiene los siguientes campos: • El identificador de la transacción es un identificador único de la transacción que realiza la operación escribir. • El identificador del elemento de datos es un identificador único del elemento de datos que se escribe. Normalmente suele coincidir con la ubicación del elemento de datos en el disco. I.T.C.J. • El valor anterior es el valor que tenía el elemento de datos antes de la escritura. • El valor nuevo es el valor que tendrá el elemento de datos después de la escritura. 15 Bases de Datos II Unidad I Existen otros registros del registro histórico especiales para registrar sucesos significativos durante el procesamiento de una transacción, tales como el comienzo de una transacción y el éxito o aborto de la misma. Se denota como sigue los diferentes tipos de registros del registro histórico. • <Ti iniciada>. La transacción Ti ha comenzado. • < Ti , Xj, V1, V2>. La transacción Ti ha realizado una escritura sobre el elemento de datos Xj . Xj tenía el valor V1 antes de la escritura y tendrá el valor V2 después de la escritura. • < Ti comprometida>. La transacción Ti se ha comprometido. • < Ti abortada>. La transacción Ti ha sido abortada. Cuando una transacción realiza una escritura es fundamental que se cree el registro del registro histórico correspondiente a esa escritura antes de modificar la base de datos. Una vez que el registro del registro histórico existe, se puede realizar la salida de la modificación a la base de datos si se desea. Además, es posible deshacer una modificación que haya salido a la base de datos. Se deshará utilizando el campo valor-anterior de los registros del registro histórico. Para que los registros del registro histórico sean útiles para recuperarse frente a errores del disco o del sistema, el registro histórico debe residir en almacenamiento estable. Por ahora suponemos que cada registro del registro histórico se escribe, tan pronto como se crea, al final del registro histórico en almacenamiento estable. Observar que en el registro histórico se tiene constancia de todas las actividades de la base de datos. Como consecuencia, el tamaño de los datos almacenados en el registro histórico puede llegar a ser extremadamente grande. 1.4.1 Modificación Diferida de la Base de Datos. La técnica de la modificación diferida garantiza la atomicidad de las transacciones mediante el almacenamiento de todas las modificaciones de la base de datos en el registro histórico, pero retardando la ejecución de todas las operaciones escribir de una transacción hasta que la transacción se compromete parcialmente. Hay que recordar que se dice que una transacción se compromete parcialmente una vez que se ejecuta la acción final de la transacción. Se supone que en esta técnica que se describe aquí las transacciones se ejecutan secuencialmente. Cuando una transacción se compromete parcialmente, la información del registro histórico asociada a esa transacción se utiliza para la ejecución de las escrituras diferidas. Si el sistema cae antes de que la transacción complete su ejecución o si la transacción aborta, la información del registro histórico simplemente se ignora. I.T.C.J. 16 Bases de Datos II Unidad I La ejecución de una transacción Ti opera de esta manera: antes de que Ti comience su ejecución se escribe en el registro histórico un registro < Ti inicida>. Una operación escribir (X) realizada por Ti se traduce en la escritura de un nuevo registro en el registro histórico. Finalmente, cuando Ti se ha comprometido parcialmente, se escribe en el registro histórico un registro < Ti comprometida>. Cuando Ti se compromete parcialmente, los registros asociados a ella en el registro histórico se utilizan para la ejecución de las escrituras diferidas. Como puede ocurrir un fallo mientras se lleva a cabo esta actualización, hay que asegurarse de que, antes del comienzo de estas actualizaciones, todos los registro del registro histórico se guardan en almacenamiento estable. Una vez que se ha hecho esto, la actualización real tiene lugar y la transacción pasa al estado comprometido. Obsérvese que la técnica de modificación diferida sólo requiere el nuevo valor de los elementos de datos. Así, se puede simplificar la estructura general de los registros de actualización del registro histórico como ya se vio en el apartado anterior, omitiendo el campo para el valor anterior. Para ilustrar esto reconsiderar el sistema bancario simplificado. Sea T0 una transacción que transfiere 50 Dlls desde la cuenta A a la cuenta B. Esta transacción se define de la manera siguiente: T0: Leer (A) A:= A-50 Escribir (A) Leer (B) B:= B+50 Escribir (B) Sea T1 una transacción que retira 100 Dlls de la cuenta C. Esta transacción se define como T1:Leer (C) C:= C-100 Escribir(C) Supongamos que estas transacciones se ejecutan secuencialmente, primero T0 y después T1, y que los saldos de las cuentas A, B y C antes de producirse la ejecución eran 1000, 2000 y 700 Dlls respectivamente. El fragmento del registro histórico que contiene la información relevante sobre estas dos transacciones se muestra a continuación I.T.C.J. 17 Bases de Datos II Unidad I < T0 iniciada> < T0 A, 950> < T0 B, 450> < T0 comprometida> < T1 iniciada> < T1 C,1100> < T0 comprometida> Figura 1.4.1a Fragmento del registro histórico de la base de datos correspondiente a T0 y T1. Las salidas reales que se producen en el sistema de bases de datos y en el registro histórico como consecuencia de la ejecución de T0 y T1 pueden seguir distintas ordenaciones. Una ordenación posible se presenta en la siguiente figura. Registro Histórico Bases de Datos < T0 iniciada> < T0 A, 950> < T0 B, 2050> < T0 comprometida> A= 950 B= 2050 < T1 iniciada> < T1 C, 600> < T0 comprometida> C= 600 Figura 1.4.1b Estado del Registro Histórico y de la base de datos correspondiente a T1 y T1. Hay que notar que le valor de A se cambia en la base de datos sólo después de que el registro < T0 A, 950> se haya introducido en el registro histórico. Mediante la utilización del registro histórico, el sistema puede manejar cualquier fallo que conduzca a la pérdida de información en el almacenamiento volátil. El esquema de recuperación usa el siguiente procedimiento de recuperación: • Rehacer(Ti ) fija el valor de todos los elementos de datos actualizados por la transacción Ti a los valores nuevos. El conjunto de elementos de datos actualizados por Ti y sus respectivos nuevos valores se encuentran en el registro histórico. I.T.C.J. 18 Bases de Datos II Unidad I La operación rehacer debe ser idempotente, esto es, el resultado de ejecutarla varias veces debe ser equivalente al resultado de ejecutarla una sola vez. Esta característica es fundamental para garantizar un correcto comportamiento incluso si el fallo se produce durante el proceso de recuperación. Después de ocurrir el fallo, el subsistema de recuperación consulta el registro histórico para determinar las transacciones que deben rehacerse. Una transacción Ti debe rehacer si y sólo si el registro histórico contiene los registros <Ti iniciada> y <Ti comprometida >. Así, si el sistema cae después de que la transacción complete su ejecución, la información en el registro histórico se utiliza para restituir el sistema a un estado consistente anterior. 1.4.2 Modificación Inmediata de la Base de Datos. La técnica de modificación inmediata permite realizar la salida de las modificaciones de la base de datos a la propia base de datos mientras que la transacción está todavía en estado activo. Las modificaciones de datos escritas por transacciones activas se denominan modificaciones no comprometidas. En caso de una caída o de un fallo en la transacción, el sistema debe utilizar el campo para el valor anterior de los registros del registro histórico descrito en el punto anterior (1.4.1) para restaurar los elementos de datos modificados a los valores que tuvieran antes de comenzar la transacción. Esta restauración se lleva a cabo mediante la operación deshacer descrita a continuación. Antes de comenzar la ejecución de una transacción Ti, se escribe en el registro histórico el registro <Ti iniciada> . Durante su ejecución, cualquier operación escribir(X) realizada por Ti, es precedida por la escritura en el registro histórico de un registro actualizado apropiado. Cuando Ti se compromete parcialmente se escribe en el registro histórico el registro <Ti comprometida>. Como la información del registro histórico se utiliza para reconstruir el estado de la base de datos, la actualización real de la base de datos no puede permitirse antes de que el registro del registro histórico correspondiente se haya escrito en almacenamiento estable. Por lo tanto, es necesario que antes de la ejecución de una operación de salida(B), se escribe en almacenamiento estables los registros del registro histórico correspondiente a B. Para ilustrarlo considerarse de nuevo el sistema bancario simplificado con la ejecución ordenada de las transacciones T0 y T1, primero T0 y después T1. Las líneas del registro histórico que contienen la información relevante concerniente a estas dos transacciones se muestra en la siguiente figura. < T0 iniciada> < T0 A, 1000 ,950> I.T.C.J. 19 Bases de Datos II Unidad I < T0 B, 2000, 2050> < T0 comprometida> < T1 iniciada> < T1 C, 700, 600> < T0 comprometida> Figura 1.4.2a Fragmento del registro histórico de la base de datos correspondiente a T1 y T1. En la figura 1.4.2b se describe una posible ordenación de las salidas reales que se producen en el sistema de bases de datos y en el registro histórico como consecuencia de la ejecución de T0 y T1. Nótese que esta ordenación no podría obtenerse con la técnica de modificación diferida que se vio en el punto anterior (1.4.1). Registro Histórico Base de Datos < T0 iniciada> < T0 A, 1000 ,950> < T0 B, 2000 , 2050> A=950 B=2050 < T0 comprometida> < T1 iniciada> < T1, C, 700, 600> C=600 < T1 comprometida> Figura 1.4.2b Estado del registro Histórico y de la Base de Datos Correspondiente a T0 y T1. Mediante la utilización del registro histórico, el sistema puede manejar cualquier fallo que no genere una pérdida de información en el almacenamiento no volátil. El esquema de recuperación usa dos procedimientos de recuperación.: • Deshacer(Ti) restaura el valor de todos los elementos de datos actualizados por la transacción Ti a los valores anteriores. • Rehacer(Ti) fija el valor de todos los elementos de datos actualizados por la transacción Ti a los nuevos valores. El conjunto de elementos de datos actualizados por Ti y sus respectivos anteriores y nuevos valores se encuentran en el registro histórico. Las operaciones deshacer y rehacer deben se idempotentes para garantizar un comportamiento correcto incluso en el caso de que el fallo se produzca durante el proceso de recuperación. I.T.C.J. 20 Bases de Datos II Unidad I Después de haberse producido un fallo, el esquema de recuperación consulta el registro histórico para determinar las transacciones que deben rehacerse y las que deben deshacerse. • Una transacción Ti debe deshacerse si el registro histórico contiene el registro <Ti iniciada>, pero no contiene el registro <Ti comprometida>. • Una transacción Ti debe rehacerse si el registro histórico contiene los registros <Ti iniciada> y <Ti comprometida>. 1.4.3 Puntos de Revisión (CheckPoints) . Cuando ocurre un fallo en el sistema se debe consultar el registro histórico para determinar las transacciones que deben rehacerse y las que deben deshacerse. En principio es necesario recorrer completamente el registro histórico para hallar esta información. En este enfoque hay dos inconvenientes principales: 1. El proceso de búsqueda consume tiempo. 2. La mayoría de las transacciones que deben rehacerse de acuerdo con el algoritmo ya tienen escritas sus actualizaciones en la base de datos. Aunque el hecho de volver a ejecutar estas transacciones no produzca resultados erróneos, sí repercutirá en un aumento del tiempo de ejecución del proceso de recuperación. Para reducir este tipo de sobrecarga se introducen los puntos de revisión. Durante la ejecución, el sistema actualiza el registro histórico utilizando una de las dos técnicas antes mencionadas (Modificación Diferida de la Base de Datos y Modificación Inmediata de la Base de Datos). Además, el sistema realiza periódicamente puntos de revisión, en los cuales tiene lugar la siguiente secuencia de acciones: 1. Escritura en almacenamiento estable de todos los registros del registro histórico que residan en ese momento en memoria principal. 2. Escritura en disco de todos los bloques de memoria intermedia que se hayan modificado. 3. Escritura en almacenamiento estable de un registro del registro histórico <revisión>. Mientras se lleva a cabo un punto de revisión no se permite que ninguna transacción realice acciones de actualización, tales como escribir en un bloque de memoria intermedia o escribir un registro del registro histórico. La presencia de un registro <revisión> en el registro histórico permite que el sistema pueda hacer más eficiente su procedimiento de recuperación. Considérese una transacción Ti que se comprometió antes del I.T.C.J. 21 Bases de Datos II Unidad I punto de revisión. Para esa transacción el registro <Ti comprometida> aparece en el registro histórico antes que el registro <revisión>. Todas la modificaciones sobre la base de datos hechas por Ti se deben haber escrito en la base de datos antes del punto de revisión. Así, en el momento de la recuperación, no es necesario ejecutar una operación rehacer sobre Ti. Esta observación permite perfeccionar los esquemas anteriores de recuperación (sigue siendo válido el supuesto de que las transacciones se ejecutan secuencialmente). Cuando se produce un fallo, el esquema de recuperación examina el registro histórico para determinar la última transacción Ti que comenzó su ejecución antes de que tuviera lugar el último punto de revisión. Para encontrar una transacción de este tipo se recorre el registro histórico hacia atrás, esto es, se empieza a buscar por el final del registro histórico hasta que se encuentra el primer registro <revisión> (como se va recorriendo el registro histórico hacia atrás, el registro encontrado corresponde al último registro <revisión> del registro histórico); después se continúa la búsqueda hacia atrás hasta que se encuentra el siguiente registro <Ti iniciada>. Este registro identifica a la transacción Ti. Una vez que ha sido identificada la transacción Ti sólo es necesario aplicar las operaciones rehacer y deshacer a la transacción Ti y a las transacciones Ti que comenzaron su ejecución después que Ti. Sea T este conjunto de transacciones. Puede ignorarse el resto del registro histórico (la parte del principio) y puede borrarse cuando se desee. El conjunto exacto de operaciones de recuperación que han de llevarse a cabo depende de si se está usando la técnica de modificación inmediata o la modificación diferida. Si se emplea la técnica de modificación inmediata, las operaciones de recuperación deben ser las siguientes: • Ejecutar deshacer(Tk) para todas las transacciones Tk de T para las que no exista un registro <Tk comprometida> en el registro histórico. • Ejecutar rehacer(Tk) para todas las transacciones Tk de T para las que aparece un registro <Tk comprometida> en el registro histórico. Obviamente no es necesario aplicar la operación rehacer cuando se está utilizando la técnica de modificación diferida. Como ejemplo considerarse el conjunto de transacciones {T0, T1,..........,T100} de modo que su ejecución se produce en el orden determinado por los subíndices. Suponer que el último punto de revisión tiene lugar durante la ejecución de la transacción T67. Así, durante el esquema de recuperación, sólo deben considerarse las transacciones T67, T68,...................,T100. Será necesario rehacer cada una de ellas si éstas se comprometieron y será necesario deshacerlas en caso contrario. 1.4.3.1 El Proceso CheckPoint. ¿Cuando se escriben en disco las páginas de datos? Los registro de transacciones se escriben cuando se ejecuta la instrucción COMMIT TRAN. Pero ¿cuando se escriben los datos en disco? La respuesta está en el proceso CheckPoint, el cual es el proceso interno que se usa en SQL Server, para “vaciar” (o copiar) las páginas de datos de la memoria hacia disco. El proceso CheckPoint, o punto de comprobación, ayuda a asegurar que la recuperación de las transacciones realizadas no se llevará una cantidad excesiva de tiempo. Después de que tiene lugar un I.T.C.J. 22 Bases de Datos II Unidad I CheckPoint se escribe una entrada en el registro para indicar que todas las páginas modificadas que estaban en memoria se han escrito a disco. Esto le da al proceso de recuperación de SQL server un punto en el registro de transacciones en donde está seguro que no debe buscar transacciones realizadas anteriormente para garantizar una recuperación completa. Hay dos tipos de puntos de comprobación en SQL Server automáticos y manuales. El proceso de punto de comprobación automático se realiza con base en cálculos internos de SQL Server. Con la opción de configuración RECOVERY INTERNAL puede configurar la frecuencia con el cual tendrá lugar el proceso de punto de comprobación. Esta opción especifica en minutos el tiempo máximo que se llevará la recuperación de cada base de datos del sistema. Si SQL Server cree que se llevaría demasiado tiempo recuperar una base de datos emitirá un punto de comprobación automático. Cuando esto sucede todas las páginas de datos modificadas (de esta base de datos) que estén en memoria se escribirán en disco, así como todos los registros de esta base de datos. El proceso de punto de comprobación automático tiene lugar cada 60 segundos, y cicla en cada base de datos para determinar se necesitan que se les aplique un punto de comprobación. El parámetro predeterminado para la opción RECOVERY INTERNAL es cero, lo que significa que SQL Server decidirá cuando necesita un punto de comprobación. Un punto de comprobación automático también sucederá en otras circunstancias. Las primera es cuando ejecute el procedimiento almacenado de sistemas sp_dboption para cambiar una opción de base de datos, en ese momento SQL Server emite automáticamente un punto de comprobación. La segunda es cuando apaga el SQL Server . Puede utilizar el comando SHUTDOWN del Transact-SQL o apagar el servicio MSSQL Server. Nota Hay que tomar en cuenta que en las base de datos que tengan puesta la opción Truncate log on CheckPoint, el proceso de punto de comprobación truncará periódicamente las transacciones realizadas que se encuentren en el registro (o cuando el registro de transacciones se llene). Puede forzar un punto de comprobación manual en cualquier momento tecleando el comando CheckPoint del Transact-SQL. Hay que tomar en cuenta que para ejecutar este comando debe ser de la función db_owner de una base de datos. Cuando se emite un punto de comprobación manual todas las páginas modificadas que están en memoria se vacían hacia el disco, en forma similar a como sucede durante el proceso de punto de comprobación automático. Pero hay que tomar en cuenta que un punto de comprobación manual no tiene efecto sobre un registro de transacciones (excepto por copiar los registro a disco), sin tomar en cuenta si esta puesta la opción de base de datos Truncate log on CheckPoint. 1.4.4 Administración de la Memoria Intermedia (Buffer) . 1.4.4.1 Registro Histórico con Memoria Intermedia. I.T.C.J. 23 Bases de Datos II Unidad I Anteriormente se supuso que se escribe cada registro del registro histórico en almacenamiento estable en el mismo momento de su creación. Esta suposición impone una sobrecarga muy alta en la ejecución del sistema por las siguientes razones. Habitualmente, la unidad de escritura en almacenamiento estable es el bloque. En la mayoría de los casos un registro del registro histórico es mucho más pequeño que un bloque. Así, la escritura de cada registro del registro histórico se traduce en una escritura mucho mayor en el nivel físico. Además de esto, como se vio anteriormente la escritura de un bloque en almacenamiento estable puede involucrar varias operaciones de escritura en el nivel físico. El costo de realizar la escritura en almacenamiento estable de un bloque es suficientemente elevado para que sea deseable escribir de una sola vez varios registro del registro histórico. Para hacer esto se escriben los registros del registro histórico en una memoria intermedia almacenada en la memoria principal en la que permanecen durante un tiempo hasta que se guardan en almacenamiento estable. Se pueden acumular varios registros del registro histórico en la memoria intermedia del registro histórico y escribirse en almacenamiento estable con una sola operación. El orden de los registros del registro histórico en el almacenamiento estable debe ser exactamente el mismo orden en el que fueron escritos en la memoria intermedia del registro histórico. Debido a la utilización de la memoria intermedia en el registro histórico, antes de ser escrito en almacenamiento estable, un registro del registro histórico puede permanecer únicamente en memoria principal (almacenamiento volátil) durante un espacio de tiempo considerable. Como esos registros se perderían si el sistema cayese, es necesario la imposición e nuevos requisitos sobre las técnicas de recuperación para garantizar la atomicidad de las transacciones: • Después de que el registro <Ti comprometida> se haya escrito en almacenamiento estable, las transacción Ti pasa al estado comprometida. • Antes des escribir en almacenamiento estable el registro <Ti comprometida>, todos los registros del registro histórico pertenecientes a la transacción Ti se deben escribir en almacenamiento estable. • Antes de que un bloque de datos en memoria principal se pueda escribir en al base de datos (en almacenamiento no volátil) todos los registros del registro histórico pertenecientes a los datos de ese bloque se deben escribir en almacenamiento estable. Esta última ligadura se denomina regla de registro de escritura anticipada (REA). (Estrictamente, la regla REA sólo necesita que haya sido puesta en almacenamiento estable la información concerniente a la operación deshacer y permite que la información relativa a la operación rehacer pueda escribirse más tarde. La diferencia es relevante en aquellos sistemas en los que la información para rehacer uy deshacer se guarda en registros del registro histórico independientes.) I.T.C.J. 24 Bases de Datos II Unidad I Las reglas anteriores representan situaciones en las que ciertos registros del registro histórico deben haber sido escritos en almacenamiento estable. No se produce ningún problema como resultado de la escritura de los registros del registro histórico antes de que sea necesaria. Así, cuando el sistema decide que es necesario escribir en almacenamiento estable un registro del registro histórico, puede escribir un bloque entero de ellos si hay suficiente registros en memoria principal como para llenar un bloque. Si no hay suficientes registros para llenar el bloque , se forma un bloque parcialmente lleno con todos los registros que hubiera en memoria principal y se ponen en almacenamiento estable. La escritura en disco de la memoria intermedia del registro histórico se denomina a veces forzar el registro histórico. 1.4.4.2 Base de Datos con Memoria intermedia. La base de datos se almacena en almacenamiento no volátil (disco) y, cuando es necesario, se traen a memoria principal los bloques de datos que hagan falta. Como la memoria principal suele ser mucho más pequeña que la base de datos completa, puede ser necesaria la sobreescritura de un bloque B1 se debe escribir antes de traer B2. Si B1 se ha modificado, B1 se debe escribir antes de traer B2. Esta jerarquía de almacenamiento se corresponde con el concepto usual de memoria virtual. Las reglas que rigen la escritura de registros del registro histórico limitan la libertad del sistema para escribir bloques de datos. Si la lectura del bloque B2 provoca que el bloque B1 tenga que escribirse en almacenamiento estable, todos los registros del registro histórico pertenecientes a los datos de B1 se deben escribir en almacenamiento estable antes de la escritura de B1. Por tanto, la secuencia de acciones que ha de llevar a cabo el sistema sería ésta: • Escritura en almacenamiento estable de los registros del registro histórico hasta que todos los registros pertenecientes al bloque B1 se hayan escrito. • Escritura en disco del bloque B1. • Lectura del bloque B2 desde el disco a la memoria principal. Para ilustrar la necesidad del requisito de registro histórico con escritura anticipada considerarse el ejemplo bancario con las instrucciones T0 y T1. Supóngase que el estado del registro histórico es < T0 iniciada> < T0 A, 1000 ,950> y que la transacción T0 realiza una operación leer(B). I.T.C.J. 25 Bases de Datos II Unidad I Supóngase también que el bloque en el que se encuentra B no está en memoria principla y que esa memoria principal está llena. Y por último que el bloque en el que reside A es el elegido para la sustitución y, por tanto, ha de escribirse en disco. Si e sistema escribe este bloque en disco y luego sucede una caída, los valores para las cuentas A, B y C en la base de datos son 950, 2000 y 700 Dlls respectivamente. Este estado de la base de datos es inconsistente. Sin embargo, según los requisitos de la regla REA, el registro del registro histórico < T0 A, 1000 ,950> debe escribirse en almacenamiento estable antes de producirse la escritura del bloque en el que se encuentra A. El sistema puede usar ese registro del registro histórico durante la recuperación para devolver a la base de datos a un estado consistente. I.T.C.J. 26