示例#1
0
        private void OnTakeSnapshot(long termPosition)
        {
            long   recordingId;
            string channel  = ctx.SnapshotChannel();
            int    streamId = ctx.SnapshotStreamId();

            using (AeronArchive archive = AeronArchive.Connect(archiveCtx))
                using (Publication publication = archive.AddRecordedExclusivePublication(channel, streamId))
                {
                    try
                    {
                        CountersReader counters  = aeron.CountersReader();
                        int            counterId = AwaitRecordingCounter(publication, counters);

                        recordingId = RecordingPos.GetRecordingId(counters, counterId);
                        SnapshotState(publication, termBaseLogPosition + termPosition);
                        service.OnTakeSnapshot(publication);

                        AwaitRecordingComplete(recordingId, publication.Position, counters, counterId, archive);
                    }
                    finally
                    {
                        archive.StopRecording(publication);
                    }
                }

            recordingLog.AppendSnapshot(recordingId, leadershipTermId, termBaseLogPosition, termPosition, timestampMs);
        }
示例#2
0
        /// <summary>
        /// Create a <seealso cref="ReplayMerge"/> to manage the merging of a replayed stream and switching to live stream as
        /// appropriate.
        /// </summary>
        /// <param name="subscription"> to use for the replay and live stream. Must be a multi-destination subscription. </param>
        /// <param name="archive"> to use for the replay. </param>
        /// <param name="replayChannel"> to use for the replay. </param>
        /// <param name="replayDestination"> to send the replay to and the destination added by the <seealso cref="Subscription"/>. </param>
        /// <param name="liveDestination"> for the live stream and the destination added by the <seealso cref="Subscription"/>. </param>
        /// <param name="recordingId"> for the replay. </param>
        /// <param name="startPosition"> for the replay. </param>
        public ReplayMerge(Subscription subscription, AeronArchive archive, string replayChannel,
                           string replayDestination, string liveDestination, long recordingId, long startPosition)
        {
            var subscriptionChannelUri = ChannelUri.Parse(subscription.Channel);

            if (!Context.MDC_CONTROL_MODE_MANUAL.Equals(subscriptionChannelUri.Get(Context.MDC_CONTROL_MODE_PARAM_NAME))
                )
            {
                throw new ArgumentException("Subscription channel must be manual control mode: mode=" +
                                            subscriptionChannelUri.Get(Context.MDC_CONTROL_MODE_PARAM_NAME)
                                            );
            }

            this.archive               = archive;
            this.subscription          = subscription;
            this.replayDestination     = replayDestination;
            this.replayChannel         = replayChannel;
            this.liveDestination       = liveDestination;
            this.recordingId           = recordingId;
            this.startPosition         = startPosition;
            this.liveAddThreshold      = LIVE_ADD_THRESHOLD;
            this.replayRemoveThreshold = REPLAY_REMOVE_THRESHOLD;

            subscription.AddDestination(replayDestination);
        }
示例#3
0
 private static void GetRecordingExtent(AeronArchive archive, RecordingExtent recordingExtent, Entry entry)
 {
     if (archive.ListRecording(entry.recordingId, recordingExtent) == 0)
     {
         throw new InvalidOperationException("Unknown recording id: " + entry.recordingId);
     }
 }
示例#4
0
        private long OnTakeSnapshot(long logPosition, long leadershipTermId)
        {
            long recordingId;

            using (AeronArchive archive = AeronArchive.Connect(archiveCtx))
                using (Publication publication = aeron.AddExclusivePublication(ctx.SnapshotChannel(), ctx.SnapshotStreamId()))
                {
                    var  channel        = ChannelUri.AddSessionId(ctx.SnapshotChannel(), publication.SessionId);
                    long subscriptionId = archive.StartRecording(channel, ctx.SnapshotStreamId(), SourceLocation.LOCAL);

                    try
                    {
                        CountersReader counters  = aeron.CountersReader();
                        int            counterId = AwaitRecordingCounter(publication.SessionId, counters);

                        recordingId = RecordingPos.GetRecordingId(counters, counterId);
                        SnapshotState(publication, logPosition, leadershipTermId);
                        service.OnTakeSnapshot(publication);

                        AwaitRecordingComplete(recordingId, publication.Position, counters, counterId, archive);
                    }
                    finally
                    {
                        archive.StopRecording(subscriptionId);
                    }
                }

            return(recordingId);
        }
