Пример #1
0
        private bool AddReplicationItemToBatch(ReplicationBatchItem item, OutgoingReplicationStatsScope stats, SkippedReplicationItemsInfo skippedReplicationItemsInfo)
        {
            if (item.Type == ReplicationBatchItem.ReplicationItemType.Document ||
                item.Type == ReplicationBatchItem.ReplicationItemType.DocumentTombstone)
            {
                if ((item.Flags & DocumentFlags.Artificial) == DocumentFlags.Artificial)
                {
                    stats.RecordArtificialDocumentSkip();
                    skippedReplicationItemsInfo.Update(item, isArtificial: true);
                    return(false);
                }
            }

            if (item.Flags.Contain(DocumentFlags.Revision) || item.Flags.Contain(DocumentFlags.DeleteRevision))
            {
                // we let pass all the conflicted/resolved revisions, since we keep them with their original change vector which might be `AlreadyMerged` at the destination.
                if (item.Flags.Contain(DocumentFlags.Conflicted) ||
                    item.Flags.Contain(DocumentFlags.Resolved))
                {
                    _orderedReplicaItems.Add(item.Etag, item);
                    return(true);
                }
            }

            // destination already has it
            if ((MissingAttachmentsInLastBatch == false || item.Type != ReplicationBatchItem.ReplicationItemType.Attachment) &&
                ChangeVectorUtils.GetConflictStatus(item.ChangeVector, _parent.LastAcceptedChangeVector) == ConflictStatus.AlreadyMerged)
            {
                stats.RecordChangeVectorSkip();
                skippedReplicationItemsInfo.Update(item);
                return(false);
            }

            if (skippedReplicationItemsInfo.SkippedItems > 0)
            {
                if (_log.IsInfoEnabled)
                {
                    var message = skippedReplicationItemsInfo.GetInfoForDebug(_parent.LastAcceptedChangeVector);
                    _log.Info(message);
                }

                skippedReplicationItemsInfo.Reset();
            }

            if (item.Type == ReplicationBatchItem.ReplicationItemType.Attachment)
            {
                _replicaAttachmentStreams[item.Base64Hash] = item;
            }

            Debug.Assert(item.Flags.Contain(DocumentFlags.Artificial) == false);
            _orderedReplicaItems.Add(item.Etag, item);
            return(true);
        }
Пример #2
0
        private bool AddReplicationItemToBatch(ReplicationBatchItem item, OutgoingReplicationStatsScope stats, SkippedReplicationItemsInfo skippedReplicationItemsInfo)
        {
            if (item.Type == ReplicationBatchItem.ReplicationItemType.Document ||
                item.Type == ReplicationBatchItem.ReplicationItemType.DocumentTombstone)
            {
                if ((item.Flags & DocumentFlags.Artificial) == DocumentFlags.Artificial)
                {
                    stats.RecordArtificialDocumentSkip();
                    skippedReplicationItemsInfo.Update(item, isArtificial: true);
                    return(false);
                }
            }


            if (item.Type == ReplicationBatchItem.ReplicationItemType.CounterTombstone &&
                _parent.SupportedFeatures.Replication.Counters == false)
            {
                // skip counter tombstones in legacy mode
                skippedReplicationItemsInfo.Update(item);
                return(false);
            }

            // destination already has it
            if ((MissingAttachmentsInLastBatch == false || item.Type != ReplicationBatchItem.ReplicationItemType.Attachment) &&
                ChangeVectorUtils.GetConflictStatus(item.ChangeVector, _parent.LastAcceptedChangeVector) == ConflictStatus.AlreadyMerged)
            {
                stats.RecordChangeVectorSkip();
                skippedReplicationItemsInfo.Update(item);
                return(false);
            }

            if (skippedReplicationItemsInfo.SkippedItems > 0)
            {
                if (_log.IsInfoEnabled)
                {
                    var message = skippedReplicationItemsInfo.GetInfoForDebug(_parent.LastAcceptedChangeVector);
                    _log.Info(message);
                }
                skippedReplicationItemsInfo.Reset();
            }

            if (item.Type == ReplicationBatchItem.ReplicationItemType.Attachment)
            {
                _replicaAttachmentStreams[item.Base64Hash] = item;
            }

            Debug.Assert(item.Flags.Contain(DocumentFlags.Artificial) == false);
            _orderedReplicaItems.Add(item.Etag, item);
            return(true);
        }
