WebsiteSpark

Wednesday, 3 April 2013

Developing custom transactional resource managers


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