-
-
Notifications
You must be signed in to change notification settings - Fork 15.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
deregister and re-register, ClosedChannelException is thrown #5125
Comments
Can you provide some details as to why you say the
Sounds like this can be accomplished using a combination of primitives provided by Netty, and deregister/register could potentially be avoided:
|
First thanks very much for your in-time reply. private static void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
final NioUnsafe unsafe = ch.unsafe();
if (!k.isValid()) {
// close the channel if the key is not valid anymore
unsafe.close(unsafe.voidPromise());
return;
}
... channel close is triggered because of the invalidity of the SelectionKey, that's what I saw. Actually, I just want to control the flow of the incoming data, so I deregister the channel from eventloop when overflow and re-register it back to the same eventloop when underflow. I don't know if it's the typical usage of deregister/re-register paradigm, you said this could potentially be avoided by the way you suggest, but here Netty acts as a client reading data from MySQL Server, what I should control is the read buffer I think, not the write buffer, so why it's all channel write related methods you offer? Could you plz explain? (maybe a naive question,:-D) |
What is the state of the Channel and the associated selector at this point? The SelectionKey will not be valid under the following circumstances:
The SelectionKey is cancelled on deregister and an new SelectionKey is created on register ... can you tell me the state of
The typical way to control how much you are reading is to disable |
Yes, I really appreciate your sincere help on my problem. And glad to tell you it's been solved with your constructive suggestions. |
@purpleknightleo - Let me reopen this issue as I think you uncovered a bug. Would you mind keeping your current code base around so you can verify a PR I will submit? |
Ok, no problem. The versions I tried include 4.0.32/33/35, I don't know if it has been fixed in later version. As I mentioned, my need should be done with autoRead, but I think deregister/re-register can also satisfy though It's too heavy-weight. |
Motivation: If a channel is deregistered from an NioEventLoop the associated SelectionKey is cancelled. If the NioEventLoop has yet to process a pending event as a result of that SelectionKey then the NioEventLoop will see the SelecitonKey is invalid and close the channel. The NioEventLoop should not close a channel if it is not registered with that NioEventLoop. Modifications: - NioEventLoop.processSelectedKeys should check that the channel is still registered to itself before closing the channel Result: NioEventLoop doesn't close a channel that is no longer registered to it when the SelectionKey is invalid Fixes netty#5125
Motivation: If a channel is deregistered from an NioEventLoop the associated SelectionKey is cancelled. If the NioEventLoop has yet to process a pending event as a result of that SelectionKey then the NioEventLoop will see the SelecitonKey is invalid and close the channel. The NioEventLoop should not close a channel if it is not registered with that NioEventLoop. Modifications: - NioEventLoop.processSelectedKeys should check that the channel is still registered to itself before closing the channel Result: NioEventLoop doesn't close a channel that is no longer registered to it when the SelectionKey is invalid Fixes netty#5125
Sorry for the confusion... I would still recommend going the |
Motivation: If a channel is deregistered from an NioEventLoop the associated SelectionKey is cancelled. If the NioEventLoop has yet to process a pending event as a result of that SelectionKey then the NioEventLoop will see the SelecitonKey is invalid and close the channel. The NioEventLoop should not close a channel if it is not registered with that NioEventLoop. Modifications: - NioEventLoop.processSelectedKeys should check that the channel is still registered to itself before closing the channel Result: NioEventLoop doesn't close a channel that is no longer registered to it when the SelectionKey is invalid Fixes #5125
@Scottmitch Sorry to tell you your fix doesn't solve my previous issue, and I think the code logic you changed has a problem. You try to judge whether the channel is still registered to the eventloop by: if (eventLoop != this || eventLoop == null) {
return;
} But in my case, when I set one thread in NioEventLoopGroup, and two clients connect to my middleware, the final result is one client succeeds and the other dies due to the reason you have known. On the other hand, after deregistered from eventloop, we can still use ch.eventloop() to get the previously bound eventloop(of course, their real binding is dismissed due to deregistration). So when the selectionKey is invalid, it goes into the code logic pasted above, but actually here it satisfies eventloop !=null && eventloop == this(because here we have only one eventloop, it can't be another one), the close process still gets in as we don't expect. if (!k.isValid()) {
final EventLoop eventLoop;
try {
eventLoop = ch.eventLoop();
} catch (Throwable ignored) {
// If the channel implementation throws an exception because there is no event loop, we ignore this
// because we are only trying to determine if ch is registered to this event loop and thus has authority
// to close ch.
return;
}
// Only close ch if ch is still registerd to this EventLoop. ch could have deregistered from the event loop
// and thus the SelectionKey could be cancelled as part of the deregistration process, but the channel is
// still healthy and should not be closed.
// See https://github.com/netty/netty/issues/5125
if (eventLoop != this || eventLoop == null || (eventloop == this && !ch.isRegistered())) {
return;
}
// close the channel if the key is not valid anymore
unsafe.close(unsafe.voidPromise());
return;
} |
@purpleknightleo - Thanks for reporting back. The issue is that the isRegistered() will not be updated until the next event loop run, and I can't repo in this state (or any state :/). Let me think about this a bit. If you could provide a unit test which reproduces the behavior that would be much appreciated ... seems non-trivial to get into this state. |
Ok, after I try the newer version, I will give you a replay ASAP. Thanks. |
Motivation: 04e33fd was incomplete. The EventLoop may not change even if the channel is deregistered. Modifications: - Check if the channel is registered, and if not return before closing Result: Fixes netty#5125
Sorry again, your fix still can't solve my problem and sorry for not offering the unit test for some reason. if (eventLoop != this || !ch.isRegistered() || ch.selectionKey() != k) {
return;
} From you fixed code, I think since you said "isRegistered() will not be updated until the next event loop run", the !ch.isRegistered() judgement is of no use. On the other hand, ch.selectionKey() != k, why this? ch is got from k.attachment(), so I think these two objects are linked that ch.selectionKey() will always return k. |
The
In summary I can't reproduce the issue you are experiencing so I'm including things that should not be logically wrong ... but not sure it will impact the scenario you are running. I will need more information to debug this more:
I also tried to create a unit test to recreate the sequence of events which I think would repro this issue (deregister, processSelectedKey, register) but was not able to get |
@purpleknightleo - ping |
No update so closing |
Motivation: If a channel is deregistered from an NioEventLoop the associated SelectionKey is cancelled. If the NioEventLoop has yet to process a pending event as a result of that SelectionKey then the NioEventLoop will see the SelecitonKey is invalid and close the channel. The NioEventLoop should not close a channel if it is not registered with that NioEventLoop. Modifications: - NioEventLoop.processSelectedKeys should check that the channel is still registered to itself before closing the channel Result: NioEventLoop doesn't close a channel that is no longer registered to it when the SelectionKey is invalid Fixes netty#5125
Hi,
I'm doing a project on middle-ware for distributed database, and I want to use Netty as client connecting to MySQL reading data. But a problem gets me stuck for such a long time so I have to ask for help. The scenario is as below:
But here the strange thing is when I run a benchmark tool with N concurrent clients executing the same SQL constantly, and the NioEventLoopGroup is with M threads created(N>M), after a while the N-M connections are shown closed, leaving M connections active to the end.
After debugging, I find during the deregister and re-register, the channel bounded to the later failed connection will be closed(seems like the SelectionKey is set invalid) , so when trying to re-register, ClosedChannelException will be thrown.
And it should be mentioned that, if I remove the deregister and re-register logic it works fine, so obviously my usage of deregister and re-register could probably be wrong in some place, could you do me a favor instructing me to locate the reason? Thank you so much in advance.
I deregister the channel in MySQLClientDecoder, and re-register in my business logic when consuming the data received.
The text was updated successfully, but these errors were encountered: