Commit Graph

1409 Commits

Author SHA1 Message Date
Trustin Lee
85ec4d9cc4 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:36:53 +09:00
Trustin Lee
69e25d21f6 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:24:19 +09:00
Trustin Lee
a337589c91 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, ChannelHandlerInvokerUtil 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:07:33 +09:00
Trustin Lee
7e2ae8758c 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:12:19 +09:00
Trustin Lee
c797e7bdc5 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 16:12:34 +09:00
Trustin Lee
9acf4a800a Copy the resolver configuration when cloning Bootstrap
Motivation:

Bootstrap.clone() does not copy the resolver configuration.

Modifications:

Copy the resolver configuration when cloning.

Result:

Bug fixed
2014-12-01 19:48:59 +09:00
Frank Barber
e9bcc518fc 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 20:09:03 +01:00
Ronald Chen
dd3036be02 replaced broken &lt with < and same for gt 2014-11-29 19:31:05 +01:00
nmittler
171fbf3b41 Race condition with completion of Channel closeFuture and unregistration.
Motivation:
AbstractChannel.close() completes the closeFuture and then proceeds to
schedule a task to fireChannelInactive and unregister the channel. If
the user shuts down the EventLoop as a result of the closeFuture
completing this can result in a RejectedExecutionException when the
unregister task is scheduled.  This is mostly noise, but it does
somewhat pollute the logs.

Modifications:
Changed AbstractChannel.close() to not complete the channelFuture and
promise until after the unregistration task is scheduled.

Result:
Noisy error log should no longer be an issue.
2014-11-21 15:07:02 +01:00
Trustin Lee
2183c129d1 Use FastThreadLocal for skipFlagsCache
Related: #3113

Motivation:

Because ChannelHandlerContext is most often instantiated by an I/O
thread, we can rely on thread-local variables to keep the skipFlags
cache, which should be faster than partitioned synchronized variable.

Modifications:

Use FastThreadLocal for skipFlagsCache instead of partitioned
synchronized map.

Result:

Less contention
2014-11-20 17:57:09 +09:00
Idel Pivnitskiy
9465db25ba 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-19 23:44:25 -05:00
Jakob Buchgraber
229f83a7e6 Correctly shutdown wrapped Executor in PausableChannelEventExecutor.shutdown()
Motivation:

PausableChannelEventExecutor().shutdown() used to call unwrap().terminationFuture() instead of unwrap.shutdown().
This error was reported by @xfrag in a comment to a commit message [1]. Tyvm.

Modifications:

PausableChannelEventExecutor.shutdown() now correctly invokes unwrap().shutdown() instead of unwrap().terminationFuture().

Result:

Correct code.

[1] 220660e351 (commitcomment-8489643)
2014-11-12 13:53:29 +01:00
Sam Young
8fbc513da7 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 09:16:35 +01:00
Trustin Lee
fce23b46a2 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:58:52 +09:00
Trustin Lee
0dc046ebed Increase the timeout of ChannelDeregistrationTest
Motivation:

When a thread-local random is used first time, it tries to get the
initial seed uniquifier from SecureRandom, and it sometimes takes time
for the system to have enough entropy.

In ChannelDeregistrationTest, the retrieval of the initial seed
uniquifier takes place lazily when a new channel is created, and it
blocks the channel creation for more than 2 seconds, resulting in test
timeouts.

Modifications:

Increase the timeout of the tests to 5 seconds, because the timeout of
the initial seed uniquifier retrieval is 3 seconds.

Result:

Less flakey tests
2014-10-21 14:08:42 +09:00
Trustin Lee
1e4bbe9839 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:16:13 +09:00
Trustin Lee
0eb059bf58 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:04:37 +09:00
Trustin Lee
fa248cecb5 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:10:36 +09:00
Trustin Lee
75ed693794 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-16 17:06:12 +09:00
Trustin Lee
d9739126f2 Finish porting netty-proxy module
- Fix problems introduced by de9c81bf6e
- Fix inspector warnings
2014-10-14 12:46:35 +09:00
Trustin Lee
e4ab108a10 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 12:38:12 +09:00
Trustin Lee
f325c261cc Auto-generate the handler name when null is specified as a name
Motivation:

