// 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); } }
// 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); }
/* Lock passed in resource _resource_ in mode _mode_ * This method needs additional code to implement lock conversion. * It does deadlock detection by timeout */ private void Lock(TP.Transaction context, TP.Lockable resource, LockMode mode) { ResourceEntry lockTarget; /* Get exclusive access to the lock table * This avoids race conditions, such as two conflicting locks being granted to concurrent threads (i.e., transactions), * or two physical resources created for one logical resource on behalf of two threads. */ lock (this.ResourceTable) { // Pick the needed resource from ResourceTable this.ResourceTable.TryGetValue(resource, out lockTarget); // Create a ResourceEntry for resource, if there is none if (lockTarget == null) { lockTarget = new ResourceEntry(); this.ResourceTable[resource] = lockTarget; } } for (int c = 0; ; c++) { /* If someone else holds a lock * (the loop already executed once and failed to set the lock) * wait for 5 seconds for the lock to be released and * if it doesn't happen, timeout for deadlock, * else try again to set the lock */ if (c > 0) { if (!lockTarget.UnlockEvent.WaitOne(System.TimeSpan.FromMilliseconds((double)deadlockTimeout), 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)); } // Get exclusive access to the resource lock (lockTarget) { // Set the lock, if you can if (lockTarget.Compatible(mode)) { lockTarget.Register(context, mode); return; } // If the request is read, see if the transaction alreday has a write lock on the resource else if (mode == LockMode.Read && lockTarget.DownGradedLockRequest(context, mode)) { // ‘context’ has a write lock on lockTarget and requested a read lock so no action is required. // return; } // If the request is write and the transaction already has a read lock on the resource, try // to upgrade the read lock to a write lock if no other transactions has a lock on this resource else if (mode == LockMode.Write && lockTarget.UpgradeLockRequest(context, mode)) { return; } } } // Debug throw new System.Exception("Internal Error"); }