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

blerer pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new b617690  Use immutable map for Read/WriteFailure exception and fix 
flaky test
b617690 is described below

commit b6176906e71620b37920eaf84fa51516b046bdce
Author: Kevin Gallardo <[email protected]>
AuthorDate: Thu Mar 12 15:35:05 2020 -0400

    Use immutable map for Read/WriteFailure exception and fix flaky test
    
    patch by Kevin Gallardo; reviewed by Benjamin Lerer for CASSANDRA-15543
---
 .../cassandra/exceptions/ReadFailureException.java |  4 ++-
 .../exceptions/RequestFailureException.java        | 21 ++++++------
 .../exceptions/WriteFailureException.java          |  4 ++-
 .../cassandra/transport/messages/ErrorMessage.java | 13 ++++++--
 .../distributed/test/SimpleReadWriteTest.java      | 37 ++++++++++++++--------
 5 files changed, 48 insertions(+), 31 deletions(-)

diff --git a/src/java/org/apache/cassandra/exceptions/ReadFailureException.java 
b/src/java/org/apache/cassandra/exceptions/ReadFailureException.java
index 72242fd..744cad4 100644
--- a/src/java/org/apache/cassandra/exceptions/ReadFailureException.java
+++ b/src/java/org/apache/cassandra/exceptions/ReadFailureException.java
@@ -19,6 +19,8 @@ package org.apache.cassandra.exceptions;
 
 import java.util.Map;
 
+import com.google.common.collect.ImmutableMap;
+
 import org.apache.cassandra.db.ConsistencyLevel;
 import org.apache.cassandra.locator.InetAddressAndPort;
 
@@ -28,7 +30,7 @@ public class ReadFailureException extends 
RequestFailureException
 
     public ReadFailureException(ConsistencyLevel consistency, int received, 
int blockFor, boolean dataPresent, Map<InetAddressAndPort, 
RequestFailureReason> failureReasonByEndpoint)
     {
-        super(ExceptionCode.READ_FAILURE, consistency, received, blockFor, 
failureReasonByEndpoint);
+        super(ExceptionCode.READ_FAILURE, consistency, received, blockFor, 
ImmutableMap.copyOf(failureReasonByEndpoint));
         this.dataPresent = dataPresent;
     }
 }
diff --git 
a/src/java/org/apache/cassandra/exceptions/RequestFailureException.java 
b/src/java/org/apache/cassandra/exceptions/RequestFailureException.java
index e982b44..56cee1a 100644
--- a/src/java/org/apache/cassandra/exceptions/RequestFailureException.java
+++ b/src/java/org/apache/cassandra/exceptions/RequestFailureException.java
@@ -17,7 +17,6 @@
  */
 package org.apache.cassandra.exceptions;
 
-import java.util.HashMap;
 import java.util.Map;
 import java.util.stream.Collectors;
 
@@ -33,21 +32,19 @@ public class RequestFailureException extends 
RequestExecutionException
 
     protected RequestFailureException(ExceptionCode code, ConsistencyLevel 
consistency, int received, int blockFor, Map<InetAddressAndPort, 
RequestFailureReason> failureReasonByEndpoint)
     {
-        super(code, String.format("Operation failed - received %d responses 
and %d failures: %s",
-                                  received,
-                                  failureReasonByEndpoint.size(),
-                                  
buildFailureString(failureReasonByEndpoint)));
+        super(code, buildErrorMessage(received, failureReasonByEndpoint));
         this.consistency = consistency;
         this.received = received;
         this.blockFor = blockFor;
+        this.failureReasonByEndpoint = failureReasonByEndpoint;
+    }
 
