/// <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));
        }
Exemple #3
0
        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);