Pārlūkot izejas kodu

HADOOP-525. Add raw comparators to record types. Contributed by Milind.

git-svn-id: https://svn.apache.org/repos/asf/lucene/hadoop/trunk@492271 13f79535-47bb-0310-9956-ffa450edef68
Doug Cutting 18 gadi atpakaļ
vecāks
revīzija
7c0f37411e

+ 3 - 0
CHANGES.txt

@@ -165,6 +165,9 @@ Trunk (unreleased changes)
 46. HADOOP-850.  Add Writable implementations for variable-length
     integers.  (ab via cutting)
 
+47. HADOOP-525.  Add raw comparators to record types.  This greatly
+    improves record sort performance.  (Milind Bhandarkar via cutting)
+
 
 Release 0.9.2 - 2006-12-15
 

+ 11 - 6
src/java/org/apache/hadoop/io/WritableComparator.java

@@ -160,14 +160,19 @@ public class WritableComparator implements Comparator {
       (readInt(bytes, start+4) & 0xFFFFFFFFL);
   }
 
+  /** Parse a double from a byte array. */
+  public static double readDouble(byte[] bytes, int start) {
+    return Double.longBitsToDouble(readLong(bytes, start));
+  }
+
   /**
    * Reads a zero-compressed encoded long from a byte array and returns it.
-   * @param bytes: byte array with decode long
-   * @param start: starting index
+   * @param bytes byte array with decode long
+   * @param start starting index
    * @throws java.io.IOException 
    * @return deserialized long
    */
