public void DictionaryContainsAllKeysInInput_ReturnsEmpty(int inputKeysCount) { var inputKeys = Enumerable.Range(0, inputKeysCount).ToArray(); var dictionary = inputKeys.ToDictionary(k => k); var missingKeys = MissingKeysResolver <int, int> .GetMissingKeys(inputKeys, dictionary, out var pooledArray); missingKeys.IsEmpty.Should().BeTrue(); pooledArray.Should().BeNull(); }
public void EmptyDictionary_ReturnsInput() { var inputKeys = Enumerable.Range(0, 10).ToArray(); var missingKeys = MissingKeysResolver <int, int> .GetMissingKeys( inputKeys, new Dictionary <int, int>(), out var pooledArray); missingKeys.ToArray().Should().BeEquivalentTo(inputKeys); pooledArray.Should().BeNull(); }
public void DictionaryIsSubsetOfInputKeys_CorrectlyReturnsOnlyThoseMissing(int inputKeysCount, int keysFoundCount) { var inputKeys = Enumerable.Range(0, inputKeysCount).ToArray(); var dictionary = inputKeys .OrderBy(_ => Guid.NewGuid()) .Take(keysFoundCount) .ToDictionary(k => k); var missingKeys = MissingKeysResolver <int, int> .GetMissingKeys( inputKeys, dictionary, out var pooledArray); missingKeys.ToArray().Should().BeEquivalentTo(inputKeys.Except(dictionary.Keys)); pooledArray.Should().NotBeNull(); }
public void DictionaryContainsKeysNotInInput_CorrectlyReturnsOnlyThoseMissing( int inputKeysCount, int keysFoundCount, int keysNotInInputCount) { var inputKeys = Enumerable.Range(0, inputKeysCount).ToArray(); var dictionary = inputKeys .OrderBy(_ => Guid.NewGuid()) .Take(keysFoundCount - keysNotInInputCount) .Concat(Enumerable.Range(1, keysNotInInputCount).Select(k => - k)) .ToDictionary(k => k); var missingKeys = MissingKeysResolver <int, int> .GetMissingKeys( inputKeys, dictionary, out _); missingKeys.ToArray().Should().BeEquivalentTo(inputKeys.Except(dictionary.Keys)); }
public async ValueTask <Dictionary <TKey, TValue> > GetMany( TParams parameters, IEnumerable <TKey> keys, CancellationToken cancellationToken) { var(start, timer) = GetDateAndTimer(); var keysMemory = keys.ToReadOnlyMemory(out var pooledKeysArray); try { cancellationToken.ThrowIfCancellationRequested(); var getFromCacheTask = GetFromCache(parameters, keysMemory); var(resultsDictionary, cacheStats) = getFromCacheTask.IsCompleted ? getFromCacheTask.Result : await getFromCacheTask.ConfigureAwait(false); if (cacheStats.CacheHits == keysMemory.Length) { return(FinalizeResults(resultsDictionary, cacheStats)); } var missingKeys = MissingKeysResolver <TKey, TValue> .GetMissingKeys( keysMemory, resultsDictionary, out var pooledMissingKeysArray); try { var maxBatchSize = _maxBatchSizeFactory?.Invoke(parameters, missingKeys) ?? _maxBatchSize; if (missingKeys.Length < maxBatchSize) { var resultsDictionaryTask = GetValuesFromFunc( parameters, missingKeys, cancellationToken, resultsDictionary); resultsDictionary = resultsDictionaryTask.IsCompleted ? resultsDictionaryTask.Result : await resultsDictionaryTask.ConfigureAwait(false); } else { var batchSizes = BatchingHelper.GetBatchSizes(missingKeys.Length, maxBatchSize, _batchBehaviour); resultsDictionary ??= new Dictionary <TKey, TValue>(_keyComparer); Task[] tasks = null; var resultsDictionaryLock = new object(); var tasksIndex = 0; var totalKeysBatchedCount = 0; for (var batchIndex = 0; batchIndex < batchSizes.Length; batchIndex++) { var keysStartIndex = totalKeysBatchedCount; var batchSize = batchSizes[batchIndex]; totalKeysBatchedCount += batchSize; var getValuesFromFuncTask = GetValuesFromFunc( parameters, keysMemory.Slice(keysStartIndex, batchSize), cancellationToken, resultsDictionary, resultsDictionaryLock); if (getValuesFromFuncTask.IsCompletedSuccessfully) { continue; } if (tasks is null) { tasks = new Task[batchSizes.Length - batchIndex]; } tasks[tasksIndex++] = getValuesFromFuncTask.AsTask(); } if (!(tasks is null)) { await Task.WhenAll(new ArraySegment <Task>(tasks, 0, tasksIndex)).ConfigureAwait(false); } } } finally { if (!(pooledMissingKeysArray is null)) { ArrayPool <TKey> .Shared.Return(pooledMissingKeysArray); } } return(FinalizeResults(resultsDictionary, cacheStats)); } catch (Exception ex) when(!(_onExceptionAction is null)) { _onExceptionAction?.Invoke(new ExceptionEvent <TParams, TKey>( parameters, keysMemory, start, timer.Elapsed, ex)); throw; } finally { if (!(pooledKeysArray is null)) { ArrayPool <TKey> .Shared.Return(pooledKeysArray); } } Dictionary <TKey, TValue> FinalizeResults( Dictionary <TKey, TValue> resultsDictionary, CacheGetManyStats cacheStats) { resultsDictionary = FilterResults(resultsDictionary, out var countExcluded); _onSuccessAction?.Invoke(new SuccessfulRequestEvent <TParams, TKey, TValue>( parameters, keysMemory, resultsDictionary, start, timer.Elapsed, cacheStats, countExcluded)); return(resultsDictionary); } }