示例#5
0
        /// <summary>
        /// Create a recovery plan for the cluster that when the steps are replayed will bring the cluster back to the
        /// latest stable state.
        /// </summary>
        /// <param name="archive"> to lookup recording descriptors. </param>
        /// <returns> a new <seealso cref="RecoveryPlan"/> for the cluster. </returns>
        public virtual RecoveryPlan CreateRecoveryPlan(AeronArchive archive)
        {
            var steps = new List <ReplayStep>();

            var snapshotStep = PlanRecovery(steps, entries, archive);

            long lastLeadershipTermId      = -1;
            long lastLogPosition           = 0;
            long lastTermPositionCommitted = -1;
            long lastTermPositionAppended  = 0;

            if (null != snapshotStep)
            {
                lastLeadershipTermId      = snapshotStep.entry.leadershipTermId;
                lastLogPosition           = snapshotStep.entry.logPosition;
                lastTermPositionCommitted = snapshotStep.entry.termPosition;
                lastTermPositionAppended  = lastTermPositionCommitted;
            }

            int size = steps.Count;

            if (size > 0)
            {
                ReplayStep replayStep = steps[size - 1];
                Entry      entry      = replayStep.entry;

                lastLeadershipTermId      = entry.leadershipTermId;
                lastLogPosition           = entry.logPosition;
                lastTermPositionCommitted = entry.termPosition;
                lastTermPositionAppended  = replayStep.recordingStopPosition;
            }

            return(new RecoveryPlan(lastLeadershipTermId, lastLogPosition, lastTermPositionCommitted, lastTermPositionAppended, snapshotStep, steps));
        }
示例#6
0
        private void LoadSnapshot(long recordingId)
        {
            using (AeronArchive archive = AeronArchive.Connect(archiveCtx))
            {
                RecordingExtent recordingExtent = new RecordingExtent();
                if (0 == archive.ListRecording(recordingId, recordingExtent))
                {
                    throw new System.InvalidOperationException("Could not find recordingId: " + recordingId);
                }

                string channel  = ctx.ReplayChannel();
                int    streamId = ctx.ReplayStreamId();

                long length    = recordingExtent.stopPosition - recordingExtent.startPosition;
                int  sessionId = (int)archive.StartReplay(recordingId, 0, length, channel, streamId);

                string replaySessionChannel = ChannelUri.AddSessionId(channel, sessionId);
                using (Subscription subscription = aeron.AddSubscription(replaySessionChannel, streamId))
                {
                    Image image = AwaitImage(sessionId, subscription);
                    LoadState(image);
                    service.OnLoadSnapshot(image);
                }
            }
        }
示例#7
0
        private void LoadSnapshot(long recordingId)
        {
            using (AeronArchive archive = AeronArchive.Connect(archiveCtx))
            {
                string channel   = ctx.ReplayChannel();
                int    streamId  = ctx.ReplayStreamId();
                int    sessionId = (int)archive.StartReplay(recordingId, 0, AeronArchive.NULL_LENGTH, channel, streamId);

                string replaySessionChannel = ChannelUri.AddSessionId(channel, sessionId);
                using (Subscription subscription = aeron.AddSubscription(replaySessionChannel, streamId))
                {
                    Image image = AwaitImage(sessionId, subscription);
                    LoadState(image);
                    service.OnLoadSnapshot(image);
                }
            }
        }
示例#8
0
        private static bool PollForResponse(AeronArchive archive, long correlationId)
        {
            ControlResponsePoller poller = archive.ControlResponsePoller();

            if (poller.Poll() > 0 && poller.IsPollComplete())
            {
                if (poller.ControlSessionId() == archive.ControlSessionId() && poller.CorrelationId() == correlationId)
                {
                    if (poller.Code() == ControlResponseCode.ERROR)
                    {
                        throw new ArchiveException("archive response for correlationId=" + correlationId +
                                                   ", error: " + poller.ErrorMessage(), (int)poller.RelevantId());
                    }

                    return(true);
                }
            }

            return(false);
        }
示例#9
0
        private void AwaitRecordingComplete(
            long recordingId,
            long completePosition,
            CountersReader counters,
            int counterId,
            AeronArchive archive)
        {
            idleStrategy.Reset();
            do
            {
                idleStrategy.Idle();
                CheckInterruptedStatus();

                if (!RecordingPos.IsActive(counters, counterId, recordingId))
                {
                    throw new InvalidOperationException("recording has stopped unexpectedly: " + recordingId);
                }

                archive.CheckForErrorResponse();
            } while (counters.GetCounterValue(counterId) < completePosition);
        }
