コード例 #1
0
ファイル: FakeBuild.cs プロジェクト: microsoft/BuildXL
        /// <summary>
        /// Check that the fake build contents are available and correct
        /// </summary>
        /// <param name="cache">The cache to read from (uses a read-only session)</param>
        /// <param name="record">The full cache record that is to be used to check the cache</param>
        /// <returns>Success if all worked</returns>
        /// <remarks>
        /// This is tied to the FakeBuild where the set of results is
        /// made as the index file which we use in the strong fingerprint
        /// and basically describes the set of entries that should be in the CasEntries
        /// </remarks>
        public static Task CheckContentsAsync(ICache cache, FullCacheRecord record)
        {
            Contract.Requires(cache != null);
            Contract.Requires(record != null);

            return(CheckContentsAsync(cache, record.StrongFingerprint.CasElement, record.CasEntries));
        }
コード例 #2
0
ファイル: TestCacheCore.cs プロジェクト: kittinap/kunnjae
        private async Task ValidateSessionAsync(HashSet <FullCacheRecord> expectedRecords, ICache cache, string sessionId, FakeBuild.CasAccessMethod accessMethod)
        {
            if (!ImplementsTrackedSessions || DummySessionName != null)
            {
                return;
            }

            ICacheReadOnlySession readOnlySession = (await cache.CreateReadOnlySessionAsync()).Success();

            // Check that the content is fine
            HashSet <FullCacheRecord> foundRecords = new HashSet <FullCacheRecord>();

            foreach (var strongFingerprintTask in cache.EnumerateSessionStrongFingerprints(DummySessionName ?? sessionId).Success().OutOfOrderTasks())
            {
                StrongFingerprint strongFingerprint = await strongFingerprintTask;
                CasEntries        casEntries        = (await readOnlySession.GetCacheEntryAsync(strongFingerprint)).Success();
                FullCacheRecord   record            = new FullCacheRecord(strongFingerprint, casEntries);
                XAssert.IsTrue(expectedRecords.Contains(record), "Found record that was not expected!");
                foundRecords.Add(record);
            }

            (await readOnlySession.CloseAsync()).Success();

            await FakeBuild.CheckContentsAsync(cache, foundRecords, accessMethod);

            XAssert.AreEqual(expectedRecords.Count, foundRecords.Count);
        }
コード例 #3
0
 // Add a record to the session if we are recording a session
 private void AddSessionRecord(FullCacheRecord record)
 {
     if (SessionEntries != null)
     {
         SessionEntries.TryAdd(record.StrongFingerprint, 1);
     }
 }
コード例 #4
0
        public virtual async Task NonDeterministicContentRespectsDisconnect()
        {
            string testCacheId = "Disconnected";
            ICache testCache   = await InitializeCacheAsync(NewCache(testCacheId, false)).SuccessAsync();

            VerticalCacheAggregator vertCache = testCache as VerticalCacheAggregator;

            XAssert.IsNotNull(vertCache);

            ICacheSession aggregatorSession = (await testCache.CreateSessionAsync()).Success();
            ICacheSession localSession      = (await vertCache.LocalCache.CreateSessionAsync()).Success();
            ICacheSession remoteSession     = (await vertCache.RemoteCache.CreateSessionAsync()).Success();

            VerticalCacheAggregatorSession vertSession = aggregatorSession as VerticalCacheAggregatorSession;

            XAssert.IsNotNull(vertSession);

            CallbackCacheSessionWrapper wrappedSession = vertSession.RemoteSession as CallbackCacheSessionWrapper;

            XAssert.IsNotNull(wrappedSession);
            PoisonSession(wrappedSession);

            CacheDeterminism determinismSource = CacheDeterminism.None;

            const string PipName = "TestPip";

            // Populate the remote cache with one set of outputs.
            FullCacheRecord remoteCacheRecord = await FakeBuild.DoNonDeterministicPipAsync(remoteSession, PipName);

            // And the local cache with a set forced to be unique.
            FullCacheRecord localCacheRecord = await FakeBuild.DoNonDeterministicPipAsync(localSession, PipName, generateVerifiablePip: true);

            PoisonAllRemoteSessions(testCache);
            DisconnectRemoteCache(testCache);

            // Now query each cache, and verify only the remote content is in each.
            // Make sure the content is in each cache. (Placing the aggregator cache first will cause backfill of the local cache)
            foreach (var currentCache in new Tuple <ICache, CacheDeterminism, string, int>[]
            {
                new Tuple <ICache, CacheDeterminism, string, int>(testCache, CacheDeterminism.None, vertCache.LocalCache.CacheId, 1),
                new Tuple <ICache, CacheDeterminism, string, int>(vertCache.LocalCache, CacheDeterminism.None, vertCache.LocalCache.CacheId, 1)
            })
            {
                await VerticalAggregatorBaseTests.ValidateItemsInCacheAsync(
                    currentCache.Item1,
                    localCacheRecord.StrongFingerprint.WeakFingerprint,
                    new List <CasHash>(localCacheRecord.CasEntries),
                    currentCache.Item2,
                    localCacheRecord.StrongFingerprint.CasElement,
                    currentCache.Item3,
                    currentCache.Item4);
            }

            XAssert.IsTrue((await testCache.ShutdownAsync()).Succeeded);
        }
