private IEnumerable <IODispatcherAsync.Step> PerformStartReader(Guid epochId)
        {
            yield return
                (_ioDispatcher.BeginUpdateStreamAcl(
                     _cancellationScope,
                     ProjectionNamesBuilder.BuildControlStreamName(epochId),
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new StreamMetadata(maxAge: ProjectionNamesBuilder.ControlStreamMaxAge),
                     completed => { }));

            yield return
                (_ioDispatcher.BeginUpdateStreamAcl(
                     _cancellationScope,
                     ProjectionNamesBuilder._projectionsMasterStream,
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new StreamMetadata(maxAge: ProjectionNamesBuilder.MasterStreamMaxAge),
                     completed => { }));

            ClientMessage.WriteEventsCompleted writeResult = null;
            yield return
                (_ioDispatcher.BeginWriteEvents(
                     _cancellationScope,
                     ProjectionNamesBuilder._projectionsMasterStream,
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new[] { new Event(Guid.NewGuid(), "$response-reader-starting", true, "{}", null) },
                     completed => writeResult = completed));

            if (writeResult.Result != OperationResult.Success)
            {
                throw new Exception("Cannot start response reader. Write result: " + writeResult.Result);
            }

            _readFrom = writeResult.LastEventNumber;

            yield return
                (_ioDispatcher.BeginWriteEvents(
                     _cancellationScope,
                     ProjectionNamesBuilder.BuildControlStreamName(epochId),
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new[] { new Event(Guid.NewGuid(), "$response-reader-started", true, "{}", null) },
                     completed => writeResult = completed));

            if (writeResult.Result != OperationResult.Success)
            {
                throw new Exception("Cannot start response reader. Write result: " + writeResult.Result);
            }

            Log.Debug(
                "PROJECTIONS: Finished Starting Projection Manager Response Reader (reads from $projections-$master)");

            ReadForward();
        }
        private IEnumerable <IODispatcherAsync.Step> StartReaderSteps()
        {
            yield return
                (_ioDispatcher.BeginUpdateStreamAcl(
                     _cancellationScope,
                     _streamId,
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new StreamMetadata(maxAge: ProjectionNamesBuilder.SlaveProjectionControlStreamMaxAge),
                     completed => { }));

            long @from = 0;

            while (!_stopped)
            {
                var eof           = false;
                var subscribeFrom = default(TFPos);
                do
                {
                    yield return
                        (_ioDispatcher.BeginReadForward(
                             _cancellationScope,
                             _streamId,
                             @from,
                             10,
                             false,
                             SystemAccount.Principal,
                             completed => {
                        if (completed.Result == ReadStreamResult.Success ||
                            completed.Result == ReadStreamResult.NoStream)
                        {
                            @from = completed.NextEventNumber == -1 ? 0 : completed.NextEventNumber;
                            eof = completed.IsEndOfStream;
                            // subscribeFrom is only used if eof
                            subscribeFrom = new TFPos(
                                completed.TfLastCommitPosition,
                                completed.TfLastCommitPosition);
                            if (completed.Result == ReadStreamResult.Success)
                            {
                                foreach (var e in completed.Events)
                                {
                                    PublishCommand(e);
                                }
                            }
                        }
                    },
                             () => Log.Warn("Read forward of stream {stream} timed out. Retrying", _streamId)));
                } while (!eof);

                _lastAwakeCorrelationId = Guid.NewGuid();
                yield return
                    (_ioDispatcher.BeginSubscribeAwake(_cancellationScope, _streamId, subscribeFrom, message => { },
                                                       _lastAwakeCorrelationId)
                    );
            }

            // unlikely we can ever get here, but still possible - do nothing
        }
        private IEnumerable <IODispatcherAsync.Step> StartCoreSteps()
        {
            var coreControlStreamID = "$projections-$" + _coreServiceId;

            DebugLogger.Log("Writing ACL to {0}", coreControlStreamID);
            yield return
                (_ioDispatcher.BeginUpdateStreamAcl(
                     _cancellationScope,
                     coreControlStreamID,
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new StreamMetadata(maxAge: ProjectionNamesBuilder.CoreControlStreamMaxAge),
                     completed => { }));

            DebugLogger.Log("ACL write completed to {0}", coreControlStreamID);
            var from = 0;

            while (!_stopped)
            {
                var eof           = false;
                var subscribeFrom = default(TFPos);
                do
                {
                    DebugLogger.Log("Reading core control stream: {0}", coreControlStreamID);
                    yield return
                        (_ioDispatcher.BeginReadForward(
                             _cancellationScope,
                             coreControlStreamID,
                             @from,
                             10,
                             false,
                             SystemAccount.Principal,
                             completed =>
                    {
                        DebugLogger.Log("Core control stream read completed {0}: {1}", coreControlStreamID, completed.Result);
                        @from = completed.NextEventNumber == -1 ? 0 : completed.NextEventNumber;
                        eof = completed.IsEndOfStream;
                        // subscribeFrom is only used if eof
                        subscribeFrom = new TFPos(
                            completed.TfLastCommitPosition,
                            completed.TfLastCommitPosition);
                        foreach (var e in completed.Events)
                        {
                            PublishCommand(e);
                        }
                    }));
                } while (!eof);
                DebugLogger.Log("Awaiting core control stream: {0}", coreControlStreamID);
                yield return
                    (_ioDispatcher.BeginSubscribeAwake(_cancellationScope, coreControlStreamID, subscribeFrom, message => { }));

                DebugLogger.Log("Core control stream await complted: {0}", coreControlStreamID);
            }
        }
        private IEnumerable <IODispatcherAsync.Step> StartCoreSteps(
            ProjectionCoreServiceMessage.StartCore startCoreMessage)
        {
            var coreControlStreamID = "$projections-$" + _coreServiceId;

            yield return
                (_ioDispatcher.BeginUpdateStreamAcl(
                     _cancellationScope,
                     coreControlStreamID,
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new StreamMetadata(maxAge: ProjectionNamesBuilder.CoreControlStreamMaxAge),
                     completed => { }));

            ClientMessage.ReadStreamEventsBackwardCompleted readResult = null;
            bool success = false;

            while (!success)
            {
                yield return
                    (_ioDispatcher.BeginReadBackward(
                         _cancellationScope,
                         coreControlStreamID,
                         -1,
                         1,
                         false,
                         SystemAccount.Principal,
                         completed => {
                    readResult = completed;
                    success = true;
                },
                         () => Log.Warn("Read backward of stream {stream} timed out. Retrying", coreControlStreamID)));
            }

            long from = 0;

            if (readResult.Result == ReadStreamResult.NoStream)
            {
                from = 0;
            }
            else
            {
                if (readResult.Result != ReadStreamResult.Success)
                {
                    throw new Exception("Cannot start control reader. Read result: " + readResult.Result);
                }

                from = readResult.LastEventNumber + 1;
            }

            Log.Debug(
                "PROJECTIONS: Finished Starting Projection Core Reader (reads from $projections-${coreServiceId})",
                _coreServiceId);
            _publisher.Publish(
                new ProjectionCoreServiceMessage.SubComponentStarted(
                    SubComponentName, startCoreMessage.InstanceCorrelationId));

            ControlSteps(startCoreMessage.InstanceCorrelationId).Run();

            while (!_stopped)
            {
                var eof           = false;
                var subscribeFrom = default(TFPos);
                do
                {
                    yield return
                        (_ioDispatcher.BeginReadForward(
                             _cancellationScope,
                             coreControlStreamID,
                             @from,
                             10,
                             false,
                             SystemAccount.Principal,
                             completed => {
                        @from = completed.NextEventNumber == -1 ? 0 : completed.NextEventNumber;
                        eof = completed.IsEndOfStream;
                        // subscribeFrom is only used if eof
                        subscribeFrom = new TFPos(
                            completed.TfLastCommitPosition,
                            completed.TfLastCommitPosition);
                        foreach (var e in completed.Events)
                        {
                            PublishCommand(e);
                        }
                    },
                             () => Log.Warn("Read forward of stream {stream} timed out. Retrying", coreControlStreamID)));
                } while (!eof);

                yield return
                    (_ioDispatcher.BeginSubscribeAwake(_cancellationScope, coreControlStreamID, subscribeFrom,
                                                       message => { }));
            }
        }
        private IEnumerable <IODispatcherAsync.Step> PerformStartReader()
        {
            yield return
                (_ioDispatcher.BeginUpdateStreamAcl(
                     _cancellationScope,
                     ProjectionNamesBuilder._projectionsControlStream,
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new StreamMetadata(maxAge: ProjectionNamesBuilder.ControlStreamMaxAge),
                     completed => { }));

            yield return
                (_ioDispatcher.BeginUpdateStreamAcl(
                     _cancellationScope,
                     ProjectionNamesBuilder._projectionsMasterStream,
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new StreamMetadata(maxAge: ProjectionNamesBuilder.MastrerStreamMaxAge),
                     completed => { }));

            ClientMessage.WriteEventsCompleted writeResult = null;
            DebugLogger.Log("Writing $response-reader-starting");
            yield return
                (_ioDispatcher.BeginWriteEvents(
                     _cancellationScope,
                     ProjectionNamesBuilder._projectionsMasterStream,
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new[] { new Event(Guid.NewGuid(), "$response-reader-starting", true, "{}", null) },
                     completed => writeResult = completed));

            if (writeResult.Result != OperationResult.Success)
            {
                throw new Exception("Cannot start response reader. Write result: " + writeResult.Result);
            }

            var from = writeResult.LastEventNumber;

            DebugLogger.Log("$response-reader-starting has been written. Starting event number is: " + from);

            _publisher.Publish(new ProjectionManagementMessage.ReaderReady());

            DebugLogger.Log("Writing $response-reader-started");
            yield return
                (_ioDispatcher.BeginWriteEvents(
                     _cancellationScope,
                     ProjectionNamesBuilder._projectionsControlStream,
                     ExpectedVersion.Any,
                     SystemAccount.Principal,
                     new[] { new Event(Guid.NewGuid(), "$response-reader-started", true, "{}", null) },
                     completed => writeResult = completed));

            if (writeResult.Result != OperationResult.Success)
            {
                throw new Exception("Cannot start response reader. Write result: " + writeResult.Result);
            }

            DebugLogger.Log("$response-reader-started has been written");

            while (true)
            {
                var eof           = false;
                var subscribeFrom = default(TFPos);
                do
                {
                    DebugLogger.Log("Reading " + ProjectionNamesBuilder._projectionsMasterStream);
                    yield return
                        (_ioDispatcher.BeginReadForward(
                             _cancellationScope,
                             ProjectionNamesBuilder._projectionsMasterStream,
                             @from,
                             10,
                             false,
                             SystemAccount.Principal,
                             completed =>
                    {
                        DebugLogger.Log(ProjectionNamesBuilder._projectionsMasterStream + " read completed: " + completed.Result);
                        if (completed.Result == ReadStreamResult.Success ||
                            completed.Result == ReadStreamResult.NoStream)
                        {
                            @from = completed.NextEventNumber == -1 ? 0 : completed.NextEventNumber;
                            eof = completed.IsEndOfStream;
                            // subscribeFrom is only used if eof
                            subscribeFrom = new TFPos(
                                completed.TfLastCommitPosition,
                                completed.TfLastCommitPosition);
                            if (completed.Result == ReadStreamResult.Success)
                            {
                                foreach (var e in completed.Events)
                                {
                                    PublishCommand(e);
                                }
                            }
                        }
                        else
                        {
                            DebugLogger.Log(
                                ProjectionNamesBuilder._projectionsMasterStream + " read completed: "
                                + completed.Result);
                        }
                    }));
                } while (!eof);
                DebugLogger.Log("Awaiting " + ProjectionNamesBuilder._projectionsMasterStream);
                yield return
                    (_ioDispatcher.BeginSubscribeAwake(
                         _cancellationScope,
                         ProjectionNamesBuilder._projectionsMasterStream,
                         subscribeFrom,
                         message => { }));

                DebugLogger.Log(ProjectionNamesBuilder._projectionsMasterStream + " await completed");
            }
        }