예제 #1
0
        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);
            }
        }
예제 #2
0
        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);
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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));
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
                }
            }
        }
예제 #7
0
        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>();
        }
예제 #8
0
        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);
        }
예제 #9
0
        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));
        }
예제 #10
0
        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));
        }
예제 #11
0
 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
 }
예제 #12
0
        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);
            }
        }