Пример #3
0
        private unsafe bool AddReplicationItemToBatch(ReplicationBatchItem item, OutgoingReplicationStatsScope stats)
        {
            if (item.Type == ReplicationBatchItem.ReplicationItemType.Document ||
                item.Type == ReplicationBatchItem.ReplicationItemType.DocumentTombstone)
            {
                if ((item.Flags & DocumentFlags.Artificial) == DocumentFlags.Artificial)
                {
                    stats.RecordArtificialDocumentSkip();

                    if (_log.IsInfoEnabled)
                    {
                        _log.Info($"Skipping replication of {item.Id} because it is an artificial document");
                    }
                    return(false);
                }

                if (CollectionName.IsSystemDocument(item.Id.Buffer, item.Id.Size, out bool isHiLo) && isHiLo == false)
                {
                    stats.RecordSystemDocumentSkip();

                    if (_log.IsInfoEnabled)
                    {
                        _log.Info($"Skipping replication of {item.Id} because it is a system document");
                    }
                    return(false);
                }
            }

            // destination already has it
            if (ChangeVectorUtils.GetConflictStatus(item.ChangeVector, _parent.LastAcceptedChangeVector) == ConflictStatus.AlreadyMerged)
            {
                stats.RecordChangeVectorSkip();

                if (_log.IsInfoEnabled)
                {
                    _log.Info($"Skipping replication of {item.Type} '{item.Id}' because destination has a higher change vector. Current: {item.ChangeVector} < Destination: {_parent._destinationLastKnownChangeVectorAsString} ");
                }
                return(false);
            }

            if (item.Type == ReplicationBatchItem.ReplicationItemType.Attachment)
            {
                _replicaAttachmentStreams[item.Base64Hash] = item;
            }

            Debug.Assert(item.Flags.HasFlag(DocumentFlags.Artificial) == false);
            _orderedReplicaItems.Add(item.Etag, item);
            return(true);
        }
Пример #4
0
        private bool ShouldSkip(ReplicationBatchItem item, OutgoingReplicationStatsScope stats, SkippedReplicationItemsInfo skippedReplicationItemsInfo)
        {
            switch (item)
            {
            case DocumentReplicationItem doc:
                if (doc.Flags.Contain(DocumentFlags.Artificial))
                {
                    stats.RecordArtificialDocumentSkip();
                    skippedReplicationItemsInfo.Update(item, isArtificial: true);
                    return(true);
                }

                if (doc.Flags.Contain(DocumentFlags.Revision) || doc.Flags.Contain(DocumentFlags.DeleteRevision))
                {
                    // we let pass all the conflicted/resolved revisions, since we keep them with their original change vector which might be `AlreadyMerged` at the destination.
                    if (doc.Flags.Contain(DocumentFlags.Conflicted) ||
                        doc.Flags.Contain(DocumentFlags.Resolved))
                    {
                        return(false);
                    }
                }

                break;

            case AttachmentReplicationItem _:
                if (MissingAttachmentsInLastBatch)
                {
                    return(false);
                }
                break;
            }

            // destination already has it
            if (ChangeVectorUtils.GetConflictStatus(item.ChangeVector, _parent.LastAcceptedChangeVector) == ConflictStatus.AlreadyMerged)
            {
                stats.RecordChangeVectorSkip();
                skippedReplicationItemsInfo.Update(item);
                return(true);
            }

            return(false);
        }
Пример #5
0
        private bool ShouldSkip(ReplicationBatchItem item, OutgoingReplicationStatsScope stats, SkippedReplicationItemsInfo skippedReplicationItemsInfo)
        {
            if (ValidatorSaysToSkip(_pathsToSend) || ValidatorSaysToSkip(_destinationAcceptablePaths))
            {
                return(true);
            }

            switch (item)
            {
            case DocumentReplicationItem doc:
                if (doc.Flags.Contain(DocumentFlags.Artificial))
                {
                    stats.RecordArtificialDocumentSkip();
                    skippedReplicationItemsInfo.Update(item, isArtificial: true);
                    return(true);
                }

                if (doc.Flags.Contain(DocumentFlags.Revision) || doc.Flags.Contain(DocumentFlags.DeleteRevision))
                {
                    // we let pass all the conflicted/resolved revisions, since we keep them with their original change vector which might be `AlreadyMerged` at the destination.
                    if (doc.Flags.Contain(DocumentFlags.Conflicted) ||
                        doc.Flags.Contain(DocumentFlags.Resolved) ||
                        (doc.Flags.Contain(DocumentFlags.FromClusterTransaction)))
                    {
                        return(false);
                    }
                }

                break;

            case AttachmentReplicationItem _:
                if (MissingAttachmentsInLastBatch)
                {
                    return(false);
                }
                break;
            }

            // destination already has it
            if (_parent._database.DocumentsStorage.GetConflictStatus(item.ChangeVector, _parent.LastAcceptedChangeVector) == ConflictStatus.AlreadyMerged)
            {
                stats.RecordChangeVectorSkip();
                skippedReplicationItemsInfo.Update(item);
                return(true);
            }

            return(false);

            bool ValidatorSaysToSkip(AllowedPathsValidator validator)
            {
                if (validator == null)
                {
                    return(false);
                }

                if (validator.ShouldAllow(item))
                {
                    return(false);
                }

                stats.RecordArtificialDocumentSkip();
                skippedReplicationItemsInfo.Update(item);

                if (_log.IsInfoEnabled)
                {
                    string key = validator.GetItemInformation(item);
                    _log.Info($"Will skip sending {key} ({item.Type}) because it was not allowed according to the incoming .");
                }

                return(true);
            }
        }