public override void Write(IChannelHandlerContext ctx, int allowedBytes)
            {
                int queuedData = _queue.ReadableBytes();

                if (!_endOfStream)
                {
                    if (0u >= (uint)queuedData)
                    {
                        if (_queue.IsEmpty())
                        {
                            // When the queue is empty it means we did clear it because of an error(...) call
                            // (as otherwise we will have at least 1 entry in there), which will happen either when called
                            // explicit or when the write itself fails. In this case just set dataSize and padding to 0
                            // which will signal back that the whole frame was consumed.
                            //
                            // See https://github.com/netty/netty/issues/8707.
                            _padding = _dataSize = 0;
                        }
                        else
                        {
                            // There's no need to write any data frames because there are only empty data frames in the
                            // queue and it is not end of stream yet. Just complete their promises by getting the buffer
                            // corresponding to 0 bytes and writing it to the channel (to preserve notification order).
                            var writePromise0 = ctx.NewPromise();
                            AddListener(writePromise0);
                            _ = ctx.WriteAsync(_queue.Remove(0, writePromise0), writePromise0);
                        }
                        return;
                    }

                    if (0u >= (uint)allowedBytes)
                    {
                        return;
                    }
                }

                // Determine how much data to write.
                int writableData = Math.Min(queuedData, allowedBytes);
                var writePromise = ctx.NewPromise();

                AddListener(writePromise);
                var toWrite = _queue.Remove(writableData, writePromise);

                _dataSize = _queue.ReadableBytes();

                // Determine how much padding to write.
                int writablePadding = Math.Min(allowedBytes - writableData, _padding);

                _padding -= writablePadding;

                // Write the frame(s).
                _ = _owner._frameWriter.WriteDataAsync(ctx, _stream.Id, toWrite, writablePadding,
                                                       _endOfStream && 0u >= (uint)Size, writePromise);
            }
        private void WritabilityChanged0(bool fail)
        {
            //channel.Configuration.SetWriteBufferWaterMark(new WriteBufferWaterMark(3, 4));
            channel.Configuration.WriteBufferLowWaterMark  = 3;
            channel.Configuration.WriteBufferHighWaterMark = 4;
            Assert.True(channel.IsWritable);
            writeQueue.Add(Unpooled.WrappedBuffer(new byte[] { 1, 2, 3 }));
            Assert.True(channel.IsWritable);
            writeQueue.Add(Unpooled.WrappedBuffer(new byte[] { 4, 5 }));
            Assert.False(channel.IsWritable);
            Assert.Equal(5, writeQueue.ReadableBytes());

            if (fail)
            {
                writeQueue.ReleaseAndFailAll(new InvalidOperationException());
            }
            else
            {
                IByteBuffer buffer = writeQueue.RemoveFirst(voidPromise);
                Assert.Equal(1, buffer.ReadByte());
                Assert.Equal(2, buffer.ReadByte());
                Assert.Equal(3, buffer.ReadByte());
                Assert.False(buffer.IsReadable());
                buffer.Release();
                Assert.True(channel.IsWritable);

                buffer = writeQueue.RemoveFirst(voidPromise);
                Assert.Equal(4, buffer.ReadByte());
                Assert.Equal(5, buffer.ReadByte());
                Assert.False(buffer.IsReadable());
                buffer.Release();
            }

            Assert.True(channel.IsWritable);
            Assert.True(writeQueue.IsEmpty());
        }