void IHandle <StorageMessage.WriteCommit> .Handle(StorageMessage.WriteCommit message)
        {
            Interlocked.Decrement(ref FlushMessagesInQueue);
            try
            {
                var commitPos = Writer.Checkpoint.ReadNonFlushed();
                var result    = ReadIndex.CheckCommitStartingAt(message.TransactionPosition, commitPos);
                switch (result.Decision)
                {
                case CommitDecision.Ok:
                {
                    var commit = WriteCommitWithRetry(LogRecord.Commit(commitPos,
                                                                       message.CorrelationId,
                                                                       message.TransactionPosition,
                                                                       result.CurrentVersion + 1));
                    ReadIndex.Commit(commit);
                    break;
                }

                case CommitDecision.WrongExpectedVersion:
                    message.Envelope.ReplyWith(new StorageMessage.WrongExpectedVersion(message.CorrelationId));
                    break;

                case CommitDecision.Deleted:
                    message.Envelope.ReplyWith(new StorageMessage.StreamDeleted(message.CorrelationId));
                    break;

                case CommitDecision.Idempotent:
                    message.Envelope.ReplyWith(new StorageMessage.AlreadyCommitted(message.CorrelationId,
                                                                                   result.EventStreamId,
                                                                                   result.StartEventNumber,
                                                                                   result.EndEventNumber));
                    break;

                case CommitDecision.CorruptedIdempotency:
                    // in case of corrupted idempotency (part of transaction is ok, other is different)
                    // then we can say that the transaction is not idempotent, so WrongExpectedVersion is ok answer
                    message.Envelope.ReplyWith(new StorageMessage.WrongExpectedVersion(message.CorrelationId));
                    break;

                case CommitDecision.InvalidTransaction:
                    message.Envelope.ReplyWith(new StorageMessage.InvalidTransaction(message.CorrelationId));
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            catch (Exception exc)
            {
                Log.ErrorException(exc, "Exception in writer.");
                throw;
            }
            finally
            {
                Flush();
            }
        }
        private void ChaseTransactionLog()
        {
            _chaser.Open();
            while (!_stop)
            {
                var result = _chaser.TryReadNext();
                if (result.Success)
                {
                    switch (result.LogRecord.RecordType)
                    {
                    case LogRecordType.Prepare:
                    {
                        var record = (PrepareLogRecord)result.LogRecord;

                        if ((record.Flags & PrepareFlags.TransactionBegin) != 0 ||
                            (record.Flags & PrepareFlags.TransactionEnd) != 0)
                        {
                            _masterBus.Publish(new StorageMessage.PrepareAck(record.CorrelationId,
                                                                             record.LogPosition,
                                                                             record.Flags));
                        }

                        break;
                    }

                    case LogRecordType.Commit:
                    {
                        var record = (CommitLogRecord)result.LogRecord;
                        _masterBus.Publish(new StorageMessage.CommitAck(record.CorrelationId,
                                                                        record.TransactionPosition,
                                                                        record.EventNumber));
                        _readIndex.Commit(record);
                        break;
                    }

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }

                if (_watch.ElapsedTicks - _lastFlush >= _flushDelay + 2 * MsPerTick)
                {
                    var start = _watch.ElapsedTicks;
                    _chaser.Flush();
                    _flushDelay = _watch.ElapsedTicks - start;
                    _lastFlush  = _watch.ElapsedTicks;
                }

                if (!result.Success)
                {
                    Thread.Sleep(1);
                }
            }
            _chaser.Close();
            _masterBus.Publish(new SystemMessage.ServiceShutdown("StorageChaser"));
        }