/// <summary> /// Date: 10/16/2011 /// Adds a lock on behalf of a transaction to the active locks. /// </summary> /// <param name = "transactionId">The transaction id.</param> /// <param name = "operationMode">The operation mode.</param> /// <remarks> /// Side effects: the new lock is added to the table entry /// </remarks> public void AddToActiveLocks(int transactionId, Enumerations.OperationMode operationMode) { Lock lockToAdd = new Lock(transactionId, operationMode); Lock result = ActiveLocks.Find(matching => matching.TransactionId == transactionId && matching.Mode == operationMode); if (result == null) ActiveLocks.Add(lockToAdd); }
/// <summary> /// 11/7/2011 /// Checks whether a write lock requests conflicts with existing locks. /// In the case that the item is locked due to recovery, we unlock the item and return false i.e. there are no conflicts. /// </summary> /// <param name = "requestedLock">The requested lock.</param> /// <param name = "entry">The lock table entry to test.</param> /// <returns>True if the requested write lock conflicts with any existing locks</returns> /// <remarks> /// Side effect: if the lock was held by the LM due to recovery, the lock will be removed /// </remarks> private bool WriteLockConflicts(Lock requestedLock, LockManagerTableEntry entry) { int? conflictingTransaction = entry.FindConflictsToWriteLock(requestedLock.TransactionId); if (conflictingTransaction == null) return false; if (conflictingTransaction == int.MinValue) { entry.RemoveLock(int.MinValue); return false; } return true; }
/// <summary> /// Date: 10/16/2011 /// Checks whether a lock request conflicts with existing locks /// </summary> /// <param name = "requestedLock">The requested lock.</param> /// <param name = "entry">The lock entries entry corresponding to the data item the lock wishes to lock.</param> /// <returns>true if requested lock conflicts with any existing locks</returns> internal bool LockConflicts(Lock requestedLock, LockManagerTableEntry entry) { if (requestedLock.Mode == Enumerations.OperationMode.Read) { if (!ReadLockConflicts(requestedLock, entry)) return false; } else if (requestedLock.Mode == Enumerations.OperationMode.Write) { if (!WriteLockConflicts(requestedLock, entry)) return false; } return true; }
/// <summary> /// 11/7/2011 /// Checks whether a read lock request conflicts with existing locks. /// </summary> /// <param name = "requestedLock">The requested lock.</param> /// <param name = "entry">The entry.</param> /// <returns>True if the requested read lock conflicts with any existing locks</returns> private bool ReadLockConflicts(Lock requestedLock, LockManagerTableEntry entry) { int? conflictingTransaction = entry.FindConflictsToReadLock(requestedLock.TransactionId); if (conflictingTransaction == null) { return false; } return true; }
public void LockConflictsTest() { LockManager target = new LockManager(); int transId = 1; int dataItem = 1; target.Lock(transId, dataItem, Enumerations.OperationMode.Read); Lock test = new Lock(transId, Enumerations.OperationMode.Read); // lock never conflicts with a lock from its own transaction Assert.IsFalse(target.LockConflicts(test, target.lockEntries[dataItem])); test = new Lock(transId, Enumerations.OperationMode.Write); Assert.IsFalse(target.LockConflicts(test, target.lockEntries[dataItem])); test = new Lock(2,Enumerations.OperationMode.Read); // two read locks do not conflict Assert.IsFalse(target.LockConflicts(test, target.lockEntries[dataItem])); test = new Lock(2, Enumerations.OperationMode.Write); // A read lock conflicts with a write lock Assert.IsTrue(target.LockConflicts(test, target.lockEntries[dataItem])); transId = dataItem = 2; target.Lock(transId, dataItem, Enumerations.OperationMode.Write); // lock never conflicts with a lock from its own transaction Assert.IsFalse(target.LockConflicts(test, target.lockEntries[dataItem])); test = new Lock(transId, Enumerations.OperationMode.Read); Assert.IsFalse(target.LockConflicts(test, target.lockEntries[dataItem])); // a write lock or read lock from another transaction always conflicts with an active write lock transId = 1; test = new Lock(transId, Enumerations.OperationMode.Read); Assert.IsTrue(target.LockConflicts(test, target.lockEntries[dataItem])); test = new Lock(transId, Enumerations.OperationMode.Write); Assert.IsTrue(target.LockConflicts(test, target.lockEntries[dataItem])); // reset everything and just test that a recovered lockmanager denies read locks until a write op comes in target = new LockManager(); // mock up what happens in a recovery - this is covered in a unit test in Site for (int i = 2; i <= 20; i += 2) { target.lockEntries[i] = new LockManagerTableEntry(); target.lockEntries[i].ActiveLocks.Add(new Lock(int.MinValue, Enumerations.OperationMode.Write)); } // try to issue a read op transId = 1; dataItem = 2; test = new Lock(transId, Enumerations.OperationMode.Read); Assert.IsTrue(target.LockConflicts(test, target.lockEntries[dataItem])); // issue a write op which will work test = new Lock(transId, Enumerations.OperationMode.Write); Assert.IsFalse(target.LockConflicts(test, target.lockEntries[dataItem])); }