コード例 #5
0
        private async Task AddToEmptyCacheAsync(bool contentIsDeterministic)
        {
            string testCacheId = "Disconnected";
            ICache testCache   = await InitializeCacheAsync(NewCache(testCacheId, false)).SuccessAsync();

            VerticalCacheAggregator vertCache = testCache as VerticalCacheAggregator;

            XAssert.IsNotNull(vertCache);

            CacheDeterminism localDeterminism = CacheDeterminism.None;

            if (contentIsDeterministic)
            {
                localDeterminism = CacheDeterminism.Tool;
            }

            CacheDeterminism initialDeterminism = contentIsDeterministic ? CacheDeterminism.Tool : CacheDeterminism.None;

            ICacheSession session = (await testCache.CreateSessionAsync()).Success();

            VerticalCacheAggregatorSession vertSession = session as VerticalCacheAggregatorSession;

            XAssert.IsNotNull(vertSession);

            CallbackCacheSessionWrapper wrappedSession = vertSession.RemoteSession as CallbackCacheSessionWrapper;

            XAssert.IsNotNull(wrappedSession);
            PoisonSession(wrappedSession);
            DisconnectRemoteCache(testCache);

            FullCacheRecord cacheRecord = await FakeBuild.DoPipAsync(session, "TestPip", determinism: initialDeterminism);

            await VerticalAggregatorBaseTests.ValidateItemsInCacheAsync(
                vertCache.LocalCache,
                cacheRecord.StrongFingerprint.WeakFingerprint,
                new List <CasHash>(cacheRecord.CasEntries),
                localDeterminism,
                cacheRecord.StrongFingerprint.CasElement,
                vertCache.LocalCache.CacheId,
                1);

            await VerticalAggregatorBaseTests.ValidateItemsInCacheAsync(
                vertCache.RemoteCache,
                cacheRecord.StrongFingerprint.WeakFingerprint,
                new List <CasHash>(cacheRecord.CasEntries),
                localDeterminism,
                cacheRecord.StrongFingerprint.CasElement,
                vertCache.RemoteCache.CacheId,
                0);

            XAssert.IsTrue((await testCache.ShutdownAsync()).Succeeded);
        }
