Skip to content

Commit 3ec03ca

Browse files
committed
HCD-247: Port CASSANDRA-19483 (#2170)
Ports CASSANDRA-19483 which added an option to group invalid legacy protocol magic exception with an no-spam logger. The test was slightly modified, it contains the timeout for log watching and ensure the logs start from the mark that happens before the exception. It ensures the test does not hang without the fix it covers. The motivation behind the port is to fix https://datastax.jira.com/browse/DSP-24639
1 parent ebe5a4f commit 3ec03ca

File tree

5 files changed

+87
-1
lines changed

5 files changed

+87
-1
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Merged from 4.0:
1212
* Add new concurrent_merkle_tree_requests config property to prevent OOM during multi-range and/or multi-table repairs (CASSANDRA-19336)
1313

1414
4.1
15+
* Optionally skip exception logging on invalid legacy protocol magic exception (CASSANDRA-19483)
1516
* Request-Based Native Transport Rate-Limiting (CASSANDRA-16663)
1617
* Add information whether sstables are dropped to SchemaChangeListener (CASSANDRA-17582)
1718
* Save sstable id as string in activity table (CASSANDRA-17585)

src/java/org/apache/cassandra/config/Config.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ public static void setClientMode(boolean clientMode)
635635
}
636636

637637
public volatile int consecutive_message_errors_threshold = 1;
638+
public volatile boolean invalid_legacy_protocol_magic_no_spam_enabled = false;
638639

639640
/**
640641
* Default compaction configuration, used if a table does not specify any.

src/java/org/apache/cassandra/config/DatabaseDescriptor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3707,4 +3707,9 @@ public static void setAnnBruteForceExpenseFactor(double factor)
37073707
Preconditions.checkArgument(factor <= StorageAttachedIndexOptions.MAXIMUM_ANN_BRUTE_FORCE_FACTOR, "ANN brute force expense factor must be at most " + StorageAttachedIndexOptions.MAXIMUM_ANN_BRUTE_FORCE_FACTOR);
37083708
conf.sai_options.ann_brute_force_factor = factor;
37093709
}
3710+
3711+
public static boolean getInvalidLegacyProtocolMagicNoSpamEnabled()
3712+
{
3713+
return conf.invalid_legacy_protocol_magic_no_spam_enabled;
3714+
}
37103715
}

src/java/org/apache/cassandra/net/InboundConnectionInitiator.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import java.net.SocketAddress;
2323
import java.util.List;
2424
import java.util.concurrent.Future;
25+
import java.util.concurrent.TimeUnit;
2526
import java.util.function.Consumer;
2627

2728
import com.google.common.annotations.VisibleForTesting;
29+
import com.google.common.base.Throwables;
2830
import org.slf4j.Logger;
2931
import org.slf4j.LoggerFactory;
3032

@@ -44,12 +46,14 @@
4446
import io.netty.handler.logging.LoggingHandler;
4547
import io.netty.handler.ssl.SslContext;
4648
import io.netty.handler.ssl.SslHandler;
49+
import org.apache.cassandra.config.DatabaseDescriptor;
4750
import org.apache.cassandra.config.EncryptionOptions;
4851
import org.apache.cassandra.exceptions.ConfigurationException;
4952
import org.apache.cassandra.locator.InetAddressAndPort;
5053
import org.apache.cassandra.net.OutboundConnectionSettings.Framing;
5154
import org.apache.cassandra.security.SSLFactory;
5255
import org.apache.cassandra.streaming.async.StreamingInboundHandler;
56+
import org.apache.cassandra.utils.NoSpamLogger;
5357
import org.apache.cassandra.utils.memory.BufferPools;
5458

5559
import static java.lang.Math.max;
@@ -67,6 +71,8 @@ public class InboundConnectionInitiator
6771
{
6872
private static final Logger logger = LoggerFactory.getLogger(InboundConnectionInitiator.class);
6973

74+
private static final NoSpamLogger noSpam5m = NoSpamLogger.getLogger(logger, 5, TimeUnit.MINUTES);
75+
7076
private static class Initializer extends ChannelInitializer<SocketChannel>
7177
{
7278
private final InboundConnectionSettings settings;
@@ -399,7 +405,11 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
399405

400406
private void exceptionCaught(Channel channel, Throwable cause)
401407
{
402-
logger.error("Failed to properly handshake with peer {}. Closing the channel.", channel.remoteAddress(), cause);
408+
if (cause != null && Throwables.getRootCause(cause) instanceof Message.InvalidLegacyProtocolMagic && DatabaseDescriptor.getInvalidLegacyProtocolMagicNoSpamEnabled())
409+
noSpam5m.warn("Failed to properly handshake with peer {}. Closing the channel. Invalid legacy protocol magic.", ((InetSocketAddress) channel.remoteAddress()).getHostName());
410+
else
411+
logger.error("Failed to properly handshake with peer {}. Closing the channel.", channel.remoteAddress(), cause);
412+
403413
try
404414
{
405415
failHandshake(channel);
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright DataStax, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.apache.cassandra.distributed.test;
18+
19+
import java.time.Duration;
20+
21+
import org.junit.Assert;
22+
import org.junit.BeforeClass;
23+
import org.junit.Test;
24+
25+
import org.apache.cassandra.config.DatabaseDescriptor;
26+
import org.apache.cassandra.distributed.Cluster;
27+
import org.apache.cassandra.distributed.api.Feature;
28+
import org.apache.cassandra.transport.SimpleClient;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
public class InternodeErrorExclusionTest extends TestBaseImpl
33+
{
34+
@BeforeClass
35+
public static void beforeClass2()
36+
{
37+
DatabaseDescriptor.clientInitialization();
38+
}
39+
40+
@Test
41+
public void testNoSpammingInvalidLegacyProtocolMagicException() throws Throwable
42+
{
43+
try (Cluster cluster = Cluster.build(1)
44+
.withConfig(c -> c
45+
.with(Feature.NETWORK)
46+
.set("invalid_legacy_protocol_magic_no_spam_enabled", true))
47+
.start())
48+
{
49+
long logMark = cluster.get(1).logs().mark();
50+
causeException();
51+
causeException();
52+
// we used no spam logger so the second message will not be emitted (the size is still 1).
53+
assertThat(cluster.get(1).logs().watchFor(logMark, Duration.ofSeconds(30), "Failed to properly handshake with peer localhost. Closing the channel. Invalid legacy protocol magic.").getResult()).hasSize(1);
54+
}
55+
}
56+
57+
private void causeException()
58+
{
59+
try (SimpleClient client = SimpleClient.builder("127.0.0.1", 7012).build())
60+
{
61+
client.connect(true);
62+
Assert.fail("Connection should fail");
63+
}
64+
catch (Exception e)
65+
{
66+
// expected
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)