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); }
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); }
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); }
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); } }