/// <inheritdoc /> public async Task <Possible <ContentAvailabilityBatchResult, Failure> > TryLoadAvailableContentAsync(IReadOnlyList <ContentHash> hashes) { using (var hashAvailabilityMapWrapper = m_hashAvailabilityMapPool.GetInstance()) using (var hashListWrapper = m_hashListPool.GetInstance()) { var hashAvailabilityMap = hashAvailabilityMapWrapper.Instance; var hashList = hashListWrapper.Instance; var uniqueUnknownAvailabilityHashes = DeduplicateAndGetUnknownAvailabilityHashes(hashes, hashAvailabilityMap, hashList); bool allContentAvailable = true; if (uniqueUnknownAvailabilityHashes.Count != 0) { // Only query inner cache if there are hashes whose availabilty is unknown var possibleBatchResult = await m_innerCache.TryLoadAvailableContentAsync(uniqueUnknownAvailabilityHashes); if (!possibleBatchResult.Succeeded || uniqueUnknownAvailabilityHashes == hashes) { // If not successful or the hashes are the same as original hashes just return the result return(possibleBatchResult); } // Populate hash availability map with results from inner cache foreach (var result in possibleBatchResult.Result.Results) { hashAvailabilityMap[result.Hash] = result; if (!result.IsAvailable) { allContentAvailable = false; } else { // Mark the hash as available for subsequent operations m_availableContent.TryAdd(result.Hash, result.SourceCache); } } } ContentAvailabilityResult[] results = new ContentAvailabilityResult[hashes.Count]; for (int i = 0; i < hashes.Count; i++) { var hash = hashes[i]; if (hashAvailabilityMap.TryGetValue(hash, out var result)) { results[i] = result; } else { throw Contract.AssertFailure(I($"Hash {hash} should be present in availability map.")); } } return(new ContentAvailabilityBatchResult(ReadOnlyArray <ContentAvailabilityResult> .FromWithoutCopy(results), allContentAvailable)); } }
private IReadOnlyList <ContentHash> DeduplicateAndGetUnknownAvailabilityHashes( IReadOnlyList <ContentHash> hashes, Dictionary <ContentHash, ContentAvailabilityResult> hashAvailabilityMap, List <ContentHash> hashList) { bool hasDuplicateOrKnownAvailableHash = false; for (int i = 0; i < hashes.Count; i++) { var hash = hashes[i]; if (!hashAvailabilityMap.TryGetValue(hash, out var result)) { if (m_availableContent.TryGetValue(hash, out var sourceCache)) { // Known available hash hasDuplicateOrKnownAvailableHash = true; result = new ContentAvailabilityResult(hash, true, 0, sourceCache); } hashAvailabilityMap[hash] = result; } else { // Duplicate hasDuplicateOrKnownAvailableHash = true; } } IReadOnlyList <ContentHash> uniqueUnknownAvailabilityHashes; if (!hasDuplicateOrKnownAvailableHash) { // Just use original set of hashes since no duplicates or known available hashes uniqueUnknownAvailabilityHashes = hashes; } else { // Only submit unique hashes which are not known to be available to the inner cache foreach (var entry in hashAvailabilityMap) { if (!entry.Value.IsAvailable) { hashList.Add(entry.Key); } } uniqueUnknownAvailabilityHashes = hashList; } return(uniqueUnknownAvailabilityHashes); }
/// <inheritdoc /> public Task <Possible <ContentAvailabilityBatchResult, Failure> > TryLoadAvailableContentAsync(IReadOnlyList <ContentHash> hashes) { return(Task.Run <Possible <ContentAvailabilityBatchResult, Failure> >( () => { lock (m_lock) { bool allAvailable = true; var results = new ContentAvailabilityResult[hashes.Count]; for (int i = 0; i < hashes.Count; i++) { CacheEntry entry; bool available = m_content.TryGetValue(hashes[i], out entry); long bytesTransferredRemotely; // The content is now in the local site, if it wasn't already. if (available) { bytesTransferredRemotely = (entry.Sites & CacheSites.Local) == 0 ? entry.Content.Length : 0; entry.Sites |= CacheSites.Local; } else { bytesTransferredRemotely = 0; } results[i] = new ContentAvailabilityResult(hashes[i], isAvailable: available, bytesTransferred: bytesTransferredRemotely, sourceCache: "InMemoryCache"); allAvailable &= available; } return new ContentAvailabilityBatchResult( ReadOnlyArray <ContentAvailabilityResult> .FromWithoutCopy(results), allContentAvailable: allAvailable); } })); }