示例#1
0
        /// <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) && entry.Sites != CacheSites.None;
                        long bytesTransferredRemotely = 0;

                        if (available)
                        {
                            if ((entry.Sites & CacheSites.Local) == 0)
                            {
                                ExceptionUtilities.HandleRecoverableIOException(
                                    () =>
                                {
                                    // Copy to local side.
                                    bytesTransferredRemotely = Download(hashes[i]);
                                },
                                    ex => throw new BuildXLException(I($"Failed to load content '{hashes[i]}' from remote site"), ex));
                            }

                            entry.Sites |= CacheSites.Local;
                        }

                        results[i] = new ContentAvailabilityResult(
                            hashes[i],
                            isAvailable: available,
                            bytesTransferred: bytesTransferredRemotely,
                            sourceCache: nameof(MockArtifactContentCache));
                        allAvailable &= available;
                    }

                    return new ContentAvailabilityBatchResult(
                        ReadOnlyArray <ContentAvailabilityResult> .FromWithoutCopy(results),
                        allContentAvailable: allAvailable);
                }
            }));
        }
示例#2
0
        /// <inheritdoc />
        public async Task <Possible <ContentAvailabilityBatchResult, Failure> > TryLoadAvailableContentAsync(IReadOnlyList <ContentHash> hashes)
        {
            // TODO: These conversions are silly.
            CasHash[] casHashes = new CasHash[hashes.Count];
            for (int i = 0; i < casHashes.Length; i++)
            {
                casHashes[i] = new CasHash(new global::BuildXL.Cache.Interfaces.Hash(hashes[i]));
            }

            Possible <ICacheSession, Failure> maybeOpen = m_cache.Get(nameof(TryLoadAvailableContentAsync));

            if (!maybeOpen.Succeeded)
            {
                return(maybeOpen.Failure);
            }

            Possible <string, Failure>[] multiMaybePinned = await maybeOpen.Result.PinToCasAsync(casHashes);

            Contract.Assume(multiMaybePinned != null);
            Contract.Assume(multiMaybePinned.Length == casHashes.Length);

            var     results             = new ContentAvailabilityResult[casHashes.Length];
            Failure aggregateFailure    = null;
            bool    allContentAvailable = true;

            for (int i = 0; i < casHashes.Length; i++)
            {
                Possible <string, Failure> maybePinned = multiMaybePinned[i];

                if (maybePinned.Succeeded)
                {
                    // TODO: This doesn't indicate what is local / how much was transfered. From the similar BuildCache adapter:
                    //  long transferred = successfulResult.TransferredBytes;
                    // TODO: This API will fail just because content isn't available; see below for that case.
                    results[i] = new ContentAvailabilityResult(hashes[i], isAvailable: true, bytesTransferred: 0, sourceCache: maybePinned.Result);
                    BuildXL.Storage.Tracing.Logger.Log.StorageCacheContentPinned(Events.StaticContext, casHashes[i].ToString(), maybePinned.Result);
                }
                else if (maybePinned.Failure is NoCasEntryFailure)
                {
                    // TODO: As above: this API will fail just because content isn't available, and that case isn't distinguishable (at least by looking at the interface alone).
                    //              That's not reasonable for implementations in general, such as BuildCache (or anything else with weak LRU; failures should not be 'normal'
                    //              By contract, IArtifactContentCache defines available vs. unavailable on the (successful) result object, as established here.
                    //              Note that we have idenitifed the content-miss case by reflecting; but that is quite fragile and requires some not-yet-prescribed co-operation from the implementations as to failure type.
                    allContentAvailable = false;
                    results[i]          = new ContentAvailabilityResult(hashes[i], isAvailable: false, bytesTransferred: 0, sourceCache: "ContentMiss");
                }
                else
                {
                    if (aggregateFailure == null)
                    {
                        aggregateFailure = maybePinned.Failure.Annotate("Retrieval failed for one or more content blobs by hash");
                    }

                    // We return only an aggregate error from this function. To prevent erasing information, we log each error returned from
                    // the cache here (the caller may choose to also log the aggregate failure.
                    BuildXL.Storage.Tracing.Logger.Log.StorageCacheCopyLocalError(
                        Events.StaticContext,
                        hashes[i].ToString(),
                        maybePinned.Failure.DescribeIncludingInnerFailures());
                }
            }

            if (aggregateFailure == null)
            {
                return(new ContentAvailabilityBatchResult(
                           ReadOnlyArray <ContentAvailabilityResult> .FromWithoutCopy(results),
                           allContentAvailable: allContentAvailable));
            }
            else
            {
                return(aggregateFailure);
            }
        }