Proprietà ACID/Controllo di affidabilità

Da Wikiversità, l'apprendimento libero.
lezione
lezione
Proprietà ACID/Controllo di affidabilità
Tipo di risorsa Tipo: lezione
Materia di appartenenza Materia: Basi di dati 2
Avanzamento Avanzamento: lezione completa al 100%

Il controllo di affidabilità (in inglese reliability control) è la componente del DBMS che si occupa di garantire le proprietà A (atomicità) e D (persistenza) delle proprietà ACID. I suoi compiti principali possono essere riassunti con:

  • Garanzia di persistenza dei dati in memoria
  • Garanzia di atomicità delle transazioni
  • Gestione dei buffer
  • Ripristino del funzionamento dopo un guasto hardware o software

Per effettuare queste operazioni utilizza un cosiddetto file di log.

Le memorie nel DBMS[modifica]

Possiamo suddividere le memorie che il DBMS usa in:

  • memoria principale: solitamente la memoria RAM della macchina, dove le operazioni avvengono e i dati vengono processati;
  • memoria di massa: le memorie persistenti anche dopo uno spegnimento della macchina, dove i dati vengono salvati, ma non sono considerate "sicure" in quanto possono danneggiarsi.
  • memoria stabile: una memoria astratta che non può essere danneggiata dove viene salvato il file di log. Ovviamente questa memoria non esiste, ma viene opportunamente simulata. La simulazione può essere software (tecniche di scrittura ridondati) oppure hardware (uso combinato di dischi fissi e dischi a nastro). Il danneggiamento alla memoria stabile è considerato un evento catastrofico e a cui non è previsto porvi rimedio.

Uso della memoria centrale[modifica]

I dati sono segmentati in pagine sia su disco che in memoria centrale (in questo ultimo caso trovano posto nel buffer pool). Il DBMS esegue le operazioni di caricamento e scaricamento da memoria centrale a memoria di massa.

Le operazioni eseguibili dalle componenti del DBMS (che verranno poi interpretate dal gestore dei buffer) sono:

  • FIX: sposta una pagina da memoria di massa al buffer pool
  • UNFIX: segnala che la pagina è ora libera e non più necessaria per ora
  • USE: richiesta di utilizzo di una pagina che è già presente nel buffer
  • SET DIRTY: indica che una pagina è stata modificata e andrà ricopiata in memoria di massa
  • FORCE: obbliga il gestore dei buffer a trasferire il prima possibile la pagina in memoria di massa

Il gestore dei buffer a sua discrezione può poi chiamare:

  • FLUSH: trasferimento di una pagina in memoria di massa, a discrezione del gestore dei buffer.

Policy del buffer[modifica]

Il gestore di buffer può adottare diverse tipologie di policy per la gestione della memoria:

  • STEAL oppure NO STEAL: nel primo caso in caso di mancanza di pagine libere o in attesa di essere spostate alla memoria centrale, alcune pagine vengono "rubate" a una transazione in esecuzione e assegnate alla transazione che ne ha fatto richiesta; nel secondo caso alla transazione richiedente viene negata la possibilità di avere una pagina.
  • FORCE oppure NO FORCE: nel primo caso le pagine modificate vengono sempre trasferite in memoria centrale dopo il commit; nel secondo caso il gestore di buffer deciderà arbitrariamente quando spostarle.

Inoltre due ottimizzazioni possono essere introdotte:

  • PRE-FETCHING: anticipa il caricamento delle pagine vicine a quella richiesta. Questo può ottimizzare nel caso in cui la transazione richieda di accedere a dati vicini in modo sequenziale
  • PRE-FLUSHING: anticipa la scrittura in memoria centrale delle pagine su cui ormai è stata chiamata la primitiva UNFIX (senza dover attendere che lo faccia la primitiva FIX).

Schema a blocchi della primitiva FIX[modifica]

Schema a blocchi del funzionamento della primitiva FIX.
Schema a blocchi del funzionamento della primitiva FIX.

Log delle transazioni[modifica]

Il file di log detto in inglese transaction log è un file sequenziale scritto su memoria stabile. Esso contiene la sequenza di operazioni svolte sulla base di dati dalle transazioni, scritte in modo ordinato (temporalmente) e sequenziale. Il suo compito principale è quello di recuperare la base di dati a seguito di un guasto (di qualsiasi natura, hardware o software). L'ultimo blocco inserito nel log è chiamato top.

Tipi di record log[modifica]

