private void GrantLocks() { bool lockGranted = false; LockRequest request = null; // Lock the list of active locks to be sure no other thread grants a lock request. lock (_activeLocks) { // If there are locks available... if (_activeLocks.Count < _maxConcurrent) { // Keep pulling from the queue until we find a pending request (or it is empty). while (!lockGranted && _pendingRequests.TryDequeue(out request)) { lockGranted = AttemptToGrantLock(request); } } } // If we found a request to grant, do so. if (lockGranted) { LockGranted?.Invoke(this, new LockGrantedEventArgs(request, this)); } }
/// <summary> /// Releases the lock held by the specified <see cref="LockRequest" />. /// </summary> /// <param name="request">The lock request.</param> /// <exception cref="ArgumentNullException"><paramref name="request" /> is null.</exception> public void ReleaseLock(LockRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } bool released = false; lock (request) { // Check the active locks to see if the specified request is one of them. released = _activeLocks.TryRemove(request.RequestId, out LockRequest removed); if (released) { request.State = LockRequestState.Released; _logger.LogTrace($"Request '{request.Name}' released lock for resource '{ResourceId}'."); } else { _logger.LogError($"Request '{request.Name}' attempted to release lock for resource '{ResourceId}', but did not have a lock."); } } if (released) { GrantLocks(); } }
/// <summary> /// Enqueues a lock request for the specified resource. /// </summary> /// <param name="requestId">The unique identifier for the request.</param> /// <param name="resourceId">The resource identifier.</param> /// <param name="requestName">The name to use for identifying the request.</param> protected void RequestLock(Guid requestId, string resourceId, string requestName) { // Create a new lock request and add it to the list of all requests. LockRequest request = new LockRequest(requestId, requestName); _allRequests.TryAdd(request.RequestId, request); // Find (or create) the resource and enqueue the request. LockResource resource = GetResource(resourceId); resource.AddRequest(request); }
private bool AttemptToGrantLock(LockRequest request) { lock (request) { if (request.State == LockRequestState.Pending) { // Move the lock request from the "pending" queue to the "active" list. _activeLocks.TryAdd(request.RequestId, request); request.State = LockRequestState.Granted; _logger.LogTrace($"Request '{request.Name}' granted lock for resource '{ResourceId}'."); return(true); } else { _logger.LogTrace($"Request '{request.Name}' for resource '{ResourceId}' is no longer pending."); return(false); } } }
/// <summary> /// Enqueues a lock request for the specified resource. /// </summary> /// <param name="requestId">The unique identifier for the request.</param> /// <param name="resourceIds">The list of resource identifiers.</param> /// <param name="requestName">The name to use for identifying the request.</param> /// <exception cref="ArgumentNullException"><paramref name="resourceIds" /> is null.</exception> protected void RequestLock(Guid requestId, IEnumerable <string> resourceIds, string requestName) { if (resourceIds == null) { throw new ArgumentNullException(nameof(resourceIds)); } // Create a new lock request and add it to the list of all requests. LockRequest request = new LockRequest(requestId, requestName); _allRequests.TryAdd(request.RequestId, request); // Find (or create) each resource and enqueue the request. foreach (string resourceId in resourceIds) { LockResource resource = GetResource(resourceId); resource.AddRequest(request); } }
/// <summary> /// Adds the specified <see cref="LockRequest" /> to the queue of consumers waiting for a lock. /// </summary> /// <param name="request">The lock request.</param> /// <exception cref="ArgumentNullException"><paramref name="request" /> is null.</exception> public void AddRequest(LockRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } lock (request) { // Don't add the request if it has already been granted, canceled, etc. if (request.State == LockRequestState.New || request.State == LockRequestState.Pending) { _pendingRequests.Enqueue(request); request.State = LockRequestState.Pending; _logger.LogTrace($"Request '{request.Name}' added to queue for resource '{ResourceId}'."); } } GrantLocks(); }
/// <summary> /// Initializes a new instance of the <see cref="LockGrantedEventArgs" /> class. /// </summary> /// <param name="lockRequest">The <see cref="LockRequest" /> that has been granted.</param> /// <param name="resource">The <see cref="LockResource"/> that has been given to the requester.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="lockRequest" /> is null. /// <para>or</para> /// <paramref name="resource" /> is null.</exception> public LockGrantedEventArgs(LockRequest lockRequest, LockResource resource) { Request = lockRequest ?? throw new ArgumentNullException(nameof(lockRequest)); Resource = resource ?? throw new ArgumentNullException(nameof(resource)); }