internal BatchResponse(
     HttpStatusCode statusCode,
     SubStatusCodes subStatusCode,
     string errorMessage,
     double requestCharge,
     TimeSpan?retryAfter,
     string activityId,
     ServerBatchRequest serverRequest,
     CosmosSerializer serializer)
     : this(statusCode, subStatusCode, errorMessage, requestCharge, retryAfter, activityId, serverRequest.Operations, serializer)
 {
 }
        internal static async Task <BatchResponse> PopulateFromContentAsync(
            ResponseMessage responseMessage,
            ServerBatchRequest serverRequest,
            CosmosSerializer serializer)
        {
            List <BatchOperationResult> results = new List <BatchOperationResult>();

            int resizerInitialCapacity = 81920;

            if (responseMessage.Content.CanSeek)
            {
                resizerInitialCapacity = (int)responseMessage.Content.Length;
            }

            Result res = await responseMessage.Content.ReadRecordIOAsync(
                record =>
            {
                Result r = BatchOperationResult.ReadOperationResult(record, out BatchOperationResult operationResult);
                if (r != Result.Success)
                {
                    return(r);
                }

                results.Add(operationResult);
                return(r);
            },
                resizer : new MemorySpanResizer <byte>(resizerInitialCapacity));

            if (res != Result.Success)
            {
                return(null);
            }

            BatchResponse response = new BatchResponse(
                responseMessage.StatusCode,
                responseMessage.Headers.SubStatusCode,
                responseMessage.ErrorMessage,
                responseMessage.Headers.RequestCharge,
                responseMessage.Headers.RetryAfter,
                responseMessage.Headers.ActivityId,
                responseMessage.Diagnostics,
                serverRequest,
                serializer);

            response.results = results;
            return(response);
        }
Exemple #3
0
        private static async Task <TransactionalBatchResponse> PopulateFromContentAsync(
            Stream content,
            ResponseMessage responseMessage,
            ServerBatchRequest serverRequest,
            CosmosSerializerCore serializer,
            ITrace trace,
            bool shouldPromoteOperationStatus)
        {
            List <TransactionalBatchOperationResult> results = new List <TransactionalBatchOperationResult>();

            // content is ensured to be seekable in caller.
            int resizerInitialCapacity = (int)content.Length;

            Result res = await content.ReadRecordIOAsync(
                (Func <ReadOnlyMemory <byte>, Result>)(record =>
            {
                Result r = TransactionalBatchOperationResult.ReadOperationResult(record, out TransactionalBatchOperationResult operationResult);
                if (r != Result.Success)
                {
                    return(r);
                }

                operationResult.Trace = trace;

                results.Add(operationResult);
                return(r);
            }),
                resizer : new MemorySpanResizer <byte>(resizerInitialCapacity));

            if (res != Result.Success)
            {
                return(null);
            }

            HttpStatusCode responseStatusCode    = responseMessage.StatusCode;
            SubStatusCodes responseSubStatusCode = responseMessage.Headers.SubStatusCode;

            // Promote the operation error status as the Batch response error status if we have a MultiStatus response
            // to provide users with status codes they are used to.
            if ((int)responseMessage.StatusCode == (int)StatusCodes.MultiStatus &&
                shouldPromoteOperationStatus)
            {
                foreach (TransactionalBatchOperationResult result in results)
                {
                    if ((int)result.StatusCode != (int)StatusCodes.FailedDependency && (int)result.StatusCode >= (int)StatusCodes.StartingErrorCode)
                    {
                        responseStatusCode    = result.StatusCode;
                        responseSubStatusCode = result.SubStatusCode;
                        break;
                    }
                }
            }

            TransactionalBatchResponse response = new TransactionalBatchResponse(
                responseStatusCode,
                responseSubStatusCode,
                responseMessage.ErrorMessage,
                responseMessage.Headers,
                trace,
                serverRequest.Operations,
                serializer)
            {
                results = results
            };

            return(response);
        }
