Sistemas de recuperação

Um sistema de computador está sujeito a falhas das mais diversas (elétrica, quebra de disco, erro de lógica…). E numa dessas, as informações da empresa podem ser perdidas. Para garantir que as propriedades da atomicidade e durabilidade das transações em um banco de dados sejam satisfeitas, os sistemas de banco de dados utilizam esquemas de recuperação.

Os esquemas de recuperação são responsáveis pela restauração do banco de dados para um estado consistente que havia antes da falha.

As falhas podem ser dos tipos:

  • falha de transação: Podem ser causadas por:
    • erros lógicos: a transação não pode continuar sua execução normal devido a uma falha interna do sistema, como por exemplo, dados não encontrados, overflow (estouro de memória) e programação incorreta do sistema. Mesmo que a transação seja reexecutada, o problema continuará ocorrendo.
    • erros de sistema: o sistema entra em um estado inadequado (deadlock) e com isso, a transação não consegue continuar sua execução normal. A transação pode ser reexecutada posteriormente.
  • Queda do sistema: algum mal-funcionamento no hardware ou software que causa a perda do conteúdo armazenado em meio volátil e faz com que o processamento da transação pare. O conteúdo armazenado em meio não-volátil permanece intacto.
  • falha de disco: um bloco de disco perde seu conteúdo em função da quebra do cabeçote ou de falha durante uma traferência de dados, por exemplo.

Para assegurar a consistência do banco de dados e a atomicidade da transação, após uma falha, devem ser usados algoritmos de recuperação. Estes algoritmos dependem do tipo da falha e de como os dados foram afetados por ela.

Eles possuem duas partes:

  • ações tomadas durante o processamento normal da transação a fim de garantir que haja informação suficiente para permitir a recuperação das falhas.
  • ações tomadas após a falha, recuperando o conteúdo do banco de dados para um estado que assegure sua consistência, a atomicidade da transação e sua durabilidade.

Alguns tipos de recuperação:

Backups

Para recuperar dados após uma falha de disco, por exemplo. O arquivo corrompido ou inconsistente é substituído por uma cópia anterior consistente. Problema: dependendo da periodicidade, a cópia pode não estar totalmente atualizada.

Recuperação baseada em log

O log é uma sequência de registros que mantém um arquivo atualizado das atividades executadas no banco de dados. Um registro de log descreve uma única ação no banco de dados e tem os seguintes valores:

  • identificador da transação (identificador único da transação que realizou a operação de escrita)
  • Identificador do item de dado (identificador único do dado – normalmente é a localização do item de dado no disco )
  • valor antigo
  • valor novo

Um log grava também:

  • start: indica o início da transação
  • commit: indica que a transação foi efetivada
  • abort: indica que a transação foi abortada

O log pode ser gravado em dois momentos: antes da execução da transação ou depois da execução da transação. Entretetanto,  se ocorrer uma falha logo após a gravação do log e antes da execução da transação, no primeiro caso, ou logo após a execução da transação e antes da gravação do log, no segundo caso, como o sistema de recuperação sabe o que deverá ser recuperado?

Para mitigar este problema, as modificações no banco de dados podem ser adiadas ou gravadas imediatamente. Existe ainda a possibilidade de inclusão de checkpoints, separando o que já foi gravado do que ainda não foi.

Modificações adiadas do banco de dados

Garante a atomicidade das transações, quando todas as modificações são escritas no log, adiando a execução das operações de escrita até sua efetivação parcial.

*Efetivação parcial: todas as operações da transação foram executadas, mas ela ainda pode ser abortada. (Não foi feito o commit ainda)*

Quando uma transação é parcialmente efetivada, as informações no log associadas àquela transação são usadas para a execução das escritas adiadas. Se ocorrer uma falha, então as informações do log serão ignoradas.

Seja Ti uma transação que será executada.

Um registro <Ti, start> é escrito no log antes da execução de Ti ser iniciada. Uma operação de escrita de Ti resulta no registro <Ti, write> no log. Quando Ti é parcialmente efetivada, um registro <Ti, commit> é escrito no log. Somente após este registro, a efetivação é iniciada.

Exemplo: Sejam T0 e T1 transações executadas serialmente, e T0 é executada antes de T1. Os valores nas contas A, B e C, são respecctivamente 1000, 2000 e 700

 T0:

Le(A)

A=A-50

Escreve(A)

Le(B)

B=B+50

Escreve(B)

T1:

Le(C)

C=C-100

Escreve(C)

 O log ficaria assim:

<T0, start>

<T0, A, 950>

<T0, B, 2050>

<T0, commit>

<T1, start>

<T1, C, 600>

