예제 #1
0
        public async Task RegisterAsync(Func <CancellationToken, Task> task)
        {
            using (await _locker.AcquireAsync())
            {
                throwIfFinished();

                _tasks.Add(task(_cts.Token));
            }
        }
예제 #2
0
        public async Task <T> AquireAsync(AsyncOperationInfo operationInfo)
        {
            ObjectInfo objectToken = null;

            do
            {
                operationInfo.CancellationToken.ThrowIfCancellationRequested();
                objectToken = await tryAquireObjectAsync();
            }while (objectToken == null);

            return(objectToken.Object); /////////////////////////////////////

            async Task <ObjectInfo> tryAquireObjectAsync()
            {
                using (await _semaphore.AcquireAsync(operationInfo))
                {
                    await populateIfAppropriateAsync();

                    return(tryAcquire());
                }

                /////////////////////////////////////

                async Task populateIfAppropriateAsync()
                {
                    var canInstantiateNew = _maxPoolSize > _objects.Count;
                    var haveSpareObject   = _objects.Any(s => !s.IsInUse);

                    if (!haveSpareObject && canInstantiateNew)
                    {
                        _objects.Add(new ObjectInfo()
                        {
                            IsInUse = false,
                            Object  = await _factory()
                        });
                    }
                }

                ObjectInfo tryAcquire()
                {
                    foreach (var objectInfo in _objects)
                    {
                        if (!objectInfo.IsInUse)
                        {
                            objectInfo.IsInUse = true;

                            return(objectInfo);
                        }
                    }

                    return(null);
                }
            }
        }
예제 #3
0
 /// <summary>
 /// Writes to standard input.
 /// </summary>
 /// <remarks>
 /// If the process has exited or this instance has been disposed, then this method does nothing.
 /// </remarks>
 public async Task WriteStandardInputLineAsync(string line)
 {
     Contract.Requires(HasStarted);
     using (await m_syncSemaphore.AcquireAsync())
     {
         if (m_standardInputWriter != null)
         {
             await m_standardInputWriter.WriteLineAsync(line);
         }
     }
 }
예제 #4
0
        public async Task ResetAsync(int badId)
        {
            // To make sure a competing thread doesn't squash a newly created session Id,
            // only squash the session ID if we are the first to discover that ours is bad.
            using var holder = await _sync.AcquireAsync();

            if (_data != null && _data.SessionId == badId)
            {
                _data.TemporaryDirectory?.Dispose();
                _data = null;
            }
        }
예제 #5
0
        public async Task AcquireSuccess()
        {
            var semaphore = new SemaphoreSlim(1);

            var acquired = await semaphore.AcquireAsync().CAF();

            Assert.IsTrue(acquired.Acquired);
            acquired.Dispose();

            acquired = await semaphore.AcquireAsync().CAF();

            Assert.IsTrue(acquired.Acquired);
            acquired.Dispose();
        }
예제 #6
0
        private async Task GarbageCollectCoreAsync(OperationContext context)
        {
            ReleaseExpiredWrappers(context, disposing: false);

            // Meant to avoid concurrent GCs from taking place. This can happen if Dispose() is called concurrently
            // along an already-running GC.
            using var token = await _gcLock.AcquireAsync(context.Token);

            // WARNING: order is important in this guard
            var size = _shutdownQueue.Count;

            while (!context.Token.IsCancellationRequested && size > 0 && _shutdownQueue.TryDequeue(out var wrapper))
            {
                // Size is constantly decreased because if we don't do it, GC can hang forever waiting until a single
                // usage decreases its reference count on the resource. The fact that we do this means that such usages
                // will take more than one GC pass to release, but that's fine.
                size--;

                if (wrapper.ReferenceCount > 0)
                {
                    _shutdownQueue.Enqueue(wrapper);
                }
                else
                {
                    await ReleaseWrapperAsync(context, wrapper);
                }
            }
        }
