Commit Graph

127 Commits

Author SHA1 Message Date
Scott Mitchell
09ecc34924 Linux EPOLL Channel Configuration test unsupported options
Motivation:
The unit tests should not fail due to using a channel option which is not supported by the underlying kernel.

Modifications:
- Ignore RuntimeExceptions which are thrown by JNI code when setsockopt or getsockopt fails.

Result:
Unit tests pass if socket option is not supported by kernel.
2015-06-02 12:54:36 -07:00
Scott Mitchell
3c432b5a19 TCP_NOTSENT_LOWAT older kernel compatibility
Motiviation:
TCP_NOTSENT_LOWAT is only supported in linux kernel 3.12 or newer. The addition of this socket option prevents older kernels from building.

Modifications:
- Conditionally define TCP_NOTSENT_LOWAT if it is not defined

Result:
Kernels older than 3.12 can still compile the EPOLL module.
2015-06-02 12:19:53 -07:00
Scott Mitchell
5121fba466 TCP_NOTSENT_LOWAT socket option support
Motiviation:
Linux provides the TCP_NOTSENT_LOWAT socket option. This can be used to control how much unsent data is queued in the tcp kernel buffers. This can be important when application level protocols (SPDY, HTTP/2) have their own priority mechanism and don't want data queued in the kernel.

Modifications:
- The epoll module will have an additional socket option TCP_NOTSENT_LOWAT
- There will be JNI methods to control the underlying linux socket option mechanism

Result:
Linux EPOLL module exposes the TCP_NOTSENT_LOWAT socket option.
2015-06-01 13:21:38 -07:00
Clebert Suconic
70e3d17620 fixing small leak on exception on the transport-epoll-native allocation
Motivation:

the JNI function ThrowNew won't release any allocated memory.
The method exceptionMessage is allocating a new string concatenating 2 constant strings
What is creating a small leak in case of these exceptions are happening.

Modifications:

Added new methods that will use exceptionMessage and free resources accordingly.
I am also removing the inline definition on these methods as they could be reused by
other added modules (e.g. libaio which should be coming soon)

Result:

