This is an automated email from the ASF dual-hosted git repository.
adelapena pushed a commit to branch cassandra-2.2
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-2.2 by this push:
new d3e48e4 Make TokenMetadata's ring version increments atomic
d3e48e4 is described below
commit d3e48e4e00b1e8bd45e0694c5a8d9a0e941fa985
Author: Caleb Rackliffe <[email protected]>
AuthorDate: Mon Feb 1 17:11:31 2021 +0000
Make TokenMetadata's ring version increments atomic
patch by Caleb Rackliffe; reviewed by Andrés de la Peña and Yifan Cai for
CASSANDRA-16286
---
CHANGES.txt | 1 +
.../apache/cassandra/locator/TokenMetadata.java | 40 ++++++++++++++++++----
.../cassandra/locator/TokenMetadataTest.java | 30 ++++++++++++++++
3 files changed, 64 insertions(+), 7 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index ff865c5..36a244a 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.2.20
+ * Make TokenMetadata's ring version increments atomic (CASSANDRA-16286)
* Remove OpenJDK log warning (CASSANDRA-15563)
* Fix the histogram merge of the table metrics (CASSANDRA-16259)
diff --git a/src/java/org/apache/cassandra/locator/TokenMetadata.java
b/src/java/org/apache/cassandra/locator/TokenMetadata.java
index aafd7f9..44eb925 100644
--- a/src/java/org/apache/cassandra/locator/TokenMetadata.java
+++ b/src/java/org/apache/cassandra/locator/TokenMetadata.java
@@ -26,6 +26,8 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.annotation.concurrent.GuardedBy;
+
import com.google.common.base.Optional;
import com.google.common.collect.*;
import org.apache.commons.lang3.StringUtils;
@@ -106,7 +108,8 @@ public class TokenMetadata
};
// signals replication strategies that nodes have joined or left the ring
and they need to recompute ownership
- private volatile long ringVersion = 0;
+ @GuardedBy("lock")
+ private long ringVersion = 0;
public TokenMetadata()
{
@@ -443,7 +446,7 @@ public class TokenMetadata
}
endpointToHostIdMap.remove(endpoint);
sortedTokens = sortTokens();
- invalidateCachedRings();
+ invalidateCachedRingsUnsafe();
}
finally
{
@@ -463,7 +466,7 @@ public class TokenMetadata
{
logger.info("Updating topology for {}", endpoint);
topology.updateEndpoint(endpoint);
- invalidateCachedRings();
+ invalidateCachedRingsUnsafe();
}
finally
{
@@ -482,7 +485,7 @@ public class TokenMetadata
{
logger.info("Updating topology for all endpoints that have
changed");
topology.updateEndpoints();
- invalidateCachedRings();
+ invalidateCachedRingsUnsafe();
}
finally
{
@@ -510,7 +513,7 @@ public class TokenMetadata
}
}
- invalidateCachedRings();
+ invalidateCachedRingsUnsafe();
}
finally
{
@@ -1088,7 +1091,7 @@ public class TokenMetadata
movingEndpoints.clear();
sortedTokens.clear();
topology.clear();
- invalidateCachedRings();
+ invalidateCachedRingsUnsafe();
}
finally
{
@@ -1234,10 +1237,33 @@ public class TokenMetadata
public long getRingVersion()
{
- return ringVersion;
+ lock.readLock().lock();
+
+ try
+ {
+ return ringVersion;
+ }
+ finally
+ {
+ lock.readLock().unlock();
+ }
}
public void invalidateCachedRings()
+ {
+ lock.writeLock().lock();
+
+ try
+ {
+ invalidateCachedRingsUnsafe();
+ }
+ finally
+ {
+ lock.writeLock().unlock();
+ }
+ }
+
+ private void invalidateCachedRingsUnsafe()
{
ringVersion++;
cachedTokenMap.set(null);
diff --git a/test/unit/org/apache/cassandra/locator/TokenMetadataTest.java
b/test/unit/org/apache/cassandra/locator/TokenMetadataTest.java
index fc8095d..6cd5180 100644
--- a/test/unit/org/apache/cassandra/locator/TokenMetadataTest.java
+++ b/test/unit/org/apache/cassandra/locator/TokenMetadataTest.java
@@ -22,6 +22,9 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
import com.google.common.collect.Iterators;
import com.google.common.collect.Multimap;
@@ -67,6 +70,33 @@ public class TokenMetadataTest
assertEquals("Mismatch at index " + i + ": " + actual,
token(expected[i]), actual.get(i));
}
+ /**
+ * This test is very likely (but not guaranteed) to fail if ring
invalidations are ever allowed to interleave.
+ */
+ @Test
+ public void testConcurrentInvalidation() throws InterruptedException
+ {
+ long startVersion = tmd.getRingVersion();
+
+ ExecutorService pool =
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
+
+ int invalidations = 1024;
+
+ for (int i = 0; i < invalidations; i++)
+ pool.execute(new Runnable()
+ {
+ public void run()
+ {
+ tmd.invalidateCachedRings();
+ }
+ });
+
+ pool.shutdown();
+
+ assertTrue(pool.awaitTermination(30, TimeUnit.SECONDS));
+ assertEquals(invalidations + startVersion, tmd.getRingVersion());
+ }
+
@Test
public void testRingIterator()
{
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]