Developing custom transactional resource managers
Transactional resource managers are the resource managers,
which takes part in the transaction (ambient transaction) and depending upon
the end result of the transaction, either they commit or does a roll back
action and bring the corresponding object to the consistent state in case of a
commit, it’s the new state whereas in case of rollback it’s the previous
consistent state.
There are two kinds of transactional resource managers, 1) persistent,
where the data or the end result is persisted on to disk for further usage or
2) transient, in which case the data is held in memory, but in a consistent
state.
The transaction we are talking about is two-phase-commit
transaction where in the first phase is getting ready with data and the second
phase is to execute the commit operation when instructed to do so.
Example of persistent transactional resource managers are
database transaction classes and same thing could be developed for say XML or a
text file say when the transaction commits successfully, then the values are
persisted to disk else rolled back.
Here we will develop a custom transient transactional
resource manager, the same thing could be extended to work with persistent
resources as well.
The interface which every transactional resource manager has
to implement is IEnlistmentNotification , under System.Transactions namespace,
defined as given below
namespace
System.Transactions
{
public interface IEnlistmentNotification
{
void Commit(Enlistment
enlistment);
void InDoubt(Enlistment
enlistment);
void Prepare(PreparingEnlistment
preparingEnlistment);
void Rollback(Enlistment
enlistment);
}
}
|
This interface defines four functions, which are Commit, Rollback, Prepare and InDoubt. The resource manager has
to implement these functions to take appropriate actions when the resource
manager gets instruction for a Commit, a Rollback, to be Prepared for or when
the ambient transaction was not able to resolve the state of current
transaction.
A commit is sent when the ambient transaction is intimated to
Complete the operation before moving out of scope. A rollback when the
execution control goes out of scope of the ambient transaction, without
executing or instructing the ambient transaction to set Complete. Prepare is
executed every time when the resource manager enlists with an ambient
transaction and finally InDoubt when the state of ambient transaction cannot be
resolved.
Here is a small windows form based application program to
demonstrate the transitional or volatile transaction manager class and the
class in action.
Volatile
object class, which implements IEnlistmentNotification
|
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using
System.Threading.Tasks;
using
System.Transactions;
namespace VollatilObject
{
public class VolatileElement<T> : IEnlistmentNotification
{
T
_oldValue = default(T);
T
__newValue = default(T);
public VolatileElement()
{}
void Enlist()
{
if(Transaction.Current
!= null)
Transaction.Current.EnlistVolatile(this, EnlistmentOptions.None);
}
public T Value {
get { return _oldValue; }
set {
Enlist();
__newValue = value;
}
}
public T NewValue
{
get { return __newValue; }
}
public T OldValue
{
get { return _oldValue; }
}
public void Commit(Enlistment
enlistment)
{
_oldValue = __newValue;
enlistment.Done();
}
public void InDoubt(Enlistment
enlistment)
{
enlistment.Done();
}
public void Prepare(PreparingEnlistment
preparingEnlistment)
{
preparingEnlistment.Prepared();
}
public void Rollback(Enlistment
enlistment)
{
enlistment.Done();
}
}
}
|
The windows
form application
|
using System;
using
System.Collections.Generic;
using
System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using
System.Threading.Tasks;
using
System.Windows.Forms;
using VollatilObject;
using
System.Transactions;
namespace TransactionClient
{
public partial class Form1 : Form
{
VolatileElement<int> intElem = new VolatileElement<int>();
VolatileElement<string> strElem = new VolatileElement<string>();
public Form1()
{
InitializeComponent();
}
private void btnCommit_Click(object sender, EventArgs e)
{
using (TransactionScope ts = new TransactionScope())
{
int tmp = 0;
if (!int.TryParse(txtInt.Text, out tmp))
MessageBox.Show("Please
enter an integet value");
intElem.Value = tmp;
strElem.Value = txtString.Text;
ts.Complete();
}
PrintOldValues();
}
private void
btnRollback_Click(object sender, EventArgs e)
{
using (TransactionScope ts = new TransactionScope())
{
int tmp = 0;
if (!int.TryParse(txtInt.Text, out tmp))
MessageBox.Show("Please
enter an integet value");
intElem.Value = tmp;
strElem.Value = txtString.Text;
ts.Dispose();
}
PrintOldValues();
}
protected void PrintOldValues()
{
txtIntOld.Text = intElem.OldValue.ToString();
txtStringOld.Text = strElem.OldValue;
}
private void button1_Click(object sender, EventArgs e)
{
int tmp = 0;
if (!int.TryParse(txtInt.Text, out tmp))
MessageBox.Show("Please enter an integet value");
intElem.Value = tmp;
strElem.Value = txtString.Text;
PrintOldValues();
}
}
}
|
|
No comments:
Post a Comment