/// <summary> Almost thread-safe version of <see cref="FetchAsync"/>. </summary> /// <remarks> /// You may call <see cref="TryGetNext"/> while the task is running, but NOT /// any other method. The function returned by the task is not thread-safe. /// /// This is intended for use in a "fetch in thread A, process in thread B" /// pattern: /// - call BackgroundFetchAsync, store into T /// - repeatedy call TryGetNext until either T is done or no more events /// - call the result of T, store into M /// - if M is false or the last call to TryGetNext returned an event, repeat /// </remarks> public async Task <Func <bool> > BackgroundFetchAsync(CancellationToken cancel = default(CancellationToken)) { const int maxBytes = 1024 * 1024 * 4; var read = await Storage.ReadAsync(Position, maxBytes, cancel); if (read.Events.Count == 0) { return(() => false); } return(() => { Position = read.NextPosition; if (read.Events.Count == 0) { return false; } foreach (var e in read.Events) { _cache.Enqueue(e); _lastSequence = e.Sequence; } return true; }); }
/// <see cref="IStorageDriver.ReadAsync"/> public async Task <DriverReadResult> ReadAsync(long position, long maxBytes, CancellationToken cancel = new CancellationToken()) { // Read data up to the requested position (if not already available) var cachePos = _cache.GetPosition(); while (position >= cachePos) { var r = await _source.ReadAsync(cachePos, maxBytes, cancel); var w = await _cache.WriteAsync(cachePos, r.Events, cancel); if (r.NextPosition == cachePos) { break; } if (!w.Success) { throw new InvalidOperationException("Failed writing to cache stream."); } if (w.NextPosition != r.NextPosition) { throw new InvalidDataException( $"Position mismatch after cache copy: {cachePos} -> ({r.NextPosition}, {w.NextPosition}."); } cachePos = w.NextPosition; } return(await _cache.ReadAsync(position, maxBytes, cancel)); }
public async Task <DriverReadResult> ReadAsync(long position, long maxBytes, CancellationToken cancel = new CancellationToken()) { var sw = Stopwatch.StartNew(); try { return(await Inner.ReadAsync(position, maxBytes, cancel)); } finally { Trace.WriteLine("ReadAsync " + sw.ElapsedMilliseconds); } }
public Task <DriverReadResult> ReadAsync(long position, long maxBytes, CancellationToken cancel = new CancellationToken()) => Wrapped.ReadAsync(position, maxBytes, cancel);