Пример #1
0
        public async ReusableTask <int> ReadAsync(ITorrentFileInfo file, long offset, byte[] buffer, int bufferOffset, int count)
        {
            Check.File(file);
            Check.Buffer(buffer);

            if (offset < 0 || offset + count > file.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            using (await Limiter.EnterAsync()) {
                using var rented = await StreamCache.GetStreamAsync(file, FileAccess.Read).ConfigureAwait(false);

                await MainLoop.SwitchToThreadpool();

                if (rented.Stream.Length < offset + count)
                {
                    return(0);
                }

                if (rented.Stream.Position != offset)
                {
                    await rented.Stream.SeekAsync(offset);
                }
                return(await rented.Stream.ReadAsync(buffer, bufferOffset, count));
            }
        }
Пример #2
0
        public async Task <T> GetValueAsync()
        {
            using (await _semaphor.EnterAsync().ConfigureAwait(false))
            {
                if (_value != null)
                {
                    return(_value);
                }
            }

            return(await UpdateOrWaitAsync().ConfigureAwait(false));
        }
        public async Task Connect()
        {
            using (await mutex.EnterAsync())
            {
                if (IsConnected)
                {
                    return;
                }

                await Client.ConnectAsync();

                IsConnected = true;
            }
        }
Пример #4
0
        public async Task SemaphoreDisposeInLock()
        {
            using var semaphore = new SemaphoreSlim(1);

            using (await semaphore.EnterAsync())
                semaphore.Dispose();
        }
Пример #5
0
        /// <summary>
        /// Maps an existing index of type <typeparamref name="TSource"/> to a new destination index of type <typeparamref name="TDestination"/>.
        /// </summary>
        protected async Task MapIndexAsync <TSource, TDestination>(string source, string destination, Func <TSource, TDestination> map, CancellationToken cancellationToken = default) where TSource : class, IDbObject where TDestination : class, IDbObject
        {
            await CreateIndexAsync <TDestination>(destination, cancellationToken);

            var options = _options.CurrentValue;

            // disable refresh and replicas
            await _client.RequestAsync(c => c.Indices.UpdateSettingsAsync(destination, x => x.IndexSettings(s => s.RefreshInterval(Time.MinusOne).NumberOfReplicas(0)), cancellationToken));

            // use semaphore to limit the number of indexing workers
            using var semaphore = new SemaphoreSlim(options.MigrationWorkers);

            _logger.LogDebug($"Using {semaphore.CurrentCount} workers for indexing.");

            var exceptions = new List <Exception>();

            void checkExceptions()
            {
                lock (exceptions)
                {
                    Exception e;

                    switch (exceptions.Count)
                    {
                    case 0: return;

                    case 1:
                        e = exceptions[0];
                        break;

                    default:
                        e = new AggregateException(exceptions);
                        break;
                    }

                    ExceptionDispatchInfo.Throw(e);
                }
            }

            var response = null as ISearchResponse <TSource>;

            try
            {
                const string scrollDuration = "1m";

                var searchMeasure = new MeasureContext();
                var batches       = 0;
                var progress      = 0;

                response = await _client.RequestAsync(c => c.SearchAsync <TSource>(s => s.Index(source).Size(options.MigrationBatchSize).Scroll(scrollDuration), cancellationToken));

                while (response.Documents.Count != 0)
                {
                    var documents = response.Documents;
                    var total     = response.Total;

                    _logger.LogDebug($"Read batch {++batches} in {searchMeasure}, {documents.Count} items.");

                    var locker = await semaphore.EnterAsync(cancellationToken);

                    var indexMeasure = new MeasureContext();

                    var _ = Task.Run(async() =>
                    {
                        using (locker)
                        {
                            try
                            {
                                var values = documents.Select(d =>
                                {
                                    var value = map(d);

                                    value?.UpdateCache(_services);
                                    return(value);
                                }).Where(d => d != null);

                                await _client.RequestAsync(c => c.IndexManyAsync(values, destination, cancellationToken));

                                lock (options)
                                {
                                    progress += documents.Count;

                                    _logger.LogInformation($"Indexed {documents.Count} items in {indexMeasure}, {progress}/{total} ({(double) progress / total:P2}).");
                                }
                            }
                            catch (Exception e)
                            {
                                lock (exceptions)
                                    exceptions.Add(e);
                            }

                            if (options.MigrationForceCollect)
                            {
                                GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
                            }
                        }
                    }, cancellationToken);

                    searchMeasure = new MeasureContext();
                    response      = await _client.RequestAsync(c => c.ScrollAsync <TSource>(scrollDuration, response.ScrollId, null, cancellationToken));

                    checkExceptions();
                }
            }
            finally
            {
                // clear scroll
                if (response != null)
                {
                    await _client.RequestAsync(c => c.ClearScrollAsync(s => s.ScrollId(response.ScrollId), cancellationToken));
                }

                // wait for all workers to exit
                for (var i = 0; i < options.MigrationWorkers; i++)
                {
                    await semaphore.WaitAsync(cancellationToken);
                }

                checkExceptions();

                _logger.LogInformation($"Refreshing index '{destination}'...");

                // refresh immediately
                await _client.RequestAsync(c => c.Indices.RefreshAsync(destination, null, cancellationToken));

                await _client.RequestAsync(c => c.Indices.UpdateSettingsAsync(destination, x => x.IndexSettings(s => s.RefreshInterval(options.RefreshInterval).NumberOfReplicas(options.ReplicaCount)), cancellationToken));
            }
        }