Exemple #4
0
        internal static async Task <TransactionalBatchResponse> FromResponseMessageAsync(
            ResponseMessage responseMessage,
            ServerBatchRequest serverRequest,
            CosmosSerializerCore serializer,
            bool shouldPromoteOperationStatus,
            ITrace trace,
            CancellationToken cancellationToken)
        {
            using (ITrace createResponseTrace = trace.StartChild("Create Trace", TraceComponent.Batch, TraceLevel.Info))
            {
                using (responseMessage)
                {
                    TransactionalBatchResponse response = null;
                    if (responseMessage.Content != null)
                    {
                        Stream content = responseMessage.Content;

                        // Shouldn't be the case practically, but handle it for safety.
                        if (!responseMessage.Content.CanSeek)
                        {
                            content = new MemoryStream();
                            await responseMessage.Content.CopyToAsync(content);
                        }

                        if (content.ReadByte() == (int)HybridRowVersion.V1)
                        {
                            content.Position = 0;
                            response         = await TransactionalBatchResponse.PopulateFromContentAsync(
                                content,
                                responseMessage,
                                serverRequest,
                                serializer,
                                trace,
                                shouldPromoteOperationStatus);

                            if (response == null)
                            {
                                // Convert any payload read failures as InternalServerError
                                response = new TransactionalBatchResponse(
                                    HttpStatusCode.InternalServerError,
                                    SubStatusCodes.Unknown,
                                    ClientResources.ServerResponseDeserializationFailure,
                                    responseMessage.Headers,
                                    trace,
                                    serverRequest.Operations,
                                    serializer);
                            }
                        }
                    }

                    if (response == null)
                    {
                        response = new TransactionalBatchResponse(
                            responseMessage.StatusCode,
                            responseMessage.Headers.SubStatusCode,
                            responseMessage.ErrorMessage,
                            responseMessage.Headers,
                            trace,
                            serverRequest.Operations,
                            serializer);
                    }

                    if (response.results == null || response.results.Count != serverRequest.Operations.Count)
                    {
                        if (responseMessage.IsSuccessStatusCode)
                        {
                            // Server should be guaranteeing number of results equal to operations when
                            // batch request is successful - so fail as InternalServerError if this is not the case.
                            response = new TransactionalBatchResponse(
                                HttpStatusCode.InternalServerError,
                                SubStatusCodes.Unknown,
                                ClientResources.InvalidServerResponse,
                                responseMessage.Headers,
                                trace,
                                serverRequest.Operations,
                                serializer);
                        }

                        // When the overall response status code is TooManyRequests, propagate the RetryAfter into the individual operations.
                        int retryAfterMilliseconds = 0;

                        if ((int)responseMessage.StatusCode == (int)StatusCodes.TooManyRequests)
                        {
                            if (!responseMessage.Headers.TryGetValue(HttpConstants.HttpHeaders.RetryAfterInMilliseconds, out string retryAfter) ||
                                retryAfter == null ||
                                !int.TryParse(retryAfter, out retryAfterMilliseconds))
                            {
                                retryAfterMilliseconds = 0;
                            }
                        }

                        response.CreateAndPopulateResults(serverRequest.Operations, trace, retryAfterMilliseconds);
                    }

                    return(response);
                }
            }
        }
        internal static async Task <BatchResponse> FromResponseMessageAsync(
            ResponseMessage responseMessage,
            ServerBatchRequest serverRequest,
            CosmosSerializer serializer)
        {
            using (responseMessage)
            {
                BatchResponse response = null;
                if (responseMessage.IsSuccessStatusCode && responseMessage.Content != null)
                {
                    response = await BatchResponse.PopulateFromContentAsync(responseMessage, serverRequest, serializer);

                    if (response == null)
                    {
                        // Convert any payload read failures as InternalServerError
                        response = new BatchResponse(
                            HttpStatusCode.InternalServerError,
                            SubStatusCodes.Unknown,
                            ClientResources.ServerResponseDeserializationFailure,
                            responseMessage.Headers.RequestCharge,
                            responseMessage.Headers.RetryAfter,
                            responseMessage.Headers.ActivityId,
                            serverRequest,
                            serializer);
                    }
                }
                else
                {
                    response = new BatchResponse(
                        responseMessage.StatusCode,
                        responseMessage.Headers.SubStatusCode,
                        responseMessage.ErrorMessage,
                        responseMessage.Headers.RequestCharge,
                        responseMessage.Headers.RetryAfter,
                        responseMessage.Headers.ActivityId,
                        serverRequest,
                        serializer);
                }

                if (response.results == null || response.results.Count != serverRequest.Operations.Count)
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        // Server should be guaranteeing number of results equal to operations when
                        // batch request is successful - so fail as InternalServerError if this is not the case.
                        response = new BatchResponse(
                            HttpStatusCode.InternalServerError,
                            SubStatusCodes.Unknown,
                            ClientResources.InvalidServerResponse,
                            responseMessage.Headers.RequestCharge,
                            responseMessage.Headers.RetryAfter,
                            responseMessage.Headers.ActivityId,
                            serverRequest,
                            serializer);
                    }

                    // When the overall response status code is TooManyRequests, propagate the RetryAfter into the individual operations.
                    int retryAfterMilliseconds = 0;

                    if ((int)responseMessage.StatusCode == (int)StatusCodes.TooManyRequests)
                    {
                        if (!responseMessage.Headers.TryGetValue(HttpConstants.HttpHeaders.RetryAfterInMilliseconds, out string retryAfter) ||
                            retryAfter == null ||
                            !int.TryParse(retryAfter, out retryAfterMilliseconds))
                        {
                            retryAfterMilliseconds = 0;
                        }
                    }

                    response.results = new List <BatchOperationResult>();
                    for (int i = 0; i < serverRequest.Operations.Count; i++)
                    {
                        response.results.Add(
                            new BatchOperationResult(response.StatusCode)
                        {
                            SubStatusCode = response.SubStatusCode,
                            RetryAfter    = TimeSpan.FromMilliseconds(retryAfterMilliseconds),
                        });
                    }
                }

                return(response);
            }
        }