<T1, commit>

 A execução poderia ser assim:

Log                                         BD

<T0, start>

<T0, A, 950>

<T0, B, 2050>

<T0, commit>

<T1, start>

<T1, C, 600>

<T1, commit>

                                               A=950

                                               B=2050

                                               C=600

 O esquema de recuperação usa a operação redo(Ti)(refazer), que redefine o valor de todos os itens de dados atualizados pela transação Ti para os novos valores. Estes valores estão no log.

Executar a operação redo(Ti) diversas vezes deve ser equivalente a executa-la apenas uma. Isso garante que os dados poderão ser recuperados mesmo que ocorra uma falha durante a recuperação.

Somente as transações que tiverem os registros de <Ti, start> e <Ti, commit> poderão ser refeitas.

Para o exemplo anterior, se ocorrer uma falha logo após a escrita de B, sem o registro do <T0, commit>. Não será executado o Redo(T0) e os registros da transação incompleta devem ser removidos do log.

Se ocorrer uma falha logo após <T0, commit> e antes de <T1, start>, será executado o Redo(T0). O Redo (T1) não será executado e os registros da transação incompleta serão removidos do log.

Se ocorrer uma falha após <T1, commit>, serão executados o Redo(T0) e Redo(T1). Se ocorrer uma falha durante a recuperação, o Redo será reexecutado.

Modificações imediatas do banco de dados

As modificações no banco de dados são enviadas enquanto as transações estão ativas, antes delas serem parcialmente efetivadas. As escritas no banco de dados, neste caso, são não-efetivadas. A atualização real não pode ocorrer antes que o dado seja escrito em uma unidade de armazenamento estável.

O registro do log deve ser feito antes da execução de cada operação e deve conter:

  1. O <Ti, start> antes do ínicio da execução da transação
  2. O registro da operação de escrita contendo:
    1. A transação que está sendo executada
    2. O identificador do item de dado
    3. O valor antigo
    4. O valor novo
    5. Quando Ti é parcialmente efetivada, deve ser registrado no log o <Ti, commit>

Este modo de recuperação possui 2 operações:

  1. Redo: refaz as transações que foram parcialmente efetivadas (o start e o commit foram escritos no log)
  2. Undo: desfaz as transações que não foram parcialmente efetivadas (o start e o commit não foram escritos no log)

Estas operações devem ter o comportamento correto mesmo se ocorrer uma falha durante o processo de recuperação.

Exemplo: Seja o log a seguir, da execução das transações T0 e T1:

<T0, start>

<T0, A, 950>

<T0, B, 2050>

<T0, commit>

<T1, start>

<T1, C, 600>

<T1, commit>

Uma possível execução seria:

Log BD
<T0, start>  
<T0, A, 950>  
<T0, B, 2050>  
  A=950
  B=2050
<T0, commit>  
<T1, start>  
<T1, C, 600>  
  C=600
<T1, commit>  

 Se acontecesse uma falha logo após a escrita de B no armazenamento estável, quando o sistema se recuperar, ele encontra o registro de start de T0 no log, mas não encontra o registro de commit de T0.  Nesse caso, será executada a operação de Undo(T0).

Log
<T0, start>
<T0, A, 950>
<T0, B, 2050>

 Se acontecesse uma falha logo após a escrita de c no armazenamento estável, quando o sistema se recuperar, ele encontra os registros de start de T0 e T1 no log, mas não encontra o registro de commit de T1. Encontra apenas o de T0.  Nesse caso, será executada a operação de Undo(T1) e Redo (T0), nesta ordem.

Log
<T0, start>
<T0, A, 950>
<T0, B, 2050>
<T0, commit>
<T1, start>
<T1, C, 600>
 

 Se ocorrer uma falha apóps o registro de <T1, commit>, serão executadas as operações de Redo (T0) e Redo (T1), nesta ordem.

Checkpoint

 Como saber o que deve ser refeito e/ou desfeito, caso ocorra uma falha durante a execução das transações? Refazer todas as transações do log (seja ele escrito usando as modificações adiadas ou imediatas) pode ser muito caro e demorado.  Para resolver este problema, usam-se pontos de controle (Checkpoints).

Quando o SGBD estiver se recuperando de uma falha, o log é percorrido do final para o início para encontrar a Ti anterior ao último checkpoint. Ao encontrar uma instrução <checkpoint> , o esquema de recuperação continua sendo percorrido retroativamente até encontrar a próxima instrução <Ti, start>. Ele então executa as operações de Redo e Undo (se for o caso) de Ti e todas as transações Tj que vierem depois de Ti. A parte anterior a Ti do log pode ser ignorada ou apagada.

Deixe um comentário