-
Notifications
You must be signed in to change notification settings - Fork 1.9k
IGNITE-27554 Improve discovery handshake diagnostics for incompatible versions #12634
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
base: master
Are you sure you want to change the base?
Conversation
563a5e3 to
e7715bc
Compare
| import org.junit.Test; | ||
|
|
||
| /** Tests Java serialization header detection in discovery messages. */ | ||
| public class TcpDiscoveryIoSessionDifferentSerializationTest extends GridCommonAbstractTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we introduce a new test like this, let's rename to something like 'TcpDiscoveryDifferentClusterVersionsTest' and fix the javadoc respectively.
|
|
||
| TcpDiscoverySpi spi = (TcpDiscoverySpi)grid.configuration().getDiscoverySpi(); | ||
|
|
||
| TcpDiscoveryHandshakeRequest req = new TcpDiscoveryHandshakeRequest(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also check the the behaviour with TcpDiscoveryPingRequest / TcpDiscoveryPingResponse. WDYT?
| /** */ | ||
| @Test | ||
| public void testDetectJavaObjectStreamHeader() throws Exception { | ||
| IgniteEx grid = startGrid(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to write a full test with server nodes of 2 appropriate versions: 2.17 and RU-supporting 2.18.
| throw new EOFException(); | ||
|
|
||
| detectSslAlert(hdr); | ||
| detectJavaObjectStreamHeader(hdr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many messages does it affect? TcpDiscoveryHandshakeRequest and TcpDiscoveryPingRequest ? Do we need to check every message? If the additional bytes follow IGNITE_HEADER, we might validate it there. WDYT?
e7715bc to
cb80839
Compare
f7a25eb to
b782572
Compare
| } | ||
|
|
||
| try { | ||
| if (MESSAGE_SERIALIZATION != serMode) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially, detectJavaObjectStreamHeader was placed after detectSslAlert. The suggestion was to avoid checking serMode after the connection is established.
To achieve this, we need a way to notify session that these checks are no longer required. The current approach is that higher-level code calls switchToFastReader and it swaps the reader implementation. As a result, we eliminate a single if check.
However, to me this looks like a very minor optimization, because I/O dominates the cost compared to a simple conditional. Moreover, it seems to break the DIP, since higher-level code now has to be aware of implementation details of TcpDiscoveryIoSession
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want not to know about the session implementation, we might create another implementation of TcpDiscoveryIoSession which can check the protocol. Not sure worth it. Or we might bring some flag checkCompatibility to the session. At the first connection, we use session with checkCompatibility=true. On next permanent connection, we might recreate session with checkCompatibility=false. This flag is used in the message serialization.
c827749 to
4c66586
Compare
|
|
||
| throw new IgniteCheckedException(e); | ||
| /** Reads 4-byte header for diagnostics. */ | ||
| protected byte[] readHeader(byte serMode) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is colled only from a derived class.
| if (MESSAGE_SERIALIZATION != serMode) { | ||
| detectSslAlert(serMode, in); | ||
| /** Base discovery message reader. */ | ||
| private abstract class DiscoveryMessageReader { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this abstract class? I would use smth. like DefaultReader (not abstract) and CheckedReader.
| } | ||
|
|
||
| try { | ||
| if (MESSAGE_SERIALIZATION != serMode) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want not to know about the session implementation, we might create another implementation of TcpDiscoveryIoSession which can check the protocol. Not sure worth it. Or we might bring some flag checkCompatibility to the session. At the first connection, we use session with checkCompatibility=true. On next permanent connection, we might recreate session with checkCompatibility=false. This flag is used in the message serialization.
|
|
||
| try { | ||
| TcpDiscoveryIoSession ses = createSession(sock); | ||
| ses.switchToFastReader(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My overal idea is to use different or flagged createSession() so that it would choose which session to create checked or fast. Same in other places of switchToFastReader()
| if (MESSAGE_SERIALIZATION != serMode) { | ||
| detectSslAlert(serMode, in); | ||
| /** Base discovery message reader. */ | ||
| private abstract class DiscoveryMessageReader { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, looks as overhead. Too much new code, more complication. We alread have many ifs, switches in the message parsing. I belive, one more wouldn't change the roitine. Instead new subclasses, we might bring to the session some flag like checkProtocol. And just recreate session with/without it.
| /** */ | ||
| public class TcpDiscoveryDifferentClusterVersionsTest extends IgniteCompatibilityAbstractTest { | ||
| /** */ | ||
| private static final String SER_MODE_MSG = "serMode byte is expected"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this message is clear to a user. We might say something of an unexpected bytes/reading, old protocol version.
4c66586 to
826b486
Compare
Thank you for submitting the pull request to the Apache Ignite.
In order to streamline the review of the contribution
we ask you to ensure the following steps have been taken:
The Contribution Checklist
The description explains WHAT and WHY was made instead of HOW.
The following pattern must be used:
IGNITE-XXXX Change summarywhereXXXX- number of JIRA issue.(see the Maintainers list)
the
green visaattached to the JIRA ticket (see TC.Bot: Check PR)Notes
If you need any help, please email [email protected] or ask anу advice on http://asf.slack.com #ignite channel.