コード例 #6
0
        public async Task NoItemFingerprint()
        {
            const string TestName    = nameof(NoItemFingerprint);
            string       testCacheId = MakeCacheId(TestName);
            ICache       cache       = await CreateCacheAsync(testCacheId);

            // Now for the session (which we base on the cache ID)
            string testSessionId = "Session1-" + testCacheId;

            ICacheSession session = await CreateSessionAsync(cache, testSessionId);

            // Note that we will be making a new fingerprint with a CasHash of NoItem
            // without pre-sending it as NoItem is a special case - it is nothing
            FullCacheRecord record = await FakeBuild.DoPipAsync(session, TestName);

            // We place this in and did not pin the NoItem yet or even send it around
            // Note that this also is doing a zero-length CasEntries
            var strong = new StrongFingerprint(record.StrongFingerprint.WeakFingerprint, CasHash.NoItem, new Hash(FingerprintUtilities.ZeroFingerprint), TestName);
            FullCacheRecordWithDeterminism oldRecord = (await session.AddOrGetAsync(
                                                            strong.WeakFingerprint,
                                                            strong.CasElement,
                                                            strong.HashElement,
                                                            CasEntries.FromCasHashes())).Success("Should work even though I did not pin CasHash.NoItem, instead it failed with {0}");

            XAssert.IsNull(oldRecord.Record, "Should have been the first one like this");

            var result = await session.GetCacheEntryAsync(strong).SuccessAsync();

            XAssert.AreEqual(0, result.Count, "We should have gotten a zero-length CasEntries");

            // We place this in and did not pin the NoItem yet or even send it around
            // Note that this does an array of NoItem CasEntries and use the
            // record.CasElement as the weak fingerprint
            CasHash[] empties = { CasHash.NoItem, CasHash.NoItem, CasHash.NoItem };
            strong    = new StrongFingerprint(new WeakFingerprintHash(strong.CasElement.ToFingerprint()), CasHash.NoItem, new Hash(FingerprintUtilities.ZeroFingerprint), TestName);
            oldRecord = (await session.AddOrGetAsync(
                             strong.WeakFingerprint,
                             CasHash.NoItem,
                             new Hash(FingerprintUtilities.ZeroFingerprint),
                             empties)).Success("Should work even though I did not pin CasHash.NoItem, instead it failed with {0}");

            XAssert.IsNull(oldRecord.Record, "Should have been the first one like this");

            result = await session.GetCacheEntryAsync(strong).SuccessAsync();

            XAssert.AreEqual(empties, result, "We should have gotten the set of empties");

            await CloseSessionAsync(session, testSessionId);

            await ShutdownCacheAsync(cache, testCacheId);
        }
コード例 #7
0
        public async Task DisconnectMostRemoteCacheAddNewReconnect()
        {
            string cacheId   = "MutlipleCacheRemote";
            ICache testCache = await InitializeCacheAsync(NewCache(cacheId, true, false, true)).SuccessAsync();

            VerticalCacheAggregator lowerVert = testCache as VerticalCacheAggregator;

            XAssert.IsNotNull(lowerVert);

            CallbackCacheWrapper callbackCache = lowerVert.RemoteCache as CallbackCacheWrapper;

            XAssert.IsNotNull(callbackCache);

            VerticalCacheAggregator upperVert = callbackCache.WrappedCache as VerticalCacheAggregator;

            XAssert.IsNotNull(upperVert);

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

            VerticalAggregatorDisconnectTests.DisconnectCache(upperVert.RemoteCache);

            FullCacheRecord cacheRecord = await FakeBuild.DoPipAsync(session, "Test Pip");

            VerticalAggregatorDisconnectTests.ConnectCache(upperVert.RemoteCache);

            // Now query each cache, and verify only the remote content is in each.
            var aggregatorStats   = new Dictionary <string, double>();
            var remoteDeterminism = CacheDeterminism.ViaCache(upperVert.RemoteCache.CacheGuid, CacheDeterminism.NeverExpires);

            foreach (var currentCache in new Tuple <ICache, CacheDeterminism, string, int, Dictionary <string, double> >[]
            {
                new Tuple <ICache, CacheDeterminism, string, int, Dictionary <string, double> >(testCache, remoteDeterminism, lowerVert.LocalCache.CacheId, 3, aggregatorStats),
                new Tuple <ICache, CacheDeterminism, string, int, Dictionary <string, double> >(lowerVert.LocalCache, remoteDeterminism, lowerVert.LocalCache.CacheId, 1, null),
                new Tuple <ICache, CacheDeterminism, string, int, Dictionary <string, double> >(upperVert.LocalCache, remoteDeterminism, upperVert.LocalCache.CacheId, 1, null),
                new Tuple <ICache, CacheDeterminism, string, int, Dictionary <string, double> >(upperVert.RemoteCache, remoteDeterminism, upperVert.RemoteCache.CacheId, 1, null)
            })
            {
                await ValidateItemsInCacheAsync(
                    currentCache.Item1,
                    cacheRecord.StrongFingerprint.WeakFingerprint,
                    new List <CasHash>(cacheRecord.CasEntries),
                    currentCache.Item2,
                    cacheRecord.StrongFingerprint.CasElement,
                    currentCache.Item3,
                    currentCache.Item4);
            }

            await testCache.ShutdownAsync().SuccessAsync();
        }
