private Task DispatchBatchAsync() { return(_sync.LockAsync( () => !_buffer.IsEmpty, async() => { TaskCompletionBuffer <TKey, TValue> copy = CopyAndClearBuffer(); TKey[] resolvedKeys = copy.Keys.ToArray(); if (_options.MaxBatchSize > 0 && copy.Count > _options.MaxBatchSize) { var chunkSize = (int)Math.Ceiling( (decimal)copy.Count / _options.MaxBatchSize); for (var i = 0; i < chunkSize; i++) { TKey[] chunkedKeys = resolvedKeys .Skip(i * _options.MaxBatchSize) .Take(_options.MaxBatchSize) .ToArray(); await FetchInternalAsync(copy, chunkedKeys) .ConfigureAwait(false); } } else { await FetchInternalAsync(copy, resolvedKeys) .ConfigureAwait(false); } })); }
private TaskCompletionBuffer <TKey, TValue> CopyAndClearBuffer() { TaskCompletionBuffer <TKey, TValue> copy = _buffer; _buffer = new TaskCompletionBuffer <TKey, TValue>(); return(copy); }
private Task DispatchBatchAsync(CancellationToken cancellationToken) { if (!_buffer.IsEmpty) { lock (_sync) { if (!_buffer.IsEmpty) { Func <Task> execute = async() => { TaskCompletionBuffer <TKey, TValue> copy = CopyAndClearBuffer(); TKey[] keys = copy.Keys.ToArray(); if (_options.MaxBatchSize > 0 && copy.Count > _options.MaxBatchSize) { // splits items from buffer into chunks and instead of // sending the complete buffer, it sends chunk by chunk var chunkSize = (int)Math.Ceiling( (decimal)copy.Count / _options.MaxBatchSize); for (var i = 0; i < chunkSize; i++) { TKey[] chunkedKeys = keys .Skip(i * _options.MaxBatchSize) .Take(_options.MaxBatchSize) .ToArray(); await FetchInternalAsync( copy, chunkedKeys, cancellationToken) .ConfigureAwait(false); } } else { // sends all items from the buffer in one batch // operation await FetchInternalAsync( copy, keys, cancellationToken) .ConfigureAwait(false); } }; return(execute()); } } } return(Task.CompletedTask); }
/// <summary> /// Initializes a new instance of the /// <see cref="DataLoaderBase{TKey, TValue}"/> class. /// </summary> /// <param name="options"> /// A configuration for <c>DataLoaders</c>. /// </param> /// <param name="cache"> /// A cache instance for <c>Tasks</c>. /// </param> /// <exception cref="ArgumentNullException"> /// Throws if <paramref name="options"/> is <c>null</c>. /// </exception> /// <exception cref="ArgumentNullException"> /// Throws if <paramref name="cache"/> is <c>null</c>. /// </exception> protected DataLoaderBase(DataLoaderOptions <TKey> options, ITaskCache <TValue> cache) { _options = options ?? throw new ArgumentNullException(nameof(options)); _buffer = new TaskCompletionBuffer <TKey, TValue>(); _cache = cache ?? throw new ArgumentNullException(nameof(cache)); _cacheKeyResolver = _options.CacheKeyResolver ?? ((TKey key) => key); StartAsyncBackgroundDispatching(); }
/// <inheritdoc/> protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { Clear(); _disposeTokenSource.Cancel(); _delaySignal?.Set(); (_cache as IDisposable).Dispose(); _disposeTokenSource.Dispose(); _delaySignal?.Dispose(); } _buffer = null; _cache = null; _delaySignal = null; _options = null; _disposed = true; } }
public void IterationSetup() { _buffer = new TaskCompletionBuffer <string, int>(); }