From 7442fc02098c468447a4610d84023336f57545a4 Mon Sep 17 00:00:00 2001 From: Sylvain Lebresne Date: Fri, 7 Dec 2012 10:07:57 +0100 Subject: [PATCH 1/2] Don't generate UUID based on other nodes' address patch by slebresne; reviewed by jbellis for CASSANDRA-5002 --- CHANGES.txt | 1 + .../org/apache/cassandra/db/RowMutation.java | 2 +- .../apache/cassandra/db/marshal/UUIDType.java | 2 +- .../hadoop/ColumnFamilyRecordReader.java | 14 +-- .../cassandra/service/AntiEntropyService.java | 2 +- .../cassandra/streaming/StreamInSession.java | 2 +- .../cassandra/streaming/StreamOutSession.java | 2 +- .../streaming/StreamingRepairTask.java | 2 +- .../cassandra/thrift/CassandraServer.java | 2 +- .../apache/cassandra/tracing/TraceState.java | 2 +- .../transport/messages/ExecuteMessage.java | 2 +- .../transport/messages/PrepareMessage.java | 2 +- .../transport/messages/QueryMessage.java | 2 +- .../org/apache/cassandra/utils/CounterId.java | 2 +- .../apache/cassandra/utils/FBUtilities.java | 21 ++++ .../org/apache/cassandra/utils/UUIDGen.java | 99 +++++++++---------- .../cassandra/cql/jdbc/ClientUtilsTest.java | 2 +- .../db/marshal/CompositeTypeTest.java | 2 +- .../db/marshal/DynamicCompositeTypeTest.java | 2 +- .../cassandra/db/marshal/RoundTripTest.java | 4 +- .../db/marshal/TimeUUIDTypeTest.java | 14 +-- .../cassandra/db/marshal/UUIDTypeTest.java | 31 ++---- .../cassandra/io/LazilyCompactedRowTest.java | 2 +- .../streaming/SerializationsTest.java | 6 +- .../org/apache/cassandra/utils/UUIDTests.java | 14 +-- .../stress/operations/CqlInserter.java | 2 +- .../cassandra/stress/util/Operation.java | 2 +- 27 files changed, 116 insertions(+), 124 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 385dca63bc..2ffaee5c7c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,7 @@ * Fix preparing insert queries (CASSANDRA-5016) * Fix preparing queries with counter increment (CASSANDRA-5022) * Fix preparing updates with collections (CASSANDRA-5017) + * Don't generate UUID based on other node address (CASSANDRA-5002) Merged from 1.1 * Improve schema propagation performance (CASSANDRA-5025) diff --git a/src/java/org/apache/cassandra/db/RowMutation.java b/src/java/org/apache/cassandra/db/RowMutation.java index 4fcee8a405..a8e845dc73 100644 --- a/src/java/org/apache/cassandra/db/RowMutation.java +++ b/src/java/org/apache/cassandra/db/RowMutation.java @@ -105,7 +105,7 @@ public class RowMutation implements IMutation public static RowMutation hintFor(RowMutation mutation, UUID targetId) throws IOException { RowMutation rm = new RowMutation(Table.SYSTEM_KS, UUIDType.instance.decompose(targetId)); - UUID hintId = UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()); + UUID hintId = UUIDGen.getTimeUUID(); // determine the TTL for the RowMutation // this is set at the smallest GCGraceSeconds for any of the CFs in the RM diff --git a/src/java/org/apache/cassandra/db/marshal/UUIDType.java b/src/java/org/apache/cassandra/db/marshal/UUIDType.java index 53f87d2d9b..cef7b00249 100644 --- a/src/java/org/apache/cassandra/db/marshal/UUIDType.java +++ b/src/java/org/apache/cassandra/db/marshal/UUIDType.java @@ -212,7 +212,7 @@ public class UUIDType extends AbstractType } else if (source.toLowerCase().equals("now")) { - idBytes = ByteBuffer.wrap(UUIDGen.decompose(UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()))); + idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes()); } // Milliseconds since epoch? else if (source.matches("^\\d+$")) diff --git a/src/java/org/apache/cassandra/hadoop/ColumnFamilyRecordReader.java b/src/java/org/apache/cassandra/hadoop/ColumnFamilyRecordReader.java index f8134b90de..07a54601a9 100644 --- a/src/java/org/apache/cassandra/hadoop/ColumnFamilyRecordReader.java +++ b/src/java/org/apache/cassandra/hadoop/ColumnFamilyRecordReader.java @@ -19,8 +19,6 @@ package org.apache.cassandra.hadoop; import java.io.IOException; import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.*; @@ -197,17 +195,7 @@ public class ColumnFamilyRecordReader extends RecordReader localAddresses = new ArrayList(); - try - { - Enumeration nets = NetworkInterface.getNetworkInterfaces(); - while (nets.hasMoreElements()) - localAddresses.addAll(Collections.list(nets.nextElement().getInetAddresses())); - } - catch (SocketException e) - { - throw new AssertionError(e); - } + Collection localAddresses = FBUtilities.getAllLocalAddresses(); for (InetAddress address : localAddresses) { diff --git a/src/java/org/apache/cassandra/service/AntiEntropyService.java b/src/java/org/apache/cassandra/service/AntiEntropyService.java index 9f97f95a16..a04402fa9f 100644 --- a/src/java/org/apache/cassandra/service/AntiEntropyService.java +++ b/src/java/org/apache/cassandra/service/AntiEntropyService.java @@ -603,7 +603,7 @@ public class AntiEntropyService public RepairSession(Range range, String tablename, boolean isSequential, boolean isLocal, String... cfnames) { - this(UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()).toString(), range, tablename, isSequential, isLocal, cfnames); + this(UUIDGen.getTimeUUID().toString(), range, tablename, isSequential, isLocal, cfnames); } private RepairSession(String id, Range range, String tablename, boolean isSequential, boolean isLocal, String[] cfnames) diff --git a/src/java/org/apache/cassandra/streaming/StreamInSession.java b/src/java/org/apache/cassandra/streaming/StreamInSession.java index a29acc74b2..96c31da0f4 100644 --- a/src/java/org/apache/cassandra/streaming/StreamInSession.java +++ b/src/java/org/apache/cassandra/streaming/StreamInSession.java @@ -59,7 +59,7 @@ public class StreamInSession extends AbstractStreamSession public static StreamInSession create(InetAddress host, IStreamCallback callback) { - StreamInSession session = new StreamInSession(host, UUIDGen.makeType1UUIDFromHost(host), callback); + StreamInSession session = new StreamInSession(host, UUIDGen.getTimeUUID(), callback); sessions.put(session.getSessionId(), session); return session; } diff --git a/src/java/org/apache/cassandra/streaming/StreamOutSession.java b/src/java/org/apache/cassandra/streaming/StreamOutSession.java index ad312ff131..dbdbad99aa 100644 --- a/src/java/org/apache/cassandra/streaming/StreamOutSession.java +++ b/src/java/org/apache/cassandra/streaming/StreamOutSession.java @@ -44,7 +44,7 @@ public class StreamOutSession extends AbstractStreamSession public static StreamOutSession create(String table, InetAddress host, IStreamCallback callback) { - return create(table, host, UUIDGen.makeType1UUIDFromHost(host), callback); + return create(table, host, UUIDGen.getTimeUUID(), callback); } public static StreamOutSession create(String table, InetAddress host, UUID sessionId) diff --git a/src/java/org/apache/cassandra/streaming/StreamingRepairTask.java b/src/java/org/apache/cassandra/streaming/StreamingRepairTask.java index 33c3f39920..5d456a6ecb 100644 --- a/src/java/org/apache/cassandra/streaming/StreamingRepairTask.java +++ b/src/java/org/apache/cassandra/streaming/StreamingRepairTask.java @@ -90,7 +90,7 @@ public class StreamingRepairTask implements Runnable public static StreamingRepairTask create(InetAddress ep1, InetAddress ep2, String tableName, String cfName, Collection> ranges, Runnable callback) { InetAddress local = FBUtilities.getBroadcastAddress(); - UUID id = UUIDGen.makeType1UUIDFromHost(local); + UUID id = UUIDGen.getTimeUUID(); // We can take anyone of the node as source or destination, however if one is localhost, we put at source to avoid a forwarding InetAddress src = ep2.equals(local) ? ep2 : ep1; InetAddress dst = ep2.equals(local) ? ep1 : ep2; diff --git a/src/java/org/apache/cassandra/thrift/CassandraServer.java b/src/java/org/apache/cassandra/thrift/CassandraServer.java index 5f05057f7f..425574257f 100644 --- a/src/java/org/apache/cassandra/thrift/CassandraServer.java +++ b/src/java/org/apache/cassandra/thrift/CassandraServer.java @@ -1817,7 +1817,7 @@ public class CassandraServer implements Cassandra.Iface public ByteBuffer trace_next_query() throws TException { - UUID sessionId = UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()); + UUID sessionId = UUIDGen.getTimeUUID(); state().getQueryState().prepareTracingSession(sessionId); return TimeUUIDType.instance.decompose(sessionId); } diff --git a/src/java/org/apache/cassandra/tracing/TraceState.java b/src/java/org/apache/cassandra/tracing/TraceState.java index e60998f323..8fb3119d38 100644 --- a/src/java/org/apache/cassandra/tracing/TraceState.java +++ b/src/java/org/apache/cassandra/tracing/TraceState.java @@ -85,7 +85,7 @@ public class TraceState public void trace(final String message) { final int elapsed = elapsed(); - final ByteBuffer eventId = ByteBufferUtil.bytes(UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress())); + final ByteBuffer eventId = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes()); final String threadName = Thread.currentThread().getName(); diff --git a/src/java/org/apache/cassandra/transport/messages/ExecuteMessage.java b/src/java/org/apache/cassandra/transport/messages/ExecuteMessage.java index ccddbc7f15..3aca4c5e0a 100644 --- a/src/java/org/apache/cassandra/transport/messages/ExecuteMessage.java +++ b/src/java/org/apache/cassandra/transport/messages/ExecuteMessage.java @@ -108,7 +108,7 @@ public class ExecuteMessage extends Message.Request UUID tracingId = null; if (isTracingRequested()) { - tracingId = UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()); + tracingId = UUIDGen.getTimeUUID(); state.prepareTracingSession(tracingId); } diff --git a/src/java/org/apache/cassandra/transport/messages/PrepareMessage.java b/src/java/org/apache/cassandra/transport/messages/PrepareMessage.java index 06f25bf289..5c1d1b91dd 100644 --- a/src/java/org/apache/cassandra/transport/messages/PrepareMessage.java +++ b/src/java/org/apache/cassandra/transport/messages/PrepareMessage.java @@ -65,7 +65,7 @@ public class PrepareMessage extends Message.Request UUID tracingId = null; if (isTracingRequested()) { - tracingId = UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()); + tracingId = UUIDGen.getTimeUUID(); state.prepareTracingSession(tracingId); } diff --git a/src/java/org/apache/cassandra/transport/messages/QueryMessage.java b/src/java/org/apache/cassandra/transport/messages/QueryMessage.java index 872782dbe2..7b8047068f 100644 --- a/src/java/org/apache/cassandra/transport/messages/QueryMessage.java +++ b/src/java/org/apache/cassandra/transport/messages/QueryMessage.java @@ -75,7 +75,7 @@ public class QueryMessage extends Message.Request UUID tracingId = null; if (isTracingRequested()) { - tracingId = UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()); + tracingId = UUIDGen.getTimeUUID(); state.prepareTracingSession(tracingId); } diff --git a/src/java/org/apache/cassandra/utils/CounterId.java b/src/java/org/apache/cassandra/utils/CounterId.java index 2520d9fe42..f37c396014 100644 --- a/src/java/org/apache/cassandra/utils/CounterId.java +++ b/src/java/org/apache/cassandra/utils/CounterId.java @@ -117,7 +117,7 @@ public class CounterId implements Comparable public static CounterId generate() { - return new CounterId(ByteBuffer.wrap(UUIDGen.decompose(UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress())))); + return new CounterId(ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes())); } /* diff --git a/src/java/org/apache/cassandra/utils/FBUtilities.java b/src/java/org/apache/cassandra/utils/FBUtilities.java index 783ce48e32..fd3ad4ce2c 100644 --- a/src/java/org/apache/cassandra/utils/FBUtilities.java +++ b/src/java/org/apache/cassandra/utils/FBUtilities.java @@ -22,6 +22,8 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.math.BigInteger; import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; import java.net.URL; import java.net.UnknownHostException; import java.nio.ByteBuffer; @@ -154,6 +156,25 @@ public class FBUtilities return broadcastInetAddress; } + public static Collection getAllLocalAddresses() + { + Set localAddresses = new HashSet(); + try + { + Enumeration nets = NetworkInterface.getNetworkInterfaces(); + if (nets != null) + { + while (nets.hasMoreElements()) + localAddresses.addAll(Collections.list(nets.nextElement().getInetAddresses())); + } + } + catch (SocketException e) + { + throw new AssertionError(e); + } + return localAddresses; + } + /** * Given two bit arrays represented as BigIntegers, containing the given * number of significant bits, calculate a midpoint. diff --git a/src/java/org/apache/cassandra/utils/UUIDGen.java b/src/java/org/apache/cassandra/utils/UUIDGen.java index e207c2060e..7da9b5b22e 100644 --- a/src/java/org/apache/cassandra/utils/UUIDGen.java +++ b/src/java/org/apache/cassandra/utils/UUIDGen.java @@ -18,11 +18,14 @@ package org.apache.cassandra.utils; import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; import java.util.Random; import java.util.UUID; @@ -34,54 +37,27 @@ public class UUIDGen { // A grand day! millis at 00:00:00.000 15 Oct 1582. private static final long START_EPOCH = -12219292800000L; - private static final long clock = new Random(System.currentTimeMillis()).nextLong(); + private static final long clockSeqAndNode = makeClockSeqAndNode(); // placement of this singleton is important. It needs to be instantiated *AFTER* the other statics. private static final UUIDGen instance = new UUIDGen(); private long lastNanos; - private final Map nodeCache = new HashMap(); - - private static final ThreadLocal localMD5Digest = new ThreadLocal() - { - @Override - protected MessageDigest initialValue() - { - try - { - return MessageDigest.getInstance("MD5"); - } - catch (NoSuchAlgorithmException nsae) - { - throw new RuntimeException("MD5 digest algorithm is not available", nsae); - } - } - - @Override - public MessageDigest get() - { - MessageDigest digest = super.get(); - digest.reset(); - return digest; - } - }; private UUIDGen() { - // make sure someone didn't whack the clock by changing the order of instantiation. - if (clock == 0) throw new RuntimeException("singleton instantiation is misplaced."); + // make sure someone didn't whack the clockSeqAndNode by changing the order of instantiation. + if (clockSeqAndNode == 0) throw new RuntimeException("singleton instantiation is misplaced."); } /** - * Creates a type 1 UUID (time-based UUID) that substitutes a hash of - * an IP address in place of the MAC (unavailable to Java). + * Creates a type 1 UUID (time-based UUID). * - * @param addr the host address to use * @return a UUID instance */ - public static UUID makeType1UUIDFromHost(InetAddress addr) + public static UUID getTimeUUID() { - return new UUID(instance.createTimeSafe(), instance.getClockSeqAndNode(addr)); + return new UUID(instance.createTimeSafe(), clockSeqAndNode); } /** creates a type 1 uuid from raw bytes. */ @@ -151,7 +127,7 @@ public class UUIDGen private static byte[] createTimeUUIDBytes(long msb) { - long lsb = instance.getClockSeqAndNode(FBUtilities.getLocalAddress()); + long lsb = clockSeqAndNode; byte[] uuidBytes = new byte[16]; for (int i = 0; i < 8; i++) @@ -177,13 +153,14 @@ public class UUIDGen return (uuid.timestamp() / 10000) + START_EPOCH; } - // todo: could cache value if we assume node doesn't change. - private long getClockSeqAndNode(InetAddress addr) + private static long makeClockSeqAndNode() { + long clock = new Random(System.currentTimeMillis()).nextLong(); + long lsb = 0; lsb |= 0x8000000000000000L; // variant (2 bits) lsb |= (clock & 0x0000000000003FFFL) << 48; // clock sequence (14 bits) - lsb |= makeNode(addr); // 6 bytes + lsb |= makeNode(); // 6 bytes return lsb; } @@ -221,31 +198,49 @@ public class UUIDGen return msb; } - // Lazily create node hashes, and cache them for later - private long makeNode(InetAddress addr) + private static long makeNode() { - if (nodeCache.containsKey(addr)) - return nodeCache.get(addr); + /* + * We don't have access to the MAC address but need to generate a node part + * that identify this host as uniquely as possible. + * The spec says that one option is to take as many source that identify + * this node as possible and hash them together. That's what we do here by + * gathering all the ip of this host. + * Note that FBUtilities.getBroadcastAddress() should be enough to uniquely + * identify the node *in the cluster* but it triggers DatabaseDescriptor + * instanciation and the UUID generator is used in Stress for instance, + * where we don't want to require the yaml. + */ + Collection localAddresses = FBUtilities.getAllLocalAddresses(); + if (localAddresses.isEmpty()) + throw new RuntimeException("Cannot generate the node component of the UUID because cannot retrieve any IP addresses."); // ideally, we'd use the MAC address, but java doesn't expose that. - byte[] hash = hash(addr.toString()); + byte[] hash = hash(localAddresses); long node = 0; for (int i = 0; i < Math.min(6, hash.length); i++) node |= (0x00000000000000ff & (long)hash[i]) << (5-i)*8; assert (0xff00000000000000L & node) == 0; - nodeCache.put(addr, node); - - return node; + // Since we don't use the mac address, the spec says that multicast + // bit (least significant bit of the first octet of the node ID) must be 1. + return node | 0x0000010000000000L; } - private static byte[] hash(String... data) + private static byte[] hash(Collection data) { - MessageDigest messageDigest = localMD5Digest.get(); - for(String block : data) - messageDigest.update(block.getBytes()); + try + { + MessageDigest messageDigest = MessageDigest.getInstance("MD5"); + for(InetAddress addr : data) + messageDigest.update(addr.getAddress()); - return messageDigest.digest(); + return messageDigest.digest(); + } + catch (NoSuchAlgorithmException nsae) + { + throw new RuntimeException("MD5 digest algorithm is not available", nsae); + } } } diff --git a/test/unit/org/apache/cassandra/cql/jdbc/ClientUtilsTest.java b/test/unit/org/apache/cassandra/cql/jdbc/ClientUtilsTest.java index 76362bf2ad..b584d1e4c5 100644 --- a/test/unit/org/apache/cassandra/cql/jdbc/ClientUtilsTest.java +++ b/test/unit/org/apache/cassandra/cql/jdbc/ClientUtilsTest.java @@ -56,7 +56,7 @@ public class ClientUtilsTest JdbcUTF8.instance.compose(JdbcUTF8.instance.decompose("string")); // UUIDGen - UUID uuid = UUIDGen.makeType1UUIDFromHost(InetAddress.getLocalHost()); + UUID uuid = UUIDGen.getTimeUUID(); JdbcTimeUUID.instance.compose(JdbcTimeUUID.instance.decompose(uuid)); JdbcUUID.instance.compose(JdbcUUID.instance.decompose(uuid)); JdbcLexicalUUID.instance.compose(JdbcLexicalUUID.instance.decompose(uuid)); diff --git a/test/unit/org/apache/cassandra/db/marshal/CompositeTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/CompositeTypeTest.java index d6c2e4fed2..2ed715ef16 100644 --- a/test/unit/org/apache/cassandra/db/marshal/CompositeTypeTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/CompositeTypeTest.java @@ -56,7 +56,7 @@ public class CompositeTypeTest extends SchemaLoader static { for (int i = 0; i < UUID_COUNT; ++i) - uuids[i] = UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()); + uuids[i] = UUIDGen.getTimeUUID(); } @Test diff --git a/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java index 08f772f425..af9e85a4d0 100644 --- a/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java @@ -52,7 +52,7 @@ public class DynamicCompositeTypeTest extends SchemaLoader static { for (int i = 0; i < UUID_COUNT; ++i) - uuids[i] = UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()); + uuids[i] = UUIDGen.getTimeUUID(); } @Test diff --git a/test/unit/org/apache/cassandra/db/marshal/RoundTripTest.java b/test/unit/org/apache/cassandra/db/marshal/RoundTripTest.java index 9cb761c4d0..ef34ac5c4c 100644 --- a/test/unit/org/apache/cassandra/db/marshal/RoundTripTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/RoundTripTest.java @@ -97,7 +97,7 @@ public class RoundTripTest @Test public void testLexicalUUID() { - UUID uuid = UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()); + UUID uuid = UUIDGen.getTimeUUID(); assert JdbcLexicalUUID.instance.getString(LexicalUUIDType.instance.fromString(uuid.toString())) .equals(uuid.toString()); assert LexicalUUIDType.instance.fromString(LexicalUUIDType.instance.getString(ByteBuffer.wrap(UUIDGen.decompose(uuid)))) @@ -109,7 +109,7 @@ public class RoundTripTest @Test public void testTimeUUID() { - UUID uuid = UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()); + UUID uuid = UUIDGen.getTimeUUID(); assert TimeUUIDType.instance.getString(TimeUUIDType.instance.fromString(uuid.toString())) .equals(uuid.toString()); assert TimeUUIDType.instance.fromString(TimeUUIDType.instance.getString(ByteBuffer.wrap(UUIDGen.decompose(uuid)))) diff --git a/test/unit/org/apache/cassandra/db/marshal/TimeUUIDTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/TimeUUIDTypeTest.java index 256fba46fe..e6c0393a7c 100644 --- a/test/unit/org/apache/cassandra/db/marshal/TimeUUIDTypeTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/TimeUUIDTypeTest.java @@ -37,7 +37,7 @@ public class TimeUUIDTypeTest @Test public void testEquality() throws UnknownHostException { - UUID a = UUIDGen.makeType1UUIDFromHost(InetAddress.getLocalHost()); + UUID a = UUIDGen.getTimeUUID(); UUID b = new UUID(a.getMostSignificantBits(), a.getLeastSignificantBits()); timeUUIDType.validate(ByteBuffer.wrap(UUIDGen.decompose(a))); @@ -48,9 +48,9 @@ public class TimeUUIDTypeTest @Test public void testSmaller() throws UnknownHostException { - UUID a = UUIDGen.makeType1UUIDFromHost(InetAddress.getLocalHost()); - UUID b = UUIDGen.makeType1UUIDFromHost(InetAddress.getLocalHost()); - UUID c = UUIDGen.makeType1UUIDFromHost(InetAddress.getLocalHost()); + UUID a = UUIDGen.getTimeUUID(); + UUID b = UUIDGen.getTimeUUID(); + UUID c = UUIDGen.getTimeUUID(); timeUUIDType.validate(ByteBuffer.wrap(UUIDGen.decompose(a))); timeUUIDType.validate(ByteBuffer.wrap(UUIDGen.decompose(b))); @@ -64,9 +64,9 @@ public class TimeUUIDTypeTest @Test public void testBigger() throws UnknownHostException { - UUID a = UUIDGen.makeType1UUIDFromHost(InetAddress.getLocalHost()); - UUID b = UUIDGen.makeType1UUIDFromHost(InetAddress.getLocalHost()); - UUID c = UUIDGen.makeType1UUIDFromHost(InetAddress.getLocalHost()); + UUID a = UUIDGen.getTimeUUID(); + UUID b = UUIDGen.getTimeUUID(); + UUID c = UUIDGen.getTimeUUID(); timeUUIDType.validate(ByteBuffer.wrap(UUIDGen.decompose(a))); timeUUIDType.validate(ByteBuffer.wrap(UUIDGen.decompose(b))); diff --git a/test/unit/org/apache/cassandra/db/marshal/UUIDTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/UUIDTypeTest.java index 0f75d2a2f4..3d6d5aa998 100644 --- a/test/unit/org/apache/cassandra/db/marshal/UUIDTypeTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/UUIDTypeTest.java @@ -23,8 +23,6 @@ package org.apache.cassandra.db.marshal; import static org.junit.Assert.assertEquals; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Random; @@ -46,8 +44,8 @@ public class UUIDTypeTest public void testCompare() { - UUID t1 = newTimeBasedUUID(); - UUID t2 = newTimeBasedUUID(); + UUID t1 = UUIDGen.getTimeUUID(); + UUID t2 = UUIDGen.getTimeUUID(); testCompare(null, t2, -1); testCompare(t1, null, 1); @@ -76,17 +74,6 @@ public class UUIDTypeTest } } - public UUID newTimeBasedUUID() - { - try - { - return UUIDGen.makeType1UUIDFromHost(InetAddress.getLocalHost()); - } catch (UnknownHostException e) - { - throw new RuntimeException(e); - } - } - public static int compareUnsigned(long n1, long n2) { if (n1 == n2) @@ -181,7 +168,7 @@ public class UUIDTypeTest @Test public void testTimeEquality() { - UUID a = newTimeBasedUUID(); + UUID a = UUIDGen.getTimeUUID(); UUID b = new UUID(a.getMostSignificantBits(), a.getLeastSignificantBits()); @@ -191,9 +178,9 @@ public class UUIDTypeTest @Test public void testTimeSmaller() { - UUID a = newTimeBasedUUID(); - UUID b = newTimeBasedUUID(); - UUID c = newTimeBasedUUID(); + UUID a = UUIDGen.getTimeUUID(); + UUID b = UUIDGen.getTimeUUID(); + UUID c = UUIDGen.getTimeUUID(); assert uuidType.compare(bytebuffer(a), bytebuffer(b)) < 0; assert uuidType.compare(bytebuffer(b), bytebuffer(c)) < 0; @@ -203,9 +190,9 @@ public class UUIDTypeTest @Test public void testTimeBigger() { - UUID a = newTimeBasedUUID(); - UUID b = newTimeBasedUUID(); - UUID c = newTimeBasedUUID(); + UUID a = UUIDGen.getTimeUUID(); + UUID b = UUIDGen.getTimeUUID(); + UUID c = UUIDGen.getTimeUUID(); assert uuidType.compare(bytebuffer(c), bytebuffer(b)) > 0; assert uuidType.compare(bytebuffer(b), bytebuffer(a)) > 0; diff --git a/test/unit/org/apache/cassandra/io/LazilyCompactedRowTest.java b/test/unit/org/apache/cassandra/io/LazilyCompactedRowTest.java index 060836664d..1a289e8047 100644 --- a/test/unit/org/apache/cassandra/io/LazilyCompactedRowTest.java +++ b/test/unit/org/apache/cassandra/io/LazilyCompactedRowTest.java @@ -304,7 +304,7 @@ public class LazilyCompactedRowTest extends SchemaLoader ByteBuffer key = ByteBufferUtil.bytes("k"); RowMutation rm = new RowMutation("Keyspace4", key); - ByteBuffer scKey = ByteBuffer.wrap(UUIDGen.decompose(UUIDGen.makeType1UUIDFromHost(FBUtilities.getBroadcastAddress()))); + ByteBuffer scKey = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes()); rm.add(new QueryPath("Super5", scKey , ByteBufferUtil.bytes("c")), ByteBufferUtil.EMPTY_BYTE_BUFFER, 0); rm.apply(); cfs.forceBlockingFlush(); diff --git a/test/unit/org/apache/cassandra/streaming/SerializationsTest.java b/test/unit/org/apache/cassandra/streaming/SerializationsTest.java index 47990abdd3..be6f2dda56 100644 --- a/test/unit/org/apache/cassandra/streaming/SerializationsTest.java +++ b/test/unit/org/apache/cassandra/streaming/SerializationsTest.java @@ -82,7 +82,7 @@ public class SerializationsTest extends AbstractSerializationsTester private void testStreamHeaderWrite() throws IOException { - UUID sessionId = UUIDGen.makeType1UUIDFromHost(FBUtilities.getLocalAddress()); + UUID sessionId = UUIDGen.getTimeUUID(); StreamHeader sh0 = new StreamHeader("Keyspace1", sessionId, makePendingFile(true, 100, OperationType.BOOTSTRAP)); StreamHeader sh1 = new StreamHeader("Keyspace1", sessionId, makePendingFile(false, 100, OperationType.BOOTSTRAP)); Collection files = new ArrayList(); @@ -125,7 +125,7 @@ public class SerializationsTest extends AbstractSerializationsTester private void testStreamReplyWrite() throws IOException { - UUID sessionId = UUIDGen.makeType1UUIDFromHost(FBUtilities.getLocalAddress()); + UUID sessionId = UUIDGen.getTimeUUID(); StreamReply rep = new StreamReply("this is a file", sessionId, StreamReply.Status.FILE_FINISHED); DataOutputStream out = getOutput("streaming.StreamReply.bin"); StreamReply.serializer.serialize(rep, out, getVersion()); @@ -159,7 +159,7 @@ public class SerializationsTest extends AbstractSerializationsTester private void testStreamRequestMessageWrite() throws IOException { - UUID sessionId = UUIDGen.makeType1UUIDFromHost(FBUtilities.getLocalAddress()); + UUID sessionId = UUIDGen.getTimeUUID(); Collection> ranges = new ArrayList>(); for (int i = 0; i < 5; i++) ranges.add(new Range(new BytesToken(ByteBufferUtil.bytes(Integer.toString(10*i))), new BytesToken(ByteBufferUtil.bytes(Integer.toString(10*i+5))))); diff --git a/test/unit/org/apache/cassandra/utils/UUIDTests.java b/test/unit/org/apache/cassandra/utils/UUIDTests.java index 6cf96d02ef..970c753390 100644 --- a/test/unit/org/apache/cassandra/utils/UUIDTests.java +++ b/test/unit/org/apache/cassandra/utils/UUIDTests.java @@ -37,15 +37,15 @@ public class UUIDTests public void verifyType1() throws UnknownHostException { - UUID uuid = UUIDGen.makeType1UUIDFromHost(InetAddress.getByName("127.0.0.1")); + UUID uuid = UUIDGen.getTimeUUID(); assert uuid.version() == 1; } @Test public void verifyOrdering1() throws UnknownHostException { - UUID one = UUIDGen.makeType1UUIDFromHost(InetAddress.getByName("127.0.0.1")); - UUID two = UUIDGen.makeType1UUIDFromHost(InetAddress.getByName("127.0.0.2")); + UUID one = UUIDGen.getTimeUUID(); + UUID two = UUIDGen.getTimeUUID(); assert one.timestamp() < two.timestamp(); } @@ -53,7 +53,7 @@ public class UUIDTests @Test public void testDecomposeAndRaw() throws UnknownHostException { - UUID a = UUIDGen.makeType1UUIDFromHost(InetAddress.getByName("127.0.0.1")); + UUID a = UUIDGen.getTimeUUID(); byte[] decomposed = UUIDGen.decompose(a); UUID b = UUIDGen.getUUID(ByteBuffer.wrap(decomposed)); assert a.equals(b); @@ -63,8 +63,8 @@ public class UUIDTests public void testTimeUUIDType() throws UnknownHostException { TimeUUIDType comp = TimeUUIDType.instance; - ByteBuffer first = ByteBuffer.wrap(UUIDGen.decompose(UUIDGen.makeType1UUIDFromHost(InetAddress.getByName("127.0.0.1")))); - ByteBuffer second = ByteBuffer.wrap(UUIDGen.decompose(UUIDGen.makeType1UUIDFromHost(InetAddress.getByName("127.0.0.1")))); + ByteBuffer first = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes()); + ByteBuffer second = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes()); assert comp.compare(first, second) < 0; assert comp.compare(second, first) > 0; ByteBuffer sameAsFirst = ByteBuffer.wrap(UUIDGen.decompose(UUIDGen.getUUID(first))); @@ -76,7 +76,7 @@ public class UUIDTests { InetAddress addr = InetAddress.getByName("127.0.0.1"); long now = System.currentTimeMillis(); - UUID uuid = UUIDGen.makeType1UUIDFromHost(addr); + UUID uuid = UUIDGen.getTimeUUID(); long tstamp = UUIDGen.getAdjustedTimestamp(uuid); // I'll be damn is the uuid timestamp is more than 10ms after now diff --git a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java b/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java index aedf2de017..47e51a4e39 100644 --- a/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java +++ b/tools/stress/src/org/apache/cassandra/stress/operations/CqlInserter.java @@ -71,7 +71,7 @@ public class CqlInserter extends Operation if (session.cqlVersion.startsWith("3")) throw new UnsupportedOperationException("Cannot use UUIDs in column names with CQL3"); - query.append(wrapInQuotesIfRequired(UUIDGen.makeType1UUIDFromHost(Session.getLocalAddress()).toString())) + query.append(wrapInQuotesIfRequired(UUIDGen.getTimeUUID().toString())) .append(" = ?"); } else diff --git a/tools/stress/src/org/apache/cassandra/stress/util/Operation.java b/tools/stress/src/org/apache/cassandra/stress/util/Operation.java index 473769250a..43e10b3d0a 100644 --- a/tools/stress/src/org/apache/cassandra/stress/util/Operation.java +++ b/tools/stress/src/org/apache/cassandra/stress/util/Operation.java @@ -211,7 +211,7 @@ public abstract class Operation protected ByteBuffer columnName(int index, boolean timeUUIDComparator) { return timeUUIDComparator - ? TimeUUIDType.instance.decompose(UUIDGen.makeType1UUIDFromHost(Session.getLocalAddress())) + ? TimeUUIDType.instance.decompose(UUIDGen.getTimeUUID()) : ByteBufferUtil.bytes(String.format("C%d", index)); } From bac979410df5a88834964fa133b3fb9f22deee3f Mon Sep 17 00:00:00 2001 From: Sylvain Lebresne Date: Fri, 7 Dec 2012 10:12:17 +0100 Subject: [PATCH 2/2] Fix message when trying to alter a clustering key type patch by slebresne; reviewed by jbellis for CASSANDRA-5012 --- CHANGES.txt | 1 + .../apache/cassandra/config/CFMetaData.java | 52 +++++++++++-------- .../cassandra/service/MigrationManager.java | 2 + 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 2ffaee5c7c..d3e04a7c5b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,6 +5,7 @@ * Fix preparing queries with counter increment (CASSANDRA-5022) * Fix preparing updates with collections (CASSANDRA-5017) * Don't generate UUID based on other node address (CASSANDRA-5002) + * Fix message when trying to alter a clustering key type (CASSANDRA-5012) Merged from 1.1 * Improve schema propagation performance (CASSANDRA-5025) diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java b/src/java/org/apache/cassandra/config/CFMetaData.java index 986e95d628..7ad2dc4f38 100644 --- a/src/java/org/apache/cassandra/config/CFMetaData.java +++ b/src/java/org/apache/cassandra/config/CFMetaData.java @@ -731,30 +731,8 @@ public final class CFMetaData public void apply(CFMetaData cfm) throws ConfigurationException { logger.debug("applying {} to {}", cfm, this); - // validate - if (!cfm.ksName.equals(ksName)) - throw new ConfigurationException(String.format("Keyspace mismatch (found %s; expected %s)", - cfm.ksName, ksName)); - if (!cfm.cfName.equals(cfName)) - throw new ConfigurationException(String.format("Column family mismatch (found %s; expected %s)", - cfm.cfName, cfName)); - if (!cfm.cfId.equals(cfId)) - throw new ConfigurationException(String.format("Column family ID mismatch (found %s; expected %s)", - cfm.cfId, cfId)); - if (!cfm.cfType.equals(cfType)) - throw new ConfigurationException("types do not match."); - - if (!cfm.comparator.isCompatibleWith(comparator)) - throw new ConfigurationException("comparators do not match or are not compatible."); - if (cfm.subcolumnComparator == null) - { - if (subcolumnComparator != null) - throw new ConfigurationException("subcolumncomparators do not match."); - // else, it's null and we're good. - } - else if (!cfm.subcolumnComparator.isCompatibleWith(subcolumnComparator)) - throw new ConfigurationException("subcolumncomparators do not match or are note compatible."); + validateCompatility(cfm); // TODO: this method should probably return a new CFMetaData so that // 1) we can keep comparator and subcolumnComparator final @@ -813,6 +791,34 @@ public final class CFMetaData logger.debug("application result is {}", this); } + public void validateCompatility(CFMetaData cfm) throws ConfigurationException + { + // validate + if (!cfm.ksName.equals(ksName)) + throw new ConfigurationException(String.format("Keyspace mismatch (found %s; expected %s)", + cfm.ksName, ksName)); + if (!cfm.cfName.equals(cfName)) + throw new ConfigurationException(String.format("Column family mismatch (found %s; expected %s)", + cfm.cfName, cfName)); + if (!cfm.cfId.equals(cfId)) + throw new ConfigurationException(String.format("Column family ID mismatch (found %s; expected %s)", + cfm.cfId, cfId)); + + if (!cfm.cfType.equals(cfType)) + throw new ConfigurationException("types do not match."); + + if (!cfm.comparator.isCompatibleWith(comparator)) + throw new ConfigurationException("comparators do not match or are not compatible."); + if (cfm.subcolumnComparator == null) + { + if (subcolumnComparator != null) + throw new ConfigurationException("subcolumncomparators do not match."); + // else, it's null and we're good. + } + else if (!cfm.subcolumnComparator.isCompatibleWith(subcolumnComparator)) + throw new ConfigurationException("subcolumncomparators do not match or are note compatible."); + } + public static Class createCompactionStrategy(String className) throws ConfigurationException { className = className.contains(".") ? className : "org.apache.cassandra.db.compaction." + className; diff --git a/src/java/org/apache/cassandra/service/MigrationManager.java b/src/java/org/apache/cassandra/service/MigrationManager.java index 9b9fed1122..7fbcfffa68 100644 --- a/src/java/org/apache/cassandra/service/MigrationManager.java +++ b/src/java/org/apache/cassandra/service/MigrationManager.java @@ -220,6 +220,8 @@ public class MigrationManager implements IEndpointStateChangeSubscriber if (oldCfm == null) throw new ConfigurationException(String.format("Cannot update non existing column family '%s' in keyspace '%s'.", cfm.cfName, cfm.ksName)); + oldCfm.validateCompatility(cfm); + logger.info(String.format("Update ColumnFamily '%s/%s' From %s To %s", cfm.ksName, cfm.cfName, oldCfm, cfm)); announce(oldCfm.toSchemaUpdate(cfm, FBUtilities.timestampMicros())); }