示例#10
0
    /// <summary>
    /// Create a <seealso cref="ReplayMerge"/> to manage the merging of a replayed stream and switching over to live stream as
    /// appropriate.
    /// </summary>
    /// <param name="subscription">           to use for the replay and live stream. Must be a multi-destination subscription. </param>
    /// <param name="archive">                to use for the replay. </param>
    /// <param name="replayChannel">          to use for the replay. </param>
    /// <param name="replayDestination">      to send the replay to and the destination added by the <seealso cref="Subscription"/>. </param>
    /// <param name="liveDestination">        for the live stream and the destination added by the <seealso cref="Subscription"/>. </param>
    /// <param name="recordingId">            for the replay. </param>
    /// <param name="startPosition">          for the replay. </param>
    /// <param name="epochClock">             to use for progress checks. </param>
    /// <param name="mergeProgressTimeoutMs"> to use for progress checks. </param>
    public ReplayMerge(Subscription subscription, AeronArchive archive, string replayChannel, string replayDestination,
                       string liveDestination, long recordingId, long startPosition, IEpochClock epochClock,
                       long mergeProgressTimeoutMs)
    {
        if (subscription.Channel.StartsWith(IPC_CHANNEL) || replayChannel.StartsWith(IPC_CHANNEL) ||
            replayDestination.StartsWith(IPC_CHANNEL) || liveDestination.StartsWith(IPC_CHANNEL))
        {
            throw new System.ArgumentException("IPC merging is not supported");
        }

        ChannelUri subscriptionChannelUri = ChannelUri.Parse(subscription.Channel);

        if (!MDC_CONTROL_MODE_MANUAL.Equals(subscriptionChannelUri.Get(MDC_CONTROL_MODE_PARAM_NAME)))
        {
            throw new ArgumentException("Subscription must have manual control-mode: control-mode=" +
                                        subscriptionChannelUri.Get(MDC_CONTROL_MODE_PARAM_NAME));
        }

        ChannelUri replayChannelUri = ChannelUri.Parse(replayChannel);

        replayChannelUri.Put(LINGER_PARAM_NAME, "0");
        replayChannelUri.Put(EOS_PARAM_NAME, "false");

        this.archive                = archive;
        this.subscription           = subscription;
        this.epochClock             = epochClock;
        this.replayDestination      = replayDestination;
        this.replayChannel          = replayChannelUri.ToString();
        this.liveDestination        = liveDestination;
        this.recordingId            = recordingId;
        this.startPosition          = startPosition;
        this.timeOfLastProgressMs   = epochClock.Time();
        this.mergeProgressTimeoutMs = mergeProgressTimeoutMs;

        subscription.AsyncAddDestination(replayDestination);
    }
示例#11
0
 private static long PolledRelevantId(AeronArchive archive)
 {
     return(archive.ControlResponsePoller().RelevantId());
 }
示例#12
0
        internal static ReplayStep PlanRecovery(List <ReplayStep> steps, List <Entry> entries, AeronArchive archive)
        {
            if (entries.Count == 0)
            {
                return(null);
            }

            int snapshotIndex = -1;

            for (int i = entries.Count - 1; i >= 0; i--)
            {
                Entry entry = entries[i];
                if (ENTRY_TYPE_SNAPSHOT == entry.type)
                {
                    snapshotIndex = i;
                }
            }

            ReplayStep      snapshotStep;
            RecordingExtent recordingExtent = new RecordingExtent();

            if (-1 != snapshotIndex)
            {
                Entry snapshot = entries[snapshotIndex];
                GetRecordingExtent(archive, recordingExtent, snapshot);

                snapshotStep = new ReplayStep(recordingExtent.startPosition, recordingExtent.stopPosition, snapshot);

                if (snapshotIndex - 1 >= 0)
                {
                    for (int i = snapshotIndex - 1; i >= 0; i--)
                    {
                        Entry entry = entries[i];
                        if (ENTRY_TYPE_TERM == entry.type)
                        {
                            GetRecordingExtent(archive, recordingExtent, snapshot);
                            long snapshotPosition = snapshot.logPosition + snapshot.termPosition;

                            if (recordingExtent.stopPosition == AeronArchive.NULL_POSITION ||
                                (entry.logPosition + recordingExtent.stopPosition) > snapshotPosition)
                            {
                                steps.Add(new ReplayStep(snapshot.termPosition, recordingExtent.stopPosition, entry));
                            }

                            break;
                        }
                    }
                }
            }
            else
            {
                snapshotStep = null;
            }

            for (int i = snapshotIndex + 1, length = entries.Count; i < length; i++)
            {
                Entry entry = entries[i];
                GetRecordingExtent(archive, recordingExtent, entry);

                steps.Add(new ReplayStep(recordingExtent.startPosition, recordingExtent.stopPosition, entry));
            }

            return(snapshotStep);
        }
示例#13
0
 /// <summary>
 /// Create a <seealso cref="ReplayMerge"/> to manage the merging of a replayed stream and switching over to live stream as
 /// appropriate.
 /// </summary>
 /// <param name="subscription">      to use for the replay and live stream. Must be a multi-destination subscription. </param>
 /// <param name="archive">           to use for the replay. </param>
 /// <param name="replayChannel">     to use for the replay. </param>
 /// <param name="replayDestination"> to send the replay to and the destination added by the <seealso cref="Subscription"/>. </param>
 /// <param name="liveDestination">   for the live stream and the destination added by the <seealso cref="Subscription"/>. </param>
 /// <param name="recordingId">       for the replay. </param>
 /// <param name="startPosition">     for the replay. </param>
 public ReplayMerge(Subscription subscription, AeronArchive archive, string replayChannel, string replayDestination,
                    string liveDestination, long recordingId, long startPosition) : this(subscription, archive, replayChannel,
                                                                                         replayDestination, liveDestination, recordingId, startPosition,
                                                                                         archive.Ctx().AeronClient().Ctx.EpochClock(), MERGE_PROGRESS_TIMEOUT_DEFAULT_MS)
 {
 }