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)); } }
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; } }
public async Task SemaphoreDisposeInLock() { using var semaphore = new SemaphoreSlim(1); using (await semaphore.EnterAsync()) semaphore.Dispose(); }
/// <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)); } }