private async Task <BoolResult> GetFileWithDedupAsync(OperationContext context, ContentHash contentHash, string path)
        {
            BlobIdentifier  blobId  = contentHash.ToBlobIdentifier();
            DedupIdentifier dedupId = blobId.ToDedupIdentifier();

            try
            {
                await TryGatedArtifactOperationAsync <object>(
                    context,
                    contentHash.ToString(),
                    "DownloadToFileAsync",
                    async innerCts =>
                {
                    await DedupStoreClient.DownloadToFileAsync(dedupId, path, null, null, EdgeCache.Allowed, innerCts);
                    return(null);
                });
            }
            catch (NullReferenceException) // Null reference thrown when DedupIdentifier doesn't exist in VSTS.
            {
                return(new BoolResult("DedupIdentifier not found."));
            }
            catch (Exception ex)
            {
                return(new BoolResult(ex));
            }

            return(BoolResult.Success);
        }
        private async Task <PinResult> PinCoreImplAsync(
            OperationContext context, ContentHash contentHash, DateTime keepUntil)
        {
            if (!contentHash.HashType.IsValidDedup())
            {
                return(new PinResult($"DedupStore client requires a HashType that supports dedup. Given hash type: {contentHash.HashType}."));
            }

            var pinResult = CheckPinInMemory(contentHash, keepUntil);

            if (pinResult.Succeeded)
            {
                return(pinResult);
            }

            BlobIdentifier  blobId  = contentHash.ToBlobIdentifier();
            DedupIdentifier dedupId = blobId.ToDedupIdentifier();

            if (dedupId.AlgorithmId == Hashing.ChunkDedupIdentifier.ChunkAlgorithmId)
            {
                // No need to optimize since pinning a chunk is always a fast operation.
                return(await PinImplAsync(context, contentHash, keepUntil));
            }

            // Since pinning the whole tree can be an expensive operation, we have optimized how we call it. Depending on the current
            //  keepUntil of the root node, which is unexpensive to check, the operation will behave differently:
            //      The pin operation will be ignored if it is greater than ignorePinThreshold, to reduce amount of calls
            //      The pin operation will be inlined if it is lower than pinInlineThreshold, to make sure that we don't try to use
            //          content that we pin in the background but has expired before we could complete the pin.
            //      The pin operation will be done asynchronously and will return success otherwise. Most calls should follow this
            //          behavior, to avoid waiting on a potentially long operation. We're confident returning a success because we
            //          know that the content is there even though we still have to extend it's keepUntil

            var keepUntilResult = await CheckNodeKeepUntilAsync(context, dedupId);

            if (!keepUntilResult.Succeeded)
            {
                // Returned a service error. Fail fast.
                return(new PinResult(keepUntilResult));
            }
            else if (!keepUntilResult.Value.HasValue)
            {
                // Content not found.
                return(new PinResult(PinResult.ResultCode.ContentNotFound));
            }

            var timeLeft = keepUntilResult.Value.Value - DateTime.UtcNow;


            // Make sure to only trigger this optimization for normal pins and not for pins for incorporate
            if (keepUntil == EndDateTime && timeLeft > _ignorePinThreshold)
            {
                Tracer.Debug(context, $"Pin was skipped because keepUntil has remaining time [{timeLeft}] that is greater than ignorePinThreshold=[{_ignorePinThreshold}]");
                _dedupCounters[Counters.PinIgnored].Increment();
                return(PinResult.Success);
            }

            var pinTask = PinImplAsync(context, contentHash, keepUntil);

            if (timeLeft < _pinInlineThreshold)
            {
                Tracer.Debug(context, $"Pin inlined because keepUntil has remaining time [{timeLeft}] that is less than pinInlineThreshold=[{_pinInlineThreshold}]");
                _dedupCounters[Counters.PinInlined].Increment();
                return(await pinTask);
            }

            pinTask.FireAndForget(context);

            return(PinResult.Success);
        }