phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jeffr...@apache.org
Subject [06/36] git commit: PHOENIX-113 Enable usage of ClientKeyValue on client-side (JamesTaylor)
Date Mon, 10 Mar 2014 04:21:37 GMT
PHOENIX-113 Enable usage of ClientKeyValue on client-side (JamesTaylor)


Project: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/commit/87608e14
Tree: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/tree/87608e14
Diff: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/diff/87608e14

Branch: refs/heads/4.0
Commit: 87608e14998fa7bf0af71346ee513a6fb6c25029
Parents: 511a5cd
Author: James Taylor <jamestaylor@apache.org>
Authored: Wed Mar 5 17:08:54 2014 -0800
Committer: James Taylor <jamestaylor@apache.org>
Committed: Wed Mar 5 17:08:54 2014 -0800

----------------------------------------------------------------------
 .../phoenix/client/ClientKeyValueBuilder.java   | 318 +++++++++++++++++--
 .../phoenix/client/GenericKeyValueBuilder.java  |  93 +++---
 .../apache/phoenix/client/KeyValueBuilder.java  |   8 +-
 .../coprocessor/MetaDataEndpointImpl.java       |   2 +-
 .../UngroupedAggregateRegionObserver.java       |  18 +-
 .../apache/phoenix/index/IndexMaintainer.java   | 111 ++++---
 .../apache/phoenix/index/PhoenixIndexCodec.java |  19 +-
 .../query/ConnectionQueryServicesImpl.java      |   6 +-
 .../query/ConnectionlessQueryServicesImpl.java  |  12 +-
 .../schema/tuple/MultiKeyValueTuple.java        |   3 +-
 .../phoenix/schema/tuple/ResultTuple.java       |   7 +-
 .../java/org/apache/phoenix/util/IndexUtil.java |  15 +-
 .../org/apache/phoenix/util/KeyValueUtil.java   |  92 ++++--
 .../org/apache/phoenix/util/MetaDataUtil.java   |  20 +-
 .../org/apache/phoenix/util/PhoenixRuntime.java |   5 +-
 .../org/apache/phoenix/util/ResultUtil.java     | 175 ----------
 .../phoenix/client/TestClientKeyValue.java      |   7 +-
 .../phoenix/client/TestClientKeyValueLocal.java |   9 +-
 .../TenantSpecificViewIndexSaltedTest.java      |   5 +-
 .../end2end/TenantSpecificViewIndexTest.java    |   5 +-
 .../apache/phoenix/util/MetaDataUtilTest.java   |   6 +-
 21 files changed, 543 insertions(+), 393 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/client/ClientKeyValueBuilder.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/client/ClientKeyValueBuilder.java b/phoenix-core/src/main/java/org/apache/phoenix/client/ClientKeyValueBuilder.java
index 71a1ddd..0ccded7 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/client/ClientKeyValueBuilder.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/client/ClientKeyValueBuilder.java
@@ -18,61 +18,323 @@
 package org.apache.phoenix.client;
 
 import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.KeyValue.KVComparator;
 import org.apache.hadoop.hbase.KeyValue.Type;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
 
