namespace MyRM
{
///
/// Base implementation of intreface LM--see TP.LM
/// Doesn't do locGk conversions,
///so T1(read) -> T1(write) will cause T1
///to deadlock with itself.
///
public class MyLM : TP.LM
{
///
///the lock table
///
System.Collections.Hashtable ResourceTable;
///
/// Exception when the resource is locked
///
public class ResourceLocked : System.Exception
{
///
/// Constructor
///
public ResourceLocked() : base()
{
}
///
/// Constructor
///
public ResourceLocked( string message ) : base( message )
{
}
///
/// Constructor
///
public ResourceLocked( string message, System.Exception e ) : base( message, e )
{
}
}
///
/// Exception for Deadlock
///
public class DeadLockDetected : System.Exception
{
///
/// Constructor
///
public DeadLockDetected() : base()
{
}
///
/// Constructor
///
public DeadLockDetected( string message ) : base( message )
{
}
///
/// Constructor
///
public DeadLockDetected( string message, System.Exception e ) : base( message, e )
{
}
}
///
/// _Length represents the number of LockModes
///
public enum LockMode
{
Null, /// Null
Read, ///Read Mode
SharedWrite, ///Shared Mode
Write, ///Write Mode
Exclusive, ///Exlusive Lock
_Length /// the number of LockModes
}
static bool [,] CompatibilityTable = new bool[ (int) MyLM.LockMode._Length, (int)MyLM.LockMode._Length ]
{
{ // Null
true, true, true, true, true
},
{ // Read
true, true, false, false, false
},
{ // SharedWrite
true, false, true, false, false
},
{ // Write
true, false, false, false, false
},
{ // Exclusive
true, false, false, false, false
}
};
class ResourceEntry
{
///
/// A ResourceEntry is a lock entry in the lock table. It includes a hash table,
/// "transactions", for each lock mode, containing transactions holding lock in that mode,
/// and a field "locked" containing the strongest lock mode held by any transaction on this resource.
///
public ResourceEntry() // the constructor
{
this.transactions = new System.Collections.Hashtable[ (int) MyLM.LockMode._Length];
this.locked = MyLM.LockMode.Null;
}
///
/// can a LockMode lock request be granted?
///
///
/// true if request can be granted; false otherwise
public bool Compatible( LockMode request )
{
return CompatibilityTable[ (int)this.locked, (int)request];
}
///
/// Add a lock of mode "request" for transaction "context"
///
///
///
public void Register( TP.Transaction context, LockMode request )
{
// First get the hash table for this lock mode, if it exists
System.Collections.Hashtable transactionList = this.transactions[(int)request];
if( transactionList == null )
{
// no hash table for this lock mode, so create one
transactionList = new System.Collections.Hashtable();
this.transactions[(int)request] = transactionList;
}
transactionList[context] = context;
if( request > locked ) // update the strongest lock mode, if necessary
locked = request;
if( evnt != null)
evnt.Reset();
}
///
/// Release a lock of mode "request" for transaction "context"
///
///
///
public void Unregister( TP.Transaction context, LockMode request )
{
// First get the hash table for this lock mode
System.Collections.Hashtable transactionList = this.transactions[(int)request];
if( transactionList == null )
return; // wasn't registered;
transactionList.Remove( context );
for( LockMode l = request; l > LockMode.Null ; locked = --l )
{
// recalculate the strongest lock mode
System.Collections.Hashtable nextTransactionList = this.transactions[(int)l];
if( nextTransactionList == null )
continue;
if( nextTransactionList.Count > 0 )
break;
}
if( request > locked )
if( evnt != null )
evnt.Set(); // if anyone was waiting for this lock, they should recheck
}
System.Threading.ManualResetEvent evnt;
public System.Threading.ManualResetEvent UnlockEvent
{
get
{
lock(this)
{
if(evnt == null)
evnt = new System.Threading.ManualResetEvent(false);
}
return evnt;
}
}
System.Collections.Hashtable [] transactions; // one entry for each LockMode
LockMode locked;
}
///
/// Constructor
///
public MyLM()
{
this.ResourceTable = new System.Collections.Hashtable();
}
///
///NEED TO ADD CODE STEP 1
///Lock a resource
///
void Lock( TP.Transaction context, TP.RS resource, LockMode mode )
{
ResourceEntry lockTarget;
lock(this.ResourceTable) // get exclusive access to the lock table
{
lockTarget = (ResourceEntry) this.ResourceTable[resource];
if( lockTarget == null ) // create a ResourceEntry for resource, if there is none
{
lockTarget = new ResourceEntry();
this.ResourceTable[resource] = lockTarget;
}
}
for( int c = 0;; c++)
{
if( c > 0 ) // 5 second timeout for deadlock
if( !lockTarget.UnlockEvent.WaitOne( 5000, false ))
throw new DeadLockDetected( string.Format( "Resource {0} timed out" , resource ));
if( c > 0 )
System.Console.WriteLine( string.Format( "Attempt {0} in resource {1}", c, resource ));
lock( lockTarget ) // get exclusive access to the ResourceEntry
{
if( lockTarget.Compatible( mode )) // set the lock, if you can
{
lockTarget.Register( context, mode );
return;
}
//WHAT IF YOU CAN'T? ADD CODE TO ATTEMPT CONVERSION CODE HERE
}
}
throw new System.Exception( "Internal Error" );
}
///
///
///
///
///
public void LockForRead( TP.Transaction context, TP.RS resource)
{
Lock( context, resource, MyLM.LockMode.Read );
}
///
///
///
///
///
public void LockForWrite( TP.Transaction context, TP.RS resource)
{
Lock( context, resource, MyLM.LockMode.Write );
}
///
///
///
///
///
///
public void Unlock( TP.Transaction context, TP.RS resource, LockMode mode )
{
ResourceEntry lockTarget;
lock(this.ResourceTable) // get exclusive access to the lock table
{
lockTarget = (ResourceEntry) this.ResourceTable[resource];
if( lockTarget == null )
return; // wasn't locked
}
lock( lockTarget )
{
lockTarget.Unregister( context, mode );
}
}
///
///
///
///
///
public void UnlockRead( TP.Transaction context, TP.RS resource )
{
Unlock( context, resource, LockMode.Read );
}
///
///
///
///
///
public void UnlockWrite( TP.Transaction context, TP.RS resource )
{
Unlock( context, resource, LockMode.Write );
}
///
/// Unlock all resources for this transaction
///
/// The transaction
public void UnlockAll( TP.Transaction context )
{
//
//loop thru' resource entries
lock (this.ResourceTable)
{
System.Collections.IDictionaryEnumerator resenum = ResourceTable.GetEnumerator();
while (resenum.MoveNext())
{
ResourceEntry lockTarget = (ResourceEntry) resenum.Value;
//unregister all unlock modes
for (int lockMode= (int)LockMode.Read; lockMode < (int)LockMode._Length; lockMode++)
{
lockTarget.Unregister (context, (LockMode)lockMode);
}
}
}
System.Console.WriteLine ("----Unlocked all for Tx: {0}--------", context.Id);
//
}
}
}