Beispiel #1
0
        public async Task RoundtripCacheEntryWithMetadata()
        {
            ContentHash pathSetHash = await AddContent("This is a list of paths");

            WeakContentFingerprint   weak   = CreateWeakFingerprint("Fingerprint text here");
            StrongContentFingerprint strong = CreateStrongFingerprint("Strong fingerprint text here");

            CacheEntry entry = await CreateCacheEntryAndStoreContent("Metadata", "A", "B");

            Possible <CacheEntryPublishResult> maybePublished = await FingerprintStore.TryPublishCacheEntryAsync(
                weak,
                pathSetHash,
                strong,
                entry);

            XAssert.IsTrue(maybePublished.Succeeded);

            CacheEntryPublishResult publishResult = maybePublished.Result;

            XAssert.AreEqual(CacheEntryPublishStatus.Published, publishResult.Status);

            Possible <CacheEntry?> maybeFetched = await FingerprintStore.TryGetCacheEntryAsync(
                weak,
                pathSetHash,
                strong);

            XAssert.IsTrue(maybeFetched.Succeeded);
            XAssert.IsTrue(maybeFetched.Result.HasValue, "Unexpected miss (was just stored)");

            CacheEntry roundtrippedEntry = maybeFetched.Result.Value;

            AssertCacheEntriesEquivalent(entry, roundtrippedEntry);
        }
        /// <inheritdoc />
        public async Task <Possible <CacheEntryPublishResult, Failure> > TryPublishCacheEntryAsync(
            WeakContentFingerprint weakFingerprint,
            ContentHash pathSetHash,
            StrongContentFingerprint strongFingerprint,
            CacheEntry entry,
            CacheEntryPublishMode publishMode = CacheEntryPublishMode.CreateNew,
            PublishCacheEntryOptions options  = default)
        {
            // We can request semantics appropriate for CreateNewOrReplaceExisting via CacheDeterminism.SinglePhaseNonDeterministic
            // Note that conflict-rejections / failures may still occur.
            CacheDeterminism determinism = publishMode == CacheEntryPublishMode.CreateNewOrReplaceExisting
                ? CacheDeterminism.SinglePhaseNonDeterministic
                : default(CacheDeterminism);

            // N.B. this includes the metadata hash.
            CasEntries adaptedHashes = new CasEntries(
                entry.ToArray(h => new CasHash(new global::BuildXL.Cache.Interfaces.Hash(h))),
                determinism);

            Possible <FullCacheRecordWithDeterminism, Failure> maybePublished = await PerformFingerprintCacheOperationAsync(
                () => m_cache.AddOrGetAsync(
                    weak: new WeakFingerprintHash(new Hash(weakFingerprint.Hash)),
                    casElement: new CasHash(new Hash(pathSetHash)),
                    hashElement: new Hash(strongFingerprint.Hash),
                    hashes: adaptedHashes,
                    urgencyHint: options.ShouldPublishAssociatedContent ? UrgencyHint.RegisterAssociatedContent : UrgencyHint.SkipRegisterContent),
                nameof(TryPublishCacheEntryAsync));

            if (maybePublished.Succeeded)
            {
                if (maybePublished.Result.Record == null)
                {
                    // Happy path: Entry accepted without an alternative.
                    return(CacheEntryPublishResult.CreatePublishedResult());
                }
                else
                {
                    // Less happy path: The underlying store has an alternative entry that we need to use instead.
                    Possible <CacheEntry, Failure> maybeConvertedConflictingEntry = TryConvertCasEntriesToCacheEntry(maybePublished.Result.Record.CasEntries, maybePublished.Result.Record.CacheId);
                    if (maybeConvertedConflictingEntry.Succeeded)
                    {
                        return(CacheEntryPublishResult.CreateConflictResult(maybeConvertedConflictingEntry.Result));
                    }
                    else
                    {
                        return(maybeConvertedConflictingEntry.Failure.Annotate(
                                   "The cache returned a conflicting entry (rejecting the proposed entry), but the conflicting entry is invalid."));
                    }
                }
            }
            else
            {
                return(maybePublished.Failure);
            }
        }
Beispiel #3
0
        private async Task PublishExpectingNoConflict(
            WeakContentFingerprint weak,
            ContentHash pathSetHash,
            StrongContentFingerprint strong,
            CacheEntry entry)
        {
            Possible <CacheEntryPublishResult> maybePublished = await FingerprintStore.TryPublishCacheEntryAsync(
                weak,
                pathSetHash,
                strong,
                entry);

            XAssert.IsTrue(maybePublished.Succeeded);

            CacheEntryPublishResult publishResult = maybePublished.Result;

            XAssert.AreEqual(CacheEntryPublishStatus.Published, publishResult.Status);
        }
Beispiel #4
0
        public async Task FailedPublishReturnsConflictingEntry()
        {
            ContentHash pathSetHash = await AddContent("This is a list of paths");

            WeakContentFingerprint   weak   = CreateWeakFingerprint("Fingerprint text here");
            StrongContentFingerprint strong = CreateStrongFingerprint("Strong fingerprint text here");

            CacheEntry originalEntry = await CreateCacheEntryAndStoreContent("Metadata", "A", "B");

            Possible <CacheEntryPublishResult> maybePublished = await FingerprintStore.TryPublishCacheEntryAsync(
                weak,
                pathSetHash,
                strong,
                originalEntry);

            XAssert.IsTrue(maybePublished.Succeeded);

            CacheEntryPublishResult publishResult = maybePublished.Result;

            XAssert.AreEqual(CacheEntryPublishStatus.Published, publishResult.Status);

            CacheEntry successorEntry = await CreateCacheEntryAndStoreContent("Metadata", "Different A", "Different B");

            Possible <CacheEntryPublishResult> maybePublishedAgain = await FingerprintStore.TryPublishCacheEntryAsync(
                weak,
                pathSetHash,
                strong,
                successorEntry);

            // The conflict info is in the result (not a failure).
            XAssert.IsTrue(maybePublishedAgain.Succeeded);
            CacheEntryPublishResult publishAgainResult = maybePublishedAgain.Result;

            XAssert.AreEqual(CacheEntryPublishStatus.RejectedDueToConflictingEntry, publishAgainResult.Status);

            // Original entry should be returned.
            AssertCacheEntriesEquivalent(publishAgainResult.ConflictingEntry, originalEntry);
        }