/// <param name="c">Customer</param> /// <param name="flights">array of flight names</param> /// <param name="location">room location if room is true</param> /// <param name="car">true if request is for a car</param> /// <param name="room">true if request is for a room</param> /// <returns>price of reservation</returns> public bool ReserveItinerary(TP.Customer c, string[] flights, string location, bool car, bool room) { TP.Transaction tid = TransactionManager.Start(); try { if (car) { Cars.Reserve(tid, c, RID.forCar(location)); } if (room) { Rooms.Reserve(tid, c, RID.forRoom(location)); } foreach (string flight in flights) { Flights.Reserve(tid, c, RID.forFlight(flight)); } TransactionManager.Commit(tid); } catch (Exception e) { TransactionManager.Abort(tid); throw; } return(true); }
/// <summary> /* Release a lock of mode _request_ for transaction _context_ * Return if context does not hold a lock for this resource */ /// </summary> 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 || transactionList[context] == null) { // This transaction wasn't registered, return immediately return; } transactionList.Remove(context); for (LockMode l = locked; 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; } } // common case plus special case where we want to convert a read lock to write lock if (request > locked || (this.locked == LockMode.Update && this.transactions[(int)LockMode.Read].Count == 0)) { // if anyone was waiting for this lock, they should recheck this.UnlockEvent.Set(); } }
// Upgrade a read lock to a write lock for the specified transaction. // Returns true if the conversion is successful, returns false otherwise. public bool UpgradeLockRequest(TP.Transaction context, LockMode request) { // There is no need to upgrade the lock if it is not a write request or if the resource is not locked if (request != LockMode.Write || locked == LockMode.Null) { return(false); } // First, deal with the case when the resouce is write-locked if (locked == LockMode.Write) { System.Collections.Hashtable writeTransactionList = this.transactions[(int)LockMode.Write]; // Assume that the write transaction list is not null when the current lock mode is Write if (writeTransactionList == null) { throw new System.ApplicationException("Write transaction list is null even when lock mode is write"); } // There is no need to do anywork if the transaction already has a write lock on the resource. if (writeTransactionList[context] != null) { return(true); } // The lock can't be upgraded if another transaction has a write lock on the resource else if (writeTransactionList.Count > 0) { return(false); } } // Deal with the case when the resource is read-locked else { // Get the list of transactions that hold a read lock on the resource System.Collections.Hashtable readTransactionList = this.transactions[(int)LockMode.Read]; // Assume that the read transaction list is not null when the current lock mode is Write // since the transaction should already have a read lock on the resource. if (readTransactionList == null) { throw new System.ApplicationException("Read transaction list is null even when lock mode is read"); } // We can upgrade the lock only if the transaction is the only one that has a read lock on the resource if (readTransactionList.Count == 1 && readTransactionList[context] != null) { // Acquire the write lock for this resource before releasing the read lock to ensure two-phase locking Register(context, LockMode.Write); Unregister(context, LockMode.Read); return(true); } // The lock can't be upgraded if another transaction has a read lock on the resource else { return(false); } } return(false); }
public bool CancelItinerary(Customer customer) { TP.Transaction tid = TransactionManager.Start(); try { if (Flights != null) { Flights.UnReserve(tid, customer); } if (Cars != null) { Cars.UnReserve(tid, customer); } if (Rooms != null) { Rooms.UnReserve(tid, customer); } TransactionManager.Commit(tid); } catch (Exception e) { TransactionManager.Abort(tid); throw new Exception("caught an exception", e); } return(true); }
// Unlock all resources for the passed in transaction public void UnlockAll(TP.Transaction context) { // Loop over the resources lock (this.ResourceTable) { // Get resource enumerator System.Collections.IDictionaryEnumerator resenum = ResourceTable.GetEnumerator(); // Loop over resources while (resenum.MoveNext()) { ResourceEntry lockTarget = (ResourceEntry)resenum.Value; lock (lockTarget) { // Unregister all unlock modes for current resource 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); }
/* Add a lock of type _request_ for transaction _context_ */ public void Register(TP.Transaction context, LockMode request) { // First get the hash table for this lock mode on this resource entry, if it exists System.Collections.Hashtable transactionList = this.transactions[(int)request]; // If there is no hash table for this lock mode, create one if (transactionList == null) { transactionList = new System.Collections.Hashtable(); this.transactions[(int)request] = transactionList; } // Add the transaction to the list for _request_ lock mode transactionList[context] = context; // Update the strongest lock mode, if necessary if (request > locked) { locked = request; } if (evnt != null) { evnt.Reset(); } }
/* Called by RM. * This method notifies TM that it is involved in a given transaction * TM keeps track of which RM is enlisted with which transaction to do distributed transactions */ /// <summary> /// </summary> /// <param name="context"></param> /// <param name="enlistingRM"> </param> public bool Enlist(TP.Transaction context, string enlistingRM) { var rm = GetResourceMananger(enlistingRM); if (rm == null) { throw new ApplicationException(enlistingRM + " not registered."); } lock (_resourceManagersEnlistedInTransactions) { if (_resourceManagersEnlistedInTransactions.ContainsKey(context)) { var list = _resourceManagersEnlistedInTransactions[context]; if (!list.Contains(rm)) { _resourceManagersEnlistedInTransactions[context].Add(rm); } } else { _resourceManagersEnlistedInTransactions.Add(context, new ResourceManagerList(rm)); } } Console.WriteLine(string.Format("TM: Transaction {0} enlisted for {1}", context.Id, enlistingRM)); return(true); }
public void AddSeatsTwoTransactions() { var wc = new MyWC.MyWC_Accessor(); var tm = new MyTM.MyTM(); var rm = new MyRM.MyRM(); MyWC_Accessor.TransactionManager = tm; rm.SetName("flight"); rm.TransactionManager = tm; tm.Register(rm); MyWC.MyWC.Flights = tm.GetResourceMananger("flight"); var context1 = new Transaction(); var context2 = new Transaction(); wc.AddSeats(context1, "FL_C", 100, 550); wc.AddSeats(context2, "SG_A", 200, 250); wc.Abort(context2); wc.Commit(context1); context1 = new Transaction(); var result = wc.ListFlights(context1); wc.Commit(context1); Assert.IsTrue((from f in result where f == "FL_C,100,550" select f).Any()); Assert.IsFalse((from f in result where f == "SG_A,200,250" select f).Any()); }
/* Add a lock of type _request_ for transaction _context_ */ public void Register(TP.Transaction context, LockMode request) { // First get the hash table for this lock mode on this resource entry, if it exists System.Collections.Hashtable transactionList = this.transactions[(int)request]; // If there is no hash table for this lock mode, create one if (transactionList == null) { transactionList = new System.Collections.Hashtable(); this.transactions[(int)request] = transactionList; } // Add the transaction to the list for _request_ lock mode transactionList[context] = context; // Update the strongest lock mode, if necessary if (request > locked) { locked = request; } // If we set locked mode to Update lock mode, we do not reset // the event because we still want to track the read locks. if (request != LockMode.Update) { this.UnlockEvent.Reset(); } }
// Commit the specified transaction public void Commit(TP.Transaction context) { if (commitFailure) { // Sleep forever if simulate failure flag is set Thread.Sleep(System.Threading.Timeout.Infinite); } // commit transaction this.dataStore.Commit(context); }
// Checks whether the lock request will potentially downgrade the lock for the specified transaction. // Returns true if the request is read lock and specified transaction already has a write lock on the resource public bool DownGradedLockRequest(TP.Transaction context, LockMode request) { System.Collections.Hashtable transactionList = this.transactions[(int)LockMode.Write]; if (request == LockMode.Read && (transactionList != null && transactionList[context] != null)) { return(true); } return(false); }
public void CancelSingleFlight() { var wc = new MyWC.MyWC_Accessor(); var tm = new MyTM.MyTM(); var rmf = new MyRM.MyRM(); var rmc = new MyRM.MyRM(); var rmr = new MyRM.MyRM(); MyWC_Accessor.TransactionManager = tm; rmf.SetName("flight"); rmf.TransactionManager = tm; rmc.SetName("car"); rmc.TransactionManager = tm; rmr.SetName("room"); rmr.TransactionManager = tm; tm.Register(rmf); tm.Register(rmc); tm.Register(rmr); MyWC.MyWC.Flights = tm.GetResourceMananger("flight"); MyWC.MyWC.Cars = tm.GetResourceMananger("car"); MyWC.MyWC.Rooms = tm.GetResourceMananger("room"); MyWC.MyWC.TransactionManager = tm; var context = new Transaction(); wc.AddSeats(context, "SEA-JFK", 1000, 200); wc.Commit(context); var c1 = new Customer(); Assert.IsTrue(wc.ReserveItinerary(c1, new[] { "SEA-JFK" }, "NY", false, false)); context = new Transaction(); Assert.AreEqual(c1, wc.ListCustomers(context)[0]); Assert.IsFalse(String.IsNullOrEmpty(wc.QueryItinerary(context, c1)), "Itinerary not found"); wc.Commit(context); context = new Transaction(); Assert.AreEqual(1000 - 1, wc.QueryFlight(context, "SEA-JFK")); wc.Commit(context); wc.CancelItinerary(c1); context = new Transaction(); Assert.AreEqual(1000, wc.QueryFlight(context, "SEA-JFK")); wc.Commit(context); }
/// <summary> /// Currently does not involve TM, will do it in later step /// </summary> /// <param name="context"></param> public XaResponse Abort(TP.Transaction context) { WaitForReady(); ++NumberAborts; if (NumberAborts >= this.VoteNoOnAbort && this.VoteNoOnAbort != 0) { return(XaResponse.XAER_RMERR); } _transactionStorage.Abort(context); _lockManager.UnlockAll(context); return(XaResponse.XA_OK); }
/// <summary> /// Call from WC in response to a client's commit /// </summary> /// <param name="context"></param> public void Commit(TP.Transaction context) { WaitTillReady(); lock (_resourceManagersEnlistedInTransactions) { if (_resourceManagersEnlistedInTransactions.ContainsKey(context)) { CommitedTransaction trans = TwoPhaseCommit.Commit(context, _resourceManagersEnlistedInTransactions[context]); trans.DoneEvent.WaitOne(TransactionTimeout * 1000); _resourceManagersEnlistedInTransactions.Remove(context); } } Console.WriteLine(string.Format("TM: Transaction {0} commited", context.Id)); }
/// <summary> /// Queries the # of given resource /// </summary> /// <param name="context"></param> /// <param name="rid"></param> /// <returns>returns the amount available for the specified item type */</returns> public int Query(TP.Transaction context, RID rid) { WaitForReady(); Enlist(context); _lockManager.LockForRead(context, rid); Console.WriteLine("RM: Query"); Resource resource = _transactionStorage.Read(context, rid); if (resource == null) { throw new ArgumentException(rid + " does not exist"); } return(resource.getCount()); }
// This function returns the list of RMs associated with the given transaction and // automatically removes the given transaction from the active transaction list private List <string> GetRMListForTransaction(TP.Transaction context) { List <string> output = null; lock (this.activeTransactions) { if (!this.activeTransactions.TryGetValue(context, out output)) { // nothing to do transaction must already have been commited return(null); } // remove from list this.activeTransactions.Remove(context); } return(output); }
/// <summary> /// Currently does not involve TM, will do it in later step /// Call to TM to enlist for distributed transaction /// </summary> /// <param name="context"></param> public void Enlist(TP.Transaction context) { WaitForReady(); try { _transactionManager.Enlist(context, this.GetName()); return; } catch (WebException) { } catch (ApplicationException) { } _transactionManager = null; ReconnectToTM(); WaitForReady(); }
public void AddDeleteCombinationsOneByOne() { var wc = new MyWC.MyWC_Accessor(); var tm = new MyTM.MyTM(); var rmf = new MyRM.MyRM(); var rmc = new MyRM.MyRM(); var rmr = new MyRM.MyRM(); MyWC_Accessor.TransactionManager = tm; rmf.SetName("flight"); rmf.TransactionManager = tm; rmc.SetName("car"); rmc.TransactionManager = tm; rmr.SetName("room"); rmr.TransactionManager = tm; tm.Register(rmf); tm.Register(rmc); tm.Register(rmr); MyWC.MyWC.Flights = tm.GetResourceMananger("flight"); MyWC.MyWC.Cars = tm.GetResourceMananger("car"); MyWC.MyWC.Rooms = tm.GetResourceMananger("room"); var context = new Transaction(); wc.AddSeats(context, "SEA-JFK", 3000, 300); wc.Commit(context); wc.AddCars(context, "NY", 2000, 200); wc.Commit(context); wc.AddRooms(context, "NY", 1000, 100); wc.Commit(context); context = new Transaction(); Assert.AreEqual(200, wc.QueryCarPrice(context, "NY")); Assert.AreEqual(300, wc.QueryFlightPrice(context, "SEA-JFK")); Assert.AreEqual(100, wc.QueryRoomPrice(context, "NY")); wc.Commit(context); }
/// <summary> // Call from WC in response to a client's abort /// </summary> /// <param name="context"></param> public void Abort(TP.Transaction context) { WaitTillReady(); lock (_resourceManagersEnlistedInTransactions) { if (_resourceManagersEnlistedInTransactions.ContainsKey(context)) { var list = _resourceManagersEnlistedInTransactions[context].ResourceManagers; foreach (RM r in list) { r.Abort(context); } _resourceManagersEnlistedInTransactions.Remove(context); } } Console.WriteLine(string.Format("TM: Transaction {0} aborted", context.Id)); }
/// <summary> /// implemented using the new TransactionStorage class /// This method adds a resource to the available ones /// </summary> /// <param name="context"></param> /// <param name="i"></param> /// <param name="count"></param> /// <param name="price"></param> /// <returns></returns> public bool Add(TP.Transaction context, TP.RID i, int count, int price) { WaitForReady(); Enlist(context); _lockManager.LockForWrite(context, i); Resource res = _transactionStorage.Read(context, i); if (res == null) { res = new Resource(i, count, price); } else { res.incrCount(count); res.setPrice(price); } _transactionStorage.Write(context, i, res); return(true); }
// Unlock a resource: find the entry and call unregister lock private void Unlock(TP.Transaction context, TP.Lockable resource, LockMode mode) { ResourceEntry lockTarget; // Get exclusive access to the lock table lock (this.ResourceTable) { this.ResourceTable.TryGetValue(resource, out lockTarget); // Check if the resource wasn't locked, and if so, then return if (lockTarget == null) { return; } } // Get exclusive access to the resource lock (lockTarget) { lockTarget.Unregister(context, mode); } }
/// <summary> /// implemented using the new TransactionStorage class /// </summary> /// <param name="context"></param> /// <param name="rid"></param> /// <returns></returns> public bool Delete(TP.Transaction context, RID rid) { WaitForReady(); Enlist(context); _lockManager.LockForWrite(context, rid); bool removed = _transactionStorage.Delete(context, rid); // drop all reservations on removed resource if (removed) { foreach (Customer c in _transactionStorage.GetCustomers(context)) { _lockManager.LockForWrite(context, c); HashSet <RID> e = _transactionStorage.Read(context, c); e.Remove(rid); _transactionStorage.Write(context, c, e); } } return(removed); }
/// <summary> /* Release a lock of mode _request_ for transaction _context_ * Return if context does not hold a lock for this resource */ /// </summary> 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 || transactionList[context] == null) { // This transaction wasn't registered, return immediately return; } transactionList.Remove(context); locked = LockMode.Null; for (LockMode l = LockMode.Write; l > LockMode.Null; --l) { // recalculate the strongest lock mode System.Collections.Hashtable nextTransactionList = this.transactions[(int)l]; if (nextTransactionList == null) { continue; } if (nextTransactionList.Count > 0) { locked = l; break; } } if (request > locked) { // if anyone was waiting for this lock, they should recheck if (evnt != null) { evnt.Set(); } } }
/// <summary> /// Called by RM. /// This method notifies TM that it is involved in a given transaction /// TM keeps track of which RM is enlisted with which transaction to do distributed transactions */ /// </summary> /// <param name="context"></param> public bool Enlist(TP.Transaction context, string enlistingRM) { // determine if this is an RM we know about this.ValidateRM(enlistingRM); lock (this.activeTransactions) { if (!this.activeTransactions.ContainsKey(context)) { // an RM is trying to enlist in a transaction // the TM knows nothing about - return false return(false); } // Add the RM to the active transaction only if it has not been added already if (!this.activeTransactions[context].Contains(enlistingRM)) { this.activeTransactions[context].Add(enlistingRM); } } System.Console.WriteLine(string.Format("Transaction {0} enlisted", context.Id)); return(true); }
// Prepare the specified transaction public bool Prepare(TP.Transaction context) { // Returns false if failure mode is set to No if (prepareFailure == PrepareFailure.PrepareReturnsNo) { return(false); } // Sleep forever to simulate timeout if failure mode is set to TimesOut else if (prepareFailure == PrepareFailure.PrepareTimesOut) { Thread.Sleep(System.Threading.Timeout.Infinite); } // Otherwise, prepare the transaction and return the result - Prepared(true) or No(false) try { this.dataStore.Prepare(context); } catch (Exception) { return(false); } return(true); }
/// <param name="c">Customer</param> /// <param name="flights">array of flight names</param> /// <param name="location">room location if room is true</param> /// <param name="car">true if request is for a car</param> /// <param name="room">true if request is for a room</param> /// <returns>price of reservation</returns> public bool ReserveItinerary(TP.Customer c, string[] flights, string location, bool car, bool room) { TP.Transaction tid = TransactionManager.Start(); try { if (car) { bool result = Cars.Reserve(tid, c, RID.forCar(location)); if (!result) { throw new InvalidOperationException(); } } if (room) { bool result = Rooms.Reserve(tid, c, RID.forRoom(location)); if (!result) { throw new InvalidOperationException(); } } foreach (string flight in flights) { bool result = Flights.Reserve(tid, c, RID.forFlight(flight)); if (!result) { throw new InvalidOperationException(); } } Commit(tid); } catch (AbortTransationException) { Abort(tid); return(false); } catch (ArgumentException) { Abort(tid); return(false); } catch (DeadLockDetected) { Abort(tid); return(false); } catch (InvalidOperationException) { Abort(tid); return(false); } catch (Exception e) { Abort(tid); throw e; } return(true); }
public void AddDeleteCombinations() { var wc = new MyWC.MyWC_Accessor(); var tm = new MyTM.MyTM(); var rmf = new MyRM.MyRM(); var rmc = new MyRM.MyRM(); var rmr = new MyRM.MyRM(); MyWC_Accessor.TransactionManager = tm; rmf.SetName("flight"); rmf.TransactionManager = tm; rmc.SetName("car"); rmc.TransactionManager = tm; rmr.SetName("room"); rmr.TransactionManager = tm; tm.Register(rmf); tm.Register(rmc); tm.Register(rmr); MyWC.MyWC.Flights = tm.GetResourceMananger("flight"); MyWC.MyWC.Cars = tm.GetResourceMananger("car"); MyWC.MyWC.Rooms = tm.GetResourceMananger("room"); var context = new Transaction(); wc.AddSeats(context, "SEA-JFK", 3000, 300); wc.AddCars(context, "NY", 2000, 200); wc.AddRooms(context, "NY", 1000, 100); wc.Commit(context); context = new Transaction(); Assert.AreEqual(200, wc.QueryCarPrice(context, "NY")); Assert.AreEqual(300, wc.QueryFlightPrice(context, "SEA-JFK")); Assert.AreEqual(100, wc.QueryRoomPrice(context, "NY")); wc.Commit(context); }
// A shortcut to unlock a write lock public void UnlockWrite(TP.Transaction context, TP.Lockable resource) { Unlock(context, resource, LockMode.Write); }
// A shortcut to unlock a read lock public void UnlockRead(TP.Transaction context, TP.Lockable resource) { Unlock(context, resource, LockMode.Read); }
// Get a write lock for the resource public void LockForWrite(TP.Transaction context, TP.Lockable resource) { Lock(context, resource, MyLM.LockMode.Write); }
// Get a read lock for the resource public void LockForRead(TP.Transaction context, TP.Lockable resource) { Lock(context, resource, MyLM.LockMode.Read); }