/// <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); }
private int AttemptLiveJoin(long nowMs) { int workCount = 0; if (Aeron.NULL_VALUE == activeCorrelationId) { long correlationId = archive.Ctx().AeronClient().NextCorrelationId(); if (archive.Proxy().GetRecordingPosition(recordingId, correlationId, archive.ControlSessionId())) { activeCorrelationId = correlationId; timeOfLastProgressMs = nowMs; workCount += 1; } } else if (PollForResponse(archive, activeCorrelationId)) { nextTargetPosition = PolledRelevantId(archive); activeCorrelationId = Aeron.NULL_VALUE; if (AeronArchive.NULL_POSITION == nextTargetPosition) { long correlationId = archive.Ctx().AeronClient().NextCorrelationId(); if (archive.Proxy().GetRecordingPosition(recordingId, correlationId, archive.ControlSessionId())) { activeCorrelationId = correlationId; timeOfLastProgressMs = nowMs; } } else { State nextState = State.CATCHUP; if (null != image) { long position = image.Position; if (ShouldAddLiveDestination(position)) { subscription.AsyncAddDestination(liveDestination); timeOfLastProgressMs = nowMs; isLiveAdded = true; } else if (ShouldStopAndRemoveReplay(position)) { subscription.AsyncRemoveDestination(replayDestination); StopReplay(); timeOfLastProgressMs = nowMs; nextState = State.MERGED; } } SetState(nextState); } workCount += 1; } return(workCount); }