This is an automated email from the ASF dual-hosted git repository.

brandonwilliams pushed a commit to branch CASSANDRA-16588-trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit 9f038b877fee83bf1c450171337db602c32c360b
Author: Brandon Williams <[email protected]>
AuthorDate: Wed Apr 14 13:49:21 2021 -0500

    Ignore stale ack in shadow
---
 src/java/org/apache/cassandra/gms/Gossiper.java    | 15 ++++++++
 .../org/apache/cassandra/gms/ShadowRoundTest.java  | 40 ++++++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/src/java/org/apache/cassandra/gms/Gossiper.java 
b/src/java/org/apache/cassandra/gms/Gossiper.java
index b5434aa..923ffc8 100644
--- a/src/java/org/apache/cassandra/gms/Gossiper.java
+++ b/src/java/org/apache/cassandra/gms/Gossiper.java
@@ -1969,12 +1969,27 @@ public class Gossiper implements 
IFailureDetectionEventListener, GossiperMBean
         return (scheduledGossipTask != null) && 
(!scheduledGossipTask.isCancelled());
     }
 
+    public boolean isShadowRoundStateMap(Map<InetAddressAndPort, 
EndpointState> epStateMap)
+    {
+        // it is possible for a previously queued ack to be sent to us when we 
come back up in shadow
+        EndpointState localState = 
epStateMap.get(FBUtilities.getBroadcastAddressAndPort());
+        if (localState != null && epStateMap.size() == 1) // response only 
contains our IP
+        {
+            logger.debug("Not exiting shadow round because received bogus ACK 
{} -> {}", FBUtilities.getBroadcastAddressAndPort(), localState);
+            return false;
+        }
+        return true;
+    }
+
     protected void maybeFinishShadowRound(InetAddressAndPort respondent, 
boolean isInShadowRound, Map<InetAddressAndPort, EndpointState> epStateMap)
     {
         if (inShadowRound)
         {
             if (!isInShadowRound)
             {
+                if (!isShadowRoundStateMap(epStateMap))
+                    return;
+
                 if (!seeds.contains(respondent))
                     logger.warn("Received an ack from {}, who isn't a seed. 
Ensure your seed list includes a live node. Exiting shadow round",
                                 respondent);
diff --git a/test/unit/org/apache/cassandra/gms/ShadowRoundTest.java 
b/test/unit/org/apache/cassandra/gms/ShadowRoundTest.java
index 2bcbc50..f5d436f 100644
--- a/test/unit/org/apache/cassandra/gms/ShadowRoundTest.java
+++ b/test/unit/org/apache/cassandra/gms/ShadowRoundTest.java
@@ -28,6 +28,7 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.cassandra.config.Config;
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.db.Keyspace;
 import org.apache.cassandra.db.commitlog.CommitLog;
@@ -39,6 +40,7 @@ import org.apache.cassandra.net.MockMessagingService;
 import org.apache.cassandra.net.MockMessagingSpy;
 import org.apache.cassandra.net.Verb;
 import org.apache.cassandra.service.StorageService;
+import org.apache.cassandra.utils.FBUtilities;
 
 import static org.apache.cassandra.net.MockMessagingService.verb;
 import static org.junit.Assert.assertEquals;
@@ -117,4 +119,42 @@ public class ShadowRoundTest
         assertEquals(0, spyAck2.messagesIntercepted);
         assertEquals(0, spyMigrationReq.messagesIntercepted);
     }
+
+    @Test
+    public void testBadAckInShadow()
+    {
+        final AtomicBoolean ackSend = new AtomicBoolean(false);
+        MockMessagingSpy spySyn = 
MockMessagingService.when(verb(Verb.GOSSIP_DIGEST_SYN))
+                .respondN((msgOut, to) ->
+                {
+                    // ACK with bad data in shadow round
+                    if (!ackSend.compareAndSet(false, true))
+                    {
+                        while (!Gossiper.instance.isEnabled()) ;
+                    }
+
+                    HeartBeatState hb = new HeartBeatState(123, 456);
+                    EndpointState state = new EndpointState(hb);
+                    GossipDigestAck payload = new GossipDigestAck(
+                            Collections.singletonList(new 
GossipDigest(FBUtilities.getBroadcastAddressAndPort(), hb.getGeneration(), 
hb.getHeartBeatVersion())),
+                            
Collections.singletonMap(FBUtilities.getBroadcastAddressAndPort(), state));
+
+                    logger.warn("Simulating bad digest ACK reply");
+                    return Message.builder(Verb.GOSSIP_DIGEST_ACK, payload)
+                                  .from(to)
+                                  .build();
+                }, 1);
+
+
+        System.setProperty(Config.PROPERTY_PREFIX + "auto_bootstrap", "false");
+        try
+        {
+            StorageService.instance.initServer();
+        }
+        catch (Exception e)
+        {
+            assertEquals("Unable to gossip with any peers", e.getMessage());
+        }
+    }
+
 }

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to