/// <summary> /// Return 'true' if at least one request has been processed, 'false' otherwise. /// </summary> public bool HandleRequest() { if (!_inbox.CanPeek) { return(false); } var next = _inbox.Peek().Span; try { var message = new Message(next); var kind = message.Header.MessageKind; var mask = message.Header.ClientId.Mask; Span <byte> response; switch (kind) { case MessageKind.OpenBlock: response = OpenBlock(new OpenBlockRequest(message.Span, mask)).Span; break; case MessageKind.GetBlockHandle: response = GetBlockHandle(new GetBlockHandleRequest(message.Span, mask)).Span; break; case MessageKind.CommitBlock: response = CommitBlock(new CommitBlockRequest(message.Span, mask)).Span; break; case MessageKind.GetBlockInfo: response = GetBlockInfo(new GetBlockInfoRequest(message.Span, mask)); break; default: throw new NotSupportedException(); } while (!_outbox.TryWrite(response)) { _log?.Log(LogSeverity.Warning, $"ChainController can't write the response to {kind}."); // Pathological situation, we don't want to overflow the logger. Thread.Sleep(1000); } } finally { _pool.Reset(); _inbox.Next(); } return(true); }
/// <remarks> /// Returned <paramref name="value"/> is valid till next call to /// TryGet. /// </remarks> public bool TryGet(T key, out Span <byte> value) { _pool.Reset(); // clear previous Get result and free some space. var keySpan = MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref key, 1)); using (var tx = _env.BeginTransaction(TransactionBeginFlags.ReadOnly)) using (var db = tx.OpenDatabase(_dbName)) { bool result = tx.TryGet(db, keySpan, out var valueSpan); if (result) { value = GetSpan(valueSpan.Length); valueSpan.CopyTo(value); } else { value = Span <byte> .Empty; } return(result); } }
public bool HandleResponse() { if (!_outbox.CanPeek) { return(false); } var next = _outbox.Peek().Span; try { var message = new Message(next); var kind = message.Header.MessageKind; // Remove client ID from message message.Header.ClientId = default; if (_requestsInProgress >= ResponseBatchSize || _responseCountInPool > 0) { var nextResponse = _responsePool.GetSpan(next.Length); next.CopyTo(nextResponse); _responseCountInPool++; if (_responseCountInPool >= ResponseBatchSize) { _socket.Send(_responsePool.Allocated()); _responsePool.Reset(); _responseCountInPool = 0; } } else { _socket.Send(next); } Interlocked.Decrement(ref _requestsInProgress); // Some responses trigger the termination of the controller. if (kind == MessageKind.CloseConnectionResponse || kind == MessageKind.ProtocolErrorResponse) { if (kind == MessageKind.ProtocolErrorResponse) { var protocolResponse = new ProtocolErrorResponse(next); _log?.Log(LogSeverity.Info, $"ConnectionController({ClientId}) on protocol error {protocolResponse.Status}."); } if (_responseCountInPool > 0) { _socket.Send(_responsePool.Allocated()); _responsePool.Reset(); _responseCountInPool = 0; } _tokenSource.Cancel(); } } finally { _outbox.Next(); } return(true); }