You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ra...@apache.org on 2015/05/05 08:09:04 UTC

[5/5] hbase git commit: HBASE-10800 - Use CellComparator instead of KVComparator (Ram)

HBASE-10800 - Use CellComparator instead of KVComparator (Ram)


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/977f8674
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/977f8674
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/977f8674

Branch: refs/heads/master
Commit: 977f867439e960c668ee6311e47c904efc40f219
Parents: 25b5098
Author: ramkrishna <ra...@gmail.com>
Authored: Tue May 5 11:38:10 2015 +0530
Committer: ramkrishna <ra...@gmail.com>
Committed: Tue May 5 11:38:10 2015 +0530

----------------------------------------------------------------------
 .../org/apache/hadoop/hbase/HRegionInfo.java    |   4 +-
 .../apache/hadoop/hbase/client/MetaCache.java   |   9 +-
 .../org/apache/hadoop/hbase/client/Result.java  |  11 +-
 .../apache/hadoop/hbase/filter/FilterList.java  |   6 +-
 .../apache/hadoop/hbase/filter/ParseFilter.java |   6 +-
 .../hbase/client/TestClientNoCluster.java       |   4 +-
 .../hadoop/hbase/client/TestOperation.java      |   9 +-
 .../org/apache/hadoop/hbase/CellComparator.java | 826 ++++++++++++-------
 .../java/org/apache/hadoop/hbase/CellUtil.java  | 146 +++-
 .../java/org/apache/hadoop/hbase/KeyValue.java  |  48 +-
 .../apache/hadoop/hbase/KeyValueTestUtil.java   |   2 +-
 .../org/apache/hadoop/hbase/KeyValueUtil.java   | 123 ++-
 .../java/org/apache/hadoop/hbase/TableName.java |   2 +-
 .../hadoop/hbase/codec/KeyValueCodec.java       |   3 +-
 .../hbase/codec/KeyValueCodecWithTags.java      |   3 +-
 .../io/encoding/BufferedDataBlockEncoder.java   |  83 +-
 .../io/encoding/CopyKeyDataBlockEncoder.java    |   4 +-
 .../hbase/io/encoding/DataBlockEncoder.java     |  10 +-
 .../hbase/io/encoding/DiffKeyDeltaEncoder.java  |   4 +-
 .../hbase/io/encoding/FastDiffDeltaEncoder.java |   4 +-
 .../io/encoding/PrefixKeyDeltaEncoder.java      |   4 +-
 .../org/apache/hadoop/hbase/util/Bytes.java     |  91 +-
 .../hbase/util/test/RedundantKVGenerator.java   |   3 +-
 .../apache/hadoop/hbase/TestCellComparator.java | 100 +--
 .../org/apache/hadoop/hbase/TestKeyValue.java   | 145 +---
 .../hadoop/hbase/codec/TestCellCodec.java       |   7 +-
 .../hbase/codec/TestCellCodecWithTags.java      |   8 +-
 .../hbase/codec/TestKeyValueCodecWithTags.java  |   8 +-
 .../org/apache/hadoop/hbase/util/TestBytes.java |  28 +-
 .../apache/hadoop/hbase/types/TestPBCell.java   |   3 +-
 .../mapreduce/IntegrationTestImportTsv.java     |   5 +-
 .../hbase/codec/prefixtree/PrefixTreeCodec.java |  18 +-
 .../codec/prefixtree/PrefixTreeSeeker.java      |  12 +-
 .../decode/PrefixTreeArrayScanner.java          |   4 +-
 .../codec/prefixtree/decode/PrefixTreeCell.java |  25 +-
 .../codec/prefixtree/row/BaseTestRowData.java   |   4 +-
 .../prefixtree/row/TestPrefixTreeSearcher.java  |   6 +-
 .../row/data/TestRowDataNumberStrings.java      |   2 +-
 .../row/data/TestRowDataSearcherRowMiss.java    |  14 +-
 .../prefixtree/row/data/TestRowDataSimple.java  |  14 +-
 .../hadoop/hbase/io/HalfStoreFileReader.java    |  24 +-
 .../hadoop/hbase/io/hfile/FixedFileTrailer.java |  54 +-
 .../org/apache/hadoop/hbase/io/hfile/HFile.java |  14 +-
 .../hadoop/hbase/io/hfile/HFileBlockIndex.java  |  50 +-
 .../hbase/io/hfile/HFilePrettyPrinter.java      |   8 +-
 .../hadoop/hbase/io/hfile/HFileReaderImpl.java  |  39 +-
 .../hbase/io/hfile/HFileWriterFactory.java      |   4 +-
 .../hadoop/hbase/io/hfile/HFileWriterImpl.java  | 141 +++-
 .../hbase/mapreduce/HFileOutputFormat2.java     |   3 +-
 .../hbase/mapreduce/KeyValueSerialization.java  |   5 +-
 .../hbase/mapreduce/KeyValueSortReducer.java    |   3 +-
 .../hadoop/hbase/mapreduce/PutSortReducer.java  |   3 +-
 .../mapreduce/SimpleTotalOrderPartitioner.java  |   2 +-
 .../hadoop/hbase/mapreduce/TextSortReducer.java |   3 +-
 .../hbase/regionserver/CellSkipListSet.java     |   4 +-
 .../hbase/regionserver/DefaultMemStore.java     |   7 +-
 .../hbase/regionserver/DefaultStoreEngine.java  |   4 +-
 .../regionserver/DefaultStoreFileManager.java   |   6 +-
 .../GetClosestRowBeforeTracker.java             |  17 +-
 .../hadoop/hbase/regionserver/HRegion.java      |  10 +-
 .../hbase/regionserver/HRegionFileSystem.java   |   6 +-
 .../hadoop/hbase/regionserver/HStore.java       |  15 +-
 .../hadoop/hbase/regionserver/KeyValueHeap.java |  10 +-
 .../hadoop/hbase/regionserver/Region.java       |   4 +-
 .../regionserver/ReversedKeyValueHeap.java      |  10 +-
 .../regionserver/ReversedStoreScanner.java      |   9 +-
 .../hadoop/hbase/regionserver/ScanInfo.java     |  10 +-
 .../hbase/regionserver/ScanQueryMatcher.java    |  40 +-
 .../apache/hadoop/hbase/regionserver/Store.java |   4 +-
 .../hadoop/hbase/regionserver/StoreEngine.java  |   8 +-
 .../hadoop/hbase/regionserver/StoreFile.java    |  72 +-
 .../hbase/regionserver/StoreFileScanner.java    |  11 +-
 .../hadoop/hbase/regionserver/StoreScanner.java |   8 +-
 .../regionserver/StripeMultiFileWriter.java     |  40 +-
 .../hbase/regionserver/StripeStoreEngine.java   |   4 +-
 .../regionserver/StripeStoreFileManager.java    |  16 +-
 .../hbase/regionserver/wal/WALCellCodec.java    |   3 +-
 .../hadoop/hbase/regionserver/wal/WALEdit.java  |   6 +-
 .../apache/hadoop/hbase/util/BloomFilter.java   |   2 +-
 .../hadoop/hbase/util/BloomFilterFactory.java   |   5 +-
 .../hadoop/hbase/util/ByteBloomFilter.java      |   6 +-
 .../hbase/util/CollectionBackedScanner.java     |  14 +-
 .../hadoop/hbase/util/CompoundBloomFilter.java  |   7 +-
 .../hbase/util/CompoundBloomFilterBase.java     |   5 +-
 .../hbase/util/CompoundBloomFilterWriter.java   |   4 +-
 .../hadoop/hbase/util/CompressionTest.java      |   2 +-
 .../org/apache/hadoop/hbase/util/HBaseFsck.java |   5 +-
 .../hadoop/hbase/HBaseTestingUtility.java       |   2 +-
 .../hbase/HFilePerformanceEvaluation.java       |   2 +-
 .../apache/hadoop/hbase/MetaMockingUtil.java    |   2 +-
 .../apache/hadoop/hbase/TestSerialization.java  |   8 +-
 .../apache/hadoop/hbase/client/TestResult.java  |  17 +-
 .../hbase/codec/TestCellMessageCodec.java       |   7 +-
 .../hbase/filter/TestDependentColumnFilter.java |   3 +-
 .../apache/hadoop/hbase/filter/TestFilter.java  |   9 +-
 .../hadoop/hbase/filter/TestFilterList.java     |  15 +-
 .../TestSingleColumnValueExcludeFilter.java     |   5 +-
 .../hbase/io/TestHalfStoreFileReader.java       |   7 +-
 .../encoding/TestBufferedDataBlockEncoder.java  |  33 +
 .../io/encoding/TestDataBlockEncoders.java      |   5 +-
 .../io/encoding/TestPrefixTreeEncoding.java     |  15 +-
 .../encoding/TestSeekToBlockWithEncoders.java   |   3 +-
 .../hadoop/hbase/io/hfile/TestCacheOnWrite.java |   3 +-
 .../hbase/io/hfile/TestFixedFileTrailer.java    |  25 +-
 .../apache/hadoop/hbase/io/hfile/TestHFile.java | 156 +++-
 .../hadoop/hbase/io/hfile/TestHFileBlock.java   |   3 +-
 .../hbase/io/hfile/TestHFileBlockIndex.java     |  24 +-
 .../hadoop/hbase/io/hfile/TestHFileSeek.java    |   6 +-
 .../hbase/io/hfile/TestHFileWriterV2.java       |   6 +-
 .../hbase/io/hfile/TestHFileWriterV3.java       |   9 +-
 .../hadoop/hbase/io/hfile/TestPrefetch.java     |   3 +-
 .../hadoop/hbase/io/hfile/TestReseekTo.java     |   3 +-
 .../hadoop/hbase/io/hfile/TestSeekTo.java       |   3 +-
 .../hbase/regionserver/KeyValueScanFixture.java |  12 +-
 .../hbase/regionserver/MockStoreFile.java       |   4 +-
 .../hbase/regionserver/TestCellSkipListSet.java |   3 +-
 .../regionserver/TestCompoundBloomFilter.java   |  13 +-
 .../hbase/regionserver/TestDefaultMemStore.java |  14 +-
 .../regionserver/TestDefaultStoreEngine.java    |   4 +-
 .../regionserver/TestGetClosestAtOrBefore.java  |   4 +-
 .../hadoop/hbase/regionserver/TestHRegion.java  |  12 +-
 .../hbase/regionserver/TestKeyValueHeap.java    |   9 +-
 .../regionserver/TestKeyValueScanFixture.java   |   3 +-
 .../regionserver/TestMultiColumnScanner.java    |   4 +-
 .../hbase/regionserver/TestQueryMatcher.java    |   6 +-
 .../hbase/regionserver/TestRecoveredEdits.java  |   6 +-
 .../regionserver/TestReversibleScanners.java    |   5 +-
 .../TestScannerHeartbeatMessages.java           |   6 +-
 .../regionserver/TestSeekOptimizations.java     |   5 +-
 .../hadoop/hbase/regionserver/TestStore.java    |  12 +-
 .../hbase/regionserver/TestStoreFile.java       |  26 +-
 .../hbase/regionserver/TestStoreScanner.java    |  13 +-
 .../hbase/regionserver/TestStripeCompactor.java |   6 +-
 .../regionserver/TestStripeStoreEngine.java     |   4 +-
 .../TestStripeStoreFileManager.java             |   5 +-
 .../compactions/TestStripeCompactionPolicy.java |   3 +-
 .../TestReplicationWALEntryFilters.java         |   3 +-
 137 files changed, 1960 insertions(+), 1131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
