예제 #1
0
        /// <summary>
        /// Gets if the resource is locked.
        /// </summary>
        /// <param name="resourceUri">The resource URI.</param>
        /// <returns>If the resource URI is locked.</returns>
        public Task <LockToken> QueryAsync(Uri resourceUri)
        {
            if (!resourceUri.Scheme.Equals("tandem", StringComparison.CurrentCultureIgnoreCase))
            {
                throw new FormatException("The protocol scheme must be tandem");
            }

            lock (_handles) {
                SlimLockHandle handle = _handles.SingleOrDefault(h => h.ResourceURI.ToString().Equals(resourceUri.ToString(), StringComparison.CurrentCultureIgnoreCase));

                if (handle == null)
                {
                    return(Task.FromResult(default(LockToken)));
                }
                else
                {
                    return(Task.FromResult(handle.Token));
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Locks a resource.
        /// </summary>
        /// <param name="resourceUri">The resource URI.</param>
        /// <param name="waitTime">The wait time.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        public async Task <ILockHandle> LockAsync(Uri resourceUri, TimeSpan waitTime = default(TimeSpan), CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!resourceUri.Scheme.Equals("tandem", StringComparison.CurrentCultureIgnoreCase))
            {
                throw new FormatException("The protocol scheme must be tandem");
            }

            lock (_handles) {
                SlimLockHandle handle = _handles.SingleOrDefault(h => h.ResourceURI.ToString().Equals(resourceUri.ToString(), StringComparison.CurrentCultureIgnoreCase));

                if (handle != null)
                {
                    // check if we don't want to wait
                    if (waitTime == TimeSpan.Zero)
                    {
                        return(null);
                    }

                    // fall through
                }
                else
                {
                    handle = new SlimLockHandle(this)
                    {
                        ResourceURI = resourceUri,
                        Token       = new LockToken(Guid.NewGuid(), null)
                    };

                    _handles.Add(handle);
                    return(handle);
                }
            }

            // add to lock queue
            TaskCompletionSource <ILockHandle> handleTaskSource = new TaskCompletionSource <ILockHandle>();

            lock (_lockQueues) {
                // get waiting list or create
                List <TaskCompletionSource <ILockHandle> > waitingList = null;

                if (!_lockQueues.TryGetValue(resourceUri.ToString(), out waitingList))
                {
                    waitingList = new List <TaskCompletionSource <ILockHandle> >();
                    _lockQueues[resourceUri.ToString()] = waitingList;
                }

                // add task
                waitingList.Add(handleTaskSource);
            }

            // race between the lock and the delay, and optionally a cancellation signal
            bool timedOut = false, cancelled = false;

            try {
                Task waitDelay = Task.Delay(waitTime, cancellationToken);
                timedOut = await Task.WhenAny(waitDelay, handleTaskSource.Task).ConfigureAwait(false) == waitDelay;
            } catch (OperationCanceledException) {
                cancelled = true;
            }

            // race between the delay or the lock being released to us
            if (timedOut || cancelled)
            {
                lock (_lockQueues) {
                    // get waiting list or create
                    List <TaskCompletionSource <ILockHandle> > waitingList = null;

                    if (!_lockQueues.TryGetValue(resourceUri.ToString(), out waitingList))
                    {
                        return(handleTaskSource.Task.Result);
                    }

                    // check if we've completed already
                    if (!waitingList.Contains(handleTaskSource))
                    {
                        return(handleTaskSource.Task.Result);
                    }
                    else
                    {
                        // remove from waiting list now
                        waitingList.Remove(handleTaskSource);

                        if (waitingList.Count == 0)
                        {
                            _lockQueues.Remove(resourceUri.ToString());
                        }

                        return(null);
                    }
                }
            }
            else
            {
                // we got the lock and wern't cancelled or timed out
                return(handleTaskSource.Task.Result);
            }
        }
예제 #3
0
        /// <summary>
        /// Releases a lock.
        /// </summary>
        /// <param name="handle">The handle.</param>
        /// <returns></returns>
        public Task <bool> ReleaseAsync(ILockHandle handle)
        {
            bool removed = false;

            // try and remove the handle from our lokc list
            lock (_handles) {
                if (_handles.Contains(handle))
                {
                    _handles.Remove((SlimLockHandle)handle);

                    // we suceeded
                    removed = true;
                }
            }

            // check if any locks waiting for this lock to be removed
            if (removed)
            {
                lock (_lockQueues) {
                    while (true)
                    {
                        // get waiting list or create
                        List <TaskCompletionSource <ILockHandle> > waitingList = null;

                        // check if we did actually complete
                        if (_lockQueues.TryGetValue(handle.ResourceURI.ToString(), out waitingList))
                        {
                            // get the next lock to fulfill
                            TaskCompletionSource <ILockHandle> waitingTask = waitingList[0];
                            waitingList.RemoveAt(0);

                            // create our handle
                            SlimLockHandle newHandle = new SlimLockHandle(this)
                            {
                                ResourceURI = handle.ResourceURI,
                                Token       = new LockToken(Guid.NewGuid(), null)
                            };

                            // add to lock list
                            _handles.Add(newHandle);

                            // try and signal that the lock has been granted
                            bool signaledLock = waitingTask.TrySetResult(newHandle);

                            // remove if waiting list is empty
                            if (waitingList.Count == 0)
                            {
                                _lockQueues.Remove(handle.ResourceURI.ToString());
                            }

                            // if we signalled a lock or we're out of locks stop
                            if (signaledLock || waitingList.Count == 0)
                            {
                                break;
                            }
                        }
                    }
                }

                return(Task.FromResult(true));
            }

            return(Task.FromResult(false));
        }