예제 #7
0
            public async Task <bool> ConnectAndPinAsync(BondCallTracker callTracker, CancellationToken cancellationToken)
            {
                using (await m_connectionSemaphore.AcquireAsync(cancellationToken))
                {
                    var connection = m_connection;
                    if (connection == null || ShouldRecreate)
                    {
                        if (m_isDisposed)
                        {
                            return(false);
                        }

                        callTracker.OnStateChanged(BondCallState.RecreateConnection);
                        connection = await RecreateConnection(connection);

                        lock (this)
                        {
                            if (m_isDisposed)
                            {
                                connection.Dispose();
                                return(false);
                            }

                            m_connection = connection;
                        }
                    }
                }

                return(true);
            }
예제 #8
0
        /// <summary>
        ///  Handle request from Peers and forward to the correct local Group instance
        /// </summary>
        public async Task GetAsync(string groupName, string key, Stream sink, ICacheControl cacheControl, CancellationToken ct)
        {
            SemaphoreHolder limiter;

            try
            {
                limiter = await _concurrencyLimiter.AcquireAsync(TimeSpan.Zero).ConfigureAwait(false);
            }
            catch (TimeoutException)
            {
                throw new ServerBusyException("Too many concurrent connection");
            }

            using (limiter)
            {
                var groupKey = new GroupKey {
                    GroupName = groupName, Endpoint = this.Endpoint
                };
                var found = GroupCache.GroupCache.GetGroup(groupKey, out Group group);
                if (!found)
                {
                    throw new GroupNotFoundException($"no such group: {groupName}");
                }
                group.Stats.TraceConcurrentServerRequests(_concurrencyLimit - _concurrencyLimiter.CurrentCount);
                group.Stats.TraceServerRequests(groupName);

                // We received a request from a peer, we need to download it locally and not forward to peer
                // because forwarding to peer would cause infinite loop if using different peer list
                await group.GetAsyncLocallyAsync(key, sink, cacheControl, ct);
            }
        }
 public async Task BindUserAsync(string token)
 {
     using (await _locker.AcquireAsync())
     {
         await Connection.SendAsync("Bind", token);
     }
 }
예제 #10
0
        private async Task <Result <Role> > UpdateRoleAsync(OperationContext context, bool release)
        {
            return(await context.PerformOperationAsync <Result <Role> >(
                       Tracer,
                       async() =>
            {
                // This mutex ensure that Release of master role during shutdown and Heartbeat role acquisition are synchronized.
                // Ensuring that a heartbeat during shutdown doesn't trigger the released master role to be acquired again.
                using (await _roleMutex.AcquireAsync())
                {
                    if (ShutdownStarted)
                    {
                        // Don't acquire a role during shutdown
                        return Role.Worker;
                    }

                    var configuredRole = _configuration.Checkpoint?.Role;
                    if (configuredRole != null)
                    {
                        return configuredRole.Value;
                    }

                    var localMachineName = _configuration.PrimaryMachineLocation.ToString();

                    var masterAcquisitonResult = await _masterLeaseKey.UseNonConcurrentReplicatedHashAsync(context, _configuration.RetryWindow, RedisOperation.UpdateRole, (batch, key) => batch.AcquireMasterRoleAsync(
                                                                                                               masterRoleRegistryKey: key,
                                                                                                               machineName: localMachineName,
                                                                                                               currentTime: _clock.UtcNow,
                                                                                                               leaseExpiryTime: _configuration.Checkpoint.MasterLeaseExpiryTime,
                                                                                                               // 1 master only is allowed. This should be changed if more than one master becomes a possible configuration
                                                                                                               slotCount: 1,
                                                                                                               release: release
                                                                                                               ),
                                                                                                           timeout: _configuration.ClusterRedisOperationTimeout).ThrowIfFailureAsync();

                    if (release)
                    {
                        Tracer.Debug(context, $"'{localMachineName}' released master role.");
                        return Role.Worker;
                    }

                    if (masterAcquisitonResult != null)
                    {
                        var priorMachineName = masterAcquisitonResult.Value.PriorMasterMachineName;
                        if (priorMachineName != localMachineName || masterAcquisitonResult.Value.PriorMachineStatus != SlotStatus.Acquired)
                        {
                            Tracer.Debug(context, $"'{localMachineName}' acquired master role from '{priorMachineName}', Status: '{masterAcquisitonResult?.PriorMachineStatus}', LastHeartbeat: '{masterAcquisitonResult?.PriorMasterLastHeartbeat}'");
                        }

                        return Role.Master;
                    }
                    else
                    {
                        return Role.Worker;
                    }
                }
            },
                       Counters[GlobalStoreCounters.UpdateRole]));
        }
