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); }
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)); } }
/// <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"); })); }