Esempio n. 1
0
        /// <inheritdoc />
        public Task <TValue> LoadAsync(TKey key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            lock (_sync)
            {
                TKey resolvedKey = _cacheKeyResolver(key);

                if (_options.Caching && _cache.TryGetValue(resolvedKey,
                                                           out Task <TValue> cachedValue))
                {
                    DispatchingDiagnostics.RecordCachedValue(resolvedKey,
                                                             cachedValue);

                    return(cachedValue);
                }

                var promise = new TaskCompletionSource <TValue>(
                    TaskCreationOptions.RunContinuationsAsynchronously);

                if (_options.Batching)
                {
                    if (!_buffer.TryAdd(resolvedKey, promise) &&
                        _buffer.TryGetValue(resolvedKey,
                                            out TaskCompletionSource <TValue> value))
                    {
                        promise.TrySetCanceled();
                        promise = value;
                    }
                }
                else
                {
                    // note: must run in the background; do not await here.
                    Task.Factory.StartNew(
                        () => DispatchAsync(resolvedKey, promise),
                        TaskCreationOptions.RunContinuationsAsynchronously);
                }

                if (_options.Caching)
                {
                    _cache.TryAdd(resolvedKey, promise.Task);
                }

                return(promise.Task);
            }
        }
Esempio n. 2
0
        /// <inheritdoc />
        public Task <TValue> LoadAsync(
            TKey key,
            CancellationToken cancellationToken)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            lock (_sync)
            {
                object cacheKey = _cacheKeyResolver(key);

                if (_options.Caching && _cache.TryGetValue(
                        cacheKey,
                        out Task <TValue>?cachedValue))
                {
                    DiagnosticEvents.ReceivedValueFromCache(
                        key,
                        cacheKey,
                        cachedValue);

                    return(cachedValue);
                }

                var promise = new TaskCompletionSource <TValue>(
                    TaskCreationOptions.RunContinuationsAsynchronously);

                if (_options.Batching)
                {
                    if (!_buffer.TryAdd(key, promise) &&
                        _buffer.TryGetValue(
                            key,
                            out TaskCompletionSource <TValue>?value))
                    {
                        promise.TrySetCanceled();
                        promise = value;
                    }
                    else
                    {
                        RaiseRequestBuffered();
                    }
                }
                else
                {
                    CancellationToken combinedToken = _disposeTokenSource
                                                      .CreateLinkedCancellationToken(cancellationToken);

                    // must run decoupled from this task, so that LoadAsync
                    // responds immediately; do not await here.
                    Task.Factory.StartNew(
                        () => DispatchSingleAsync(
                            key,
                            promise,
                            combinedToken),
                        TaskCreationOptions.RunContinuationsAsynchronously);
                }

                if (_options.Caching)
                {
                    _cache.TryAdd(cacheKey, promise.Task);
                }

                return(promise.Task);
            }
        }