Exemple #1
0
        internal static async Task AddAcquisitionRequestAsync(this IDatabase db, DSemaphoreContext sempahoreContext, double currentTime, long counter)
        {
            // add the current time
            await db.SortedSetAddAsync(sempahoreContext.SemaphoreName, sempahoreContext.Id, currentTime);

            // add the current count
            await db.SortedSetAddAsync(sempahoreContext.CounterSetName, sempahoreContext.Id, counter);
        }
Exemple #2
0
        private async Task <bool> CanBeAcquiredAsync(DSemaphoreContext sempahoreContext, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var currentPosition = await _db.SortedSetRankAsync(sempahoreContext.CounterSetName, sempahoreContext.Id);

            return(currentPosition.HasValue && currentPosition.Value < _maxCount);
        }
Exemple #3
0
        /// <summary>
        /// Exits the <see cref="DSemaphoreContext"/>.
        /// </summary>
        private async Task ReleaseAsync(DSemaphoreContext context, CancellationToken cancellationToken)
        {
            await _locker.WaitAsync(cancellationToken);

            try
            {
                if (!_contexts.ContainsKey(context.Id))
                {
                    return;
                }

                await _db.RemoveSemaphoreAsync(context);

                _contexts.TryRemove(context.Id, out _);
            }
            finally
            {
                _locker.Release();
            }
        }
Exemple #4
0
        internal static async Task RemoveSemaphoreAsync(this IDatabase db, DSemaphoreContext sempahoreContext)
        {
            await db.SortedSetRemoveAsync(sempahoreContext.SemaphoreName, sempahoreContext.Id);

            await db.SortedSetRemoveAsync(sempahoreContext.CounterSetName, sempahoreContext.Id);
        }
Exemple #5
0
        internal static async Task RemoveObsoleteAcquisitionRequestsAsync(this IDatabase db, DSemaphoreContext sempahoreContext, double outdatedLimit)
        {
            await db.SortedSetRemoveRangeByScoreAsync(sempahoreContext.SemaphoreName, 0, outdatedLimit);

            await db.SortedSetCombineAndStoreAsync(
                SetOperation.Intersect,
                sempahoreContext.CounterSetName,
                new RedisKey[] { sempahoreContext.CounterSetName, sempahoreContext.SemaphoreName },
                new double[] { 1, 0 }
                );
        }
Exemple #6
0
        public async Task <bool> WaitAsync(TimeSpan timeout, string id = null, CancellationToken cancellationToken = default)
        {
            CheckDispose();

            if (timeout < _minimumTimeoutTime)
            {
                throw new ArgumentOutOfRangeException($"{nameof(timeout)} cannot be less than {_minimumTimeoutTime}");
            }

            if (cancellationToken.IsCancellationRequested)
            {
                return(await Task.FromCanceled <bool>(cancellationToken));
            }

            using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken, default);

            id ??= Guid.NewGuid().ToString();

            var semaphoreContext = _contexts.GetOrAdd(id, s => new Lazy <DSemaphoreContext>(() => DSemaphoreContext.CreateNewContext(id, _semaphoreName))).Value;
            var isAcquired       = false;

            if (semaphoreContext.CreationDate < DateTime.Now)
            {
                var currentTime            = semaphoreContext.CreationDate.ToOADate();
                var obsoleteSemaphoreLimit = (semaphoreContext.CreationDate - timeout).ToOADate();

                await _db.RemoveObsoleteAcquisitionRequestsAsync(semaphoreContext, obsoleteSemaphoreLimit);

                var currentCounter = await _db.StringIncrementAsync(semaphoreContext.CounterName);

                await _db.AddAcquisitionRequestAsync(semaphoreContext, currentTime, currentCounter);

                var stopwatch = Stopwatch.StartNew();

                while (stopwatch.Elapsed <= timeout)
                {
                    isAcquired = await CanBeAcquiredAsync(semaphoreContext, cts.Token);

                    if (isAcquired)
                    {
                        break;
                    }

                    await Task.Delay(_retryTime, cancellationToken);
                }
            }

            await ReleaseAsync(semaphoreContext, cts.Token);

            cts.Cancel();

            return(isAcquired);
        }