-        // It is possible for the passed in failureReasonByEndpoint map
-        // to have new entries added after this exception is constructed
-        // (e.g. a delayed failure response from a replica). So to be safe
-        // we make a copy of the map at this point to ensure it will not be
-        // modified any further. Otherwise, there could be implications when
-        // we encode this map for transport.
-        this.failureReasonByEndpoint = new HashMap<>(failureReasonByEndpoint);
+    private static String buildErrorMessage(int received, 
Map<InetAddressAndPort, RequestFailureReason> failures)
+    {
+        return String.format("Operation failed - received %d responses and %d 
failures: %s",
+                             received,
+                             failures.size(),
+                             buildFailureString(failures));
     }
 
     private static String buildFailureString(Map<InetAddressAndPort, 
RequestFailureReason> failures)
diff --git 
a/src/java/org/apache/cassandra/exceptions/WriteFailureException.java 
b/src/java/org/apache/cassandra/exceptions/WriteFailureException.java
index a7dc66a..bcda9e6 100644
--- a/src/java/org/apache/cassandra/exceptions/WriteFailureException.java
+++ b/src/java/org/apache/cassandra/exceptions/WriteFailureException.java
@@ -19,6 +19,8 @@ package org.apache.cassandra.exceptions;
 
 import java.util.Map;
 
+import com.google.common.collect.ImmutableMap;
+
 import org.apache.cassandra.db.ConsistencyLevel;
 import org.apache.cassandra.db.WriteType;
 import org.apache.cassandra.locator.InetAddressAndPort;
@@ -29,7 +31,7 @@ public class WriteFailureException extends 
RequestFailureException
 
     public WriteFailureException(ConsistencyLevel consistency, int received, 
int blockFor, WriteType writeType, Map<InetAddressAndPort, 
RequestFailureReason> failureReasonByEndpoint)
     {
-        super(ExceptionCode.WRITE_FAILURE, consistency, received, blockFor, 
failureReasonByEndpoint);
+        super(ExceptionCode.WRITE_FAILURE, consistency, received, blockFor, 
ImmutableMap.copyOf(failureReasonByEndpoint));
         this.writeType = writeType;
     }
 }
diff --git a/src/java/org/apache/cassandra/transport/messages/ErrorMessage.java 
b/src/java/org/apache/cassandra/transport/messages/ErrorMessage.java
index cd2af54..14b4ac4 100644
--- a/src/java/org/apache/cassandra/transport/messages/ErrorMessage.java
+++ b/src/java/org/apache/cassandra/transport/messages/ErrorMessage.java
@@ -18,14 +18,15 @@
 package org.apache.cassandra.transport.messages;
 
 import java.net.InetAddress;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.handler.codec.CodecException;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -89,15 +90,21 @@ public class ErrorMessage extends Message.Response
                         // The number of failures is also present in protocol 
v5, but used instead to specify the size of the failure map
                         int failure = body.readInt();
 
-                        Map<InetAddressAndPort, RequestFailureReason> 
failureReasonByEndpoint = new ConcurrentHashMap<>();
+                        Map<InetAddressAndPort, RequestFailureReason> 
failureReasonByEndpoint;
                         if (version.isGreaterOrEqualTo(ProtocolVersion.V5))
                         {
+                            ImmutableMap.Builder<InetAddressAndPort, 
RequestFailureReason> builder = ImmutableMap.builderWithExpectedSize(failure);
                             for (int i = 0; i < failure; i++)
                             {
                                 InetAddress endpoint = 
CBUtil.readInetAddr(body);
                                 RequestFailureReason failureReason = 
RequestFailureReason.fromCode(body.readUnsignedShort());
-                                
failureReasonByEndpoint.put(InetAddressAndPort.getByAddress(endpoint), 
failureReason);
+                                
builder.put(InetAddressAndPort.getByAddress(endpoint), failureReason);
                             }
+                            failureReasonByEndpoint = builder.build();
+                        }
+                        else
+                        {
+                            failureReasonByEndpoint = Collections.emptyMap();
                         }
 
                         if (code == ExceptionCode.WRITE_FAILURE)
diff --git 
a/test/distributed/org/apache/cassandra/distributed/test/SimpleReadWriteTest.java
 
b/test/distributed/org/apache/cassandra/distributed/test/SimpleReadWriteTest.java
index 4292598..e5ee240 100644
--- 
a/test/distributed/org/apache/cassandra/distributed/test/SimpleReadWriteTest.java
+++ 
b/test/distributed/org/apache/cassandra/distributed/test/SimpleReadWriteTest.java
@@ -35,6 +35,7 @@ import static org.junit.Assert.assertEquals;
 
 import static org.apache.cassandra.net.Verb.READ_REPAIR_REQ;
 import static 
