Пример #1
0
        public bool TryResolveIdenticalDocument(DocumentsOperationContext context, string id,
                                                BlittableJsonReaderObject incomingDoc,
                                                long lastModifiedTicks,
                                                string incomingChangeVector)
        {
            var existing          = _database.DocumentsStorage.GetDocumentOrTombstone(context, id, throwOnConflict: false);
            var existingDoc       = existing.Document;
            var existingTombstone = existing.Tombstone;

            if (existingDoc != null)
            {
                var compareResult = DocumentCompare.IsEqualTo(existingDoc.Data, incomingDoc, DocumentCompare.DocumentCompareOptions.MergeMetadata);
                if (compareResult == DocumentCompareResult.NotEqual)
                {
                    return(false);
                }

                // no real conflict here, both documents have identical content so we only merge the change vector without increasing the local etag to prevent ping-pong replication
                var mergedChangeVector = ChangeVectorUtils.MergeVectors(incomingChangeVector, existingDoc.ChangeVector);

                var nonPersistentFlags = NonPersistentDocumentFlags.FromResolver;

                nonPersistentFlags |= compareResult.HasFlag(DocumentCompareResult.AttachmentsNotEqual)
                    ? NonPersistentDocumentFlags.ResolveAttachmentsConflict : NonPersistentDocumentFlags.None;

                if (compareResult.HasFlag(DocumentCompareResult.CountersNotEqual))
                {
                    nonPersistentFlags |= NonPersistentDocumentFlags.ResolveCountersConflict;
                }

                if (compareResult.HasFlag(DocumentCompareResult.TimeSeriesNotEqual))
                {
                    nonPersistentFlags |= NonPersistentDocumentFlags.ResolveTimeSeriesConflict;
                }

                _database.DocumentsStorage.Put(context, id, null, incomingDoc, lastModifiedTicks, mergedChangeVector, nonPersistentFlags: nonPersistentFlags);
                return(true);
            }

            if (existingTombstone != null && incomingDoc == null)
            {
                // Conflict between two tombstones resolves to the local tombstone
                existingTombstone.ChangeVector = ChangeVectorUtils.MergeVectors(incomingChangeVector, existingTombstone.ChangeVector);
                using (Slice.External(context.Allocator, existingTombstone.LowerId, out Slice lowerId))
                {
                    _database.DocumentsStorage.ConflictsStorage.DeleteConflicts(context, lowerId, null, existingTombstone.ChangeVector);
                }
                return(true);
            }

            return(false);
        }
Пример #2
0
        public bool ShouldVersionDocument(CollectionName collectionName, NonPersistentDocumentFlags nonPersistentFlags,
                                          BlittableJsonReaderObject existingDocument, BlittableJsonReaderObject document, ref DocumentFlags documentFlags,
                                          out RevisionsCollectionConfiguration configuration)
        {
            configuration = GetRevisionsConfiguration(collectionName.Name);
            if (configuration.Disabled)
            {
                return(false);
            }

            try
            {
                if ((nonPersistentFlags & NonPersistentDocumentFlags.FromSmuggler) != NonPersistentDocumentFlags.FromSmuggler)
                {
                    return(true);
                }
                if (existingDocument == null)
                {
                    if ((nonPersistentFlags & NonPersistentDocumentFlags.SkipRevisionCreation) == NonPersistentDocumentFlags.SkipRevisionCreation)
                    {
                        // Smuggler is configured to avoid creating new revisions during import
                        return(false);
                    }

                    // we are not going to create a revision if it's an import from v3
                    // (since this import is going to import revisions as well)
                    return((nonPersistentFlags & NonPersistentDocumentFlags.LegacyHasRevisions) != NonPersistentDocumentFlags.LegacyHasRevisions);
                }

                // compare the contents of the existing and the new document
                if (DocumentCompare.IsEqualTo(existingDocument, document, false) != DocumentCompareResult.NotEqual)
                {
                    // no need to create a new revision, both documents have identical content
                    return(false);
                }

                return(true);
            }
            finally
            {
                documentFlags |= DocumentFlags.HasRevisions;
            }
        }
Пример #3
0
        public bool TryResolveIdenticalDocument(DocumentsOperationContext context, string id,
                                                BlittableJsonReaderObject incomingDoc,
                                                long lastModifiedTicks,
                                                string incomingChangeVector)
        {
            var existing          = _database.DocumentsStorage.GetDocumentOrTombstone(context, id, throwOnConflict: false);
            var existingDoc       = existing.Document;
            var existingTombstone = existing.Tombstone;

            if (existingDoc != null)
            {
                var compareResult = DocumentCompare.IsEqualTo(existingDoc.Data, incomingDoc, true);
                if (compareResult == DocumentCompareResult.NotEqual)
                {
                    return(false);
                }

                // no real conflict here, both documents have identical content
                var mergedChangeVector = ChangeVectorUtils.MergeVectors(incomingChangeVector, existingDoc.ChangeVector);
                var nonPersistentFlags = (compareResult & DocumentCompareResult.ShouldRecreateDocument) == DocumentCompareResult.ShouldRecreateDocument
                    ? NonPersistentDocumentFlags.ResolveAttachmentsConflict : NonPersistentDocumentFlags.None;
                _database.DocumentsStorage.Put(context, id, null, incomingDoc, lastModifiedTicks, mergedChangeVector, nonPersistentFlags: nonPersistentFlags);
                return(true);
            }

            if (existingTombstone != null && incomingDoc == null)
            {
                // Conflict between two tombstones resolves to the local tombstone
                existingTombstone.ChangeVector = ChangeVectorUtils.MergeVectors(incomingChangeVector, existingTombstone.ChangeVector);
                using (Slice.External(context.Allocator, existingTombstone.LowerId, out Slice lowerId))
                {
                    _database.DocumentsStorage.ConflictsStorage.DeleteConflicts(context, lowerId, null, existingTombstone.ChangeVector);
                }
                return(true);
            }

            return(false);
        }