There's no way to generate the name of a handler being newly added
automatically and reliably.

For example, let's say you have a routine that adds a set of handlers to
a pipeline using addBefore() or addAfter().  Because addBefore() and
addAfter() always require non-conflicting non-null handler name, making
the multiple invocation of the routine on the same pipeline is
non-trivial.

Modifications:

- If a user specifies null as the name of the new handler,
  DefaultChannelPipeline generates one.
- Update the documentation of ChannelPipeline to match the new behavior

Result:

A user doesn't need to worry about name conflicts anymore.
2014-10-14 12:33:44 +09:00
Luke Wood
8f8a06ab0a 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:13:32 +02:00
Jakob Buchgraber
8bc7deeb87 Improve error reporting in SingleThreadEventLoopTest. Fixes #2894
Motivation:

When an assertTrue(condition) statement fails we usually don't know
why, as the parameters of the condition are not logged.

Modifications:

Include relevant parameters in the assertion error message.

Result:

Easier to debug and understand test failures.
2014-09-20 15:29:43 -04:00
Jakob Buchgraber
b72a05edb4 Shutdown Executor on MultithreadEventLoopGroup shutdown. Fixes #2837
Motivation:

Currently the Executor created by (Nio|Epoll)EventLoopGroup is not correctly shutdown.
This might lead to resource shortages, due to resources not being freed asap.

Modifications:

If (Nio|Epoll)EventLoopGroup create their internal Executor via a constructor
provided `ExecutorServiceFactory` object or via
MultithreadEventLoopGroup.newDefaultExecutorService(...) the ExecutorService.shutdown()
method will be called after (Nio|Epoll)EventLoopGroup is shutdown.

ExecutorService.shutdown() will not be called if the Executor object was passed
to the (Nio|Epoll)EventLoopGroup (that is, it was instantiated outside of Netty).

Result:

Correctly release resources on (Nio|Epoll)EventLoopGroup shutdown.
2014-09-12 12:17:29 +09:00
Jakob Buchgraber
c40b0d2e07 Reset interrupted flag in SingleThreadEventLoopTest. Fixes #2841
Motivation:

Once the interrupted flag in SingleThreadEventLoopB was set it was never reset.
That way the eventloop thread was always in an interrupted state and all calls
to Thread.sleep/LockSupport.parkNanos would fail.

Modifications:

Reset interrupted flag.

Result:

Number of GC runs when executing the test is down to zero (from 20 - 50).
Looking at the heap dump shows >10x decrease in memory consumption e.g.
the number of ForkJoinTasks is down to 25k from 350k previously. Similar
is true for BlockingQueue.Node objects.
2014-09-01 16:33:15 +02:00
Jakob Buchgraber
0d549706f1 Reduce Memory Usage of SingleThreadEventLoopTest
Motivation:

The SingleThreadEventLoopTest allocated up to half a gigabyte of memory per run,
causing up to 50 GC runs in ~20 seconds.

Modification:

Charlie Hunt identified TLAB allocations to be the root cause of this excessive
memory usage [1]. By reusing the Executor in every test we can reduce the
memory usage by >50%.

Result:

Lower Memory Usage and fewer Garbage Collector runs.
Helps to resolve GitHub issue #2841.

[1] https://twitter.com/charlesjhunt/status/505351389317722112
2014-08-29 19:31:31 +02:00
Norman Maurer
3b114a51df Cleanup test
Motivation:

Saw a lot of inspector warnings

Modifications:

Fix inspector warnings

Result:

