diff --git a/CHANGES.txt b/CHANGES.txt index ff7c965138..134eb6aac6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -13,6 +13,7 @@ algorithmically (CASSANDRA-1220 * remove message deserialization stage, and uncap read/write stages so slow reads/writes don't block gossip processing (CASSANDRA-1358) + * faster UUIDType, LongType comparisons (CASSANDRA-1386, 1393) 0.6.4 diff --git a/src/java/org/apache/cassandra/db/marshal/LongType.java b/src/java/org/apache/cassandra/db/marshal/LongType.java index 398510f4f7..aba359b4c7 100644 --- a/src/java/org/apache/cassandra/db/marshal/LongType.java +++ b/src/java/org/apache/cassandra/db/marshal/LongType.java @@ -22,7 +22,8 @@ package org.apache.cassandra.db.marshal; import java.nio.ByteBuffer; -import java.nio.ByteOrder; + +import org.apache.cassandra.utils.FBUtilities; public class LongType extends AbstractType { @@ -37,9 +38,10 @@ public class LongType extends AbstractType return 1; } - long L1 = ByteBuffer.wrap(o1).getLong(); - long L2 = ByteBuffer.wrap(o2).getLong(); - return Long.valueOf(L1).compareTo(Long.valueOf(L2)); + int diff = o1[0] - o2[0]; + if (diff != 0) + return diff; + return FBUtilities.compareByteArrays(o1, o2); } public String getString(byte[] bytes) diff --git a/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java b/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java index addaa120c5..c21e1c0aa9 100644 --- a/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java +++ b/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java @@ -36,10 +36,29 @@ public class TimeUUIDType extends AbstractType { return 1; } - - long t1 = LexicalUUIDType.getUUID(o1).timestamp(); - long t2 = LexicalUUIDType.getUUID(o2).timestamp(); - return t1 < t2 ? -1 : (t1 > t2 ? 1 : FBUtilities.compareByteArrays(o1, o2)); + int res = compareTimestampBytes(o1, o2); + if (res != 0) + return res; + return FBUtilities.compareByteArrays(o1, o2); + } + + private static int compareTimestampBytes(byte[] o1, byte[] o2) + { + int d = (o1[6] & 0xF) - (o2[6] & 0xF); + if (d != 0) return d; + d = (o1[7] & 0xFF) - (o2[7] & 0xFF); + if (d != 0) return d; + d = (o1[4] & 0xFF) - (o2[4] & 0xFF); + if (d != 0) return d; + d = (o1[5] & 0xFF) - (o2[5] & 0xFF); + if (d != 0) return d; + d = (o1[0] & 0xFF) - (o2[0] & 0xFF); + if (d != 0) return d; + d = (o1[1] & 0xFF) - (o2[1] & 0xFF); + if (d != 0) return d; + d = (o1[2] & 0xFF) - (o2[2] & 0xFF); + if (d != 0) return d; + return (o1[3] & 0xFF) - (o2[3] & 0xFF); } public String getString(byte[] bytes) diff --git a/test/unit/org/apache/cassandra/db/marshal/TimeUUIDTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/TimeUUIDTypeTest.java new file mode 100644 index 0000000000..6d39dc0292 --- /dev/null +++ b/test/unit/org/apache/cassandra/db/marshal/TimeUUIDTypeTest.java @@ -0,0 +1,51 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ +package org.apache.cassandra.db.marshal; + +import java.util.Arrays; +import java.util.Random; + +import org.junit.Test; + +public class TimeUUIDTypeTest +{ + TimeUUIDType timeUUIDType = new TimeUUIDType(); + + @Test + public void testTimestampComparison() + { + Random rng = new Random(); + byte[][] uuids = new byte[100][]; + for (int i = 0; i < uuids.length; i++) + { + uuids[i] = new byte[16]; + rng.nextBytes(uuids[i]); + // set version to 1 + uuids[i][6] &= 0x0F; + uuids[i][6] |= 0x10; + } + Arrays.sort(uuids, timeUUIDType); + for (int i = 1; i < uuids.length; i++) + { + long i0 = LexicalUUIDType.getUUID(uuids[i - 1]).timestamp(); + long i1 = LexicalUUIDType.getUUID(uuids[i]).timestamp(); + assert i0 <= i1; + } + } +} diff --git a/test/unit/org/apache/cassandra/db/marshal/TypeCompareTest.java b/test/unit/org/apache/cassandra/db/marshal/TypeCompareTest.java index c5227882aa..baed193f6a 100644 --- a/test/unit/org/apache/cassandra/db/marshal/TypeCompareTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/TypeCompareTest.java @@ -23,6 +23,8 @@ package org.apache.cassandra.db.marshal; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Random; import java.util.UUID; import org.apache.commons.lang.ArrayUtils; @@ -68,6 +70,27 @@ public class TypeCompareTest assert comparator.compare("a".getBytes("UTF-8"), "z".getBytes("UTF-8")) < 0; } + @Test + public void testLong() + { + Random rng = new Random(); + byte[][] data = new byte[1000][]; + for (int i = 0; i < data.length; i++) + { + data[i] = new byte[8]; + rng.nextBytes(data[i]); + } + + Arrays.sort(data, new LongType()); + + for (int i = 1; i < data.length; i++) + { + long l0 = ByteBuffer.wrap(data[i - 1]).getLong(); + long l1 = ByteBuffer.wrap(data[i]).getLong(); + assert l0 <= l1; + } + } + @Test public void testTimeUUID() {