Commits

pcmanus committed 6a1ed62

Allow DynamicCompositeType to compare components of different types

patch by slebresne; reviewed by edanuff for CASSANDRA-3625

Comments (0)

Files changed (3)

  * 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)

src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java

         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;
     }
     {
         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();
+        }
+    }
 }

test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java

         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);
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.