Cleaner code
2014-08-29 16:01:54 +02:00
Norman Maurer
5b0f60cff9 [#2841] Fix SingleThreadEventLoopTest that was failing because of GC pressure
Motivation:

Sometimes the SingleThreadEventLoopTest did fail on our CI. This was because of GC pressure produced by Thread.sleep(...) when interrupted as it creates a new InterruptedException all the time (and need to fill it).

Modifications:

Replace Thread.sleep(...) with LockSupport.parkNanos(...) to eliminate exception overhead.

Result:

SingleThreadEventLoopTest produce a lot less garbage.
2014-08-29 14:57:48 +02:00
Norman Maurer
0b5df22aec [#2797] Let EventExecutorGroup extend AutoCloseable
Motivation:

To make it more easy to shutdown an EventExecutorGroup / EventLoopGroup we should let both of them extend AutoCloseable.

Modifications:

Let EventExecutorGroup extend AutoCloseable and impement it.

Result:

Easier shutdown of EventExecutorGroup and EventLoopGroup
2014-08-26 14:04:27 +02:00
Jakob Buchgraber
0381fa67a8 Undo AbstractChannelHandlerContext extend PausableChannelEventExecutor. Fixes #2814
Motivation:
Our last-minute change that made AbstractChannelHandlerContext implement PausableChannelEventExecutor broke the socksproxy example.

Modifications:
AbstractChannelHandlerContext does not inherit from PausableChannelEventExecutor anymore. Instead we'll allocate an extra object on demand.

Result:

AbstractChannelHandlerContext.executor().newPromise() returns the correct type.
2014-08-26 13:50:40 +02:00
Norman Maurer
62e26a2818 [#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:35:06 +02:00
Trustin Lee
44d9163169 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:57:12 -07:00
Trustin Lee
23d15c71ee 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:44:05 -07:00
Norman Maurer
cb666c1169 [#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:59:25 +02:00
Norman Maurer
050e7ed933 [#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:56:27 +02:00
Norman Maurer
88e9c7366b Revert "[#2761] ChannelOutboundBuffer can cause data-corruption because of caching ByteBuffers"
This reverts commit c7be4e4937.
2014-08-13 21:46:36 +02:00
Norman Maurer
bb9ab03462 [#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:25:00 +02:00
Norman Maurer
ed7364f384 Revert "[#2762] Not expand ByteBuffer[] in ChannelOutboundBuffer"
This reverts commit 8cfc64fa1d as it may cause problem if a CompositeByteBuf has more then 1024 components.
2014-08-13 16:36:40 +02:00
Norman Maurer
8cfc64fa1d [#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:55:06 +02:00
Norman Maurer
c7be4e4937 [#2761] ChannelOutboundBuffer can cause data-corruption because of caching ByteBuffers
Motivation:

We cache the ByteBuffers in ChannelOutboundBuffer.nioBuffers() for the Entries in the ChannelOutboundBuffer to reduce some overhead. The problem is this can lead to data-corruption if an incomplete write happens and next time we try to do a non-gathering write.

To fix this we should remove the caching which does not help a lot anyway and just make the code buggy.

Modifications:

Remove the caching of ByteBuffers.

Result:

No more data-corruption.
2014-08-13 11:16:14 +02:00
Norman Maurer
c5b6808645 Allow to obtain RecvByteBufAllocator.Handle to allow more flexible implementations
Motivation:

At the moment it's only possible for a user to set the RecvByteBufAllocator for a Channel but not access the Handle once it is assigned. This makes it hard to write more flexible implementations.

Modifications:

Add a new method to the Channel.Unsafe to allow access the the used Handle for the Channel. The RecvByteBufAllocator.Handle is created lazily.

Result:

It's possible to write more flexible implementatons that allow to adjust stuff on the fly for a Handle that is used by a Channel
2014-08-12 06:54:29 +02:00
Norman Maurer
7764b0e3de [#2752] Add PendingWriteQueue for queue up writes
Motivation:

Sometimes ChannelHandler need to queue writes to some point and then process these. We currently have no datastructure for this so the user will use an Queue or something like this. The problem is with this Channel.isWritable() will not work as expected and so the user risk to write to fast. That's exactly what happened in our SslHandler. For this purpose we need to add a special datastructure which will also take care of update the Channel and so be sure that Channel.isWritable() works as expected.

Modifications:

- Add PendingWriteQueue which can be used for this purpose
- Make use of PendingWriteQueue in SslHandler

Result:

It is now possible to queue writes in a ChannelHandler and still have Channel.isWritable() working as expected. This also fixes #2752.
2014-08-12 06:41:08 +02:00
Jakob Buchgraber
220660e351 Deregistration of a Channel from an EventLoop
Motivation:

After a channel is created it's usually assigned to an
EventLoop. During the lifetime of a Channel the
EventLoop is then responsible for processing all I/O
and compute tasks of the Channel.

For various reasons (e.g. load balancing) a user might
require the ability for a Channel to be assigned to
another EventLoop during its lifetime.

Modifications:

Introduce under the hood changes that ensure that Netty's
thread model is obeyed during and after the deregistration
of a channel.

Ensure that tasks (one time and periodic) are executed by
the right EventLoop at all times.

Result:

A Channel can be deregistered from one and re-registered with
another EventLoop.
2014-08-11 15:28:46 -07:00
Jakob Buchgraber
f8bee2e94c Make Nio/EpollEventLoop run on a ForkJoinPool
Related issue: #2250

Motivation:

Prior to this commit, Netty's non blocking EventLoops
were each assigned a fixed thread by which all of the
EventLoop's I/O and handler logic would be performed.

While this is a fine approach for most users of Netty,
some advanced users require more flexibility in
scheduling the EventLoops.

Modifications:

Remove all direct usages of threads in MultithreadEventExecutorGroup,
SingleThreadEventExecutor et al., and introduce an Executor
abstraction instead.

The way to think about this change is, that each
iteration of an eventloop is now a task that gets scheduled
in a ForkJoinPool.

While the ForkJoinPool is the default, one also has the
ability to plug in his/her own Executor (aka thread pool)
into a EventLoop(Group).

Result:

Netty hands off thread management to a ForkJoinPool by default.
Users can also provide their own thread pool implementation and
get some control over scheduling Netty's EventLoops
2014-08-11 15:28:46 -07:00
Norman Maurer
4a3ef90381 Port ChannelOutboundBuffer and related changes from 4.0
Motivation:

We did various changes related to the ChannelOutboundBuffer in 4.0 branch. This commit port all of them over and so make sure our branches are synced in terms of these changes.

Related to [#2734], [#2709], [#2729], [#2710] and [#2693] .

Modification:
Port all changes that was done on the ChannelOutboundBuffer.

This includes the port of the following commits:
 - 73dfd7c01b
 - 997d8c32d2
 - e282e504f1
 - 5e5d1a58fd
 - 8ee3575e72
 - d6f0d12a86
 - 16e50765d1
 - 3f3e66c31a

Result:
 - Less memory usage by ChannelOutboundBuffer
 - Same code as in 4.0 branch
 - Make it possible to use ChannelOutboundBuffer with Channel implementation that not extends AbstractChannel
2014-08-05 15:00:56 +02:00
Norman Maurer
148b23b28b Fix broken test after change the maximal value of the pid. Part of [#2706] 2014-07-28 10:39:01 -07:00
Norman Maurer
d82cc29d0c [#2706] Allow pid up to 4194304
Motivation:

The PID_MAX_LIMIT on 64bit linux systems is 4194304 and on osx it is 99998. At the moment we use 65535 as an upper-limit which is too small.

Modifications:

Use 4194304 as max possible value

Result:

No more false-positives when try to detect current pid.
2014-07-28 10:16:25 -07:00
Norman Maurer
2131edadf2 [#2692] Allows notify ChannelFutureProgressListener on complete writes
Motivation:

We have some inconsistency when handling writes. Sometimes we call ChannelOutboundBuffer.progress(...) also for complete writes and sometimes not. We should call it always.

Modifications:

Correctly call ChannelOuboundBuffer.progress(...) for complete and incomplete writes.

Result:

Consistent behavior
2014-07-28 04:20:04 -07:00
Norman Maurer
ca0571cc9d Optimize native transport for gathering writes
Motivation:

While benchmarking the native transport with gathering writes I noticed that it is quite slow. This is due the fact that we need to do a lot of array copies to get the buffers into the iov array.

Modification:

Introduce a new class calles IovArray which allows to fill buffers directly in a iov array that can be passed over to JNI without any array copies. This gives a nice optimization in terms of speed when doing gathering writes.

Result:

Big performance improvement when doing gathering writes. See the included benchmark...

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

With this change:
[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-25 09:54:41 +02:00