private async Task <StrongFingerprint> PublishValueForRandomStrongFingerprintAsync(
            Context context,
            string cacheNamespace,
            BackingOption backingOption,
            TimeSpan expiryMinimum,
            TimeSpan expiryRange)
        {
            StrongFingerprint publishedFingerprint = await CreateBackedRandomStrongFingerprintAsync(context, cacheNamespace);

            Func <DisposableDirectory, ICache> createCache = dir => CreateBareBuildCache(
                dir, cacheNamespace, FileSystem, Logger, backingOption, ItemStorageOption, expiryMinimum, expiryRange);

            Func <ICacheSession, Task> publishAsync = async(ICacheSession session) =>
            {
                ContentHashListWithDeterminism valueToPublish =
                    await CreateRandomContentHashListWithDeterminismAsync(context, true, session);

                AddOrGetContentHashListResult addOrGetResult = await session.AddOrGetContentHashListAsync(
                    context, publishedFingerprint, valueToPublish, Token);

                // Ensure the new value was successfully published and that it was the winning value for that key
                Assert.True(addOrGetResult.Succeeded);
                Assert.Null(addOrGetResult.ContentHashListWithDeterminism.ContentHashList);
            };

            await RunTestAsync(context, publishAsync, createCache);

            return(publishedFingerprint);
        }
Exemple #2
0
        public void AddOrGetContentHashListStop(Context context, AddOrGetContentHashListResult result, StrongFingerprint fingerprint)
        {
            if (_eventSource.IsEnabled())
            {
                _eventSource.AddOrGetContentHashListStop(context.Id.ToString(), (int)result.Code, result.ErrorMessage);
            }

            _addOrGetContentHashListCallCounter.Completed(result.Duration.Ticks);

            if (result.Succeeded)
            {
                if (result.ContentHashListWithDeterminism.ContentHashList == null)
                {
                    _addOrGetContentHashListAddCounter.Increment();
                }
                else
                {
                    _addOrGetContentHashListGetCounter.Increment();
                }
            }
            else
            {
                _addOrGetContentHashListErrorCounter.Increment();
            }

            if (context.IsEnabled)
            {
                Debug(context, $"{Name}.AddOrGetContentHashList() stop {result.Duration.TotalMilliseconds}ms result=[{result}], fingerprint=[{fingerprint}]");
            }
        }
        public async Task MixSyncModes(SynchronizationMode fromSyncMode, SynchronizationMode toSyncMode)
        {
            var context = new Context(Logger);

            using (var testDirectory = new DisposableDirectory(FileSystem))
            {
                StrongFingerprint sfp = StrongFingerprint.Random();
                ContentHashListWithDeterminism value = new ContentHashListWithDeterminism(ContentHashList.Random(), CacheDeterminism.None);
                await RunTestAsync(
                    context,
                    testDirectory,
                    async (store, session) =>
                {
                    // Add a value to a store with one sync mode
                    AddOrGetContentHashListResult addResult = await session.AddOrGetContentHashListAsync(context, sfp, value, Token);
                    Assert.True(addResult.Succeeded);
                    Assert.Null(addResult.ContentHashListWithDeterminism.ContentHashList);
                },
                    testDir => CreateSQLiteMemoizationStore(testDirectory.Path, fromSyncMode));

                await RunTestAsync(
                    context,
                    testDirectory,
                    async (store, session) =>
                {
                    // Make sure the same value can still be read from another sync mode
                    GetContentHashListResult getResult = await session.GetContentHashListAsync(context, sfp, Token);
                    getResult.ShouldBeSuccess();
                    Assert.Equal(value, getResult.ContentHashListWithDeterminism);

                    // Make sure a new value can be written in another sync mode
                    StrongFingerprint newSfp = StrongFingerprint.Random();
                    ContentHashListWithDeterminism newValue =
                        new ContentHashListWithDeterminism(ContentHashList.Random(), CacheDeterminism.None);
                    AddOrGetContentHashListResult addResult = await session.AddOrGetContentHashListAsync(context, newSfp, newValue, Token);
                    Assert.True(addResult.Succeeded);
                    Assert.Null(addResult.ContentHashListWithDeterminism.ContentHashList);
                },
                    testDir => CreateSQLiteMemoizationStore(testDirectory.Path, toSyncMode));
            }
        }
