private void Restore(BootstrapInfo info, IRingBuffer <TransformationItem> transformRing, IRingBuffer <JournalItem> journalRing) { var startingSequence = Math.Min(info.DispatchSequence + 1, info.SnapshotSequence + 1); Log.InfoFormat("Restoring from sequence {0}, will dispatch and will replay messages (this could take some time...).", startingSequence); var replayed = false; foreach (var message in this.store.Load(startingSequence)) { replayed = Replay(info, transformRing, message) || replayed; this.Dispatch(info, journalRing, message); if (message.Sequence % 25000 == 0) { Log.InfoFormat("Pushed message sequence {0} for replay", message.Sequence); } } Log.Info("All journaled messages restored into transformation disruptor; awaiting transformation completion."); if (!replayed) { this.OnComplete(true); } }
public virtual bool Restore(BootstrapInfo info, IDisruptor <JournalItem> journalDisruptor, IRepository repository) { if (info == null) { throw new ArgumentNullException("info"); } if (journalDisruptor == null) { throw new ArgumentNullException("journalDisruptor"); } if (repository == null) { throw new ArgumentNullException("repository"); } using (var disruptor = this.disruptors.CreateStartupTransformationDisruptor(repository, info, this.OnComplete)) { if (disruptor != null) { disruptor.Start(); } var ring = disruptor == null ? null : disruptor.RingBuffer; this.Restore(info, ring, journalDisruptor.RingBuffer); this.mutex.WaitOne(); return(this.success); } }
public bool Start(BootstrapInfo info) { if (this.started) { return(true); } this.started = true; Log.Info("Loading mementos from latest snapshot."); info = this.snapshots.RestoreSnapshots(this.repository, info); if (info == null) { return(this.started = false); } Log.Info("Starting snapshot disruptor."); this.snapshotDisruptor = this.disruptors.CreateSnapshotDisruptor(); this.snapshotDisruptor.Start(); Log.Info("Starting journal disruptor."); this.journalDisruptor = this.disruptors.CreateJournalDisruptor(info); this.journalDisruptor.Start(); Log.Info("Restoring messages from journal."); var restored = this.messages.Restore(info, this.journalDisruptor, this.repository); if (!restored) { return(this.started = false); } Log.InfoFormat("Taking snapshots of hydratables at sequence {0}", info.JournaledSequence); this.snapshots.SaveSnapshot(this.repository, this.snapshotDisruptor.RingBuffer, info); Log.Info("Starting primary transformation disruptor."); this.transformationDisruptor = this.disruptors.CreateTransformationDisruptor(this.repository, info); this.transformationDisruptor.Start(); GC.Collect(2, GCCollectionMode.Forced); Log.Info("Attempting to start message listener."); this.clock = this.timeout.CreateSystemClock(this.transformationDisruptor.RingBuffer); this.clock.Start(); this.listener = this.messaging.CreateMessageListener(this.transformationDisruptor.RingBuffer); this.listener.Start(); Log.Info("Bootstrap process complete; listening for incoming messages."); return(this.started = true); }
public virtual IDisruptor <JournalItem> CreateJournalDisruptor(BootstrapInfo info) { var messageStore = this.persistence.CreateMessageStore(info.SerializedTypes); var messageSender = this.messaging.CreateNewMessageSender(); var checkpointStore = this.persistence.CreateDispatchCheckpointStore(); var disruptor = CreateSingleThreadedDisruptor <JournalItem>(new SleepingWaitStrategy(), 1024 * 16); disruptor.HandleEventsWith(new Phases.Journal.SerializationHandler(CreateOutboundSerializer())) .Then(new JournalHandler(messageStore)) .Then(new AcknowledgmentHandler(), new DispatchHandler(messageSender)) .Then(new DispatchCheckpointHandler(checkpointStore)) .Then(new ClearItemHandler()); this.journalRing = new RingBufferBase <JournalItem>(disruptor.RingBuffer); return(new DisruptorBase <JournalItem>(disruptor)); }
private static bool Replay(BootstrapInfo info, IRingBuffer <TransformationItem> transformRing, JournaledMessage message) { if (message.Sequence <= info.SnapshotSequence) { return(false); } var next = transformRing.Next(); var claimed = transformRing[next]; claimed.AsJournaledMessage(message.Sequence, message.SerializedBody, message.SerializedType, message.SerializedHeaders); transformRing.Publish(next); return(true); }
public virtual BootstrapInfo RestoreSnapshots(IRepository repository, BootstrapInfo info) { if (info == null) { throw new ArgumentNullException("info"); } if (repository == null) { throw new ArgumentNullException("repository"); } if (info.JournaledSequence == 0) { return(info); } using (var reader = this.snapshotFactory.CreateSystemSnapshotStreamReader(info.JournaledSequence)) { if (reader.MessageSequence == 0) { return(info); } if (reader.Count == 0) { return(info.AddSnapshotSequence(reader.MessageSequence)); } Log.InfoFormat( "Restoring {0} mementos from the snapshot at message sequence {1} (this could take some time...).", reader.Count, reader.MessageSequence); using (var disruptor = this.disruptorFactory.CreateBootstrapDisruptor(repository, reader.Count, this.OnComplete)) { Publish(reader, disruptor.Start()); this.mutex.WaitOne(); return(this.success ? info.AddSnapshotSequence(reader.MessageSequence) : null); } } }
static void InstantiateStuff() { info = new BootstrapInfo(42, 24, new string[0], new Collection <Guid>()); info2 = new BootstrapInfo(43, 25, new[] { "blah" }, new Collection <Guid>()); repository = Substitute.For <IRepository>(); disruptors = Substitute.For <DisruptorFactory>(); snapshots = Substitute.For <SnapshotBootstrapper>(); messages = Substitute.For <MessageBootstrapper>(); timeout = Substitute.For <TimeoutFactory>(); messaging = Substitute.For <MessagingFactory>(); systemClock = Substitute.For <SystemClock>(); journalDisruptor = Substitute.For <IDisruptor <JournalItem> >(); snapshotDisruptor = Substitute.For <IDisruptor <SnapshotItem> >(); transformationDisruptor = Substitute.For <IDisruptor <TransformationItem> >(); transformationRingBuffer = Substitute.For <IRingBuffer <TransformationItem> >(); listener = Substitute.For <MessageListener>(); bootstrapper = new Bootstrapper(repository, disruptors, snapshots, messages, timeout, messaging); naps = new List <TimeSpan>(); }
private void Dispatch(BootstrapInfo info, IRingBuffer <JournalItem> journalRing, JournaledMessage message) { if (message.Sequence <= info.DispatchSequence) { return; // already dispatched } if (message.ForeignId != Guid.Empty) { return; // only re-dispatch messages which originated here } if (this.internalTypes.Contains(message.SerializedType)) { return; } var next = journalRing.Next(); var claimed = journalRing[next]; claimed.AsBootstrappedDispatchMessage(message.Sequence, message.SerializedBody, message.SerializedType, message.SerializedHeaders); journalRing.Publish(next); }
public virtual IDisruptor <TransformationItem> CreateStartupTransformationDisruptor(IRepository repository, BootstrapInfo info, Action <bool> complete) { var countdown = info.JournaledSequence - info.SnapshotSequence; if (countdown == 0) { return(null); } var serializerCount = 1; if (countdown > 1024 * 32) { serializerCount++; } if (countdown > 1024 * 512) { serializerCount++; } if (countdown > 1024 * 1024 * 4) { serializerCount++; } var replayTransientTypes = new HashSet <Type>(); var serializers = new SerializationHandler[serializerCount]; for (var i = 0; i < serializerCount; i++) { serializers[i] = new SerializationHandler(this.CreateInboundSerializer(), replayTransientTypes, serializerCount, i); } var transformationHandler = this.CreateTransformationHandler(repository, info.JournaledSequence); var slots = ComputeDisruptorSize(countdown); var disruptor = CreateSingleThreadedDisruptor <TransformationItem>(new SleepingWaitStrategy(), slots); disruptor.HandleEventsWith(serializers.Cast <IEventHandler <TransformationItem> >().ToArray()) .Then(transformationHandler) .Then(new CountdownHandler(countdown, complete)) .Then(new ClearItemHandler()); return(new DisruptorBase <TransformationItem>(disruptor)); }
public virtual IDisruptor <TransformationItem> CreateTransformationDisruptor(IRepository repository, BootstrapInfo info) { var serializationHandler = new SerializationHandler(this.CreateInboundSerializer(), this.transientTypes); var systemSnapshotTracker = new SystemSnapshotTracker(info.JournaledSequence, this.snapshotFrequency, this.snapshotRing, repository); var transformationHandler = this.CreateTransformationHandler(repository, info.JournaledSequence, systemSnapshotTracker); var disruptor = CreateMultithreadedDisruptor <TransformationItem>(new SleepingWaitStrategy(), 1024 * 32); disruptor .HandleEventsWith(serializationHandler) .Then(transformationHandler) .Then(new ClearItemHandler()); return(new DisruptorBase <TransformationItem>(disruptor)); }
public virtual void SaveSnapshot(IRepository repository, IRingBuffer <SnapshotItem> ringBuffer, BootstrapInfo info) { TakePublicSnapshot(repository, ringBuffer); this.TryTakeSystemSnapshot(repository, ringBuffer, info); // this must *always* happen after public snapshots }
private void TryTakeSystemSnapshot(IRepository repository, IRingBuffer <SnapshotItem> ringBuffer, BootstrapInfo info) { if ((info.JournaledSequence - info.SnapshotSequence) <= this.snapshotFrequency) { return; } var items = repository.Items; var remaining = items.Count; foreach (var hydratable in items) { var next = ringBuffer.Next(); var claimed = ringBuffer[next]; claimed.AsPartOfSystemSnapshot(info.JournaledSequence, --remaining, hydratable.Key, hydratable.Memento, hydratable.MementoType); ringBuffer.Publish(next); } }