Commit Graph

1305 Commits

Author SHA1 Message Date
Norman Maurer
f35158f402 Revert "Do not suppress channelReadComplete() when a handler was just added"
This reverts commit a41b46ff43.
2015-04-20 09:02:14 +02:00
Norman Maurer
2e1325aa9d Revert "Add another test case for channelReadComplete() suppression"
This reverts commit 5fca3de098.
2015-04-20 09:02:01 +02:00
Pierre DAL-PRA
2221dc6b20 Small typos fixes in Channel's Javadoc 2015-03-21 16:13:05 +01:00
Wouter
f78c384fec Fix typo in javadoc 2015-03-18 17:15:45 +01:00
Trustin Lee
5d15e18cbf Fix SocketException in NioSocketChannelUnsafe.closeExecutor()
Related: #3464

Motivation:

When a connection attempt is failed,
NioSocketChannelUnsafe.closeExecutor() triggers a SocketException,
suppressing the channelUnregistered() event.

Modification:

Do not attempt to get SO_LINGER value when a socket is not open yet.

Result:

One less bug
2015-03-05 15:17:43 +09:00
jongyoon lim
269695d043 typo_fix in the comment 2015-02-25 20:30:49 +01:00
Norman Maurer
6950bfb5d8 Allow to use EmbeddedChannel.schedule*(...)
Motivation:

At the moment when EmbeddedChannel is used and a ChannelHandler tries to schedule and task it will throw an UnsupportedOperationException. This makes it impossible to test these handlers or even reuse them with EmbeddedChannel.

Modifications:

- Factor out reusable scheduling code into AbstractSchedulingEventExecutor
- Let EmbeddedEventLoop and SingleThreadEventExecutor extend AbstractSchedulingEventExecutor
- add EmbbededChannel.runScheduledPendingTasks() which allows to run all scheduled tasks that are ready

Result:

Embeddedchannel is now usable even with ChannelHandler that try to schedule tasks.
2015-02-20 09:53:25 +01:00
jongyoon lim
a2f77e743e removed an unnecessary local variable for consistency 2015-02-18 20:13:05 +01:00
Norman Maurer
47f095856c Allow to get existing ChannelOption / AttributeKey from String
Motivation:

We should allow to get a ChannelOption/AttributeKey from a String. This will make it a lot easier to make use of configuration files in applications.

Modifications:

- Add exists(...), newInstance(...) method to ChannelOption and AttributeKey and alter valueOf(...) to return an existing instance for a String or create one.
- Add unit tests.

Result:

Much more flexible usage of ChannelOption and AttributeKey.
2015-02-18 09:12:43 +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
Cristian
c03f57e9bd Fixed ServerBootstrap#group(EventLoopGroup, EventLoopGroup) javadoc 2015-02-16 07:39:25 +01:00
Trustin Lee
5fca3de098 Add another test case for channelReadComplete() suppression
Related commit:
- a41b46ff43

Motivation:

We need a test case for the commit above.
2015-02-09 16:29:02 +09: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
Trustin Lee
10a5635acb Reorder PlatformDependent.isRoot() check
Motivation:

isRoot() is an expensive operation. We should avoid calling it if
possible.

Modifications:

Move the isRoot() checks to the end of the 'if' block, so that isRoot()
is evaluated only when really necessary.

Result:

isRoot() is evaluated only when SO_BROADCAST is set and the bind address
is anylocal address.
2015-02-08 11:59:56 +09:00
Trustin Lee
a41b46ff43 Do not suppress channelReadComplete() when a handler was just added
Related:
- 8b2fb2b985

Motivation:

The commit mentioned above introduced a regression where
channelReadComplete() event is swallowed by a handler which was added
dynamically.

Modifications:

Do not suppress channelReadComplete() if the current handler's
channelRead() method was not invoked at all, so that a just-added
handler does not suppress channelReadComplete().

Result:

Regression is gone, and channelReadComplete() is invoked when necessary.
2015-02-07 23:18:46 +09:00
Trustin Lee
8b2fb2b985 Ensure channelReadComplete() is called only when necessary
Related:
- 375b9e1307

Motivation:

Even if a handler called ctx.fireChannelReadComplete(), the next handler
should not get its channelReadComplete() invoked if fireChannelRead()
was not invoked before.