Exemple #4
0
        /// <summary>
        ///     Store a ContentHashList
        /// </summary>
        internal Task <AddOrGetContentHashListResult> AddOrGetContentHashListAsync(
            Context context,
            StrongFingerprint strongFingerprint,
            ContentHashListWithDeterminism contentHashListWithDeterminism,
            IContentSession contentSession,
            CancellationToken cts)
        {
            return(AddOrGetContentHashListCall.RunAsync(Tracer, new OperationContext(context, cts), strongFingerprint, async() =>
            {
                const int maxAttempts = 5;
                int attemptCount = 0;
                while (attemptCount++ <= maxAttempts)
                {
                    var contentHashList = contentHashListWithDeterminism.ContentHashList;
                    var determinism = contentHashListWithDeterminism.Determinism;

                    // Load old value
                    var oldContentHashListWithDeterminism = await GetContentHashListAsync(strongFingerprint);
                    var oldContentHashList = oldContentHashListWithDeterminism.ContentHashList;
                    var oldDeterminism = oldContentHashListWithDeterminism.Determinism;

                    // Make sure we're not mixing SinglePhaseNonDeterminism records
                    if (oldContentHashList != null &&
                        (oldDeterminism.IsSinglePhaseNonDeterministic != determinism.IsSinglePhaseNonDeterministic))
                    {
                        return AddOrGetContentHashListResult.SinglePhaseMixingError;
                    }

                    // Match found.
                    // Replace if incoming has better determinism or some content for the existing entry is missing.
                    if (oldContentHashList == null || oldDeterminism.ShouldBeReplacedWith(determinism) ||
                        !(await contentSession.EnsureContentIsAvailableAsync(context, oldContentHashList, cts).ConfigureAwait(false)))
                    {
                        AddOrGetContentHashListResult contentHashListResult = await RunExclusiveAsync(
                            async() =>
                        {
                            // double check again.
                            var contentHashListInStore = await GetContentHashListAsync(strongFingerprint);

                            if (contentHashListInStore != oldContentHashListWithDeterminism)
                            {
                                return new AddOrGetContentHashListResult(contentHashListInStore);
                            }

                            var fileTimeUtc = _clock.UtcNow.ToFileTimeUtc();

                            await _replaceCommandPool.RunAsync(
                                new SQLiteParameter("@weakFingerprint", SerializeWithHashType(strongFingerprint.WeakFingerprint)),
                                new SQLiteParameter("@selectorContentHash", strongFingerprint.Selector.ContentHash.SerializeReverse()),
                                new SQLiteParameter("@selectorOutput", strongFingerprint.Selector.Output),
                                new SQLiteParameter("@fileTimeUtc", fileTimeUtc),
                                new SQLiteParameter("@payload", contentHashList.Payload?.ToArray()),
                                new SQLiteParameter("@determinism", determinism.EffectiveGuid.ToByteArray()),
                                new SQLiteParameter("@serializedDeterminism", determinism.Serialize()),
                                new SQLiteParameter("@contentHashList", contentHashList.Serialize()));

                            // Bump count if this is a new entry.
                            if (oldContentHashList == null)
                            {
                                IncrementCountOnAdd();
                            }

                            // Accept the value
                            return new AddOrGetContentHashListResult(
                                new ContentHashListWithDeterminism(null, determinism));
                        });

                        // our add lost - need to retry.
                        if (contentHashListResult.ContentHashListWithDeterminism.ContentHashList != null)
                        {
                            continue;
                        }

                        if (contentHashListResult.ContentHashListWithDeterminism.ContentHashList == null)
                        {
                            return contentHashListResult;
                        }
                    }

                    if (oldContentHashList != null && oldContentHashList.Equals(contentHashList))
                    {
                        return new AddOrGetContentHashListResult(
                            new ContentHashListWithDeterminism(null, oldDeterminism));
                    }

                    // If we didn't accept a deterministic tool's data, then we're in an inconsistent state
                    if (determinism.IsDeterministicTool)
                    {
                        return new AddOrGetContentHashListResult(
                            AddOrGetContentHashListResult.ResultCode.InvalidToolDeterminismError,
                            oldContentHashListWithDeterminism);
                    }

                    // If we did not accept the given value, return the value in the cache
                    return new AddOrGetContentHashListResult(oldContentHashListWithDeterminism);
                }

                return new AddOrGetContentHashListResult("Hit too many races attempting to add content hash list into the cache");
            }));
        }