You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by en...@apache.org on 2013/05/10 07:58:17 UTC

svn commit: r1480887 - in /hbase/branches/0.94/src: main/java/org/apache/hadoop/hbase/client/coprocessor/ main/java/org/apache/hadoop/hbase/filter/ test/java/org/apache/hadoop/hbase/filter/ test/java/org/apache/hadoop/hbase/zookeeper/

Author: enis
Date: Fri May 10 05:58:16 2013
New Revision: 1480887

URL: http://svn.apache.org/r1480887
Log:
HBASE-8513 [0.94] Fix class files with CRLF endings

Modified:
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/coprocessor/BigDecimalColumnInterpreter.java
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java
    hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilter.java
    hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestRecoverableZooKeeper.java

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/coprocessor/BigDecimalColumnInterpreter.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/coprocessor/BigDecimalColumnInterpreter.java?rev=1480887&r1=1480886&r2=1480887&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/coprocessor/BigDecimalColumnInterpreter.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/coprocessor/BigDecimalColumnInterpreter.java Fri May 10 05:58:16 2013
@@ -1,104 +1,104 @@
-/*
- *
- * 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.hadoop.hbase.client.coprocessor;
-
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.hadoop.hbase.KeyValue;
-import org.apache.hadoop.hbase.coprocessor.ColumnInterpreter;
-import org.apache.hadoop.hbase.util.Bytes;
-
-/**
- * ColumnInterpreter for doing Aggregation's with BigDecimal columns. 
- * This class is required at the RegionServer also.
- *
- */
-public class BigDecimalColumnInterpreter implements ColumnInterpreter<BigDecimal, BigDecimal> {
-  private static final Log log = LogFactory.getLog(BigDecimalColumnInterpreter.class);
-
-  @Override
-  public void readFields(DataInput arg0) throws IOException {
-  }
-
-  @Override
-  public void write(DataOutput arg0) throws IOException {
-  }
-
-  @Override
-  public BigDecimal getValue(byte[] family, byte[] qualifier, KeyValue kv)
-      throws IOException {
-    if ((kv == null || kv.getValue() == null)) return null;
-    return Bytes.toBigDecimal(kv.getValue()).setScale(2, RoundingMode.HALF_EVEN);
-  }
-
-  @Override
-  public BigDecimal add(BigDecimal val1, BigDecimal val2) {
-    if ((((val1 == null) ? 1 : 0) ^ ((val2 == null) ? 1 : 0)) != 0) {
-      return ((val1 == null) ? val2 : val1);
-    }
-    if (val1 == null) return null;
-    return val1.add(val2).setScale(2, RoundingMode.HALF_EVEN);
-  }
-
-  @Override
-  public BigDecimal getMaxValue() {
-    return BigDecimal.valueOf(Double.MAX_VALUE);
-  }
-
-  @Override
-  public BigDecimal getMinValue() {
-    return BigDecimal.valueOf(Double.MIN_VALUE);
-  }
-
-  @Override
-  public BigDecimal multiply(BigDecimal val1, BigDecimal val2) {
-    return (((val1 == null) || (val2 == null)) ? null : val1.multiply(val2).setScale(2,
-      RoundingMode.HALF_EVEN));
-  }
-
-  @Override
-  public BigDecimal increment(BigDecimal val) {
-    return ((val == null) ? null : val.add(BigDecimal.ONE));
-  }
-
-  @Override
-  public BigDecimal castToReturnType(BigDecimal val) {
-    return val;
-  }
-
-  @Override
-  public int compare(BigDecimal val1, BigDecimal val2) {
-    if ((((val1 == null) ? 1 : 0) ^ ((val2 == null) ? 1 : 0)) != 0) {
-      return ((val1 == null) ? -1 : 1);
-    }
-    if (val1 == null) return 0;
-    return val1.compareTo(val2);
-  }
-
-  @Override
-  public double divideForAvg(BigDecimal val1, Long paramLong) {
-    return (((paramLong == null) || (val1 == null)) ? (Double.NaN) :
-      val1.doubleValue() / paramLong.doubleValue());
-  }
-}
+/*
+ *
+ * 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.hadoop.hbase.client.coprocessor;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.coprocessor.ColumnInterpreter;
+import org.apache.hadoop.hbase.util.Bytes;
+
+/**
+ * ColumnInterpreter for doing Aggregation's with BigDecimal columns. 
+ * This class is required at the RegionServer also.
+ *
+ */
+public class BigDecimalColumnInterpreter implements ColumnInterpreter<BigDecimal, BigDecimal> {
+  private static final Log log = LogFactory.getLog(BigDecimalColumnInterpreter.class);
+
+  @Override
+  public void readFields(DataInput arg0) throws IOException {
+  }
+
+  @Override
+  public void write(DataOutput arg0) throws IOException {
+  }
+
+  @Override
+  public BigDecimal getValue(byte[] family, byte[] qualifier, KeyValue kv)
+      throws IOException {
+    if ((kv == null || kv.getValue() == null)) return null;
+    return Bytes.toBigDecimal(kv.getValue()).setScale(2, RoundingMode.HALF_EVEN);
+  }
+
+  @Override
+  public BigDecimal add(BigDecimal val1, BigDecimal val2) {
+    if ((((val1 == null) ? 1 : 0) ^ ((val2 == null) ? 1 : 0)) != 0) {
+      return ((val1 == null) ? val2 : val1);
+    }
+    if (val1 == null) return null;
+    return val1.add(val2).setScale(2, RoundingMode.HALF_EVEN);
+  }
+
+  @Override
+  public BigDecimal getMaxValue() {
+    return BigDecimal.valueOf(Double.MAX_VALUE);
+  }
+
+  @Override
+  public BigDecimal getMinValue() {
+    return BigDecimal.valueOf(Double.MIN_VALUE);
+  }
+
+  @Override
+  public BigDecimal multiply(BigDecimal val1, BigDecimal val2) {
+    return (((val1 == null) || (val2 == null)) ? null : val1.multiply(val2).setScale(2,
+      RoundingMode.HALF_EVEN));
+  }
+
+  @Override
+  public BigDecimal increment(BigDecimal val) {
+    return ((val == null) ? null : val.add(BigDecimal.ONE));
+  }
+
+  @Override
+  public BigDecimal castToReturnType(BigDecimal val) {
+    return val;
+  }
+
+  @Override
+  public int compare(BigDecimal val1, BigDecimal val2) {
+    if ((((val1 == null) ? 1 : 0) ^ ((val2 == null) ? 1 : 0)) != 0) {
+      return ((val1 == null) ? -1 : 1);
+    }
+    if (val1 == null) return 0;
+    return val1.compareTo(val2);
+  }
+
+  @Override
+  public double divideForAvg(BigDecimal val1, Long paramLong) {
+    return (((paramLong == null) || (val1 == null)) ? (Double.NaN) :
+      val1.doubleValue() / paramLong.doubleValue());
+  }
+}

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java?rev=1480887&r1=1480886&r2=1480887&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java Fri May 10 05:58:16 2013
@@ -1,289 +1,289 @@
-/**
- * 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.hadoop.hbase.filter;
-
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.hadoop.hbase.KeyValue;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.util.Pair;
-
-/**
- * Filters data based on fuzzy row key. Performs fast-forwards during scanning.
- * It takes pairs (row key, fuzzy info) to match row keys. Where fuzzy info is
- * a byte array with 0 or 1 as its values:
- * <ul>
- *   <li>
- *     0 - means that this byte in provided row key is fixed, i.e. row key's byte at same position
- *         must match
- *   </li>
- *   <li>
- *     1 - means that this byte in provided row key is NOT fixed, i.e. row key's byte at this
- *         position can be different from the one in provided row key
- *   </li>
- * </ul>
- *
- *
- * Example:
- * Let's assume row key format is userId_actionId_year_month. Length of userId is fixed
- * and is 4, length of actionId is 2 and year and month are 4 and 2 bytes long respectively.
- *
- * Let's assume that we need to fetch all users that performed certain action (encoded as "99")
- * in Jan of any year. Then the pair (row key, fuzzy info) would be the following:
- * row key = "????_99_????_01" (one can use any value instead of "?")
- * fuzzy info = "\x01\x01\x01\x01\x00\x00\x00\x00\x01\x01\x01\x01\x00\x00\x00"
- *
- * I.e. fuzzy info tells the matching mask is "????_99_????_01", where at ? can be any value.
- *
- */
-public class FuzzyRowFilter extends FilterBase {
-  private List<Pair<byte[], byte[]>> fuzzyKeysData;
-  private boolean done = false;
-
-  /**
-   * Used internally for reflection, do NOT use it directly
-   */
-  public FuzzyRowFilter() {
-  }
-
-  public FuzzyRowFilter(List<Pair<byte[], byte[]>> fuzzyKeysData) {
-    this.fuzzyKeysData = fuzzyKeysData;
-  }
-
-  // TODO: possible improvement: save which fuzzy row key to use when providing a hint
-  @Override
-  public ReturnCode filterKeyValue(KeyValue kv) {
-    byte[] rowKey = kv.getRow();
-    // assigning "worst" result first and looking for better options
-    SatisfiesCode bestOption = SatisfiesCode.NO_NEXT;
-    for (Pair<byte[], byte[]> fuzzyData : fuzzyKeysData) {
-      SatisfiesCode satisfiesCode =
-              satisfies(rowKey, fuzzyData.getFirst(), fuzzyData.getSecond());
-      if (satisfiesCode == SatisfiesCode.YES) {
-        return ReturnCode.INCLUDE;
-      }
-
-      if (satisfiesCode == SatisfiesCode.NEXT_EXISTS) {
-        bestOption = SatisfiesCode.NEXT_EXISTS;
-      }
-    }
-
-    if (bestOption == SatisfiesCode.NEXT_EXISTS) {
-      return ReturnCode.SEEK_NEXT_USING_HINT;
-    }
-
-    // the only unhandled SatisfiesCode is NO_NEXT, i.e. we are done
-    done = true;
-    return ReturnCode.NEXT_ROW;
-  }
-
-  @Override
-  public KeyValue getNextKeyHint(KeyValue currentKV) {
-    byte[] rowKey = currentKV.getRow();
-    byte[] nextRowKey = null;
-    // Searching for the "smallest" row key that satisfies at least one fuzzy row key
-    for (Pair<byte[], byte[]> fuzzyData : fuzzyKeysData) {
-      byte[] nextRowKeyCandidate = getNextForFuzzyRule(rowKey,
-              fuzzyData.getFirst(), fuzzyData.getSecond());
-      if (nextRowKeyCandidate == null) {
-        continue;
-      }
-      if (nextRowKey == null || Bytes.compareTo(nextRowKeyCandidate, nextRowKey) < 0) {
-        nextRowKey = nextRowKeyCandidate;
-      }
-    }
-
-    if (nextRowKey == null) {
-      // SHOULD NEVER happen
-      // TODO: is there a better way than throw exception? (stop the scanner?)
-      throw new IllegalStateException("No next row key that satisfies fuzzy exists when" +
-                                         " getNextKeyHint() is invoked." +
-                                         " Filter: " + this.toString() +
-                                         " currentKV: " + currentKV.toString());
-    }
-
-    return KeyValue.createFirstOnRow(nextRowKey);
-  }
-
-  @Override
-  public boolean filterAllRemaining() {
-    return done;
-  }
-
-  @Override
-  public void write(DataOutput dataOutput) throws IOException {
-    dataOutput.writeInt(this.fuzzyKeysData.size());
-    for (Pair<byte[], byte[]> fuzzyData : fuzzyKeysData) {
-      Bytes.writeByteArray(dataOutput, fuzzyData.getFirst());
-      Bytes.writeByteArray(dataOutput, fuzzyData.getSecond());
-    }
-  }
-
-  @Override
-  public void readFields(DataInput dataInput) throws IOException {
-    int count = dataInput.readInt();
-    this.fuzzyKeysData = new ArrayList<Pair<byte[], byte[]>>(count);
-    for (int i = 0; i < count; i++) {
-      byte[] keyBytes = Bytes.readByteArray(dataInput);
-      byte[] keyMeta = Bytes.readByteArray(dataInput);
-      this.fuzzyKeysData.add(new Pair<byte[], byte[]>(keyBytes, keyMeta));
-    }
-  }
-
-  @Override
-  public String toString() {
-    final StringBuilder sb = new StringBuilder();
-    sb.append("FuzzyRowFilter");
-    sb.append("{fuzzyKeysData=");
-    for (Pair<byte[], byte[]> fuzzyData : fuzzyKeysData) {
-      sb.append('{').append(Bytes.toStringBinary(fuzzyData.getFirst())).append(":");
-      sb.append(Bytes.toStringBinary(fuzzyData.getSecond())).append('}');
-    }
-    sb.append("}, ");
-    return sb.toString();
-  }
-
-  // Utility methods
-
-  static enum SatisfiesCode {
-    // row satisfies fuzzy rule
-    YES,
-    // row doesn't satisfy fuzzy rule, but there's possible greater row that does
-    NEXT_EXISTS,
-    // row doesn't satisfy fuzzy rule and there's no greater row that does
-    NO_NEXT
-  }
-
-  static SatisfiesCode satisfies(byte[] row,
-                                         byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
-    return satisfies(row, 0, row.length, fuzzyKeyBytes, fuzzyKeyMeta);
-  }
-
-  private static SatisfiesCode satisfies(byte[] row, int offset, int length,
-                                         byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
-    if (row == null) {
-      // do nothing, let scan to proceed
-      return SatisfiesCode.YES;
-    }
-
-    boolean nextRowKeyCandidateExists = false;
-
-    for (int i = 0; i < fuzzyKeyMeta.length && i < length; i++) {
-      // First, checking if this position is fixed and not equals the given one
-      boolean byteAtPositionFixed = fuzzyKeyMeta[i] == 0;
-      boolean fixedByteIncorrect = byteAtPositionFixed && fuzzyKeyBytes[i] != row[i + offset];
-      if (fixedByteIncorrect) {
-        // in this case there's another row that satisfies fuzzy rule and bigger than this row
-        if (nextRowKeyCandidateExists) {
-          return SatisfiesCode.NEXT_EXISTS;
-        }
-
-        // If this row byte is less than fixed then there's a byte array bigger than
-        // this row and which satisfies the fuzzy rule. Otherwise there's no such byte array:
-        // this row is simply bigger than any byte array that satisfies the fuzzy rule
-        boolean rowByteLessThanFixed = (row[i + offset] & 0xFF) < (fuzzyKeyBytes[i] & 0xFF);
-        return  rowByteLessThanFixed ? SatisfiesCode.NEXT_EXISTS : SatisfiesCode.NO_NEXT;
-      }
-
-      // Second, checking if this position is not fixed and byte value is not the biggest. In this
-      // case there's a byte array bigger than this row and which satisfies the fuzzy rule. To get
-      // bigger byte array that satisfies the rule we need to just increase this byte
-      // (see the code of getNextForFuzzyRule below) by one.
-      // Note: if non-fixed byte is already at biggest value, this doesn't allow us to say there's
-      //       bigger one that satisfies the rule as it can't be increased.
-      if (fuzzyKeyMeta[i] == 1 && !isMax(fuzzyKeyBytes[i])) {
-        nextRowKeyCandidateExists = true;
-      }
-    }
-
-    return SatisfiesCode.YES;
-  }
-
-  private static boolean isMax(byte fuzzyKeyByte) {
-    return (fuzzyKeyByte & 0xFF) == 255;
-  }
-
-  static byte[] getNextForFuzzyRule(byte[] row, byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
-    return getNextForFuzzyRule(row, 0, row.length, fuzzyKeyBytes, fuzzyKeyMeta);
-  }
-
-  /**
-   * @return greater byte array than given (row) which satisfies the fuzzy rule if it exists,
-   *         null otherwise
-   */
-  private static byte[] getNextForFuzzyRule(byte[] row, int offset, int length,
-                                            byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
-    // To find out the next "smallest" byte array that satisfies fuzzy rule and "greater" than
-    // the given one we do the following:
-    // 1. setting values on all "fixed" positions to the values from fuzzyKeyBytes
-    // 2. if during the first step given row did not increase, then we increase the value at
-    //    the first "non-fixed" position (where it is not maximum already)
-
-    // It is easier to perform this by using fuzzyKeyBytes copy and setting "non-fixed" position
-    // values than otherwise.
-    byte[] result = Arrays.copyOf(fuzzyKeyBytes,
-                                  length > fuzzyKeyBytes.length ? length : fuzzyKeyBytes.length);
-    int toInc = -1;
-
-    boolean increased = false;
-    for (int i = 0; i < result.length; i++) {
-      if (i >= fuzzyKeyMeta.length || fuzzyKeyMeta[i] == 1) {
-        result[i] = row[offset + i];
-        if (!isMax(row[i])) {
-          // this is "non-fixed" position and is not at max value, hence we can increase it
-          toInc = i;
-        }
-      } else if (i < fuzzyKeyMeta.length && fuzzyKeyMeta[i] == 0) {
-        if ((row[i + offset] & 0xFF) < (fuzzyKeyBytes[i] & 0xFF)) {
-          // if setting value for any fixed position increased the original array,
-          // we are OK
-          increased = true;
-          break;
-        }
-        if ((row[i + offset] & 0xFF) > (fuzzyKeyBytes[i] & 0xFF)) {
-          // if setting value for any fixed position makes array "smaller", then just stop:
-          // in case we found some non-fixed position to increase we will do it, otherwise
-          // there's no "next" row key that satisfies fuzzy rule and "greater" than given row
-          break;
-        }
-      }
-    }
-
-    if (!increased) {
-      if (toInc < 0) {
-        return null;
-      }
-      result[toInc]++;
-
-      // Setting all "non-fixed" positions to zeroes to the right of the one we increased so
-      // that found "next" row key is the smallest possible
-      for (int i = toInc + 1; i < result.length; i++) {
-        if (i >= fuzzyKeyMeta.length || fuzzyKeyMeta[i] == 1) {
-          result[i] = 0;
-        }
-      }
-    }
-
-    return result;
-  }
-}
+/**
+ * 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.hadoop.hbase.filter;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.Pair;
+
+/**
+ * Filters data based on fuzzy row key. Performs fast-forwards during scanning.
+ * It takes pairs (row key, fuzzy info) to match row keys. Where fuzzy info is
+ * a byte array with 0 or 1 as its values:
+ * <ul>
+ *   <li>
+ *     0 - means that this byte in provided row key is fixed, i.e. row key's byte at same position
+ *         must match
+ *   </li>
+ *   <li>
+ *     1 - means that this byte in provided row key is NOT fixed, i.e. row key's byte at this
+ *         position can be different from the one in provided row key
+ *   </li>
+ * </ul>
+ *
+ *
+ * Example:
+ * Let's assume row key format is userId_actionId_year_month. Length of userId is fixed
+ * and is 4, length of actionId is 2 and year and month are 4 and 2 bytes long respectively.
+ *
+ * Let's assume that we need to fetch all users that performed certain action (encoded as "99")
+ * in Jan of any year. Then the pair (row key, fuzzy info) would be the following:
+ * row key = "????_99_????_01" (one can use any value instead of "?")
+ * fuzzy info = "\x01\x01\x01\x01\x00\x00\x00\x00\x01\x01\x01\x01\x00\x00\x00"
+ *
+ * I.e. fuzzy info tells the matching mask is "????_99_????_01", where at ? can be any value.
+ *
+ */
+public class FuzzyRowFilter extends FilterBase {
+  private List<Pair<byte[], byte[]>> fuzzyKeysData;
+  private boolean done = false;
+
+  /**
+   * Used internally for reflection, do NOT use it directly
+   */
+  public FuzzyRowFilter() {
+  }
+
+  public FuzzyRowFilter(List<Pair<byte[], byte[]>> fuzzyKeysData) {
+    this.fuzzyKeysData = fuzzyKeysData;
+  }
+
+  // TODO: possible improvement: save which fuzzy row key to use when providing a hint
+  @Override
+  public ReturnCode filterKeyValue(KeyValue kv) {
+    byte[] rowKey = kv.getRow();
+    // assigning "worst" result first and looking for better options
+    SatisfiesCode bestOption = SatisfiesCode.NO_NEXT;
+    for (Pair<byte[], byte[]> fuzzyData : fuzzyKeysData) {
+      SatisfiesCode satisfiesCode =
+              satisfies(rowKey, fuzzyData.getFirst(), fuzzyData.getSecond());
+      if (satisfiesCode == SatisfiesCode.YES) {
+        return ReturnCode.INCLUDE;
+      }
+
+      if (satisfiesCode == SatisfiesCode.NEXT_EXISTS) {
+        bestOption = SatisfiesCode.NEXT_EXISTS;
+      }
+    }
+
+    if (bestOption == SatisfiesCode.NEXT_EXISTS) {
+      return ReturnCode.SEEK_NEXT_USING_HINT;
+    }
+
+    // the only unhandled SatisfiesCode is NO_NEXT, i.e. we are done
+    done = true;
+    return ReturnCode.NEXT_ROW;
+  }
+
+  @Override
+  public KeyValue getNextKeyHint(KeyValue currentKV) {
+    byte[] rowKey = currentKV.getRow();
+    byte[] nextRowKey = null;
+    // Searching for the "smallest" row key that satisfies at least one fuzzy row key
+    for (Pair<byte[], byte[]> fuzzyData : fuzzyKeysData) {
+      byte[] nextRowKeyCandidate = getNextForFuzzyRule(rowKey,
+              fuzzyData.getFirst(), fuzzyData.getSecond());
+      if (nextRowKeyCandidate == null) {
+        continue;
+      }
+      if (nextRowKey == null || Bytes.compareTo(nextRowKeyCandidate, nextRowKey) < 0) {
+        nextRowKey = nextRowKeyCandidate;
+      }
+    }
+
+    if (nextRowKey == null) {
+      // SHOULD NEVER happen
+      // TODO: is there a better way than throw exception? (stop the scanner?)
+      throw new IllegalStateException("No next row key that satisfies fuzzy exists when" +
+                                         " getNextKeyHint() is invoked." +
+                                         " Filter: " + this.toString() +
+                                         " currentKV: " + currentKV.toString());
+    }
+
+    return KeyValue.createFirstOnRow(nextRowKey);
+  }
+
+  @Override
+  public boolean filterAllRemaining() {
+    return done;
+  }
+
+  @Override
+  public void write(DataOutput dataOutput) throws IOException {
+    dataOutput.writeInt(this.fuzzyKeysData.size());
+    for (Pair<byte[], byte[]> fuzzyData : fuzzyKeysData) {
+      Bytes.writeByteArray(dataOutput, fuzzyData.getFirst());
+      Bytes.writeByteArray(dataOutput, fuzzyData.getSecond());
+    }
+  }
+
+  @Override
+  public void readFields(DataInput dataInput) throws IOException {
+    int count = dataInput.readInt();
+    this.fuzzyKeysData = new ArrayList<Pair<byte[], byte[]>>(count);
+    for (int i = 0; i < count; i++) {
+      byte[] keyBytes = Bytes.readByteArray(dataInput);
+      byte[] keyMeta = Bytes.readByteArray(dataInput);
+      this.fuzzyKeysData.add(new Pair<byte[], byte[]>(keyBytes, keyMeta));
+    }
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder();
+    sb.append("FuzzyRowFilter");
+    sb.append("{fuzzyKeysData=");
+    for (Pair<byte[], byte[]> fuzzyData : fuzzyKeysData) {
+      sb.append('{').append(Bytes.toStringBinary(fuzzyData.getFirst())).append(":");
+      sb.append(Bytes.toStringBinary(fuzzyData.getSecond())).append('}');
+    }
+    sb.append("}, ");
+    return sb.toString();
+  }
+
+  // Utility methods
+
+  static enum SatisfiesCode {
+    // row satisfies fuzzy rule
+    YES,
+    // row doesn't satisfy fuzzy rule, but there's possible greater row that does
+    NEXT_EXISTS,
+    // row doesn't satisfy fuzzy rule and there's no greater row that does
+    NO_NEXT
+  }
+
+  static SatisfiesCode satisfies(byte[] row,
+                                         byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
+    return satisfies(row, 0, row.length, fuzzyKeyBytes, fuzzyKeyMeta);
+  }
+
+  private static SatisfiesCode satisfies(byte[] row, int offset, int length,
+                                         byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
+    if (row == null) {
+      // do nothing, let scan to proceed
+      return SatisfiesCode.YES;
+    }
+
+    boolean nextRowKeyCandidateExists = false;
+
+    for (int i = 0; i < fuzzyKeyMeta.length && i < length; i++) {
+      // First, checking if this position is fixed and not equals the given one
+      boolean byteAtPositionFixed = fuzzyKeyMeta[i] == 0;
+      boolean fixedByteIncorrect = byteAtPositionFixed && fuzzyKeyBytes[i] != row[i + offset];
+      if (fixedByteIncorrect) {
+        // in this case there's another row that satisfies fuzzy rule and bigger than this row
+        if (nextRowKeyCandidateExists) {
+          return SatisfiesCode.NEXT_EXISTS;
+        }
+
+        // If this row byte is less than fixed then there's a byte array bigger than
+        // this row and which satisfies the fuzzy rule. Otherwise there's no such byte array:
+        // this row is simply bigger than any byte array that satisfies the fuzzy rule
+        boolean rowByteLessThanFixed = (row[i + offset] & 0xFF) < (fuzzyKeyBytes[i] & 0xFF);
+        return  rowByteLessThanFixed ? SatisfiesCode.NEXT_EXISTS : SatisfiesCode.NO_NEXT;
+      }
+
+      // Second, checking if this position is not fixed and byte value is not the biggest. In this
+      // case there's a byte array bigger than this row and which satisfies the fuzzy rule. To get
+      // bigger byte array that satisfies the rule we need to just increase this byte
+      // (see the code of getNextForFuzzyRule below) by one.
+      // Note: if non-fixed byte is already at biggest value, this doesn't allow us to say there's
+      //       bigger one that satisfies the rule as it can't be increased.
+      if (fuzzyKeyMeta[i] == 1 && !isMax(fuzzyKeyBytes[i])) {
+        nextRowKeyCandidateExists = true;
+      }
+    }
+
+    return SatisfiesCode.YES;
+  }
+
+  private static boolean isMax(byte fuzzyKeyByte) {
+    return (fuzzyKeyByte & 0xFF) == 255;
+  }
+
+  static byte[] getNextForFuzzyRule(byte[] row, byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
+    return getNextForFuzzyRule(row, 0, row.length, fuzzyKeyBytes, fuzzyKeyMeta);
+  }
+
+  /**
+   * @return greater byte array than given (row) which satisfies the fuzzy rule if it exists,
+   *         null otherwise
+   */
+  private static byte[] getNextForFuzzyRule(byte[] row, int offset, int length,
+                                            byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
+    // To find out the next "smallest" byte array that satisfies fuzzy rule and "greater" than
+    // the given one we do the following:
+    // 1. setting values on all "fixed" positions to the values from fuzzyKeyBytes
+    // 2. if during the first step given row did not increase, then we increase the value at
+    //    the first "non-fixed" position (where it is not maximum already)
+
+    // It is easier to perform this by using fuzzyKeyBytes copy and setting "non-fixed" position
+    // values than otherwise.
+    byte[] result = Arrays.copyOf(fuzzyKeyBytes,
+                                  length > fuzzyKeyBytes.length ? length : fuzzyKeyBytes.length);
+    int toInc = -1;
+
+    boolean increased = false;
+    for (int i = 0; i < result.length; i++) {
+      if (i >= fuzzyKeyMeta.length || fuzzyKeyMeta[i] == 1) {
+        result[i] = row[offset + i];
+        if (!isMax(row[i])) {
+          // this is "non-fixed" position and is not at max value, hence we can increase it
+          toInc = i;
+        }
+      } else if (i < fuzzyKeyMeta.length && fuzzyKeyMeta[i] == 0) {
+        if ((row[i + offset] & 0xFF) < (fuzzyKeyBytes[i] & 0xFF)) {
+          // if setting value for any fixed position increased the original array,
+          // we are OK
+          increased = true;
+          break;
+        }
+        if ((row[i + offset] & 0xFF) > (fuzzyKeyBytes[i] & 0xFF)) {
+          // if setting value for any fixed position makes array "smaller", then just stop:
+          // in case we found some non-fixed position to increase we will do it, otherwise
+          // there's no "next" row key that satisfies fuzzy rule and "greater" than given row
+          break;
+        }
+      }
+    }
+
+    if (!increased) {
+      if (toInc < 0) {
+        return null;
+      }
+      result[toInc]++;
+
+      // Setting all "non-fixed" positions to zeroes to the right of the one we increased so
+      // that found "next" row key is the smallest possible
+      for (int i = toInc + 1; i < result.length; i++) {
+        if (i >= fuzzyKeyMeta.length || fuzzyKeyMeta[i] == 1) {
+          result[i] = 0;
+        }
+      }
+    }
+
+    return result;
+  }
+}