コード例 #8
0
        /// <summary>
        /// Execute a fake build based on this pip definition into the given cache session
        /// </summary>
        /// <param name="session">The cache session to use</param>
        /// <returns>The FullCacheRecord of the build operation</returns>
        public async Task <FullCacheRecord> BuildAsync(ICacheSession session)
        {
            Contract.Requires(session != null);

            FullCacheRecord record = await FakeBuild.DoPipAsync(
                session,
                pipName : PipName,
                pipSize : PipSize,
                weakIndex : WeakIndex,
                hashIndex : HashIndex,
                determinism : Determinism);

            if (Determinism.IsDeterministicTool)
            {
                XAssert.IsTrue(record.CasEntries.Determinism.IsDeterministicTool, "Tool was supposed to be deterministic");
            }

            return(record);
        }
コード例 #9
0
        public async Task CacheDataPersistedReadOnlyCache()
        {
            string testName = "CacheDataPersistedReadOnly";

            ICache firstInvocation = await CreateCacheAsync(testName, true);

            Guid originalGuid = firstInvocation.CacheGuid;

            ICacheSession session = (await firstInvocation.CreateSessionAsync("sessionName")).Success();

            FullCacheRecord cacheRecord = await FakeBuild.DoPipAsync(session, "PipA");

            (await session.CloseAsync()).Success();
            await ShutdownCacheAsync(firstInvocation, testName);

            ICache secondInvocation = await GetExistingCacheAsync(testName, true, true);

            XAssert.AreEqual(originalGuid, secondInvocation.CacheGuid, "Persistent caches: GUID should not change");

            XAssert.IsTrue(secondInvocation.IsReadOnly, "This should have been a read-only cache");

            ICacheReadOnlySession newSession = (await secondInvocation.CreateReadOnlySessionAsync()).Success();

            int fingerprintsFound = 0;

            foreach (var singleFingerprint in newSession.EnumerateStrongFingerprints(cacheRecord.StrongFingerprint.WeakFingerprint))
            {
                var sfp = (await singleFingerprint).Success();

                XAssert.AreEqual(cacheRecord.StrongFingerprint, sfp, "Fingerprints must match");

                fingerprintsFound++;
            }

            XAssert.AreEqual(1, fingerprintsFound, "A single instance of the fingerprint should have been found after restarting the cache.");

            (await newSession.CloseAsync()).Success();

            await ShutdownCacheAsync(secondInvocation, testName);
        }
コード例 #10
0
        public virtual async Task ReadOnlyRemoteIsNotUpdatedWhenDisconnected()
        {
            string testCacheId = "Disconnected";
            ICache testCache   = await InitializeCacheAsync(NewCache(testCacheId, false)).SuccessAsync();

            VerticalCacheAggregator vertCache = testCache as VerticalCacheAggregator;

            XAssert.IsNotNull(vertCache);

            PoisonAllRemoteSessions(testCache);
            DisconnectRemoteCache(testCache);

            ICacheSession session = (await testCache.CreateSessionAsync()).Success();

            FullCacheRecord cacheRecord = await FakeBuild.DoPipAsync(session, "TestPip");

            await VerticalAggregatorBaseTests.ValidateItemsInCacheAsync(
                vertCache.LocalCache,
                cacheRecord.StrongFingerprint.WeakFingerprint,
                new List <CasHash>(cacheRecord.CasEntries),
                CacheDeterminism.None,
                cacheRecord.StrongFingerprint.CasElement,
                vertCache.LocalCache.CacheId,
                1);

            var remoteSession = await vertCache.RemoteCache.CreateReadOnlySessionAsync().SuccessAsync();

            int fingerprintsReturned = 0;

            foreach (var fingerprint in remoteSession.EnumerateStrongFingerprints(cacheRecord.StrongFingerprint.WeakFingerprint))
            {
                fingerprintsReturned++;
            }

            XAssert.AreEqual(0, fingerprintsReturned, "No fingerprints should have been found in the remote cache.");
            AssertSuccess(await testCache.ShutdownAsync());
        }
