Commit Graph

107 Commits

Author SHA1 Message Date
Norman Maurer
6880e27ce9 [#3463] EpollSocketChannel.localAddress() returns always null if Native.connect() was not able to connect directly
Motivation:

Due a a regression that was introduced by b898bdd we failed to set the localAddress if the connect did not success directly.

Modifications:

Correct set localAddress in doConnect(...)

Result:

Be able to get the localAddress in all cases.
2015-03-04 20:02:37 +01:00
Norman Maurer
f8e158a39f [#3457] Proper fix for IllegalStateException caused by closed file descriptor / channel
Motivation:

During 6b941e9bdb I introduced a regression that could cause an IllegalStateException.
A non-proper fix was commited as part of #3443. This commit add a proper fix.

Modifications:

Remove FileDescriptor.INVALID and add FileDescriptor.isOpen() as replacement. Once FileDescriptor.close() is called isOpen() will return false.

Result:

No more IllegalStateException caused by a close channel.
2015-03-01 19:36:31 +01:00
Norman Maurer
7ae44f8910 [#3066] EpollDatagramChannel never calls fireChannelActive() after connect()
Motivation:

EpollDragramChannel never calls fireChannelActive after connect() which is a bug.

Modifications:

Correctly call fireChannelActive if needed

Result:

Correct behaviour
2015-02-28 15:52:10 +01:00
Norman Maurer
b54857b9a0 Pass struct's per pointer to eliminate memory copy.
Motivation:

Before struct's were passed per value and not pointer. This did enforce a memory copy which is not needed.

Modifications:

- Use "const struct....*" as replacement

Result:

No more unnecessary memory copies
2015-02-27 20:58:03 +01:00
Norman Maurer
6293b0579c Fix byte order when retrieve address from filedescriptor
Motivation:

When create address from filedescriptor we may use incorrect byte order and so end up with an incorrect InetAddress.

Modification:

Not manually shift bytes

Result:

Correct address in all cases.
2015-02-27 20:54:03 +01:00
Norman Maurer
42677f82a6 Fix regression introduced by 20e32f62ec
Motivation:

Because of a regression sometimes accept could produce an IllegalArgumentException

Modifications:

Correctly respect offset when decode port and scope id.

Result:

No more IllegalArgumentException
2015-02-24 11:03:02 +01:00
Norman Maurer
960a486f13 [#3443] Fix IllegalStateException which could be triggered when the channel goes inactive during the eventloop processing
Motivation:

This is a regression that was introduced as part of 6b941e9bdb. The regression could produce an "infinity" triggering of IllegalStateException if a channel goes inactive while process the events for it.

Modifications:

Correctly check if the channel is still active before trigger the callbacks.

Result:

No more IllegalStateException
2015-02-23 19:10:33 +01:00
Norman Maurer
c21067aab6 Directly receive remote address when call accept(...)
Motivation:

There is a small race in the native transport where an accept(...) may success but a later try to obtain the remote address from the fd may fail is the fd is already closed.

Modifications:

Let accept(...) directly set the remote address.

Result:

No more race possible.
2015-02-23 14:54:27 +01:00
Norman Maurer
556a3d5980 Correctly handle autoRead == false when epoll LT is used
Motivation:

When epoll LT is used and autoRead == false when entering epollIn() we need to return without reading any data.

Modifications:

Correctly respect autoRead == false if using epoll LT.

Result:

Consistent and correct behaviour.
2015-02-23 07:38:14 +01:00
Norman Maurer
29a5bc9fb6 [#3438] Throw pre-instanced IOException on connection reset
Motivation:

In the native transport we should throw a pre-instanced IOException on connection reset while reading.

Modifications:

Correctly throw pre-instanced IOException when ECONNRESET is received

Result:

Less overhead on connection reset
2015-02-21 21:31:05 +01:00
Norman Maurer
027d868438 Move generic unix classes/interfaces out of epoll package
Motivation:

As we plan to have other native transports soon (like a kqueue transport) we should move unix classes/interfaces out of the epoll package so we
introduce other implementations without breaking stuff before the next stable release.

Modifications:

Create a new io.netty.channel.unix package and move stuff over there.

Result:

Possible to introduce other native impls beside epoll.
2015-02-17 17:55:12 +01:00
Norman Maurer
9d697d7a9a Allow to create Epoll*Channel from FileDescriptor
Motivation:

Sometimes it's useful to be able to create a Epoll*Channel from an existing file descriptor. This is especially helpful if you integrade some c/jni code.

Modifications:

- Add extra constructor to Epoll*Channel implementations that take a FileDescriptor as an argument
- Make Rename EpollFileDescriptor to NativeFileDescriptor and make it public
- Also ensure we obtain the correct remote/local address when create a Channel from a FileDescriptor

Result:

It's now possible to create a FileDescriptor and instance a Epoll*Channel via it.
2015-02-09 09:56:10 +01:00
Norman Maurer
33f75d3740 Not execute shutdownOutput(...) and close(...) in the EventLoop if SO_LINGER is used.
Motivation:

If SO_LINGER is used shutdownOutput() and close() syscalls will block until either all data was send or until the timeout exceed. This is a problem when we try to execute them on the EventLoop as this means the EventLoop may be blocked and so can not process any other I/O.

Modifications:

- Add AbstractUnsafe.closeExecutor() which returns null by default and use this Executor for close if not null.
- Override the closeExecutor() in NioSocketChannel and EpollSocketChannel and return GlobalEventExecutor.INSTANCE if getSoLinger() > 0
- use closeExecutor() in shutdownInput(...) in NioSocketChannel and EpollSocketChannel

 Result:

No more blocking of the EventLoop if SO_LINGER is used and shutdownOutput() or close() is called.
2015-02-08 20:11:15 +01:00
Norman Maurer
6231113c38 Give compiler hint about inline functions
Motivation:

Some of the methods are frequently called and so should be inlined if possible.

Modifications:

Give the compiler a hint that we want to inline these methods.

Result:

Better performance if inlined.
2015-02-08 13:57:13 +01:00
Norman Maurer
adeb950c91 Cleanup code. Part of [#3398] 2015-02-08 13:04:12 +01:00
Norman Maurer
795de8a590 Add workaround for bug in older linux kernels handling epoll_wait(...)
Motivation:

Older linux kernels have problems handling a large value for epoll_wait(...) and so wait for ever.

Modifications:

Adjust timeout on the fly if a too big value is passed in.

Result:

Correctly works also on older kernels.
2015-02-08 11:35:50 +01:00
Norman Maurer
4d0eeb0dcc Respect ChannelConfig.getWriteSpinCount() when using epoll transport
Motivation:

The writeSpinCount was ignored in the epoll transport and it just kept on trying writing. This could cause unnessary cpu spinning if a slow remote peer was reading the data very very slow.

Modification:

- Correctly take writeSpinCount into account when writing.

Result:

Less cpu spinning when writing to a slow remote peer.
2015-02-08 11:07:46 +01:00
Norman Maurer
3ca6e4bd54 Correctly set EPOLLRDHUP for all stream channels.
Motivation:

Fix regression introduced by 585ce1593f, which missed to set EPOLLRDHUP for all stream channels.

Modifications:

Correctly set EPOLLRDHUP for all stream channels in the AbstractEpollStreamChannel constructor.

Result:

No more test failures in EpollDomain*Channel tests.
2015-02-07 21:29:46 +01:00
Norman Maurer
585ce1593f Faster event processing when epoll transport is used
Motivation:

Before we used a long[] to store the ready events, this had a few problems and limitations:
 - An extra loop was needed to translate between epoll_event and our long
 - JNI may need to do extra memory copy if the JVM not supports pinning
 - More branches

Modifications:

- Introduce a EpollEventArray which allows to directly write in a struct epoll_event* and pass it to epoll_wait.

Result:

Better speed when using native transport, as shown in the benchmark.

Before:
[xxx@xxx wrk]$ ./wrk -H 'Connection: keep-alive' -d 120 -c 256 -t 16 -s scripts/pipeline-many.lua  http://xxx:8080/plaintext
Running 2m test @ http://xxx:8080/plaintext
 16 threads and 256 connections
 Thread Stats   Avg      Stdev     Max   +/- Stdev
   Latency    14.56ms    8.64ms 117.15ms   80.58%
   Req/Sec   286.17k    38.71k  421.48k    68.17%
 546324329 requests in 2.00m, 73.78GB read
Requests/sec: 4553438.39
Transfer/sec:    629.66MB

After:
[xxx@xxx wrk]$ ./wrk -H 'Connection: keep-alive' -d 120 -c 256 -t 16 -s scripts/pipeline-many.lua  http://xxx:8080/plaintext
Running 2m test @ http://xxx:8080/plaintext
 16 threads and 256 connections
 Thread Stats   Avg      Stdev     Max   +/- Stdev
   Latency    14.12ms    8.69ms 100.40ms   83.08%
   Req/Sec   294.79k    40.23k  472.70k    66.75%
 555997226 requests in 2.00m, 75.08GB read
Requests/sec: 4634343.40
Transfer/sec:    640.85MB
2015-02-07 08:22:26 +01:00
Norman Maurer
dd32313fad Allow to change epoll mode
Motivation:
Netty uses edge-triggered epoll by default for performance reasons. The downside here is that a messagesPerRead limit can not be enforced correctly, as we need to consume everything from the channel when notified.

Modification:
- Allow to switch epoll modes before channel is registered
- Some refactoring to share more code

Result:
It's now possible to switch epoll mode.
2015-02-04 21:34:55 +01:00
Norman Maurer
495fa6be3c Allow to recv and send file descriptors when using EpollDomainSocketChannel.
Motiviation:

When using domain sockets on linux it is supported to recv and send file descriptors. This can be used to pass around for example sockets.

Modifications:
- Add support for recv and send file descriptors when using EpollDomainSocketChannel.
- Allow to obtain the file descriptor for an Epoll*Channel so it can be send via domain sockets.

Result:
recv and send of file descriptors is supported now.
2015-02-04 19:59:12 +01:00
Norman Maurer
b898bdda84 Add support for Unix Domain Sockets when using native epoll transport
Motivation:

Using Unix Domain Sockets can be very useful when communication should take place on the same host and has less overhead then using loopback. We should support this with the native epoll transport.

Modifications:

- Add support for Unix Domain Sockets.
- Adjust testsuite to be able to reuse tests.

Result:

Unix Domain Sockets are now support when using native epoll transport.
2015-02-04 15:34:13 +01:00
Norman Maurer
bed3502772 [#3378] Automatically increase number of possible handled events
Motivation:

At the moment the max number of events that can be handled per epoll wakup was set during construction.

Modifications:

- Automatically increase the max number of events to handle

Result:

Better performance when a lot of events need to be handled without adjusting the code.
2015-01-30 06:42:25 +01:00
Norman Maurer
5b30dbef38 [#3377] Faster overflow guard when generate nextId in EpollEventLoop
Motivation:

The current way how the guard against overflow when generating the nextId() is pretty slow once an overflow happened.

Modifications:

Once a possible overflow is detected all ids used by the EpollEventLoop are scrubed and re-assigned to the registered Channels. This way we only need to do extra work each time an overflow is detected.

Result:

More consistent performance even after the first overflow was detected.
2015-01-30 06:18:41 +01:00
Norman Maurer
d79e4ffe07 [#3112] Add supprt for TCP_INFO when using EpollSocketChannel
Motivation:

On Linux, you can gather various metrics using getsockopt(..., TCP_INFO,
...).

Modifications:

Add EpollSocketChannel.tcpInfo() which returns EpollTcpInfo that exposes
all metrics exposed via getsockopt(..., TCP_INFO, ...)

Result:

TCP_INFO support implemented
2015-01-27 07:06:03 +01:00
Norman Maurer
0d58d07bbf Fix NPE when remote address can not be obtained
Motivation:

In the native transport we use getpeername to obtain the remote address from the file descriptor. This may fail for various reasons in which case NULL is returned.

Modifications:

- Check for null when try to obtain remote / local address

Result:

No more NPE
2015-01-26 10:42:41 +01:00
Trustin Lee
4b6b4b511c Fix duplicate channelReadComplete() in EpollDatagramChannel 2014-12-31 19:13:27 +09:00
Trustin Lee
63536c3d73 Fire channelReadComplete() in EpollDatagramChannel
Related: #3274

Motivation:

channelReadComplete() event is not triggered after reading successfully
in EpollDatagramChannel.

Modifications:

- Trigger exceptionCaught() event for read failure only once for less
  noise
- Trigger channelReadComplete() event at the end of the read.

Result:

Fix #3274
2014-12-31 17:30:56 +09:00
Trustin Lee
b900fd3cfb Clean up the exception messages
- Consistency
- Use the method name of the current scope if possible
2014-12-30 12:48:37 +09:00
Trustin Lee
1c30c8eced Throw exceptions outside the native code
Rebased and cleaned-up based on the work by @normanmaurer

Motivation:

Currently, IOExceptions and ClosedChannelExceptions are thrown from
inside the JNI methods. Instantiation of Java objects inside JNI code is
an expensive operation, needless to say about filling stack trace for
every instantiation of an exception.

Modifications:

Change most JNI methods to return a negative value on failure so that
the exceptions are instantiated outside the native code.

Also, pre-instantiate some commonly-thrown exceptions for better
performance.

Result:

Performance gain
2014-12-30 12:20:43 +09:00
Norman Maurer
08684cb749 Remove bottleneck while create InetSocketAddress in native transport
Motivation:

Everytime a new connection is accepted via EpollSocketServerChannel it will create a new EpollSocketChannel that needs to get the remote and local addresses in the constructor. The current implementation uses new InetSocketAddress(String, int) to create these. This is quite slow due the implementation in oracle and openjdk.

Modifications:

Encode all needed informations into a byte array before return from jni layer and then use new InetSocketAddress(InetAddress, int) to create the socket addresses. This allows to create the InetAddress via a byte[] and so reduce the overhead, this is done either by using InetAddress.getByteAddress(byte[]) or by Inet6Address.getByteAddress(String, byte[], int).

Result:

Reduce performance overhead while accept new connections with native transport
2014-12-12 18:15:55 +01:00
Trustin Lee
9c4ba81b0b Test TLS renegotiation with explicit cipher suite change
Motivation:

So far, our TLS renegotiation test did not test changing cipher suite
during renegotiation explicitly.

Modifications:

- Switch the cipher suite during renegotiation

Result:

We are now sure the cipher suite change works.
2014-12-12 17:50:48 +09:00
Norman Maurer
a4450b76d9 Allow to lazy create a DefaultFileRegion from a File
Motivation:

We only provided a constructor in DefaultFileRegion that takes a FileChannel which means the File itself needs to get opened on construction. This has the problem that if you want to write a lot of Files very fast you may end up with may open FD's even if they are not needed yet. This can lead to hit the open FD limit of the OS.

Modifications:

Add a new constructor to DefaultFileRegion which allows to construct it from a File. The FileChannel will only be obtained when transferTo(...) is called or the DefaultFileRegion is explicit open'ed via open() (this is needed for the native epoll transport)

Result:

Less resource usage when writing a lot of DefaultFileRegion.
2014-12-11 12:01:52 +01:00
Trustin Lee
e9685ea45a Add SslHandler.renegotiate()
Related: #3125

Motivation:

We did not expose a way to initiate TLS renegotiation and to get
notified when the renegotiation is done.

Modifications:

- Add SslHandler.renegotiate() so that a user can initiate TLS
  renegotiation and get the future that's notified on completion
- Make SslHandler.handshakeFuture() return the future for the most
  recent handshake so that a user can get the future of the last
  renegotiation
- Add the test for renegotiation to SocketSslEchoTest

Result:

Both client-initiated and server-initiated renegotiations are now
supported properly.
2014-12-11 18:06:16 +09:00
Trustin Lee
f0e2aa424d Add AbstractUnsafe.annotateConnectException()
Motivation:

JDK's exception messages triggered by a connection attempt failure do
not contain the related remote address in its message.  We currently
append the remote address to ConnectException's message, but I found
that we need to cover more exception types such as SocketException.

Modifications:

- Add AbstractUnsafe.annotateConnectException() to de-duplicate the
  code that appends the remote address

Result:

- Less duplication
- A transport implementor can annotate connection attempt failure
  message more easily
2014-10-14 17:50:31 +09:00
Norman Maurer
9968c61fbe [#2926] Fix 1 byte memory leak in native transport
Motivation:

We use malloc(1) in the on JNI_OnLoad method but never free the allocated memory. This means we have a tiny memory leak of 1 byte.

Modifications:

Call free(...) on previous allocated memory.

Result:

Fix memory leak
2014-09-22 15:07:40 +02:00
Scott Mitchell
b9582f4329 Fix Native EPOLL Build Failure
Motiviation:
If sendmmsg is already defined then the native epoll module failed to build because of conflicting definitions.
The mmsghdr type was also redefined on systems that already supported this structure.

Modifications:
Provide a way so that systems which already define sendmmsg and mmsghdr can build
Provide a way so that systems which don't define sendmmsg and mmsghdr can build

Result:
The native EPOLL module can build in more environments
2014-09-17 20:59:47 +02:00
Norman Maurer
b4feb7ac19 Directly write CompositeByteBuf if possible without memory copy. Related to [#2719]
Motivation:

In linux it is possible to write more then one buffer withone syscall when sending datagram messages.

Modifications:

Not copy CompositeByteBuf if it only contains direct buffers.

Result:

More performance due less overhead for copy.
2014-09-10 14:30:58 +02:00
Norman Maurer
7867f986fa Add support for sendmmsg(...) and so allow to write multiple DatagramPackets with one syscall. Related to [#2719]
Motivation:

On linux with glibc >= 2.14 it is possible to send multiple DatagramPackets with one syscall. This can be a huge performance win and so we should support it in our native transport.

Modification:

- Add support for sendmmsg by reuse IovArray
- Factor out ThreadLocal support of IovArray to IovArrayThreadLocal for better separation as we use IovArray also without ThreadLocal in NativeDatagramPacketArray now
- Introduce NativeDatagramPacketArray which is used for sendmmsg(...)
- Implement sendmmsg(...) via jni
- Expand DatagramUnicastTest to test also sendmmsg(...)

Result:

Netty now automatically use sendmmsg(...) if it is supported and we have more then 1 DatagramPacket in the ChannelOutboundBuffer and flush() is called.
2014-09-09 09:43:07 +02:00
Norman Maurer
07876ebf68 Allow to write CompositeByteBuf directly via EpollDatagramChannel. Related to [#2719]
Motivation:

On linux it is possible to use the sendMsg(...) system call to write multiple buffers with one system call when using datagram/udp.

Modifications:

- Implement the needed changes and make use of sendMsg(...) if possible for max performance
- Add tests that test sending datagram packets with all kind of different ByteBuf implementations.

Result:

Performance improvement when using CompoisteByteBuf and EpollDatagramChannel.
2014-09-09 09:43:07 +02:00
Norman Maurer
6d1b96fb63 [#2867] Workaround performance issue with IPv4-mapped-on-IPv6 addresses
Motivation:

InetAddress.getByName(...) uses exceptions for control flow when try to parse IPv4-mapped-on-IPv6 addresses. This is quite expensive.

Modifications:

Detect IPv4-mapped-on-IPv6 addresses in the JNI level and convert to IPv4 addresses before pass to InetAddress.getByName(...) (via InetSocketAddress constructor).

Result:

Eliminate performance problem causes by exception creation when parsing IPv4-mapped-on-IPv6 addresses.
2014-09-09 06:36:40 +02:00
Norman Maurer
b9101b0331 [#2823] Writing DefaultFileRegion with EpollSocketChannel may cause hang
Motivation:

In EpollSocketchannel.doWriteFileRegion(...) we need to make sure we write until sendFile(...) returns either 0 or all is written. Otherwise we may not get notified once the Channel is writable again.

This is the case as we use EPOLL_ET.

Modifications:

Always write until either sendFile returns 0 or all is written.

Result:

No more hangs when writing DefaultFileRegion can happen.
2014-08-26 15:07:02 +02:00
Norman Maurer
1fc2ad49ec Allow efficient writing of CompositeByteBuf when using native epoll transport.
Motivation:

There were no way to efficient write a CompositeByteBuf as we always did a memory copy to a direct buffer in this case. This is not needed as we can just write a CompositeByteBuf as long as all the components are buffers with a memory address.

Modifications:

- Write CompositeByteBuf which contains only direct buffers without memory copy
- Also handle CompositeByteBuf that have more components then 1024.

Result:

More efficient writing of CompositeByteBuf.
2014-08-21 10:56:41 +02:00
Trustin Lee
37eebc682f Fix data corruption in FileRegion transfer with epoll transport
Related issue: #2764

Motivation:

EpollSocketChannel.writeFileRegion() does not handle the case where the
position of a FileRegion is non-zero properly.

Modifications:

- Improve SocketFileRegionTest so that it tests the cases where the file
  transfer begins from the middle of the file
- Add another jlong parameter named 'base_off' so that we can take the
  position of a FileRegion into account

Result:

Improved test passes. Corruption is gone.
2014-08-13 16:58:14 -07:00
Trustin Lee
fb5583d788 Refactoring in preparation to unify I/O logic for all branches
Motivation:

While trying to merge our ChannelOutboundBuffer changes we've made last
week, I realized that we have quite a bit of conflicting changes at 4.1
and master. It was primarily because we added
ChannelOutboundBuffer.beforeAdd() and moved some logic there, such as
direct buffer conversion.

However, this is not possible with the changes we've made for 4.0. We
made ChannelOutboundBuffer final for example.

Maintaining multiple branch is already getting painful and having
different core will make it even worse, so I think we should keep the
differences between 4.0 and other branches minimal.

Modifications:

- Move ChannelOutboundBuffer.safeRelease() to ReferenceCountUtil
- Add ByteBufUtil.threadLocalBuffer()
  - Backported from ThreadLocalPooledDirectByteBuf
- Make most methods in AbstractUnsafe final
  - Add AbstractChannel.filterOutboundMessage() so that a transport can
    convert a message to another (e.g. heap -> off-heap), and also
    reject unsupported messages
  - Move all direct buffer conversions to filterOutboundMessage()
  - Move all type checks to filterOutboundMessage()
- Move AbstractChannel.checkEOF() to OioByteStreamChannel, because it's
  the only place it is used at all
- Remove ChannelOutboundBuffer.current(Object), because it's not used
  anymore
- Add protected direct buffer conversion methods to AbstractNioChannel
  and AbstractEpollChannel so that they can be used by their subtypes
- Update all transport implementations according to the changes above

Result:

- The missing extension point in 4.0 has been added.
  - AbstractChannel.filterOutboundMessage()
  - Thanks to the new extension point, we moved all transport-specific
    logic from ChannelOutboundBuffer to each transport implementation
- We can copy most of the transport implementations in 4.0 to 4.1 and
  master now, so that we have much less merge conflict when we modify
  the core.
2014-08-05 08:04:23 +02:00
Trustin Lee
b175b3d8be Add more utility methods to check the availability of the epoll transport
Related issue: #2733

Motivation:

Unlike OpenSsl, Epoll lacks a couple useful availability checker
methods:

- ensureAvailability()
- unavailabilityCause()

Modifications:

Add missing methods

Result:

More ways to check the availability and to get the cause of
unavailability programatically.
2014-08-04 15:03:25 -07:00
Trustin Lee
16e50765d1 Fix a stall write in EpollSocketChannel
Motivation:

When a ChannelOutboundBuffer contains a series of entries whose messages
are all empty buffers, EpollSocketChannel sometimes fails to remove
them. As a result, the result of the write(EmptyByteBuf) is never
notified, making the user application hang.

Modifications:

- Add ChannelOutboundBuffer.removeBytes(long) method that updates the
  progress of the entries and removes them as much as the specified
  number of written bytes.  It also updates the reader index of
  partially flushed buffer.
  - Make both NioSocketChannel and EpollSocketChannel use it to reduce
    code duplication
  - Replace EpollSocketChannel.updateOutboundBuffer()
- Refactor EpollSocketChannel.doWrite() for simplicity
  - Split doWrite() into doWriteSingle() and doWriteMultiple()
- Do not add a zero-length buffer to IovArray
- Do not perform any real I/O when the size of IovArray is 0

Result:

Another regression is gone.
2014-08-01 16:58:12 -07:00
Trustin Lee
5e5d1a58fd Overall cleanup
- ChannelOutboundBuffer.Entry.buffers -> bufs for consistency
- Make Native.IOV_MAX final because it's a constant
- Naming changes
  - FlushedMessageProcessor -> MessageProcessor just in case we can
    reuse it for unflushed messages in the future
- Add ChannelOutboundBuffer.Entry.recycle() that does not return the
  next entry, and use it wherever possible
- Javadoc clean-up
2014-07-30 14:57:13 -07:00
Norman Maurer
e282e504f1 Optimize gathering write in the epoll transport
Motivation:

While benchmarking the native transport, I noticed that gathering write
is not as fast as expected.  It was due to the fact that we have to do a
lot of array copies to put the buffer addresses into the iovec struct
array.

Modifications:

Introduce a new class called IovArray, which allows to fill buffers
directly into an off-heap array of iovec structs, so that it can be
passed over to JNI without any extra array copies.

Result:

Big performance improvement when doing gathering writes:

Before:

[nmaurer@xxx]~% wrk/wrk -H 'Host: localhost' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Connection: keep-alive' -d 120 -c 256 -t 16 --pipeline 256  http://xxx:8080/plaintext
Running 2m test @ http://xxx:8080/plaintext
  16 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    23.44ms   16.37ms 259.57ms   91.77%
    Req/Sec   181.99k    31.69k  304.60k    78.12%
  346544071 requests in 2.00m, 46.48GB read
Requests/sec: 2887885.09
Transfer/sec:    396.59MB

After:

[nmaurer@xxx]~% wrk/wrk -H 'Host: localhost' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Connection: keep-alive' -d 120 -c 256 -t 16 --pipeline 256  http://xxx:8080/plaintext
Running 2m test @ http://xxx:8080/plaintext
  16 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    21.93ms   16.33ms 305.73ms   92.34%
    Req/Sec   194.56k    33.75k  309.33k    77.04%
  369617503 requests in 2.00m, 49.57GB read
Requests/sec: 3080169.65
Transfer/sec:    423.00MB
2014-07-30 14:57:13 -07:00
Trustin Lee
997d8c32d2 Fix a regression caused by 73dfd7c01b
Motivation:

73dfd7c01b introduced various test
failures because:

- EpollSocketChannel.doWrite() raised a NullPointerException when
  notifying the write progress.
- ChannelOutboundBuffer.nioBuffers() did not expand the internal array
  when the pending entries contained more than 1024 buffers, dropping
  the remainder.

Modifications:

- Fix the NPE in EpollSocketChannel by removing an unnecessary progress
  update
- Expand the thread-local buffer array if there is not enough room,
  which was the original behavior dropped by the offending commit

Result:

Regression is gone.
2014-07-30 13:49:17 -07:00