8. Controle de Concorrência

 

O principal objetivo do controle de concorrência do banco de dados é assegurar que a execução concorrente de transações não resulte em perda da consistência do banco de dados. Como muitos SGBDs são sistemas que permitem quaisquer números de transações para acessar o banco de dados, é necessário um mecanismo de controle de concorrência para assegurar que as transações concorrentes não interfiram em outra operação.

 

Este controle é encontrado através de vários mecanismos aos quais nos referiremos como esquemas de controle de concorrência.

 

8.1. Escalonamentos

 

Quando diversas transações rodam concorrentemente, a consistência do banco de dados pode ser destruída apesar da correção de cada transação individual. Nesta seção será apresentado o conceito de seriabilidade para ajudar a identificar aquelas execuções que são garantidas para assegurar a consistência.

 

8.1.2.      Escalonamentos Seriais e Não-Seriais

 

Digamos que T0 e T1 sejam duas transações que transferem fundos de uma conta para outra. A transação T0 transfere R$50 da conta A para a conta B e é definido como:

T0:       read(A);

            A := A - 50;

            write(A);

            read(B);

            B := B + 50;

            write(B).

 

A transação T1 transfere 10% do saldo da conta A para a conta B e é definido como:

T1:       read(A);

            temp := A* 0,1;

            A := A - temp;

            write(A);

            read(B);

            B := B + temp;

            write(B).

 

Digamos que A e B tenham R$ 1000 e R$ 2000 respectivamente. Se executarmos T0 seguido por T1, no fim da execução A e B terão R$ 855 e R$2145 respectivamente. Assim, a quantia total de dinheiro nas contas A e B, isto é A + B, é preservada depois da execução das duas transações.

 

Da mesma forma, se a sequência de execução for T1 seguida por T0, A + B é preservada, e os valores finais de A e B são R$ 850 e R$ 2150 respectivamente.

 

As sequências acimas são ditas “escalonamentos”.  Elas representam a ordem cronológica na qual as instruções são executadas no sistema. Logicamente, um schedule para um conjunto de transações precisa consistir em todas as instruções dessas transações e precisa preservar a ordem na qual as instruções aparecem em cada instrução individual. Por exemplo, na transação T0, a instrução write(A) precisa aparecer antes da instrução read(B).

 

Os escalonamentos descritos acima são chamados “escalonamentos seriais”. Cada schedule serial consiste em uma sequência de instruções de várias transações na qual as instruções pertencentes a uma única transação aparecem juntas naquele schedule.Assim, para um conjunto de n transações, exitem n! Diferentes Escalonamentos seriais válidos.

 

Quando diversas transações são executadas concorrentemente, o schedule correspondente não precisa ser mais serial. Assim, o número de schedules possíveis para um conjunto de n transações é muito maior que n!. Voltando ao nosso exemplo anterior, suponha que duas transações sejam executadas concorrentemente. Diversas sequências de execução são possiveis, uma vez que as várias instruções das duas transações agora podem ser intercaladas. Um schedule destes é mostrado a seguir. Depois da execução deste schedule, a ordem de A + B é realmente preservada.

 

To

T1

                read(A);

                A := A - 50;

                write(A);

 

 

                read(A);

                temp := A* 0,1;

                A := A - temp;

                write(A);

                read(B);

                B := B + 50;

                write(B).

 

 

                read(B);

                B := B + temp;

                write(B).

 

Nem todas as execuções concorrentes resultam num estado correto. Para ilustrar, considere o schedule não-serial a seguir. Depois da execução deste schedule, chegamos a um estado no qual os valores finais das contas A e B são R$ 950  e R$ 2100, respectivamente. Este estado final é um estado inconsistente, uma vez que ganhamos R$ 50 no processo de execução concorrente. Realmente a soma de A + B não é realmente preservada pela execução das duas transações.

 

To

T1

                read(A);

                A := A - 50;

 

 

                read(A);

                temp := A* 0,1;

                A := A - temp;

                write(A);

              read(B);

            write(A);  

            read(B);

            B := B + 50;

                write(B).

 

 

                B := B + temp;

                write(B).

 

De forma clara, um schedule, depois de executado, precisa deixar o banco de dados em um estado consistente. Além do mais, o efeito de um schedule poderia ser um que teria ocorrido sem nenhuma execução concorrente. Isto é, o schedule deve, em todo caso, ser equivalente a um schedule serial.

 


 

8.2. Protocolos baseados em bloqueios

 

Um modo de assegurar a seriabilidade na execução de transações é requerer que o acesso aos itens de dados seja feito de uma maneira mutuamente exclusiva; isto é, enquanto uma transação acessa um item de dado, nenhuma outra transação pode modificar aquele item. O método mais comum usado para implementar isto é permitir a uma transação acessar um item de dado apenas se ela está concorrentemente mantendo um bloqueio naquele item.

 

8.2.1. Bloqueios

 

Existem vários modos no qual um item de dado pode ser bloqueado. Nesta seção, restringimos nossa atenção a dois modos:

 

v     Partilhado: Se uma transação Ti obteve um bloqueio no modo partilhado (representado por P) no item Qi, então Ti pode ler este item mas não pode gravar Q.

 

v     Exclusivo: Se uma transação Ti obteve um bloqueio no modo exclusivo (representado por E) no item Qi, então Ti pode ler e gravar Q.

 

A seguir, será mostrada uma matriz de compatibilidade dos modos de bloqueios.

 

 

Compartilhado

Exclusivo

Compartilhado

Verdadeiro

falso

Exclusivo

falso

falso

Repare que o modo partilhado é compatível com o modo partilhado, mas não é com o modo e xclusivo. A qualquer momento, diversos bloqueios do modo partilhado podem ser mantidos simultaneamente (por transações diferentes) em um mesmo item de dado particular. Uma requisição bloqueio subsequente do modo exclusivo tem de esperar até  que o bloqueio do modo compartilhado corrente seja solto.

 

Uma transação requer um bloqueio partilhado num item de dado Q executando a instrução lock-P(Q). Da mesma forma, um bloqueio exclusivo é requisitado através da instrução lock-E(Q). O item de dado pode ser desbloqueado através da instrução unlock(Q).

 

Para ilustrar, considere novamente nosso sistema bancário simplificado. Digamos que A e B sejam duas contas que são acessadas pelas transações T7 e T8. A transação T7 transfere R$50,00 da conta B para a conta A, e é definida como:

 

T7:       lock-P(B);

read(B);

B := B - 50;

unlock(B);

lock-E(A);

read(A);

A := A + 50;

write (A);

unlock(A)

 

Em algumas situações, pode-se ter impasses (deadlock). Quando ocorre um impasse, o sistema precisa repetir uma das duas transações.

Free Web Hosting