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

modifica

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

modifica

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

modifica

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

Definizione

modifica

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

modifica

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.

Esempio 1

modifica

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

modifica

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

modifica
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

modifica

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

modifica
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

modifica

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

Bibliografia

modifica

Voci correlate

modifica