Пример #4
0
            protected override long ExecuteCmd(DocumentsOperationContext context)
            {
                for (int i = 0; i < NumberOfCommands; i++)
                {
                    var cmd = Commands[i];

                    Debug.Assert(cmd.Type == CommandType.PUT || cmd.Type == CommandType.Counters || cmd.Type == CommandType.TimeSeries || cmd.Type == CommandType.TimeSeriesBulkInsert || cmd.Type == CommandType.AttachmentPUT);

                    switch (cmd.Type)
                    {
                    case CommandType.PUT:
                        try
                        {
                            if (SkipOverwriteIfUnchanged)
                            {
                                var existingDoc = Database.DocumentsStorage.Get(context, cmd.Id, DocumentFields.Data, throwOnConflict: false);
                                if (existingDoc != null)
                                {
                                    var compareResult = DocumentCompare.IsEqualTo(existingDoc.Data, cmd.Document,
                                                                                  DocumentCompare.DocumentCompareOptions.MergeMetadata);

                                    if (compareResult.HasFlag(DocumentCompareResult.Equal))
                                    {
                                        Debug.Assert(BitOperations.PopCount((ulong)compareResult) == 1 ||
                                                     compareResult.HasFlag(DocumentCompareResult.AttachmentsNotEqual) ||
                                                     compareResult.HasFlag(DocumentCompareResult.CountersNotEqual) ||
                                                     compareResult.HasFlag(DocumentCompareResult.TimeSeriesNotEqual));
                                        continue;
                                    }
                                }
                            }

                            Database.DocumentsStorage.Put(context, cmd.Id, null, cmd.Document);
                        }
                        catch (VoronConcurrencyErrorException)
                        {
                            // RavenDB-10581 - If we have a concurrency error on "doc-id/"
                            // this means that we have existing values under the current etag
                            // we'll generate a new (random) id for them.

                            // The TransactionMerger will re-run us when we ask it to as a
                            // separate transaction

                            for (; i < NumberOfCommands; i++)
                            {
                                cmd = Commands[i];
                                if (cmd.Type != CommandType.PUT)
                                {
                                    continue;
                                }

                                if (cmd.Id?.EndsWith(Database.IdentityPartsSeparator) == true)
                                {
                                    cmd.Id       = MergedPutCommand.GenerateNonConflictingId(Database, cmd.Id);
                                    RetryOnError = true;
                                }
                            }

                            throw;
                        }

                        break;

                    case CommandType.Counters:
                    {
                        var collection = CountersHandler.ExecuteCounterBatchCommand.GetDocumentCollection(cmd.Id, Database, context, fromEtl: false, out _);

                        foreach (var counterOperation in cmd.Counters.Operations)
                        {
                            counterOperation.DocumentId = cmd.Counters.DocumentId;
                            Database.DocumentsStorage.CountersStorage.IncrementCounter(context, cmd.Id, collection, counterOperation.CounterName, counterOperation.Delta, out _);

                            var updates = GetDocumentUpdates(cmd.Id);
                            updates.AddCounter(counterOperation.CounterName);
                        }

                        break;
                    }

                    case CommandType.TimeSeries:
                    case CommandType.TimeSeriesBulkInsert:
                    {
                        var docCollection = TimeSeriesHandler.ExecuteTimeSeriesBatchCommand.GetDocumentCollection(Database, context, cmd.Id, fromEtl: false);
                        Database.DocumentsStorage.TimeSeriesStorage.AppendTimestamp(context,
                                                                                    cmd.Id,
                                                                                    docCollection,
                                                                                    cmd.TimeSeries.Name,
                                                                                    cmd.TimeSeries.Appends
                                                                                    );
                        break;
                    }

                    case CommandType.AttachmentPUT:
                    {
                        using (cmd.AttachmentStream.Stream)
                        {
                            Database.DocumentsStorage.AttachmentsStorage.PutAttachment(context, cmd.Id, cmd.Name,
                                                                                       cmd.ContentType ?? "", cmd.AttachmentStream.Hash, cmd.ChangeVector, cmd.AttachmentStream.Stream, updateDocument: false);
                        }

                        var updates = GetDocumentUpdates(cmd.Id);
                        updates.AddAttachment();

                        break;
                    }
                    }
                }

                if (_documentsToUpdate.Count > 0)
                {
                    foreach (var kvp in _documentsToUpdate)
                    {
                        var documentId = kvp.Key;
                        var updates    = kvp.Value;

                        if (updates.Attachments)
                        {
                            Database.DocumentsStorage.AttachmentsStorage.UpdateDocumentAfterAttachmentChange(context, documentId);
                        }

                        if (updates.Counters != null && updates.Counters.Count > 0)
                        {
                            var docToUpdate = Database.DocumentsStorage.Get(context, documentId);
                            if (docToUpdate != null)
                            {
                                Database.DocumentsStorage.CountersStorage.UpdateDocumentCounters(context, docToUpdate, documentId, updates.Counters, countersToRemove: null, NonPersistentDocumentFlags.ByCountersUpdate);
                            }
                        }
                    }
                }

                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Executed {NumberOfCommands:#,#;;0} bulk insert operations, size: ({new Size(TotalSize, SizeUnit.Bytes)})");
                }

                return(NumberOfCommands);
            }