Exemple #1
0
 /// <summary>
 /// Whether or not an existing guarantee is stronger than a provided guarantee.
 /// </summary>
 public static bool HasStrongerGuarantee(
     this ContentAvailabilityGuarantee existingGuarantee,
     ContentAvailabilityGuarantee otherGuarantee)
 {
     // behaviour: this.HasStrongerGuarantee(that)
     // returns true if this has content backed by cache and that is not.
     // returns false if they are equal or if the other has content backed by cache
     // and this does not.
     return(existingGuarantee < otherGuarantee);
 }
        /// <inheritdoc />
        protected async Task <AddOrGetContentHashListResult> AddOrGetContentHashListAsync(
            Context context,
            StrongFingerprint strongFingerprint,
            ContentHashListWithDeterminism contentHashListWithDeterminism,
            ContentAvailabilityGuarantee guarantee)
        {
            try
            {
                DateTime expirationUtc = FingerprintTracker.GenerateNewExpiration();
                var      valueToAdd    = new ContentHashListWithCacheMetadata(
                    contentHashListWithDeterminism, expirationUtc, guarantee);

                Tracer.Debug(
                    context,
                    $"Adding contentHashList=[{valueToAdd.ContentHashListWithDeterminism.ContentHashList}] determinism=[{valueToAdd.ContentHashListWithDeterminism.Determinism}] to VSTS with contentAvailabilityGuarantee=[{valueToAdd.ContentGuarantee}] and expirationUtc=[{expirationUtc}]");

                var contentHashListResponseObject = await ContentHashListAdapter.AddContentHashListAsync(context, CacheNamespace, strongFingerprint, valueToAdd).ConfigureAwait(false);

                if (!contentHashListResponseObject.Succeeded)
                {
                    return(new AddOrGetContentHashListResult(contentHashListResponseObject));
                }

                var contentHashListResponse   = contentHashListResponseObject.Data;
                var inconsistencyErrorMessage = CheckForResponseInconsistency(contentHashListResponse);
                if (inconsistencyErrorMessage != null)
                {
                    return(new AddOrGetContentHashListResult(inconsistencyErrorMessage));
                }

                ContentHashList contentHashListToReturn = UnpackContentHashListAfterAdd(
                    contentHashListWithDeterminism.ContentHashList, contentHashListResponse);

                CacheDeterminism determinismToReturn = UnpackDeterminism(contentHashListResponse, CacheId);
                if (guarantee == ContentAvailabilityGuarantee.AllContentBackedByCache && !determinismToReturn.IsDeterministic)
                {
                    return(new AddOrGetContentHashListResult(
                               "Inconsistent BuildCache service response. Unbacked values should never override backed values."));
                }

                FingerprintTracker.Track(strongFingerprint, contentHashListResponse.GetRawExpirationTimeUtc());
                return(new AddOrGetContentHashListResult(new ContentHashListWithDeterminism(contentHashListToReturn, determinismToReturn)));
            }
            catch (Exception e)
            {
                return(new AddOrGetContentHashListResult(e));
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="BlobContentHashListWithCacheMetadata"/> class.
        /// </summary>
        public BlobContentHashListWithCacheMetadata(
            BlobContentHashListWithDeterminism contentHashListWithDeterminism,
            DateTime?contentHashListExpirationUtc,
            ContentAvailabilityGuarantee contentGuarantee,
            byte[] hashOfExistingContentHashList = null)
        {
            if (contentHashListExpirationUtc != null && contentHashListExpirationUtc.Value.Kind != DateTimeKind.Utc)
            {
                throw new ArgumentException("Time to live must be an absolute UTC date time.");
            }

            ContentHashListWithDeterminism = contentHashListWithDeterminism;
            ContentHashListExpirationUtc   = contentHashListExpirationUtc;
            ContentGuarantee = contentGuarantee;
            HashOfExistingContentHashList = hashOfExistingContentHashList;
        }
Exemple #4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DistributedContentSession{T}"/> class.
 /// </summary>
 public DistributedContentSession(
     string name,
     IContentSession inner,
     IContentLocationStore contentLocationStore,
     ContentAvailabilityGuarantee contentAvailabilityGuarantee,
     DistributedContentCopier <T> contentCopier,
     byte[] localMachineLocation,
     PinCache pinCache = null,
     ContentTrackerUpdater contentTrackerUpdater = null,
     DistributedContentStoreSettings settings    = default)
     : base(
         name,
         inner,
         contentLocationStore,
         contentAvailabilityGuarantee,
         contentCopier,
         localMachineLocation,
         pinCache: pinCache,
         contentTrackerUpdater: contentTrackerUpdater,
         settings)
 {
 }
Exemple #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DistributedContentSession{T}"/> class.
 /// </summary>
 public DistributedContentSession(
     string name,
     IContentSession inner,
     IContentLocationStore contentLocationStore,
     ContentAvailabilityGuarantee contentAvailabilityGuarantee,
     DistributedContentCopier <T> contentCopier,
     MachineLocation localMachineLocation,
     PinCache pinCache = null,
     ContentTrackerUpdater contentTrackerUpdater = null,
     DistributedContentStoreSettings settings    = default)
     : base(
         name,
         inner,
         contentLocationStore,
         contentAvailabilityGuarantee,
         contentCopier,
         localMachineLocation,
         pinCache: pinCache,
         contentTrackerUpdater: contentTrackerUpdater,
         settings)
 {
     _putFileGate = new SemaphoreSlim(settings.MaximumConcurrentPutFileOperations);
 }
Exemple #6
0
        /// <inheritdoc />
        public Task <AddOrGetContentHashListResult> AddOrGetContentHashListAsync(
            Context context,
            StrongFingerprint strongFingerprint,
            ContentHashListWithDeterminism contentHashListWithDeterminism,
            CancellationToken cts,
            UrgencyHint urgencyHint)
        {
            return(new OperationContext(context, cts).PerformOperationAsync(
                       Tracer.MemoizationStoreTracer,
                       async() =>
            {
                // TODO: Split this out into separate implementations for WriteThrough vs. WriteBehind (bug 1365340)
                if (WriteThroughContentSession == null)
                {
                    ContentAvailabilityGuarantee guarantee =
                        ManuallyExtendContentLifetime
                                ? ContentAvailabilityGuarantee.NoContentBackedByCache
                                : ContentAvailabilityGuarantee.AllContentBackedByCache;

                    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}], expirationUtc=[{expirationUtc}], forceUpdate=[{ForceUpdateOnAddContentHashList}]";
                    Tracer.Debug(context, debugString);
                    Result <ContentHashListWithCacheMetadata> responseObject =
                        await ContentHashListAdapter.AddContentHashListAsync(
                            context,
                            CacheNamespace,
                            strongFingerprint,
                            valueToAdd,
                            forceUpdate: ForceUpdateOnAddContentHashList).ConfigureAwait(false);

                    if (!responseObject.Succeeded)
                    {
                        return new AddOrGetContentHashListResult(responseObject);
                    }

                    ContentHashListWithCacheMetadata response = responseObject.Value;
                    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);

                        await TrackFingerprintAsync(context, strongFingerprint, rawExpiration).ConfigureAwait(false);
                        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.");
                await TrackFingerprintAsync(context, strongFingerprint, rawExpiration).ConfigureAwait(false);
                return new AddOrGetContentHashListResult(new ContentHashListWithDeterminism(null, CacheDeterminism.None));
            },
                       traceOperationStarted: true,
                       extraStartMessage: $"StrongFingerprint=({strongFingerprint}), ForceUpdate=({ForceUpdateOnAddContentHashList}) {contentHashListWithDeterminism.ToTraceString()}",
                       extraEndMessage: _ => $"StrongFingerprint=({strongFingerprint}), ForceUpdate=({ForceUpdateOnAddContentHashList}) {contentHashListWithDeterminism.ToTraceString()}"));
        }