private bool Initialized(object message) { void OnGetReplicationProgresses() { ReadReplicationProgresses().PipeTo(Sender, success: data => new GetReplicationProgressesSuccess(data), failure: cause => new GetReplicationProgressesFailure(cause)); } void OnGetReplicationProgress(string sourceLogId) { var version = clock.VersionVector; ReadReplicationProgress(sourceLogId).PipeTo(Sender, success: data => new GetReplicationProgressSuccess(sourceLogId, data, version), failure: cause => new GetReplicationProgressFailure(cause)); } void OnSetReplicationProgress(SetReplicationProgress m) { WriteReplicationProgresses(ImmutableDictionary <string, long> .Empty.Add(m.SourceLogId, m.ReplicationProgress)) .PipeTo(Sender, success: () => new SetReplicationProgressSuccess(m.SourceLogId, m.ReplicationProgress), failure: cause => new SetReplicationProgressFailure(cause)); } void OnReplay(Replay replay) { if (replay.AggregateId is null) { if (!(replay.Subscriber is null)) { registry = registry.RegisterDefaultSubscriber(replay.Subscriber); } var from = replay.FromSequenceNr; var iid = replay.InstanceId; Read(AdjustFromSequenceNr(from), clock.SequenceNr, replay.Max) .PipeTo(Sender, success: data => new ReplaySuccess(data.Events, data.To, iid), failure: cause => new ReplayFailure(cause, from, iid)); } else { var emitterAggregateId = replay.AggregateId; if (!(replay.Subscriber is null)) { registry = registry.RegisterAggregateSubscriber(replay.Subscriber, emitterAggregateId); } var from = replay.FromSequenceNr; var iid = replay.InstanceId; Read(AdjustFromSequenceNr(from), clock.SequenceNr, replay.Max, emitterAggregateId) .PipeTo(Sender, success: data => new ReplaySuccess(data.Events, data.To, iid), failure: cause => new ReplayFailure(cause, from, iid)); } } void OnReplicationRead(ReplicationRead read) { if (!(channel is null)) { channel.Tell(read); } var from = read.FromSequenceNr; var targetLogId = read.TargetLogId; remoteReplicationProgress = remoteReplicationProgress.SetItem(targetLogId, Math.Max(0, from - 1)); ReplicationRead(from, clock.SequenceNr, read.Max, read.ScanLimit, e => e.IsReplicable(read.CurrentTargetVersionVector, read.Filter)) .PipeTo(Self, Sender, success: data => new ReplicationReadSuccess(data.Events.ToArray(), from, data.To, targetLogId, null), failure: cause => new ReplicationReadFailure(new ReplicationReadSourceException(cause.Message), targetLogId)); } void OnReplicationReadSuccess(ReplicationReadSuccess success) { // Post-exclude events using a possibly updated version vector received from the // target. This is an optimization to save network bandwidth. If omitted, events // are still excluded at target based on the current local version vector at the // target (for correctness). var targetLogId = success.TargetLogId; var currentTargetVersionVector = this.replicaVersionVectors.GetValueOrDefault(targetLogId, VectorTime.Zero); var updated = new List <DurableEvent>(success.Events.Count); foreach (var e in success.Events) { if (!e.IsBefore(currentTargetVersionVector)) { updated.Add(e); } } var reply = new ReplicationReadSuccess(updated, success.FromSequenceNr, success.ReplicationProgress, success.TargetLogId, clock.VersionVector); Sender.Tell(reply); if (!(channel is null)) { channel.Tell(reply); } LogFilterStatistics("source", success.Events, updated); } void OnReplicationReadFailure(ReplicationReadFailure failure) { Sender.Tell(failure); if (!(channel is null)) { channel.Tell(failure); } } void OnDelete(Delete delete) { var actualDeletedToSeqNr = Math.Max(Math.Min(delete.ToSequenceNr, clock.SequenceNr), deletionMetadata.ToSequenceNr); if (actualDeletedToSeqNr > deletionMetadata.ToSequenceNr) { var updatedDeletionMetadata = new DeletionMetadata(actualDeletedToSeqNr, delete.RemoteLogIds); WriteDeletionMetadata(updatedDeletionMetadata).PipeTo(Self, Sender, success: () => new DeleteSuccess(updatedDeletionMetadata.ToSequenceNr, updatedDeletionMetadata.RemoteLogIds), failure: cause => new DeleteFailure(cause)); } } void OnDeleteSuccess(DeleteSuccess success) { this.deletionMetadata = new DeletionMetadata(success.DeletedTo, success.RemoteLogIds ?? ImmutableHashSet <string> .Empty); Self.Tell(new PhysicalDelete()); Sender.Tell(success); } void OnPhysicalDelete() { if (!physicalDeletionRunning) { // Becomes Long.MaxValue in case of an empty-set to indicate that all event are replicated as required var replicatedSeqNr = deletionMetadata.RemoteLogIds.IsEmpty ? long.MaxValue : deletionMetadata.RemoteLogIds.Select(id => remoteReplicationProgress.GetValueOrDefault(id, 0)).Min(); var deleteTo = Math.Min(deletionMetadata.ToSequenceNr, replicatedSeqNr); physicalDeletionRunning = true; Delete(deleteTo).PipeTo(Self, success: data => new PhysicalDeleteSuccess(data), failure: cause => new PhysicalDeleteFailure(cause)); } } void OnPhysicalDeleteSuccess(long deletedTo) { physicalDeletionRunning = false; if (deletionMetadata.ToSequenceNr > deletedTo) { scheduler.ScheduleTellOnce(Settings.DeletionRetryDelay, Self, new PhysicalDelete(), Self); } } void OnPhysicalDeleteFailure(Exception cause) { if (!(cause is PhysicalDeletionNotSupportedException)) { var delay = Settings.DeletionRetryDelay; Logger.Error(cause, "Physical deletion of events failed. Retry in {0}", delay); physicalDeletionRunning = false; scheduler.ScheduleTellOnce(delay, Self, new PhysicalDelete(), Self); } } void OnLoadSnapshot(LoadSnapshot load) { var emitterId = load.EmitterId; var iid = load.InstanceId; SnapshotStore.Load(emitterId).PipeTo(Sender, success: data => new LoadSnapshotSuccess(data, iid), failure: cause => new LoadSnapshotFailure(cause, iid)); } void OnSaveSnapshot(SaveSnapshot save) { var snapshot = save.Snapshot; var iid = save.InstanceId; SnapshotStore.Save(snapshot).PipeTo(Sender, save.Initiator, success: () => new SaveSnapshotSuccess(snapshot.Metadata, iid), failure: cause => new SaveSnapshotFailure(snapshot.Metadata, cause, iid)); } void OnDeleteSnapshots(long lowerSequenceNr) { SnapshotStore.Delete(lowerSequenceNr).PipeTo(Sender, success: () => new DeleteSnapshotsSuccess(), failure: cause => new DeleteSnapshotsFailure(cause)); } void OnAdjustEventLogClock() { clock = clock.AdjustSequenceNrToProcessTime(Id); WriteEventLogClockSnapshot(clock).PipeTo(Sender, success: () => new AdjustEventLogClockSuccess(clock), failure: cause => new AdjustEventLogClockFailure(cause)); } void OnWriteBatchesSuccess(WriteBatchesSuccess success) { this.clock = success.Clock; foreach (var write in success.UpdatedWrites) { write.ReplyTo.Tell(new WriteSuccess(write.Events, write.CorrelationId, write.InstanceId), write.Initiator); registry.NotifySubscribers(write.Events, s => !s.Equals(write.ReplyTo)); } if (!(channel is null)) { channel.Tell(new NotificationChannel.Updated(success.UpdatedEvents)); } } void OnWriteBatchesFailure(WriteBatchesFailure failure) { foreach (var write in failure.Writes) { write.ReplyTo.Tell(new WriteFailure(write.Events, failure.Cause, write.CorrelationId, write.InstanceId), write.Initiator); } } void OnWriteReplicatedBatchesSuccess(WriteReplicatedBatchesSuccess success) { this.clock = success.Clock; foreach (var w in success.UpdatedWrites) { var builder = ImmutableDictionary.CreateBuilder <string, ReplicationMetadata>(); foreach (var(k, v) in w.Metadata) { builder[k] = v.WithVersionVector(success.Clock.VersionVector); } var ws = new ReplicationWriteSuccess(w.Events, builder.ToImmutable(), w.ContinueReplication); registry.NotifySubscribers(w.Events); if (!(channel is null)) { channel.Tell(w); } // Write failure of replication progress can be ignored. Using a stale // progress to resume replication will redundantly read events from a // source log but these events will be successfully identified as // duplicates, either at source or latest at target. WriteReplicationProgresses(w.ReplicationProgresses.ToImmutableDictionary()).PipeTo(w.ReplyTo, success: () => ws, failure: cause => { Logger.Warning("Writing of replication progress failed: {0}", cause); return(new ReplicationWriteFailure(cause)); }); } if (!(channel is null)) { channel.Tell(new NotificationChannel.Updated(success.UpdatedEvents)); } } void OnWriteReplicatedBatchesFailure(WriteReplicatedBatchesFailure failure) { foreach (var write in failure.Writes) { write.ReplyTo.Tell(new ReplicationWriteFailure(failure.Cause)); } } switch (message) { case GetEventLogClock _: Sender.Tell(new GetEventLogClockSuccess(this.clock)); return(true); case GetReplicationProgresses _: OnGetReplicationProgresses(); return(true); case GetReplicationProgress _: OnGetReplicationProgress(((GetReplicationProgress)message).SourceLogId); return(true); case SetReplicationProgress _: OnSetReplicationProgress((SetReplicationProgress)message); return(true); case Replay _: OnReplay((Replay)message); return(true); case ReplicationRead _: OnReplicationRead((ReplicationRead)message); return(true); case ReplicationReadSuccess _: OnReplicationReadSuccess((ReplicationReadSuccess)message); return(true); case ReplicationReadFailure _: OnReplicationReadFailure((ReplicationReadFailure)message); return(true); case Write _: ProcessWrites(((Write)message).WithReplyToDefault(Sender)); return(true); case WriteMany _: ProcessWrites(((WriteMany)message).Writes.ToArray()); Sender.Tell(WriteManyComplete.Instance); return(true); case WriteBatchesSuccess _: OnWriteBatchesSuccess((WriteBatchesSuccess)message); return(true); case WriteBatchesFailure _: OnWriteBatchesFailure((WriteBatchesFailure)message); return(true); case ReplicationWrite _: ProcessReplicationWrites(((ReplicationWrite)message).WithReplyToDefault(Sender)); return(true); case WriteReplicatedBatchesSuccess _: OnWriteReplicatedBatchesSuccess((WriteReplicatedBatchesSuccess)message); return(true); case WriteReplicatedBatchesFailure _: OnWriteReplicatedBatchesFailure((WriteReplicatedBatchesFailure)message); return(true); case ReplicationWriteMany _: ProcessReplicationWrites(((ReplicationWriteMany)message).Writes.ToArray()); Sender.Tell(new ReplicationWriteManyComplete()); return(true); case Delete _: OnDelete((Delete)message); return(true); case DeleteSuccess _: OnDeleteSuccess((DeleteSuccess)message); return(true); case DeleteFailure _: Sender.Tell(message); return(true); case PhysicalDelete _: OnPhysicalDelete(); return(true); case PhysicalDeleteSuccess _: OnPhysicalDeleteSuccess(((PhysicalDeleteSuccess)message).DeletedTo); return(true); case PhysicalDeleteFailure _: OnPhysicalDeleteFailure(((PhysicalDeleteFailure)message).Cause); return(true); case LoadSnapshot _: OnLoadSnapshot((LoadSnapshot)message); return(true); case SaveSnapshot _: OnSaveSnapshot((SaveSnapshot)message); return(true); case DeleteSnapshots _: OnDeleteSnapshots(((DeleteSnapshots)message).LowerSequenceNr); return(true); case AdjustEventLogClock _: OnAdjustEventLogClock(); return(true); case Terminated _: registry = registry.UnregisterSubscriber(((Terminated)message).ActorRef); return(true); default: return(false); } }
public async Task Delete(Guid aggregateId) { await SnapshotStore.Delete(aggregateId); // Todo: Delete events? }