Exemple #6
0
        internal static async Task <TransactionalBatchResponse> FromResponseMessageAsync(
            ResponseMessage responseMessage,
            ServerBatchRequest serverRequest,
            CosmosSerializerCore serializer,
            bool shouldPromoteOperationStatus,
            bool shouldPerformDecryption,
            CancellationToken cancellationToken)
        {
            using (responseMessage)
            {
                TransactionalBatchResponse response = null;
                if (responseMessage.Content != null)
                {
                    Stream content = responseMessage.Content;

                    // Shouldn't be the case practically, but handle it for safety.
                    if (!responseMessage.Content.CanSeek)
                    {
                        content = new MemoryStream();
                        await responseMessage.Content.CopyToAsync(content);
                    }

                    if (content.ReadByte() == (int)HybridRowVersion.V1)
                    {
                        content.Position = 0;
                        response         = await TransactionalBatchResponse.PopulateFromContentAsync(
                            content,
                            responseMessage,
                            serverRequest,
                            serializer,
                            shouldPromoteOperationStatus);

                        if (response == null)
                        {
                            // Convert any payload read failures as InternalServerError
                            response = new TransactionalBatchResponse(
                                HttpStatusCode.InternalServerError,
                                SubStatusCodes.Unknown,
                                ClientResources.ServerResponseDeserializationFailure,
                                responseMessage.Headers.RequestCharge,
                                responseMessage.Headers.RetryAfter,
                                responseMessage.Headers.ActivityId,
                                responseMessage.DiagnosticsContext,
                                serverRequest.Operations,
                                serializer);
                        }
                    }
                }

                if (response == null)
                {
                    response = new TransactionalBatchResponse(
                        responseMessage.StatusCode,
                        responseMessage.Headers.SubStatusCode,
                        responseMessage.ErrorMessage,
                        responseMessage.Headers.RequestCharge,
                        responseMessage.Headers.RetryAfter,
                        responseMessage.Headers.ActivityId,
                        responseMessage.DiagnosticsContext,
                        serverRequest.Operations,
                        serializer);
                }

                if (response.results == null || response.results.Count != serverRequest.Operations.Count)
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        // Server should be guaranteeing number of results equal to operations when
                        // batch request is successful - so fail as InternalServerError if this is not the case.
                        response = new TransactionalBatchResponse(
                            HttpStatusCode.InternalServerError,
                            SubStatusCodes.Unknown,
                            ClientResources.InvalidServerResponse,
                            responseMessage.Headers.RequestCharge,
                            responseMessage.Headers.RetryAfter,
                            responseMessage.Headers.ActivityId,
                            responseMessage.DiagnosticsContext,
                            serverRequest.Operations,
                            serializer);
                    }

                    // When the overall response status code is TooManyRequests, propagate the RetryAfter into the individual operations.
                    int retryAfterMilliseconds = 0;

                    if ((int)responseMessage.StatusCode == (int)StatusCodes.TooManyRequests)
                    {
                        if (!responseMessage.Headers.TryGetValue(HttpConstants.HttpHeaders.RetryAfterInMilliseconds, out string retryAfter) ||
                            retryAfter == null ||
                            !int.TryParse(retryAfter, out retryAfterMilliseconds))
                        {
                            retryAfterMilliseconds = 0;
                        }
                    }

                    response.CreateAndPopulateResults(serverRequest.Operations, retryAfterMilliseconds);
                }
                else if (shouldPerformDecryption)
                {
                    for (int index = 0; index < serverRequest.Operations.Count; index++)
                    {
                        ContainerCore containerCore = serverRequest.Operations[index].ContainerCore;
                        TransactionalBatchOperationResult result = response.results[index];
                        result.ResourceStream = await containerCore.ClientContext.DecryptItemAsync(
                            result.ResourceStream,
                            (DatabaseCore)containerCore.Database,
                            responseMessage.DiagnosticsContext,
                            cancellationToken);
                    }
                }

                return(response);
            }
        }