コード例 #1
0
        /// <inheritdoc />
        public IEnumerable <Task <Possible <StrongFingerprint, Failure> > > EnumerateStrongFingerprints(
            WeakFingerprintHash weak, UrgencyHint urgencyHint, Guid activityId)
        {
            // TODO: Extend IAsyncEnumerable up through EnumerateStrongFingerprints
            var tcs = TaskSourceSlim.Create <IEnumerable <GetSelectorResult> >();

            yield return(Task.Run(
                             async() =>
            {
                try
                {
                    var results = await ReadOnlyCacheSession.GetSelectors(new Context(Logger), weak.ToMemoization(), CancellationToken.None).ToListAsync();
                    tcs.SetResult(results);
                    return results.Any() ? results.First().FromMemoization(weak, CacheId) : StrongFingerprintSentinel.Instance;
                }
                catch (Exception ex)
                {
                    tcs.SetException(ex);
                    throw;
                }
            }));

            // For now, callers should always await the first task before enumerating the rest
            Contract.Assert(tcs.Task.IsCompleted);
            IEnumerable <GetSelectorResult> otherResults = tcs.Task.GetAwaiter().GetResult();

            foreach (var otherResult in otherResults.Skip(1))
            {
                yield return(Task.FromResult(otherResult.FromMemoization(weak, CacheId)));
            }
        }
コード例 #2
0
        /// <summary>
        /// Failure of an observed input list filter
        /// </summary>
        /// <param name="cacheId">Cache ID where failure happened</param>
        /// <param name="weak">Weak fingerprint component of the strong fingerprint</param>
        /// <param name="casElement">The CasElement component of the strong fingerprint</param>
        /// <param name="hashElement">The HashElement component of the strong fingerprint</param>
        /// <param name="message">Details about the failure</param>
        public InputListFilterFailure(string cacheId, WeakFingerprintHash weak, CasHash casElement, Hash hashElement, string message)
        {
            Contract.Requires(message != null);

            m_strongFingerprint = new StrongFingerprint(weak, casElement, hashElement, cacheId);
            m_message           = message;
        }
コード例 #3
0
        /// <summary>
        /// Creates a FakeStrongFingerpint and the associated FakeBuild streams.
        /// </summary>
        /// <param name="pipName">Name of the pip</param>
        /// <param name="generateVerifiablePip">Determines if CheckContentsAsync can verify the contents of the build</param>
        /// <param name="pipSize">Number of files to include in the pip</param>
        /// <remarks>
        /// This method is the StrongFingerprint generation algorithm for FakeBuild.DoNondeterministicPipAsync
        /// </remarks>
        /// <returns>A FakeStrongFingerprint that has the FakeBuild class</returns>
        public static FakeStrongFingerprint Create(string pipName, bool generateVerifiablePip = false, int pipSize = 3)
        {
            FakeBuild           fake = new FakeBuild(pipName, pipSize, forceUniqueOutputs: !generateVerifiablePip);
            WeakFingerprintHash weak = CreateWeak(pipName.ToLowerInvariant());
            Hash simpleHash          = CreateHash(pipName.ToUpperInvariant());

            return(new FakeStrongFingerprint(weak, simpleHash, fake));
        }
コード例 #4
0
        private async Task <Possible <FullCacheRecordWithDeterminism, Failure> > AddToCache(ICacheSession session, params string[] thePaths)
        {
            WeakFingerprintHash weak    = FakeStrongFingerprint.CreateWeak(session.CacheId);
            CasHash             casHash = await AddPathSet(session, thePaths);

            Hash simpleHash = FakeStrongFingerprint.CreateHash(session.CacheSessionId);

            return(await session.AddOrGetAsync(weak, casHash, simpleHash, CasEntries.FromCasHashes(casHash)));
        }
コード例 #5
0
        /// <summary>
        /// Create the failure, including the weak fingerprint for which enumeration failed
        /// </summary>
        /// <param name="cacheId">The cacheId where the failure happened</param>
        /// <param name="weak">The weak fingerprint for which enumeration was attempted</param>
        /// <param name="rootCause">Optional root cause exception</param>
        public StrongFingerprintEnumerationFailure(string cacheId, WeakFingerprintHash weak, Exception rootCause)
        {
            Contract.Requires(cacheId != null);
            Contract.Requires(rootCause != null);

            m_cacheId   = cacheId;
            m_weak      = weak;
            m_rootCause = rootCause;
        }
コード例 #6
0
        public void SelectorResultSuccessFromMemoization()
        {
            WeakFingerprintHash weak           = RandomHelpers.CreateRandomWeakFingerprintHash();
            GetSelectorResult   selectorResult = new GetSelectorResult(Selector.Random(HashType.Vso0, FingerprintUtilities.FingerprintLength));
            Possible <BuildXLStrongFingerprint, Failure> maybeStrongFingerprint = selectorResult.FromMemoization(weak, CacheId);

            Assert.True(maybeStrongFingerprint.Succeeded);
            Assert.Equal(weak, maybeStrongFingerprint.Result.WeakFingerprint);
            Assert.Equal(selectorResult.Selector.ContentHash.FromMemoization(), maybeStrongFingerprint.Result.CasElement);
            Assert.Equal(selectorResult.Selector.Output, maybeStrongFingerprint.Result.HashElement.ToArray());
            Assert.Equal(CacheId, maybeStrongFingerprint.Result.CacheId);
        }
