예제 #1
0
        public async Task <long> GetPositionAsync(CancellationToken cancel = new CancellationToken())
        {
            var sw = Stopwatch.StartNew();

            try
            {
                return(await Inner.GetPositionAsync(cancel));
            }
            finally
            {
                Trace.WriteLine("GetPositionAsync " + sw.ElapsedMilliseconds);
            }
        }
 public Task <long> GetPositionAsync(CancellationToken cancel = new CancellationToken()) =>
 Wrapped.GetPositionAsync(cancel);
예제 #3
0
        /// <summary> Appends events to the stream. </summary>
        /// <remarks>
        /// The sequence number may not be before the current one.
        /// You can provide an arbitrarily large number of events, which will then be
        /// split into multiple writes.
        /// </remarks>
        public async Task WriteAsync(
            IEnumerable <KeyValuePair <uint, TEvent> > events,
            CancellationToken cancel = default(CancellationToken))
        {
            var sequence = _sequence ?? await LastWrittenAsync(cancel).ConfigureAwait(false);

            var position = (long)(_position ??
                                  (_position = await _driver.GetPositionAsync(cancel).ConfigureAwait(false)));

            // If an exception is thrown before we return properly, it might leave the
            // cached values (_sequence and _position) in an invalid state, so we null
            // them to cause a re-load on the next call. If returning properly, we'll
            // set them back to the proper values.
            _sequence = null;
            _position = null;

            var list      = new List <RawEvent>();
            var otherList = new List <RawEvent>();

            // Assigned the current writing task every time 'write' is called.
            Task writing = Task.FromResult(0);

            // Writes the events in the list to the driver
            Func <IReadOnlyList <RawEvent>, Task> write = async written =>
            {
                if (written.Count == 0)
                {
                    return;
                }

                var result = await _driver.WriteAsync(position, written, cancel)
                             .ConfigureAwait(false);

                if (!result.Success)
                {
                    throw new Exception(
                              $"Error writing events {written[0].Sequence} to {written[written.Count - 1].Sequence}");
                }

                position = result.NextPosition;
            };

            foreach (var kv in events)
            {
                cancel.ThrowIfCancellationRequested();

                var e   = kv.Value;
                var seq = kv.Key;

                if (seq <= sequence)
                {
                    throw new ArgumentException($"Out-of-order sequence #{seq}", nameof(events));
                }

                sequence = seq;
                list.Add(new RawEvent(seq, _serializer.Serialize(e)));

                // Avoid runaway scheduling (having to write increasingly
                // large sets of events because write is slower than enumeration
                // or serialization)
                //
                // Also, start a new write as soon as the previous one is done.
                if (writing.IsCompleted || list.Count > 1000)
                {
                    await writing.ConfigureAwait(false);

                    // The created task will ALWAYS be awaited, to guarantee
                    // that exceptions bubble up appropriately.
                    writing = write(list);

                    // Do not overwrite the list straight away, as it will
                    // be used during the write process. Instead, keep two
                    // lists and swap them (there is only one write process
                    // and one serialization process running at any given
                    // time, so two lists are enough).
                    var temp = list;
                    list      = otherList;
                    otherList = temp;

                    list.Clear();
                }
            }

            await writing.ConfigureAwait(false);

            await write(list).ConfigureAwait(false);

            // Cache the values we reached.
            _sequence = sequence;
            _position = position;
        }
예제 #4
0
 /// <see cref="IStorageDriver.GetPositionAsync"/>
 public Task <long> GetPositionAsync(CancellationToken cancel = new CancellationToken()) =>
 _source.GetPositionAsync(cancel);