Sezioni critiche eseguite in mutua esclusione => in certi casi (basi di dati) è preferibile che le operazioi siano compiute del tutto, o non compiute affatto.
7.10.1 Modello del sistema
Transazione = insieme di operazioni che eseguono un'unica funzione logica => il problema è preservare l'atomicità nonostante i guasti.
Transazione: composta da read e write, e seguita da commit o abort.
Una transazione abortita può aver modificato dei dati => rollback ad uno stato consistente precedente.
Le periferiche di archiviazione sono classificate, rispetto a questa visione, in:
- archivio volatile
- archivio non volatile
- archivio stabile = astrazione, ovviamente nella realtà non si può dare niente per scontato
7.10.2 Recupero basato sui log

The Log Lady
Log = registro in cui sono registrate tutte le modifiche effettuate; salvato in memoria stabile.
Ogni record nel log descrive un'operazione di scrittura e ha i seguenti campi:
- nome della transazione
- nome dell'oggetto modificato
- vecchio valore
- nuovo valore
Esistono poi diversi tipi di record:
- inizio transazione
- commit della transazione
Write-ahead logging = prima di eseguire una scrittura, modifico il log.
Con il log si possono ripristinare tutti i dati:
- undo(Ti) = ripristina tutte le cose modificate dalla transazione Ti
- redo(Ti) = ripete tutte le cose fatte dalla transazione Ti
Undo e redo sono idempotenti = più esecuzioni della stessa operazione devono dare luogo allo stesso risultato.
Se una transazione fa abort, si esegue undo(Ti).
Se c'è un guasto, le transazioni vengono messe in 2 gruppi:
- se la transazione i ha un begin nel log, ma non un commit, faccio l'undo
- se la transazione i ha un begin ed un commit, faccio il redo
7.10.3 Punti di verifica
Quando c'è un guasto, non parto dall'inizio del log, ma dall'ultimo punto di verifica = checkpoint.
Checkpoint = eseguito periodicamente. Salva nel log:
- scrive i record del log ancora in memoria volatile, in memoria stabile
- scrive tutti i dati modificati in memoria volatile
- scrive un record <checkpoint> nel log
Quando accade un guasto:
- si torna all'ultimo checkpoint
- trovo:
- l'ultima transazione che è iniziata ma non committata prima del checkpoint
- tutte le operazioni iniziate dopo il checkpoint
- faccio il redo di tutte le transazioni che hanno un commit nel log dopo il checkpoint
- faccio l'undo di tutte le transazioni che non hanno un commit nel log dopo il checkpoint
7.10.4 Transazioni atomiche concorrenti
Serializzabilità = l'esecuzione concorrente di un gruppo di transazioni deve essere equivalente all'esecuzione delle stesse transazioni in un qualsiasi ordine seriale.
Gli algoritmi di controllo della concorrenza si occupano di questa proprietà.
7.10.4.1 Serializzabilità
Schedulazione = sequenza di esecuzione di transazioni.
Schedulazione seriale = sequenza di istruzioni di varie transazioni, in cui le istruzioni di una transazione appaiono insieme.
=> n transazioni => n! schedulazioni seriali valide.
Una schedulazione non seriale non è necessariamente non corretta, ma deve essere equivalente ad una schedulazione seriale per essere corretta.
Per verificare ciò, uso il concetto di conflitto tra operazioni = due operazioni sono in conflitto se
- appartengono a transazioni diverse
- accedono allo stesso dato
- almeno una delle due è una scrittura
Una schedulazione non seriale è equivalente ad una schedulazione seriale se presenta gli stessi conflitti => è valida = conflict serializable.
7.10.4.2 Protocollo di lock
Si associa a ciascun dato un lock e ogni transazione deve rispettare il protocollo di lock.
Su di un dato, una transazione può ottenere:
- lock condiviso (S = shared) = può leggere ma non scrivere
- lock esclusivo (X = exclusive) = può leggere e scrivere
Se il lock chiesto è disponibile, viene concesso, altrimenti la transazione aspetta.
Il protocollo di lock a 2 fasi prevede che le richieste di lock e gli unlock siano eseguiti in 2 fasi distinte:
- fase di crescita = una transazione ottiene lock ma non può rilasciarli
- fase di contrazione = una transazione può rilasciare i lock ma non può ottenerne di nuovi.
Quando una transazione rilascia il primo lock, entra nella fase di contrazione e non può richiederne altri, anche su altri dati.
Il protocollo di lock a 2 fasi assicura serializzabilità ma non l'assenza di stalli.
7.10.4.3 Protocolli basati su marche di tempo
Si assegna una marca di tempo = timestamp unica e fissa ad ogni transazione, in ordine crescente (le si possono ricavare dal clock del computer o da un contatore).
Ciascun dato possiede due marche di tempo:
- WTM = la marca di tempo più elevata tra quelle delle transazioni che hanno eseguito scritture sul dato
- RTM = la marca di tempo più elevata tra quelle delle transazioni che hanno eseguito letture sul dato
Le operazioni di read e write devono rispettare le marche di tempo:
- read
- se il ts della transazione che vuole leggere è inferiore al WTM, viene rifiutata perché troppo vecchia
- se no viene accettata, e l'RTM viene aggiornato al maggiore tra il ts di questa transazione ed il valore precedente
- write
- se il ts della transazione che vuole scrivere è inferiore al WTM o al RTM, viene rifiutata perché troppo vecchia
- viene aggiornato il WTM
Garantisce serializzabilità, anche se in modo più restrittivo rispetto al lock a 2 fasi (alcune schedulazioni accettat dal lock a 2 fasi sono rifiutate dal protocollo basato sui timestamp).
Inoltre, assicura anche l'assenza di stalli.