Modified: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilter.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilter.java?rev=1480887&r1=1480886&r2=1480887&view=diff
==============================================================================
--- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilter.java (original)
+++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilter.java Fri May 10 05:58:16 2013
@@ -1,204 +1,204 @@
-/**
- * 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.hadoop.hbase.filter;
-
-import org.apache.hadoop.hbase.SmallTests;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Category(SmallTests.class)
-public class TestFuzzyRowFilter {
-  @Test
-  public void testSatisfies() {
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
-            FuzzyRowFilter.satisfies(new byte[]{1, (byte) -128, 0, 0, 1}, // row to check
-                                     new byte[]{1, 0, 1}, // fuzzy row
-                                     new byte[]{0, 1, 0})); // mask
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
-            FuzzyRowFilter.satisfies(new byte[]{1, (byte) -128, 1, 0, 1},
-                                     new byte[]{1, 0, 1},
-                                     new byte[]{0, 1, 0}));
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
-            FuzzyRowFilter.satisfies(new byte[]{1, (byte) -128, 2, 0, 1},
-                                     new byte[]{1, 0, 1},
-                                     new byte[]{0, 1, 0}));
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NO_NEXT,
-            FuzzyRowFilter.satisfies(new byte[]{2, 3, 1, 1, 1},
-                                     new byte[]{1, 0, 1},
-                                     new byte[]{0, 1, 0}));
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
-            FuzzyRowFilter.satisfies(new byte[]{1, 2, 1, 3, 3},
-                                     new byte[]{1, 2, 0, 3},
-                                     new byte[]{0, 0, 1, 0}));
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
-            FuzzyRowFilter.satisfies(new byte[]{1, 1, 1, 3, 0}, // row to check
-                                     new byte[]{1, 2, 0, 3}, // fuzzy row
-                                     new byte[]{0, 0, 1, 0})); // mask
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
-            FuzzyRowFilter.satisfies(new byte[]{1, 1, 1, 3, 0},
-                                     new byte[]{1, (byte) 245, 0, 3},
-                                     new byte[]{0, 0, 1, 0}));
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NO_NEXT,
-            FuzzyRowFilter.satisfies(new byte[]{1, (byte) 245, 1, 3, 0},
-                                     new byte[]{1, 1, 0, 3},
-                                     new byte[]{0, 0, 1, 0}));
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NO_NEXT,
-            FuzzyRowFilter.satisfies(new byte[]{1, 3, 1, 3, 0},
-                                     new byte[]{1, 2, 0, 3},
-                                     new byte[]{0, 0, 1, 0}));
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NO_NEXT,
-            FuzzyRowFilter.satisfies(new byte[]{2, 1, 1, 1, 0},
-                                     new byte[]{1, 2, 0, 3},
-                                     new byte[]{0, 0, 1, 0}));
-
-    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
-            FuzzyRowFilter.satisfies(new byte[]{1, 2, 1, 0, 1},
-                                     new byte[]{0, 1, 2},
-                                     new byte[]{1, 0, 0}));
-  }
-
-  @Test
-  public void testGetNextForFuzzyRule() {
-    assertNext(
-            new byte[]{0, 1, 2}, // fuzzy row
-            new byte[]{1, 0, 0}, // mask
-            new byte[]{1, 2, 1, 0, 1}, // current
-            new byte[]{2, 1, 2, 0, 0}); // expected next
-
-    assertNext(
-            new byte[]{0, 1, 2}, // fuzzy row
-            new byte[]{1, 0, 0}, // mask
-            new byte[]{1, 1, 2, 0, 1}, // current
-            new byte[]{1, 1, 2, 0, 2}); // expected next
-
-    assertNext(
-            new byte[]{0, 1, 0, 2, 0}, // fuzzy row
-            new byte[]{1, 0, 1, 0, 1}, // mask
-            new byte[]{1, 0, 2, 0, 1}, // current
-            new byte[]{1, 1, 0, 2, 0}); // expected next
-
-    assertNext(
-            new byte[]{1, 0, 1},
-            new byte[]{0, 1, 0},
-            new byte[]{1, (byte) 128, 2, 0, 1},
-            new byte[]{1, (byte) 129, 1, 0, 0});
-
-    assertNext(
-            new byte[]{0, 1, 0, 1},
-            new byte[]{1, 0, 1, 0},
-            new byte[]{5, 1, 0, 1},
-            new byte[]{5, 1, 1, 1});
-
-    assertNext(
-            new byte[]{0, 1, 0, 1},
-            new byte[]{1, 0, 1, 0},
-            new byte[]{5, 1, 0, 1, 1},
-            new byte[]{5, 1, 0, 1, 2});
-
-    assertNext(
-            new byte[]{0, 1, 0, 0}, // fuzzy row
-            new byte[]{1, 0, 1, 1}, // mask
-            new byte[]{5, 1, (byte) 255, 1}, // current
-            new byte[]{5, 1, (byte) 255, 2}); // expected next
-
-    assertNext(
-            new byte[]{0, 1, 0, 1}, // fuzzy row
-            new byte[]{1, 0, 1, 0}, // mask
-            new byte[]{5, 1, (byte) 255, 1}, // current
-            new byte[]{6, 1, 0, 1}); // expected next
-
-    assertNext(
-            new byte[]{0, 1, 0, 1}, // fuzzy row
-            new byte[]{1, 0, 1, 0}, // mask
-            new byte[]{5, 1, (byte) 255, 0}, // current
-            new byte[]{5, 1, (byte) 255, 1}); // expected next
-
-    assertNext(
-            new byte[]{5, 1, 1, 0},
-            new byte[]{0, 0, 1, 1},
-            new byte[]{5, 1, (byte) 255, 1},
-            new byte[]{5, 1, (byte) 255, 2});
-
-    assertNext(
-            new byte[]{1, 1, 1, 1},
-            new byte[]{0, 0, 1, 1},
-            new byte[]{1, 1, 2, 2},
-            new byte[]{1, 1, 2, 3});
-
-    assertNext(
-            new byte[]{1, 1, 1, 1},
-            new byte[]{0, 0, 1, 1},
-            new byte[]{1, 1, 3, 2},
-            new byte[]{1, 1, 3, 3});
-
-    assertNext(
-            new byte[]{1, 1, 1, 1},
-            new byte[]{1, 1, 1, 1},
-            new byte[]{1, 1, 2, 3},
-            new byte[]{1, 1, 2, 4});
-
-    assertNext(
-            new byte[]{1, 1, 1, 1},
-            new byte[]{1, 1, 1, 1},
-            new byte[]{1, 1, 3, 2},
-            new byte[]{1, 1, 3, 3});
-
-    assertNext(
-            new byte[]{1, 1, 0, 0},
-            new byte[]{0, 0, 1, 1},
-            new byte[]{0, 1, 3, 2},
-            new byte[]{1, 1, 0, 0});
-
-    // No next for this one
-    Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
-            new byte[]{2, 3, 1, 1, 1}, // row to check
-            new byte[]{1, 0, 1}, // fuzzy row
-            new byte[]{0, 1, 0})); // mask
-    Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
-            new byte[]{1, (byte) 245, 1, 3, 0},
-            new byte[]{1, 1, 0, 3},
-            new byte[]{0, 0, 1, 0}));
-    Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
-            new byte[]{1, 3, 1, 3, 0},
-            new byte[]{1, 2, 0, 3},
-            new byte[]{0, 0, 1, 0}));
-    Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
-            new byte[]{2, 1, 1, 1, 0},
-            new byte[]{1, 2, 0, 3},
-            new byte[]{0, 0, 1, 0}));
-  }
-
-  private void assertNext(byte[] fuzzyRow, byte[] mask, byte[] current, byte[] expected) {
-    byte[] nextForFuzzyRule = FuzzyRowFilter.getNextForFuzzyRule(current, fuzzyRow, mask);
-    Assert.assertArrayEquals(expected, nextForFuzzyRule);
-  }
-
-  @org.junit.Rule
-  public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
-          new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
-}
+/**
+ * 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.hadoop.hbase.filter;
+
+import org.apache.hadoop.hbase.SmallTests;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(SmallTests.class)
+public class TestFuzzyRowFilter {
+  @Test
+  public void testSatisfies() {
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
+            FuzzyRowFilter.satisfies(new byte[]{1, (byte) -128, 0, 0, 1}, // row to check
+                                     new byte[]{1, 0, 1}, // fuzzy row
+                                     new byte[]{0, 1, 0})); // mask
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
+            FuzzyRowFilter.satisfies(new byte[]{1, (byte) -128, 1, 0, 1},
+                                     new byte[]{1, 0, 1},
+                                     new byte[]{0, 1, 0}));
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
+            FuzzyRowFilter.satisfies(new byte[]{1, (byte) -128, 2, 0, 1},
+                                     new byte[]{1, 0, 1},
+                                     new byte[]{0, 1, 0}));
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NO_NEXT,
+            FuzzyRowFilter.satisfies(new byte[]{2, 3, 1, 1, 1},
+                                     new byte[]{1, 0, 1},
+                                     new byte[]{0, 1, 0}));
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
+            FuzzyRowFilter.satisfies(new byte[]{1, 2, 1, 3, 3},
+                                     new byte[]{1, 2, 0, 3},
+                                     new byte[]{0, 0, 1, 0}));
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
+            FuzzyRowFilter.satisfies(new byte[]{1, 1, 1, 3, 0}, // row to check
+                                     new byte[]{1, 2, 0, 3}, // fuzzy row
+                                     new byte[]{0, 0, 1, 0})); // mask
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
+            FuzzyRowFilter.satisfies(new byte[]{1, 1, 1, 3, 0},
+                                     new byte[]{1, (byte) 245, 0, 3},
+                                     new byte[]{0, 0, 1, 0}));
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NO_NEXT,
+            FuzzyRowFilter.satisfies(new byte[]{1, (byte) 245, 1, 3, 0},
+                                     new byte[]{1, 1, 0, 3},
+                                     new byte[]{0, 0, 1, 0}));
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NO_NEXT,
+            FuzzyRowFilter.satisfies(new byte[]{1, 3, 1, 3, 0},
+                                     new byte[]{1, 2, 0, 3},
+                                     new byte[]{0, 0, 1, 0}));
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NO_NEXT,
+            FuzzyRowFilter.satisfies(new byte[]{2, 1, 1, 1, 0},
+                                     new byte[]{1, 2, 0, 3},
+                                     new byte[]{0, 0, 1, 0}));
+
+    Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
+            FuzzyRowFilter.satisfies(new byte[]{1, 2, 1, 0, 1},
+                                     new byte[]{0, 1, 2},
+                                     new byte[]{1, 0, 0}));
+  }
+
+  @Test
+  public void testGetNextForFuzzyRule() {
+    assertNext(
+            new byte[]{0, 1, 2}, // fuzzy row
+            new byte[]{1, 0, 0}, // mask
+            new byte[]{1, 2, 1, 0, 1}, // current
+            new byte[]{2, 1, 2, 0, 0}); // expected next
+
+    assertNext(
+            new byte[]{0, 1, 2}, // fuzzy row
+            new byte[]{1, 0, 0}, // mask
+            new byte[]{1, 1, 2, 0, 1}, // current
+            new byte[]{1, 1, 2, 0, 2}); // expected next
+
+    assertNext(
+            new byte[]{0, 1, 0, 2, 0}, // fuzzy row
+            new byte[]{1, 0, 1, 0, 1}, // mask
+            new byte[]{1, 0, 2, 0, 1}, // current
+            new byte[]{1, 1, 0, 2, 0}); // expected next
+
+    assertNext(
+            new byte[]{1, 0, 1},
+            new byte[]{0, 1, 0},
+            new byte[]{1, (byte) 128, 2, 0, 1},
+            new byte[]{1, (byte) 129, 1, 0, 0});
+
+    assertNext(
+            new byte[]{0, 1, 0, 1},
+            new byte[]{1, 0, 1, 0},
+            new byte[]{5, 1, 0, 1},
+            new byte[]{5, 1, 1, 1});
+
+    assertNext(
+            new byte[]{0, 1, 0, 1},
+            new byte[]{1, 0, 1, 0},
+            new byte[]{5, 1, 0, 1, 1},
+            new byte[]{5, 1, 0, 1, 2});
+
+    assertNext(
+            new byte[]{0, 1, 0, 0}, // fuzzy row
+            new byte[]{1, 0, 1, 1}, // mask
+            new byte[]{5, 1, (byte) 255, 1}, // current
+            new byte[]{5, 1, (byte) 255, 2}); // expected next
+
+    assertNext(
+            new byte[]{0, 1, 0, 1}, // fuzzy row
+            new byte[]{1, 0, 1, 0}, // mask
+            new byte[]{5, 1, (byte) 255, 1}, // current
+            new byte[]{6, 1, 0, 1}); // expected next
+
+    assertNext(
+            new byte[]{0, 1, 0, 1}, // fuzzy row
+            new byte[]{1, 0, 1, 0}, // mask
+            new byte[]{5, 1, (byte) 255, 0}, // current
+            new byte[]{5, 1, (byte) 255, 1}); // expected next
+
+    assertNext(
+            new byte[]{5, 1, 1, 0},
+            new byte[]{0, 0, 1, 1},
+            new byte[]{5, 1, (byte) 255, 1},
+            new byte[]{5, 1, (byte) 255, 2});
+
+    assertNext(
+            new byte[]{1, 1, 1, 1},
+            new byte[]{0, 0, 1, 1},
+            new byte[]{1, 1, 2, 2},
+            new byte[]{1, 1, 2, 3});
+
+    assertNext(
+            new byte[]{1, 1, 1, 1},
+            new byte[]{0, 0, 1, 1},
+            new byte[]{1, 1, 3, 2},
+            new byte[]{1, 1, 3, 3});
+
+    assertNext(
+            new byte[]{1, 1, 1, 1},
+            new byte[]{1, 1, 1, 1},
+            new byte[]{1, 1, 2, 3},
+            new byte[]{1, 1, 2, 4});
+
+    assertNext(
+            new byte[]{1, 1, 1, 1},
+            new byte[]{1, 1, 1, 1},
+            new byte[]{1, 1, 3, 2},
+            new byte[]{1, 1, 3, 3});
+
+    assertNext(
+            new byte[]{1, 1, 0, 0},
+            new byte[]{0, 0, 1, 1},
+            new byte[]{0, 1, 3, 2},
+            new byte[]{1, 1, 0, 0});
+
+    // No next for this one
+    Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
+            new byte[]{2, 3, 1, 1, 1}, // row to check
+            new byte[]{1, 0, 1}, // fuzzy row
+            new byte[]{0, 1, 0})); // mask
+    Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
+            new byte[]{1, (byte) 245, 1, 3, 0},
+            new byte[]{1, 1, 0, 3},
+            new byte[]{0, 0, 1, 0}));
+    Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
+            new byte[]{1, 3, 1, 3, 0},
+            new byte[]{1, 2, 0, 3},
+            new byte[]{0, 0, 1, 0}));
+    Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
+            new byte[]{2, 1, 1, 1, 0},
+            new byte[]{1, 2, 0, 3},
+            new byte[]{0, 0, 1, 0}));
+  }
+
+  private void assertNext(byte[] fuzzyRow, byte[] mask, byte[] current, byte[] expected) {
+    byte[] nextForFuzzyRule = FuzzyRowFilter.getNextForFuzzyRule(current, fuzzyRow, mask);
+    Assert.assertArrayEquals(expected, nextForFuzzyRule);
+  }
+
+  @org.junit.Rule
+  public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
+          new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
+}

Modified: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestRecoverableZooKeeper.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestRecoverableZooKeeper.java?rev=1480887&r1=1480886&r2=1480887&view=diff
==============================================================================
--- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestRecoverableZooKeeper.java (original)
+++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestRecoverableZooKeeper.java Fri May 10 05:58:16 2013
@@ -1,123 +1,123 @@
-/*
- * 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.hadoop.hbase.zookeeper;
-
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.Properties;
-
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hbase.Abortable;
-import org.apache.hadoop.hbase.HBaseTestingUtility;
-import org.apache.hadoop.hbase.HConstants;
-import org.apache.hadoop.hbase.MediumTests;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.zookeeper.CreateMode;
-import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.Watcher;
-import org.apache.zookeeper.ZooDefs.Ids;
-import org.apache.zookeeper.ZooKeeper;
-import org.apache.zookeeper.data.Stat;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Category(MediumTests.class)
-public class TestRecoverableZooKeeper {
-
-  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
-
-  Abortable abortable = new Abortable() {
-    @Override
-    public void abort(String why, Throwable e) {
-
-    }
-
-    @Override
-    public boolean isAborted() {
-      return false;
-    }
-  };
-
-  @BeforeClass
-  public static void setUpBeforeClass() throws Exception {
-    TEST_UTIL.startMiniZKCluster();
-  }
-
-  @AfterClass
-  public static void tearDownAfterClass() throws Exception {
-    TEST_UTIL.shutdownMiniZKCluster();
-  }
-
-  @Test
-  public void testSetDataVersionMismatchInLoop() throws Exception {
-    String znode = "/hbase/unassigned/9af7cfc9b15910a0b3d714bf40a3248f";
-    Configuration conf = TEST_UTIL.getConfiguration();
-    Properties properties = ZKConfig.makeZKProps(conf);
-    ZooKeeperWatcher zkw = new ZooKeeperWatcher(conf, "testSetDataVersionMismatchInLoop",
-        abortable, true);
-    String ensemble = ZKConfig.getZKQuorumServersString(properties);
-    RecoverableZooKeeper rzk = ZKUtil.connect(conf, ensemble, zkw);
-    rzk.create(znode, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
-    rzk.setData(znode, "OPENING".getBytes(), 0);
-    Field zkField = RecoverableZooKeeper.class.getDeclaredField("zk");
-    zkField.setAccessible(true);
-    int timeout = conf.getInt(HConstants.ZK_SESSION_TIMEOUT, HConstants.DEFAULT_ZK_SESSION_TIMEOUT);
-    ZookeeperStub zkStub = new ZookeeperStub(ensemble, timeout, zkw);
-    zkStub.setThrowExceptionInNumOperations(1);
-    zkField.set(rzk, zkStub);
-    byte[] opened = "OPENED".getBytes();
-    rzk.setData(znode, opened, 1);
-    byte[] data = rzk.getData(znode, false, new Stat());
-    assertTrue(Bytes.equals(opened, data));
-  }
-
-  class ZookeeperStub extends ZooKeeper {
-
-    private int throwExceptionInNumOperations;
-
-    public ZookeeperStub(String connectString, int sessionTimeout, Watcher watcher)
-        throws IOException {
-      super(connectString, sessionTimeout, watcher);
-    }
-
-    public void setThrowExceptionInNumOperations(int throwExceptionInNumOperations) {
-      this.throwExceptionInNumOperations = throwExceptionInNumOperations;
-    }
-
-    private void checkThrowKeeperException() throws KeeperException {
-      if (throwExceptionInNumOperations == 1) {
-        throwExceptionInNumOperations = 0;
-        throw new KeeperException.ConnectionLossException();
-      }
-      if (throwExceptionInNumOperations > 0)
-        throwExceptionInNumOperations--;
-    }
-
-    @Override
-    public Stat setData(String path, byte[] data, int version) throws KeeperException,
-        InterruptedException {
-      Stat stat = super.setData(path, data, version);
-      checkThrowKeeperException();
-      return stat;
-    }
-  }
-}
+/*
+ * 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.hadoop.hbase.zookeeper;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Properties;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.Abortable;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.MediumTests;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.Stat;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(MediumTests.class)
+public class TestRecoverableZooKeeper {
+
+  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+
+  Abortable abortable = new Abortable() {
+    @Override
+    public void abort(String why, Throwable e) {
+
+    }
+
+    @Override
+    public boolean isAborted() {
+      return false;
+    }
+  };
+
+  @BeforeClass
+  public static void setUpBeforeClass() throws Exception {
+    TEST_UTIL.startMiniZKCluster();
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TEST_UTIL.shutdownMiniZKCluster();
+  }
+
+  @Test
+  public void testSetDataVersionMismatchInLoop() throws Exception {
+    String znode = "/hbase/unassigned/9af7cfc9b15910a0b3d714bf40a3248f";
+    Configuration conf = TEST_UTIL.getConfiguration();
+    Properties properties = ZKConfig.makeZKProps(conf);
+    ZooKeeperWatcher zkw = new ZooKeeperWatcher(conf, "testSetDataVersionMismatchInLoop",
+        abortable, true);
+    String ensemble = ZKConfig.getZKQuorumServersString(properties);
+    RecoverableZooKeeper rzk = ZKUtil.connect(conf, ensemble, zkw);
+    rzk.create(znode, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+    rzk.setData(znode, "OPENING".getBytes(), 0);
+    Field zkField = RecoverableZooKeeper.class.getDeclaredField("zk");
+    zkField.setAccessible(true);
+    int timeout = conf.getInt(HConstants.ZK_SESSION_TIMEOUT, HConstants.DEFAULT_ZK_SESSION_TIMEOUT);
+    ZookeeperStub zkStub = new ZookeeperStub(ensemble, timeout, zkw);
+    zkStub.setThrowExceptionInNumOperations(1);
+    zkField.set(rzk, zkStub);
+    byte[] opened = "OPENED".getBytes();
+    rzk.setData(znode, opened, 1);
+    byte[] data = rzk.getData(znode, false, new Stat());
+    assertTrue(Bytes.equals(opened, data));
+  }
+
+  class ZookeeperStub extends ZooKeeper {
+
+    private int throwExceptionInNumOperations;
+
+    public ZookeeperStub(String connectString, int sessionTimeout, Watcher watcher)
+        throws IOException {
+      super(connectString, sessionTimeout, watcher);
+    }
+
+    public void setThrowExceptionInNumOperations(int throwExceptionInNumOperations) {
+      this.throwExceptionInNumOperations = throwExceptionInNumOperations;
+    }
+
+    private void checkThrowKeeperException() throws KeeperException {
+      if (throwExceptionInNumOperations == 1) {
+        throwExceptionInNumOperations = 0;
+        throw new KeeperException.ConnectionLossException();
+      }
+      if (throwExceptionInNumOperations > 0)
+        throwExceptionInNumOperations--;
+    }
+
+    @Override
+    public Stat setData(String path, byte[] data, int version) throws KeeperException,
+        InterruptedException {
+      Stat stat = super.setData(path, data, version);
+      checkThrowKeeperException();
+      return stat;
+    }
+  }
+}