예제 #11
0
        public async Task AutomaticallyReleaseASemaphore()
        {
            var semaphore = new SemaphoreSlim(1);

            using (await semaphore.AcquireAsync())
            {
                Assert.That(semaphore.CurrentCount, Is.EqualTo(0));
            }
            Assert.That(semaphore.CurrentCount, Is.EqualTo(1));
        }
예제 #12
0
        public void AcquireFail()
        {
            var semaphore    = new SemaphoreSlim(0);
            var cancellation = new CancellationTokenSource(100);

            Assert.ThrowsAsync <TaskCanceledException>(async() =>
            {
                using var acquired = await semaphore.AcquireAsync(cancellation.Token).CAF();
            });
        }
예제 #13
0
        async Task provideNextPartAsync()
        {
            using (await _locker.AcquireAsync())
            {
                var length = _flashDumpWriteStream.Length - _lastPosition;
                await _partsProvider.ProvideNextAndWaitTillFinishesAsync(_lastPosition, length, new AsyncOperationInfo());

                _lastPosition += length;
            }
        }
예제 #14
0
 /// <nodoc />
 public async Task FlushAsync(OperationContext context)
 {
     // This lock is required to ensure no flushes happen concurrently. We may loose updates if that happens.
     // AcquireAsync is used so as to avoid multiple concurrent tasks just waiting; this way we return the
     // task to the thread pool in between.
     using (await _flushMutex.AcquireAsync())
     {
         PerformFlush(context);
     }
 }
        public async Task SemaphoreSlim_AcquireAsync_WithGcCollect_Test()
        {
            var  sync = new SemaphoreSlim(1);
            Task fireForget;

            using (await sync.AcquireAsync(TimeSpan.FromSeconds(5)))
            {
                CollectGC();
                fireForget = Task.Run(async() =>
                {
                    await Task.Delay(30);
                    using (await sync.AcquireAsync(TimeSpan.FromSeconds(5)))
                    {
                    }
                });
            }
            CollectGC();
            await fireForget;
        }
예제 #16
0
        /// <nodoc />
        public async Task <CounterCollection <FlushableCacheCounters> > FlushAsync(OperationContext context)
        {
            // Make it likely that this runs in a separate thread other than the one that triggered the flush
            await Task.Yield();

            // This lock is required to ensure no flushes happen concurrently. We may loose updates if that happens.
            // AcquireAsync is used so as to avoid multiple concurrent tasks just waiting; this way we return the
            // task to the thread pool in between.
            using (await _flushMutex.AcquireAsync())
            {
                return(PerformFlush(context));
            }
        }
        public async Task SemaphoreSlim_AcquireAsync_Test()
        {
            var  sync = new SemaphoreSlim(1);
            Task fireForget;

            using (await sync.AcquireAsync(TimeSpan.FromSeconds(5)))
            {
                fireForget = Task.Run(async() =>
                {
                    using (await sync.AcquireAsync(TimeSpan.FromSeconds(5)))
                    {
                    }
                });
                await Task.Delay(5).ConfigureAwait(false);

                Assert.IsFalse(fireForget.IsCompleted, "fireForget.IsCompleted");
            }
            await Task.Delay(5).ConfigureAwait(false);

            Assert.IsTrue(fireForget.IsCompleted);
            await fireForget;
        }
