private DownloadAndSaveObjectResult TryDownloadAndSaveObject(
            string objectId,
            CancellationToken cancellationToken,
            RequestSource requestSource,
            bool retryOnFailure)
        {
            if (objectId == GVFSConstants.AllZeroSha)
            {
                return(DownloadAndSaveObjectResult.Error);
            }

            DateTime negativeCacheRequestTime;

            if (this.objectNegativeCache.TryGetValue(objectId, out negativeCacheRequestTime))
            {
                if (negativeCacheRequestTime > DateTime.Now.Subtract(NegativeCacheTTL))
                {
                    return(DownloadAndSaveObjectResult.ObjectNotOnServer);
                }

                this.objectNegativeCache.TryRemove(objectId, out negativeCacheRequestTime);
            }

            // To reduce allocations, reuse the same buffer when writing objects in this batch
            byte[] bufToCopyWith = new byte[StreamUtil.DefaultCopyBufferSize];

            RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .InvocationResult output = this.GitObjectRequestor.TryDownloadLooseObject(
                objectId,
                retryOnFailure,
                cancellationToken,
                requestSource.ToString(),
                onSuccess: (tryCount, response) =>
            {
                // If the request is from git.exe (i.e. NamedPipeMessage) then we should assume that if there is an
                // object on disk it's corrupt somehow (which is why git is asking for it)
                this.WriteLooseObject(
                    response.Stream,
                    objectId,
                    overwriteExistingObject: requestSource == RequestSource.NamedPipeMessage,
                    bufToCopyWith: bufToCopyWith);

                return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(new GitObjectsHttpRequestor.GitObjectTaskResult(true)));
            });

            if (output.Result != null)
            {
                if (output.Succeeded && output.Result.Success)
                {
                    return(DownloadAndSaveObjectResult.Success);
                }

                if (output.Result.HttpStatusCodeResult == HttpStatusCode.NotFound)
                {
                    this.objectNegativeCache.AddOrUpdate(objectId, DateTime.Now, (unused1, unused2) => DateTime.Now);
                    return(DownloadAndSaveObjectResult.ObjectNotOnServer);
                }
            }

            return(DownloadAndSaveObjectResult.Error);
        }