Example #1
0
        // Protected methods

        protected static void SetReturnValue(ComputeMethodInput input, Result <TOut> output)
        {
            if (input.Method.ReturnsValueTask)
            {
                input.Invocation.ReturnValue =
                    // ReSharper disable once HeapView.BoxingAllocation
                    output.IsValue(out var v)
                        ? ValueTaskEx.FromResult(v)
                        : ValueTaskEx.FromException <TOut>(output.Error !);
            }
            else
            {
                input.Invocation.ReturnValue =
                    output.IsValue(out var v)
                        ? Task.FromResult(v)
                        : Task.FromException <TOut>(output.Error !);
            }
        }
Example #2
0
        public override async Task <T> InvokeAndStrip(
            ComputeMethodInput input, IComputed?usedBy, ComputeContext?context,
            CancellationToken cancellationToken = default)
        {
            context ??= ComputeContext.Current;
            ResultBox <T>?output;

            // Read-Lock-RetryRead-Compute-Store pattern

            var computed = TryGetExisting(input);

            if (computed != null)
            {
                output = await computed.TryUseExisting(context, usedBy, cancellationToken)
                         .ConfigureAwait(false);

                if (output != null)
                {
                    return(output.Value);
                }
            }

            using var @lock = await Locks.Lock(input, cancellationToken).ConfigureAwait(false);

            computed = TryGetExisting(input);
            if (computed != null)
            {
                output = await computed.TryUseExisting(context, usedBy, cancellationToken)
                         .ConfigureAwait(false);

                if (output != null)
                {
                    return(output.Value);
                }
            }

            computed = (IAsyncComputed <T>) await Compute(input, computed, cancellationToken)
                       .ConfigureAwait(false);

            var rOutput = computed.Output; // RenewTimeouts isn't called yet, so it's ok

            computed.UseNew(context, usedBy);
            return(rOutput !.Value);
        }
        protected override async ValueTask <IComputed <T> > Compute(
            ComputeMethodInput input, IComputed <T>?existing,
            CancellationToken cancellationToken)
        {
            var tag      = VersionGenerator.Next();
            var computed = CreateComputed(input, tag);

            try {
                using var _ = Computed.ChangeCurrent(computed);
                var result = input.InvokeOriginalFunction(cancellationToken);
                if (input.Method.ReturnsValueTask)
                {
                    var output = await((ValueTask <T>)result).ConfigureAwait(false);
                    computed.TrySetOutput(output);
                }
                else
                {
                    var output = await((Task <T>)result).ConfigureAwait(false);
                    computed.TrySetOutput(output);
                }
            }
            catch (OperationCanceledException e) {
                computed.TrySetOutput(Result.Error <T>(e));
                computed.Invalidate();
                throw;
            }
            catch (Exception e) {
                if (e is AggregateException ae)
                {
                    e = ae.GetFirstInnerException();
                }
                computed.TrySetOutput(Result.Error <T>(e));
                // Weird case: if the output is already set, all we can
                // is to ignore the exception we've just caught;
                // throwing it further will probably make it just worse,
                // since the the caller have to take this scenario into acc.
            }
            return(computed);
        }
 protected abstract IComputed <T> CreateComputed(ComputeMethodInput input, LTag tag);
Example #5
0
        protected new IAsyncComputed <T>?TryGetExisting(ComputeMethodInput input)
        {
            var computed = ComputedRegistry.Instance.TryGet(input);

            return(computed as IAsyncComputed <T>);
        }
Example #6
0
 protected override IComputed <T> CreateComputed(ComputeMethodInput input, LTag tag)
 => new SwappingComputed <T>(Options, input, tag);