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

dcapwell 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 af9439bcd7 IllegalArgumentException in Gossiper#order due to 
concurrent mutations to elements being applied
af9439bcd7 is described below

commit af9439bcd781756a0d845215c4c03c5fd8e74b86
Author: David Capwell <[email protected]>
AuthorDate: Mon Oct 10 15:39:52 2022 -0700

    IllegalArgumentException in Gossiper#order due to concurrent mutations to 
elements being applied
    
    patch by David Capwell; reviewed by Blake Eggleston for CASSANDRA-17908
---
 CHANGES.txt                                     |  1 +
 src/java/org/apache/cassandra/gms/Gossiper.java | 40 +++++++++++++++++--------
 2 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index c0a7723887..37ad298e45 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 4.2
+ * IllegalArgumentException in Gossiper#order due to concurrent mutations to 
elements being applied (CASSANDRA-17908)
  * Include estimated active compaction remaining write size when starting a 
new compaction (CASSANDRA-17931)
  * Mixed mode support for internode authentication during TLS upgrades 
(CASSANDRA-17923)
  * Revert Mockito downgrade from CASSANDRA-17750 (CASSANDRA-17496)
diff --git a/src/java/org/apache/cassandra/gms/Gossiper.java 
b/src/java/org/apache/cassandra/gms/Gossiper.java
index d0fab0cac5..d05ef94bea 100644
--- a/src/java/org/apache/cassandra/gms/Gossiper.java
+++ b/src/java/org/apache/cassandra/gms/Gossiper.java
@@ -1528,22 +1528,38 @@ public class Gossiper implements 
IFailureDetectionEventListener, GossiperMBean
      * In that case above, the {@link Map#entrySet()} ordering can be random, 
causing h4 to apply before h2, which will
      * be rejected by subscripers (only after updating gossip causing zero 
retries).
      */
-    private static Comparator<Entry<InetAddressAndPort, EndpointState>> 
STATE_MAP_ORDERING =
-    ((Comparator<Entry<InetAddressAndPort, EndpointState>>) (e1, e2) -> {
-        // check status first, make sure bootstrap status happens-after all 
others
-        if (BOOTSTRAPPING_STATUS.contains(getGossipStatus(e1.getValue())))
-            return 1;
-        if (BOOTSTRAPPING_STATUS.contains(getGossipStatus(e2.getValue())))
-            return -1;
-        return 0;
-    })
-    .thenComparingInt((Entry<InetAddressAndPort, EndpointState> e) -> 
e.getValue().getHeartBeatState().getGeneration())
-    .thenComparing(Entry::getKey);
+    private static Comparator<Entry<InetAddressAndPort, EndpointState>> 
stateOrderMap()
+    {
+        // There apears to be some edge cases where the state we are ordering 
get added to the global state causing
+        // ordering to change... to avoid that rely on a cache
+        // see CASSANDRA-17908
+        class Cache extends HashMap<InetAddressAndPort, EndpointState>
+        {
+            EndpointState get(Entry<InetAddressAndPort, EndpointState> e)
+            {
+                if (containsKey(e.getKey()))
+                    return get(e.getKey());
+                put(e.getKey(), new EndpointState(e.getValue()));
+                return get(e.getKey());
+            }
+        }
+        Cache cache = new Cache();
+        return ((Comparator<Entry<InetAddressAndPort, EndpointState>>) (e1, 
e2) -> {
+            // check status first, make sure bootstrap status happens-after 
all others
+            if (BOOTSTRAPPING_STATUS.contains(getGossipStatus(cache.get(e1))))
+                return 1;
+            if (BOOTSTRAPPING_STATUS.contains(getGossipStatus(cache.get(e2))))
+                return -1;
+            return 0;
+        })
+        .thenComparingInt((Entry<InetAddressAndPort, EndpointState> e) -> 
cache.get(e).getHeartBeatState().getGeneration())
+        .thenComparing(Entry::getKey);
+    }
 
     private static Iterable<Entry<InetAddressAndPort, EndpointState>> 
order(Map<InetAddressAndPort, EndpointState> epStateMap)
     {
         List<Entry<InetAddressAndPort, EndpointState>> list = new 
ArrayList<>(epStateMap.entrySet());
-        Collections.sort(list, STATE_MAP_ORDERING);
+        Collections.sort(list, stateOrderMap());
         return list;
     }
 


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

Reply via email to