# Dirty read

In informatica con il termine dirty read, o uncommitted dependency, si intende un errore nella gestione della concorrenza tra transazioni dovuta ad una dipendenza write → read.
Il dirty read è una perdita di modifiche in una base di dati causato da una dipendenza di una transazione da un'altra non completata con successo con conseguente lettura di dati incoerenti.

## Definizione

Si è in presenza di dirty read quando una transazione Ta legge un dato X con versione 0, denotato come X(0), ne produce una nuova versione X(1) che viene letta da un'altra transazione Tb, ma X(1) non permane al termine dell'esecuzione Ta.

## Cascading abort

Quando una transazione Ta fallisce, il recovery manager ne elimina gli effetti, in particolare i dati modificati dalla transazione abortita e da tutte le altre transazioni che hanno effettuato dirty read.
In questo caso si verifica una catena di fallimenti di transazioni alterate da Ta noto come cascading abort.

## Recoverability

Al fine di ovviare i problemi dei cascading abort si introduce il concetto di Recoverability, ripristinabilità.

### Definizione

Una transazione T è Recoverable se le viene impedito di eseguire il commit prima che tutte le transazioni, che scrivono valori letti da T, eseguano commit o abortiscano.

## Avoiding Cascading Abort

La recoverability evita di far fallire transazioni che abbiano eseguito il commit. Tuttavia non rimuove il cascading abort per transazioni attive.
Per evitarlo è sufficiente impedire la dirty read ritardando ogni lettura di un dato di cui altre transazioni operino write. La lettura sarà possibile solo al commit delle transazioni scriventi.

## Esempi
### Esempio 1

Consideriamo il seguente schema funzionale:
| Tempo | Transazione Ta | Transazione Tb |
| t(0) | read[X(0)] | |
| t(1) | write[X(1)] | |
| t(2) | | read[X(1)] |
| t(3) | rollback | |
La transazione Tb vede il valore X(1) al tempo t(2) che di fatto non esiste, in quanto al tempo t(3) il valore verrà ripristinato a X(0). La lettura eseguita da Tb pertanto non è corretta.

### Esempio 2

Il problema del dirty read può presentarsi anche in assenza di rollback:
| Tempo | Transazione Ta | Transazione Tb |
| t(0) | read[X(0)] | |
| t(1) | write[X(1)] | |
| t(2) | | read[X(1)] |
| t(3) | read[X(1)] | |
| t(4) | write[X(2)] | |
In questo caso Tb legge il valore X(1) che però è incoerente in quanto la versione finale sarà X(2).

### Esempio di cascading abort

| Tempo | Transazione Ta | Transazione Tb |
| t(0) | read[X(0)] | |
| t(1) | write[X(1)] | |
| t(2) | | read[X(1)] |
| t(3) | | read[Y(0)] |
| t(4) | | write[Y(1)] |
| t(5) | | |
| t(6) | rollback | |
Poiché Ta subisce il rollback, viene ripristinato il valore X(0). Dato che Tb ha eseguito una dirty read, anche le sue operazioni verranno annullate ripristinando il valore Y(0).

### Esempio di cascading abort con commit di Tb

Il problema nasce nel caso in cui Tb esegua il commit a t(5):
| Tempo | Transazione Ta | Transazione Tb |
| t(0) | read[X(0)] | |
| t(1) | write[X(1)] | |
| t(2) | | read[X(1)] |
| t(3) | | read[Y(0)] |
| t(4) | | write[Y(1)] |
| t(5) | | commit |
| t(6) | rollback | |
In questo caso il recovery manager ha due possibilità operative:
* Lasciare permanenti i prodotti di Tb, violando però la semantica della read.
* Annullare gli effetti prodotti da Tb, violando la semantica del commit ed violando la durability (Vedi ACID) delle committed transaction.

### Esempio di recoverability

| Tempo | Transazione Ta | Transazione Tb |
| t(0) | read[X(0)] | |
| t(1) | write[X(1)] | |
| t(2) | | read[Y(0)] |
| t(3) | | read[X(1)] |
| t(4) | | write[Y(1)] |
| t(5) | | |
| t(6) | commit | |
| t(7) | | commit |
Al tempo t(5) vi è una richiesta di commit di Tb. Questa richiesta viene ritardata in quanto l'esecuzione di Tb legge dati alterati da Ta. Solo il commit di Ta rende possibile quello di Tb al tempo successivo.

### Esempio di Avoiding Cascade Abort

Riportiamo la tabella dell'esempio precedente:
| Tempo | Transazione Ta | Transazione Tb |
| t(0) | read[X(0)] | |
| t(1) | write[X(1)] | |
| t(2) | | read[Y(0)] |
| t(3) | | read[X(1)] |
| t(4) | | write[Y(1)] |
| t(5) | commit | |
| t(6) | | commit |
L'esecuzione è Recoverable ma non evita Avoiding Cascade Abort. Ritardando la lettura di X(i) da parte di Tb viene risolto il problema:
| Tempo | Transazione Ta | Transazione Tb |
| t(0) | read[X(0)] | |
| t(1) | write[X(1)] | |
| t(2) | | read[Y(0)] |
| t(3) | commit | |
| t(4) | | read[X(1)] |
| t(5) | | write[Y(1)] |
| t(6) | | commit |