index ad85d5e..b127489 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java
@@ -27,10 +27,10 @@ import java.util.List;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hbase.KeyValue.KVComparator;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.classification.InterfaceStability;
 import org.apache.hadoop.hbase.client.RegionReplicaUtil;
+import org.apache.hadoop.hbase.KeyValue.KVComparator;
 import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.exceptions.DeserializationException;
 import org.apache.hadoop.hbase.master.RegionState;
@@ -842,7 +842,7 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
   @Deprecated
   public KVComparator getComparator() {
     return isMetaRegion()?
-      KeyValue.META_COMPARATOR: KeyValue.COMPARATOR;
+        KeyValue.META_COMPARATOR: KeyValue.COMPARATOR;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java
index 9cfc516..66ef546 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetaCache.java
@@ -31,13 +31,12 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HRegionLocation;
-import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.RegionLocations;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.KeyValue.KVComparator;
+import org.apache.hadoop.hbase.CellComparator;
 
 /**
  * A cache implementation for region locations from meta.
@@ -96,9 +95,9 @@ public class MetaCache {
     return null;
   }
 
-  private KVComparator getRowComparator(TableName tableName) {
-    return TableName.META_TABLE_NAME.equals(tableName) ? KeyValue.META_COMPARATOR
-        : KeyValue.COMPARATOR;
+  private CellComparator getRowComparator(TableName tableName) {
+    return TableName.META_TABLE_NAME.equals(tableName) ? CellComparator.META_COMPARATOR
+        : CellComparator.COMPARATOR;
   }
   /**
    * Put a newly discovered HRegionLocation into the cache.

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Result.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Result.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Result.java
index 5a9aff3..4c58da5 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Result.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Result.java
@@ -31,6 +31,7 @@ import java.util.NavigableMap;
 import java.util.TreeMap;
 
 import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.CellComparator;
 import org.apache.hadoop.hbase.CellScannable;
 import org.apache.hadoop.hbase.CellScanner;
 import org.apache.hadoop.hbase.CellUtil;
@@ -204,14 +205,14 @@ public class Result implements CellScannable, CellScanner {
    * Return the array of Cells backing this Result instance.
    *
    * The array is sorted from smallest -> largest using the
-   * {@link KeyValue#COMPARATOR}.
+   * {@link CellComparator#COMPARATOR}.
    *
    * The array only contains what your Get or Scan specifies and no more.
    * For example if you request column "A" 1 version you will have at most 1
    * Cell in the array. If you request column "A" with 2 version you will
    * have at most 2 Cells, with the first one being the newer timestamp and
    * the second being the older timestamp (this is the sort order defined by
-   * {@link KeyValue#COMPARATOR}).  If columns don't exist, they won't be
+   * {@link CellComparator#COMPARATOR}).  If columns don't exist, they won't be
    * present in the result. Therefore if you ask for 1 version all columns,
    * it is safe to iterate over this array and expect to see 1 Cell for
    * each column and no more.
@@ -237,7 +238,7 @@ public class Result implements CellScannable, CellScanner {
 
   /**
    * Return the Cells for the specific column.  The Cells are sorted in
-   * the {@link KeyValue#COMPARATOR} order.  That implies the first entry in
+   * the {@link CellComparator#COMPARATOR} order.  That implies the first entry in
    * the list is the most recent column.  If the query (Scan or Get) only
    * requested 1 version the list will contain at most 1 entry.  If the column
    * did not exist in the result set (either the column does not exist
@@ -282,7 +283,7 @@ public class Result implements CellScannable, CellScanner {
             family, qualifier);
 
     // pos === ( -(insertion point) - 1)
-    int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
+    int pos = Arrays.binarySearch(kvs, searchTerm, CellComparator.COMPARATOR);
     // never will exact match
     if (pos < 0) {
       pos = (pos+1) * -1;
@@ -327,7 +328,7 @@ public class Result implements CellScannable, CellScanner {
         qualifier, qoffset, qlength);
 
     // pos === ( -(insertion point) - 1)
-    int pos = Arrays.binarySearch(kvs, searchTerm, KeyValue.COMPARATOR);
+    int pos = Arrays.binarySearch(kvs, searchTerm, CellComparator.COMPARATOR);
     // never will exact match
     if (pos < 0) {
       pos = (pos+1) * -1;

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FilterList.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FilterList.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FilterList.java
index ba1a818..a7856cd 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FilterList.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FilterList.java
@@ -25,7 +25,7 @@ import java.util.List;
 
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellComparator;
-import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.classification.InterfaceStability;
 import org.apache.hadoop.hbase.exceptions.DeserializationException;
@@ -216,7 +216,7 @@ final public class FilterList extends Filter {
 
   @Override
   public Cell transformCell(Cell c) throws IOException {
-    if (!CellComparator.equals(c, referenceCell)) {
+    if (!CellUtil.equals(c, referenceCell)) {
       throw new IllegalStateException("Reference Cell: " + this.referenceCell + " does not match: "
           + c);
     }
@@ -415,7 +415,7 @@ final public class FilterList extends Filter {
           keyHint = curKeyHint;
           continue;
         }
-        if (KeyValue.COMPARATOR.compare(keyHint, curKeyHint) > 0) {
+        if (CellComparator.COMPARATOR.compare(keyHint, curKeyHint) > 0) {
           keyHint = curKeyHint;
         }
       }

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/ParseFilter.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/ParseFilter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/ParseFilter.java
index 8101f4a..5089308 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/ParseFilter.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/ParseFilter.java
@@ -32,7 +32,6 @@ import java.util.Stack;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.classification.InterfaceStability;
 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
@@ -294,7 +293,7 @@ public class ParseFilter {
  * @return an ArrayList containing the arguments of the filter in the filter string
  */
   public static ArrayList<byte []> getFilterArguments (byte [] filterStringAsByteArray) {
-    int argumentListStartIndex = KeyValue.getDelimiter(filterStringAsByteArray, 0,
+    int argumentListStartIndex = Bytes.searchDelimiterIndex(filterStringAsByteArray, 0,
                                                        filterStringAsByteArray.length,
                                                        ParseConstants.LPAREN);
     if (argumentListStartIndex == -1) {
@@ -818,7 +817,8 @@ public class ParseFilter {
  * @return the parsed arguments of the comparator as a 2D byte array
  */
   public static byte [][] parseComparator (byte [] comparator) {
-    final int index = KeyValue.getDelimiter(comparator, 0, comparator.length, ParseConstants.COLON);
+    final int index = Bytes.searchDelimiterIndex(comparator, 0, comparator.length,
+        ParseConstants.COLON);
     if (index == -1) {
       throw new IllegalArgumentException("Incorrect comparator");
     }

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java
index f085ace..29b32b3 100644
--- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java
+++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java
@@ -32,12 +32,14 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
+import org.apache.hadoop.hbase.CellComparator;
 
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.conf.Configured;
+import org.apache.hadoop.hbase.CellComparator;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
@@ -642,7 +644,7 @@ public class TestClientNoCluster extends Configured implements Tool {
    * Comparator for meta row keys.
    */
   private static class MetaRowsComparator implements Comparator<byte []> {
-    private final KeyValue.KVComparator delegate = new KeyValue.MetaComparator();
+    private final CellComparator delegate = CellComparator.META_COMPARATOR;
     @Override
     public int compare(byte[] left, byte[] right) {
       return delegate.compareRows(left, 0, left.length, right, 0, right.length);

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestOperation.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestOperation.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestOperation.java
index 96c4190d..37890f9 100644
--- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestOperation.java
+++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestOperation.java
@@ -29,6 +29,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.CellComparator;
 import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.KeyValue;
@@ -387,7 +388,7 @@ public class TestOperation {
     Assert.assertEquals(1984L, c.get(0).getTimestamp());
     Assert.assertArrayEquals(VALUE, CellUtil.cloneValue(c.get(0)));
     Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimeStamp());
-    Assert.assertEquals(0, KeyValue.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
+    Assert.assertEquals(0, CellComparator.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
 
     p = new Put(ROW);
     p.add(FAMILY, ByteBuffer.wrap(QUALIFIER), 2013L, null);
@@ -396,7 +397,7 @@ public class TestOperation {
     Assert.assertEquals(2013L, c.get(0).getTimestamp());
     Assert.assertArrayEquals(new byte[]{}, CellUtil.cloneValue(c.get(0)));
     Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimeStamp());
-    Assert.assertEquals(0, KeyValue.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
+    Assert.assertEquals(0, CellComparator.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
 
     p = new Put(ByteBuffer.wrap(ROW));
     p.add(FAMILY, ByteBuffer.wrap(QUALIFIER), 2001L, null);
@@ -406,7 +407,7 @@ public class TestOperation {
     Assert.assertArrayEquals(new byte[]{}, CellUtil.cloneValue(c.get(0)));
     Assert.assertArrayEquals(ROW, CellUtil.cloneRow(c.get(0)));
     Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimeStamp());
-    Assert.assertEquals(0, KeyValue.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
+    Assert.assertEquals(0, CellComparator.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
 
     p = new Put(ByteBuffer.wrap(ROW), 1970L);
     p.add(FAMILY, ByteBuffer.wrap(QUALIFIER), 2001L, null);
@@ -416,7 +417,7 @@ public class TestOperation {
     Assert.assertArrayEquals(new byte[]{}, CellUtil.cloneValue(c.get(0)));
     Assert.assertArrayEquals(ROW, CellUtil.cloneRow(c.get(0)));
     Assert.assertEquals(1970L, p.getTimeStamp());
-    Assert.assertEquals(0, KeyValue.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
+    Assert.assertEquals(0, CellComparator.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-common/src/main/java/org/apache/hadoop/hbase/CellComparator.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellComparator.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellComparator.java
index 540c967..904d40d 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellComparator.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellComparator.java
@@ -21,6 +21,8 @@ package org.apache.hadoop.hbase;
 import java.io.Serializable;
 import java.util.Comparator;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.KeyValue.Type;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.classification.InterfaceStability;
@@ -34,6 +36,9 @@ import com.google.common.primitives.Longs;
  * takes account of the special formatting of the row where we have commas to delimit table from
  * regionname, from row.  See KeyValue for how it has a special comparator to do hbase:meta cells
  * and yet another for -ROOT-.
+ * While using this comparator for {{@link #compareRows(Cell, Cell)} et al, the hbase:meta cells format
+ * should be taken into consideration, for which the instance of this comparator 
+ * should be used.  In all other cases the static APIs in this comparator would be enough
  */
 @edu.umd.cs.findbugs.annotations.SuppressWarnings(
     value="UNKNOWN",
@@ -41,24 +46,74 @@ import com.google.common.primitives.Longs;
 @InterfaceAudience.Private
 @InterfaceStability.Evolving
 public class CellComparator implements Comparator<Cell>, Serializable {
+  static final Log LOG = LogFactory.getLog(CellComparator.class);
   private static final long serialVersionUID = -8760041766259623329L;
 
+  /**
+   * Comparator for plain key/values; i.e. non-catalog table key/values. Works on Key portion
+   * of KeyValue only.
+   */
+  public static final CellComparator COMPARATOR = new CellComparator();
+  /**
+   * A {@link CellComparator} for <code>hbase:meta</code> catalog table
+   * {@link KeyValue}s.
+   */
+  public static final CellComparator META_COMPARATOR = new MetaCellComparator();
+
   @Override
   public int compare(Cell a, Cell b) {
     return compare(a, b, false);
   }
 
   /**
+   * Compares only the key portion of a cell. It does not include the sequence id/mvcc of the
+   * cell 
+   * @param left
+   * @param right
+   * @return an int greater than 0 if left > than right
+   *                lesser than 0 if left < than right
+   *                equal to 0 if left is equal to right
+   */
+  public final int compareKeyIgnoresMvcc(Cell left, Cell right) {
+    return compare(left, right, true);
+  }
+
+  /**
+   * Used when a cell needs to be compared with a key byte[] such as cases of
+   * finding the index from the index block, bloom keys from the bloom blocks
+   * This byte[] is expected to be serialized in the KeyValue serialization format
+   * If the KeyValue (Cell's) serialization format changes this method cannot be used.
+   * @param left the cell to be compared
+   * @param key the serialized key part of a KeyValue
+   * @param offset the offset in the key byte[]
+   * @param length the length of the key byte[]
+   * @return an int greater than 0 if left is greater than right
+   *                lesser than 0 if left is lesser than right
+   *                equal to 0 if left is equal to right
+   * TODO : We will be moving over to 
+   * compare(Cell, Cell) so that the key is also converted to a cell
+   */
+  public final int compare(Cell left, byte[] key, int offset, int length) {
+    // row
+    short rrowlength = Bytes.toShort(key, offset);
+    int c = compareRows(left, key, offset + Bytes.SIZEOF_SHORT, rrowlength);
+    if (c != 0) return c;
+
+    // Compare the rest of the two KVs without making any assumptions about
+    // the common prefix. This function will not compare rows anyway, so we
+    // don't need to tell it that the common prefix includes the row.
+    return compareWithoutRow(left, key, offset, length, rrowlength);
+  }
+
+  /**
    * Compare cells.
-   * TODO: Replace with dynamic rather than static comparator so can change comparator
-   * implementation.
    * @param a
    * @param b
    * @param ignoreSequenceid True if we are to compare the key portion only and ignore
    * the sequenceid. Set to false to compare key and consider sequenceid.
    * @return 0 if equal, -1 if a < b, and +1 if a > b.
    */
-  public static int compare(final Cell a, final Cell b, boolean ignoreSequenceid) {
+  private final int compare(final Cell a, final Cell b, boolean ignoreSequenceid) {
     // row
     int c = compareRows(a, b);
     if (c != 0) return c;
@@ -75,292 +130,481 @@ public class CellComparator implements Comparator<Cell>, Serializable {
     }
   }
 
-  public static int findCommonPrefixInRowPart(Cell left, Cell right, int rowCommonPrefix) {
-    return findCommonPrefix(left.getRowArray(), right.getRowArray(), left.getRowLength()
-        - rowCommonPrefix, right.getRowLength() - rowCommonPrefix, left.getRowOffset()
-        + rowCommonPrefix, right.getRowOffset() + rowCommonPrefix);
+  /**
+   * Compares the family and qualifier part of the cell
+   * TODO : Handle BB cases here
+   * @param left the left cell
+   * @param right the right cell
+   * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
+   */
+  public final static int compareColumns(final Cell left, final Cell right) {
+    int lfoffset = left.getFamilyOffset();
+    int rfoffset = right.getFamilyOffset();
+    int lclength = left.getQualifierLength();
+    int rclength = right.getQualifierLength();
+    int lfamilylength = left.getFamilyLength();
+    int rfamilylength = right.getFamilyLength();
+    int diff = compareFamilies(left.getFamilyArray(), lfoffset, lfamilylength,
+        right.getFamilyArray(), rfoffset, rfamilylength);
+    if (diff != 0) {
+      return diff;
+    } else {
+      return compareQualifiers(left.getQualifierArray(), left.getQualifierOffset(), lclength,
+          right.getQualifierArray(), right.getQualifierOffset(), rclength);
+    }
   }
 
-  private static int findCommonPrefix(byte[] left, byte[] right, int leftLength, int rightLength,
-      int leftOffset, int rightOffset) {
-    int length = Math.min(leftLength, rightLength);
-    int result = 0;
-
-    while (result < length && left[leftOffset + result] == right[rightOffset + result]) {
-      result++;
+  /**
+   * Compares the family and qualifier part of the cell
+   * We explicitly pass the offset and length details of the cells to avoid
+   * re-parsing of the offset and length from the cell. Used only internally.
+   * @param left
+   * @param lfamilyOffset
+   * @param lfamilylength
+   * @param lqualOffset
+   * @param lQualLength
+   * @param right
+   * @param rfamilyOffset
+   * @param rfamilylength
+   * @param rqualOffset
+   * @param rqualLength
+   * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
+   */
+  private final static int compareColumns(final Cell left, int lfamilyOffset, int lfamilylength,
+      int lqualOffset, int lQualLength, final Cell right, final int rfamilyOffset,
+      final int rfamilylength, final int rqualOffset, int rqualLength) {
+    int diff = compareFamilies(left.getFamilyArray(), lfamilyOffset, lfamilylength,
+        right.getFamilyArray(), rfamilyOffset, rfamilylength);
+    if (diff != 0) {
+      return diff;
+    } else {
+      return compareQualifiers(left.getQualifierArray(), lqualOffset, lQualLength,
+          right.getQualifierArray(), rqualOffset, rqualLength);
     }
-    return result;
   }
-
-  public static int findCommonPrefixInFamilyPart(Cell left, Cell right, int familyCommonPrefix) {
-    return findCommonPrefix(left.getFamilyArray(), right.getFamilyArray(), left.getFamilyLength()
-        - familyCommonPrefix, right.getFamilyLength() - familyCommonPrefix, left.getFamilyOffset()
-        + familyCommonPrefix, right.getFamilyOffset() + familyCommonPrefix);
+  
+  /**
+   * Compares the family and qualifier part of a cell with a serialized Key value byte[]
+   * We explicitly pass the offset and length details of the cells to avoid
+   * re-parsing of the offset and length from the cell. Used only internally.
+   * @param left the cell to be compared
+   * @param lfamilyOffset
+   * @param lfamilylength
+   * @param lqualOffset
+   * @param lQualLength
+   * @param right the serialized key value byte array to be compared
+   * @param rfamilyOffset
+   * @param rfamilylength
+   * @param rqualOffset
+   * @param rqualLength
+   * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
+   */
+  private final static int compareColumns(final Cell left, final int lfamilyOffset,
+      final int lfamilylength, final int lqualOffset, final int lQualLength, final byte[] right,
+      final int rfamilyOffset, final int rfamilylength, final int rqualOffset,
+      final int rqualLength) {
+    int diff = compareFamilies(left.getFamilyArray(), lfamilyOffset, lfamilylength, right,
+        rfamilyOffset, rfamilylength);
+    if (diff != 0) {
+      return diff;
+    } else {
+      return compareQualifiers(left.getQualifierArray(), lqualOffset, lQualLength, right,
+          rqualOffset, rqualLength);
+    }
   }
 
-  public static int findCommonPrefixInQualifierPart(Cell left, Cell right,
-      int qualifierCommonPrefix) {
-    return findCommonPrefix(left.getQualifierArray(), right.getQualifierArray(),
-        left.getQualifierLength() - qualifierCommonPrefix, right.getQualifierLength()
-            - qualifierCommonPrefix, left.getQualifierOffset() + qualifierCommonPrefix,
-        right.getQualifierOffset() + qualifierCommonPrefix);
+  /**
+   * Compare the families of left and right cell
+   * TODO : Handle BB cases here
+   * @param left
+   * @param right
+   * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
+   */
+  public final static int compareFamilies(Cell left, Cell right) {
+    return compareFamilies(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(),
+        right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength());
   }
 
-  /**************** equals ****************************/
+  /**
+   * We explicitly pass the offset and length details of the cells to avoid
+   * re-parsing of the offset and length from the cell. Used only internally.
+   * @param left
+   * @param lOffset
+   * @param lLength
+   * @param right
+   * @param rOffset
+   * @param rLength
+   * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
+   */
+  private final static int compareFamilies(Cell left, int lOffset, int lLength, Cell right,
+      int rOffset, int rLength) {
+    return compareFamilies(left.getFamilyArray(), lOffset, lLength, right.getFamilyArray(),
+        rOffset, rLength);
+  }
 
-  public static boolean equals(Cell a, Cell b){
-    return equalsRow(a, b)
-        && equalsFamily(a, b)
-        && equalsQualifier(a, b)
-        && equalsTimestamp(a, b)
-        && equalsType(a, b);
+  private final static int compareFamilies(Cell left, int lOffset, int lLength, byte[] right,
+      int rOffset, int rLength) {
+    return compareFamilies(left.getFamilyArray(), lOffset, lLength, right, rOffset, rLength);
   }
 
-  public static boolean equalsRow(Cell a, Cell b){
-    return Bytes.equals(
-      a.getRowArray(), a.getRowOffset(), a.getRowLength(),
-      b.getRowArray(), b.getRowOffset(), b.getRowLength());
+  private final static int compareFamilies(byte[] leftFamily, int lFamOffset, int lFamLength,
+      byte[] rightFamily, int rFamOffset, int rFamLen) {
+    return Bytes.compareTo(leftFamily, lFamOffset, lFamLength, rightFamily, rFamOffset, rFamLen);
   }
 
-  public static boolean equalsFamily(Cell a, Cell b){
-    return Bytes.equals(
-      a.getFamilyArray(), a.getFamilyOffset(), a.getFamilyLength(),
-      b.getFamilyArray(), b.getFamilyOffset(), b.getFamilyLength());
+  /**
+   * Compare the qualifiers part of the left and right cells.
+   * TODO : Handle BB cases here
+   * @param left
+   * @param right
+   * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
+   */
+  public final static int compareQualifiers(Cell left, Cell right) {
+    return compareQualifiers(left.getQualifierArray(), left.getQualifierOffset(),
+        left.getQualifierLength(), right.getQualifierArray(), right.getQualifierOffset(),
+        right.getQualifierLength());
   }
 
-  public static boolean equalsQualifier(Cell a, Cell b){
-    return Bytes.equals(
-      a.getQualifierArray(), a.getQualifierOffset(), a.getQualifierLength(),
-      b.getQualifierArray(), b.getQualifierOffset(), b.getQualifierLength());
+ /**
+  * We explicitly pass the offset and length details of the cells to avoid
+  * re-parsing of the offset and length from the cell. Used only internally.
+  * @param left
+  * @param lOffset
+  * @param lLength
+  * @param right
+  * @param rOffset
+  * @param rLength
+  * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
+  */
+  private final static int compareQualifiers(Cell left, int lOffset, int lLength, Cell right,
+      int rOffset, int rLength) {
+    return compareQualifiers(left.getQualifierArray(), lOffset,
+        lLength, right.getQualifierArray(), rOffset,
+        rLength);
   }
 
-  public static boolean equalsTimestamp(Cell a, Cell b){
-    return a.getTimestamp() == b.getTimestamp();
+  /**
+   * We explicitly pass the offset and length details of the cells to avoid
+   * re-parsing of the offset and length from the cell. Used only internally.
+   * @param left
+   * @param lOffset
+   * @param lLength
+   * @param right
+   * @param rOffset
+   * @param rLength
+   * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
+   */
+  private final static int compareQualifiers(Cell left, int lOffset, int lLength, byte[] right,
+      int rOffset, int rLength) {
+    return compareQualifiers(left.getQualifierArray(), lOffset,
+        lLength, right, rOffset,
+        rLength);
   }
 
-  public static boolean equalsType(Cell a, Cell b){
-    return a.getTypeByte() == b.getTypeByte();
+  private static int compareQualifiers(byte[] leftCol, int lColOffset, int lColLength,
+      byte[] rightCol, int rColOffset, int rColLength) {
+    return Bytes.compareTo(leftCol, lColOffset, lColLength, rightCol, rColOffset, rColLength);
   }
 
-  public static int compareColumns(final Cell left, final Cell right) {
-    int lfoffset = left.getFamilyOffset();
-    int rfoffset = right.getFamilyOffset();
-    int lclength = left.getQualifierLength();
-    int rclength = right.getQualifierLength();
-    int lfamilylength = left.getFamilyLength();
-    int rfamilylength = right.getFamilyLength();
-    int diff = compare(left.getFamilyArray(), lfoffset, lfamilylength, right.getFamilyArray(),
-        rfoffset, rfamilylength);
-    if (diff != 0) {
-      return diff;
-    } else {
-      return compare(left.getQualifierArray(), left.getQualifierOffset(), lclength,
-          right.getQualifierArray(), right.getQualifierOffset(), rclength);
+  /**
+   * Compare columnFamily, qualifier, timestamp, and key type (everything
+   * except the row). This method is used both in the normal comparator and
+   * the "same-prefix" comparator. Note that we are assuming that row portions
+   * of both KVs have already been parsed and found identical, and we don't
+   * validate that assumption here.
+   * TODO :  we will have to handle BB cases here
+   * @param commonPrefix
+   *          the length of the common prefix of the two key-values being
+   *          compared, including row length and row
+   */
+  private final int compareWithoutRow(Cell left,
+      byte[] right, int roffset, int rlength, short rowlength) {
+    /***
+     * KeyValue Format and commonLength:
+     * |_keyLen_|_valLen_|_rowLen_|_rowKey_|_famiLen_|_fami_|_Quali_|....
+     * ------------------|-------commonLength--------|--------------
+     */
+    int commonLength = KeyValue.ROW_LENGTH_SIZE + KeyValue.FAMILY_LENGTH_SIZE + rowlength;
+
+    // commonLength + TIMESTAMP_TYPE_SIZE
+    int commonLengthWithTSAndType = KeyValue.TIMESTAMP_TYPE_SIZE + commonLength;
+    // ColumnFamily + Qualifier length.
+    int lcolumnlength = left.getFamilyLength() + left.getQualifierLength();
+    int rcolumnlength = rlength - commonLengthWithTSAndType;
+
+    byte ltype = left.getTypeByte();
+    byte rtype = right[roffset + (rlength - 1)];
+
+    // If the column is not specified, the "minimum" key type appears the
+    // latest in the sorted order, regardless of the timestamp. This is used
+    // for specifying the last key/value in a given row, because there is no
+    // "lexicographically last column" (it would be infinitely long). The
+    // "maximum" key type does not need this behavior.
+    if (lcolumnlength == 0 && ltype == Type.Minimum.getCode()) {
+      // left is "bigger", i.e. it appears later in the sorted order
+      return 1;
+    }
+    if (rcolumnlength == 0 && rtype == Type.Minimum.getCode()) {
+      return -1;
     }
-  }
 
-  public static int compareFamilies(Cell left, Cell right) {
-    return Bytes.compareTo(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(),
-        right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength());
-  }
+    int lfamilyoffset = left.getFamilyOffset();
+    int rfamilyoffset = commonLength + roffset;
 
-  public static int compareQualifiers(Cell left, Cell right) {
-    return Bytes.compareTo(left.getQualifierArray(), left.getQualifierOffset(),
-        left.getQualifierLength(), right.getQualifierArray(), right.getQualifierOffset(),
-        right.getQualifierLength());
-  }
+    // Column family length.
+    int lfamilylength = left.getFamilyLength();
+    int rfamilylength = right[rfamilyoffset - 1];
+    // If left family size is not equal to right family size, we need not
+    // compare the qualifiers.
+    boolean sameFamilySize = (lfamilylength == rfamilylength);
+    if (!sameFamilySize) {
+      // comparing column family is enough.
+      return compareFamilies(left, lfamilyoffset, lfamilylength, right,
+          rfamilyoffset, rfamilylength);
+    }
+    // Compare family & qualifier together.
+    // Families are same. Compare on qualifiers.
+    int lQualOffset = left.getQualifierOffset();
+    int lQualLength = left.getQualifierLength();
+    int comparison = compareColumns(left, lfamilyoffset, lfamilylength, lQualOffset, lQualLength,
+        right, rfamilyoffset, rfamilylength, rfamilyoffset + rfamilylength,
+        (rcolumnlength - rfamilylength));
+    if (comparison != 0) {
+      return comparison;
+    }
 
-  public int compareFlatKey(Cell left, Cell right) {
-    int compare = compareRows(left, right);
+    // //
+    // Next compare timestamps.
+    long rtimestamp = Bytes.toLong(right, roffset + (rlength - KeyValue.TIMESTAMP_TYPE_SIZE));
+    int compare = compareTimestamps(left.getTimestamp(), rtimestamp);
     if (compare != 0) {
       return compare;
     }
-    return compareWithoutRow(left, right);
+
+    // Compare types. Let the delete types sort ahead of puts; i.e. types
+    // of higher numbers sort before those of lesser numbers. Maximum (255)
+    // appears ahead of everything, and minimum (0) appears after
+    // everything.
+    return (0xff & rtype) - (0xff & ltype);
   }
 
   /**
-   * Do not use comparing rows from hbase:meta. Meta table Cells have schema (table,startrow,hash)
-   * so can't be treated as plain byte arrays as this method does.
+   * Compares the rows of the left and right cell
+   * For the hbase:meta case the 
+   * ({@link #compareRows(byte[], int, int, byte[], int, int)} is overridden such
+   * that it can handle the hbase:meta cells. The caller should ensure using the 
+   * appropriate comparator for hbase:meta
+   * TODO : Handle BB cases here
+   * @param left
+   * @param right
+   * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
    */
-  public static int compareRows(final Cell left, final Cell right) {
-    return Bytes.compareTo(left.getRowArray(), left.getRowOffset(), left.getRowLength(),
+  public final int compareRows(final Cell left, final Cell right) {
+    return compareRows(left.getRowArray(), left.getRowOffset(), left.getRowLength(),
         right.getRowArray(), right.getRowOffset(), right.getRowLength());
   }
 
   /**
+   * Compares the rows of two cells
+   * We explicitly pass the offset and length details of the cell to avoid re-parsing
+   * of the offset and length from the cell
+   * @param left the cell to be compared
+   * @param loffset the row offset of the left cell
+   * @param llength the row length of the left cell
+   * @param right the cell to be compared
+   * @param roffset the row offset of the right cell
+   * @param rlength the row length of the right cell
+   * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
+   */
+  private final int compareRows(Cell left, int loffset, int llength, Cell right, int roffset,
+      int rlength) {
+    // TODO : for BB based cells all the hasArray based checks would happen
+    // here. But we may have
+    // to end up in multiple APIs accepting byte[] and BBs
+    return compareRows(left.getRowArray(), loffset, llength, right.getRowArray(), roffset,
+        rlength);
+  }
+
+  /**
+   * Compares the row part of the cell with a simple plain byte[] like the
+   * stopRow in Scan. This should be used with context where for hbase:meta
+   * cells the {{@link #META_COMPARATOR} should be used
+   *
+   * @param left
+   *          the cell to be compared
+   * @param right
+   *          the kv serialized byte[] to be compared with
+   * @param roffset
+   *          the offset in the byte[]
+   * @param rlength
+   *          the length in the byte[]
+   * @return 0 if both cell and the byte[] are equal, 1 if the cell is bigger
+   *         than byte[], -1 otherwise
+   */
+  public final int compareRows(Cell left, byte[] right, int roffset,
+      int rlength) {
+    // TODO : for BB based cells all the hasArray based checks would happen
+    // here. But we may have
+    // to end up in multiple APIs accepting byte[] and BBs
+    return compareRows(left.getRowArray(), left.getRowOffset(), left.getRowLength(), right,
+        roffset, rlength);
+  }
+  /**
    * Do not use comparing rows from hbase:meta. Meta table Cells have schema (table,startrow,hash)
    * so can't be treated as plain byte arrays as this method does.
    */
-  public static int compareRows(byte[] left, int loffset, int llength, byte[] right, int roffset,
+  // TODO : CLEANUP : in order to do this we may have to modify some code
+  // HRegion.next() and will involve a
+  // Filter API change also. Better to do that later along with
+  // HBASE-11425/HBASE-13387.
+  public int compareRows(byte[] left, int loffset, int llength, byte[] right, int roffset,
       int rlength) {
     return Bytes.compareTo(left, loffset, llength, right, roffset, rlength);
   }
 
-  public static int compareWithoutRow(final Cell leftCell, final Cell rightCell) {
+  private static int compareWithoutRow(final Cell left, final Cell right) {
     // If the column is not specified, the "minimum" key type appears the
     // latest in the sorted order, regardless of the timestamp. This is used
     // for specifying the last key/value in a given row, because there is no
     // "lexicographically last column" (it would be infinitely long). The
     // "maximum" key type does not need this behavior.
     // Copied from KeyValue. This is bad in that we can't do memcmp w/ special rules like this.
-    // TODO
-    if (leftCell.getFamilyLength() + leftCell.getQualifierLength() == 0
-          && leftCell.getTypeByte() == Type.Minimum.getCode()) {
+    int lFamLength = left.getFamilyLength();
+    int rFamLength = right.getFamilyLength();
+    int lQualLength = left.getQualifierLength();
+    int rQualLength = right.getQualifierLength();
+    if (lFamLength + lQualLength == 0
+          && left.getTypeByte() == Type.Minimum.getCode()) {
       // left is "bigger", i.e. it appears later in the sorted order
       return 1;
     }
-    if (rightCell.getFamilyLength() + rightCell.getQualifierLength() == 0
-        && rightCell.getTypeByte() == Type.Minimum.getCode()) {
+    if (rFamLength + rQualLength == 0
+        && right.getTypeByte() == Type.Minimum.getCode()) {
       return -1;
     }
-    boolean sameFamilySize = (leftCell.getFamilyLength() == rightCell.getFamilyLength());
+    boolean sameFamilySize = (lFamLength == rFamLength);
+    int lFamOffset = left.getFamilyOffset();
+    int rFamOffset = right.getFamilyOffset();
     if (!sameFamilySize) {
       // comparing column family is enough.
-
-      return Bytes.compareTo(leftCell.getFamilyArray(), leftCell.getFamilyOffset(),
-          leftCell.getFamilyLength(), rightCell.getFamilyArray(), rightCell.getFamilyOffset(),
-          rightCell.getFamilyLength());
+      return compareFamilies(left, lFamOffset, lFamLength, right, rFamOffset, rFamLength);
     }
-    int diff = compareColumns(leftCell, rightCell);
+    // Families are same. Compare on qualifiers.
+    int lQualOffset = left.getQualifierOffset();
+    int rQualOffset = right.getQualifierOffset();
+    int diff = compareColumns(left, lFamOffset, lFamLength, lQualOffset, lQualLength, right,
+        rFamOffset, rFamLength, rQualOffset, rQualLength);
     if (diff != 0) return diff;
 
-    diff = compareTimestamps(leftCell, rightCell);
+    diff = compareTimestamps(left, right);
     if (diff != 0) return diff;
 
     // Compare types. Let the delete types sort ahead of puts; i.e. types
     // of higher numbers sort before those of lesser numbers. Maximum (255)
     // appears ahead of everything, and minimum (0) appears after
     // everything.
-    return (0xff & rightCell.getTypeByte()) - (0xff & leftCell.getTypeByte());
+    return (0xff & right.getTypeByte()) - (0xff & left.getTypeByte());
   }
 
-  public static int compareTimestamps(final Cell left, final Cell right) {
-    long ltimestamp = left.getTimestamp();
-    long rtimestamp = right.getTimestamp();
-    return compareTimestamps(ltimestamp, rtimestamp);
-  }
-
-  /********************* hashCode ************************/
-
   /**
-   * Returns a hash code that is always the same for two Cells having a matching equals(..) result.
+   * Compare the timestamp of the left and right cell
+   *
+   * @param left
+   * @param right
+   * @return 0 if equal, -1 if left's ts is less than right's ts, 1 if left's ts
+   *         is greater than right's ts
    */
-  public static int hashCode(Cell cell){
-    if (cell == null) {// return 0 for empty Cell
-      return 0;
-    }
-
-    int hash = calculateHashForKeyValue(cell);
-    hash = 31 * hash + (int)cell.getMvccVersion();
-    return hash;
+  public static int compareTimestamps(final Cell left, final Cell right) {
+    return compareTimestamps(left.getTimestamp(), right.getTimestamp());
   }
 
   /**
-   * Returns a hash code that is always the same for two Cells having a matching
-   * equals(..) result. Note : Ignore mvcc while calculating the hashcode
-   * 
-   * @param cell
-   * @return hashCode
+   * Used to compare two cells based on the column hint provided. This is specifically
+   * used when we need to optimize the seeks based on the next indexed key. This is an
+   * advance usage API specifically needed for some optimizations.
+   * @param nextIndexedCell the next indexed cell 
+   * @param currentCell the cell to be compared
+   * @param foff the family offset of the currentCell
+   * @param flen the family length of the currentCell
+   * @param colHint the column hint provided - could be null
+   * @param coff the offset of the column hint if provided, if not offset of the currentCell's
+   * qualifier
+   * @param clen the length of the column hint if provided, if not length of the currentCell's
+   * qualifier
+   * @param ts the timestamp to be seeked
+   * @param type the type to be seeked
+   * @return an int based on the given column hint
+   * TODO : To be moved out of here because this is a special API used in scan
+   * optimization.
    */
-  public static int hashCodeIgnoreMvcc(Cell cell) {
-    if (cell == null) {// return 0 for empty Cell
-      return 0;
+  // compare a key against row/fam/qual/ts/type
+  public final int compareKeyBasedOnColHint(Cell nextIndexedCell, Cell currentCell, int foff,
+      int flen, byte[] colHint, int coff, int clen, long ts, byte type) {
+
+    int compare = 0;
+    compare = compareRows(nextIndexedCell, nextIndexedCell.getRowOffset(),
+        nextIndexedCell.getRowLength(), currentCell, currentCell.getRowOffset(),
+        currentCell.getRowLength());
+    if (compare != 0) {
+      return compare;
+    }
+    // If the column is not specified, the "minimum" key type appears the
+    // latest in the sorted order, regardless of the timestamp. This is used
+    // for specifying the last key/value in a given row, because there is no
+    // "lexicographically last column" (it would be infinitely long). The
+    // "maximum" key type does not need this behavior.
+    if (nextIndexedCell.getFamilyLength() + nextIndexedCell.getQualifierLength() == 0
+        && nextIndexedCell.getTypeByte() == Type.Minimum.getCode()) {
+      // left is "bigger", i.e. it appears later in the sorted order
+      return 1;
+    }
+    int qualLen = currentCell.getQualifierLength();
+    if (flen + clen == 0 && type == Type.Minimum.getCode()) {
+      return -1;
     }
 
-    int hash = calculateHashForKeyValue(cell);
-    return hash;
-  }
-
-  private static int calculateHashForKeyValue(Cell cell) {
-    //pre-calculate the 3 hashes made of byte ranges
-    int rowHash = Bytes.hashCode(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
-    int familyHash =
-      Bytes.hashCode(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
-    int qualifierHash = Bytes.hashCode(cell.getQualifierArray(), cell.getQualifierOffset(),
-      cell.getQualifierLength());
-
-    //combine the 6 sub-hashes
-    int hash = 31 * rowHash + familyHash;
-    hash = 31 * hash + qualifierHash;
-    hash = 31 * hash + (int)cell.getTimestamp();
-    hash = 31 * hash + cell.getTypeByte();
-    return hash;
-  }
-
-
-  /******************** lengths *************************/
-
-  public static boolean areKeyLengthsEqual(Cell a, Cell b) {
-    return a.getRowLength() == b.getRowLength()
-        && a.getFamilyLength() == b.getFamilyLength()
-        && a.getQualifierLength() == b.getQualifierLength();
-  }
-
-  public static boolean areRowLengthsEqual(Cell a, Cell b) {
-    return a.getRowLength() == b.getRowLength();
-  }
-
-
-  /*********************common prefixes*************************/
-
-  private static int compare(byte[] left, int leftOffset, int leftLength, byte[] right,
-      int rightOffset, int rightLength) {
-    return Bytes.compareTo(left, leftOffset, leftLength, right, rightOffset, rightLength);
-  }
-
-  public static int compareCommonRowPrefix(Cell left, Cell right, int rowCommonPrefix) {
-    return compare(left.getRowArray(), left.getRowOffset() + rowCommonPrefix, left.getRowLength()
-        - rowCommonPrefix, right.getRowArray(), right.getRowOffset() + rowCommonPrefix,
-        right.getRowLength() - rowCommonPrefix);
-  }
-
-  public static int compareCommonFamilyPrefix(Cell left, Cell right,
-      int familyCommonPrefix) {
-    return compare(left.getFamilyArray(), left.getFamilyOffset() + familyCommonPrefix,
-        left.getFamilyLength() - familyCommonPrefix, right.getFamilyArray(),
-        right.getFamilyOffset() + familyCommonPrefix,
-        right.getFamilyLength() - familyCommonPrefix);
-  }
+    compare = compareFamilies(nextIndexedCell, nextIndexedCell.getFamilyOffset(),
+        nextIndexedCell.getFamilyLength(), currentCell, currentCell.getFamilyOffset(),
+        flen);
+    if (compare != 0) {
+      return compare;
+    }
+    if (colHint == null) {
+      compare = compareQualifiers(nextIndexedCell, nextIndexedCell.getQualifierOffset(),
+          nextIndexedCell.getQualifierLength(), currentCell, currentCell.getQualifierOffset(),
+          qualLen);
+    } else {
+      compare = compareQualifiers(nextIndexedCell, nextIndexedCell.getQualifierOffset(),
+          nextIndexedCell.getQualifierLength(), colHint, coff, clen);
+    }
+    if (compare != 0) {
+      return compare;
+    }
+    // Next compare timestamps.
+    compare = compareTimestamps(nextIndexedCell.getTimestamp(), ts);
+    if (compare != 0) {
+      return compare;
+    }
 
-  public static int compareCommonQualifierPrefix(Cell left, Cell right,
-      int qualCommonPrefix) {
-    return compare(left.getQualifierArray(), left.getQualifierOffset() + qualCommonPrefix,
-        left.getQualifierLength() - qualCommonPrefix, right.getQualifierArray(),
-        right.getQualifierOffset() + qualCommonPrefix, right.getQualifierLength()
-            - qualCommonPrefix);
+    // Compare types. Let the delete types sort ahead of puts; i.e. types
+    // of higher numbers sort before those of lesser numbers. Maximum (255)
+    // appears ahead of everything, and minimum (0) appears after
+    // everything.
+    return (0xff & type) - (0xff & nextIndexedCell.getTypeByte());
   }
 
-  /***************** special cases ****************************/
   /**
-   * special case for KeyValue.equals
+   * The below older timestamps sorting ahead of newer timestamps looks
+   * wrong but it is intentional. This way, newer timestamps are first
+   * found when we iterate over a memstore and newer versions are the
+   * first we trip over when reading from a store file.
+   * @param ltimestamp
+   * @param rtimestamp
+   * @return 1 if left timestamp > right timestamp
+   *         -1 if left timestamp < right timestamp
+   *         0 if both timestamps are equal
    */
-  public static boolean equalsIgnoreMvccVersion(Cell a, Cell b){
-    return 0 == compareStaticIgnoreMvccVersion(a, b);
-  }
-
-  private static int compareStaticIgnoreMvccVersion(Cell a, Cell b) {
-    // row
-    int c = compareRows(a, b);
-    if (c != 0) return c;
-
-    // family
-    c = compareColumns(a, b);
-    if (c != 0) return c;
-
-    // timestamp: later sorts first
-    c = compareTimestamps(a, b);
-    if (c != 0) return c;
-
-    //type
-    c = (0xff & b.getTypeByte()) - (0xff & a.getTypeByte());
-    return c;
-  }
-
-  private static int compareTimestamps(final long ltimestamp, final long rtimestamp) {
-    // The below older timestamps sorting ahead of newer timestamps looks
-    // wrong but it is intentional. This way, newer timestamps are first
-    // found when we iterate over a memstore and newer versions are the
-    // first we trip over when reading from a store file.
+  public static int compareTimestamps(final long ltimestamp, final long rtimestamp) {
     if (ltimestamp < rtimestamp) {
       return 1;
     } else if (ltimestamp > rtimestamp) {
@@ -370,7 +614,7 @@ public class CellComparator implements Comparator<Cell>, Serializable {
   }
 
   /**
-   * Counter part for the KeyValue.RowOnlyComparator
+   * Comparator that compares row component only of a Cell
    */
   public static class RowComparator extends CellComparator {
     @Override
@@ -380,119 +624,61 @@ public class CellComparator implements Comparator<Cell>, Serializable {
   }
 
   /**
-   * Try to return a Cell that falls between <code>left</code> and <code>right</code> but that is
-   * shorter; i.e. takes up less space. This trick is used building HFile block index.
-   * Its an optimization. It does not always work.  In this case we'll just return the
-   * <code>right</code> cell.
-   * @param comparator Comparator to use.
-   * @param left
-   * @param right
-   * @return A cell that sorts between <code>left</code> and <code>right</code>.
-   */
-  public static Cell getMidpoint(final KeyValue.KVComparator comparator, final Cell left,
-      final Cell right) {
-    // TODO: Redo so only a single pass over the arrays rather than one to compare and then a
-    // second composing midpoint.
-    if (right == null) {
-      throw new IllegalArgumentException("right cell can not be null");
-    }
-    if (left == null) {
-      return right;
-    }
-    // If Cells from meta table, don't mess around. meta table Cells have schema
-    // (table,startrow,hash) so can't be treated as plain byte arrays. Just skip out without
-    // trying to do this optimization.
-    if (comparator != null && comparator instanceof KeyValue.MetaComparator) {
-      return right;
-    }
-    int diff = compareRows(left, right);
-    if (diff > 0) {
-      throw new IllegalArgumentException("Left row sorts after right row; left=" +
-        CellUtil.getCellKeyAsString(left) + ", right=" + CellUtil.getCellKeyAsString(right));
-    }
-    if (diff < 0) {
-      // Left row is < right row.
-      byte [] midRow = getMinimumMidpointArray(left.getRowArray(), left.getRowOffset(),
-          left.getRowLength(),
-        right.getRowArray(), right.getRowOffset(), right.getRowLength());
-      // If midRow is null, just return 'right'.  Can't do optimization.
-      if (midRow == null) return right;
-      return CellUtil.createCell(midRow);
-    }
-    // Rows are same. Compare on families.
-    diff = compareFamilies(left, right);
-    if (diff > 0) {
-      throw new IllegalArgumentException("Left family sorts after right family; left=" +
-          CellUtil.getCellKeyAsString(left) + ", right=" + CellUtil.getCellKeyAsString(right));
-    }
-    if (diff < 0) {
-      byte [] midRow = getMinimumMidpointArray(left.getFamilyArray(), left.getFamilyOffset(),
-          left.getFamilyLength(),
-        right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength());
-      // If midRow is null, just return 'right'.  Can't do optimization.
-      if (midRow == null) return right;
-      // Return new Cell where we use right row and then a mid sort family.
-      return CellUtil.createCell(right.getRowArray(), right.getRowOffset(), right.getRowLength(),
-        midRow, 0, midRow.length, HConstants.EMPTY_BYTE_ARRAY, 0,
-        HConstants.EMPTY_BYTE_ARRAY.length);
-    }
-    // Families are same. Compare on qualifiers.
-    diff = compareQualifiers(left, right);
-    if (diff > 0) {
-      throw new IllegalArgumentException("Left qualifier sorts after right qualifier; left=" +
-          CellUtil.getCellKeyAsString(left) + ", right=" + CellUtil.getCellKeyAsString(right));
-    }
-    if (diff < 0) {
-      byte [] midRow = getMinimumMidpointArray(left.getQualifierArray(), left.getQualifierOffset(),
-          left.getQualifierLength(),
-        right.getQualifierArray(), right.getQualifierOffset(), right.getQualifierLength());
-      // If midRow is null, just return 'right'.  Can't do optimization.
-      if (midRow == null) return right;
-      // Return new Cell where we use right row and family and then a mid sort qualifier.
-      return CellUtil.createCell(right.getRowArray(), right.getRowOffset(), right.getRowLength(),
-        right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength(),
-        midRow, 0, midRow.length);
-    }
-    // No opportunity for optimization. Just return right key.
-    return right;
-  }
-
-  /**
-   * @param leftArray
-   * @param leftOffset
-   * @param leftLength
-   * @param rightArray
-   * @param rightOffset
-   * @param rightLength
-   * @return Return a new array that is between left and right and minimally sized else just return
-   * null as indicator that we could not create a mid point.
+   * A {@link CellComparator} for <code>hbase:meta</code> catalog table
+   * {@link KeyValue}s.
    */
-  private static byte [] getMinimumMidpointArray(final byte [] leftArray, final int leftOffset,
-        final int leftLength,
-      final byte [] rightArray, final int rightOffset, final int rightLength) {
-    // rows are different
-    int minLength = leftLength < rightLength ? leftLength : rightLength;
-    short diffIdx = 0;
-    while (diffIdx < minLength &&
-        leftArray[leftOffset + diffIdx] == rightArray[rightOffset + diffIdx]) {
-      diffIdx++;
-    }
-    byte [] minimumMidpointArray = null;
-    if (diffIdx >= minLength) {
-      // leftKey's row is prefix of rightKey's.
-      minimumMidpointArray = new byte[diffIdx + 1];
-      System.arraycopy(rightArray, rightOffset, minimumMidpointArray, 0, diffIdx + 1);
-    } else {
-      int diffByte = leftArray[leftOffset + diffIdx];
-      if ((0xff & diffByte) < 0xff && (diffByte + 1) < (rightArray[rightOffset + diffIdx] & 0xff)) {
-        minimumMidpointArray = new byte[diffIdx + 1];
-        System.arraycopy(leftArray, leftOffset, minimumMidpointArray, 0, diffIdx);
-        minimumMidpointArray[diffIdx] = (byte) (diffByte + 1);
+  public static class MetaCellComparator extends CellComparator {
+ 
+    @Override
+    public int compareRows(byte[] left, int loffset, int llength, byte[] right, int roffset,
+        int rlength) {
+      int leftDelimiter = Bytes.searchDelimiterIndex(left, loffset, llength, HConstants.DELIMITER);
+      int rightDelimiter = Bytes
+          .searchDelimiterIndex(right, roffset, rlength, HConstants.DELIMITER);
+      // Compare up to the delimiter
+      int lpart = (leftDelimiter < 0 ? llength : leftDelimiter - loffset);
+      int rpart = (rightDelimiter < 0 ? rlength : rightDelimiter - roffset);
+      int result = Bytes.compareTo(left, loffset, lpart, right, roffset, rpart);
+      if (result != 0) {
+        return result;
+      } else {
+        if (leftDelimiter < 0 && rightDelimiter >= 0) {
+          return -1;
+        } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
+          return 1;
+        } else if (leftDelimiter < 0 && rightDelimiter < 0) {
+          return 0;
+        }
+      }
+      // Compare middle bit of the row.
+      // Move past delimiter
+      leftDelimiter++;
+      rightDelimiter++;
+      int leftFarDelimiter = Bytes.searchDelimiterIndexInReverse(left, leftDelimiter, llength
+          - (leftDelimiter - loffset), HConstants.DELIMITER);
+      int rightFarDelimiter = Bytes.searchDelimiterIndexInReverse(right, rightDelimiter, rlength
+          - (rightDelimiter - roffset), HConstants.DELIMITER);
+      // Now compare middlesection of row.
+      lpart = (leftFarDelimiter < 0 ? llength + loffset : leftFarDelimiter) - leftDelimiter;
+      rpart = (rightFarDelimiter < 0 ? rlength + roffset : rightFarDelimiter) - rightDelimiter;
+      result = super.compareRows(left, leftDelimiter, lpart, right, rightDelimiter, rpart);
+      if (result != 0) {
+        return result;
       } else {
-        minimumMidpointArray = new byte[diffIdx + 1];
-        System.arraycopy(rightArray, rightOffset, minimumMidpointArray, 0, diffIdx + 1);
+        if (leftDelimiter < 0 && rightDelimiter >= 0) {
+          return -1;
+        } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
+          return 1;
+        } else if (leftDelimiter < 0 && rightDelimiter < 0) {
+          return 0;
+        }
       }
+      // Compare last part of row, the rowid.
+      leftFarDelimiter++;
+      rightFarDelimiter++;
+      result = Bytes.compareTo(left, leftFarDelimiter, llength - (leftFarDelimiter - loffset),
+          right, rightFarDelimiter, rlength - (rightFarDelimiter - roffset));
+      return result;
     }
-    return minimumMidpointArray;
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
index bce3957..7ddcfe6 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map.Entry;
 import java.util.NavigableMap;
 
+import org.apache.hadoop.hbase.CellComparator.MetaCellComparator;
 import org.apache.hadoop.hbase.KeyValue.Type;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.classification.InterfaceStability;
@@ -379,8 +380,10 @@ public final class CellUtil {
   }
 
   public static boolean matchingRow(final Cell left, final byte[] buf) {
-    return Bytes.equals(left.getRowArray(), left.getRowOffset(), left.getRowLength(), buf, 0,
-        buf.length);
+    if (buf == null) {
+      return left.getQualifierLength() == 0;
+    }
+    return matchingRow(left, buf, 0, buf.length);
   }
 
   public static boolean matchingRow(final Cell left, final byte[] buf, final int offset,
@@ -395,8 +398,10 @@ public final class CellUtil {
   }
 
   public static boolean matchingFamily(final Cell left, final byte[] buf) {
-    return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(), buf,
-        0, buf.length);
+    if (buf == null) {
+      return left.getFamilyLength() == 0;
+    }
+    return matchingFamily(left, buf, 0, buf.length);
   }
 
   public static boolean matchingFamily(final Cell left, final byte[] buf, final int offset,
@@ -411,14 +416,29 @@ public final class CellUtil {
         right.getQualifierLength());
   }
 
+  /**
+   * Finds if the qualifier part of the cell and the KV serialized
+   * byte[] are equal
+   * @param left
+   * @param buf the serialized keyvalue format byte[]
+   * @return true if the qualifier matches, false otherwise
+   */
   public static boolean matchingQualifier(final Cell left, final byte[] buf) {
     if (buf == null) {
       return left.getQualifierLength() == 0;
     }
-    return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
-        left.getQualifierLength(), buf, 0, buf.length);
+    return matchingQualifier(left, buf, 0, buf.length);
   }
 
+  /**
+   * Finds if the qualifier part of the cell and the KV serialized
+   * byte[] are equal
+   * @param left
+   * @param buf the serialized keyvalue format byte[]
+   * @param offset the offset of the qualifier in the byte[]
+   * @param length the length of the qualifier in the byte[]
+   * @return true if the qualifier matches, false otherwise
+   */
   public static boolean matchingQualifier(final Cell left, final byte[] buf, final int offset,
       final int length) {
     if (buf == null) {
@@ -902,4 +922,118 @@ public final class CellUtil {
 
     return builder.toString();
   }
+
+  /***************** special cases ****************************/
+
+  /**
+   * special case for Cell.equals
+   */
+  public static boolean equalsIgnoreMvccVersion(Cell a, Cell b) {
+    // row
+    boolean res = matchingRow(a, b);
+    if (!res)
+      return res;
+
+    // family
+    res = matchingColumn(a, b);
+    if (!res)
+      return res;
+
+    // timestamp: later sorts first
+    if (!matchingTimestamp(a, b))
+      return false;
+
+    // type
+    int c = (0xff & b.getTypeByte()) - (0xff & a.getTypeByte());
+    if (c != 0)
+      return false;
+    else return true;
+  }
+
+  /**************** equals ****************************/
+
+  public static boolean equals(Cell a, Cell b) {
+    return matchingRow(a, b) && matchingFamily(a, b) && matchingQualifier(a, b)
+        && matchingTimestamp(a, b) && matchingType(a, b);
+  }
+
+  public static boolean matchingTimestamp(Cell a, Cell b) {
+    return CellComparator.compareTimestamps(a.getTimestamp(), b.getTimestamp()) == 0;
+  }
+
+  public static boolean matchingType(Cell a, Cell b) {
+    return a.getTypeByte() == b.getTypeByte();
+  }
+
+  /**
+   * Compares the row of two keyvalues for equality
+   * 
+   * @param left
+   * @param right
+   * @return True if rows match.
+   */
+  public static boolean matchingRows(final Cell left, final Cell right) {
+    short lrowlength = left.getRowLength();
+    short rrowlength = right.getRowLength();
+    return matchingRows(left, lrowlength, right, rrowlength);
+  }
+
+  /**
+   * @param left
+   * @param lrowlength
+   * @param right
+   * @param rrowlength
+   * @return True if rows match.
+   */
+  private static boolean matchingRows(final Cell left, final short lrowlength, final Cell right,
+      final short rrowlength) {
+    return lrowlength == rrowlength
+        && matchingRows(left.getRowArray(), left.getRowOffset(), lrowlength, right.getRowArray(),
+            right.getRowOffset(), rrowlength);
+  }
+
+  /**
+   * Compare rows. Just calls Bytes.equals, but it's good to have this
+   * encapsulated.
+   * 
+   * @param left
+   *          Left row array.
+   * @param loffset
+   *          Left row offset.
+   * @param llength
+   *          Left row length.
+   * @param right
+   *          Right row array.
+   * @param roffset
+   *          Right row offset.
+   * @param rlength
+   *          Right row length.
+   * @return Whether rows are the same row.
+   */
+  private static boolean matchingRows(final byte[] left, final int loffset, final int llength,
+      final byte[] right, final int roffset, final int rlength) {
+    return Bytes.equals(left, loffset, llength, right, roffset, rlength);
+  }
+
+  /**
+   * Compares the row and column of two keyvalues for equality
+   * 
+   * @param left
+   * @param right
+   * @return True if same row and column.
+   */
+  public static boolean matchingRowColumn(final Cell left, final Cell right) {
+    short lrowlength = left.getRowLength();
+    short rrowlength = right.getRowLength();
+
+    if ((lrowlength + left.getFamilyLength() + left.getQualifierLength()) != (rrowlength
+        + right.getFamilyLength() + right.getQualifierLength())) {
+      return false;
+    }
+
+    if (!matchingRows(left, lrowlength, right, rrowlength)) {
+      return false;
+    }
+    return matchingColumn(left, right);
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java
index 9857d8c..8835957 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java
@@ -95,17 +95,23 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
   /**
    * Comparator for plain key/values; i.e. non-catalog table key/values. Works on Key portion
    * of KeyValue only.
+   * @deprecated Use {@link CellComparator#COMPARATOR} instead
    */
+  @Deprecated
   public static final KVComparator COMPARATOR = new KVComparator();
   /**
    * A {@link KVComparator} for <code>hbase:meta</code> catalog table
    * {@link KeyValue}s.
+   * @deprecated Use {@link CellComparator#META_COMPARATOR} instead
    */
+  @Deprecated
   public static final KVComparator META_COMPARATOR = new MetaComparator();
 
   /**
    * Needed for Bloom Filters.
+   *    * @deprecated Use {@link Bytes#BYTES_RAWCOMPARATOR} instead
    */
+  @Deprecated
   public static final KVComparator RAW_COMPARATOR = new RawBytesComparator();
 
   /** Size of the key length field in bytes*/
@@ -1061,7 +1067,7 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
     if (!(other instanceof Cell)) {
       return false;
     }
-    return CellComparator.equals(this, (Cell)other);
+    return CellUtil.equals(this, (Cell)other);
   }
 
   /**
@@ -1069,7 +1075,23 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
    */
   @Override
   public int hashCode() {
-    return CellComparator.hashCodeIgnoreMvcc(this);
+    return calculateHashForKey(this);
+  }
+
+  private int calculateHashForKey(Cell cell) {
+    // pre-calculate the 3 hashes made of byte ranges
+    int rowHash = Bytes.hashCode(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
+    int familyHash = Bytes.hashCode(cell.getFamilyArray(), cell.getFamilyOffset(),
+        cell.getFamilyLength());
+    int qualifierHash = Bytes.hashCode(cell.getQualifierArray(), cell.getQualifierOffset(),
+        cell.getQualifierLength());
+
+    // combine the 6 sub-hashes
+    int hash = 31 * rowHash + familyHash;
+    hash = 31 * hash + qualifierHash;
+    hash = 31 * hash + (int) cell.getTimestamp();
+    hash = 31 * hash + cell.getTypeByte();
+    return hash;
   }
 
   //---------------------------------------------------------------------------
@@ -1714,7 +1736,9 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
   /**
    * A {@link KVComparator} for <code>hbase:meta</code> catalog table
    * {@link KeyValue}s.
+   * @deprecated : {@link CellComparator#META_COMPARATOR} to be used
    */
+  @Deprecated
   public static class MetaComparator extends KVComparator {
     /**
      * Compare key portion of a {@link KeyValue} for keys in <code>hbase:meta</code>
@@ -1722,11 +1746,7 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
      */
     @Override
     public int compare(final Cell left, final Cell right) {
-      int c = compareRowKey(left, right);
-      if (c != 0) {
-        return c;
-      }
-      return CellComparator.compareWithoutRow(left, right);
+      return CellComparator.META_COMPARATOR.compareKeyIgnoresMvcc(left, right);
     }
 
     @Override
@@ -1831,7 +1851,9 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
    * Compare KeyValues.  When we compare KeyValues, we only compare the Key
    * portion.  This means two KeyValues with same Key but different Values are
    * considered the same as far as this Comparator is concerned.
+   * @deprecated : Use {@link CellComparator}.
    */
+  @Deprecated
   public static class KVComparator implements RawComparator<Cell>, SamePrefixComparator<byte[]> {
 
     /**
@@ -1857,7 +1879,7 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
      * @return 0 if equal, <0 if left smaller, >0 if right smaller
      */
     protected int compareRowKey(final Cell left, final Cell right) {
-      return CellComparator.compareRows(left, right);
+      return CellComparator.COMPARATOR.compareRows(left, right);
     }
 
     /**
@@ -1946,7 +1968,7 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
     }
 
     public int compareOnlyKeyPortion(Cell left, Cell right) {
-      return CellComparator.compare(left, right, true);
+      return CellComparator.COMPARATOR.compareKeyIgnoresMvcc(left, right);
     }
 
     /**
@@ -1955,7 +1977,7 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
      */
     @Override
     public int compare(final Cell left, final Cell right) {
-      int compare = CellComparator.compare(left, right, false);
+      int compare = CellComparator.COMPARATOR.compare(left, right);
       return compare;
     }
 
@@ -2269,8 +2291,7 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
      * @param leftKey
      * @param rightKey
      * @return 0 if equal, <0 if left smaller, >0 if right smaller
-     * @deprecated Since 0.99.2; Use
-     *             {@link CellComparator#getMidpoint(KeyValue.KVComparator, Cell, Cell) instead}
+     * @deprecated Since 0.99.2;
      */
     @Deprecated
     public byte[] getShortMidpointKey(final byte[] leftKey, final byte[] rightKey) {
@@ -2556,8 +2577,9 @@ public class KeyValue implements Cell, HeapSize, Cloneable, SettableSequenceId,
   }
 
   /**
-   * This is a TEST only Comparator used in TestSeekTo and TestReseekTo.
+   * @deprecated  Not to be used for any comparsions
    */
+  @Deprecated
   public static class RawBytesComparator extends KVComparator {
     /**
      * The HFileV2 file format's trailer contains this class name.  We reinterpret this and

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueTestUtil.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueTestUtil.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueTestUtil.java
index f0c8b48..50a409d 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueTestUtil.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueTestUtil.java
@@ -85,7 +85,7 @@ public class KeyValueTestUtil {
     for (Cell kv1 : kvCollection1) {
       boolean found = false;
       for (Cell kv2 : kvCollection2) {
-        if (CellComparator.equalsIgnoreMvccVersion(kv1, kv2)) found = true;
+        if (CellUtil.equalsIgnoreMvccVersion(kv1, kv2)) found = true;
       }
       if (!found) return false;
     }

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueUtil.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueUtil.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueUtil.java
index 7cbfdd6..4ef14fc 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueUtil.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueUtil.java
@@ -18,7 +18,10 @@
 
 package org.apache.hadoop.hbase;
 
+import java.io.DataInput;
+import java.io.DataOutput;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -31,6 +34,7 @@ import org.apache.hadoop.hbase.util.ByteBufferUtils;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.IterableUtils;
 import org.apache.hadoop.hbase.util.SimpleMutableByteRange;
+import org.apache.hadoop.io.IOUtils;
 import org.apache.hadoop.io.WritableUtils;
 
 import com.google.common.base.Function;
@@ -541,6 +545,122 @@ public class KeyValueUtil {
     });
     return new ArrayList<KeyValue>(lazyList);
   }
+  /**
+   * Write out a KeyValue in the manner in which we used to when KeyValue was a
+   * Writable.
+   *
+   * @param kv
+   * @param out
+   * @return Length written on stream
+   * @throws IOException
+   * @see #create(DataInput) for the inverse function
+   */
+  public static long write(final KeyValue kv, final DataOutput out) throws IOException {
+    // This is how the old Writables write used to serialize KVs. Need to figure
+    // way to make it
+    // work for all implementations.
+    int length = kv.getLength();
+    out.writeInt(length);
+    out.write(kv.getBuffer(), kv.getOffset(), length);
+    return length + Bytes.SIZEOF_INT;
+  }
+
+  /**
+   * Create a KeyValue reading from the raw InputStream. Named
+   * <code>iscreate</code> so doesn't clash with {@link #create(DataInput)}
+   *
+   * @param in
+   * @return Created KeyValue OR if we find a length of zero, we will return
+   *         null which can be useful marking a stream as done.
+   * @throws IOException
+   */
+  public static KeyValue iscreate(final InputStream in) throws IOException {
+    byte[] intBytes = new byte[Bytes.SIZEOF_INT];
+    int bytesRead = 0;
+    while (bytesRead < intBytes.length) {
+      int n = in.read(intBytes, bytesRead, intBytes.length - bytesRead);
+      if (n < 0) {
+        if (bytesRead == 0)
+          return null; // EOF at start is ok
+        throw new IOException("Failed read of int, read " + bytesRead + " bytes");
+      }
+      bytesRead += n;
+    }
+    // TODO: perhaps some sanity check is needed here.
+    byte[] bytes = new byte[Bytes.toInt(intBytes)];
+    IOUtils.readFully(in, bytes, 0, bytes.length);
+    return new KeyValue(bytes, 0, bytes.length);
+  }
+
+  /**
+   * @param b
+   * @return A KeyValue made of a byte array that holds the key-only part.
+   *         Needed to convert hfile index members to KeyValues.
+   */
+  public static KeyValue createKeyValueFromKey(final byte[] b) {
+    return createKeyValueFromKey(b, 0, b.length);
+  }
+
+  /**
+   * @param bb
+   * @return A KeyValue made of a byte buffer that holds the key-only part.
+   *         Needed to convert hfile index members to KeyValues.
+   */
+  public static KeyValue createKeyValueFromKey(final ByteBuffer bb) {
+    return createKeyValueFromKey(bb.array(), bb.arrayOffset(), bb.limit());
+  }
+
+  /**
+   * @param b
+   * @param o
+   * @param l
+   * @return A KeyValue made of a byte array that holds the key-only part.
+   *         Needed to convert hfile index members to KeyValues.
+   */
+  public static KeyValue createKeyValueFromKey(final byte[] b, final int o, final int l) {
+    byte[] newb = new byte[l + KeyValue.ROW_OFFSET];
+    System.arraycopy(b, o, newb, KeyValue.ROW_OFFSET, l);
+    Bytes.putInt(newb, 0, l);
+    Bytes.putInt(newb, Bytes.SIZEOF_INT, 0);
+    return new KeyValue(newb);
+  }
+
+  /**
+   * @param in
+   *          Where to read bytes from. Creates a byte array to hold the
+   *          KeyValue backing bytes copied from the steam.
+   * @return KeyValue created by deserializing from <code>in</code> OR if we
+   *         find a length of zero, we will return null which can be useful
+   *         marking a stream as done.
+   * @throws IOException
+   */
+  public static KeyValue create(final DataInput in) throws IOException {
+    return create(in.readInt(), in);
+  }
+
+  /**
+   * Create a KeyValue reading <code>length</code> from <code>in</code>
+   * 
+   * @param length
+   * @param in
+   * @return Created KeyValue OR if we find a length of zero, we will return
+   *         null which can be useful marking a stream as done.
+   * @throws IOException
+   */
+  public static KeyValue create(int length, final DataInput in) throws IOException {
+
+    if (length <= 0) {
+      if (length == 0)
+        return null;
+      throw new IOException("Failed read " + length + " bytes, stream corrupt?");
+    }
+
+    // This is how the old Writables.readFrom used to deserialize. Didn't even
+    // vint.
+    byte[] bytes = new byte[length];
+    in.readFully(bytes);
+    return new KeyValue(bytes, 0, length);
+  }
 
   public static void oswrite(final Cell cell, final OutputStream out, final boolean withTags)
       throws IOException {
@@ -576,7 +696,8 @@ public class KeyValueUtil {
       // write tags if we have to
       if (withTags && tlen > 0) {
         // 2 bytes tags length followed by tags bytes
-        // tags length is serialized with 2 bytes only(short way) even if the type is int. As this
+        // tags length is serialized with 2 bytes only(short way) even if the
+        // type is int. As this
         // is non -ve numbers, we save the sign bit. See HBASE-11437
         out.write((byte) (0xff & (tlen >> 8)));
         out.write((byte) (0xff & tlen));

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java
index ff86963..0781e1c 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java
@@ -23,10 +23,10 @@ import java.util.Arrays;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArraySet;
 
-import org.apache.hadoop.hbase.KeyValue.KVComparator;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.classification.InterfaceStability;
 import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.KeyValue.KVComparator;
 
 /**
  * Immutable POJO class for representing a table name.

http://git-wip-us.apache.org/repos/asf/hbase/blob/977f8674/hbase-common/src/main/java/org/apache/hadoop/hbase/codec/KeyValueCodec.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/codec/KeyValueCodec.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/codec/KeyValueCodec.java
index f41d6b0..7610b30 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/codec/KeyValueCodec.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/codec/KeyValueCodec.java
@@ -23,7 +23,6 @@ import java.io.OutputStream;
 
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.HBaseInterfaceAudience;
-import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.KeyValueUtil;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 
@@ -65,7 +64,7 @@ public class KeyValueCodec implements Codec {
     }
 
     protected Cell parseCell() throws IOException {
-      return KeyValue.iscreate(in);
+      return KeyValueUtil.iscreate(in);
     }
   }