Allow DynamicCompositeType to compare components of different types

patch by slebresne; reviewed by edanuff for CASSANDRA-3625


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/6a1ed620
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/6a1ed620
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/6a1ed620

Branch: refs/heads/trunk
Commit: 6a1ed6205cad8d019eb6eda326d7796a8a0dd67b
Parents: f2cb272
Author: Sylvain Lebresne <sylv...@datastax.com>
Authored: Fri Jan 13 08:49:21 2012 +0100
Committer: Sylvain Lebresne <sylv...@datastax.com>
Committed: Fri Jan 13 08:49:21 2012 +0100

----------------------------------------------------------------------
 CHANGES.txt                                        |    2 +
 .../cassandra/db/marshal/DynamicCompositeType.java |   54 ++++++++++++++-
 .../db/marshal/DynamicCompositeTypeTest.java       |   28 ++++++++
 3 files changed, 81 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/6a1ed620/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 39211a4..30c002d 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -26,6 +26,8 @@
  * Improve stream protocol mismatch errors (CASSANDRA-3652)
  * Avoid multiple thread doing HH to the same target (CASSANDRA-3681)
  * Add JMX property for rp_timeout_in_ms (CASSANDRA-2940)
+ * Allow DynamicCompositeType to compare component of different types
+   (CASSANDRA-3625)
 Merged from 0.8:
  * avoid logging (harmless) exception when GC takes < 1ms (CASSANDRA-3656)
  * prevent new nodes from thinking down nodes are up forever (CASSANDRA-3626)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6a1ed620/src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java 
b/src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java
index 592f392..53e10d3 100644
--- a/src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java
@@ -117,11 +117,25 @@ public class DynamicCompositeType extends 
AbstractCompositeType
         AbstractType comp1 = getComparator(bb1);
         AbstractType comp2 = getComparator(bb2);
 
-        // This rely on comparator always being singleton instances
+        // Fast test if the comparator uses singleton instances
         if (comp1 != comp2)
         {
-            logger.error("Mismatch between {} and {}", comp1, comp2);
-            throw new RuntimeException("Comparator mismatch while comparing 
two DynamicCompositeType colum name");
+            /*
+             * We compare component of different types by comparing the
+             * comparator class names. We start with the simple classname
+             * first because that will be faster in almost all cases, but
+             * allback on the full name if necessary
+            */
+            int cmp = 
comp1.getClass().getSimpleName().compareTo(comp2.getClass().getSimpleName());
+            if (cmp != 0)
+                return cmp < 0 ? FixedValueComparator.instance : 
ReversedType.getInstance(FixedValueComparator.instance);
+
+            cmp = 
comp1.getClass().getName().compareTo(comp2.getClass().getName());
+            if (cmp != 0)
+                return cmp < 0 ? FixedValueComparator.instance : 
ReversedType.getInstance(FixedValueComparator.instance);
+
+            // if cmp == 0, we're actually having the same type, but one that
+            // did not have a singleton instance. It's ok (though inefficient).
         }
         return comp1;
     }
@@ -263,4 +277,38 @@ public class DynamicCompositeType extends 
AbstractCompositeType
     {
         return getClass().getName() + 
TypeParser.stringifyAliasesParameters(aliases);
     }
+
+    /*
+     * A comparator that always sorts it's first argument before the second
+     * one.
+     */
+    private static class FixedValueComparator extends AbstractType<Void>
+    {
+        public static final FixedValueComparator instance = new 
FixedValueComparator();
+
+        public int compare(ByteBuffer v1, ByteBuffer v2)
+        {
+            return -1;
+        }
+
+        public Void compose(ByteBuffer bytes)
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        public ByteBuffer decompose(Void value)
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        public String getString(ByteBuffer bytes)
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        public void validate(ByteBuffer bytes)
+        {
+            throw new UnsupportedOperationException();
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6a1ed620/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java 
b/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java
index 100c50e..e453705 100644
--- a/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java
+++ b/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java
@@ -192,6 +192,34 @@ public class DynamicCompositeTypeTest extends CleanupHelper
         assert iter.next().name().equals(cname5);
     }
 
+    @Test
+    public void testUncomparableColumns()
+    {
+        ByteBuffer bytes = ByteBuffer.allocate(2 + 2 + 4 + 1);
+        bytes.putShort((short)(0x8000 | 'b'));
+        bytes.putShort((short) 4);
+        bytes.put(new byte[4]);
+        bytes.put((byte) 0);
+        bytes.rewind();
+
+        ByteBuffer uuid = ByteBuffer.allocate(2 + 2 + 16 + 1);
+        uuid.putShort((short)(0x8000 | 't'));
+        uuid.putShort((short) 16);
+        uuid.put(UUIDGen.decompose(uuids[0]));
+        uuid.put((byte) 0);
+        uuid.rewind();
+
+        try
+        {
+            int c = comparator.compare(bytes, uuid);
+            assert c == -1 : "Expecting bytes to sort before uuid, but got " + 
c;
+        }
+        catch (Exception e)
+        {
+            fail("Shouldn't throw exception");
+        }
+    }
+
     private void addColumn(RowMutation rm, ByteBuffer cname)
     {
         rm.add(new QueryPath(cfName, null , cname), 
ByteBufferUtil.EMPTY_BYTE_BUFFER, 0);

Reply via email to