+import com.google.common.primitives.Longs;
+
 /**
- * A {@link KeyValueBuilder} that builds {@link ClientKeyValue}, eliminating the extra byte copies
- * inherent in the standard {@link KeyValue} implementation.
+ * A {@link KeyValueBuilder} that builds {@link ClientKeyValue}, eliminating the extra byte copies inherent in the
+ * standard {@link KeyValue} implementation.
  * <p>
  * This {@link KeyValueBuilder} is only supported in HBase 0.94.14+ (
- * {@link PhoenixDatabaseMetaData#CLIENT_KEY_VALUE_BUILDER_THRESHOLD}), with the addition of
- * HBASE-9834.
+ * {@link PhoenixDatabaseMetaData#CLIENT_KEY_VALUE_BUILDER_THRESHOLD}), with the addition of HBASE-9834.
  */
 public class ClientKeyValueBuilder extends KeyValueBuilder {
 
     public static final KeyValueBuilder INSTANCE = new ClientKeyValueBuilder();
 
-  private ClientKeyValueBuilder() {
-    // private ctor for singleton
-  }
+    private ClientKeyValueBuilder() {
+        // private ctor for singleton
+    }
 
-  @Override
-  public KeyValue buildPut(ImmutableBytesWritable row, ImmutableBytesWritable family,
-      ImmutableBytesWritable qualifier, long ts, ImmutableBytesWritable value) {
-    return new ClientKeyValue(row, family, qualifier, ts, Type.Put, value);
-  }
+    @Override
+    public KeyValue buildPut(ImmutableBytesWritable row, ImmutableBytesWritable family,
+            ImmutableBytesWritable qualifier, long ts, ImmutableBytesWritable value) {
+        return new ClientKeyValue(row, family, qualifier, ts, Type.Put, value);
+    }
 
-  @Override
-  public KeyValue buildDeleteFamily(ImmutableBytesWritable row, ImmutableBytesWritable family,
+    @Override
+    public KeyValue buildDeleteFamily(ImmutableBytesWritable row, ImmutableBytesWritable family,
             ImmutableBytesWritable qualifier, long ts) {
         return new ClientKeyValue(row, family, qualifier, ts, Type.DeleteFamily, null);
-  }
+    }
 
-  @Override
-  public KeyValue buildDeleteColumns(ImmutableBytesWritable row, ImmutableBytesWritable family,
+    @Override
+    public KeyValue buildDeleteColumns(ImmutableBytesWritable row, ImmutableBytesWritable family,
             ImmutableBytesWritable qualifier, long ts) {
         return new ClientKeyValue(row, family, qualifier, ts, Type.DeleteColumn, null);
-  }
+    }
 
-  @Override
-  public KeyValue buildDeleteColumn(ImmutableBytesWritable row, ImmutableBytesWritable family,
+    @Override
+    public KeyValue buildDeleteColumn(ImmutableBytesWritable row, ImmutableBytesWritable family,
             ImmutableBytesWritable qualifier, long ts) {
         return new ClientKeyValue(row, family, qualifier, ts, Type.Delete, null);
-  }
+    }
 
-  @Override
-  public int compareQualifier(KeyValue kv, byte[] key, int offset, int length) {
+    @Override
+    public int compareQualifier(KeyValue kv, byte[] key, int offset, int length) {
         byte[] qual = kv.getQualifier();
         return Bytes.compareTo(qual, 0, qual.length, key, offset, length);
-  }
+    }
 
-  @Override
-  public void getValueAsPtr(KeyValue kv, ImmutableBytesWritable ptr) {
-        ClientKeyValue ckv = (ClientKeyValue) kv;
+    @Override
+    public void getValueAsPtr(KeyValue kv, ImmutableBytesWritable ptr) {
+        ClientKeyValue ckv = (ClientKeyValue)kv;
         ImmutableBytesWritable value = ckv.getRawValue();
         ptr.set(value.get(), value.getOffset(), value.getLength());
-  }
+    }
+
+    /**
+     * 
+     * Singleton ClientKeyValue version of KVComparator that doesn't assume we
+     * have a backing buffer for the key value
+     *
+     */
+    private static class ClientKeyValueComparator extends KVComparator {
+        private ClientKeyValueComparator() { // Singleton
+        }
+        
+        public int compareTypes(final KeyValue left, final KeyValue right) {
+            return left.getType() - right.getType();
+        }
+
+        public int compareMemstoreTimestamps(final KeyValue left, final KeyValue right) {
+            // Descending order
+            return Longs.compare(right.getMemstoreTS(), left.getMemstoreTS());
+        }
+
+        @Override
+        public int compareTimestamps(final KeyValue left, final KeyValue right) {
+            // Descending order
+            return Longs.compare(right.getTimestamp(), left.getTimestamp());
+        }
+
+
+        @Override
+        public int compare(final KeyValue left, final KeyValue right) {
+            int c = compareRows(left, right);
+            if (c != 0) return c;
+            c = Bytes.compareTo(left.getFamily(), right.getFamily());
+            if (c != 0) return c;
+            c = Bytes.compareTo(left.getQualifier(), right.getQualifier());
+            c = compareTimestamps(left, right);
+            if (c != 0) return c;
+            c = compareTypes(left, right);
+            if (c != 0) return c;            
+            
+            return compareMemstoreTimestamps(left, right);
+        }
+
+        /**
+         * @param left
+         * @param right
+         * @return Result comparing rows.
+         */
+        @Override
+        public int compareRows(final KeyValue left, final KeyValue right) {
+            return Bytes.compareTo(left.getRow(), right.getRow());
+        }
+
+        /**
+         * @param left
+         * @param lrowlength Length of left row.
+         * @param right
+         * @param rrowlength Length of right row.
+         * @return Result comparing rows.
+         */
+        @Override
+        public int compareRows(final KeyValue left, final short lrowlength,
+            final KeyValue right, final short rrowlength) {
+            return Bytes.compareTo(left.getRow(), 0, lrowlength, right.getRow(), 0, rrowlength);
+        }
+
+        /**
+         * @param left
+         * @param row - row key (arbitrary byte array)
+         * @return RawComparator
+         */
+        @Override
+        public int compareRows(final KeyValue left, final byte [] row) {
+            return Bytes.compareTo(left.getRow(), row);
+        }
+
+        @Override
+        public int compareColumns(final KeyValue left, 
+                final byte [] right, final int roffset, final int rlength, final int rfamilyLength) {
+          // Compare family portion first.
+          byte[] lcf = left.getFamily();
+          int diff = Bytes.compareTo(lcf, 0, lcf.length,
+            right, roffset, rfamilyLength);
+          if (diff != 0) {
+            return diff;
+          }
+          // Compare qualifier portion
+          byte[] lcq = left.getQualifier();
+          return Bytes.compareTo(lcq, 0, lcq.length,
+            right, roffset + rfamilyLength, rlength - rfamilyLength);
+
+        }
+
+        /**
+         * Compares the row and column of two keyvalues for equality
+         * @param left
+         * @param right
+         * @return True if same row and column.
+         */
+        @Override
+        public boolean matchingRowColumn(final KeyValue left, final KeyValue right) {
+            if (compareRows(left, right) != 0) {
+                return false;
+            }
+            if (Bytes.compareTo(left.getFamily(), right.getFamily()) != 0) {
+                return false;
+            }
+            if (Bytes.compareTo(left.getQualifier(), right.getQualifier()) != 0) {
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * @param left
+         * @param right
+         * @return True if rows match.
+         */
+        @Override
+        public boolean matchingRows(final KeyValue left, final byte [] right) {
+          return Bytes.equals(left.getRow(), right);
+        }
+
+        /**
+         * Compares the row of two keyvalues for equality
+         * @param left
+         * @param right
+         * @return True if rows match.
+         */
+        @Override
+        public boolean matchingRows(final KeyValue left, final KeyValue right) {
+            return compareRows(left, right) == 0;
+        }
+
+        /**
+         * @param left
+         * @param lrowlength
+         * @param right
+         * @param rrowlength
+         * @return True if rows match.
+         */
+        @Override
+        public boolean matchingRows(final KeyValue left, final short lrowlength,
+            final KeyValue right, final short rrowlength) {
+            return compareRows(left, lrowlength, right, rrowlength) == 0;
+        }
+
+        @Override
+        protected Object clone() throws CloneNotSupportedException {
+          return this; // Makes no sense to clone this
+        }
+
+        /**
+         * @return Comparator that ignores timestamps; useful counting versions.
+         */
+        @Override
+        public KVComparator getComparatorIgnoringTimestamps() {
+            return IGNORE_TIMESTAMP_COMPARATOR;
+        }
+
+        /**
+         * @return Comparator that ignores key type; useful checking deletes
+         */
+        @Override
+        public KVComparator getComparatorIgnoringType() {
+            return IGNORE_TYPE_COMPARATOR;
+        }
+    }
+    
+    /**
+     * 
+     * Singleton ClientKeyValue version of KVComparator that ignores differences in the Type
+     *
+     */
+    private static class IgnoreTypeClientKeyValueComparator extends ClientKeyValueComparator {
+        private IgnoreTypeClientKeyValueComparator() { // Singleton
+        }
+        
+        @Override
+        public int compareTypes(final KeyValue left, final KeyValue right) {
+            return 0;
+        }
+        
+        @Override
+        public KVComparator getComparatorIgnoringTimestamps() {
+            return IGNORE_TIMESTAMP_AND_TYPE_COMPARATOR;
+        }
+    }
+
+
+    /**
+     * 
+     * Singleton ClientKeyValue version of KVComparator that ignores differences in the Timestamp
+     *
+     */
+    private static class IgnoreTimestampClientKeyValueComparator extends ClientKeyValueComparator {
+        private IgnoreTimestampClientKeyValueComparator() { // Singleton
+        }
+        
+        @Override
+        public int compareMemstoreTimestamps(final KeyValue left, final KeyValue right) {
+            return 0;
+        }
+
+        @Override
+        public int compareTimestamps(final KeyValue left, final KeyValue right) {
+            return 0;
+        }
+        
+        @Override
+        public KVComparator getComparatorIgnoringType() {
+            return IGNORE_TYPE_COMPARATOR;
+        }
+    }
+    
+    /**
+     * 
+     * Singleton ClientKeyValue version of KVComparator that ignores differences in the Timestamp and Type
+     *
+     */
+    private static final class IgnoreTimestampAndTypeClientKeyValueComparator extends IgnoreTimestampClientKeyValueComparator {
+        private IgnoreTimestampAndTypeClientKeyValueComparator() { // Singleton
+        }
+        
+        @Override
+        public int compareTypes(final KeyValue left, final KeyValue right) {
+            return 0;
+        }
+
+        @Override
+        public KVComparator getComparatorIgnoringTimestamps() {
+            return this;
+        }
+
+        @Override
+        public KVComparator getComparatorIgnoringType() {
+            return this;
+        }
+    }
+
+    private static final KVComparator COMPARATOR = new ClientKeyValueComparator();
+    private static final KVComparator IGNORE_TYPE_COMPARATOR = new IgnoreTypeClientKeyValueComparator();
+    private static final KVComparator IGNORE_TIMESTAMP_COMPARATOR = new IgnoreTimestampClientKeyValueComparator();
+    private static final KVComparator IGNORE_TIMESTAMP_AND_TYPE_COMPARATOR = new IgnoreTimestampAndTypeClientKeyValueComparator();
+    
+    @Override
+    public KVComparator getKeyValueComparator() {
+        return COMPARATOR;
+    }
+
+    @Override
+    public int compareRow(KeyValue kv, byte[] rrow, int roffset, int rlength) {
+        byte[] lrow = kv.getRow();
+        return Bytes.compareTo(lrow, 0, lrow.length, rrow, roffset, rlength);
+    }
+
+    @Override
+    public int compareFamily(KeyValue kv, byte[] rbuf, int roffset, int rlength) {
+        byte[] lcf = kv.getFamily();
+        return Bytes.compareTo(lcf, 0, lcf.length, rbuf, roffset, rlength);
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/client/GenericKeyValueBuilder.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/client/GenericKeyValueBuilder.java b/phoenix-core/src/main/java/org/apache/phoenix/client/GenericKeyValueBuilder.java
index b374e1d..d5ec825 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/client/GenericKeyValueBuilder.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/client/GenericKeyValueBuilder.java
@@ -20,6 +20,7 @@ package org.apache.phoenix.client;
 import static org.apache.phoenix.hbase.index.util.ImmutableBytesPtr.copyBytesIfNecessary;
 
 import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.KeyValue.KVComparator;
 import org.apache.hadoop.hbase.KeyValue.Type;
 import org.apache.hadoop.hbase.client.Delete;
 import org.apache.hadoop.hbase.client.Put;
@@ -27,55 +28,69 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Bytes;
 
 /**
- * {@link KeyValueBuilder} that does simple byte[] copies to build the underlying key-value. This is
- * exactly the same behavior as currently used in {@link Delete} and {@link Put}.
+ * {@link KeyValueBuilder} that does simple byte[] copies to build the underlying key-value. This is exactly the same
+ * behavior as currently used in {@link Delete} and {@link Put}.
  */
 public class GenericKeyValueBuilder extends KeyValueBuilder {
 
-  public static final KeyValueBuilder INSTANCE = new GenericKeyValueBuilder();
+    public static final KeyValueBuilder INSTANCE = new GenericKeyValueBuilder();
 
-  private GenericKeyValueBuilder() {
-    // private ctor for singleton
-  }
+    private GenericKeyValueBuilder() {
+        // private ctor for singleton
+    }
 
-  @Override
-  public KeyValue buildPut(ImmutableBytesWritable row, ImmutableBytesWritable family,
-      ImmutableBytesWritable qualifier, long ts, ImmutableBytesWritable value) {
-    return build(row, family, qualifier, ts, Type.Put, value);
-  }
+    @Override
+    public KeyValue buildPut(ImmutableBytesWritable row, ImmutableBytesWritable family,
+            ImmutableBytesWritable qualifier, long ts, ImmutableBytesWritable value) {
+        return build(row, family, qualifier, ts, Type.Put, value);
+    }
 
-  @Override
-  public KeyValue buildDeleteFamily(ImmutableBytesWritable row, ImmutableBytesWritable family,
-      ImmutableBytesWritable qualifier, long ts) {
-    return build(row, family, qualifier, ts, Type.DeleteFamily, null);
-  }
+    @Override
+    public KeyValue buildDeleteFamily(ImmutableBytesWritable row, ImmutableBytesWritable family,
+            ImmutableBytesWritable qualifier, long ts) {
+        return build(row, family, qualifier, ts, Type.DeleteFamily, null);
+    }
 
-  @Override
-  public KeyValue buildDeleteColumns(ImmutableBytesWritable row, ImmutableBytesWritable family,
-      ImmutableBytesWritable qualifier, long ts) {
-    return build(row, family, qualifier, ts, Type.DeleteColumn, null);
-  }
+    @Override
+    public KeyValue buildDeleteColumns(ImmutableBytesWritable row, ImmutableBytesWritable family,
+            ImmutableBytesWritable qualifier, long ts) {
+        return build(row, family, qualifier, ts, Type.DeleteColumn, null);
+    }
 
-  @Override
-  public KeyValue buildDeleteColumn(ImmutableBytesWritable row, ImmutableBytesWritable family,
+    @Override
+    public KeyValue buildDeleteColumn(ImmutableBytesWritable row, ImmutableBytesWritable family,
             ImmutableBytesWritable qualifier, long ts) {
-    return build(row, family, qualifier, ts, Type.Delete, null);
-  }
+        return build(row, family, qualifier, ts, Type.Delete, null);
+    }
+
+    private KeyValue build(ImmutableBytesWritable row, ImmutableBytesWritable family, ImmutableBytesWritable qualifier,
+            long ts, KeyValue.Type type, ImmutableBytesWritable value) {
+        return new KeyValue(copyBytesIfNecessary(row), copyBytesIfNecessary(family), copyBytesIfNecessary(qualifier),
+                ts, type, value == null ? null : copyBytesIfNecessary(value));
+    }
+
+    @Override
+    public int compareQualifier(KeyValue kv, byte[] key, int offset, int length) {
+        return Bytes.compareTo(kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength(), key, offset, length);
+    }
+
+    @Override
+    public int compareFamily(KeyValue kv, byte[] key, int offset, int length) {
+        return Bytes.compareTo(kv.getBuffer(), kv.getFamilyOffset(), kv.getFamilyLength(), key, offset, length);
+    }
 
-  private KeyValue build(ImmutableBytesWritable row, ImmutableBytesWritable family,
-      ImmutableBytesWritable qualifier, long ts, KeyValue.Type type, ImmutableBytesWritable value) {
-    return new KeyValue(copyBytesIfNecessary(row), copyBytesIfNecessary(family),
-        copyBytesIfNecessary(qualifier), ts, type, value == null? null: copyBytesIfNecessary(value));
-  }
+    @Override
+    public void getValueAsPtr(KeyValue kv, ImmutableBytesWritable writable) {
+        writable.set(kv.getBuffer(), kv.getValueOffset(), kv.getValueLength());
+    }
 
-  @Override
-  public int compareQualifier(KeyValue kv, byte[] key, int offset, int length) {
-    return Bytes.compareTo(kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength(), key,
-      offset, length);
-  }
+    @Override
+    public KVComparator getKeyValueComparator() {
+        return KeyValue.COMPARATOR;
+    }
 
-  @Override
-  public void getValueAsPtr(KeyValue kv, ImmutableBytesWritable writable) {
-    writable.set(kv.getBuffer(), kv.getValueOffset(), kv.getValueLength());
-  }
+    @Override
+    public int compareRow(KeyValue kv, byte[] rrow, int roffset, int rlength) {
+        return Bytes.compareTo(kv.getBuffer(), kv.getRowOffset(), kv.getRowLength(), rrow, roffset, rlength);
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/client/KeyValueBuilder.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/client/KeyValueBuilder.java b/phoenix-core/src/main/java/org/apache/phoenix/client/KeyValueBuilder.java
index 1a76dfd..6849dc3 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/client/KeyValueBuilder.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/client/KeyValueBuilder.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.KeyValue.KVComparator;
 import org.apache.hadoop.hbase.client.Delete;
 import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
@@ -61,8 +62,7 @@ public abstract class KeyValueBuilder {
         }
     }
 
-    // FIXME: Temporarily disabling usage of this pending more testing
-    private static final int CUSTOM_KEY_VALUE_MIN_VERSION = MetaDataUtil.encodeVersion("0.94.99");
+    private static final int CUSTOM_KEY_VALUE_MIN_VERSION = MetaDataUtil.encodeVersion("0.94.14");
 
     public static KeyValueBuilder get(String hbaseVersion) {
         int version = MetaDataUtil.encodeVersion(hbaseVersion);
@@ -115,9 +115,13 @@ public abstract class KeyValueBuilder {
    */
   public abstract int compareQualifier(KeyValue kv, byte[] key, int offset, int length);
 
+  public abstract int compareFamily(KeyValue kv, byte[] key, int offset, int length);
+  public abstract int compareRow(KeyValue kv, byte[] row, int offset, int length);
   /**
    * @param kv to read
    * @param ptr set with the value from the {@link KeyValue}
    */
   public abstract void getValueAsPtr(KeyValue kv, ImmutableBytesWritable ptr);
+  
+  public abstract KVComparator getKeyValueComparator();
 }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
index 89cc4d2..b911120 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
@@ -715,7 +715,7 @@ public class MetaDataEndpointImpl extends BaseEndpointCoprocessor implements Met
         if (results.isEmpty()) {
             return new MetaDataMutationResult(MutationCode.TABLE_NOT_FOUND, EnvironmentEdgeManager.currentTimeMillis(), null);
         }
-        KeyValue typeKeyValue = KeyValueUtil.getColumnLatest(results, PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES, PhoenixDatabaseMetaData.TABLE_TYPE_BYTES);
+        KeyValue typeKeyValue = KeyValueUtil.getColumnLatest(GenericKeyValueBuilder.INSTANCE, results, PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES, PhoenixDatabaseMetaData.TABLE_TYPE_BYTES);
         assert(typeKeyValue != null && typeKeyValue.getValueLength() == 1);
         if ( tableType != PTableType.fromSerializedValue(typeKeyValue.getBuffer()[typeKeyValue.getValueOffset()]))  {
             // We said to drop a table, but found a view or visa versa

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
index 0a840d4..d77276b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java
@@ -50,12 +50,7 @@ import org.apache.hadoop.hbase.regionserver.RegionScanner;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.Pair;
 import org.apache.hadoop.io.WritableUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
+import org.apache.phoenix.client.GenericKeyValueBuilder;
 import org.apache.phoenix.client.KeyValueBuilder;
 import org.apache.phoenix.exception.ValueTypeIncompatibleException;
 import org.apache.phoenix.expression.Expression;
@@ -68,18 +63,23 @@ import org.apache.phoenix.join.HashJoinInfo;
 import org.apache.phoenix.join.ScanProjector;
 import org.apache.phoenix.query.QueryConstants;
 import org.apache.phoenix.query.QueryServicesOptions;
-import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.schema.ConstraintViolationException;
 import org.apache.phoenix.schema.PColumn;
 import org.apache.phoenix.schema.PDataType;
 import org.apache.phoenix.schema.PRow;
 import org.apache.phoenix.schema.PTable;
 import org.apache.phoenix.schema.PTableImpl;
+import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.schema.tuple.MultiKeyValueTuple;
 import org.apache.phoenix.util.ByteUtil;
 import org.apache.phoenix.util.KeyValueUtil;
 import org.apache.phoenix.util.ScanUtil;
 import org.apache.phoenix.util.SchemaUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
 
 /**
@@ -103,7 +103,9 @@ public class UngroupedAggregateRegionObserver extends BaseScannerRegionObserver
     @Override
     public void start(CoprocessorEnvironment e) throws IOException {
         super.start(e);
-        this.kvBuilder = KeyValueBuilder.get(e.getHBaseVersion());
+        // Can't use ClientKeyValueBuilder on server-side because the memstore expects to
+        // be able to get a single backing buffer for a KeyValue.
+        this.kvBuilder = GenericKeyValueBuilder.INSTANCE;
     }
 
     private static void commitBatch(HRegion region, List<Pair<Mutation,Integer>> mutations, byte[] indexUUID) throws IOException {

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java b/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java
index fcd3c94..e3d7588 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java
@@ -49,6 +49,7 @@ import org.apache.phoenix.schema.PColumnFamily;
 import org.apache.phoenix.schema.PDataType;
 import org.apache.phoenix.schema.PIndexState;
 import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.PTable.ViewType;
 import org.apache.phoenix.schema.PTableType;
 import org.apache.phoenix.schema.RowKeySchema;
 import org.apache.phoenix.schema.SaltingUtil;
@@ -87,8 +88,8 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
         if (dataTable.getType() == PTableType.INDEX || index.getType() != PTableType.INDEX || !dataTable.getIndexes().contains(index)) {
             throw new IllegalArgumentException();
         }
-        int indexPosOffset = index.getBucketNum() == null ? 0 : 1;
         IndexMaintainer maintainer = new IndexMaintainer(dataTable, index);
+        int indexPosOffset = (index.getBucketNum() == null ? 0 : 1) + (maintainer.isMultiTenant ? 1 : 0) + (maintainer.viewIndexId == null ? 0 : 1);
         RowKeyMetaData rowKeyMetaData = maintainer.getRowKeyMetaData();
         for (int i = indexPosOffset; i < index.getPKColumns().size(); i++) {
             PColumn indexColumn = index.getPKColumns().get(i);
@@ -96,7 +97,7 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
             PColumn column = IndexUtil.getDataColumn(dataTable, indexColumn.getName().getString());
             boolean isPKColumn = SchemaUtil.isPKColumn(column);
             if (isPKColumn) {
-                int dataPkPos = dataTable.getPKColumns().indexOf(column) - (dataTable.getBucketNum() == null ? 0 : 1);
+                int dataPkPos = dataTable.getPKColumns().indexOf(column) - (dataTable.getBucketNum() == null ? 0 : 1) - (maintainer.isMultiTenant ? 1 : 0);
                 rowKeyMetaData.setIndexPkPosition(dataPkPos, indexPos);
             } else {
                 maintainer.getIndexedColumnTypes().add(column.getDataType());
@@ -164,16 +165,14 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
     
     public static List<IndexMaintainer> deserialize(ImmutableBytesWritable metaDataPtr,
             KeyValueBuilder builder) {
-        return deserialize(metaDataPtr.get(), metaDataPtr.getOffset(), metaDataPtr.getLength(),
-            builder);
+        return deserialize(metaDataPtr.get(), metaDataPtr.getOffset(), metaDataPtr.getLength());
     }
     
-    public static List<IndexMaintainer> deserialize(byte[] buf, KeyValueBuilder builder) {
-        return deserialize(buf, 0, buf.length, builder);
+    public static List<IndexMaintainer> deserialize(byte[] buf) {
+        return deserialize(buf, 0, buf.length);
     }
 
-    public static List<IndexMaintainer> deserialize(byte[] buf, int offset, int length,
-            KeyValueBuilder builder) {
+    public static List<IndexMaintainer> deserialize(byte[] buf, int offset, int length) {
         ByteArrayInputStream stream = new ByteArrayInputStream(buf, offset, length);
         DataInput input = new DataInputStream(stream);
         List<IndexMaintainer> maintainers = Collections.emptyList();
@@ -187,7 +186,6 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
             for (int i = 0; i < size; i++) {
                 IndexMaintainer maintainer = new IndexMaintainer(rowKeySchema, isDataTableSalted);
                 maintainer.readFields(input);
-                maintainer.setKvBuilder(builder);
                 maintainers.add(maintainer);
             }
         } catch (IOException e) {
@@ -220,7 +218,6 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
     private int[] dataPkPosition;
     private int maxTrailingNulls;
     private ColumnReference dataEmptyKeyValueRef;
-    private KeyValueBuilder kvBuilder;
     
     private IndexMaintainer(RowKeySchema dataRowKeySchema, boolean isDataTableSalted) {
         this.dataRowKeySchema = dataRowKeySchema;
@@ -229,18 +226,35 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
 
     private IndexMaintainer(PTable dataTable, PTable index) {
         this(dataTable.getRowKeySchema(), dataTable.getBucketNum() != null);
+        this.isMultiTenant = dataTable.isMultiTenant();
+        this.viewIndexId = index.getViewIndexId() == null ? null : MetaDataUtil.getViewIndexIdDataType().toBytes(index.getViewIndexId());
+
         RowKeySchema dataRowKeySchema = dataTable.getRowKeySchema();
         boolean isDataTableSalted = dataTable.getBucketNum() != null;
         byte[] indexTableName = index.getPhysicalName().getBytes();
         Integer nIndexSaltBuckets = index.getBucketNum();
         boolean indexWALDisabled = index.isWALDisabled();
-        int indexPosOffset = index.getBucketNum() == null ? 0 : 1;
+        int indexPosOffset = (index.getBucketNum() == null ? 0 : 1) + (this.isMultiTenant ? 1 : 0) + (this.viewIndexId == null ? 0 : 1);
         int nIndexColumns = index.getColumns().size() - indexPosOffset;
         int nIndexPKColumns = index.getPKColumns().size() - indexPosOffset;
-
-        int nDataPKColumns = dataRowKeySchema.getFieldCount() - (isDataTableSalted ? 1 : 0);
-        this.isMultiTenant = dataTable.isMultiTenant();
-        this.viewIndexId = dataTable.getViewIndexId() == null ? null : MetaDataUtil.getViewIndexIdDataType().toBytes(dataTable.getViewIndexId());
+        this.rowKeyMetaData = newRowKeyMetaData(nIndexPKColumns);
+        BitSet bitSet = this.rowKeyMetaData.getViewConstantColumnBitSet();
+
+        int dataPosOffset = (isDataTableSalted ? 1 : 0) + (this.isMultiTenant ? 1 : 0);
+        int nDataPKColumns = dataRowKeySchema.getFieldCount() - dataPosOffset;
+        // For indexes on updatable views, we need to remember which data columns are "constants"
+        // These are the values in a VIEW where clause. For these, we don't put them in the
+        // index, as they're the same for every row in the index.
+        if (dataTable.getViewType() == ViewType.UPDATABLE) {
+            List<PColumn>dataPKColumns = dataTable.getPKColumns();
+            for (int i = dataPosOffset; i < dataPKColumns.size(); i++) {
+                PColumn dataPKColumn = dataPKColumns.get(i);
+                if (dataPKColumn.getViewConstant() != null) {
+                    bitSet.set(i);
+                    nDataPKColumns--;
+                }
+            }
+        }
         this.indexTableName = indexTableName;
         this.indexedColumns = Sets.newLinkedHashSetWithExpectedSize(nIndexPKColumns-nDataPKColumns);
         this.indexedColumnTypes = Lists.<PDataType>newArrayListWithExpectedSize(nIndexPKColumns-nDataPKColumns);
@@ -249,7 +263,6 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
         this.allColumns = Sets.newLinkedHashSetWithExpectedSize(nDataPKColumns + nIndexColumns);
         this.allColumns.addAll(indexedColumns);
         this.allColumns.addAll(coveredColumns);
-        this.rowKeyMetaData = newRowKeyMetaData(nIndexPKColumns);
         this.nIndexSaltBuckets  = nIndexSaltBuckets == null ? 0 : nIndexSaltBuckets;
         this.dataEmptyKeyValueCF = SchemaUtil.getEmptyColumnFamily(dataTable);
         this.emptyKeyValueCFPtr = SchemaUtil.getEmptyColumnFamilyPtr(index);
@@ -285,16 +298,22 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
                 output.write(viewIndexId);
             }
             
+            BitSet viewConstantColumnBitSet = this.rowKeyMetaData.getViewConstantColumnBitSet();
             // Write index row key
             for (int i = dataPosOffset; i < dataRowKeySchema.getFieldCount(); i++) {
                 Boolean hasValue=dataRowKeySchema.next(ptr, i, maxRowKeyOffset);
-                int pos = rowKeyMetaData.getIndexPkPosition(i-dataPosOffset);
-                if (Boolean.TRUE.equals(hasValue)) {
-                    dataRowKeyLocator[0][pos] = ptr.getOffset();
-                    dataRowKeyLocator[1][pos] = ptr.getLength();
-                } else {
-                    dataRowKeyLocator[0][pos] = 0;
-                    dataRowKeyLocator[1][pos] = 0;
+                // Ignore view constants from the data table, as these
+                // don't need to appear in the index (as they're the
+                // same for all rows in this index)
+                if (!viewConstantColumnBitSet.get(i)) {
+                    int pos = rowKeyMetaData.getIndexPkPosition(i-dataPosOffset);
+                    if (Boolean.TRUE.equals(hasValue)) {
+                        dataRowKeyLocator[0][pos] = ptr.getOffset();
+                        dataRowKeyLocator[1][pos] = ptr.getLength();
+                    } else {
+                        dataRowKeyLocator[0][pos] = 0;
+                        dataRowKeyLocator[1][pos] = 0;
+                    }
                 }
             }
             BitSet descIndexColumnBitSet = rowKeyMetaData.getDescIndexColumnBitSet();
@@ -365,14 +384,14 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
     }
 
     @SuppressWarnings("deprecation")
-    public Put buildUpdateMutation(ValueGetter valueGetter, ImmutableBytesWritable dataRowKeyPtr, long ts) throws IOException {
+    public Put buildUpdateMutation(KeyValueBuilder kvBuilder, ValueGetter valueGetter, ImmutableBytesWritable dataRowKeyPtr, long ts) throws IOException {
         Put put = null;
         // New row being inserted: add the empty key value
         if (valueGetter.getLatestValue(dataEmptyKeyValueRef) == null) {
             byte[] indexRowKey = this.buildRowKey(valueGetter, dataRowKeyPtr);
             put = new Put(indexRowKey);
             // add the keyvalue for the empty row
-            put.add(this.kvBuilder.buildPut(new ImmutableBytesPtr(indexRowKey),
+            put.add(kvBuilder.buildPut(new ImmutableBytesPtr(indexRowKey),
                 this.getEmptyKeyValueFamily(), QueryConstants.EMPTY_COLUMN_BYTES_PTR, ts,
                 ByteUtil.EMPTY_BYTE_ARRAY_PTR));
             put.setWriteToWAL(!indexWALDisabled);
@@ -389,18 +408,18 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
                     put.setWriteToWAL(!indexWALDisabled);
                 }
                 //this is a little bit of extra work for installations that are running <0.94.14, but that should be rare and is a short-term set of wrappers - it shouldn't kill GC
-                put.add(this.kvBuilder.buildPut(rowKey, ref.getFamilyWritable(), cq, ts, value));
+                put.add(kvBuilder.buildPut(rowKey, ref.getFamilyWritable(), cq, ts, value));
             }
         }
         return put;
     }
 
-    public Put buildUpdateMutation(ValueGetter valueGetter, ImmutableBytesWritable dataRowKeyPtr) throws IOException {
-        return buildUpdateMutation(valueGetter, dataRowKeyPtr, HConstants.LATEST_TIMESTAMP);
+    public Put buildUpdateMutation(KeyValueBuilder kvBuilder, ValueGetter valueGetter, ImmutableBytesWritable dataRowKeyPtr) throws IOException {
+        return buildUpdateMutation(kvBuilder, valueGetter, dataRowKeyPtr, HConstants.LATEST_TIMESTAMP);
     }
     
-    public Delete buildDeleteMutation(ValueGetter valueGetter, ImmutableBytesWritable dataRowKeyPtr, Collection<KeyValue> pendingUpdates) throws IOException {
-        return buildDeleteMutation(valueGetter, dataRowKeyPtr, pendingUpdates, HConstants.LATEST_TIMESTAMP);
+    public Delete buildDeleteMutation(KeyValueBuilder kvBuilder, ValueGetter valueGetter, ImmutableBytesWritable dataRowKeyPtr, Collection<KeyValue> pendingUpdates) throws IOException {
+        return buildDeleteMutation(kvBuilder, valueGetter, dataRowKeyPtr, pendingUpdates, HConstants.LATEST_TIMESTAMP);
     }
     
     public boolean isRowDeleted(Collection<KeyValue> pendingUpdates) {
@@ -445,13 +464,14 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
     /**
      * Used for immutable indexes that only index PK column values. In that case, we can handle a data row deletion,
      * since we can build the corresponding index row key.
+     * @param kvBuilder TODO
      */
-    public Delete buildDeleteMutation(ImmutableBytesWritable dataRowKeyPtr, long ts) throws IOException {
-        return buildDeleteMutation(null, dataRowKeyPtr, Collections.<KeyValue>emptyList(), ts);
+    public Delete buildDeleteMutation(KeyValueBuilder kvBuilder, ImmutableBytesWritable dataRowKeyPtr, long ts) throws IOException {
+        return buildDeleteMutation(kvBuilder, null, dataRowKeyPtr, Collections.<KeyValue>emptyList(), ts);
     }
     
     @SuppressWarnings("deprecation")
-    public Delete buildDeleteMutation(ValueGetter oldState, ImmutableBytesWritable dataRowKeyPtr, Collection<KeyValue> pendingUpdates, long ts) throws IOException {
+    public Delete buildDeleteMutation(KeyValueBuilder kvBuilder, ValueGetter oldState, ImmutableBytesWritable dataRowKeyPtr, Collection<KeyValue> pendingUpdates, long ts) throws IOException {
         byte[] indexRowKey = this.buildRowKey(oldState, dataRowKeyPtr);
         // Delete the entire row if any of the indexed columns changed
         if (oldState == null || isRowDeleted(pendingUpdates) || hasIndexedColumnChanged(oldState, pendingUpdates)) { // Deleting the entire row
@@ -651,13 +671,16 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
         allColumns.addAll(indexedColumns);
         allColumns.addAll(coveredColumns);
         
-        int dataPkOffset = isDataTableSalted ? 1 : 0;
+        int dataPkOffset = (isDataTableSalted ? 1 : 0) + (isMultiTenant ? 1 : 0);
         int nIndexPkColumns = getIndexPkColumnCount();
         dataPkPosition = new int[nIndexPkColumns];
         Arrays.fill(dataPkPosition, -1);
+        BitSet viewConstantColumnBitSet = rowKeyMetaData.getViewConstantColumnBitSet();
         for (int i = dataPkOffset; i < dataRowKeySchema.getFieldCount(); i++) {
-            int dataPkPosition = rowKeyMetaData.getIndexPkPosition(i-dataPkOffset);
-            this.dataPkPosition[dataPkPosition] = i;
+            if (!viewConstantColumnBitSet.get(i)) {
+                int dataPkPosition = rowKeyMetaData.getIndexPkPosition(i-dataPkOffset);
+                this.dataPkPosition[dataPkPosition] = i;
+            }
         }
         
         // Calculate the max number of trailing nulls that we should get rid of after building the index row key.
@@ -686,12 +709,8 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
         maxTrailingNulls = nIndexPkColumns-indexPkPos-1;
     }
 
-    public void setKvBuilder(KeyValueBuilder builder) {
-        this.kvBuilder = builder;
-    }
-
     private int getIndexPkColumnCount() {
-        return dataRowKeySchema.getFieldCount() + indexedColumns.size() - (isDataTableSalted ? 1 : 0);
+        return dataRowKeySchema.getFieldCount() + indexedColumns.size() - (isDataTableSalted ? 1 : 0) - (isMultiTenant ? 1 : 0) - (viewIndexId == null ? 0 : 1);
     }
     
     private RowKeyMetaData newRowKeyMetaData() {
@@ -711,12 +730,14 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
     
     private abstract class RowKeyMetaData implements Writable {
         private BitSet descIndexColumnBitSet;
+        private BitSet viewConstantColumnBitSet;
         
         private RowKeyMetaData() {
         }
         
         private RowKeyMetaData(int nIndexedColumns) {
             descIndexColumnBitSet = BitSet.withCapacity(nIndexedColumns);
+            viewConstantColumnBitSet = BitSet.withCapacity(dataRowKeySchema.getMaxFields()); // Size based on number of data PK columns
       }
         
         protected int getByteSize() {
@@ -730,17 +751,25 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
         public void readFields(DataInput input) throws IOException {
             int length = getIndexPkColumnCount();
             descIndexColumnBitSet = BitSet.read(input, length);
+            int vclength = dataRowKeySchema.getMaxFields();
+            viewConstantColumnBitSet = BitSet.read(input, vclength);
         }
         
         @Override
         public void write(DataOutput output) throws IOException {
             int length = getIndexPkColumnCount();
             BitSet.write(output, descIndexColumnBitSet, length);
+            int vclength = dataRowKeySchema.getMaxFields();
+            BitSet.write(output, viewConstantColumnBitSet, vclength);
         }
 
         private BitSet getDescIndexColumnBitSet() {
             return descIndexColumnBitSet;
         }
+
+        private BitSet getViewConstantColumnBitSet() {
+            return viewConstantColumnBitSet;
+        }
     }
     
     private static int BYTE_OFFSET = 127;

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/index/PhoenixIndexCodec.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/index/PhoenixIndexCodec.java b/phoenix-core/src/main/java/org/apache/phoenix/index/PhoenixIndexCodec.java
index 762ca7c..d184c46 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/index/PhoenixIndexCodec.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/index/PhoenixIndexCodec.java
@@ -30,12 +30,11 @@ import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Pair;
-
-import com.google.common.collect.Lists;
 import org.apache.phoenix.cache.GlobalCache;
 import org.apache.phoenix.cache.IndexMetaDataCache;
 import org.apache.phoenix.cache.ServerCacheClient;
 import org.apache.phoenix.cache.TenantCache;
+import org.apache.phoenix.client.GenericKeyValueBuilder;
 import org.apache.phoenix.client.KeyValueBuilder;
 import org.apache.phoenix.exception.SQLExceptionCode;
 import org.apache.phoenix.exception.SQLExceptionInfo;
@@ -50,6 +49,8 @@ import org.apache.phoenix.hbase.index.write.IndexWriter;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.ServerUtil;
 
+import com.google.common.collect.Lists;
+
 /**
  * Phoenix-based {@link IndexCodec}. Manages all the logic of how to cleanup an index (
  * {@link #getIndexDeletes(TableState)}) as well as what the new index state should be (
@@ -60,7 +61,7 @@ public class PhoenixIndexCodec extends BaseIndexCodec {
     public static final String INDEX_UUID = "IdxUUID";
 
     private RegionCoprocessorEnvironment env;
-    private KeyValueBuilder builder;
+    private KeyValueBuilder kvBuilder;
 
     @Override
     public void initialize(RegionCoprocessorEnvironment env) {
@@ -70,7 +71,9 @@ public class PhoenixIndexCodec extends BaseIndexCodec {
         // server
         conf.setIfUnset(IndexWriter.INDEX_FAILURE_POLICY_CONF_KEY,
             PhoenixIndexFailurePolicy.class.getName());
-        this.builder = KeyValueBuilder.get(env.getHBaseVersion());
+        // We cannot use the ClientKeyValueBuilder because when these hit the memstore
+        // the memstore assmes we have a backing buffer.
+        this.kvBuilder = GenericKeyValueBuilder.INSTANCE;
     }
 
     List<IndexMaintainer> getIndexMaintainers(Map<String, byte[]> attributes) throws IOException{
@@ -84,7 +87,7 @@ public class PhoenixIndexCodec extends BaseIndexCodec {
         byte[] md = attributes.get(INDEX_MD);
         List<IndexMaintainer> indexMaintainers;
         if (md != null) {
-            indexMaintainers = IndexMaintainer.deserialize(md, builder);
+            indexMaintainers = IndexMaintainer.deserialize(md);
         } else {
             byte[] tenantIdBytes = attributes.get(PhoenixRuntime.TENANT_ID_ATTRIB);
             ImmutableBytesWritable tenantId =
@@ -129,7 +132,7 @@ public class PhoenixIndexCodec extends BaseIndexCodec {
             // get the values from the scanner so we can actually use them
             ValueGetter valueGetter = IndexManagementUtil.createGetterFromScanner(scanner, dataRowKey);
             ptr.set(dataRowKey);
-            Put put = maintainer.buildUpdateMutation(valueGetter, ptr, state.getCurrentTimestamp());
+            Put put = maintainer.buildUpdateMutation(kvBuilder, valueGetter, ptr, state.getCurrentTimestamp());
             indexUpdate.setTable(maintainer.getIndexTableName());
             indexUpdate.setUpdate(put);
             //make sure we close the scanner when we are done
@@ -158,8 +161,8 @@ public class PhoenixIndexCodec extends BaseIndexCodec {
             ValueGetter valueGetter = IndexManagementUtil.createGetterFromScanner(scanner, dataRowKey);
             ptr.set(dataRowKey);
             Delete delete =
-                maintainer.buildDeleteMutation(valueGetter, ptr, state.getPendingUpdate(),
-                  state.getCurrentTimestamp());
+                maintainer.buildDeleteMutation(kvBuilder, valueGetter, ptr,
+                  state.getPendingUpdate(), state.getCurrentTimestamp());
             scanner.close();
             indexUpdate.setUpdate(delete);
             indexUpdates.add(indexUpdate);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index a124faf..5c654b2 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -1167,14 +1167,14 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
 
         if (result.getMutationCode() == MutationCode.COLUMN_NOT_FOUND) { // Success
             // Flush the table if transitioning DISABLE_WAL from TRUE to FALSE
-            if (Boolean.FALSE.equals(PDataType.BOOLEAN.toObject(
-                    MetaDataUtil.getMutationKVByteValue(m,PhoenixDatabaseMetaData.DISABLE_WAL_BYTES, kvBuilder, ptr)))) {
+            if (  MetaDataUtil.getMutationValue(m,PhoenixDatabaseMetaData.DISABLE_WAL_BYTES, kvBuilder, ptr)
+               && Boolean.FALSE.equals(PDataType.BOOLEAN.toObject(ptr))) {
                 flushTable(table.getPhysicalName().getBytes());
             }
             
             if (tableType == PTableType.TABLE) {
                 // If we're changing MULTI_TENANT to true or false, create or drop the view index table
-                if (MetaDataUtil.getMutationKeyValue(m, PhoenixDatabaseMetaData.MULTI_TENANT_BYTES, kvBuilder, ptr)){
+                if (MetaDataUtil.getMutationValue(m, PhoenixDatabaseMetaData.MULTI_TENANT_BYTES, kvBuilder, ptr)){
                     long timestamp = MetaDataUtil.getClientTimeStamp(m);
                     if (Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(ptr.get(), ptr.getOffset(), ptr.getLength()))) {
                         this.ensureViewIndexTableCreated(table, timestamp);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java
index 56d1d1d..4c2e382 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java
@@ -17,7 +17,7 @@
  */
 package org.apache.phoenix.query;
 
-import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.INDEX_STATE_BYTES;
 
 import java.sql.SQLException;
 import java.util.Collections;
@@ -29,7 +29,6 @@ import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HRegionLocation;
 import org.apache.hadoop.hbase.HTableDescriptor;
-import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.client.HBaseAdmin;
 import org.apache.hadoop.hbase.client.HTableInterface;
 import org.apache.hadoop.hbase.client.Mutation;
@@ -65,6 +64,7 @@ import org.apache.phoenix.schema.SequenceNotFoundException;
 import org.apache.phoenix.schema.TableAlreadyExistsException;
 import org.apache.phoenix.schema.TableNotFoundException;
 import org.apache.phoenix.schema.TableRef;
+import org.apache.phoenix.util.MetaDataUtil;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.SchemaUtil;
 
@@ -256,8 +256,12 @@ public class ConnectionlessQueryServicesImpl extends DelegateQueryServices imple
     public MetaDataMutationResult updateIndexState(List<Mutation> tableMetadata, String parentTableName) throws SQLException {
         byte[][] rowKeyMetadata = new byte[3][];
         SchemaUtil.getVarChars(tableMetadata.get(0).getRow(), rowKeyMetadata);
-        KeyValue newKV = tableMetadata.get(0).getFamilyMap().get(TABLE_FAMILY_BYTES).get(0);
-        PIndexState newState =  PIndexState.fromSerializedValue(newKV.getBuffer()[newKV.getValueOffset()]);
+        Mutation m = MetaDataUtil.getTableHeaderRow(tableMetadata);
+        ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+        if (!MetaDataUtil.getMutationValue(m, INDEX_STATE_BYTES, kvBuilder, ptr)) {
+            throw new IllegalStateException();
+        }
+        PIndexState newState =  PIndexState.fromSerializedValue(ptr.get()[ptr.getOffset()]);
         byte[] tenantIdBytes = rowKeyMetadata[PhoenixDatabaseMetaData.TENANT_ID_INDEX];
         String schemaName = Bytes.toString(rowKeyMetadata[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX]);
         String indexName = Bytes.toString(rowKeyMetadata[PhoenixDatabaseMetaData.TABLE_NAME_INDEX]);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/MultiKeyValueTuple.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/MultiKeyValueTuple.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/MultiKeyValueTuple.java
index 3c00dfc..bd2f390 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/MultiKeyValueTuple.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/MultiKeyValueTuple.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.client.GenericKeyValueBuilder;
 import org.apache.phoenix.util.KeyValueUtil;
 
 import com.google.common.collect.ImmutableList;
@@ -53,7 +54,7 @@ public class MultiKeyValueTuple extends BaseTuple {
 
     @Override
     public KeyValue getValue(byte[] family, byte[] qualifier) {
-        return KeyValueUtil.getColumnLatest(values, family, qualifier);
+        return KeyValueUtil.getColumnLatest(GenericKeyValueBuilder.INSTANCE, values, family, qualifier);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/ResultTuple.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/ResultTuple.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/ResultTuple.java
index b12dd6a..ec8d061 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/ResultTuple.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/ResultTuple.java
@@ -21,7 +21,8 @@ import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.phoenix.util.ResultUtil;
+import org.apache.phoenix.client.GenericKeyValueBuilder;
+import org.apache.phoenix.util.KeyValueUtil;
 
 
 public class ResultTuple extends BaseTuple {
@@ -44,7 +45,7 @@ public class ResultTuple extends BaseTuple {
     
     @Override
     public void getKey(ImmutableBytesWritable ptr) {
-        ResultUtil.getKey(result, ptr);
+        ptr.set(result.getRow());
     }
 
     @Override
@@ -54,7 +55,7 @@ public class ResultTuple extends BaseTuple {
 
     @Override
     public KeyValue getValue(byte[] family, byte[] qualifier) {
-        return result.getColumnLatest(family, qualifier);
+        return KeyValueUtil.getColumnLatest(GenericKeyValueBuilder.INSTANCE, result.raw(), family, qualifier);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
index 7075980..e2121b9 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
@@ -143,11 +143,10 @@ public class IndexUtil {
     }
 
     public static List<Mutation> generateIndexData(final PTable table, PTable index,
-            List<Mutation> dataMutations, ImmutableBytesWritable ptr, KeyValueBuilder builder)
+            List<Mutation> dataMutations, ImmutableBytesWritable ptr, final KeyValueBuilder kvBuilder)
             throws SQLException {
         try {
             IndexMaintainer maintainer = index.getIndexMaintainer(table);
-            maintainer.setKvBuilder(builder);
             List<Mutation> indexMutations = Lists.newArrayListWithExpectedSize(dataMutations.size());
            for (final Mutation dataMutation : dataMutations) {
                 long ts = MetaDataUtil.getClientTimeStamp(dataMutation);
@@ -172,22 +171,24 @@ public class IndexUtil {
                             }
                             byte[] qualifier = ref.getQualifier();
                             for (KeyValue kv : kvs) {
-                                if (Bytes.compareTo(kv.getBuffer(), kv.getFamilyOffset(), kv.getFamilyLength(), family, 0, family.length) == 0 &&
-                                    Bytes.compareTo(kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength(), qualifier, 0, qualifier.length) == 0) {
-                                    return new ImmutableBytesPtr(kv.getBuffer(), kv.getValueOffset(), kv.getValueLength());
+                                if (  kvBuilder.compareFamily(kv, family, 0, family.length) == 0
+                                   && kvBuilder.compareQualifier(kv, qualifier, 0, qualifier.length) == 0) {
+                                    ImmutableBytesPtr ptr = new ImmutableBytesPtr();
+                                    kvBuilder.getValueAsPtr(kv, ptr);
+                                    return ptr;
                                 }
                             }
                             return null;
                         }
                         
                     };
-                    indexMutations.add(maintainer.buildUpdateMutation(valueGetter, ptr, ts));
+                    indexMutations.add(maintainer.buildUpdateMutation(kvBuilder, valueGetter, ptr, ts));
                 } else {
                     if (!maintainer.getIndexedColumns().isEmpty()) {
                         throw new SQLExceptionInfo.Builder(SQLExceptionCode.NO_DELETE_IF_IMMUTABLE_INDEX).setSchemaName(table.getSchemaName().getString())
                         .setTableName(table.getTableName().getString()).build().buildException();
                     }
-                    indexMutations.add(maintainer.buildDeleteMutation(ptr, ts));
+                    indexMutations.add(maintainer.buildDeleteMutation(kvBuilder, ptr, ts));
                 }
             }
             return indexMutations;

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/util/KeyValueUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/KeyValueUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/KeyValueUtil.java
index b89731b..51bd373 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/KeyValueUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/KeyValueUtil.java
@@ -17,15 +17,17 @@
  */
 package org.apache.phoenix.util;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
 import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.KeyValue.KVComparator;
 import org.apache.hadoop.hbase.KeyValue.Type;
-import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.phoenix.client.KeyValueBuilder;
 
 /**
  * 
@@ -40,15 +42,6 @@ public class KeyValueUtil {
     private KeyValueUtil() {
     }
 
-    public static KeyValue newKeyValue(Result r, byte[] cf, byte[] cq, long ts, byte[] value, int valueOffset, int valueLength) {
-        byte[] bytes = ResultUtil.getRawBytes(r);
-        return new KeyValue(bytes, ResultUtil.getKeyOffset(r), ResultUtil.getKeyLength(r),
-                cf, 0, cf.length,
-                cq, 0, cq.length,
-                ts, Type.Put,
-                value, valueOffset, valueLength);
-    }
-
     public static KeyValue newKeyValue(byte[] key, byte[] cf, byte[] cq, long ts, byte[] value, int valueOffset, int valueLength) {
         return new KeyValue(key, 0, key.length,
                 cf, 0, cf.length,
@@ -77,22 +70,19 @@ public class KeyValueUtil {
         return newKeyValue(key,cf,cq,ts,value,0,value.length);
     }
 
-    public static KeyValue newKeyValue(Result r, byte[] cf, byte[] cq, long ts, byte[] value) {
-        return newKeyValue(r,cf,cq,ts,value,0,value.length);
-    }
-
     /**
      * Binary search for latest column value without allocating memory in the process
+     * @param kvBuilder TODO
      * @param kvs
      * @param family
      * @param qualifier
      */
-    public static KeyValue getColumnLatest(List<KeyValue>kvs, byte[] family, byte[] qualifier) {
+    public static KeyValue getColumnLatest(KeyValueBuilder kvBuilder, List<KeyValue>kvs, byte[] family, byte[] qualifier) {
         if (kvs.size() == 0) {
         	return null;
         }
-        KeyValue row = kvs.get(0);
-        Comparator<KeyValue> comp = new SearchComparator(row.getBuffer(), row.getRowOffset(), row.getRowLength(), family, qualifier);
+        KeyValue kvForRow = kvs.get(0);
+        Comparator<KeyValue> comp = new SearchComparator(kvBuilder, kvForRow, family, qualifier);
         // pos === ( -(insertion point) - 1)
         int pos = Collections.binarySearch(kvs, null, comp);
         // never will exact match
@@ -116,6 +106,43 @@ public class KeyValueUtil {
         return kv;
     }
 
+
+    /**
+     * Binary search for latest column value without allocating memory in the process
+     * @param kvBuilder TODO
+     * @param kvs
+     * @param family
+     * @param qualifier
+     */
+    public static KeyValue getColumnLatest(KeyValueBuilder kvBuilder, KeyValue[] kvs, byte[] family, byte[] qualifier) {
+        if (kvs.length == 0) {
+            return null;
+        }
+        KeyValue kvForRow = kvs[0];
+        Comparator<KeyValue> comp = new SearchComparator(kvBuilder, kvForRow, family, qualifier);
+        // pos === ( -(insertion point) - 1)
+        int pos = Arrays.binarySearch(kvs, null, comp);
+        // never will exact match
+        if (pos < 0) {
+          pos = (pos+1) * -1;
+          // pos is now insertion point
+        }
+        if (pos == kvs.length) {
+          return null; // doesn't exist
+        }
+    
+        KeyValue kv = kvs[pos];
+        if (Bytes.compareTo(kv.getBuffer(), kv.getFamilyOffset(), kv.getFamilyLength(),
+                family, 0, family.length) != 0) {
+            return null;
+        }
+        if (Bytes.compareTo(kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength(),
+                qualifier, 0, qualifier.length) != 0) {
+            return null;
+        }
+        return kv;
+    }
+
     /*
      * Special comparator, *only* works for binary search.
      * Current JDKs only uses the search term on the right side,
@@ -123,45 +150,40 @@ public class KeyValueUtil {
      * to inline the search term in the comparator
      */
 	private static class SearchComparator implements Comparator<KeyValue> {
-		private final byte[] row;
+	    private final KeyValueBuilder kvBuilder;
+		private final KeyValue r;
 		private final byte[] family;
 		private final byte[] qualifier;
-		private final int rowOff;
-		private final int rowLen;
 
-		public SearchComparator(byte[] r, int rOff, int rLen, byte[] f, byte[] q) {
-			row = r;
+		public SearchComparator(KeyValueBuilder kvBuilder, KeyValue r, byte[] f, byte[] q) {
+		    this.kvBuilder = kvBuilder;
+			this.r = r;
 			family = f;
 			qualifier = q;
-			rowOff = rOff;
-			rowLen = rLen;
 		}
 
 		@Override
         public int compare(final KeyValue l, final KeyValue ignored) {
 			assert ignored == null;
-			final byte[] buf = l.getBuffer();
-			final int rOff = l.getRowOffset();
-			final short rLen = l.getRowLength();
+            KVComparator comparator = kvBuilder.getKeyValueComparator();
 			// row
-			int val = Bytes.compareTo(buf, rOff, rLen, row, rowOff, rowLen);
+			int val = comparator.compareRows(l, r);
 			if (val != 0) {
 				return val;
 			}
-			// family
-			final int fOff = l.getFamilyOffset(rLen);
-			final byte fLen = l.getFamilyLength(fOff);
-			val = Bytes.compareTo(buf, fOff, fLen, family, 0, family.length);
+            // family
+			val = kvBuilder.compareFamily(l, family, 0, family.length);
 			if (val != 0) {
 				return val;
 			}
 			// qualifier
-			val = Bytes.compareTo(buf, l.getQualifierOffset(fOff),
-					l.getQualifierLength(rLen, fLen), qualifier, 0, qualifier.length);
+            val = kvBuilder.compareQualifier(l, qualifier, 0, qualifier.length);
 			if (val != 0) {
 				return val;
 			}
-			// want latest TS and type, so we get the first
+			// We want the latest TS and type, so we get the first one.
+			// This assumes they KV are passed in ordered from latest to earliest,
+			// as that's the order the server sends them.
 			return 1;
 		}
 	}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
index adf7f98..47fc56b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
@@ -197,7 +197,7 @@ public class MetaDataUtil {
     
     public static PTableType getTableType(List<Mutation> tableMetaData, KeyValueBuilder builder,
       ImmutableBytesPtr value) {
-        if (getMutationKeyValue(getPutOnlyTableHeaderRow(tableMetaData),
+        if (getMutationValue(getPutOnlyTableHeaderRow(tableMetaData),
             PhoenixDatabaseMetaData.TABLE_TYPE_BYTES, builder, value)) {
             return PTableType.fromSerializedValue(value.get()[value.getOffset()]);
         }
@@ -212,14 +212,6 @@ public class MetaDataUtil {
         return tableMetaData.get(0);
     }
 
-    public static byte[] getMutationKVByteValue(Mutation headerRow, byte[] key,
-        KeyValueBuilder builder, ImmutableBytesWritable ptr) {
-        if (getMutationKeyValue(headerRow, key, builder, ptr)) {
-            return ByteUtil.copyKeyBytesIfNecessary(ptr);
-        }
-        return ByteUtil.EMPTY_BYTE_ARRAY;
-    }
-
   /**
    * Get the mutation who's qualifier matches the passed key
    * <p>
@@ -229,10 +221,10 @@ public class MetaDataUtil {
    * @param headerRow mutation to check
    * @param key to check
    * @param builder that created the {@link KeyValue KeyValues} in the {@link Mutation}
-   * @param ptr to update with the value of the mutation
-   * @return the value of the matching {@link KeyValue}
+   * @param ptr to point to the KeyValue's value if found
+   * @return true if the KeyValue was found and false otherwise
    */
-  public static boolean getMutationKeyValue(Mutation headerRow, byte[] key,
+  public static boolean getMutationValue(Mutation headerRow, byte[] key,
       KeyValueBuilder builder, ImmutableBytesWritable ptr) {
         List<KeyValue> kvs = headerRow.getFamilyMap().get(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES);
         if (kvs != null) {
@@ -282,14 +274,14 @@ public class MetaDataUtil {
     }
     
     public static boolean isMultiTenant(Mutation m, KeyValueBuilder builder, ImmutableBytesWritable ptr) {
-        if (getMutationKeyValue(m, PhoenixDatabaseMetaData.MULTI_TENANT_BYTES, builder, ptr)) {
+        if (getMutationValue(m, PhoenixDatabaseMetaData.MULTI_TENANT_BYTES, builder, ptr)) {
             return Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(ptr));
         }
         return false;
     }
     
     public static boolean isSalted(Mutation m, KeyValueBuilder builder, ImmutableBytesWritable ptr) {
-        return MetaDataUtil.getMutationKeyValue(m, PhoenixDatabaseMetaData.SALT_BUCKETS_BYTES, builder, ptr);
+        return MetaDataUtil.getMutationValue(m, PhoenixDatabaseMetaData.SALT_BUCKETS_BYTES, builder, ptr);
     }
     
     public static byte[] getViewIndexPhysicalName(byte[] physicalTableName) {

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java b/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
index 2080022..736100b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
@@ -287,7 +287,8 @@ public class PhoenixRuntime {
      * @throws SQLException 
      */
     public static Iterator<Pair<byte[],List<KeyValue>>> getUncommittedDataIterator(Connection conn, boolean includeMutableIndexes) throws SQLException {
-        final Iterator<Pair<byte[],List<Mutation>>> iterator = conn.unwrap(PhoenixConnection.class).getMutationState().toMutations(includeMutableIndexes);
+        final PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
+        final Iterator<Pair<byte[],List<Mutation>>> iterator = pconn.getMutationState().toMutations(includeMutableIndexes);
         return new Iterator<Pair<byte[],List<KeyValue>>>() {
 
             @Override
@@ -306,7 +307,7 @@ public class PhoenixRuntime {
                         }
                     }
                 }
-                Collections.sort(keyValues, KeyValue.COMPARATOR);
+                Collections.sort(keyValues, pconn.getKeyValueBuilder().getKeyValueComparator());
                 return new Pair<byte[], List<KeyValue>>(pair.getFirst(),keyValues);
             }
 

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/main/java/org/apache/phoenix/util/ResultUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/ResultUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/ResultUtil.java
deleted file mode 100644
index d33ace7..0000000
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/ResultUtil.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * 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.phoenix.util;
-
-import java.util.Arrays;
-import java.util.Comparator;
-
-import org.apache.hadoop.hbase.KeyValue;
-import org.apache.hadoop.hbase.client.Result;
-import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
-import org.apache.hadoop.hbase.util.Bytes;
-
-/**
- * Static class for various methods that would be nice to have added to {@link org.apache.hadoop.hbase.client.Result}.
- * These methods work off of the raw bytes preventing the explosion of Result into object form.
- * 
- * 
- * @since 0.1
- */
-public class ResultUtil {
-    public static final Result EMPTY_RESULT = new Result() {
-        @Override
-        public final boolean isEmpty() { return true; }
-    };
-    
-    private ResultUtil() {
-    }
-    
-    /**
-     * Return a pointer into a potentially much bigger byte buffer that points to the key of a Result.
-     * @param r
-     */
-    public static ImmutableBytesWritable getKey(Result r) {
-        return getKey(r, 0);
-    }
-    
-    public static void getKey(Result r, ImmutableBytesWritable key) {
-        key.set(r.getRow());
-        //key.set(getRawBytes(r), getKeyOffset(r), getKeyLength(r));
-    }
-    
-    public static void getKey(KeyValue value, ImmutableBytesWritable key) {
-        key.set(value.getBuffer(), value.getRowOffset(), value.getRowLength());
-    }
-    
-    /**
-     * Return a pointer into a potentially much bigger byte buffer that points to the key of a Result.
-     * Use offset to return a subset of the key bytes, for example to skip the organization ID embedded
-     * in all of our keys.
-     * @param r
-     * @param offset offset added to start of key and subtracted from key length (to select subset of key bytes)
-     */
-    public static ImmutableBytesWritable getKey(Result r, int offset) {
-        return new ImmutableBytesWritable(getRawBytes(r), getKeyOffset(r) + offset, getKeyLength(r) - offset);
-    }
-
-    public static void getKey(Result r, int offset, int length, ImmutableBytesWritable key) {
-        key.set(getRawBytes(r), getKeyOffset(r) + offset, length);
-    }
-
-    /**
-     * Comparator for comparing the keys from two Results in-place, without allocating new byte arrays
-     */
-    public static final Comparator<Result> KEY_COMPARATOR = new Comparator<Result>() {
-
-        @Override
-        public int compare(Result r1, Result r2) {
-            byte[] r1Bytes = getRawBytes(r1);
-            byte[] r2Bytes = getRawBytes(r2);
-            return Bytes.compareTo(r1Bytes, getKeyOffset(r1), getKeyLength(r1), r2Bytes, getKeyOffset(r2), getKeyLength(r2));
-        }
-        
-    };
-    
-    /**
-     * Get the offset into the Result byte array to the key.
-     * @param r
-     * @return
-     */
-    static int getKeyOffset(Result r) {
-        // Special case for when Result was instantiated via KeyValue array (no bytes in that case) versus returned from a scanner
-        return (r.getBytes() == null ? r.raw()[0].getOffset() : (r.getBytes().getOffset() + Bytes.SIZEOF_INT /* KV length in Result */)) + KeyValue.ROW_OFFSET /* key offset in KV */ + Bytes.SIZEOF_SHORT /* key length */;
-    }
-    
-    static int getKeyLength(Result r) {
-        // Key length stored right before key as a short
-        return Bytes.toShort(getRawBytes(r), getKeyOffset(r) - Bytes.SIZEOF_SHORT);
-    }
-    
-    static byte[] getRawBytes(Result r) {
-        // Handle special case for when Result was instantiated via KeyValue array (no bytes in that case) versus returned from a scanner
-        ImmutableBytesWritable rPtr = r.getBytes();
-        if (rPtr != null)
-            return rPtr.get();
-        return r.raw()[0].getBuffer();
-    }
-
-    public static int compareKeys(Result r1, Result r2) {
-        return Bytes.compareTo(getRawBytes(r1), getKeyOffset(r1), getKeyLength(r1), getRawBytes(r2), getKeyOffset(r2), getKeyLength(r2));
-    }
-
-    /**
-     * Binary search for latest column value without allocating memory in the process
-     */
-    public static KeyValue getColumnLatest(Result r, byte[] family, byte[] qualifier) {
-        byte[] rbytes = getRawBytes(r);
-        int roffset = getKeyOffset(r);
-        int rlength = getKeyLength(r);
-        return getColumnLatest(r, rbytes, roffset, rlength, family, 0, family.length, qualifier, 0, qualifier.length);
-    }
-
-    public static KeyValue getSearchTerm(Result r, byte[] family, byte[] qualifier) {
-        byte[] rbytes = getRawBytes(r);
-        int roffset = getKeyOffset(r);
-        int rlength = getKeyLength(r);
-        return KeyValue.createFirstOnRow(rbytes, roffset, rlength, family, 0, family.length, qualifier, 0, qualifier.length);
-    }
-    /**
-     * Binary search for latest column value without allocating memory in the process
-     */
-    public static KeyValue getColumnLatest(Result r, byte[] row, int roffset, int rlength, byte[] family, int foffset, int flength, byte[] qualifier, int qoffset, int qlength) {
-        KeyValue searchTerm = KeyValue.createFirstOnRow(row, roffset, rlength, family, foffset, flength, qualifier, qoffset, qlength);
-        return getColumnLatest(r,searchTerm);
-        
-    }
-
-     /**
-     * Binary search for latest column value without allocating memory in the process
-     * @param r
-     * @param searchTerm
-     */
-    public static KeyValue getColumnLatest(Result r, KeyValue searchTerm) {
-        KeyValue [] kvs = r.raw(); // side effect possibly.
-        if (kvs == null || kvs.length == 0) {
-          return null;
-        }
-        
-        // pos === ( -(insertion point) - 1)
-        int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
-        // never will exact match
-        if (pos < 0) {
-          pos = (pos+1) * -1;
-          // pos is now insertion point
-        }
-        if (pos == kvs.length) {
-          return null; // doesn't exist
-        }
-
-        KeyValue kv = kvs[pos];
-        if (Bytes.compareTo(kv.getBuffer(), kv.getFamilyOffset(), kv.getFamilyLength(),
-                searchTerm.getBuffer(), searchTerm.getFamilyOffset(), searchTerm.getFamilyLength()) != 0) {
-            return null;
-        }
-        if (Bytes.compareTo(kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength(),
-                searchTerm.getBuffer(), searchTerm.getQualifierOffset(), searchTerm.getQualifierLength()) != 0) {
-            return null;
-        }
-        return kv;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValue.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValue.java b/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValue.java
index 3b76dfa..ff4ecba 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValue.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValue.java
@@ -34,13 +34,9 @@ import org.apache.hadoop.hbase.client.Scan;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 
-/**
- * TODO: once the only test is not ignored, make this class concrete again
- */
-public abstract class TestClientKeyValue {
+public class TestClientKeyValue {
   private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
   private static byte[] ROW = Bytes.toBytes("testRow");
   private static byte[] FAMILY = Bytes.toBytes("testFamily");
@@ -67,7 +63,6 @@ public abstract class TestClientKeyValue {
    * @throws Exception
    */
   @Test
-  @Ignore("Only supported with HBase 0.94.14")
   public void testClientKeyValue() throws Exception {
     byte[] TABLE = Bytes.toBytes("testClientKeyValue");
     HTable table = TEST_UTIL.createTable(TABLE, new byte[][] { FAMILY });

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValueLocal.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValueLocal.java b/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValueLocal.java
index 980499e..5a4dfd4 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValueLocal.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/client/TestClientKeyValueLocal.java
@@ -19,26 +19,23 @@ package org.apache.phoenix.client;
 
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
 
 import org.apache.hadoop.hbase.KeyValue;
-import org.apache.hadoop.hbase.TestKeyValue;
 import org.apache.hadoop.hbase.KeyValue.Type;
+import org.apache.hadoop.hbase.TestKeyValue;
 import org.apache.hadoop.hbase.client.Delete;
 import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.io.DataInputBuffer;
 import org.apache.hadoop.io.DataOutputBuffer;
-import org.junit.Ignore;
 import org.junit.Test;
 
-import org.apache.phoenix.client.ClientKeyValue;
-
 /**
  * Ensure that we can accss a {@link ClientKeyValue} as expected. For instance, write it to bytes
  * and then read it back into a {@link KeyValue} as expected or compare columns to other
@@ -205,7 +202,6 @@ public class TestClientKeyValueLocal {
    * @throws Exception
    */
   @Test
-  @Ignore("Only supported with HBase 0.94.14")
   public void testUsableWithPut() throws Exception {
     final byte[] a = Bytes.toBytes("aaa");
     byte[] family1 = Bytes.toBytes("abc");
@@ -231,7 +227,6 @@ public class TestClientKeyValueLocal {
    * @throws Exception
    */
   @Test
-  @Ignore("Only supported with HBase 0.94.14")
   public void testUsableWithDelete() throws Exception {
     final byte[] a = Bytes.toBytes("aaa");
     byte[] family1 = Bytes.toBytes("abc");

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java
index f6941fb..748fa3e 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java
@@ -1,17 +1,16 @@
 package org.apache.phoenix.end2end;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class TenantSpecificViewIndexSaltedTest extends BaseTenantSpecificViewIndexTest {
     private static final Integer SALT_BUCKETS = 3;
     
-    @Test @Ignore("PHOENIX-110")
+    @Test
     public void testUpdatableSaltedView() throws Exception {
         testUpdatableView(SALT_BUCKETS);
     }
     
-    @Test@Ignore("PHOENIX-110")
+    @Test
     public void testUpdatableViewsWithSameNameDifferentTenants() throws Exception {
         testUpdatableViewsWithSameNameDifferentTenants(SALT_BUCKETS);
     }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java
index e4f2454..0983bab 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java
@@ -17,17 +17,16 @@
  */
 package org.apache.phoenix.end2end;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class TenantSpecificViewIndexTest extends BaseTenantSpecificViewIndexTest {
 	
-    @Test @Ignore("PHOENIX-110")
+    @Test
     public void testUpdatableView() throws Exception {
         testUpdatableView(null);
     }
 
-    @Test @Ignore("PHOENIX-110")
+    @Test
     public void testUpdatableViewsWithSameNameDifferentTenants() throws Exception {
         testUpdatableViewsWithSameNameDifferentTenants(null);
     }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/87608e14/phoenix-core/src/test/java/org/apache/phoenix/util/MetaDataUtilTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/MetaDataUtilTest.java b/phoenix-core/src/test/java/org/apache/phoenix/util/MetaDataUtilTest.java
index 235358e..caacd57 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/util/MetaDataUtilTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/MetaDataUtilTest.java
@@ -71,7 +71,7 @@ public class MetaDataUtilTest {
 
     // read back out the value
     ImmutableBytesPtr ptr = new ImmutableBytesPtr();
-    assertTrue(MetaDataUtil.getMutationKeyValue(put, qualifier, builder, ptr));
+    assertTrue(MetaDataUtil.getMutationValue(put, qualifier, builder, ptr));
     assertEquals("Value returned doesn't match stored value for " + builder.getClass().getName()
         + "!", 0,
       ByteUtil.BYTES_PTR_COMPARATOR.compare(ptr, wrap(value)));
@@ -84,13 +84,13 @@ public class MetaDataUtilTest {
     KeyValueBuilder.addQuietly(put, builder, kv);
 
     // read back out the value
-    assertTrue(MetaDataUtil.getMutationKeyValue(put, qualifier, builder, ptr));
+    assertTrue(MetaDataUtil.getMutationValue(put, qualifier, builder, ptr));
     assertEquals("Value returned doesn't match stored value for " + builder.getClass().getName()
         + "!", 0,
       ByteUtil.BYTES_PTR_COMPARATOR.compare(ptr, wrap(value)));
 
     // ensure that we don't get matches for qualifiers that don't match
-    assertFalse(MetaDataUtil.getMutationKeyValue(put, Bytes.toBytes("not a match"), builder, ptr));
+    assertFalse(MetaDataUtil.getMutationValue(put, Bytes.toBytes("not a match"), builder, ptr));
   }
 
   private static ImmutableBytesPtr wrap(byte[] bytes) {


Mime
View raw message