コード例 #7
0
ファイル: Extensions.cs プロジェクト: kittinap/kunnjae
        /// <summary>
        /// Iterates over input strong fingerprints and returns all unique weak fingerprints
        /// </summary>
        /// <param name="strongFingerprints">Strong fingerprints to iterate over</param>
        /// <returns>All unique weak fingerprints found among input strong fingerprints</returns>
        public static IEnumerable <WeakFingerprintHash> ProduceWeakFingerprints(this IEnumerable <StrongFingerprint> strongFingerprints)
        {
            HashSet <WeakFingerprintHash> weakFingerprintsAlreadyFound = new HashSet <WeakFingerprintHash>();

            foreach (StrongFingerprint strongFingerprint in strongFingerprints)
            {
                WeakFingerprintHash weakFingerprint = strongFingerprint.WeakFingerprint;
                if (weakFingerprintsAlreadyFound.Add(weakFingerprint))
                {
                    yield return(weakFingerprint);
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// Writes the Start Activity event
        /// </summary>
        public void Start(WeakFingerprintHash weak, UrgencyHint urgencyHint)
        {
            Start();

            if (TraceMethodArgumentsEnabled())
            {
                Write(
                    ParameterOptions,
                    new
                {
                    WeakFingerprintHash = weak,
                    UrgencyHint         = urgencyHint,
                });
            }
        }
コード例 #9
0
        /// <summary>
        /// Writes the Start Activity event
        /// </summary>
        public void Start(WeakFingerprintHash weak, CasHash casElement, Hash hashElement, CasEntries hashes, UrgencyHint urgencyHint)
        {
            Start();

            if (TraceMethodArgumentsEnabled())
            {
                Write(
                    ParameterOptions,
                    new
                {
                    WeakFingerprintHash = weak,
                    CasHash             = casElement,
                    Hash        = hashElement,
                    CasEntries  = hashes,
                    UrgencyHint = urgencyHint,
                });
            }
        }
コード例 #10
0
        public async Task AddWithoutPinWeak()
        {
            const string TestName    = nameof(AddWithoutPinWeak);
            string       testCacheId = MakeCacheId(TestName);
            ICache       cache       = await CreateCacheAsync(testCacheId, strictMetadataCasCoupling : false);

            // Only caches that are not strict metadata to CAS coupling need this test
            if (cache.StrictMetadataCasCoupling)
            {
                (await cache.ShutdownAsync()).Success();
                return;
            }

            string        testSessionId = "Session1-" + testCacheId;
            ICacheSession session       = await CreateSessionAsync(cache, testSessionId);

            FakeBuild fake = new FakeBuild(TestName, 2);

            // We fake up a CasHash - never actually add to the cache - weak cas
            CasHash inputList = fake.OutputListHash;

            CasHash[] items = new CasHash[fake.Outputs.Length];
            for (int i = 0; i < fake.Outputs.Length; i++)
            {
                items[i] = new CasHash(fake.OutputHashes[i]);
            }

            // We use the hash of our output list as the weak fingerprint and extra hash
            var outputListFingerprintHash = fake.OutputListHash.ToFingerprint();
            WeakFingerprintHash weak      = new WeakFingerprintHash(outputListFingerprintHash);

            // This should work since the session is weak.
            FullCacheRecordWithDeterminism record = (await session.AddOrGetAsync(weak, inputList, outputListFingerprintHash, items)).Success();

            XAssert.IsNull(record.Record, "There should not have been anything in the cache");

            // Doing it twice does not change things...
            record = (await session.AddOrGetAsync(weak, inputList, outputListFingerprintHash, items)).Success();
            XAssert.IsNull(record.Record, "It matches exactly, so no bother");

            await CloseSessionAsync(session, testSessionId);

            await ShutdownCacheAsync(cache, testCacheId);
        }
コード例 #11
0
        /// <inheritdoc />
        public IEnumerable <Task <Possible <PublishedEntryRef, Failure> > > ListPublishedEntriesByWeakFingerprint(WeakContentFingerprint weak)
        {
            WeakFingerprintHash cacheCoreWeakFingerprint = new WeakFingerprintHash(new Hash(weak.Hash));

            // TODO: We assume that everything up until the first sentinel is local. This is fine for a simple 'vertical' aggregator
            //       of a local and remote cache, but isn't general.
            PublishedEntryRefLocality currentLocality = PublishedEntryRefLocality.Local;

            foreach (Task <Possible <StrongFingerprint, Failure> > entryPromise in m_cache.EnumerateStrongFingerprints(cacheCoreWeakFingerprint))
            {
                if (entryPromise.IsCompleted && entryPromise.Result.Succeeded && entryPromise.Result.Result is StrongFingerprintSentinel)
                {
                    currentLocality = PublishedEntryRefLocality.Remote;
                    continue;
                }

                yield return(AdaptPublishedEntry(entryPromise, currentLocality));
            }
        }
コード例 #12
0
        public async Task CacheMissTest()
        {
            const string TestName    = nameof(CacheMissTest);
            string       testCacheId = MakeCacheId(TestName);
            ICache       cache       = await CreateCacheAsync(testCacheId);

            ICacheSession session = await cache.CreateSessionAsync().SuccessAsync();

            FakeBuild fb = new FakeBuild("test", 3);

            StrongFingerprint fakeFingerprint = new StrongFingerprint(WeakFingerprintHash.Random(), new CasHash(fb.OutputHashes[0]), fb.OutputHashes[0], "fake");

            var response = await session.GetCacheEntryAsync(fakeFingerprint);

            XAssert.IsFalse(response.Succeeded);
            XAssert.AreEqual(typeof(NoMatchingFingerprintFailure), response.Failure.GetType(), response.Failure.Describe());

            await CloseSessionAsync(session, null);
            await ShutdownCacheAsync(cache, testCacheId);
        }
コード例 #13
0
ファイル: FakeBuild.cs プロジェクト: microsoft/BuildXL
        private static async Task <FullCacheRecord> DoPipAsyncImpl(ICacheSession session,
                                                                   WeakFingerprintHash weak,
                                                                   Hash simpleHash,
                                                                   FakeBuild fake,
                                                                   CacheDeterminism determinism,
                                                                   CasAccessMethod accessMethod)
        {
            foreach (var strongTask in session.EnumerateStrongFingerprints(weak))
            {
                StrongFingerprint possibleHit = await strongTask.SuccessAsync();

                if (fake.OutputListHash.Equals(possibleHit.CasElement))
                {
                    if (simpleHash.Equals(possibleHit.HashElement))
                    {
                        // A cache hit!  Our strong fingerprint matched
                        return(new FullCacheRecord(possibleHit, await session.GetCacheEntryAsync(possibleHit).SuccessAsync()));
                    }
                }
            }

            // A cache miss - add the content to the cache and then
            // add the build.
            CasHash inputList = await AddToCasAsync(fake.OutputList, accessMethod, session).SuccessAsync();

            CasHash[] items = new CasHash[fake.Outputs.Length];
            for (int i = 0; i < items.Length; i++)
            {
                items[i] = await AddToCasAsync(fake.Outputs[i], accessMethod, session).SuccessAsync();
            }

            CasEntries entries = new CasEntries(items, determinism);

            FullCacheRecordWithDeterminism cacheRecord = await session.AddOrGetAsync(weak, inputList, simpleHash, entries).SuccessAsync();

            XAssert.AreEqual(null, cacheRecord.Record);

            // Produce a full cache record manually - such that the CacheId is our own "NewRecordCacheId"
            return(new FullCacheRecord(new StrongFingerprint(weak, inputList, simpleHash, NewRecordCacheId), entries));
        }
コード例 #14
0
ファイル: FakeBuild.cs プロジェクト: microsoft/BuildXL
        /// <summary>
        /// This will do a build into the session with a given name
        /// and output count.
        /// </summary>
        /// <param name="session">The cache session to work with</param>
        /// <param name="pipName">Some text that acts as a base element in the output</param>
        /// <param name="pipSize">Number of elements in the output.  Must be enough to cover the variants</param>
        /// <param name="weakIndex">Variant with different weak index - defaults to 1</param>
        /// <param name="hashIndex">Variant with different hash index - defaults to 0</param>
        /// <param name="accessMethod">Method (File or stream) for how files are materialized from the cache</param>
        /// <param name="determinism">Determinism to provide for new build records</param>
        /// <returns>The FullCacheRecord of the build</returns>
        /// <remarks>
        /// This will do a "fake build" including a cache lookup via weak fingerprints
        /// and then return either the existing FullCacheRecord or add the build as a new
        /// one.  A new FullCacheRecord will have the StrongFingerprint.CacheId set to NewRecordCacheId
        /// </remarks>
        public static Task <FullCacheRecord> DoPipAsync(
            ICacheSession session,
            string pipName,
            int pipSize   = DefaultFakeBuildSize,
            int weakIndex = 1,
            int hashIndex = 0,
            CacheDeterminism determinism = default(CacheDeterminism),
            CasAccessMethod accessMethod = CasAccessMethod.Stream)
        {
            Contract.Requires(session != null);
            Contract.Requires(pipName != null);
            Contract.Requires(pipSize > 0);
            Contract.Requires(weakIndex >= 0 && weakIndex < pipSize);
            Contract.Requires(hashIndex >= 0 && hashIndex < pipSize);

            FakeBuild fake = new FakeBuild(pipName, pipSize);

            WeakFingerprintHash weak = new WeakFingerprintHash(FingerprintUtilities.Hash(fake.OutputHashes[weakIndex].ToString()).ToByteArray());
            Hash simpleHash          = new Hash(FingerprintUtilities.Hash(fake.OutputHashes[hashIndex].ToString()));

            return(DoPipAsyncImpl(session, weak, simpleHash, fake, determinism, accessMethod));
        }
コード例 #15
0
        public Task <Possible <FullCacheRecordWithDeterminism, Failure> > AddOrGetAsync(WeakFingerprintHash weak, CasHash casElement, Hash hashElement, CasEntries hashes, UrgencyHint urgencyHint, Guid activityId)
        {
            var callback = AddOrGetAsyncCallback;

            if (callback != null)
            {
                return(callback(weak, casElement, hashElement, hashes, urgencyHint, activityId, m_realSession));
            }
            else
            {
                return(m_realSession.AddOrGetAsync(weak, casElement, hashElement, hashes, urgencyHint, activityId));
            }
        }
コード例 #16
0
 public IEnumerable <Task <Possible <StrongFingerprint, Failure> > > EnumerateStrongFingerprints(WeakFingerprintHash weak, UrgencyHint urgencyHint, Guid activityId)
 {
     return(m_session.EnumerateStrongFingerprints(weak, urgencyHint, activityId));
 }
コード例 #17
0
ファイル: RandomHelpers.cs プロジェクト: kittinap/kunnjae
 /// <summary>
 /// Create a random WeakFingerprintHash
 /// </summary>
 public static WeakFingerprintHash CreateRandomWeakFingerprintHash()
 {
     return(WeakFingerprintHash.Random());
 }
コード例 #18
0
        private Possible <FullCacheRecordWithDeterminism, Failure> AddOrGet(WeakFingerprintHash weak, CasHash casElement, BuildXL.Cache.Interfaces.Hash hashElement, CasEntries hashes)
        {
            Contract.Requires(!IsClosed);
            Contract.Requires(hashes.IsValid);

            Contract.Assert(!m_readOnly);

            // We check the Cas entries if we are strict
            if (StrictMetadataCasCoupling)
            {
                // Check that the content is valid.
                if (!m_pinnedToCas.ContainsKey(casElement))
                {
                    return(new UnpinnedCasEntryFailure(CacheId, casElement));
                }

                foreach (CasHash hash in hashes)
                {
                    if (!m_pinnedToCas.ContainsKey(hash))
                    {
                        return(new UnpinnedCasEntryFailure(CacheId, hash));
                    }
                }
            }

            var strongFingerprints = Cache.Fingerprints.GetOrAdd(weak, (key) => new ConcurrentDictionary <StrongFingerprint, FullCacheRecord>());

            var record = strongFingerprints.AddOrUpdate(
                new StrongFingerprint(weak, casElement, hashElement, Cache.CacheId),
                (strong) => new FullCacheRecord(strong, hashes),
                (strong, oldRecord) =>
            {
                // Do no harm here - we will recheck this outside to produce the error that it was a bad attempt
                if (oldRecord.CasEntries.Determinism.IsSinglePhaseNonDeterministic != hashes.Determinism.IsSinglePhaseNonDeterministic)
                {
                    return(oldRecord);
                }

                // We replace if we are SinglePhaseNonDeterministic *or*
                // if we are upgrading the determinism.
                if (hashes.Determinism.IsSinglePhaseNonDeterministic ||
                    (!oldRecord.CasEntries.Determinism.IsDeterministicTool &&
                     (hashes.Determinism.IsDeterministic && !hashes.Determinism.Equals(oldRecord.CasEntries.Determinism))) ||
                    HasMissingContent(oldRecord.CasEntries))
                {
                    oldRecord = new FullCacheRecord(strong, hashes);
                }

                return(oldRecord);
            });

            if (record.CasEntries.Determinism.IsSinglePhaseNonDeterministic != hashes.Determinism.IsSinglePhaseNonDeterministic)
            {
                return(new SinglePhaseMixingFailure(CacheId));
            }

            AddSessionRecord(record);
            if (record.CasEntries.Equals(hashes))
            {
                record = null;
            }
            else
            {
                // Check if tool determinism did not make it in - that means a very bad thing happened
                if (hashes.Determinism.IsDeterministicTool)
                {
                    return(new NotDeterministicFailure(Cache.CacheId, record, new FullCacheRecord(record.StrongFingerprint, hashes)));
                }
            }

            if (record == null)
            {
                return(new FullCacheRecordWithDeterminism(hashes.GetFinalDeterminism(Cache.IsAuthoritative, Cache.CacheGuid, CacheDeterminism.NeverExpires)));
            }
            else
            {
                return(new FullCacheRecordWithDeterminism(new FullCacheRecord(record.StrongFingerprint, record.CasEntries.GetModifiedCasEntriesWithDeterminism(Cache.IsAuthoritative, Cache.CacheGuid, CacheDeterminism.NeverExpires))));
            }
        }
コード例 #19
0
        public async Task AddWithoutPin()
        {
            const string TestName    = nameof(AddWithoutPin);
            string       testCacheId = MakeCacheId(TestName);
            ICache       cache       = await CreateCacheAsync(testCacheId);

            string        testSessionId = "Session1-" + testCacheId;
            ICacheSession session       = await CreateSessionAsync(cache, testSessionId);

            FakeBuild fake = new FakeBuild(TestName, 2);

            CasHash inputList = (await session.AddToCasAsync(fake.OutputList)).Success();

            // Verify that we can read the content after it was added in
            // this session since it was pinned
            using (Stream stream = (await session.GetStreamAsync(inputList)).Success())
            {
                stream.AsString();
            }

            CasHash[] items = new CasHash[fake.Outputs.Length];
            for (int i = 0; i < fake.Outputs.Length; i++)
            {
                items[i] = (await session.AddToCasAsync(fake.Outputs[i])).Success();

                // Verify that we can read the content after it was added in
                // this session since it was pinned
                using (Stream stream = (await session.GetStreamAsync(items[i])).Success())
                {
                    stream.AsString();
                }
            }

            await CloseSessionAsync(session, testSessionId);

            testSessionId = "Session2-" + testCacheId;
            session       = await CreateSessionAsync(cache, testSessionId);

            // We use the hash of our output list as the weak fingerprint and extra hash
            var outputListFingerprintHash = fake.OutputListHash.ToFingerprint();
            WeakFingerprintHash weak      = new WeakFingerprintHash(outputListFingerprintHash);

            if (cache.StrictMetadataCasCoupling)
            {
                // This should fail as we did not pin or add the content yet
                var error = await session.AddOrGetAsync(weak, inputList, outputListFingerprintHash, items);

                XAssert.IsFalse(error.Succeeded, "Add of weak fingerprint when items not first added to CAS was successful.");
                XAssert.IsTrue(error.Failure is UnpinnedCasEntryFailure, "Error failure was not expected type {0}, it was {1} {2}", typeof(UnpinnedCasEntryFailure).Name, error.Failure.GetType().Name, error.Failure.Describe());

                // Doing it twice does not change things...
                error = await session.AddOrGetAsync(weak, inputList, outputListFingerprintHash, items);

                XAssert.IsFalse(error.Succeeded, "Add of weak fingerprint when items not first added to CAS was successful.");
                XAssert.IsTrue(error.Failure is UnpinnedCasEntryFailure, "Error failure was not expected type {0}, it was {1}, {2}", typeof(UnpinnedCasEntryFailure).Name, error.Failure.GetType().Name, error.Failure.Describe());
            }

            await CloseSessionAsync(session, testSessionId);

            await ShutdownCacheAsync(cache, testCacheId);
        }
コード例 #20
0
        public IEnumerable <Task <Possible <StrongFingerprint, Failure> > > EnumerateStrongFingerprints(WeakFingerprintHash weak, UrgencyHint urgencyHint, Guid activityId)
        {
            ConcurrentDictionary <StrongFingerprint, FullCacheRecord> strongFingerprints;

            if (Cache.Fingerprints.TryGetValue(weak, out strongFingerprints))
            {
                foreach (StrongFingerprint strongFingerprint in strongFingerprints.Keys)
                {
                    yield return(Task.FromResult(new Possible <StrongFingerprint, Failure>(strongFingerprint)));
                }
            }
        }
コード例 #21
0
        public Task <Possible <FullCacheRecordWithDeterminism, Failure> > AddOrGetAsync(WeakFingerprintHash weak, CasHash casElement, BuildXL.Cache.Interfaces.Hash hashElement, CasEntries hashes, UrgencyHint urgencyHint, Guid activityId)
        {
            Contract.Requires(!IsClosed);
            Contract.Requires(hashes.IsValid);
            Contract.Assert(!m_readOnly);

            return(Task.Run(() => AddOrGet(weak, casElement, hashElement, hashes)));
        }
コード例 #22
0
        public async Task <Possible <FullCacheRecordWithDeterminism, Failure> > AddOrGetAsync(WeakFingerprintHash weak, CasHash casElement, Hash hashElement, CasEntries hashes, UrgencyHint urgencyHint, Guid activityId)
        {
            var check = await CheckInputList(weak, casElement, hashElement, urgencyHint, activityId);

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

            return(await m_session.AddOrGetAsync(weak, casElement, hashElement, hashes, urgencyHint, activityId));
        }
コード例 #23
0
        /// <summary>
        /// Check the input list against the regex
        /// </summary>
        /// <param name="weak">The weak fingerprint (for logging on failure)</param>
        /// <param name="casElement">The CasElement of the strong fingerprint</param>
        /// <param name="hashElement">The hashElement of the strong fingerprint (for logging on failure)</param>
        /// <param name="urgencyHint">Pass-through</param>
        /// <param name="activityId">Pass-through activityId</param>
        /// <returns>false if the check was not performed, true if the checks were performed, failure if the regex checks failed</returns>
        /// <remarks>
        /// This will attempt to validate the CAS stored input list against the regex rules
        /// </remarks>
        private async Task <Possible <bool, Failure> > CheckInputList(WeakFingerprintHash weak, CasHash casElement, Hash hashElement, UrgencyHint urgencyHint, Guid activityId)
        {
            // If we either have no CasHash item or we have no regex to check, just return false
            // (that we did nothing)
            if (casElement.Equals(CasHash.NoItem) || ((Cache.MustIncludeRegex == null) && (Cache.MustNotIncludeRegex == null)))
            {
                return(false);
            }

            // mustInclude start out false if we need to check for mustInclude
            // Once we get a mustInclude match we no longer need to check.
            // If we have no mustInclude regex, we set it to true such that
            // we don't bother checking it
            bool mustInclude = Cache.MustIncludeRegex == null;

            // This is just to make a faster check for the MustNotinclude
            // case.  If we have the regex then we must check each entry
            // but in many cases we don't have the regex so let this be a quick out.
            bool checkMustNot = Cache.MustNotIncludeRegex != null;

            // Try to get the observed inputs from the CasHash given
            var possibleStream = await GetStreamAsync(casElement, urgencyHint, activityId);

            if (!possibleStream.Succeeded)
            {
                // If we could not get a stream to the CasEntery in the fingerprint.
                return(new InputListFilterFailure(Cache.CacheId, weak, casElement, hashElement, "Failed to get stream of CasElement"));
            }

            // Deserialize the contents of the path set.
            using (possibleStream.Result)
            {
                PathTable     pathTable    = new PathTable();
                BuildXLReader reader       = new BuildXLReader(false, possibleStream.Result, true);
                var           maybePathSet = ObservedPathSet.TryDeserialize(pathTable, reader);
                if (maybePathSet.Succeeded)
                {
                    // Deserialization was successful
                    foreach (ObservedPathEntry entry in maybePathSet.Result.Paths)
                    {
                        string filepath = entry.Path.ToString(pathTable);

                        // Have we seen a must-have entry yet?  If not check if this is one
                        // that way once we found one we want we stop checking this regex
                        if (!mustInclude)
                        {
                            mustInclude = Cache.MustIncludeRegex.IsMatch(filepath);
                        }

                        // Now, if we are looking for a must not include, we just check for that
                        // and if it matches we fail
                        if (checkMustNot)
                        {
                            if (Cache.MustNotIncludeRegex.IsMatch(filepath))
                            {
                                return(new InputListFilterFailure(Cache.CacheId, weak, casElement, hashElement, string.Format(CultureInfo.InvariantCulture, "Failed due to a MustNotInclude file: {0}", filepath)));
                            }
                        }
                    }
                }
                else
                {
                    return(new InputListFilterFailure(Cache.CacheId, weak, casElement, hashElement, "Failed to deserialize observed inputs"));
                }
            }

            if (!mustInclude)
            {
                return(new InputListFilterFailure(Cache.CacheId, weak, casElement, hashElement, "Failed due to not including at least one MustInclude file"));
            }

            return(true);
        }
コード例 #24
0
        public IEnumerable <Task <Possible <StrongFingerprint, Failure> > > EnumerateStrongFingerprints(WeakFingerprintHash weak, UrgencyHint urgencyHint, Guid activityId)
        {
            using (var eventing = new EnumerateStrongFingerprintsActivity(CompositingCache.EventSource, activityId, this))
            {
                eventing.Start(weak, urgencyHint);

                var ret = m_metadataSession.EnumerateStrongFingerprints(weak, urgencyHint, eventing.Id);
                eventing.Stop();
                return(ret);
            }
        }
コード例 #25
0
        public async Task <Possible <FullCacheRecordWithDeterminism, Failure> > AddOrGetAsync(WeakFingerprintHash weak, CasHash casElement, Hash hashElement, CasEntries hashes, UrgencyHint urgencyHint, Guid activityId)
        {
            var addResult = await CacheSession.AddOrGetContentHashListAsync(
                new Context(Logger),
                new BuildXL.Cache.MemoizationStore.Interfaces.Sessions.StrongFingerprint(
                    weak.ToMemoization(),
                    new Selector(casElement.ToMemoization(), hashElement.RawHash.ToByteArray())),
                hashes.ToMemoization(),
                CancellationToken.None);

            var strong = new StrongFingerprint(weak, casElement, hashElement, CacheId);

            switch (addResult.Code)
            {
            case AddOrGetContentHashListResult.ResultCode.Success:
                SessionEntries?.TryAdd(strong, 1);

                return(addResult.ContentHashListWithDeterminism.ContentHashList == null
                        ? new FullCacheRecordWithDeterminism(addResult.ContentHashListWithDeterminism.Determinism.FromMemoization())
                        : new FullCacheRecordWithDeterminism(new FullCacheRecord(strong, addResult.ContentHashListWithDeterminism.FromMemoization())));

            case AddOrGetContentHashListResult.ResultCode.SinglePhaseMixingError:
                return(new SinglePhaseMixingFailure(CacheId));

            case AddOrGetContentHashListResult.ResultCode.InvalidToolDeterminismError:
                return(new NotDeterministicFailure(
                           CacheId,
                           new FullCacheRecord(strong, addResult.ContentHashListWithDeterminism.FromMemoization()),
                           new FullCacheRecord(strong, hashes)));

            case AddOrGetContentHashListResult.ResultCode.Error:
                return(new CacheFailure(addResult.ErrorMessage));

            default:
                return(new CacheFailure("Unrecognized AddOrGetContentHashListAsync result code: " + addResult.Code + ", error message: " + (addResult.ErrorMessage ?? string.Empty)));
            }
        }
コード例 #26
0
        public IEnumerable <Task <Possible <StrongFingerprint, Failure> > > EnumerateStrongFingerprints(WeakFingerprintHash weak, UrgencyHint urgencyHint, Guid activityId)
        {
            var callback = EnumerateStrongFingerprintsCallback;

            if (callback != null)
            {
                return(callback(weak, urgencyHint, activityId, m_realSession));
            }
            else
            {
                return(m_realSession.EnumerateStrongFingerprints(weak, urgencyHint, activityId));
            }
        }
コード例 #27
0
        public async Task <Possible <FullCacheRecordWithDeterminism, Failure> > AddOrGetAsync(WeakFingerprintHash weak, CasHash casElement, Hash hashElement, CasEntries hashes, UrgencyHint urgencyHint, Guid activityId)
        {
            using (var eventing = new AddOrGetActivity(CompositingCache.EventSource, activityId, this))
            {
                eventing.Start(weak, casElement, hashElement, hashes, urgencyHint);

                // First, check if all the content has been pinned.
                if (Cache.StrictMetadataCasCoupling)
                {
                    List <CasHash> referencedHashes = new List <CasHash>(hashes);
                    referencedHashes.Add(casElement);

                    foreach (CasHash oneHash in referencedHashes)
                    {
                        if (!PinnedToCas.ContainsKey(oneHash))
                        {
                            return(eventing.StopFailure(new UnpinnedCasEntryFailure(Cache.CacheId, oneHash)));
                        }
                    }
                }

                // Then check the determinism bit...
                var testStrongFingerprint = new StrongFingerprint(weak, casElement, hashElement, Cache.CacheId);

                var existRecordCheck = await m_metadataSession.GetCacheEntryAsync(testStrongFingerprint, urgencyHint, eventing.Id);

                if (existRecordCheck.Succeeded)
                {
                    // There's an existing record, so we need the rules for determinism upgrade / downgrade. Which are complicated by the existance
                    // (or lack there of) of the associated content.

                    // First we'll check for determinism upgrades or other situations that don't require content probes.
                    var existingRecord = existRecordCheck.Result;

                    // If the determinsim is going from no determinism to some determinism OR the record is going from a non-tool
                    // determinism to a tool determinism, replace
                    if ((existingRecord.Determinism.IsNone && hashes.Determinism.IsDeterministic) ||
                        (hashes.Determinism.IsDeterministicTool && !existingRecord.Determinism.IsDeterministicTool))
                    {
                        return(eventing.Returns(await m_metadataSession.AddOrGetAsync(weak, casElement, hashElement, hashes, urgencyHint, eventing.Id)));
                    }

                    // Before trying to probe for files, see if the entries are identical.
                    // If so, tell the caller we stored their record.
                    if (hashes == existingRecord && hashes.Determinism.EffectiveGuid == existingRecord.Determinism.EffectiveGuid)
                    {
                        return(eventing.Returns(new FullCacheRecordWithDeterminism(CacheDeterminism.None)));
                    }

                    // The rest of the determinism moves depend on if the files exist or not.
                    bool foundAllFiles = true;

                    var pinCheck = await m_casSession.PinToCasAsync(existRecordCheck.Result, urgencyHint, eventing.Id);

                    foreach (var oneOutput in pinCheck)
                    {
                        if (!oneOutput.Succeeded)
                        {
                            foundAllFiles = false;
                        }
                    }

                    // Ok, so now with the knowledge of file existance, if we're missing files, allow the call through no matter what.
                    if (!foundAllFiles)
                    {
                        return(eventing.Returns(await m_metadataSession.AddOrGetAsync(weak, casElement, hashElement, hashes, urgencyHint, eventing.Id)));
                    }

                    // If the existing entry is more deterministic than what we're being given or
                    // the records are the same level, unless tool deterministic or single phase.
                    if ((existingRecord.Determinism.IsDeterministic && !hashes.Determinism.IsDeterministic) ||
                        (existingRecord.Determinism.IsDeterministicTool && !hashes.Determinism.IsDeterministicTool) ||
                        (existingRecord.Determinism.EffectiveGuid == hashes.Determinism.EffectiveGuid && !existingRecord.Determinism.IsDeterministicTool && !existingRecord.Determinism.IsSinglePhaseNonDeterministic))
                    {
                        // If the records are identical except for determinsim, return null.
                        if (existingRecord == hashes)
                        {
                            return(eventing.Returns(new FullCacheRecordWithDeterminism(CacheDeterminism.None)));
                        }

                        return(eventing.Returns(new FullCacheRecordWithDeterminism(new FullCacheRecord(testStrongFingerprint, existingRecord))));
                    }

                    // And now the error conditions.
                    // If a tool determinism collection, or an attempt to go from deterministic to not deterministic.
                    if (existingRecord.Determinism.IsDeterministicTool && hashes.Determinism.IsDeterministicTool)
                    {
                        return(eventing.StopFailure(new NotDeterministicFailure(Cache.CacheId, new FullCacheRecord(testStrongFingerprint, existingRecord), new FullCacheRecord(testStrongFingerprint, hashes))));
                    }
                }

                return(eventing.Returns(await m_metadataSession.AddOrGetAsync(weak, casElement, hashElement, hashes, urgencyHint, eventing.Id)));
            }
        }
コード例 #28
0
        public IEnumerable <Task <Possible <StrongFingerprint, Failure> > > EnumerateStrongFingerprints(WeakFingerprintHash weak, UrgencyHint urgencyHint, Guid activityId)
        {
            Contract.Requires(!IsClosed);

            using (var counter = m_counters.EnumerateStrongFingerprintsCounter())
            {
                using (var eventing = new EnumerateStrongFingerprintsActivity(BasicFilesystemCache.EventSource, activityId, this))
                {
                    eventing.Start(weak, urgencyHint);

                    // It's possible the cache could encounter an IO error when attempting to enumerate the fingerprints.
                    // This shouldn't be a fatal error. we just want to catch and record it, then continue on.
                    // Due to the use of yield a foreach loop can't be used here while still handling the error,
                    // so the enumation must be done manually.
                    using (var enumerator = m_cache.EnumerateStrongFingerprints(weak).GetEnumerator())
                    {
                        while (true)
                        {
                            StrongFingerprint strong = null;
                            try
                            {
                                if (!enumerator.MoveNext())
                                {
                                    break;
                                }

                                strong = enumerator.Current;
                            }
                            catch (IOException ex)
                            {
                                eventing.StopFailure(new StrongFingerprintEnumerationFailure(m_cache.CacheId, weak, ex));
                                yield break;
                            }
                            catch (UnauthorizedAccessException ex)
                            {
                                eventing.StopFailure(new StrongFingerprintEnumerationFailure(m_cache.CacheId, weak, ex));
                                yield break;
                            }

                            counter.YieldReturn();
                            yield return(Task.FromResult(new Possible <StrongFingerprint, Failure>(strong)));
                        }
                    }

                    eventing.Stop();
                }
            }
        }
コード例 #29
0
        /// <summary>
        /// Responsible for parsing the supplied command
        /// line arguments
        /// </summary>
        /// <param name="args">
        /// Array of the command line arguments
        /// </param>
        public Args(string[] args)
            : base(args)
        {
            string jsonFilePath    = null;
            string sessionIDFilter = null;
            string inputAssertionListDumpMustIncludeRegex    = null;
            string inputAssertionListDumpMustNotIncludeRegex = null;
            string outputFileName = null;
            string weakFingerprintInputFilepath = null;

            foreach (Option opt in Options)
            {
                if (s_helpStrings.Any(s => opt.Name.Equals(s, StringComparison.OrdinalIgnoreCase)))
                {
                    Help = true;
                    WriteHelp();
                    return;
                }
                else if (opt.Name.Equals("statisticalAnalysis", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("sa", StringComparison.OrdinalIgnoreCase))
                {
                    m_runStatisticalAnalysis = true;
                }
                else if (opt.Name.Equals("contentAnalysis", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("ca", StringComparison.OrdinalIgnoreCase))
                {
                    m_analyzeContent = true;
                }
                else if (opt.Name.Equals("consistencyCheck", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("cc", StringComparison.OrdinalIgnoreCase))
                {
                    m_runConsistencyCheck = true;
                }
                else if (opt.Name.Equals("inputAssertionListCheck", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("ic", StringComparison.OrdinalIgnoreCase))
                {
                    m_findInputAssertionListAnomalies = true;
                }
                else if (opt.Name.Equals("contentBreakdown", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("cb", StringComparison.OrdinalIgnoreCase))
                {
                    m_runContentBreakdown = true;
                }
                else if (opt.Name.Equals("jsonString", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("js", StringComparison.OrdinalIgnoreCase))
                {
                    m_jsonString = opt.Value;
                }
                else if (opt.Name.Equals("jsonFile", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("jf", StringComparison.OrdinalIgnoreCase))
                {
                    jsonFilePath = opt.Value;
                }
                else if (opt.Name.Equals("sessionIDFilter", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("sf", StringComparison.OrdinalIgnoreCase))
                {
                    sessionIDFilter = opt.Value;
                }
                else if (opt.Name.Equals("rehashCASContent", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("rc", StringComparison.OrdinalIgnoreCase))
                {
                    m_rehashCASContent = true;
                }
                else if (opt.Name.Equals("outputFile", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("of", StringComparison.OrdinalIgnoreCase))
                {
                    outputFileName = opt.Value;
                }
                else if (opt.Name.Equals("inputAssertionListSizeDisparityMinimumFactor", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("mf", StringComparison.OrdinalIgnoreCase))
                {
                    if (!double.TryParse(opt.Value, out m_inputAssertionListSizeDisparityMinimumFactor))
                    {
                        throw Error("The value for option '" + opt.Name + "' must be a valid double");
                    }

                    if (m_inputAssertionListSizeDisparityMinimumFactor <= 1.0)
                    {
                        WriteWarning("WARNING! The value for option '" + opt.Name + "' must be > 1" +
                                     ". Defaulting to " + InputAssertionListChecker.DefaultDisparityFactor);
                        m_inputAssertionListSizeDisparityMinimumFactor = InputAssertionListChecker.DefaultDisparityFactor;
                    }
                }
                else if (opt.Name.Equals("weakFingerprintInputFilepath", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("wi", StringComparison.OrdinalIgnoreCase))
                {
                    weakFingerprintInputFilepath = opt.Value;
                }
                else if (opt.Name.Equals("weakFingerprintOutputFilepath", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("wo", StringComparison.OrdinalIgnoreCase))
                {
                    m_weakFingerprintOutputFilepath = opt.Value;
                }
                else if (opt.Name.Equals("inputAssertionListDump", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
                {
                    m_dumpInputAssertionLists = true;
                }
                else if (opt.Name.Equals("inputAssertionListDumpMustIncludeRegex", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("ii", StringComparison.OrdinalIgnoreCase))
                {
                    inputAssertionListDumpMustIncludeRegex = opt.Value;
                }
                else if (opt.Name.Equals("inputAssertionListDumpMustNotIncludeRegex", StringComparison.OrdinalIgnoreCase) ||
                         opt.Name.Equals("in", StringComparison.OrdinalIgnoreCase))
                {
                    inputAssertionListDumpMustNotIncludeRegex = opt.Value;
                }
                else
                {
                    WriteWarning("WARNING! Unrecognized command line option: " + opt.Name);
                }
            }

            // Initialize json config string
            bool jsonFileProvided = jsonFilePath != null;

            if (jsonFileProvided)
            {
                m_jsonString = File.ReadAllText(jsonFilePath);
            }

            if (string.IsNullOrEmpty(m_jsonString))
            {
                throw Error("Either the json string must be specified or a path to a file containing the json string must be specified.");
            }

            // Initialize session id regex
            if (string.IsNullOrEmpty(sessionIDFilter))
            {
                m_sessionRegex = new Regex(".*", RegexOptions.Compiled);
            }
            else
            {
                try
                {
                    m_sessionRegex = new Regex(sessionIDFilter, RegexOptions.Compiled | RegexOptions.CultureInvariant);
                }
                catch (Exception e)
                {
                    throw Error("Initializing the session ID regex failed with exception: [{0}].", e);
                }
            }

            if (string.IsNullOrEmpty(inputAssertionListDumpMustIncludeRegex))
            {
                m_inputAssertionListDumpMustIncludeRegex = null;
            }
            else
            {
                try
                {
                    m_inputAssertionListDumpMustIncludeRegex = new Regex(inputAssertionListDumpMustIncludeRegex, RegexOptions.Compiled | RegexOptions.CultureInvariant);
                }
                catch (Exception e)
                {
                    throw Error("Initializing the input assertion list must include regex failed with exception: [{0}].", e);
                }
            }

            if (string.IsNullOrEmpty(inputAssertionListDumpMustNotIncludeRegex))
            {
                m_inputAssertionListDumpMustNotIncludeRegex = null;
            }
            else
            {
                try
                {
                    m_inputAssertionListDumpMustNotIncludeRegex = new Regex(inputAssertionListDumpMustNotIncludeRegex, RegexOptions.Compiled | RegexOptions.CultureInvariant);
                }
                catch (Exception e)
                {
                    throw Error("Initializing the input assertion list must not include regex failed with exception: [{0}].", e);
                }
            }

            // Initialize output destination text writer
            if (string.IsNullOrEmpty(outputFileName))
            {
                m_outputDestination = Console.Out;
                m_outputBasePath    = null;
                Console.Error.WriteLine("\nUsing output destination: Console");
            }
            else
            {
                m_outputBasePath = Path.GetDirectoryName(outputFileName);
                FileStream fileStream = null;
                try
                {
                    fileStream          = new FileStream(outputFileName, FileMode.Create);
                    m_outputDestination = new StreamWriter(fileStream);
                }
                catch (Exception e)
                {
                    if (fileStream != null)
                    {
                        fileStream.Dispose();
                    }

                    throw Error("Opening the output file failed with exception: [{0}]", e);
                }

                Console.Error.WriteLine("\nUsing output destination: " + outputFileName);
            }

            // Read in weak fingerprints to use
            // Expected file format is one weak fingerprint per line, as a hex string
            if (!string.IsNullOrEmpty(weakFingerprintInputFilepath))
            {
                FileStream fileStream = File.OpenRead(weakFingerprintInputFilepath);
                try
                {
                    using (StreamReader streamReader = new StreamReader(fileStream))
                    {
                        fileStream = null;
                        WeakFingerprintHash weakFingerprint;
                        string line;
                        while ((line = streamReader.ReadLine()) != null)
                        {
                            if (WeakFingerprintHash.TryParse(line, out weakFingerprint))
                            {
                                m_inputWeakFingerprints.Add(weakFingerprint);
                            }
                        }
                    }
                }
                finally
                {
                    if (fileStream != null)
                    {
                        fileStream.Dispose();
                    }
                }

                if (m_inputWeakFingerprints.Count == 0)
                {
                    throw Error("Could not load any weak fingerprints from {0}", weakFingerprintInputFilepath);
                }
            }

            m_weakFingerprintsFound = string.IsNullOrEmpty(m_weakFingerprintOutputFilepath) ? null : new ConcurrentDictionary <WeakFingerprintHash, byte>();
        }
コード例 #30
0
        public async Task <Possible <FullCacheRecordWithDeterminism, Failure> > AddOrGetAsync(WeakFingerprintHash weak, CasHash casElement, Hash hashElement, CasEntries hashes, UrgencyHint urgencyHint, Guid activityId)
        {
            Contract.Requires(!IsClosed);
            Contract.Requires(hashes.IsValid);
            Contract.Assert(!IsReadOnly);

            using (var counter = m_counters.AddOrGetCounter())
            {
                using (var eventing = new AddOrGetActivity(BasicFilesystemCache.EventSource, activityId, this))
                {
                    eventing.Start(weak, casElement, hashElement, hashes, urgencyHint);

                    counter.SetEntriesCount(hashes.Count);  // The size of what we are adding (effectively)

                    // We check the Cas entries if we are strict
                    if (StrictMetadataCasCoupling)
                    {
                        // Check that the content is valid.
                        if (!m_pinnedToCas.ContainsKey(casElement))
                        {
                            counter.Failed();
                            return(eventing.StopFailure(new UnpinnedCasEntryFailure(CacheId, casElement)));
                        }

                        foreach (CasHash hash in hashes)
                        {
                            if (!m_pinnedToCas.ContainsKey(hash))
                            {
                                counter.Failed();
                                return(eventing.StopFailure(new UnpinnedCasEntryFailure(CacheId, hash)));
                            }
                        }
                    }

                    StrongFingerprint strong = new StrongFingerprint(weak, casElement, hashElement, CacheId);

                    // Assume we accepted the Add and there is nothing to return
                    FullCacheRecord result = null;

                    string strongFingerprintName = m_cache.GetStrongFingerprintFilename(strong);

                    try
                    {
                        using (FileStream file = await m_cache.ContendedOpenStreamAsync(strongFingerprintName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                        {
                            // The compiler thinks that it is not assigned down below at the end
                            // even though it would be set by the writeEntries being true in that case
                            CasEntries oldCasEntries = hashes;

                            // Assume we will write our new enties to the file.
                            bool writeEntries = true;

                            // If there is some data in the file already, we need to try to read it.
                            if (file.Length > 0)
                            {
                                var possibleOldCasEntries = await m_cache.ReadCacheEntryAsync(file);

                                // Only if it was formatted correctly do we continue to check if
                                // we should replace it.
                                if (possibleOldCasEntries.Succeeded)
                                {
                                    oldCasEntries = possibleOldCasEntries.Result;
                                    writeEntries  = false;

                                    // We can only replace if both or neither is SinglePhaseNonDeterministic
                                    if (oldCasEntries.Determinism.IsSinglePhaseNonDeterministic != hashes.Determinism.IsSinglePhaseNonDeterministic)
                                    {
                                        counter.Failed();
                                        return(eventing.StopFailure(new SinglePhaseMixingFailure(CacheId)));
                                    }

                                    // Should we replace?
                                    if (hashes.Determinism.IsSinglePhaseNonDeterministic ||
                                        (!oldCasEntries.Determinism.IsDeterministicTool &&
                                         (hashes.Determinism.IsDeterministic && !oldCasEntries.Determinism.Equals(hashes.Determinism))))
                                    {
                                        // We are replacing due to determinism
                                        counter.Det();
                                        writeEntries = true;
                                    }
                                    else if (HasMissingContent(oldCasEntries))
                                    {
                                        counter.Repair();
                                        writeEntries = true;
                                    }
                                    else if (oldCasEntries.Determinism.IsDeterministicTool && hashes.Determinism.IsDeterministicTool && !oldCasEntries.Equals(hashes))
                                    {
                                        // We have a non-deterministic tool!
                                        counter.Failed();
                                        return(eventing.StopFailure(new NotDeterministicFailure(CacheId, new FullCacheRecord(strong, oldCasEntries), new FullCacheRecord(strong, hashes))));
                                    }
                                }
                            }

                            // Are we going to write the entries?
                            if (writeEntries)
                            {
                                // We are writing so the old entries don't count
                                oldCasEntries = hashes;

                                // Write from the front
                                file.SetLength(0);
                                await m_cache.WriteCacheEntryAsync(file, hashes);
                            }
                            else
                            {
                                counter.Dup();
                            }

                            // If what is in the cache is different than what we are
                            // asking to add, build a FullCacheRecord to return what
                            // is in the cache.
                            if (!oldCasEntries.Equals(hashes))
                            {
                                counter.Get();
                                result = new FullCacheRecord(strong, oldCasEntries);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        counter.Failed();
                        return(eventing.StopFailure(new StrongFingerprintAccessFailure(m_cache.CacheId, strong, e)));
                    }

                    AddSessionRecord(strong);

                    if (result != null)
                    {
                        return
                            (eventing.Returns(
                                 new FullCacheRecordWithDeterminism(
                                     new FullCacheRecord(
                                         result.StrongFingerprint,
                                         result.CasEntries.GetModifiedCasEntriesWithDeterminism(
                                             m_cache.IsAuthoritative,
                                             m_cache.CacheGuid,
                                             CacheDeterminism.NeverExpires)))));
                    }
                    else
                    {
                        return(eventing.Returns(new FullCacheRecordWithDeterminism(hashes.GetFinalDeterminism(m_cache.IsAuthoritative, m_cache.CacheGuid, DateTime.UtcNow.Add(m_cache.TimeToLive)))));
                    }
                }
            }
        }