org.apache.cassandra.net.OutboundConnections.LARGE_MESSAGE_THRESHOLD;
+import static org.junit.Assert.fail;
 
 public class SimpleReadWriteTest extends DistributedTestBase
 {
@@ -144,7 +145,7 @@ public class SimpleReadWriteTest extends DistributedTestBase
             try
             {
                 cluster.coordinator(1).execute("SELECT * FROM " + KEYSPACE + 
".tbl WHERE pk = 1", ConsistencyLevel.ALL);
-                Assert.fail("Read timeout expected but it did not occur");
+                fail("Read timeout expected but it did not occur");
             }
             catch (Exception ex)
             {
@@ -228,19 +229,24 @@ public class SimpleReadWriteTest extends 
DistributedTestBase
             // Introduce schema disagreement
             cluster.schemaChange("ALTER TABLE " + KEYSPACE + ".tbl ADD v2 
int", 1);
 
-            Exception thrown = null;
             try
             {
                 cluster.coordinator(1).execute("INSERT INTO " + KEYSPACE + 
".tbl (pk, ck, v1, v2) VALUES (2, 2, 2, 2)",
                                               ConsistencyLevel.QUORUM);
+                fail("Should have failed because of schema disagreement.");
             }
-            catch (RuntimeException e)
+            catch (Exception e)
             {
-                thrown = e;
-            }
+                Assert.assertTrue(e instanceof RuntimeException);
+                RuntimeException re = ((RuntimeException) e);
+                // for some reason, we get weird errors when trying to check 
class directly
+                // I suppose it has to do with some classloader manipulation 
going on
+                
Assert.assertTrue(re.getCause().getClass().toString().contains("WriteFailureException"));
+                // we may see 1 or 2 failures in here, because of the 
fail-fast behavior of AbstractWriteResponseHandler
+                
Assert.assertTrue(re.getMessage().contains("INCOMPATIBLE_SCHEMA from 127.0.0.2")
+                                  || 
re.getMessage().contains("INCOMPATIBLE_SCHEMA from 127.0.0.3"));
 
-            
Assert.assertTrue(thrown.getMessage().contains("INCOMPATIBLE_SCHEMA from 
127.0.0.2"));
-            
Assert.assertTrue(thrown.getMessage().contains("INCOMPATIBLE_SCHEMA from 
127.0.0.3"));
+            }
         }
     }
 
@@ -258,20 +264,23 @@ public class SimpleReadWriteTest extends 
DistributedTestBase
             // Introduce schema disagreement
             cluster.schemaChange("ALTER TABLE " + KEYSPACE + ".tbl ADD v2 
int", 1);
 
-            Exception thrown = null;
             try
             {
-                assertRows(cluster.coordinator(1).execute("SELECT * FROM " + 
KEYSPACE + ".tbl WHERE pk = 1",
-                                                         ConsistencyLevel.ALL),
-                           row(1, 1, 1, null));
+                cluster.coordinator(1).execute("SELECT * FROM " + KEYSPACE + 
".tbl WHERE pk = 1", ConsistencyLevel.ALL);
+                fail("Should have failed because of schema disagreement.");
             }
             catch (Exception e)
             {
-                thrown = e;
+                Assert.assertTrue(e instanceof RuntimeException);
+                RuntimeException re = ((RuntimeException) e);
+                // for some reason, we get weird errors when trying to check 
class directly
+                // I suppose it has to do with some classloader manipulation 
going on
+                
Assert.assertTrue(re.getCause().getClass().toString().contains("ReadFailureException"));
+                // we may see 1 or 2 failures in here, because of the 
fail-fast behavior of ReadCallback
+                
Assert.assertTrue(re.getMessage().contains("INCOMPATIBLE_SCHEMA from 127.0.0.2")
+                                  || 
re.getMessage().contains("INCOMPATIBLE_SCHEMA from 127.0.0.3"));
             }
 
-            
Assert.assertTrue(thrown.getMessage().contains("INCOMPATIBLE_SCHEMA from 
127.0.0.2"));
-            
Assert.assertTrue(thrown.getMessage().contains("INCOMPATIBLE_SCHEMA from 
127.0.0.3"));
         }
     }
 


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

Reply via email to