/// <inheritdoc /> public Task <GetContentHashListResult> GetContentHashListAsync( Context context, StrongFingerprint strongFingerprint, CancellationToken cts, UrgencyHint urgencyHint) { return(GetContentHashListCall.RunAsync(Tracer.MemoizationStoreTracer, context, strongFingerprint, async() => { // Check for pre-fetched data ContentHashListWithDeterminism contentHashListWithDeterminism; if (ContentHashListWithDeterminismCache.Instance.TryGetValue( CacheNamespace, strongFingerprint, out contentHashListWithDeterminism)) { Tracer.RecordUseOfPrefetchedContentHashList(); FingerprintTracker.Track( strongFingerprint, contentHashListWithDeterminism.Determinism.ExpirationUtc); return new GetContentHashListResult(contentHashListWithDeterminism); } // No pre-fetched data. Need to query the server. ObjectResult <ContentHashListWithCacheMetadata> responseObject = await ContentHashListAdapter.GetContentHashListAsync(context, CacheNamespace, strongFingerprint).ConfigureAwait(false); if (!responseObject.Succeeded) { return new GetContentHashListResult(responseObject); } ContentHashListWithCacheMetadata response = responseObject.Data; if (response.ContentHashListWithDeterminism.ContentHashList == null) { // Miss return new GetContentHashListResult(new ContentHashListWithDeterminism(null, CacheDeterminism.None)); } GetContentHashListResult unpackResult = UnpackContentHashListWithDeterminismAfterGet(response, CacheId); if (!unpackResult.Succeeded) { return unpackResult; } SealIfNecessaryAfterGet(context, strongFingerprint, response); FingerprintTracker.Track(strongFingerprint, response.GetRawExpirationTimeUtc()); return new GetContentHashListResult(unpackResult.ContentHashListWithDeterminism); })); }
/// <inheritdoc /> public Task <BoolResult> IncorporateStrongFingerprintsAsync( Context context, IEnumerable <Task <StrongFingerprint> > strongFingerprints, CancellationToken cts, UrgencyHint urgencyHint) { return(IncorporateStrongFingerprintsCall.RunAsync(Tracer.MemoizationStoreTracer, context, async() => { // BuildCache remembers fingerprints for all content that has been fetched or added through it's APIs. // However, the build may end up satisfying some fingerprints without using BuildCache. The build or // other cache instances in the cache topology can track these "other" fingerprints and ask that the // fingerprints be included in the cache session using the incoporate API. BuildCache will extend the // expiration of the fingerprints and mapped content, as if they had just been published. foreach (var strongFingerprintTask in strongFingerprints) { var strongFingerprint = await strongFingerprintTask.ConfigureAwait(false); // The Incorporate API currently does allow passing the expiration, so we can't pass it here. FingerprintTracker.Track(strongFingerprint); } return BoolResult.Success; })); }
/// <inheritdoc /> public Task <AddOrGetContentHashListResult> AddOrGetContentHashListAsync( Context context, StrongFingerprint strongFingerprint, ContentHashListWithDeterminism contentHashListWithDeterminism, CancellationToken cts, UrgencyHint urgencyHint) { return(AddOrGetContentHashListCall.RunAsync(Tracer.MemoizationStoreTracer, new OperationContext(context, cts), strongFingerprint, async() => { // TODO: Split this out into separate implementations for WriteThrough vs. WriteBehind (bug 1365340) if (WriteThroughContentSession == null) { // Guaranteed content is currently only available for BlobSessions. (bug 144396) ContentAvailabilityGuarantee guarantee = BackingContentSession is BlobContentSession ? ContentAvailabilityGuarantee.AllContentBackedByCache : ContentAvailabilityGuarantee.NoContentBackedByCache; return await AddOrGetContentHashListAsync( context, strongFingerprint, contentHashListWithDeterminism, guarantee).ConfigureAwait(false); } // Ensure that the content exists somewhere before trying to add if (!await EnsureContentIsAvailableAsync( context, contentHashListWithDeterminism.ContentHashList.Hashes, cts, urgencyHint).ConfigureAwait(false)) { return new AddOrGetContentHashListResult( "Referenced content must exist in the cache before a new content hash list is added."); } DateTime expirationUtc = FingerprintTracker.GenerateNewExpiration(); var valueToAdd = new ContentHashListWithCacheMetadata( contentHashListWithDeterminism, expirationUtc, ContentAvailabilityGuarantee.NoContentBackedByCache); DateTime?rawExpiration = null; const int addLimit = 3; for (int addAttempts = 0; addAttempts < addLimit; addAttempts++) { var debugString = $"Adding contentHashList=[{valueToAdd.ContentHashListWithDeterminism.ContentHashList}] " + $"determinism=[{valueToAdd.ContentHashListWithDeterminism.Determinism}] to VSTS with " + $"contentAvailabilityGuarantee=[{valueToAdd.ContentGuarantee}] and expirationUtc=[{expirationUtc}]"; Tracer.Debug(context, debugString); ObjectResult <ContentHashListWithCacheMetadata> responseObject = await ContentHashListAdapter.AddContentHashListAsync( context, CacheNamespace, strongFingerprint, valueToAdd).ConfigureAwait(false); if (!responseObject.Succeeded) { return new AddOrGetContentHashListResult(responseObject); } ContentHashListWithCacheMetadata response = responseObject.Data; var inconsistencyErrorMessage = CheckForResponseInconsistency(response); if (inconsistencyErrorMessage != null) { return new AddOrGetContentHashListResult(inconsistencyErrorMessage); } rawExpiration = response.GetRawExpirationTimeUtc(); ContentHashList contentHashListToReturn = UnpackContentHashListAfterAdd(contentHashListWithDeterminism.ContentHashList, response); CacheDeterminism determinismToReturn = UnpackDeterminism(response, CacheId); bool needToUpdateExistingValue = await CheckNeedToUpdateExistingValueAsync( context, response, contentHashListToReturn, cts, urgencyHint).ConfigureAwait(false); if (!needToUpdateExistingValue) { SealIfNecessaryAfterUnbackedAddOrGet(context, strongFingerprint, contentHashListWithDeterminism, response); FingerprintTracker.Track(strongFingerprint, rawExpiration); return new AddOrGetContentHashListResult( new ContentHashListWithDeterminism(contentHashListToReturn, determinismToReturn)); } var hashOfExistingContentHashList = response.HashOfExistingContentHashList; Tracer.Debug(context, $"Attempting to replace unbacked value with hash {hashOfExistingContentHashList.ToHex()}"); valueToAdd = new ContentHashListWithCacheMetadata( contentHashListWithDeterminism, expirationUtc, ContentAvailabilityGuarantee.NoContentBackedByCache, hashOfExistingContentHashList ); } Tracer.Warning( context, $"Lost the AddOrUpdate race {addLimit} times against unbacked values. Returning as though the add succeeded for now."); FingerprintTracker.Track(strongFingerprint, rawExpiration); return new AddOrGetContentHashListResult(new ContentHashListWithDeterminism(null, CacheDeterminism.None)); })); }