public static ReplicationBatchItem From(Tombstone doc) { var item = new ReplicationBatchItem { Etag = doc.Etag, Id = doc.LowerId, TransactionMarker = doc.TransactionMarker, ChangeVector = doc.ChangeVector }; switch (doc.Type) { case Tombstone.TombstoneType.Document: item.Type = ReplicationItemType.DocumentTombstone; item.Collection = doc.Collection; item.Flags = doc.Flags; item.LastModifiedTicks = doc.LastModified.Ticks; break; case Tombstone.TombstoneType.Attachment: item.Type = ReplicationItemType.AttachmentTombstone; break; case Tombstone.TombstoneType.Revision: item.Type = ReplicationItemType.RevisionTombstone; item.Collection = doc.Collection; break; default: throw new ArgumentOutOfRangeException(nameof(doc.Type)); } return(item); }
private void DisposeReplicationItem(ReplicationBatchItem item) { if (item.Type == ReplicationBatchItem.ReplicationItemType.Attachment) { item.Stream.Dispose(); } else { item.Data?.Dispose(); //item.Value.Data is null if tombstone } }
public string GetItemInformation(ReplicationBatchItem item) { return(item switch { AttachmentReplicationItem a => "Attachment for " + GetDocumentId(a.Key), AttachmentTombstoneReplicationItem at => "Attachment tombstone for: " + GetDocumentId(at.Key), CounterReplicationItem c => "Counter for " + c.Id, DocumentReplicationItem d => "Document " + d.Id, RevisionTombstoneReplicationItem r => "Revision for: " + r.Id, TimeSeriesDeletedRangeItem td => "Time Series deletion range for: " + GetDocumentId(td.Key), TimeSeriesReplicationItem t => "Time Series for: " + GetDocumentId(t.Key), _ => throw new ArgumentOutOfRangeException($"{nameof(item)} - {item}") });
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); }
private void AssertNoLegacyReplicationViolation(ReplicationBatchItem item) { if (_parent.SupportedFeatures.Replication.CountersBatch == false) { AssertNotCounterForLegacyReplication(item); } if (_parent.SupportedFeatures.Replication.ClusterTransaction == false) { AssertNotClusterTransactionDocumentForLegacyReplication(item); } if (_parent.SupportedFeatures.Replication.TimeSeries == false) { AssertNotTimeSeriesForLegacyReplication(item); } }
private void AssertNotIncrementalTimeSeriesForLegacyReplication(ReplicationBatchItem item) { if (item.Type == ReplicationBatchItem.ReplicationItemType.TimeSeriesSegment || item.Type == ReplicationBatchItem.ReplicationItemType.DeletedTimeSeriesRange) { using (_parent._database.DocumentsStorage.ContextPool.AllocateOperationContext(out JsonOperationContext context)) { LazyStringValue name; switch (item) { case TimeSeriesDeletedRangeItem timeSeriesDeletedRangeItem: TimeSeriesValuesSegment.ParseTimeSeriesKey(timeSeriesDeletedRangeItem.Key, context, out _, out name); break; case TimeSeriesReplicationItem timeSeriesReplicationItem: name = timeSeriesReplicationItem.Name; break; default: return; } if (TimeSeriesHandler.CheckIfIncrementalTs(name) == false) { return; } } // the other side doesn't support incremental time series, stopping replication var message = $"{_parent.Node.FromString()} found an item of type 'IncrementalTimeSeries' to replicate to {_parent.Destination.FromString()}, " + $"while we are in legacy mode (downgraded our replication version to match the destination). " + $"Can't send Incremental-TimeSeries in legacy mode, destination {_parent.Destination.FromString()} does not support Incremental-TimeSeries feature. Stopping replication."; if (_log.IsInfoEnabled) { _log.Info(message); } throw new LegacyReplicationViolationException(message); } }