/// <summary> Attempt to save this projection to the destination stream. </summary>
        /// <remarks>
        ///     The returned task does not access the projection in any way, so the
        ///     projection may be safely accessed before the task has finished executing.
        /// </remarks>
        /// <returns>
        ///     True if saving was successful, false if it failed.
        /// </returns>
        public async Task <bool> TrySaveAsync(CancellationToken cancel = default)
        {
            if (_possiblyInconsistent)
            {
                _log?.Warning($"[{Name}] state is possibly inconsistent, not saving.");
                return(false);
            }

            if (_cacheProvider == null)
            {
                _log?.Warning($"[{Name}] no write cache provider !");
                return(false);
            }

            var sequence = Sequence;
            var current  = Current;

            _log?.Debug($"[{Name}] saving to seq {sequence}.");

            var sw = Stopwatch.StartNew();

            var wrote = 0L;

            try
            {
                await _cacheProvider.TryWriteAsync(Name, async destination =>
                {
                    try
                    {
                        using (destination)
                        {
                            using (var wr = new BinaryWriter(destination, Encoding.UTF8, true))
                                wr.Write(sequence);

                            if (!await _projection.TrySaveAsync(destination, current, cancel))
                            {
                                _log?.Warning($"[{Name}] projection failed to save.");
                                throw new Exception("INTERNAL.DO.NOT.SAVE");
                            }

                            if (!destination.CanWrite)
                            {
                                throw new Exception("Projection saving closed the stream ! ");
                            }

                            using (var wr = new BinaryWriter(destination, Encoding.UTF8, true))
                                wr.Write(sequence);

                            wrote = destination.Position;
                        }
                    }
                    catch (Exception e) when(e.Message == "INTERNAL.DO.NOT.SAVE")
                    {
                    }
                    catch (Exception e)
                    {
                        _log?.Warning($"[{Name}] while saving to cache.", e);
                        throw new Exception("INTERNAL.DO.NOT.SAVE", e);
                    }
                }).ConfigureAwait(false);

                if (wrote == 0)
                {
                    _log?.Warning($"[{Name}] caching is disabled for this projection.");
                }
                else
                {
                    _log?.Info($"[{Name}] saved {wrote} bytes to cache in {sw.Elapsed:mm':'ss'.'fff}.");
                }

                return(true);
            }
            catch (Exception e) when(e.Message == "INTERNAL.DO.NOT.SAVE")
            {
                // The inner function asked us not to save, and already logged the reason.
                // But if an inner exception is included, throw it (preserving the existing
                // stack trace).
                if (e.InnerException != null)
                {
                    ExceptionDispatchInfo.Capture(e.InnerException).Throw();
                }

                return(false);
            }
            catch (Exception ex)
            {
                _log?.Warning($"[{Name}] when opening write cache.", ex);
                return(false);
            }
        }
Beispiel #2
0
        /// <summary> Attempt to save this projection to the destination stream. </summary>
        /// <remarks>
        /// The returned task does not access the object in any way, so the object
        /// may be safely accessed before the task has finished executing.
        /// </remarks>
        public async Task TrySaveAsync(CancellationToken cancel = default(CancellationToken))
        {
            if (_possiblyInconsistent)
            {
                _log?.Warning($"[{Name}] state is possibly inconsistent, not saving.");
                return;
            }

            if (_cacheProvider == null)
            {
                _log?.Warning($"[{Name}] no write cache provider !");
                return;
            }

            var sequence = Sequence;
            var current  = Current;

            _log?.Debug($"[{Name}] saving to seq {sequence}.");

            Stream destination;
            var    sw = Stopwatch.StartNew();

            try
            {
                destination = await _cacheProvider.OpenWriteAsync(Name);
            }
            catch (Exception ex)
            {
                _log?.Warning($"[{Name}] when opening write cache.", ex);
                throw;
            }

            if (destination == null)
            {
                _log?.Warning($"[{Name}] caching is disabled for this projection.");
                return;
            }

            try
            {
                using (destination)
                {
                    using (var wr = new BinaryWriter(destination, Encoding.UTF8, true))
                        wr.Write(sequence);

                    if (!await _projection.TrySaveAsync(destination, current, cancel))
                    {
                        _log?.Warning($"[{Name}] projection failed to save.");
                        return;
                    }

                    if (!destination.CanWrite)
                    {
                        throw new Exception("Projection saving closed the stream ! ");
                    }

                    using (var wr = new BinaryWriter(destination, Encoding.UTF8, true))
                        wr.Write(sequence);
                }
            }
            catch (Exception e)
            {
                _log?.Warning($"[{Name}] while saving to cache.", e);
                throw;
            }

            _log?.Info($"[{Name}] saved in cache in {sw.Elapsed:mm':'ss'.'fff}.");
        }