Possiamo dividere i tipi di record di log in due categorie:

  • Log di transazione: registrano le operazioni effettuate dalle transazioni sulla base di dati (con ovvio significato)
    • BEGIN B (Transaction)
    • COMMIT C (Transaction)
    • ABORT A (Transaction)
    • UPDATE U (Transaction, Object identifier, Before State, After State)
    • INSERT I (Transaction, Object identifier, After State)
    • DELETE D (Transaction, Object identifier, Before State)
  • Log di sistema: registrano operazioni eseguite dal sistema, in questo caso dal controllore di affidabilità (verranno approfondite più avanti)
    • CHECKPOINT CHECK (T1, T2, T3, ...)
    • DUMP DUMP ()

Esempio[modifica]

Sia T1 una transazione che effettua un UPDATE sull'oggetto O1 portandolo dallo stato S1 allo stato S2. Allora nel log verrà scritto:

  • BEGIN (T1)
  • UPDATE (T1, O1, S1, S2)
  • COMMIT (T1)

Possono generarsi tre casi:

  1. la transazione va a buon fine
  2. la transazione fallisce prima del commit oppure raggiunge uno stato di rollback oppure avviene un guasto prima del commit: operazione eseguita UNDO (T1)
  3. avviene un guasto dopo il commit: operazione eseguita REDO (T1)

Si noti che i comandi UNDO e REDO godono di proprietà di idempotenza:

  • UNDO (UNDO (T1)) = UNDO (T1)
  • REDO (REDO (T1)) = REDO (T1)

Regole di transazione[modifica]

Per garantire l'efficacia del log devono essere rispettate due regole:

  • la regola write-ahead-log: la parte del record del log Before State deve essere scritta in memoria stabile PRIMA di effettuare l'operazione di scrittura o cancellazione sul database (in questo modo è sempre possibile annullare le operazioni)
  • la regola commit-precedence: la parte del record del log After State deve essere scritta in memoria stabile PRIMA di effettuare il COMMIT. (in questo modo è sempre possibile rifare le operazioni)

Checkpoint[modifica]

Il checkpoint è un'operazione che viene svolta periodicamente dal gestore di affidabilità per registrare lo stato attuale delle transizioni attive. Lo scopo principale è velocizzare e semplificare le operazioni di ripristino a seguito di un guasto. Per eseguire il checkpoint il gestore di affidabilità sospende tutte le operazioni di commit, abort e scrittura di tutte le transazioni; successivamente invoca un comando FORCE e scrive in modo sincrono nel log il checkpoint. Successivamente il normale funzionamento può riprendere e le transazioni vengono "liberate".

Dump[modifica]

Il dump è operazione di tipo politico cioè viene decisa dagli amministratori del sistema e autonomamente dal DBMS. Consiste nel copiare l'intera base di dati su supporti considerati stabili e può essere effettuata solo quando il sistema è inattivo (nel fine settimana o di notte). Successivamente viene scritto in modo sincrono nel log il record corrispondente.

Tipi di guasto[modifica]

Guasto di sistema[modifica]

Il guasto di sistema detto anche soft failure è la perdita di dati in memoria centrale dovuta a un problema software (bug, crash del sistema, ecc.) oppure da interruzione di dispositivi hardware (ad esempio cali di tensione). Questi guasti portano la base di dati in uno stato inconsistente, mantenendo però validi i dati in memoria di massa.

Guasto di dispositivo[modifica]

Il guasto di dispositivo detto anche hard failure è la perdita di dati in memoria di massa e in memoria centrale (si noti che i dati in memoria centrale in caso di guasto di quella di massa non possono essere ritenuti affidabili). Sarà poi l'analisi del log (scritto su memoria stabile) a dover ricostruire la base di dati in memoria di massa prima del riavvio del servizio DBMS.

Reazione ai guasti[modifica]

Il ripristino del sistema può essere di due tipi: ripresa a caldo o warm restart se avviene a seguito di un guasto di sistema, oppure ripresa a freddo o cold restart se avviene a seguito di un guasto di dispositivo.

Ripresa a caldo[modifica]

La ripresa a caldo è articolata in quattro fasi:

  1. Checkpoint-search: si cerca l'ultimo checkpoint effettuato nel log a partire dal blocco di top;
  2. Si costruiscono due insiemi: REDO-set e UNDO-set, i quali contengono le transazioni che hanno già superato il commit e quelle che non lo hanno superato. Queste ultime saranno da annullare, mentre le prime da rifare;
  3. Si applicano le azioni per l'UNDO delle transazioni nell'omonimo set, scorrendo il log all'indietro. Si noti che il log può essere analizzato anche prima del checkpoint;
  4. Infine si applicano le azioni per il REDO delle transazioni da rifare.

Ripresa a freddo[modifica]

La ripresa a freddo è articolata in tre fasi:

  1. Accesso al dump: si accede all'ultimo dump della base di dati e si cerca la copia dei dati danneggiati;
  2. Correzione dei dati: attraverso il log si ricostruisce lo stato dei dati, riportandoli all'ultimo valore antecedente il guasto;
  3. Si esegue una ripresa a caldo.