コード例 #11
0
        public async Task SimpleDummySession()
        {
            const string TestName    = "SimpleSession";
            string       testCacheId = MakeCacheId(TestName);
            ICache       cache       = await CreateCacheAsync(testCacheId);

            // Now for the session (which we base on the cache ID)
            string testSessionId = "Session1-" + testCacheId;

            ICacheSession session = await CreateSessionAsync(cache, testSessionId);

            // Do the default fake build for this test (first time, no cache hit)
            FullCacheRecord built = await FakeBuild.DoPipAsync(session, TestName);

            XAssert.AreEqual(FakeBuild.NewRecordCacheId, built.CacheId, "Should have been a new cache entry!");

            // Now we see if we can get back the items we think we should
            await CloseSessionAsync(session, testSessionId);

            // We need a read only session to get the CasEntries
            ICacheReadOnlySession readOnlySession = (await cache.CreateReadOnlySessionAsync()).Success();

            // Validate that the cache contains a dummy session and it has the one cache record it needs.
            HashSet <FullCacheRecord> found = new HashSet <FullCacheRecord>();

            foreach (var strongFingerprintTask in cache.EnumerateSessionStrongFingerprints(MemoizationStoreAdapterCache.DummySessionName).Success().OutOfOrderTasks())
            {
                StrongFingerprint strongFingerprint = await strongFingerprintTask;
                CasEntries        casEntries        = (await readOnlySession.GetCacheEntryAsync(strongFingerprint)).Success();
                FullCacheRecord   record            = new FullCacheRecord(strongFingerprint, casEntries);

                // If it is not the record we already found...
                if (!found.Contains(record))
                {
                    found.Add(record);
                }

                XAssert.AreEqual(1, found.Count, "There should be only 1 unique record in the session");

                XAssert.AreEqual(built.StrongFingerprint.WeakFingerprint, record.StrongFingerprint.WeakFingerprint);
                XAssert.AreEqual(built.StrongFingerprint.CasElement, record.StrongFingerprint.CasElement);
                XAssert.AreEqual(built.StrongFingerprint.HashElement, record.StrongFingerprint.HashElement);
                XAssert.AreEqual(built.CasEntries.Count, record.CasEntries.Count, "Did not return the same number of items");
                XAssert.IsTrue(record.CasEntries.Equals(built.CasEntries), "Items returned are not the same hash and/or order order");

                XAssert.AreEqual(built, record);

                // We can not check record.CasEntries.IsDeterministic
                // as the cache may have determined that they are deterministic
                // via cache determinism recovery.
            }

            XAssert.AreEqual(1, found.Count, "There should be 1 and only 1 record in the session!");

            await readOnlySession.CloseAsync().SuccessAsync();

            // Check that the cache has the items in it
            await FakeBuild.CheckContentsAsync(cache, built);

            // Now redo the "build" with a cache hit
            testSessionId = "Session2-" + testCacheId;
            session       = await CreateSessionAsync(cache, testSessionId);

            FullCacheRecord rebuilt = await FakeBuild.DoPipAsync(session, TestName);

            XAssert.AreEqual(built, rebuilt, "Should have been the same build!");

            // We make sure we did get it from a cache rather than a manual rebuild.
            XAssert.AreNotEqual(built.CacheId, rebuilt.CacheId, "Should not be the same cache ID");

            await CloseSessionAsync(session, testSessionId);

            readOnlySession = await cache.CreateReadOnlySessionAsync().SuccessAsync();

            // Now that we have done the second build via a cache hit, it should produce the
            // same cache record as before
            foreach (var strongFingerprintTask in cache.EnumerateSessionStrongFingerprints(MemoizationStoreAdapterCache.DummySessionName).Success().OutOfOrderTasks())
            {
                StrongFingerprint strongFingerprint = await strongFingerprintTask;
                CasEntries        casEntries        = (await readOnlySession.GetCacheEntryAsync(strongFingerprint)).Success();
                FullCacheRecord   record            = new FullCacheRecord(strongFingerprint, casEntries);

                XAssert.IsTrue(found.Contains(record), "Second session should produce the same cache record but did not!");
            }

            (await readOnlySession.CloseAsync()).Success();

            await ShutdownCacheAsync(cache, testCacheId);
        }
コード例 #12
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))));
            }
        }
コード例 #13
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)))));
                    }
                }
            }
        }