El Problema de Control de Concurrencia
Cuando dos o más transacciones se ejecutan concurrentemente, sus operaciones se ejecutan en un modelo intercalado. Esto significa que las operaciones de un programa se ejecutan entre dos operaciones de otro programa. Esta intercalación puede causar que los programas no funcionen correctamente, o interfieran, y de esta manera, dejaría inconsistente a la base de datos. Esta interferencia se debe completamente a la intercalación de las operaciones, puesto que puede ocurrir a pesar de que cada programa funciona correctamente cuando se ejecuta de forma individual y no se presenta falla alguna en el sistema. El objetivo del control de concurrencia es evitar la interferencia y, por ende, los errores.
Veamos algunos ejemplos para entender cómo es que los programas pueden interferir con otros. Volviendo al ejemplo del banco, supongamos que tenemos un programa llamado Depositar, el cual deposita dinero en una cuenta.
Cuando dos o más transacciones se ejecutan concurrentemente, sus operaciones se ejecutan en un modelo intercalado. Esto significa que las operaciones de un programa se ejecutan entre dos operaciones de otro programa. Esta intercalación puede causar que los programas no funcionen correctamente, o interfieran, y de esta manera, dejaría inconsistente a la base de datos. Esta interferencia se debe completamente a la intercalación de las operaciones, puesto que puede ocurrir a pesar de que cada programa funciona correctamente cuando se ejecuta de forma individual y no se presenta falla alguna en el sistema. El objetivo del control de concurrencia es evitar la interferencia y, por ende, los errores.
Veamos algunos ejemplos para entender cómo es que los programas pueden interferir con otros. Volviendo al ejemplo del banco, supongamos que tenemos un programa llamado Depositar, el cual deposita dinero en una cuenta.
Procedure Depositar (Cuenta, Monto)
begin
Start;
temp := Leer(Cuentas[Cuenta]);
temp := temp + Monto;
Escribir(Cuentas[Cuenta],temp);
Commit;
temp := Leer(Cuentas[Cuenta]);
temp := temp + Monto;
Escribir(Cuentas[Cuenta],temp);
Commit;
end
Supongamos que la cuenta 7 tiene un saldo de US$1000 y que el cliente 1 deposita US$100 en la cuenta 7 en el mismo instante en el que el cliente 2 deposita US$100000 en la cuenta 7. Cada uno de los clientes llama al procedimiento Depositar de tal manera que se crea una transacción para realizar su actualización. La ejecución concurrente de éstos depósitos produce una secuencia de lecturas y escrituras en la base de datos, tales como
Leer1(Cuentas[7]) devuelve el valor de US$1000
Leer2(Cuentas[7]) devuelve el valor de US$1000
Escribir2(Cuentas[7], US$101000
Commit2
Escribir1(Cuentas[7], US$1100)
Commit1
Leer2(Cuentas[7]) devuelve el valor de US$1000
Escribir2(Cuentas[7], US$101000
Commit2
Escribir1(Cuentas[7], US$1100)
Commit1
El resultado de esta ejecución es que la Cuenta[7] contiene US$1100. A pesar que el depósito del cliente 2 concluyó satisfactoriamente, la interferencia con la ejecución de Depósito del cliente 1 causó que el depósito del cliente 2 se pierda. Este fenónemo de actualización perdida ocurre cuando dos transacciones, mientras intentan modificar un dato, ambas leen el valor antiguo del elemento antes que ninguna haya modificado su valor.
Otro problema del control de concurrencia se ilustra con el siguiente programa, llamado ImprimirSuma, el cual imprime la suma de los saldos de dos cuentas.
Otro problema del control de concurrencia se ilustra con el siguiente programa, llamado ImprimirSuma, el cual imprime la suma de los saldos de dos cuentas.
Procedure ImprimirSuma(Cuenta1, Cuenta2)
begin
Start;
temp1 := Leer(Cuentas[Cuenta1]);
output(temp1);
temp2 := Leer(Cuentas[Cuenta2]);
output(temp2);
temp1 := temp1 $+$ temp2;
output(temp1);
Commit;
temp1 := Leer(Cuentas[Cuenta1]);
output(temp1);
temp2 := Leer(Cuentas[Cuenta2]);
output(temp2);
temp1 := temp1 $+$ temp2;
output(temp1);
Commit;
end
Supongamos que las cuentas 8 y 9 tiene un saldo de US$200 cada una, y que el cliente 3 imprime los saldos de las cuentas 8 y 9 (utilizando ImprimirSuma) en el mismo instante en el que el cliente 4 transfiere US$100 de la cuenta 8 a la cuenta 9 (utilizando Transferir). La ejecución concurrente de estas dos transacciones puede originar la siguiente ejecución de operaciones de la base de datos.
Leer4(Cuentas[8]) devuelve el valor de US$200
Escribir4(Cuentas[8], US$100)
Leer3 (Cuentas[8]) devuelve el valor de US$100
Leer3 (Cuentas[9]) devuelve el valor de US$200
Leer4 (Cuentas[9]) devuelve el valor de US$200
Escribir4 (Cuentas[9], US$300)
Commit4
Commit3
Escribir4(Cuentas[8], US$100)
Leer3 (Cuentas[8]) devuelve el valor de US$100
Leer3 (Cuentas[9]) devuelve el valor de US$200
Leer4 (Cuentas[9]) devuelve el valor de US$200
Escribir4 (Cuentas[9], US$300)
Commit4
Commit3
El procedimiento Transferir interfiere con ImprimirSuma en esta ejecución, causando que ImprimirSuma imprima el valor de US$300, la cual no es la suma correcta de los saldos de las cuentas 8 y 9. El procedimiento ImprimirSuma no capturó los US$100 en tránsito de la cuenta 8 a la cuenta 9. Es importante recalcar que, a pesar de la interferencia, Transferir todavíia asigna los valores correctos en la base de datos.
Este tipo de interferencia se denomina análisis inconsistente que ocurre cuando una transacción lee un dato antes que otra transacción lo actualice y lea otro dato después que la misma transacción lo ha actualizado. Es decir, la extracción (lectura) de los datos sólo percibe algunos de los resultados de la transacción de actualización.
Para conseguir el objetivo del control de concurrencia se utiliza un sincronizador. Un sincronizador es un programa (o una colección de ellos) que controla la ejecución concurrente de las transacciones; su función radica en ordenar las operaciones que forman parte de las transacciones que se requieren ejecutar concurrentemente, de tal manera que la ejecución resultante sea correcta. Usando tres operaciones básicas (ejecución, rechazo y retraso de una operación) el sincronizador puede controlar el orden en el cual las operaciones son ejecutadas por el Administrador de Datos (DM). Cuando éste recibe una operación de la transacción (mediante el TM), usualmente trata de pasarla al DM inmediatamente, si no produce alguna ejecución incorrecta. Si el sincronizador decide que la ejecución de la operación puede producir resultados incorrectos, puede o retrasarla (en caso de que pueda procesar correctamente la operación más adelante) o rechazarla (si no es posible procesarla en el futuro de tal manera que produzca resultados correctos).
Por ejemplo, retomemos la ejecución concurrente de dos transacciones Depositar, que depositan US$100 y US$100,000 en la cuenta 7
Este tipo de interferencia se denomina análisis inconsistente que ocurre cuando una transacción lee un dato antes que otra transacción lo actualice y lea otro dato después que la misma transacción lo ha actualizado. Es decir, la extracción (lectura) de los datos sólo percibe algunos de los resultados de la transacción de actualización.
Para conseguir el objetivo del control de concurrencia se utiliza un sincronizador. Un sincronizador es un programa (o una colección de ellos) que controla la ejecución concurrente de las transacciones; su función radica en ordenar las operaciones que forman parte de las transacciones que se requieren ejecutar concurrentemente, de tal manera que la ejecución resultante sea correcta. Usando tres operaciones básicas (ejecución, rechazo y retraso de una operación) el sincronizador puede controlar el orden en el cual las operaciones son ejecutadas por el Administrador de Datos (DM). Cuando éste recibe una operación de la transacción (mediante el TM), usualmente trata de pasarla al DM inmediatamente, si no produce alguna ejecución incorrecta. Si el sincronizador decide que la ejecución de la operación puede producir resultados incorrectos, puede o retrasarla (en caso de que pueda procesar correctamente la operación más adelante) o rechazarla (si no es posible procesarla en el futuro de tal manera que produzca resultados correctos).
Por ejemplo, retomemos la ejecución concurrente de dos transacciones Depositar, que depositan US$100 y US$100,000 en la cuenta 7
Leer1 (Cuentas[7]) devuelve el valor de US$1000
Leer2 (Cuentas[7]) devuelve el valor de US$1000
Escribir2 (Cuentas[7], US$101000)
Commit2
Escribir1(Cuentas[7], US$1100)
Commit1
Leer2 (Cuentas[7]) devuelve el valor de US$1000
Escribir2 (Cuentas[7], US$101000)
Commit2
Escribir1(Cuentas[7], US$1100)
Commit1
Para evitar esta ejecución incorrecta, un sincronizador debe decidir rechazar Escribir1 provocando que la transacción T1 sea cancelada. En este caso, el usuario o el Administrador de Transacciones puede reenviar T1 , la cual ahora se puede ejecutar sin interferir con T2. Como otra alternativa, el sincronizador puede prevenir la ejecución anterior retrasando Leer2 hasta que reciba y procese Escribir1 y de esta forma evitando que se rechace Escribir1 más adelante.
Por lo tanto, un DBMS que controla la ejecución concurrente de sus transacciones tiene una estructura como la siguiente :
Por lo tanto, un DBMS que controla la ejecución concurrente de sus transacciones tiene una estructura como la siguiente :
No hay comentarios:
Publicar un comentario