예제 #18
0
        private async Task WaitUntilReportEof(bool cancel)
        {
            using (await m_reportReaderSemaphore.AcquireAsync())
            {
                if (m_reportReader != null)
                {
                    await m_reportReader.CompletionAsync(!cancel);

                    m_reportReader.Dispose();
                    m_reportReader = null;
                }
            }
        }
        public async Task AcquireAsyncAndSucceed()
        {
            var s = new SemaphoreSlim(1);

            using (var a = await s.AcquireAsync())
            {
                Assert.That(a.Acquired, Is.True);
                Assert.That((bool)a, Is.True);
                Assert.That(s.CurrentCount, Is.EqualTo(0));
            }

            Assert.That(s.CurrentCount, Is.EqualTo(1));

            using (var a = await s.AcquireAsync(default))
        public async Task AddSubscription()
        {
            if (_disposed == 1)
            {
                throw new ObjectDisposedException(nameof(EventSubscriptionBase));
            }

            // accepted race condition, _busy can be disposed here and will throw an ObjectDisposedException

            using (await _busy.AcquireAsync().CAF())
            {
                _subscriptionsCount++;
                if (_subscriptionsCount > 1)
                {
                    return;
                }

                var subscription = CreateSubscription();
                await ClusterEvents.InstallSubscriptionAsync(subscription).CAF();

                _subscriptionId = subscription.Id;
            }
        }
예제 #21
0
        public Task ResetAsync(OperationContext context, int badId)
        {
            return(context.PerformOperationAsync(
                       Tracer,
                       async() =>
            {
                double lockAcquisitionDurationMs = 0;
                // To make sure a competing thread doesn't squash a newly created session Id,
                // only squash the session ID if we are the first to discover that ours is bad.
                using (var releaser = await _sync.AcquireAsync())
                {
                    if (_data != null && _data.SessionId == badId)
                    {
                        _data.TemporaryDirectory?.Dispose();
                        _data = null;
                    }

                    lockAcquisitionDurationMs = releaser.LockAcquisitionDuration.TotalMilliseconds;
                }

                return Result.Success(lockAcquisitionDurationMs);
            },
                       extraEndMessage: r => $"LockAcquisitionDuration=[{r.ToStringWithValue()}ms]"));
        }
예제 #22
0
            public async Task Invoke(HttpContext httpContext, IServiceProvider serviceProvider)
            {
                if (!_initialized)
                {
                    using (await _locker.AcquireAsync())
                    {
                        if (!_initialized)
                        {
                            await _initializator.InitializeAsync(serviceProvider);

                            _initialized = true;
                        }
                    }
                }

                await _next(httpContext);
            }
예제 #23
0
        public Task <BoolResult> AppendAsync(OperationContext context, BlockReference cursor, Stream stream)
        {
            var msg = $"{cursor}";

            return(context.PerformOperationAsync(Tracer, async() =>
            {
                using var _ = await _lock.AcquireAsync(context.Token);

                Contract.Assert(!State.Seals.GetOrDefault(cursor.LogId.Value, false), $"Can't append to `{cursor}` because the log is sealed");

                State.Seals[cursor.LogId.Value] = false;
                var storage = State.Blobs.GetOrAdd(cursor.LogId.Value, _ => new MemoryStream());

                await stream.CopyToAsync(storage, 1024, context.Token);

                return BoolResult.Success;
            },
예제 #24
0
        /// <summary>
        /// Queries the endpoint for the RequestId.
        /// This method should be called only after the request has been created, otherwise, it will throw an exception.
        /// </summary>
        /// <remarks>
        /// On workers, m_requestId / m_domainId won't be initialized, so we need to query the server for the right values.
        /// </remarks>
        private async Task EnsureRequestIdAndDomainIdAreInitalizedAsync()
        {
            // Check whether the field is initialized, so we are not wastefully acquire the semaphore.
            if (string.IsNullOrEmpty(m_requestId))
            {
                using (await m_requestIdAcquisitionMutex.AcquireAsync())
                {
                    // check whether we still need to query the server
                    if (string.IsNullOrEmpty(m_requestId) || m_domainId == null)
                    {
                        using (m_counters.StartStopwatch(SymbolClientCounter.GetRequestIdDuration))
                        {
                            var result = await m_symbolClient.GetRequestByNameAsync(RequestName, CancellationToken);

                            m_requestId = result.Id;
                            m_domainId  = result.DomainId;
                        }
                    }
                }
            }
        }
예제 #25
0
        protected async Task safeReloadAsync()
        {
            if (isEnabled())
            {
                using (await _locker.AcquireAsync())
                    using (new FlagInverseAction(true, v => IsLoading = v))
                    {
                        try
                        {
                            Logger.LogInfoEverywhere("Обновление графика отклонений");

                            await ReloadAsync();

                            Logger.LogOKEverywhere("График отклонений обновлен");
                        }
                        catch (Exception ex)
                        {
                            Clear();

                            Logger.LogErrorEverywhere("Ошибка во время обновления графика отклонений", ex);
                        }
                    }
            }
        }
        /// <summary>
        /// Store the fingerprint store directory to the cache
        /// </summary>
        public static async Task <Possible <long> > TrySaveFingerprintStoreAsync(
            this EngineCache cache,
            LoggingContext loggingContext,
            AbsolutePath path,
            PathTable pathTable,
            string key,
            string environment)
        {
            var           fingerprint = ComputeFingerprint(pathTable, key, environment);
            var           pathStr     = path.ToString(pathTable);
            BoxRef <long> size        = 0;

            SemaphoreSlim concurrencyLimiter = new SemaphoreSlim(8);
            var           tasks = new List <Task <Possible <StringKeyedHash, Failure> > >();

            FileUtilities.EnumerateDirectoryEntries(pathStr, (name, attr) =>
            {
                var task = Task.Run(async() =>
                {
                    using (await concurrencyLimiter.AcquireAsync())
                    {
                        var filePath    = path.Combine(pathTable, name);
                        var storeResult = await cache.ArtifactContentCache.TryStoreAsync(
                            FileRealizationMode.Copy,
                            filePath.Expand(pathTable));

                        if (storeResult.Succeeded)
                        {
                            Interlocked.Add(ref size.Value, new FileInfo(filePath.ToString(pathTable)).Length);
                        }

                        return(storeResult.Then(result => new StringKeyedHash()
                        {
                            Key = path.ExpandRelative(pathTable, filePath),
                            ContentHash = result.ToBondContentHash()
                        }));
                    }
                });

                tasks.Add(task);
            });

            var storedFiles = await Task.WhenAll(tasks);

            var failure = storedFiles.Where(p => !p.Succeeded).Select(p => p.Failure).FirstOrDefault();

            Logger.Log.GettingFingerprintStoreTrace(loggingContext, I($"Saving fingerprint store to cache: Success='{failure == null}', FileCount={storedFiles.Length} Size={size.Value}"));
            if (failure != null)
            {
                return(failure);
            }

            PackageDownloadDescriptor descriptor = new PackageDownloadDescriptor()
            {
                TraceInfo    = loggingContext.Session.Environment,
                FriendlyName = nameof(FingerprintStore),
                Contents     = storedFiles.Select(p => p.Result).ToList()
            };

            var storeDescriptorResult = await cache.ArtifactContentCache.TrySerializeAndStoreContent(descriptor);

            Logger.Log.GettingFingerprintStoreTrace(loggingContext, I($"Saving fingerprint store descriptor to cache: Success='{storeDescriptorResult.Succeeded}'"));
            if (!storeDescriptorResult.Succeeded)
            {
                return(storeDescriptorResult.Failure);
            }

            var associatedFileHashes = descriptor.Contents.Select(s => s.ContentHash.ToContentHash()).ToArray().ToReadOnlyArray().GetSubView(0);
            var cacheEntry           = new CacheEntry(storeDescriptorResult.Result, null, associatedFileHashes);

            var publishResult = await cache.TwoPhaseFingerprintStore.TryPublishTemporalCacheEntryAsync(loggingContext, fingerprint, cacheEntry);

            Logger.Log.GettingFingerprintStoreTrace(loggingContext, I($"Publishing fingerprint store to cache: Fingerprint='{fingerprint}' Hash={storeDescriptorResult.Result}"));
            return(size.Value);
        }
        /// <summary>
        /// Retrieve the fingerprint store from the cache
        /// </summary>
        public static async Task <Possible <bool> > TryRetrieveFingerprintStoreAsync(
            this EngineCache cache,
            LoggingContext loggingContext,
            AbsolutePath path,
            PathTable pathTable,
            string key,
            string environment)
        {
            var fingerprint        = ComputeFingerprint(pathTable, key, environment);
            var possibleCacheEntry = await cache.TwoPhaseFingerprintStore.TryGetLatestCacheEntryAsync(loggingContext, fingerprint);

            if (!possibleCacheEntry.Succeeded)
            {
                Logger.Log.GettingFingerprintStoreTrace(
                    loggingContext,
                    I($"Failed loading fingerprint store cache entry from cache: Key='{key}' Failure: {possibleCacheEntry.Failure.DescribeIncludingInnerFailures()}"));

                return(possibleCacheEntry.Failure);
            }

            Logger.Log.GettingFingerprintStoreTrace(
                loggingContext,
                I($"Loaded fingerprint store entry from cache: Key='{key}' Fingerprint='{fingerprint}' MetadataHash='{possibleCacheEntry.Result?.MetadataHash ?? ContentHashingUtilities.ZeroHash}'"));

            if (!possibleCacheEntry.Result.HasValue)
            {
                return(false);
            }

            var fingerprintStoreDescriptorHash = possibleCacheEntry.Result.Value.MetadataHash;
            var maybePinned = await cache.ArtifactContentCache.TryLoadAvailableContentAsync(possibleCacheEntry.Result.Value.ToArray());

            var result = await maybePinned.ThenAsync <Unit>(
                async pinResult =>
            {
                if (!pinResult.AllContentAvailable)
                {
                    return(new Failure <string>(I($"Could not pin content for fingerprint store '{string.Join(", ", pinResult.Results.Where(r => !r.IsAvailable).Select(r => r.Hash))}'")));
                }

                var maybeLoadedDescriptor = await cache.ArtifactContentCache.TryLoadAndDeserializeContent <PackageDownloadDescriptor>(fingerprintStoreDescriptorHash);
                if (!maybeLoadedDescriptor.Succeeded)
                {
                    return(maybeLoadedDescriptor.Failure);
                }

                Logger.Log.GettingFingerprintStoreTrace(
                    loggingContext,
                    I($"Loaded fingerprint store cache descriptor from cache: Key='{key}' Hash='{fingerprintStoreDescriptorHash}'"));

                PackageDownloadDescriptor descriptor = maybeLoadedDescriptor.Result;

                SemaphoreSlim concurrencyLimiter = new SemaphoreSlim(8);
                var materializedFiles            = await Task.WhenAll(descriptor.Contents.Select(async subPathKeyedHash =>
                {
                    await Task.Yield();
                    using (await concurrencyLimiter.AcquireAsync())
                    {
                        var filePath          = path.Combine(pathTable, subPathKeyedHash.Key);
                        var maybeMaterialized = await cache.ArtifactContentCache.TryMaterializeAsync(
                            FileRealizationMode.Copy,
                            filePath.Expand(pathTable),
                            subPathKeyedHash.ContentHash.ToContentHash());

                        return(maybeMaterialized);
                    }
                }).ToList());

                var failure = materializedFiles.Where(p => !p.Succeeded).Select(p => p.Failure).FirstOrDefault();
                if (failure != null)
                {
                    return(failure);
                }
                return(Unit.Void);
            });

            if (!result.Succeeded)
            {
                Logger.Log.GettingFingerprintStoreTrace(
                    loggingContext,
                    I($"Failed loading fingerprint store from cache: Key='{key}' Failure: {result.Failure.DescribeIncludingInnerFailures()}"));

                return(result.Failure);
            }

            Logger.Log.GettingFingerprintStoreTrace(loggingContext, I($"Loaded fingerprint store from cache: Key='{key}' Path='{path.ToString(pathTable)}'"));

            return(true);
        }
예제 #28
0
 public Task <IDisposable> LockAsync() => _locker.AcquireAsync();