private void OnRead(UvStreamHandle handle, int status) { if (status == 0) { // A zero status does not indicate an error or connection end. It indicates // there is no data to be read right now. // See the note at http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb. // We need to clean up whatever was allocated by OnAlloc. _inputBuffer.FlushAsync(); return; } var normalRead = status > 0; var normalDone = status == EOF; var errorDone = !(normalDone || normalRead); var readCount = normalRead ? status : 0; if (!normalRead) { handle.ReadStop(); } IOException error = null; if (errorDone) { Exception uvError; handle.Libuv.Check(status, out uvError); error = new IOException(uvError.Message, uvError); // REVIEW: Should we treat ECONNRESET as an error? // Ignore the error for now _input.CompleteWriter(); } else if (readCount == 0 || _input.Writing.IsCompleted) { _input.CompleteWriter(); } else { _inputBuffer.Advance(readCount); var task = _inputBuffer.FlushAsync(); if (!task.IsCompleted) { // If there's back pressure handle.ReadStop(); // Resume reading when task continues task.ContinueWith((t, state) => ((UvTcpConnection)state).StartReading(), this); } } }
public void ByteByByteTest() { WritableBuffer writableBuffer = default; for (int i = 1; i <= 1024 * 1024; i++) { writableBuffer = _pipe.Writer.Alloc(100); writableBuffer.Advance(1); writableBuffer.Commit(); Assert.Equal(i, _pipe.Length); } writableBuffer.FlushAsync(); for (int i = 1024 * 1024 - 1; i >= 0; i--) { var result = _pipe.Reader.ReadAsync().GetResult(); var consumed = result.Buffer.Slice(1).Start; Assert.Equal(i + 1, result.Buffer.Length); _pipe.Reader.Advance(consumed, consumed); Assert.Equal(i, _pipe.Length); } }
private byte[] Read() { _buffer.FlushAsync().GetAwaiter().GetResult(); var readResult = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var data = readResult.Buffer.ToArray(); _pipe.Reader.Advance(readResult.Buffer.End); return(data); }
public static void RunSingleSegmentParser(int numberOfRequests, int concurrentConnections, byte[] requestPayload, WriteResponseDelegate writeResponse) { var factory = new PipeFactory(); var listener = new FakeListener(factory, concurrentConnections); listener.OnConnection(async connection => { while (true) { // Wait for data var result = await connection.Input.ReadAsync(); ReadableBuffer input = result.Buffer; try { if (input.IsEmpty && result.IsCompleted) { // No more data break; } var requestBuffer = input.First; if (requestBuffer.Length != 492) { continue; } // Parse the input http request WritableBuffer output = WriteResponse(writeResponse, connection, requestBuffer); await output.FlushAsync(); } catch (Exception e) { var istr = new Utf8String(input.First.Span).ToString(); Debug.WriteLine(e.Message); } finally { // Consume the input connection.Input.Advance(input.End, input.End); } } }); var tasks = new Task[numberOfRequests]; for (int i = 0; i < numberOfRequests; i++) { tasks[i] = listener.ExecuteRequestAsync(requestPayload); } Task.WaitAll(tasks); listener.Dispose(); factory.Dispose(); }
private Task FlushAsync(WritableBuffer writableBuffer, long bytesWritten, CancellationToken cancellationToken) { var awaitable = writableBuffer.FlushAsync(cancellationToken); if (awaitable.IsCompleted) { // The flush task can't fail today return(Task.CompletedTask); } return(FlushAsyncAwaited(awaitable, bytesWritten, cancellationToken)); }
private static void RunServerForNode() { UvThread uvThread = new UvThread(); var ip = IPAddress.Any; UvTcpListener listener = new UvTcpListener(uvThread, new IPEndPoint(ip, port)); listener.OnConnection(async connection => { Interlocked.Increment(ref connectionCounter); var input = connection.Input; var output = connection.Output; var flag = false; //Used for stop sending info to connected client. await Task.Factory.StartNew(async() => { //Wait for client disconnection. var result = await input.ReadAsync(); flag = true; }); while (!flag) { try { WritableBuffer oBuffer = output.Alloc(); oBuffer.WriteUtf8String(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss:ms")); await oBuffer.FlushAsync(); Interlocked.Increment(ref sendCounter); await Task.Delay(r.Next(0, 500)); } catch (Exception e) { break; } } }); listener.Start(); var pid = System.Diagnostics.Process.GetCurrentProcess().Id; Console.WriteLine($"Listening on {ip} on port {port} / PID {pid}"); Console.ReadKey(); listener.Stop(); uvThread.Dispose(); }
public void Complete(int status, long requestCorrelation, uint bytesTransferred) { // Receives if (requestCorrelation >= 0) { if (bytesTransferred == 0 || _input.ReaderCompleted.IsCompleted) { _input.CompleteWriting(); } else { _buffer.CommitBytes((int)bytesTransferred); _buffer.FlushAsync(); ProcessReceives(); } } else { SendCompleting(requestCorrelation); } }
/// <summary> /// Sends a command and it's parameters to the Stream. /// </summary> /// <param name="connection">The connection to the Redis Server.</param> /// <param name="command">The command.</param> /// <param name="parameters">The paramaters for the command.</param> public static async Task WriteCommandAsync(this RedisConnection connection, string command, IEnumerable <object> parameters = null) { if (command == null) { throw new ArgumentNullException(nameof(command)); } if (connection == null) { throw new ArgumentNullException(nameof(connection)); } var sizeOfCommandArray = 1 + (parameters?.Count() ?? 0); WritableBuffer output = connection.Output.Alloc(); // output the command array start output.Write(RedisProtocol.Utf8ArrayStart); output.Append(sizeOfCommandArray, TextEncoder.Utf8); output.Write(RedisProtocol.Utf8CRLF); // output the command var commandData = (Utf8String)command; WriteRedisBulkString(output, commandData); if (sizeOfCommandArray > 1) { foreach (object obj in parameters) { WriteObject(output, obj); } } await output.FlushAsync(); // TODO: should I call this? // connection.Output.Complete(); }
private async Task ReceiveFromSocketAndPushToWriterAsync() { SocketAsyncEventArgs args = null; try { // wait for someone to be interested in data before we // start allocating buffers and probing the socket args = GetOrCreateSocketAsyncEventArgs(); while (!_stopping) { bool haveWriteBuffer = false; WritableBuffer buffer = default(WritableBuffer); var initialSegment = default(ArraySegment <byte>); try { int bytesFromInitialDataBuffer = 0; if (Socket.Available == 0) { // now, this gets a bit messy unfortunately, because support for the ideal option // (zero-length reads) is platform dependent switch (_bufferStyle) { case BufferStyle.Unknown: try { initialSegment = await ReceiveInitialDataUnknownStrategyAsync(args); } catch { initialSegment = default(ArraySegment <byte>); } if (initialSegment.Array == null) { continue; // redo from start } break; case BufferStyle.UseZeroLengthBuffer: // if we already have a buffer, use that (but: zero count); otherwise use a shared // zero-length; this avoids constantly changing the buffer that the args use, which // avoids some overheads args.SetBuffer(args.Buffer ?? _zeroLengthBuffer, 0, 0); // await async for the io work to be completed await Socket.ReceiveSignalAsync(args); break; case BufferStyle.UseSmallBuffer: // We need to do a speculative receive with a *cheap* buffer while we wait for input; it would be *nice* if // we could do a zero-length receive, but this is not supported equally on all platforms (fine on Windows, but // linux hates it). The key aim here is to make sure that we don't tie up an entire block from the memory pool // waiting for input on a socket; fine for 1 socket, not so fine for 100,000 sockets // do a short receive while we wait (async) for data initialSegment = LeaseSmallBuffer(); args.SetBuffer(initialSegment.Array, initialSegment.Offset, initialSegment.Count); // await async for the io work to be completed await Socket.ReceiveSignalAsync(args); break; } if (args.SocketError != SocketError.Success) { throw new SocketException((int)args.SocketError); } // note we can't check BytesTransferred <= 0, as we always // expect 0; but if we returned, we expect data to be // buffered *on the socket*, else EOF if ((bytesFromInitialDataBuffer = args.BytesTransferred) <= 0) { if (ReferenceEquals(initialSegment.Array, _zeroLengthBuffer)) { // sentinel value that means we should just // consume sync (we expect there to be data) initialSegment = default(ArraySegment <byte>); } else { // socket reported EOF RecycleSmallBuffer(ref initialSegment); } if (Socket.Available == 0) { // yup, definitely an EOF break; } } } // note that we will try to coalesce things here to reduce the number of flushes; we // certainly want to coalesce the initial buffer (from the speculative receive) with the initial // data, but we probably don't want to buffer indefinitely; for now, it will buffer up to 4 pages // before flushing (entirely arbitrarily) - might want to make this configurable later buffer = _input.Writer.Alloc(SmallBufferSize * 2); haveWriteBuffer = true; const int FlushInputEveryBytes = 4 * MemoryPool.MaxPooledBlockLength; if (initialSegment.Array != null) { // need to account for anything that we got in the speculative receive if (bytesFromInitialDataBuffer != 0) { buffer.Write(new Span <byte>(initialSegment.Array, initialSegment.Offset, bytesFromInitialDataBuffer)); } // make the small buffer available to other consumers RecycleSmallBuffer(ref initialSegment); } bool isEOF = false; while (Socket.Available != 0 && buffer.BytesWritten < FlushInputEveryBytes) { buffer.Ensure(); // ask for *something*, then use whatever is available (usually much much more) SetBuffer(buffer.Buffer, args); // await async for the io work to be completed await Socket.ReceiveSignalAsync(args); // either way, need to validate if (args.SocketError != SocketError.Success) { throw new SocketException((int)args.SocketError); } int len = args.BytesTransferred; if (len <= 0) { // socket reported EOF isEOF = true; break; } // record what data we filled into the buffer buffer.Advance(len); } if (isEOF) { break; } } finally { RecycleSmallBuffer(ref initialSegment); if (haveWriteBuffer) { _stopping = (await buffer.FlushAsync()).IsCompleted; } } } _input.Writer.Complete(); } catch (Exception ex) { // don't trust signal after an error; someone else could // still have it and invoke Set if (args != null) { args.UserToken = null; } _input?.Writer.Complete(ex); } finally { try { Socket.Shutdown(SocketShutdown.Receive); } catch { } RecycleSocketAsyncEventArgs(args); } }
public async Task FlushAsync() { await _writableBuffer.FlushAsync(); _needAlloc = true; }
public WritableBufferAwaitable FlushAsync() => _innerBuffer.FlushAsync();
public void ReceiveEndComplete() { _buffer.FlushAsync(); }
public async Task FlushAsync(WritableBuffer buffer) { await buffer.FlushAsync(); }