Beispiel #1
0
            public override int Execute(DocumentsOperationContext context)
            {
                if (Database.ServerStore.Configuration.Core.FeaturesAvailability == FeaturesAvailability.Stable)
                {
                    FeaturesAvailabilityException.Throw("Cluster Transactions");
                }
                var global = context.LastDatabaseChangeVector ??
                             (context.LastDatabaseChangeVector = DocumentsStorage.GetDatabaseChangeVector(context));
                var dbGrpId = Database.DatabaseGroupId;
                var current = ChangeVectorUtils.GetEtagById(global, dbGrpId);

                foreach (var command in _batch)
                {
                    Replies.Add(command.Index, new DynamicJsonArray());
                    Reply = Replies[command.Index];

                    var commands = command.Commands;
                    var count    = command.PreviousCount;
                    var options  = Options[command.Index] = command.Options;

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

                    if (commands != null)
                    {
                        foreach (BlittableJsonReaderObject blittableCommand in commands)
                        {
                            count++;
                            var changeVector = $"RAFT:{count}-{dbGrpId}";

                            var cmd = JsonDeserializationServer.ClusterTransactionDataCommand(blittableCommand);

                            switch (cmd.Type)
                            {
                            case CommandType.PUT:
                                if (current < count)
                                {
                                    // delete the document to avoid exception if we put new document in a different collection.
                                    // TODO: document this behavior
                                    using (DocumentIdWorker.GetSliceFromId(context, cmd.Id, out Slice lowerId))
                                    {
                                        Database.DocumentsStorage.Delete(context, lowerId, cmd.Id, expectedChangeVector: null,
                                                                         nonPersistentFlags: NonPersistentDocumentFlags.SkipRevisionCreation);
                                    }

                                    var putResult = Database.DocumentsStorage.Put(context, cmd.Id, null, cmd.Document.Clone(context), changeVector: changeVector,
                                                                                  flags: DocumentFlags.FromClusterTransaction);
                                    context.DocumentDatabase.HugeDocuments.AddIfDocIsHuge(cmd.Id, cmd.Document.Size);
                                    AddPutResult(putResult);
                                }
                                else
                                {
                                    try
                                    {
                                        var item = Database.DocumentsStorage.GetDocumentOrTombstone(context, cmd.Id);
                                        if (item.Missing)
                                        {
                                            AddPutResult(new DocumentsStorage.PutOperationResults
                                            {
                                                ChangeVector = changeVector,
                                                Id           = cmd.Id,
                                                LastModified = DateTime.UtcNow,
                                                Collection   = Database.DocumentsStorage.ExtractCollectionName(context, cmd.Document)
                                            });
                                            continue;
                                        }
                                        var collection = GetCollection(context, item);
                                        AddPutResult(new DocumentsStorage.PutOperationResults
                                        {
                                            ChangeVector = changeVector,
                                            Id           = cmd.Id,
                                            Flags        = item.Document?.Flags ?? item.Tombstone.Flags,
                                            LastModified = item.Document?.LastModified ?? item.Tombstone.LastModified,
                                            Collection   = collection
                                        });
                                    }
                                    catch (DocumentConflictException)
                                    {
                                        AddPutResult(new DocumentsStorage.PutOperationResults
                                        {
                                            ChangeVector = changeVector,
                                            Id           = cmd.Id,
                                            Collection   = GetFirstConflictCollection(context, cmd)
                                        });
                                    }
                                }

                                break;

                            case CommandType.DELETE:
                                if (current < count)
                                {
                                    using (DocumentIdWorker.GetSliceFromId(context, cmd.Id, out Slice lowerId))
                                    {
                                        var deleteResult = Database.DocumentsStorage.Delete(context, lowerId, cmd.Id, null, changeVector: changeVector,
                                                                                            documentFlags: DocumentFlags.FromClusterTransaction);
                                        AddDeleteResult(deleteResult, cmd.Id);
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        var item = Database.DocumentsStorage.GetDocumentOrTombstone(context, cmd.Id);
                                        if (item.Missing)
                                        {
                                            AddDeleteResult(new DocumentsStorage.DeleteOperationResult
                                            {
                                                ChangeVector = changeVector,
                                                Collection   = null
                                            }, cmd.Id);
                                            continue;
                                        }
                                        var collection = GetCollection(context, item);
                                        AddDeleteResult(new DocumentsStorage.DeleteOperationResult
                                        {
                                            ChangeVector = changeVector,
                                            Collection   = collection
                                        }, cmd.Id);
                                    }
                                    catch (DocumentConflictException)
                                    {
                                        AddDeleteResult(new DocumentsStorage.DeleteOperationResult
                                        {
                                            ChangeVector = changeVector,
                                            Collection   = GetFirstConflictCollection(context, cmd)
                                        }, cmd.Id);
                                    }
                                }
                                break;

                            default:
                                throw new NotSupportedException($"{cmd.Type} is not supported in {nameof(ClusterTransactionMergedCommand)}.");
                            }
                        }
                    }

                    if (context.LastDatabaseChangeVector == null)
                    {
                        context.LastDatabaseChangeVector = global;
                    }

                    var result = ChangeVectorUtils.TryUpdateChangeVector("RAFT", dbGrpId, count, context.LastDatabaseChangeVector);
                    if (result.IsValid)
                    {
                        context.LastDatabaseChangeVector = result.ChangeVector;
                    }
                }

                return(Reply.Count);
            }