/// <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));
        }
Пример #2
0
        /// <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));
        }
Пример #3
0
        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);
        }