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")); }