Exemplo n.º 1
0
        public async Task BulkDocs()
        {
            using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
                using (var command = new MergedBatchCommand(Database))
                {
                    var contentType = HttpContext.Request.ContentType;
                    if (contentType == null ||
                        contentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
                    {
                        await BatchRequestParser.BuildCommandsAsync(context, command, RequestBodyStream(), Database, ServerStore);
                    }
                    else if (contentType.StartsWith("multipart/mixed", StringComparison.OrdinalIgnoreCase) ||
                             contentType.StartsWith("multipart/form-data", StringComparison.OrdinalIgnoreCase))
                    {
                        await ParseMultipart(context, command);
                    }
                    else
                    {
                        ThrowNotSupportedType(contentType);
                    }

                    var waitForIndexesTimeout       = GetTimeSpanQueryString("waitForIndexesTimeout", required: false);
                    var waitForIndexThrow           = GetBoolValueQueryString("waitForIndexThrow", required: false) ?? true;
                    var specifiedIndexesQueryString = HttpContext.Request.Query["waitForSpecificIndex"];

                    if (command.IsClusterTransaction)
                    {
                        if (Server.Configuration.Core.FeaturesAvailability == FeaturesAvailability.Stable)
                        {
                            FeaturesAvailabilityException.Throw("Cluster Transactions");
                        }

                        using (Database.ClusterTransactionWaiter.CreateTask(out var taskId))
                        {
                            // Since this is a cluster transaction we are not going to wait for the write assurance of the replication.
                            // Because in any case the user will get a raft index to wait upon on his next request.
                            var options = new ClusterTransactionCommand.ClusterTransactionOptions(taskId)
                            {
                                WaitForIndexesTimeout       = waitForIndexesTimeout,
                                WaitForIndexThrow           = waitForIndexThrow,
                                SpecifiedIndexesQueryString = specifiedIndexesQueryString.Count > 0 ? specifiedIndexesQueryString.ToList() : null
                            };
                            await HandleClusterTransaction(context, command, options);
                        }
                        return;
                    }

                    if (waitForIndexesTimeout != null)
                    {
                        command.ModifiedCollections = new HashSet <string>();
                    }

                    try
                    {
                        await Database.TxMerger.Enqueue(command);

                        command.ExceptionDispatchInfo?.Throw();
                    }
                    catch (ConcurrencyException)
                    {
                        HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
                        throw;
                    }

                    var waitForReplicasTimeout = GetTimeSpanQueryString("waitForReplicasTimeout", required: false);
                    if (waitForReplicasTimeout != null)
                    {
                        var numberOfReplicasStr             = GetStringQueryString("numberOfReplicasToWaitFor", required: false) ?? "1";
                        var throwOnTimeoutInWaitForReplicas = GetBoolValueQueryString("throwOnTimeoutInWaitForReplicas", required: false) ?? true;

                        await WaitForReplicationAsync(Database, waitForReplicasTimeout.Value, numberOfReplicasStr, throwOnTimeoutInWaitForReplicas, command.LastChangeVector);
                    }

                    if (waitForIndexesTimeout != null)
                    {
                        await WaitForIndexesAsync(ContextPool, Database, waitForIndexesTimeout.Value, specifiedIndexesQueryString.ToList(), waitForIndexThrow,
                                                  command.LastChangeVector, command.LastTombstoneEtag, command.ModifiedCollections);
                    }

                    HttpContext.Response.StatusCode = (int)HttpStatusCode.Created;
                    using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                    {
                        context.Write(writer, new DynamicJsonValue
                        {
                            [nameof(BatchCommandResult.Results)] = command.Reply
                        });
                    }
                }
        }
Exemplo n.º 2
0
        public async Task BulkDocs()
        {
            using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
                using (var command = new MergedBatchCommand {
                    Database = Database
                })
                {
                    var contentType = HttpContext.Request.ContentType;
                    if (contentType == null ||
                        contentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
                    {
                        command.ParsedCommands = await BatchRequestParser.BuildCommandsAsync(context, RequestBodyStream(), Database, ServerStore);
                    }
                    else if (contentType.StartsWith("multipart/mixed", StringComparison.OrdinalIgnoreCase) ||
                             contentType.StartsWith("multipart/form-data", StringComparison.OrdinalIgnoreCase))
                    {
                        await ParseMultipart(context, command);
                    }
                    else
                    {
                        ThrowNotSupportedType(contentType);
                    }

                    var waitForIndexesTimeout = GetTimeSpanQueryString("waitForIndexesTimeout", required: false);
                    if (waitForIndexesTimeout != null)
                    {
                        command.ModifiedCollections = new HashSet <string>();
                    }
                    try
                    {
                        await Database.TxMerger.Enqueue(command);

                        command?.ExceptionDispatchInfo?.Throw();
                    }
                    catch (ConcurrencyException)
                    {
                        HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
                        throw;
                    }

                    var waitForReplicasTimeout = GetTimeSpanQueryString("waitForReplicasTimeout", required: false);
                    if (waitForReplicasTimeout != null)
                    {
                        await WaitForReplicationAsync(waitForReplicasTimeout.Value, command);
                    }

                    if (waitForIndexesTimeout != null)
                    {
                        await
                        WaitForIndexesAsync(waitForIndexesTimeout.Value, command.LastChangeVector, command.LastTombstoneEtag,
                                            command.ModifiedCollections);
                    }

                    HttpContext.Response.StatusCode = (int)HttpStatusCode.Created;

                    using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                    {
                        context.Write(writer, new DynamicJsonValue
                        {
                            ["Results"] = command.Reply
                        });
                    }
                }
        }
Exemplo n.º 3
0
        private async Task HandleClusterTransaction(DocumentsOperationContext context, MergedBatchCommand command, ClusterTransactionCommand.ClusterTransactionOptions options)
        {
            var clusterTransactionCommand = new ClusterTransactionCommand(Database.Name, command.ParsedCommands, options);
            var result = await ServerStore.SendToLeaderAsync(clusterTransactionCommand);

            if (result.Result is List <string> errors)
            {
                HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
                throw new ConcurrencyException($"Failed to execute cluster transaction due to the following issues: {string.Join(Environment.NewLine, errors)}");
            }

            // wait for the command to be applied on this node
            await ServerStore.WaitForCommitIndexChange(RachisConsensus.CommitIndexModification.GreaterOrEqual, result.Index);

            var array = new DynamicJsonArray();

            if (clusterTransactionCommand.DatabaseCommandsCount > 0)
            {
                var reply = (ClusterTransactionCompletionResult)await Database.ClusterTransactionWaiter.WaitForResults(options.TaskId, HttpContext.RequestAborted);

                if (reply.IndexTask != null)
                {
                    await reply.IndexTask;
                }

                array = reply.Array;
            }

            foreach (var clusterCommands in clusterTransactionCommand.ClusterCommands)
            {
                array.Add(new DynamicJsonValue
                {
                    ["Type"]  = clusterCommands.Type,
                    ["Key"]   = clusterCommands.Id,
                    ["Index"] = result.Index
                });
            }

            HttpContext.Response.StatusCode = (int)HttpStatusCode.Created;
            using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
            {
                context.Write(writer, new DynamicJsonValue
                {
                    [nameof(BatchCommandResult.Results)]          = array,
                    [nameof(BatchCommandResult.TransactionIndex)] = result.Index
                });
            }
        }