No more leaks in case of failures.
2015-05-31 09:36:19 +02:00
Norman Maurer
f2ba221e7e [#3785] Correctly handle connection refused with native transport
Motivation:

Due a bug we not correctly handled connection refused errors and so failed the connect promise with the wrong exception.
Beside this we some times even triggered fireChannelActive() which is not correct.

Modifications:

- Add testcase
- correctly detect connect errors

Result:

Correct and consistent handling.
2015-05-27 13:38:50 +02:00
Norman Maurer
e903979a28 Not try to write more then Integer.MAX_VALUE / SSIZE_MAX via writev
Motivation:

When trying to write more then Integer.MAX_VALUE / SSIZE_MAX via writev(...) the OS may return EINVAL depending on the kernel or the actual OS (bsd / osx always return EINVAL). This will trigger an IOException.

Modifications:

Never try to write more then Integer.MAX_VALUE / SSIZE_MAX when using writev.

Result:

No more IOException when write more data then Integer.MAX_VALUE / SSIZE_MAX via writev.
2015-05-21 12:02:10 +02:00
Norman Maurer
3c60c9ce32 Fix regression introduced by 08e4b076be. 2015-05-06 17:57:13 +02:00
Norman Maurer
d711eb827d [#3709] Ensure all data is read from socket when EPOLLRDUP is received
Motivation:

When EPOLLRDHUP is received we need to try to read at least one time to ensure
that we read all pending data from the socket. Otherwise we may loose data.

Modifications:

- Ensure we read all data from socket
- Ensure file descriptor is closed on doClose() even if doDeregister() throws an Exception.
- Only handle either EPOLLRDHUP or EPOLLIN as only one is needed to detect connection reset.

Result:

No more data loss on connection reset.
2015-05-06 08:45:39 +02:00
Norman Maurer
5f5cdd1089 Proper handling of epoll_ctl errors
Motivation:

When using epoll_ctl we should respect the return value and do the right thing depending on it.

Modifications:

Adjust java and native code to respect epoll_ctl return values.

Result:

Correct and cleaner code.
2015-05-06 08:20:32 +02:00
Norman Maurer
ad9bec4d9d Add support for splice(...)
Motivation:

Linux supports splice(...) to transfer data from one filedescriptor to another without
pass data through the user-space. This allows to write high-performant proxy code or to stream
stuff from the socket directly the the filesystem.

Modification:

Add AbstractEpollStreamChannel.spliceTo(...) method to support splice(...) system call

Result:

Splice is now supported when using the native linux transport.

Conflicts:

	transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollStreamChannel.java
2015-04-30 07:10:46 +02:00
Norman Maurer
1cce998bb0 [#3662] Fail the connect future on close
Motivation:

Because of a bug we missed to fail the connect future when doClose() is called. This can lead to a future which is never notified and so may lead to deadlocks in user-programs.

Modifications:

Correctly fail the connect future when doClose() is called and the connection was not established yet.

Result:

Connect future is always notified.
2015-04-27 20:05:00 +02:00
Norman Maurer
b4b14ea19f Ensure backward-compability with 4.0
Motivation:

Each different *ChannelOption did extend ChannelOption in 4.0, which we changed in 4.1. This is a breaking change in terms of the API so we need to ensure we keep the old hierarchy.

Modifications:

- Let all *ChannelOption extend ChannelOption
- Add back constructor and mark it as @deprecated

Result:

No API breakage between 4.0 and 4.1
2015-04-19 13:25:42 +02:00
Norman Maurer
e48b8f5c49 [#3539] Correctly handle EPOLLRDHUP
Motivation:

As we missed to correctly handle EPOLLRDHUP we produce an IOException which is unnessary. This leads
to have exceptionCaught(...) methods called.

Modifications:

When EPOLLRDHUP was received just close the socket and fail all pending writes.

Result:

Correctly handle of EPOLLRDHUP and so not miss-leading exceptions.
2015-04-14 06:57:11 +02:00
Norman Maurer
c7827dc16a First load RuntimeException to prevent segfault on error
Motivation:

When an error happens during loading the native library it may try to generate a new RuntimeException before the RuntimeException is loaded.

Modifications:

- Load RuntimeException as first

Result:

No more segfaults possible
2015-03-13 18:28:40 +01:00
Norman Maurer
3df7b4dac7 Respect -Djava.net.preferIPv4Stack when using epoll transport
Motivation:

On a system where ipv4 and ipv6 are supported a user may want to use -Djava.net.preferIPv4Stack=true to restrict it to use ipv4 only.
This is currently ignored with the epoll transport.

Modifications:

Respect java.net.preferIPv4Stack system property.

Result:

-Djava.net.preferIPv4Stack=true will have the effect the user is looking for.
2015-03-11 02:50:11 +01:00
Norman Maurer
1a83232ab2 [#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:07:09 +01:00
Norman Maurer
d6016b7be8 [#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:41:09 +01:00
Norman Maurer
91db4b71b2 [#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:28 +01:00
Norman Maurer
6c24dd4d8f 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:26 +01:00
Norman Maurer
01bc2d6d80 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:14 +01:00
Norman Maurer
237b393a8e 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:02:55 +01:00
Norman Maurer
5bb1377072 [#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:06:02 +01:00
Norman Maurer
88dae15bc2 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:58 +01:00
Norman Maurer
93343ff00c 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:44:04 +01:00
Norman Maurer
91538d9b53 [#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:28 +01:00
Norman Maurer
6e508e60e7 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:56:01 +01:00
Norman Maurer
865a83c15d 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:22 +01:00
Norman Maurer
a69fbaeed9 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:15:47 +01:00
Norman Maurer
7a3d91f43d 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:38 +01:00
Norman Maurer
f762b4bb68 Cleanup code. Part of [#3398] 2015-02-08 13:04:26 +01:00
Norman Maurer
0a452bef8e 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:36:15 +01:00
Norman Maurer
4e6cec0e26 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:08:27 +01:00
Norman Maurer
730ec357d2 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:31:40 +01:00
Norman Maurer
ed98ce27e1 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:46 +01:00
Norman Maurer
b984ca7979 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:37:34 +01:00
Norman Maurer
3030b4afe3 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 20:07:43 +01:00
Norman Maurer
f771a97592 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:39:41 +01:00
Norman Maurer
6b8ec6b781 [#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:51:34 +01:00
Norman Maurer
c66da29644 [#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:19:14 +01:00
Norman Maurer
c5bd8fd264 [#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:38 +01:00
Norman Maurer
bc97d7d7a1 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:43:12 +01:00
Trustin Lee
650bb5358d Fix duplicate channelReadComplete() in EpollDatagramChannel 2014-12-31 19:13:56 +09:00
Trustin Lee
f398f2f7b5 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:34:54 +09:00
Trustin Lee
f26be2e973 Clean up the exception messages
- Consistency
- Use the method name of the current scope if possible
2014-12-30 12:52:18 +09:00
Trustin Lee
aa42287e46 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:25:23 +09:00
Norman Maurer
73c0f85d63 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:16:23 +01:00
Trustin Lee
e7cf1dcb98 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:49:16 +09:00
Norman Maurer
12c9ce7f67 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:04:17 +01:00
Trustin Lee
1dc1831abf 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-10 18:59:50 +09:00
Trustin Lee
e848066cab Name resolver API and DNS-based name resolver
Motivation:

So far, we relied on the domain name resolution mechanism provided by
JDK.  It served its purpose very well, but had the following
shortcomings:

- Domain name resolution is performed in a blocking manner.
  This becomes a problem when a user has to connect to thousands of
  different hosts. e.g. web crawlers
- It is impossible to employ an alternative cache/retry policy.
  e.g. lower/upper bound in TTL, round-robin
- It is impossible to employ an alternative name resolution mechanism.
  e.g. Zookeeper-based name resolver

Modification:

- Add the resolver API in the new module: netty-resolver
- Implement the DNS-based resolver: netty-resolver-dns
  .. which uses netty-codec-dns
- Make ChannelFactory reusable because it's now used by
  io.netty.bootstrap, io.netty.resolver.dns, and potentially by other
  modules in the future
  - Move ChannelFactory from io.netty.bootstrap to io.netty.channel
  - Deprecate the old ChannelFactory
  - Add ReflectiveChannelFactory

Result:

It is trivial to resolve a large number of domain names asynchronously.
2014-10-16 17:05:20 +09:00