Modifications:

- Ensure channelReadComplete() is invoked only when the handler of the
  current context actually produced a message, because otherwise there's
  no point of triggering channelReadComplete().
  i.e. channelReadComplete() must follow channelRead().
- Fix a bug where ctx.read() was not called if the handler of the
  current context did not produce any message, making the connection
  stall. Read the new comment for more information.

Result:

- channelReadComplete() is invoked only when it makes sense.
- No stale connection
2015-02-07 16:12:43 +09:00
Norman Maurer
ca8b937c14 [#3367] Fix re-entrance bug in PendingWriteQueue
Motivation:

Because of a re-entrance bug in PendingWriteQueue it was possible to get the queue corrupted and also trigger an IllegalStateException caused by multiple recycling of the internal PendingWrite objects.

Modifications:

- Correctly guard against re-entrance

Result:

No more IllegalStateException possible
2015-02-06 19:31:37 +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
Marco Craveiro
108a95caca Minor idiomatic changes to java docs 2015-02-04 08:28:40 +01:00
haohao
97324454dd [#3368] Ensure ByteBuf is not release two times
Motivation:

As the ByteBuf is not set to null after release it we may try to release it again in handleReadException()

Modifications:

-  set ByteBuf to null to avoid another byteBuf.release() to be called in handleReadException()

Result:

No IllegalReferenceCountException anymore
2015-01-29 18:26:22 +01:00
Norman Maurer
375b9e1307 Ensure ctx.fireChannelReadComplete() is only called when something was produced
Motivation:

ctx.fireChannelReadComplete() should only be called if something is produced during a channelRead(...) operation. Also we must ensure that it will be called
if channelRead(...) produced something at some point as channelRead(...) maybe called multiple times by the transport before channelReadComplete(...) is called.

Modifications:

- Ensure channelReadComplete(...) only triggers ctx.fireChannelReadComplete() when a previous channelRead(...) call produced a message
- Ensure read() is called of more data is needed

Result:

Correct semantic with channelReadComplete(...) events and also ensure no stales
2015-01-26 09:51:45 +01:00
ysammy
39820ef303 Fix documentation for ChannelHandlerContext#fireChannelReadComplete
Motivation:
Fix a minor documentation bug in
ChannelHandlerContext#fireChannelReadComplete.

Modifications:
ChannelHandlerContext#fireChannelReadComplete no longer references an
incorrect method in its javadoc.

Results:
Documentation is correct.
2014-12-12 18:43:27 +01: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
b8abe2d92e Trigger channelWritabilityChanged() later to avoid reentrance
Related: #3212

Motivation:

When SslHandler and ChunkedWriteHandler exists in a pipeline together,
it is possible that ChunkedWriteHandler.channelWritabilityChanged()
invokes SslHandler.flush() and vice versa. Because they can feed each
other (i.e. ChunkedWriteHandler.channelWritabilityChanged() ->
SslHandler.flush() -> ChunkedWriteHandler.channelWritabilityChanged() ->
..), they can fall into an inconsistent state due to reentrance (e.g.
bad MAC record at the remote peer due to incorrect ordering.)

Modifications:

- Trigger channelWritabilityChanged() using EventLoop.execute() when
  there's a chance where channelWritabilityChanged() can cause a
  reentrance issue
- Fix test failures caused by the modification

Result:

Fix the handler reentrance issues related with a
channelWritabilityChanged() event
2014-12-10 18:46:01 +09:00
Trustin Lee
1e35d06efb Make PendingWriteQueue.recycle() update its state before triggering an event
Related: #3212

Motivation:

PendingWriteQueue.recycle() updates its data structure after triggering
a channelWritabilityChanged() event. It causes a rare corruption such as
double free when channelWritabilityChanged() method accesses the
PendingWriteQueue.

Modifications:

Update the state of PendingWriteQueue before triggering an event.

Result:

Fix a rare double-free problem
2014-12-07 23:28:18 +09:00
Trustin Lee
1122189771 Trigger exceptionCaught() when VoidChannelPromise fails
Related: #3190

Motivation:

When an outbound handler method raises an exception, its promise is
marked as failed.  If the promise is done already, the exception is
logged.

When the promise is void, exceptionCaught() must be triggered to notify
a user. However, AbstractChannelHandlerContext simply swallows it.

Modifications:

Do not swallow an exception when the promise is void.

Result:

A user who uses a void promise for an outbound operation will be
notified on failure.
2014-12-07 16:00:35 +09:00
Trustin Lee
2fadef31ef Fire channelRead() event immediately in OIO message channels
Related: #3189

Motivation:

OIO transport implementations block for at most 1 second to wait for
additional messages (or accepted connections).

However, because AbstractOioMessageChannel defers the channelRead()
events for the messages read so far until there's nothing to read up to
maxMessagesPerRead, any read operation will be followed by a 1-second
delay.

Modifications:

Fire channelRead() events as soon as doRead() returns so that there is
no 1 second delay between the actual read and the channelRead() event.

Result:

No more weird 1-second delay
2014-12-07 12:13:33 +09:00
Trustin Lee
c774b65f86 Fix a race condition where handler is removed before unregistration
Related: #3156

Motivation:

Let's say we have a channel with the following pipeline configuration:

  HEAD --> [E1] H1 --> [E2] H2 --> TAIL

when the channel is deregistered, the channelUnregistered() methods of
H1 and H2 will be invoked from the executor thread of E1 and E2
respectively. To ensure that the channelUnregistered() methods are
invoked from the correct thread, new one-time tasks will be created
accordingly and be scheduled via Executor.execute(Runnable).

As soon as the one-time tasks are scheduled,
DefaultChannelPipeline.fireChannelUnregistered() will start to remove
all handlers from the pipeline via teardownAll(). This process is
performed in reversed order of event propagation. i.e. H2 is removed
first, and then H1 is removed.

If the channelUnregistered() event has been passed to H2 before H2 is
removed, a user does not see any problem.

If H2 has been removed before channelUnregistered() event is passed to
H2, a user will often see the following confusing warning message:

  An exceptionCaught() event was fired, and it reached at the tail of
  the pipeline. It usually means the last handler in the pipeline did
  not handle the exception.

Modifications:

To ensure that the handlers are removed *after* all events are
propagated, traverse the pipeline in ascending order before performing
the actual removal.

Result:

A user does not get the confusing warning message anymore.
2014-12-05 15:51:40 +09:00
Frank Barber
a83a970276 Prevent channel re-registration from firing channelActive
Motivation:

AbstractUnsafe considers two possibilities during channel registration. First,
the channel may be an outgoing connection, in which case it will be registered
before becoming active. Second, the channel may be an incoming connection in,
which case the channel will already be active when it is registered. To handle
the second case, AbstractUnsafe checks if the channel is active after
registration and calls ChannelPipeline.fireChannelActive() if so.  However, if
an active channel is deregistered and then re-registered this logic causes a
second fireChannelActive() to be invoked. This is unexpected; it is reasonable
for handlers to assume that this method will only be invoked once per channel.

Modifications:

This change introduces a flag into AbstractUnsafe to recognize if this is the
first or a subsequent registration. ChannelPipeline.fireChannelActive() is only
possible for the first registration.

Result:

ChannelPipeline.fireChannelActive() is only called once.
2014-11-30 19:43:48 +01:00
Ronald Chen
ae4017e76a replaced broken &lt with < and same for gt 2014-11-29 19:36:30 +01:00
Idel Pivnitskiy
3d200085a4 Small performance improvements
Motivation:

Found performance issues via FindBugs and PMD.

Modifications:

- Removed unnecessary boxing/unboxing operations in DefaultTextHeaders.convertToInt(CharSequence) and DefaultTextHeaders.convertToLong(CharSequence). A boxed primitive is created from a string, just to extract the unboxed primitive value.
- Added a static modifier for DefaultHttp2Connection.ParentChangedEvent class. This class is an inner class, but does not use its embedded reference to the object which created it. This reference makes the instances of the class larger, and may keep the reference to the creator object alive longer than necessary.
- Added a static compiled Pattern to avoid compile it each time it is used when we need to replace some part of authority.
- Improved using of StringBuilders.

Result:

Performance improvements.
2014-11-20 00:58:35 -05:00
Sam Young
bb94f05083 Add generic versions of PromiseAggregator and PromiseNotifier.
Motivation:

ChannelPromiseAggregator and ChannelPromiseNotifiers only allow
consumers to work with Channels as the result type. Generic versions
of these classes allow consumers to aggregate or broadcast the results
of an asynchronous execution with other result types.

Modifications:

Add PromiseAggregator and PromiseNotifier. Add unit tests for both.
Remove code in ChannelPromiseAggregator and ChannelPromiseNotifier and
modify them to extend the new base classes.

Result:

Consumers can now aggregate or broadcast the results of an asynchronous
execution with results types other than Channel.
2014-11-07 08:44:20 +01:00
Trustin Lee
9b4481b59a Fix a compilation error 2014-10-25 17:13:57 +09:00
Trustin Lee
d794ea515b Fix compilation errors in ChannelOutboundBufferTest 2014-10-25 16:57:47 +09:00
Trustin Lee
ee9cbda9f0 Implement user-defined writability flags
Related: #2945

Motivation:

Some special handlers such as TrafficShapingHandler need to override the
writability of a Channel to throttle the outbound traffic.

Modifications:

Add a new indexed property called 'user-defined writability flag' to
ChannelOutboundBuffer so that a handler can override the writability of
a Channel easily.

Result:

A handler can override the writability of a Channel using an unsafe API.
For example:

  Channel ch = ...;
  ch.unsafe().outboundBuffer().setUserDefinedWritability(1, false);
2014-10-25 15:59:30 +09:00
Trustin Lee
d36950503c Make Bootstrap and ServerBootstrap fully overridable
Related: #2034

Motivation:

Some users want to mock Bootstrap (or ServerBootstrap), and thus they
should not be final but be fully overridable and extensible.

Modifications:

Remove finals wherever possible

Result:

@daschl is happy.
2014-10-17 16:17:48 +09:00
Trustin Lee
c13f72c5b6 Fix an infinite loop when writing a zero-length FileRegion
Related: #2964

Motivation:

Writing a zero-length FileRegion to an NIO channel will lead to an
infinite loop.

Modification:

- Do not write a zero-length FileRegion by protecting with proper 'if'.
- Update the testsuite

Result:

Another bug fixed
2014-10-17 16:06:57 +09:00
Trustin Lee
2443005c15 Do not consider PortUnreachableException to require channel closure
Motivation:

When a datagram packet is sent to a destination where nobody actually listens to,
the server O/S will respond with an ICMP Port Unreachable packet.
The ICMP Port Unreachable packet is translated into PortUnreachableException by JDK.
PortUnreachableException is not a harmful exception that prevents a user from sending a datagram.
Therefore, we should not close a datagram channel when PortUnreachableException is caught.

Modifications:

- Do not close a channel when the caught exception is PortUnreachableException.

Result:

A datagram channel is not closed unexpectedly anymore.
2014-10-14 17:50:31 +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
Luke Wood
bcfd6da1dd Access autoRead via an AtomicIntegerFieldUpdater.
Motiviation:

Before this change, autoRead was a volatile boolean accessed directly.  Any thread that invoked the DefaultChannelConfig#setAutoRead(boolean) method would read the current value of autoRead, and then set a new value.  If the old value did not match the new value, some action would be immediately taken as part of the same method call.

As volatile only provides happens-before consistency, there was no guarantee that the calling thread was actually the thread mutating the state of the autoRead variable (such that it should be the one to invoke the follow-up actions).  For example, with 3 threads:
 * Thread 1: get = false
 * Thread 1: set = true
 * Thread 1: invokes read()
 * Thread 2: get = true
 * Thread 3: get = true
 * Thread 2: set = false
 * Thread 2: invokes autoReadCleared()
 * Event Loop receives notification from the Selector that data is available, but as autoRead has been cleared, cancels the operation and removes read interest
 * Thread 3: set = true

This results in a livelock - autoRead is set true, but no reads will happen even if data is available (as readyOps).  The only way around this livelock currently is to set autoRead to false, and then back to true.

Modifications:

Write access to the autoRead variable is now made using the getAndSet() method of an AtomicIntegerFieldUpdater, AUTOREAD_UPDATER.  This also changed the type of the underlying autoRead variable to be an integer, as no AtomicBooleanFieldUpdater class exists.  Boolean logic is retained by assuming that 1 is true and 0 is false.

Result:

There is no longer a race condition between retrieving the old value of the autoRead variable and setting a new value.
2014-10-13 15:16:28 +02:00
Norman Maurer
16e2e1b181 [#2586] Use correct EventExecutor to notify for bind failures on late registration
Motivation:

We used the wrong EventExecutor to notify for bind failures if a late registration was done.

Modifications:

Use the correct EventExecutor to notify and only use the GlobelEventExecutor if the registration fails itself.

Result:

The correct Thread will do the notification.
2014-08-20 16:32:39 +02:00
Trustin Lee
929f1bad80 Fix a bug where ChannelOutboundBuffer.removeBytes() throws ClassCastException
When a ChannelOutboundBuffer contains ByteBufs followed by a FileRegion,
removeBytes() will fail with a ClassCastException.  It should break the
loop instead.
2014-08-15 09:56:47 -07:00
Trustin Lee
e3d6d8e561 Fix the regression caused by f31c630c8c
f31c630c8c was causing
SocketGatheringWriteTest to fail because it does not take the case where
an empty buffer exists in a gathering write.

When there is an empty buffer in a gathering write, the number of
buffers returned by ChannelOutboundBuffer.nioBuffer() and the actual
number of write attemps can differ.

To remove the write requests correctly, a byte transport must use
ChannelOutboundBuffer.removeBytes()
2014-08-15 09:41:07 -07:00
Norman Maurer
2bd7a8387d Fix checkstyle 2014-08-15 12:59:51 +02:00
Norman Maurer
450a6e3b99 [#2771] Correctly handle constructing of EmbeddedChannel
Motivation:

Because of an incorrect logic in teh EmbeddedChannel constructor it is not possible to use EmbeddedChannel with a ChannelInitializer as constructor argument. This is because it adds the internal LastInboundHandler to its ChannelPipeline before it register itself to the EventLoop.

Modifications:

First register self to EventLoop before add LastInboundHandler to the ChannelPipeline.

Result:

It's now possible to use EmbeddedChannel with ChannelInitializer.
2014-08-15 12:12:57 +02:00
Norman Maurer
f31c630c8c [#2769] Fix regression when writing different message types
Motivation:

Due a regression NioSocketChannel.doWrite(...) will throw a ClassCastException if you do something like:

channel.write(bytebuf);
channel.write(fileregion);
channel.flush();

Modifications:

Correctly handle writing of different message types by using the correct message count while loop over them.

Result:

No more ClassCastException
2014-08-15 11:55:48 +02:00
Norman Maurer
c46b197c61 [#2761] Proper work-around for data-corruption caused by cached ByteBuffers
Motivation:

The previous fix did disable the caching of ByteBuffers completely which can cause performance regressions. This fix makes sure we use nioBuffers() for all writes in NioSocketChannel and so prevent data-corruptions. This is still kind of a workaround which will be replaced by a more fundamental fix later.

Modifications:

- Revert 4059c9f354
- Use nioBuffers() for all writes to prevent data-corruption

Result:

No more data-corruption but still retain the original speed.
2014-08-13 21:21:15 +02:00
Norman Maurer
2c03030950 Revert "[#2761] ChannelOutboundBuffer can cause data-corruption because of caching ByteBuffers"
This reverts commit 4059c9f354.
2014-08-13 16:41:47 +02:00
Norman Maurer
1e6fddfc72 Revert "[#2762] Not expand ByteBuffer[] in ChannelOutboundBuffer"
This reverts commit 3db0128db9 as it may cause problem if a CompositeByteBuf has more then 1024 components.
2014-08-13 16:41:20 +02:00
Norman Maurer
3db0128db9 [#2762] Not expand ByteBuffer[] in ChannelOutboundBuffer
Motivation:

At the moment we expand the ByteBuffer[] when we have more then 1024 ByteBuffer to write and replace the stored instance in its FastThreadLocal. This is not needed and may even harm performance on linux as IOV_MAX is 1024 and so this may cause the JVM to do an array copy.

Modifications:

Just exit the nioBuffers() method if we can not fit more ByteBuffer in the array. This way we will pick them up on the next call.

Result:

Remove uncessary array copy and simplify the code.
2014-08-13 11:59:20 +02:00