Commit di una transazione monofase e multifase
[Questo argomento è una versione preliminare della documentazione e può essere soggetto a modifiche nelle versioni future. Sono presenti anche argomenti vuoti, utilizzati come segnaposto].
Ogni risorsa utilizzata in una transazione viene gestita da un gestore di risorse (in seguito indicato con la sigla GR), le cui azioni vengono coordinate da una gestione transazioni (in seguito indicate con la sigla GT). Nell'argomento Integrazione di risorse come partecipanti a una transazione viene descritto come integrare una o più risorse in una transazione. Questo argomento descrive invece come coordinare il commit di una transazione fra le risorse integrate.
Al termine della transazione, l'applicazione richiede che venga eseguito il commit o il rollback della transazione. La gestione transazioni deve eliminare qualsiasi possibilità che si verifichino situazioni di incoerenza, come ad esempio nel caso di una transazione per cui alcuni gestori di risorse votano a favore del commit mentre altri votano a favore del rollback.
Se la transazione interessa più di una risorsa, è necessario eseguire un commit a due fasi. Il protocollo di commit a due fasi, che prevede una fase di preparazione e una fase di commit, garantisce che al termine della transazione venga eseguito coerentemente il commit oppure il rollback di tutte le modifiche apportate alle risorse. Tutti i partecipanti vengono quindi informati in merito al risultato finale. Per informazioni dettagliate sul protocollo 2PC, consultare il libro sui concetti e sulle tecniche di elaborazione delle transazioni scritto da Jim Gray e appartenente alla collana Morgan Kaufmann sui sistemi di gestione dei dati (ISBN:1558601902).
Le prestazioni delle transazioni possono anche essere ottimizzate tramite il protocollo di commit monofase. Per ulteriori informazioni, vedere Ottimizzazione mediante commit monofase e notifica monofase promuovibile.
Se si desidera soltanto ricevere informazioni sul risultato di una transazione senza partecipare alla votazione, è necessario essere registrati all'evento TransactionCompleted.
Protocollo 2PC
Nella prima fase della transazione, la gestione transazioni esegue una query su ogni risorsa allo scopo di determinare se eseguire il commit o il rollback di una transazione. Nella seconda fase della transazione, la gestione transazioni informa ogni risorsa in merito al risultato delle query eseguite, consentendo l'esecuzione delle operazioni di pulizia eventualmente necessarie.
Per poter partecipare a questo tipo di transazione, un gestore di risorse deve implementare l'interfaccia IEnlistmentNotification, che fornisce i metodi chiamati dal GT per l'invio delle notifiche durante un commit a due fasi. Di seguito è riportato un esempio di questa implementazione.
Public Class EnlistmentClass
Implements IEnlistmentNotification
Public Sub Prepare(ByVal myPreparingEnlistment As PreparingEnlistment) Implements System.Transactions.IEnlistmentNotification.Prepare
Console.WriteLine("Prepare notification received")
'Perform transactional work
'If work finished correctly, reply with prepared
myPreparingEnlistment.Prepared()
End Sub
Public Sub Commit(ByVal myEnlistment As Enlistment) Implements System.Transactions.IEnlistmentNotification.Commit
Console.WriteLine("Commit notification received")
'Do any work necessary when commit notification is received
'Declare done on the enlistment
myEnlistment.Done()
End Sub
Public Sub Rollback(ByVal myEnlistment As Enlistment) Implements System.Transactions.IEnlistmentNotification.Rollback
Console.WriteLine("Rollback notification received")
'Do any work necessary when rollback notification is received
'Declare done on the enlistment
myEnlistment.Done()
End Sub
Public Sub InDoubt(ByVal myEnlistment As Enlistment) Implements System.Transactions.IEnlistmentNotification.InDoubt
Console.WriteLine("In doubt notification received")
'Do any work necessary when indout notification is received
'Declare done on the enlistment
myEnlistment.Done()
End Sub
End Class
class myEnlistmentClass : IEnlistmentNotification
{
public void Prepare(PreparingEnlistment preparingEnlistment)
{
Console.WriteLine("Prepare notification received");
//Perform transactional work
//If work finished correctly, reply prepared
preparingEnlistment.Prepared();
// otherwise, do a ForceRollback
preparingEnlistment.ForceRollback();
}
public void Commit(Enlistment enlistment)
{
Console.WriteLine("Commit notification received");
//Do any work necessary when commit notification is received
//Declare done on the enlistment
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
Console.WriteLine("Rollback notification received");
//Do any work necessary when rollback notification is received
//Declare done on the enlistment
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
Console.WriteLine("In doubt notification received");
//Do any work necessary when indout notification is received
//Declare done on the enlistment
enlistment.Done();
}
}
Fase di preparazione (fase 1)
Quando riceve dall'applicazione una richiesta di commit tramite una chiamata al metodo Commit, la gestione transazioni avvia la fase di preparazione di tutti i partecipanti integrati. A tale scopo, chiama il metodo Prepare su ogni risorsa integrata al fine di determinare per ognuna di esse il voto espresso in merito alla transazione.
Come illustrato nel semplice esempio seguente, il gestore di risorse che implementa l'interfaccia IEnlistmentNotification deve prima implementare il metodo Prepare.
public void Prepare(PreparingEnlistment preparingEnlistment)
{
Console.WriteLine("Prepare notification received");
//Perform work
Console.Write("reply with prepared? [Y|N] ");
c = Console.ReadKey();
Console.WriteLine();
//If work finished correctly, reply with prepared
if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))
{
preparingEnlistment.Prepared();
break;
}
// otherwise, do a ForceRollback
else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))
{
preparingEnlistment.ForceRollback();
break;
}
}
Quando il gestore di risorse durevole riceve questa chiamata, deve registrare le informazioni per il ripristino della transazione (disponibili tramite il recupero della proprietà RecoveryInformation) nonché qualsiasi informazione necessaria al completamento della transazione in caso di commit. Non è necessario eseguire questa operazione all'interno del metodo Prepare, in quanto il GR può eseguirla mediante un thread di lavoro.
Dopo aver completato la fase di preparazione, il GR deve votare il commit o il rollback della transazione chiamando rispettivamente il metodo Prepared o il metodo ForceRollback. Si noti che la classe PreparingEnlistment eredita un metodo Done dalla classe Enlistment. Se si chiama questo metodo sul callback PreparingEnlistment durante la fase di preparazione, il GT riceve una notifica in cui si indica che l'integrazione è di sola lettura (ovvero, i gestori di risorse possono leggere ma non aggiornare i dati protetti dalle transazioni) e il GT non informa più il GR in merito al risultato della transazione nella fase 2.
L'applicazione riceve informazioni sull'esito positivo del commit della transazione dopo che tutti i gestori di risorse votano tramite il metodo Prepared.
Fase di commit (fase 2)
Nella seconda fase della transazione, se tutti i GR inviano al GT una conferma di esito positivo relativamente alla fase 1, ovvero se tutti i GR hanno richiamato il metodo Prepared al termine della fase di preparazione, il GT richiama il metodo Commit per ogni gestore di risorse. I gestori di risorse possono quindi rendere definitive le modifiche e completare il commit.
Se almeno uno dei gestori di risorse invia una conferma di esito negativo relativamente alla fase 1, la gestione transazioni richiama il metodo Rollback per ogni gestore di risorse e segnala all'applicazione la non riuscita del commit.
Ne consegue che il gestore di risorse deve implementare i metodi seguenti.
public void Commit (Enlistment enlistment)
{
// Do any work necessary when commit notification is received
// Declare done on the enlistment
enlistment.Done();
}
public void Rollback (Enlistment enlistment)
{
// Do any work necessary when rollback notification is received
// Declare done on the enlistment
enlistment.Done();
}
Il GR deve eseguire tutte le operazioni necessarie per completare la transazione in base al tipo di notifica e quindi informare il GT in merito chiamando il metodo Done sul parametro Enlistment. Queste operazioni possono essere eseguite su un thread di lavoro. Si osservi che nella fase 2 le notifiche possono presentarsi inline nello stesso thread che ha chiamato il metodo Prepared nella fase 1. Ne consegue che, dopo la chiamata al metodo Prepared, non occorre eseguire alcuna operazione (ad esempio il rilascio dei blocchi) che si prevede sia stata completata prima di ricevere le notifiche della fase 2.
Implementazione di InDoubt
Infine, è necessario implementare il metodo InDoubt per il gestore di risorse volatile. Questo metodo viene chiamato se la gestione transazioni perde il contatto con uno o più partecipanti, il cui stato risulta pertanto sconosciuto. In questo caso è necessario registrare questo problema in modo che in un secondo momento sia possibile verificare se uno o più partecipanti della transazione sono rimasti in uno stato incoerente.
public void InDoubt (Enlistment enlistment)
{
// log this
enlistment.Done();
}
Ottimizzazione mediante commit monofase
Il protocollo di commit monofase è più efficiente in fase di esecuzione, poiché tutti gli aggiornamenti vengono eseguiti senza alcuna coordinazione esplicita. Per ulteriori informazioni in merito, vedere Ottimizzazione mediante commit monofase e notifica monofase promuovibile.
Vedere anche
Concetti
Ottimizzazione mediante commit monofase e notifica monofase promuovibile
Integrazione di risorse come partecipanti a una transazione