Esempio n. 1
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);
        }
Esempio n. 2
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);
        }
Esempio n. 3
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);
                }
            }
        }
Esempio n. 4
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);
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// To be called when a new leader event is delivered. This method needs to be called when using the
        /// <seealso cref="EgressAdapter"/> or <seealso cref="EgressPoller"/> rather than <seealso cref="#pollEgress()"/> method.
        /// </summary>
        /// <param name="clusterSessionId"> which must match <seealso cref="#clusterSessionId()"/>. </param>
        /// <param name="leaderMemberId">   which has become the new leader. </param>
        /// <param name="memberEndpoints">  comma separated list of cluster members endpoints to connect to with the leader first. </param>
        public void OnNewLeader(long clusterSessionId, int leaderMemberId, string memberEndpoints)
        {
            if (clusterSessionId != _clusterSessionId)
            {
                throw new ClusterException("invalid clusterSessionId=" + clusterSessionId + " expected " +
                                           _clusterSessionId);
            }

            _leaderMemberId = leaderMemberId;

            if (_isUnicast)
            {
                _publication?.Dispose();
                _fragmentAssembler.Clear();
                UpdateMemberEndpoints(memberEndpoints);

                ChannelUri channelUri = ChannelUri.Parse(_ctx.IngressChannel());
                channelUri.Put(Aeron.Aeron.Context.ENDPOINT_PARAM_NAME, _endpointByMemberIdMap[leaderMemberId]);
                _publication = AddIngressPublication(channelUri.ToString(), _ctx.IngressStreamId());
            }
        }
Esempio n. 6
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);
    }
Esempio n. 7
0
        private Publication ConnectToCluster()
        {
            Publication publication     = null;
            string      ingressChannel  = _ctx.IngressChannel();
            int         ingressStreamId = _ctx.IngressStreamId();
            long        deadlineNs      = _nanoClock.NanoTime() + _ctx.MessageTimeoutNs();

            if (_isUnicast)
            {
                ChannelUri    channelUri   = ChannelUri.Parse(ingressChannel);
                int           memberCount  = _endpointByMemberIdMap.Count;
                Publication[] publications = new Publication[memberCount];

                foreach (var entry in _endpointByMemberIdMap)
                {
                    channelUri.Put(Aeron.Aeron.Context.ENDPOINT_PARAM_NAME, entry.Value);
                    string channel = channelUri.ToString();
                    publications[entry.Key] = AddIngressPublication(channel, ingressStreamId);
                }

                int connectedIndex = -1;
                while (true)
                {
                    for (int i = 0; i < memberCount; i++)
                    {
                        if (publications[i].IsConnected)
                        {
                            connectedIndex = i;
                            break;
                        }
                    }

                    if (-1 != connectedIndex)
                    {
                        for (int i = 0; i < memberCount; i++)
                        {
                            if (i == connectedIndex)
                            {
                                publication = publications[i];
                            }
                            else
                            {
                                publications[i]?.Dispose();
                            }
                        }

                        break;
                    }

                    if (_nanoClock.NanoTime() > deadlineNs)
                    {
                        for (int i = 0; i < memberCount; i++)
                        {
                            CloseHelper.QuietDispose(publications[i]);
                        }

                        throw new TimeoutException("awaiting connection to cluster");
                    }

                    _idleStrategy.Idle();
                }
            }
            else
            {
                publication = AddIngressPublication(ingressChannel, ingressStreamId);

                _idleStrategy.Reset();
                while (!publication.IsConnected)
                {
                    if (_nanoClock.NanoTime() > deadlineNs)
                    {
                        CloseHelper.QuietDispose(publication);

                        throw new TimeoutException("awaiting connection to cluster");
                    }

                    _idleStrategy.Idle();
                }
            }

            return(publication);
        }