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); // } } }