/// <inheritdoc /> public Task <BlobContentHashListResponse> AddContentHashListAsync( string cacheNamespace, StrongFingerprint strongFingerprint, BlobContentHashListWithCacheMetadata contentHashList, bool forceUpdate) { var contentHashListParameters = new { cacheNamespace, weakFingerprint = strongFingerprint.WeakFingerprint.ToHex(), selectorContentHash = strongFingerprint.Selector.ContentHash.ToHex(), selectorOutput = strongFingerprint.Selector.Output?.ToHex() ?? BuildCacheResourceIds.NoneSelectorOutput, }; var queryParameters = new Dictionary <string, string>(); if (forceUpdate) { queryParameters["forceUpdate"] = forceUpdate.ToString(); } return(PostAsync <BlobContentHashListWithCacheMetadata, BlobContentHashListResponse>( contentHashList, BuildCacheResourceIds.BlobContentHashListResourceId, contentHashListParameters, queryParameters: queryParameters)); }
/// <inheritdoc /> public Task <BlobContentHashListResponse> AddContentHashListAsync( string cacheNamespace, StrongFingerprint strongFingerprint, BlobContentHashListWithCacheMetadata contentHashList) { var contentHashListParameters = new { cacheNamespace, weakFingerprint = strongFingerprint.WeakFingerprint.ToHex(), selectorContentHash = strongFingerprint.Selector.ContentHash.ToHex(), selectorOutput = strongFingerprint.Selector.Output?.ToHex() ?? BuildCacheResourceIds.NoneSelectorOutput }; return(PostAsync <BlobContentHashListWithCacheMetadata, BlobContentHashListResponse>( contentHashList, BuildCacheResourceIds.BlobContentHashListResourceId, contentHashListParameters)); }
public void NonDeterministicItemShouldNotBeCached() { var cache = BlobContentHashListCache.Instance; var cacheNamespace = "ns"; var strongFingerprint = new StrongFingerprint(Fingerprint.Random(), Selector.Random()); var contentHashList = new BlobContentHashListWithCacheMetadata( new BlobContentHashListWithDeterminism(Guid.NewGuid(), CreateBlobIdentifier()), DateTime.UtcNow); // Lets check first that the content hash list is not deterministic. contentHashList.Determinism.IsDeterministic.Should().BeFalse(); cache.AddValue(cacheNamespace, strongFingerprint, contentHashList); bool foundInCache = cache.TryGetValue(cacheNamespace, strongFingerprint, out _); foundInCache.Should().BeFalse("The cache should not save non-deterministic content hash lists."); }
private async Task <ObjectResult <ContentHashListWithCacheMetadata> > UnpackBlobContentHashListAsync(Context context, BlobContentHashListWithCacheMetadata blobCacheMetadata) { Contract.Assert(blobCacheMetadata != null); if (blobCacheMetadata.ContentHashListWithDeterminism.BlobIdentifier == null) { return(new ObjectResult <ContentHashListWithCacheMetadata>( new ContentHashListWithCacheMetadata( new ContentHashListWithDeterminism(null, blobCacheMetadata.Determinism), blobCacheMetadata.GetRawExpirationTimeUtc(), blobCacheMetadata.ContentGuarantee, blobCacheMetadata.HashOfExistingContentHashList))); } BlobIdentifier blobId = blobCacheMetadata.ContentHashListWithDeterminism.BlobIdentifier; Func <ContentHash, CancellationToken, Task <ObjectResult <Stream> > > openStreamFunc = async(hash, cts) => { OpenStreamResult openStreamResult = await _blobContentSession.OpenStreamAsync(context, hash, cts); if (openStreamResult.Succeeded) { return(new ObjectResult <Stream>(openStreamResult.Stream)); } return(new ObjectResult <Stream>(openStreamResult)); }; StructResult <ContentHashListWithDeterminism> contentHashListResult = await BlobContentHashListExtensions.UnpackFromBlob( openStreamFunc, blobId); if (contentHashListResult.Succeeded) { var contentHashListWithCacheMetadata = new ContentHashListWithCacheMetadata( contentHashListResult.Data, blobCacheMetadata.GetRawExpirationTimeUtc(), blobCacheMetadata.ContentGuarantee, blobCacheMetadata.HashOfExistingContentHashList); return(new ObjectResult <ContentHashListWithCacheMetadata>(contentHashListWithCacheMetadata)); } else { return(new ObjectResult <ContentHashListWithCacheMetadata>(contentHashListResult)); } }
/// <inheritdoc /> public async Task <ObjectResult <ContentHashListWithCacheMetadata> > AddContentHashListAsync( Context context, string cacheNamespace, StrongFingerprint strongFingerprint, ContentHashListWithCacheMetadata valueToAdd) { try { Func <System.IO.Stream, System.Threading.CancellationToken, Task <StructResult <ContentHash> > > putStreamFunc = async(stream, cts) => { PutResult putResult = await _blobContentSession.PutStreamAsync(context, HashType.Vso0, stream, cts); if (putResult.Succeeded) { return(new StructResult <ContentHash>(putResult.ContentHash)); } return(new StructResult <ContentHash>(putResult)); }; StructResult <ContentHash> blobIdOfContentHashListResult = await BlobContentHashListExtensions.PackInBlob( putStreamFunc, valueToAdd.ContentHashListWithDeterminism); if (!blobIdOfContentHashListResult.Succeeded) { return(new ObjectResult <ContentHashListWithCacheMetadata>(blobIdOfContentHashListResult)); } var blobContentHashListWithDeterminism = new BlobContentHashListWithDeterminism( valueToAdd.ContentHashListWithDeterminism.Determinism.EffectiveGuid, BlobIdentifierToContentHashExtensions.ToBlobIdentifier(blobIdOfContentHashListResult.Data)); var blobContentHashListWithCacheMetadata = new BlobContentHashListWithCacheMetadata( blobContentHashListWithDeterminism, valueToAdd.GetRawExpirationTimeUtc(), valueToAdd.ContentGuarantee, valueToAdd.HashOfExistingContentHashList); BlobContentHashListResponse addResult = await ArtifactHttpClientErrorDetectionStrategy.ExecuteWithTimeoutAsync( context, "AddContentHashList", innerCts => _buildCacheHttpClient.AddContentHashListAsync( cacheNamespace, strongFingerprint, blobContentHashListWithCacheMetadata), CancellationToken.None).ConfigureAwait(false); DownloadUriCache.Instance.BulkAddDownloadUris(addResult.BlobDownloadUris); // add succeeded but returned an empty contenthashlistwith cache metadata. correct this. if (addResult.ContentHashListWithCacheMetadata == null) { return (new ObjectResult <ContentHashListWithCacheMetadata>( new ContentHashListWithCacheMetadata( new ContentHashListWithDeterminism(null, blobContentHashListWithCacheMetadata.Determinism), blobContentHashListWithCacheMetadata.GetRawExpirationTimeUtc(), blobContentHashListWithCacheMetadata.ContentGuarantee))); } else { return(await UnpackBlobContentHashListAsync(context, addResult.ContentHashListWithCacheMetadata)); } } catch (Exception ex) { return(new ObjectResult <ContentHashListWithCacheMetadata>(ex)); } }
/// <summary> /// Adds a content hash list and its corresponding determinism value into the in-memory cache. /// </summary> public void AddValue(string cacheNamespace, StrongFingerprint strongFingerprint, BlobContentHashListWithCacheMetadata newValue) { // If there was a race, keep the value with the better determinism var contentHashListCacheDictionary = _cacheNamespaceToContentHashListCacheDictionary.GetOrAdd( cacheNamespace, key => new StrongFingerprintToHashListDictionary()); contentHashListCacheDictionary.AddOrUpdate( strongFingerprint, newValue, (oldStrongFingerprint, oldValue) => oldValue.Determinism.ShouldBeReplacedWith(newValue.Determinism) ? newValue : oldValue); }
/// <summary> /// Tries to get a content hash list for a specific strong fingerprint in the cache. /// </summary> public bool TryGetValue(string cacheNamespace, StrongFingerprint strongFingerprint, out BlobContentHashListWithCacheMetadata value) { // Try to get the existing value var contentHashListCacheDictionary = _cacheNamespaceToContentHashListCacheDictionary.GetOrAdd( cacheNamespace, key => new StrongFingerprintToHashListDictionary()); while (contentHashListCacheDictionary.TryGetValue(strongFingerprint, out BlobContentHashListWithCacheMetadata existingValue)) { if (existingValue.Determinism.IsDeterministic) { // The value is either tool deterministic or it's cache deterministic and has not expired, so it's usable value = existingValue; return(true); } if (contentHashListCacheDictionary.Remove(strongFingerprint, existingValue)) { // Removal was successful, so nothing usable value = null; return(false); } } // Nothing usable value = null; return(false); }