-  static long readVLong(byte[] bytes, int start) throws IOException {
+  public static long readVLong(byte[] bytes, int start) throws IOException {
       int len = bytes[start];
       if (len >= -112) {
           return len;
@@ -186,12 +191,12 @@ public class WritableComparator implements Comparator {
   
   /**
    * Reads a zero-compressed encoded integer from a byte array and returns it.
-   * @param bytes: byte array with the encoded integer
-   * @param start: start index
+   * @param bytes byte array with the encoded integer
+   * @param start start index
    * @throws java.io.IOException 
    * @return deserialized integer
    */
-  static int readVInt(byte[] bytes, int start) throws IOException {
+  public static int readVInt(byte[] bytes, int start) throws IOException {
       return (int) readVLong(bytes, start);
   }
 }

+ 39 - 2
src/java/org/apache/hadoop/record/compiler/JBoolean.java

@@ -33,11 +33,48 @@ public class JBoolean extends JType {
         return "z";
     }
     
-    public String genJavaCompareTo(String fname) {
-        return "    ret = ("+fname+" == peer."+fname+")? 0 : ("+fname+"?1:-1);\n";
+    String getJavaCompareToWrapper(String fname, String other) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("          boolean ee1 = ("+fname+".toBoolean()\n");
+      sb.append("          boolean ee2 = ("+other+".toBoolean()\n");
+      sb.append("          ret = (ee1 == ee2)? 0 :(ee1?-1:1);\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareTo(String fname, String other) {
+        return "    ret = ("+fname+" == "+other+")? 0 : ("+fname+"?1:-1);\n";
     }
     
     public String genJavaHashCode(String fname) {
         return "     ret = ("+fname+")?0:1;\n";
     }
+    
+    // In Binary format, boolean is written as byte. true = 1, false = 0
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           if ("+l+"<1) {\n");
+      sb.append("             throw new IOException(\"Boolean is exactly 1 byte. Provided buffer is smaller.\");\n");
+      sb.append("           }\n");
+      sb.append("           "+s+"++; "+l+"--;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    // In Binary format, boolean is written as byte. true = 1, false = 0
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           if (l1<1 || l2<1) {\n");
+      sb.append("             throw new IOException(\"Boolean is exactly 1 byte. Provided buffer is smaller.\");\n");
+      sb.append("           }\n");
+      sb.append("           if (b1[s1] != b2[s2]) {\n");
+      sb.append("             return (b1[s1]<b2[s2])? -1 : 0;\n");
+      sb.append("           }\n");
+      sb.append("           s1++; s2++; l1--; l2--;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 37 - 2
src/java/org/apache/hadoop/record/compiler/JBuffer.java

@@ -55,8 +55,18 @@ public class JBuffer extends JCompType {
         return "        a_.writeBuffer("+fname+",\""+tag+"\");\n";
     }
     
-    public String genJavaCompareTo(String fname) {
-        return "";
+    public String genJavaCompareTo(String fname, String other) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("    {\n");
+      sb.append("      byte[] my = "+fname+".toByteArray();\n");
+      sb.append("      byte[] ur = "+other+".toByteArray();\n");
+      sb.append("      ret = WritableComparator.compareBytes(my,0,my.length,ur,0,ur.length);\n");
+      sb.append("    }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareToWrapper(String fname, String other) {
+      return "    "+genJavaCompareTo(fname, other);
     }
     
     public String genJavaEquals(String fname, String peer) {
@@ -66,4 +76,29 @@ public class JBuffer extends JCompType {
     public String genJavaHashCode(String fname) {
         return "    ret = "+fname+".toString().hashCode();\n";
     }
+    
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           int i = WritableComparator.readVInt("+b+", "+s+");\n");
+      sb.append("           int z = WritableUtils.getVIntSize(i);\n");
+      sb.append("           "+s+" += z+i; "+l+" -= (z+i);\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           int i1 = WritableComparator.readVInt(b1, s1);\n");
+      sb.append("           int i2 = WritableComparator.readVInt(b2, s2);\n");
+      sb.append("           int z1 = WritableUtils.getVIntSize(i1);\n");
+      sb.append("           int z2 = WritableUtils.getVIntSize(i2);\n");
+      sb.append("           s1+=z1; s2+=z2; l1-=z1; l2-=z2;\n");
+      sb.append("           int r1 = WritableComparator.compareBytes(b1,s1,l1,b2,s2,l2);\n");
+      sb.append("           if (r1 != 0) { return (r1<0)?-1:0; }\n");
+      sb.append("           s1+=i1; s2+=i2; l1-=i1; l1-=i2;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 25 - 0
src/java/org/apache/hadoop/record/compiler/JByte.java

@@ -32,4 +32,29 @@ public class JByte extends JType {
     public String getSignature() {
         return "b";
     }
+    
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           if ("+l+"<1) {\n");
+      sb.append("             throw new IOException(\"Byte is exactly 1 byte. Provided buffer is smaller.\");\n");
+      sb.append("           }\n");
+      sb.append("           "+s+"++; "+l+"--;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           if (l1<1 || l2<1) {\n");
+      sb.append("             throw new IOException(\"Byte is exactly 1 byte. Provided buffer is smaller.\");\n");
+      sb.append("           }\n");
+      sb.append("           if (b1[s1] != b2[s2]) {\n");
+      sb.append("             return (b1[s1]<b2[s2])?-1:0;\n");
+      sb.append("           }\n");
+      sb.append("           s1++; s2++; l1--; l2--;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 6 - 2
src/java/org/apache/hadoop/record/compiler/JCompType.java

@@ -41,8 +41,12 @@ abstract class JCompType extends JType {
         return cgetFunc + getFunc;
     }
     
-    String genJavaCompareTo(String fname) {
-        return "    ret = "+fname+".compareTo(peer."+fname+");\n";
+    String genJavaCompareTo(String fname, String other) {
+        return "    ret = "+fname+".compareTo("+other+");\n";
+    }
+    
+    String genJavaCompareToWrapper(String fname, String other) {
+        return "    "+genJavaCompareTo(fname, other);
     }
     
     String genJavaEquals(String fname, String peer) {

+ 27 - 0
src/java/org/apache/hadoop/record/compiler/JDouble.java

@@ -37,4 +37,31 @@ public class JDouble extends JType {
         String tmp = "Double.doubleToLongBits("+fname+")";
         return "    ret = (int)("+tmp+"^("+tmp+">>>32));\n";
     }
+    
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           if ("+l+"<8) {\n");
+      sb.append("             throw new IOException(\"Double is exactly 8 bytes. Provided buffer is smaller.\");\n");
+      sb.append("           }\n");
+      sb.append("           "+s+"+=8; "+l+"-=8;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           if (l1<8 || l2<8) {\n");
+      sb.append("             throw new IOException(\"Double is exactly 8 bytes. Provided buffer is smaller.\");\n");
+      sb.append("           }\n");
+      sb.append("           double d1 = WritableComparator.readDouble(b1, s1);\n");
+      sb.append("           double d2 = WritableComparator.readDouble(b2, s2);\n");
+      sb.append("           if (d1 != d2) {\n");
+      sb.append("             return ((d1-d2) < 0) ? -1 : 0;\n");
+      sb.append("           }\n");
+      sb.append("           s1+=8; s2+=8; l1-=8; l2-=8;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 9 - 1
src/java/org/apache/hadoop/record/compiler/JField.java

@@ -78,7 +78,15 @@ public class JField {
     }
     
     public String genJavaCompareTo() {
-        return mType.genJavaCompareTo(getName());
+        return mType.genJavaCompareTo(getName(), "peer."+getName());
+    }
+    
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      return mType.genJavaSlurpBytes(b,s,l);
+    }
+    
+    public String genJavaCompareBytes() {
+      return mType.genJavaCompareBytes();
     }
     
     public String genJavaEquals() {

+ 27 - 0
src/java/org/apache/hadoop/record/compiler/JFloat.java

@@ -36,4 +36,31 @@ public class JFloat extends JType {
     public String genJavaHashCode(String fname) {
         return "    ret = Float.floatToIntBits("+fname+");\n";
     }
+    
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           if ("+l+"<4) {\n");
+      sb.append("             throw new IOException(\"Float is exactly 4 bytes. Provided buffer is smaller.\");\n");
+      sb.append("           }\n");
+      sb.append("           "+s+"+=4; "+l+"-=4;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           if (l1<4 || l2<4) {\n");
+      sb.append("             throw new IOException(\"Float is exactly 4 bytes. Provided buffer is smaller.\");\n");
+      sb.append("           }\n");
+      sb.append("           float f1 = WritableComparator.readFloat(b1, s1);\n");
+      sb.append("           float f2 = WritableComparator.readFloat(b2, s2);\n");
+      sb.append("           if (f1 != f2) {\n");
+      sb.append("             return ((f1-f2) < 0) ? -1 : 0;\n");
+      sb.append("           }\n");
+      sb.append("           s1+=4; s2+=4; l1-=4; l2-=4;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 25 - 0
src/java/org/apache/hadoop/record/compiler/JInt.java

@@ -32,4 +32,29 @@ public class JInt extends JType {
     public String getSignature() {
         return "i";
     }
+    
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           int i = WritableComparator.readVInt("+b+", "+s+");\n");
+      sb.append("           int z = WritableUtils.getVIntSize(i);\n");
+      sb.append("           "+s+"+=z; "+l+"-=z;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           int i1 = WritableComparator.readVInt(b1, s1);\n");
+      sb.append("           int i2 = WritableComparator.readVInt(b2, s2);\n");
+      sb.append("           if (i1 != i2) {\n");
+      sb.append("             return ((i1-i2) < 0) ? -1 : 0;\n");
+      sb.append("           }\n");
+      sb.append("           int z1 = WritableUtils.getVIntSize(i1);\n");
+      sb.append("           int z2 = WritableUtils.getVIntSize(i2);\n");
+      sb.append("           s1+=z1; s2+=z2; l1-=z1; l2-=z2;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 25 - 0
src/java/org/apache/hadoop/record/compiler/JLong.java

@@ -36,4 +36,29 @@ public class JLong extends JType {
     public String genJavaHashCode(String fname) {
         return "    ret = (int) ("+fname+"^("+fname+">>>32));\n";
     }
+    
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           long i = WritableComparator.readVLong("+b+", "+s+");\n");
+      sb.append("           int z = WritableUtils.getVIntSize(i);\n");
+      sb.append("           "+s+"+=z; "+l+"-=z;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           long i1 = WritableComparator.readVLong(b1, s1);\n");
+      sb.append("           long i2 = WritableComparator.readVLong(b2, s2);\n");
+      sb.append("           if (i1 != i2) {\n");
+      sb.append("             return ((i1-i2) < 0) ? -1 : 0;\n");
+      sb.append("           }\n");
+      sb.append("           int z1 = WritableUtils.getVIntSize(i1);\n");
+      sb.append("           int z2 = WritableUtils.getVIntSize(i2);\n");
+      sb.append("           s1+=z1; s2+=z2; l1-=z1; l2-=z2;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 72 - 2
src/java/org/apache/hadoop/record/compiler/JMap.java

@@ -49,8 +49,31 @@ public class JMap extends JCompType {
         return "{" + mKey.getSignature() + mValue.getSignature() +"}";
     }
     
-    public String genJavaCompareTo(String fname) {
-        return "";
+    public String genJavaCompareTo(String fname, String other) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("    {\n");
+      sb.append("      java.util.Set "+getId("set1")+" = "+fname+".keySet();\n");
+      sb.append("      java.util.Set "+getId("set2")+" = "+other+".keySet();\n");
+      sb.append("      java.util.Iterator "+getId("miter1")+" = "+
+          getId("set1")+".iterator();\n");
+      sb.append("      java.util.Iterator "+getId("miter2")+" = "+
+          getId("set2")+".iterator();\n");
+      sb.append("      for(; "+getId("miter1")+".hasNext() && "+
+          getId("miter2")+".hasNext(); ) {\n");
+      sb.append("        "+mKey.getJavaWrapperType()+" "+getId("k1")+
+          " = ("+mKey.getJavaWrapperType()+") "+getId("miter1")+".next();\n");
+      sb.append("        "+mKey.getJavaWrapperType()+" "+getId("k2")+
+          " = ("+mKey.getJavaWrapperType()+") "+getId("miter2")+".next();\n");
+      sb.append(mKey.genJavaCompareToWrapper(getId("k1"), getId("k2")));
+      sb.append("         if (ret != 0) { return ret; }\n");
+      sb.append("      }\n");
+      sb.append("      ret = ("+getId("set1")+".size() - "+getId("set2")+".size());\n");
+      sb.append("    }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareToWrapper(String fname, String other) {
+      return genJavaCompareTo(fname, other);
     }
     
     public String genJavaReadWrapper(String fname, String tag, boolean decl) {
@@ -98,4 +121,51 @@ public class JMap extends JCompType {
     public String genJavaWriteMethod(String fname, String tag) {
         return genJavaWriteWrapper(fname, tag);
     }
+    
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      incrLevel();
+      sb.append("           int "+getId("mi")+
+          " = WritableComparator.readVInt("+b+", "+s+");\n");
+      sb.append("           int "+getId("mz")+
+          " = WritableUtils.getVIntSize("+getId("mi")+");\n");
+      sb.append("           "+s+"+="+getId("mz")+"; "+l+"-="+getId("mz")+";\n");
+      sb.append("           for (int "+getId("midx")+" = 0; "+getId("midx")+
+          " < "+getId("mi")+"; "+getId("midx")+"++) {");
+      sb.append(mKey.genJavaSlurpBytes(b,s,l));
+      sb.append(mValue.genJavaSlurpBytes(b,s,l));
+      sb.append("           }\n");
+      decrLevel();
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      incrLevel();
+      sb.append("           int "+getId("mi1")+
+          " = WritableComparator.readVInt(b1, s1);\n");
+      sb.append("           int "+getId("mi2")+
+          " = WritableComparator.readVInt(b2, s2);\n");
+      sb.append("           int "+getId("mz1")+
+          " = WritableUtils.getVIntSize("+getId("mi1")+");\n");
+      sb.append("           int "+getId("mz2")+
+          " = WritableUtils.getVIntSize("+getId("mi2")+");\n");
+      sb.append("           s1+="+getId("mz1")+"; s2+="+getId("mz2")+
+          "; l1-="+getId("mz1")+"; l2-="+getId("mz2")+";\n");
+      sb.append("           for (int "+getId("midx")+" = 0; "+getId("midx")+
+          " < "+getId("mi1")+" && "+getId("midx")+" < "+getId("mi2")+
+          "; "+getId("midx")+"++) {");
+      sb.append(mKey.genJavaCompareBytes());
+      sb.append(mValue.genJavaSlurpBytes("b1", "s1", "l1"));
+      sb.append(mValue.genJavaSlurpBytes("b2", "s2", "l2"));
+      sb.append("           }\n");
+      sb.append("           if ("+getId("mi1")+" != "+getId("mi2")+
+          ") { return ("+getId("mi1")+"<"+getId("mi2")+")?-1:0; }\n");
+      decrLevel();
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 74 - 1
src/java/org/apache/hadoop/record/compiler/JRecord.java

@@ -104,6 +104,27 @@ public class JRecord extends JCompType {
         return "    a_.writeRecord("+fname+",\""+tag+"\");\n";
     }
     
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           int r = "+getJavaFQName()+
+          ".Comparator.slurpRaw("+b+","+s+","+l+");\n");
+      sb.append("           "+s+"+=r; "+l+"-=r;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           int r1 = "+getJavaFQName()+
+          ".Comparator.compareRaw(b1,s1,l1,b2,s2,l2);\n");
+      sb.append("           if (r1 <= 0) { return r1; }\n");
+      sb.append("           s1+=r1; s2+=r1; l1-=r1; l2-=r1;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
     public void genCppCode(FileWriter hh, FileWriter cc)
         throws IOException {
         String[] ns = getCppNameSpace().split("::");
@@ -236,8 +257,16 @@ public class JRecord extends JCompType {
         FileWriter jj = new FileWriter(jfile);
         jj.write("// File generated by hadoop record compiler. Do not edit.\n");
         jj.write("package "+getJavaPackage()+";\n\n");
+        jj.write("import java.io.IOException;\n");
+        jj.write("import org.apache.commons.logging.Log;\n");
+        jj.write("import org.apache.commons.logging.LogFactory;\n");
+        jj.write("import org.apache.hadoop.io.WritableComparator;\n");
+        jj.write("import org.apache.hadoop.io.WritableComparable;\n");
+        jj.write("import org.apache.hadoop.io.WritableUtils;\n");
         jj.write("import org.apache.hadoop.io.Text;\n\n");
-        jj.write("public class "+getName()+" implements org.apache.hadoop.record.Record, org.apache.hadoop.io.WritableComparable {\n");
+        jj.write("public class "+getName()+" implements org.apache.hadoop.record.Record, WritableComparable {\n");
+        jj.write("  private static final Log LOG= LogFactory.getLog(\""+
+            this.getJavaFQName()+"\");\n");
         for (Iterator i = mFields.iterator(); i.hasNext();) {
             JField jf = (JField) i.next();
             jj.write(jf.genJavaDecl());
@@ -380,6 +409,50 @@ public class JRecord extends JCompType {
         jj.write("    return \""+getSignature()+"\";\n");
         jj.write("  }\n");
         
+        jj.write("  public static class Comparator extends WritableComparator {\n");
+        jj.write("    public Comparator() {\n");
+        jj.write("      super("+getName()+".class);\n");
+        jj.write("    }\n");
+
+        jj.write("    static public int slurpRaw(byte[] b, int s, int l) {\n");
+        jj.write("      try {\n");
+        jj.write("        int os = s;\n");
+        for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
+            JField jf = (JField) i.next();
+            jj.write(jf.genJavaSlurpBytes("b","s","l"));
+        }
+        jj.write("        return (os - s);\n");
+        jj.write("      } catch(IOException e) {\n");
+        jj.write("        LOG.warn(e);\n");
+        jj.write("        throw new RuntimeException(e);\n");
+        jj.write("      }\n");
+        jj.write("    }\n");
+        
+        jj.write("    static public int compareRaw(byte[] b1, int s1, int l1,\n");
+        jj.write("                       byte[] b2, int s2, int l2) {\n");
+        jj.write("      try {\n");
+        jj.write("        int os1 = s1;\n");
+        for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
+            JField jf = (JField) i.next();
+            jj.write(jf.genJavaCompareBytes());
+        }
+        jj.write("        return (os1 - s1);\n");
+        jj.write("      } catch(IOException e) {\n");
+        jj.write("        LOG.warn(e);\n");
+        jj.write("        throw new RuntimeException(e);\n");
+        jj.write("      }\n");
+        jj.write("    }\n");
+        jj.write("    public int compare(byte[] b1, int s1, int l1,\n");
+        jj.write("                       byte[] b2, int s2, int l2) {\n");
+        jj.write("      int ret = compareRaw(b1,s1,l1,b2,s2,l2);\n");
+        jj.write("      return (ret == -1)? -1 : ((ret==0)? 1 : 0);");
+        jj.write("    }\n");
+        jj.write("  }\n\n");
+        jj.write("  static {\n");
+        jj.write("    WritableComparator.define("+getName()+".class, new Comparator());\n");
+        jj.write("  }\n");
+
+        
         jj.write("}\n");
         
         jj.close();

+ 23 - 0
src/java/org/apache/hadoop/record/compiler/JString.java

@@ -45,5 +45,28 @@ public class JString extends JCompType {
         return "        a_.writeString("+fname+",\""+tag+"\");\n";
     }
     
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           int i = WritableComparator.readVInt("+b+", "+s+");\n");
+      sb.append("           int z = WritableUtils.getVIntSize(i);\n");
+      sb.append("           "+s+"+=(z+i); "+l+"-= (z+i);\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
     
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("           int i1 = WritableComparator.readVInt(b1, s1);\n");
+      sb.append("           int i2 = WritableComparator.readVInt(b2, s2);\n");
+      sb.append("           int z1 = WritableUtils.getVIntSize(i1);\n");
+      sb.append("           int z2 = WritableUtils.getVIntSize(i2);\n");
+      sb.append("           s1+=z1; s2+=z2; l1-=z1; l2-=z2;\n");
+      sb.append("           int r1 = WritableComparator.compareBytes(b1,s1,l1,b2,s2,l2);\n");
+      sb.append("           if (r1 != 0) { return (r1<0)?-1:0; }\n");
+      sb.append("           s1+=i1; s2+=i2; l1-=i1; l1-=i2;\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 20 - 2
src/java/org/apache/hadoop/record/compiler/JType.java

@@ -112,8 +112,26 @@ abstract public class JType {
         return "        a_.write"+mMethodSuffix+"("+fname+"."+mUnwrapMethod+"(),\""+tag+"\");\n";
     }
     
-    String genJavaCompareTo(String fname) {
-        return "    ret = ("+fname+" == peer."+fname+")? 0 :(("+fname+"<peer."+fname+")?-1:1);\n";
+    String genJavaCompareToWrapper(String fname, String other) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      sb.append("          "+mJavaName+" ee1 = ("+fname+"."+mUnwrapMethod+"();\n");
+      sb.append("          "+mJavaName+" ee2 = ("+other+"."+mUnwrapMethod+"();\n");
+      sb.append("          ret = (ee1 == ee2)? 0 :((ee1<ee2)?-1:1);\n");
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    String genJavaCompareTo(String fname, String other) {
+        return "    ret = ("+fname+" == "+other+")? 0 :(("+fname+"<"+other+")?-1:1);\n";
+    }
+    
+    String genJavaCompareBytes() {
+      return "        // throw new IOException(\"Not Implemented yet!\");\n";
+    }
+    
+    String genJavaSlurpBytes(String b, String s, String l) {
+      return "        // throw new IOException(\"Not Implemented yet!\");\n";
     }
     
     String genJavaEquals(String fname, String peer) {

+ 66 - 2
src/java/org/apache/hadoop/record/compiler/JVector.java

@@ -46,8 +46,30 @@ public class JVector extends JCompType {
         return "[" + mElement.getSignature() + "]";
     }
     
-    public String genJavaCompareTo(String fname) {
-        return "";
+    public String genJavaCompareTo(String fname, String other) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("    {\n");
+      sb.append("      int "+getId("len1")+" = "+fname+".size();\n");
+      sb.append("      int "+getId("len2")+" = "+other+".size();\n");
+      sb.append("      for(int "+getId("vidx")+" = 0; "+getId("vidx")+"<"+
+          getId("len1")+" && "+getId("vidx")+"<"+getId("len2")+"; "+
+          getId("vidx")+"++) {\n");
+      sb.append("        "+mElement.getJavaWrapperType()+" "+getId("e1")+
+          " = ("+mElement.getJavaWrapperType()+") "+fname+
+          ".get("+getId("vidx")+");\n");
+      sb.append("        "+mElement.getJavaWrapperType()+" "+getId("e2")+
+          " = ("+mElement.getJavaWrapperType()+") "+other+
+          ".get("+getId("vidx")+");\n");
+      sb.append(mElement.genJavaCompareToWrapper(getId("e1"), getId("e2")));
+      sb.append("         if (ret != 0) { return ret; }\n");
+      sb.append("      }\n");
+      sb.append("      ret = ("+getId("len1")+" - "+getId("len2")+");\n");
+      sb.append("    }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareToWrapper(String fname, String other) {
+      return genJavaCompareTo(fname, other);
     }
     
     public String genJavaReadWrapper(String fname, String tag, boolean decl) {
@@ -91,4 +113,46 @@ public class JVector extends JCompType {
     public String genJavaWriteMethod(String fname, String tag) {
         return genJavaWriteWrapper(fname, tag);
     }
+    
+    public String genJavaSlurpBytes(String b, String s, String l) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      incrLevel();
+      sb.append("           int "+getId("vi")+
+          " = WritableComparator.readVInt("+b+", "+s+");\n");
+      sb.append("           int "+getId("vz")+
+          " = WritableUtils.getVIntSize("+getId("vi")+");\n");
+      sb.append("           "+s+"+="+getId("vz")+"; "+l+"-="+getId("vz")+";\n");
+      sb.append("           for (int "+getId("vidx")+" = 0; "+getId("vidx")+
+          " < "+getId("vi")+"; "+getId("vidx")+"++)");
+      sb.append(mElement.genJavaSlurpBytes(b,s,l));
+      decrLevel();
+      sb.append("        }\n");
+      return sb.toString();
+    }
+    
+    public String genJavaCompareBytes() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("        {\n");
+      incrLevel();
+      sb.append("           int "+getId("vi1")+
+          " = WritableComparator.readVInt(b1, s1);\n");
+      sb.append("           int "+getId("vi2")+
+          " = WritableComparator.readVInt(b2, s2);\n");
+      sb.append("           int "+getId("vz1")+
+          " = WritableUtils.getVIntSize("+getId("vi1")+");\n");
+      sb.append("           int "+getId("vz2")+
+          " = WritableUtils.getVIntSize("+getId("vi2")+");\n");
+      sb.append("           s1+="+getId("vz1")+"; s2+="+getId("vz2")+
+          "; l1-="+getId("vz1")+"; l2-="+getId("vz2")+";\n");
+      sb.append("           for (int "+getId("vidx")+" = 0; "+getId("vidx")+
+          " < "+getId("vi1")+" && "+getId("vidx")+" < "+getId("vi2")+
+          "; "+getId("vidx")+"++)");
+      sb.append(mElement.genJavaCompareBytes());
+      sb.append("           if ("+getId("vi1")+" != "+getId("vi2")+
+          ") { return ("+getId("vi1")+"<"+getId("vi2")+")?-1:0; }\n");
+      decrLevel();
+      sb.append("        }\n");
+      return sb.toString();
+    }
 }

+ 60 - 18
src/test/org/apache/hadoop/record/test/RecBuffer.java

@@ -1,26 +1,16 @@
-/**
- * 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.
- */
 // File generated by hadoop record compiler. Do not edit.
 package org.apache.hadoop.record.test;
 
+import java.io.IOException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.io.WritableComparator;
+import org.apache.hadoop.io.WritableComparable;
+import org.apache.hadoop.io.WritableUtils;
 import org.apache.hadoop.io.Text;
 
-public class RecBuffer implements org.apache.hadoop.record.Record, org.apache.hadoop.io.WritableComparable {
+public class RecBuffer implements org.apache.hadoop.record.Record, WritableComparable {
+  private static final Log LOG= LogFactory.getLog("org.apache.hadoop.record.test.RecBuffer");
   private java.io.ByteArrayOutputStream mData;
   private java.util.BitSet bs_;
   public RecBuffer() {
@@ -85,6 +75,11 @@ public class RecBuffer implements org.apache.hadoop.record.Record, org.apache.ha
     }
     RecBuffer peer = (RecBuffer) peer_;
     int ret = 0;
+    {
+      byte[] my = mData.toByteArray();
+      byte[] ur = peer.mData.toByteArray();
+      ret = WritableComparator.compareBytes(my,0,my.length,ur,0,ur.length);
+    }
     if (ret != 0) return ret;
      return ret;
   }
@@ -111,4 +106,51 @@ public class RecBuffer implements org.apache.hadoop.record.Record, org.apache.ha
   public static String signature() {
     return "LRecBuffer(B)";
   }
+  public static class Comparator extends WritableComparator {
+    public Comparator() {
+      super(RecBuffer.class);
+    }
+    static public int slurpRaw(byte[] b, int s, int l) {
+      try {
+        int os = s;
+        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s += z+i; l -= (z+i);
+        }
+        return (os - s);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    static public int compareRaw(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      try {
+        int os1 = s1;
+        {
+           int i1 = WritableComparator.readVInt(b1, s1);
+           int i2 = WritableComparator.readVInt(b2, s2);
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+           int r1 = WritableComparator.compareBytes(b1,s1,l1,b2,s2,l2);
+           if (r1 != 0) { return (r1<0)?-1:0; }
+           s1+=i1; s2+=i2; l1-=i1; l1-=i2;
+        }
+        return (os1 - s1);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    public int compare(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      int ret = compareRaw(b1,s1,l1,b2,s2,l2);
+      return (ret == -1)? -1 : ((ret==0)? 1 : 0);    }
+  }
+
+  static {
+    WritableComparator.define(RecBuffer.class, new Comparator());
+  }
 }

+ 55 - 18
src/test/org/apache/hadoop/record/test/RecInt.java

@@ -1,26 +1,16 @@
-/**
- * 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.
- */
 // File generated by hadoop record compiler. Do not edit.
 package org.apache.hadoop.record.test;
 
+import java.io.IOException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.io.WritableComparator;
+import org.apache.hadoop.io.WritableComparable;
+import org.apache.hadoop.io.WritableUtils;
 import org.apache.hadoop.io.Text;
 
-public class RecInt implements org.apache.hadoop.record.Record, org.apache.hadoop.io.WritableComparable {
+public class RecInt implements org.apache.hadoop.record.Record, WritableComparable {
+  private static final Log LOG= LogFactory.getLog("org.apache.hadoop.record.test.RecInt");
   private int mData;
   private java.util.BitSet bs_;
   public RecInt() {
@@ -112,4 +102,51 @@ public class RecInt implements org.apache.hadoop.record.Record, org.apache.hadoo
   public static String signature() {
     return "LRecInt(i)";
   }
+  public static class Comparator extends WritableComparator {
+    public Comparator() {
+      super(RecInt.class);
+    }
+    static public int slurpRaw(byte[] b, int s, int l) {
+      try {
+        int os = s;
+        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s+=z; l-=z;
+        }
+        return (os - s);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    static public int compareRaw(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      try {
+        int os1 = s1;
+        {
+           int i1 = WritableComparator.readVInt(b1, s1);
+           int i2 = WritableComparator.readVInt(b2, s2);
+           if (i1 != i2) {
+             return ((i1-i2) < 0) ? -1 : 0;
+           }
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+        }
+        return (os1 - s1);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    public int compare(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      int ret = compareRaw(b1,s1,l1,b2,s2,l2);
+      return (ret == -1)? -1 : ((ret==0)? 1 : 0);    }
+  }
+
+  static {
+    WritableComparator.define(RecInt.class, new Comparator());
+  }
 }

+ 55 - 18
src/test/org/apache/hadoop/record/test/RecRecord0.java

@@ -1,26 +1,16 @@
-/**
- * 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.
- */
 // File generated by hadoop record compiler. Do not edit.
 package org.apache.hadoop.record.test;
 
+import java.io.IOException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.io.WritableComparator;
+import org.apache.hadoop.io.WritableComparable;
+import org.apache.hadoop.io.WritableUtils;
 import org.apache.hadoop.io.Text;
 
-public class RecRecord0 implements org.apache.hadoop.record.Record, org.apache.hadoop.io.WritableComparable {
+public class RecRecord0 implements org.apache.hadoop.record.Record, WritableComparable {
+  private static final Log LOG= LogFactory.getLog("org.apache.hadoop.record.test.RecRecord0");
   private Text mStringVal;
   private java.util.BitSet bs_;
   public RecRecord0() {
@@ -112,4 +102,51 @@ public class RecRecord0 implements org.apache.hadoop.record.Record, org.apache.h
   public static String signature() {
     return "LRecRecord0(s)";
   }
+  public static class Comparator extends WritableComparator {
+    public Comparator() {
+      super(RecRecord0.class);
+    }
+    static public int slurpRaw(byte[] b, int s, int l) {
+      try {
+        int os = s;
+        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s+=(z+i); l-= (z+i);
+        }
+        return (os - s);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    static public int compareRaw(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      try {
+        int os1 = s1;
+        {
+           int i1 = WritableComparator.readVInt(b1, s1);
+           int i2 = WritableComparator.readVInt(b2, s2);
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+           int r1 = WritableComparator.compareBytes(b1,s1,l1,b2,s2,l2);
+           if (r1 != 0) { return (r1<0)?-1:0; }
+           s1+=i1; s2+=i2; l1-=i1; l1-=i2;
+        }
+        return (os1 - s1);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    public int compare(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      int ret = compareRaw(b1,s1,l1,b2,s2,l2);
+      return (ret == -1)? -1 : ((ret==0)? 1 : 0);    }
+  }
+
+  static {
+    WritableComparator.define(RecRecord0.class, new Comparator());
+  }
 }

+ 275 - 18
src/test/org/apache/hadoop/record/test/RecRecord1.java

@@ -1,26 +1,16 @@
-/**
- * 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.
- */
 // File generated by hadoop record compiler. Do not edit.
 package org.apache.hadoop.record.test;
 
+import java.io.IOException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.io.WritableComparator;
+import org.apache.hadoop.io.WritableComparable;
+import org.apache.hadoop.io.WritableUtils;
 import org.apache.hadoop.io.Text;
 
-public class RecRecord1 implements org.apache.hadoop.record.Record, org.apache.hadoop.io.WritableComparable {
+public class RecRecord1 implements org.apache.hadoop.record.Record, WritableComparable {
+  private static final Log LOG= LogFactory.getLog("org.apache.hadoop.record.test.RecRecord1");
   private boolean mBoolVal;
   private byte mByteVal;
   private int mIntVal;
@@ -299,8 +289,37 @@ public class RecRecord1 implements org.apache.hadoop.record.Record, org.apache.h
     if (ret != 0) return ret;
     ret = mStringVal.compareTo(peer.mStringVal);
     if (ret != 0) return ret;
+    {
+      byte[] my = mBufferVal.toByteArray();
+      byte[] ur = peer.mBufferVal.toByteArray();
+      ret = WritableComparator.compareBytes(my,0,my.length,ur,0,ur.length);
+    }
     if (ret != 0) return ret;
+    {
+      int len10 = mVectorVal.size();
+      int len20 = peer.mVectorVal.size();
+      for(int vidx0 = 0; vidx0<len10 && vidx0<len20; vidx0++) {
+        Text e10 = (Text) mVectorVal.get(vidx0);
+        Text e20 = (Text) peer.mVectorVal.get(vidx0);
+        ret = e10.compareTo(e20);
+         if (ret != 0) { return ret; }
+      }
+      ret = (len10 - len20);
+    }
     if (ret != 0) return ret;
+    {
+      java.util.Set set10 = mMapVal.keySet();
+      java.util.Set set20 = peer.mMapVal.keySet();
+      java.util.Iterator miter10 = set10.iterator();
+      java.util.Iterator miter20 = set20.iterator();
+      for(; miter10.hasNext() && miter20.hasNext(); ) {
+        Text k10 = (Text) miter10.next();
+        Text k20 = (Text) miter20.next();
+        ret = k10.compareTo(k20);
+         if (ret != 0) { return ret; }
+      }
+      ret = (set10.size() - set20.size());
+    }
     if (ret != 0) return ret;
     ret = mRecordVal.compareTo(peer.mRecordVal);
     if (ret != 0) return ret;
@@ -369,4 +388,242 @@ public class RecRecord1 implements org.apache.hadoop.record.Record, org.apache.h
   public static String signature() {
     return "LRecRecord1(zbilfdsB[s]{ss}LRecRecord0(s))";
   }
+  public static class Comparator extends WritableComparator {
+    public Comparator() {
+      super(RecRecord1.class);
+    }
+    static public int slurpRaw(byte[] b, int s, int l) {
+      try {
+        int os = s;
+        {
+           if (l<1) {
+             throw new IOException("Boolean is exactly 1 byte. Provided buffer is smaller.");
+           }
+           s++; l--;
+        }
+        {
+           if (l<1) {
+             throw new IOException("Byte is exactly 1 byte. Provided buffer is smaller.");
+           }
+           s++; l--;
+        }
+        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s+=z; l-=z;
+        }
+        {
+           long i = WritableComparator.readVLong(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s+=z; l-=z;
+        }
+        {
+           if (l<4) {
+             throw new IOException("Float is exactly 4 bytes. Provided buffer is smaller.");
+           }
+           s+=4; l-=4;
+        }
+        {
+           if (l<8) {
+             throw new IOException("Double is exactly 8 bytes. Provided buffer is smaller.");
+           }
+           s+=8; l-=8;
+        }
+        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s+=(z+i); l-= (z+i);
+        }
+        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s += z+i; l -= (z+i);
+        }
+        {
+           int vi1 = WritableComparator.readVInt(b, s);
+           int vz1 = WritableUtils.getVIntSize(vi1);
+           s+=vz1; l-=vz1;
+           for (int vidx1 = 0; vidx1 < vi1; vidx1++)        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s+=(z+i); l-= (z+i);
+        }
+        }
+        {
+           int mi1 = WritableComparator.readVInt(b, s);
+           int mz1 = WritableUtils.getVIntSize(mi1);
+           s+=mz1; l-=mz1;
+           for (int midx1 = 0; midx1 < mi1; midx1++) {        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s+=(z+i); l-= (z+i);
+        }
+        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s+=(z+i); l-= (z+i);
+        }
+           }
+        }
+        {
+           int r = org.apache.hadoop.record.test.RecRecord0.Comparator.slurpRaw(b,s,l);
+           s+=r; l-=r;
+        }
+        return (os - s);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    static public int compareRaw(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      try {
+        int os1 = s1;
+        {
+           if (l1<1 || l2<1) {
+             throw new IOException("Boolean is exactly 1 byte. Provided buffer is smaller.");
+           }
+           if (b1[s1] != b2[s2]) {
+             return (b1[s1]<b2[s2])? -1 : 0;
+           }
+           s1++; s2++; l1--; l2--;
+        }
+        {
+           if (l1<1 || l2<1) {
+             throw new IOException("Byte is exactly 1 byte. Provided buffer is smaller.");
+           }
+           if (b1[s1] != b2[s2]) {
+             return (b1[s1]<b2[s2])?-1:0;
+           }
+           s1++; s2++; l1--; l2--;
+        }
+        {
+           int i1 = WritableComparator.readVInt(b1, s1);
+           int i2 = WritableComparator.readVInt(b2, s2);
+           if (i1 != i2) {
+             return ((i1-i2) < 0) ? -1 : 0;
+           }
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+        }
+        {
+           long i1 = WritableComparator.readVLong(b1, s1);
+           long i2 = WritableComparator.readVLong(b2, s2);
+           if (i1 != i2) {
+             return ((i1-i2) < 0) ? -1 : 0;
+           }
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+        }
+        {
+           if (l1<4 || l2<4) {
+             throw new IOException("Float is exactly 4 bytes. Provided buffer is smaller.");
+           }
+           float f1 = WritableComparator.readFloat(b1, s1);
+           float f2 = WritableComparator.readFloat(b2, s2);
+           if (f1 != f2) {
+             return ((f1-f2) < 0) ? -1 : 0;
+           }
+           s1+=4; s2+=4; l1-=4; l2-=4;
+        }
+        {
+           if (l1<8 || l2<8) {
+             throw new IOException("Double is exactly 8 bytes. Provided buffer is smaller.");
+           }
+           double d1 = WritableComparator.readDouble(b1, s1);
+           double d2 = WritableComparator.readDouble(b2, s2);
+           if (d1 != d2) {
+             return ((d1-d2) < 0) ? -1 : 0;
+           }
+           s1+=8; s2+=8; l1-=8; l2-=8;
+        }
+        {
+           int i1 = WritableComparator.readVInt(b1, s1);
+           int i2 = WritableComparator.readVInt(b2, s2);
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+           int r1 = WritableComparator.compareBytes(b1,s1,l1,b2,s2,l2);
+           if (r1 != 0) { return (r1<0)?-1:0; }
+           s1+=i1; s2+=i2; l1-=i1; l1-=i2;
+        }
+        {
+           int i1 = WritableComparator.readVInt(b1, s1);
+           int i2 = WritableComparator.readVInt(b2, s2);
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+           int r1 = WritableComparator.compareBytes(b1,s1,l1,b2,s2,l2);
+           if (r1 != 0) { return (r1<0)?-1:0; }
+           s1+=i1; s2+=i2; l1-=i1; l1-=i2;
+        }
+        {
+           int vi11 = WritableComparator.readVInt(b1, s1);
+           int vi21 = WritableComparator.readVInt(b2, s2);
+           int vz11 = WritableUtils.getVIntSize(vi11);
+           int vz21 = WritableUtils.getVIntSize(vi21);
+           s1+=vz11; s2+=vz21; l1-=vz11; l2-=vz21;
+           for (int vidx1 = 0; vidx1 < vi11 && vidx1 < vi21; vidx1++)        {
+           int i1 = WritableComparator.readVInt(b1, s1);
+           int i2 = WritableComparator.readVInt(b2, s2);
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+           int r1 = WritableComparator.compareBytes(b1,s1,l1,b2,s2,l2);
+           if (r1 != 0) { return (r1<0)?-1:0; }
+           s1+=i1; s2+=i2; l1-=i1; l1-=i2;
+        }
+           if (vi11 != vi21) { return (vi11<vi21)?-1:0; }
+        }
+        {
+           int mi11 = WritableComparator.readVInt(b1, s1);
+           int mi21 = WritableComparator.readVInt(b2, s2);
+           int mz11 = WritableUtils.getVIntSize(mi11);
+           int mz21 = WritableUtils.getVIntSize(mi21);
+           s1+=mz11; s2+=mz21; l1-=mz11; l2-=mz21;
+           for (int midx1 = 0; midx1 < mi11 && midx1 < mi21; midx1++) {        {
+           int i1 = WritableComparator.readVInt(b1, s1);
+           int i2 = WritableComparator.readVInt(b2, s2);
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+           int r1 = WritableComparator.compareBytes(b1,s1,l1,b2,s2,l2);
+           if (r1 != 0) { return (r1<0)?-1:0; }
+           s1+=i1; s2+=i2; l1-=i1; l1-=i2;
+        }
+        {
+           int i = WritableComparator.readVInt(b1, s1);
+           int z = WritableUtils.getVIntSize(i);
+           s1+=(z+i); l1-= (z+i);
+        }
+        {
+           int i = WritableComparator.readVInt(b2, s2);
+           int z = WritableUtils.getVIntSize(i);
+           s2+=(z+i); l2-= (z+i);
+        }
+           }
+           if (mi11 != mi21) { return (mi11<mi21)?-1:0; }
+        }
+        {
+           int r1 = org.apache.hadoop.record.test.RecRecord0.Comparator.compareRaw(b1,s1,l1,b2,s2,l2);
+           if (r1 <= 0) { return r1; }
+           s1+=r1; s2+=r1; l1-=r1; l2-=r1;
+        }
+        return (os1 - s1);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    public int compare(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      int ret = compareRaw(b1,s1,l1,b2,s2,l2);
+      return (ret == -1)? -1 : ((ret==0)? 1 : 0);    }
+  }
+
+  static {
+    WritableComparator.define(RecRecord1.class, new Comparator());
+  }
 }

+ 55 - 18
src/test/org/apache/hadoop/record/test/RecString.java

@@ -1,26 +1,16 @@
-/**
- * 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.
- */
 // File generated by hadoop record compiler. Do not edit.
 package org.apache.hadoop.record.test;
 
+import java.io.IOException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.io.WritableComparator;
+import org.apache.hadoop.io.WritableComparable;
+import org.apache.hadoop.io.WritableUtils;
 import org.apache.hadoop.io.Text;
 
-public class RecString implements org.apache.hadoop.record.Record, org.apache.hadoop.io.WritableComparable {
+public class RecString implements org.apache.hadoop.record.Record, WritableComparable {
+  private static final Log LOG= LogFactory.getLog("org.apache.hadoop.record.test.RecString");
   private Text mData;
   private java.util.BitSet bs_;
   public RecString() {
@@ -112,4 +102,51 @@ public class RecString implements org.apache.hadoop.record.Record, org.apache.ha
   public static String signature() {
     return "LRecString(s)";
   }
+  public static class Comparator extends WritableComparator {
+    public Comparator() {
+      super(RecString.class);
+    }
+    static public int slurpRaw(byte[] b, int s, int l) {
+      try {
+        int os = s;
+        {
+           int i = WritableComparator.readVInt(b, s);
+           int z = WritableUtils.getVIntSize(i);
+           s+=(z+i); l-= (z+i);
+        }
+        return (os - s);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    static public int compareRaw(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      try {
+        int os1 = s1;
+        {
+           int i1 = WritableComparator.readVInt(b1, s1);
+           int i2 = WritableComparator.readVInt(b2, s2);
+           int z1 = WritableUtils.getVIntSize(i1);
+           int z2 = WritableUtils.getVIntSize(i2);
+           s1+=z1; s2+=z2; l1-=z1; l2-=z2;
+           int r1 = WritableComparator.compareBytes(b1,s1,l1,b2,s2,l2);
+           if (r1 != 0) { return (r1<0)?-1:0; }
+           s1+=i1; s2+=i2; l1-=i1; l1-=i2;
+        }
+        return (os1 - s1);
+      } catch(IOException e) {
+        LOG.warn(e);
+        throw new RuntimeException(e);
+      }
+    }
+    public int compare(byte[] b1, int s1, int l1,
+                       byte[] b2, int s2, int l2) {
+      int ret = compareRaw(b1,s1,l1,b2,s2,l2);
+      return (ret == -1)? -1 : ((ret==0)? 1 : 0);    }
+  }
+
+  static {
+    WritableComparator.define(RecString.class, new Comparator());
+  }
 }