View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.filter;
21  
22  import java.nio.ByteBuffer;
23  
24  import org.apache.hadoop.hbase.classification.InterfaceAudience;
25  import org.apache.hadoop.hbase.classification.InterfaceStability;
26  import org.apache.hadoop.hbase.exceptions.DeserializationException;
27  import org.apache.hadoop.hbase.protobuf.generated.ComparatorProtos;
28  
29  import com.google.protobuf.InvalidProtocolBufferException;
30  
31  /**
32   * A bit comparator which performs the specified bitwise operation on each of the bytes
33   * with the specified byte array. Then returns whether the result is non-zero.
34   */
35  @InterfaceAudience.Public
36  @InterfaceStability.Stable
37  public class BitComparator extends ByteArrayComparable {
38  
39    /** Bit operators. */
40    @InterfaceAudience.Public
41    @InterfaceStability.Stable
42    public enum BitwiseOp {
43      /** and */
44      AND,
45      /** or */
46      OR,
47      /** xor */
48      XOR
49    }
50    protected BitwiseOp bitOperator;
51  
52    /**
53     * Constructor
54     * @param value value
55     * @param bitOperator operator to use on the bit comparison
56     */
57    public BitComparator(byte[] value, BitwiseOp bitOperator) {
58      super(value);
59      this.bitOperator = bitOperator;
60    }
61  
62    /**
63     * @return the bitwise operator
64     */
65    public BitwiseOp getOperator() {
66      return bitOperator;
67    }
68  
69    /**
70     * @return The comparator serialized using pb
71     */
72    public byte [] toByteArray() {
73      ComparatorProtos.BitComparator.Builder builder =
74        ComparatorProtos.BitComparator.newBuilder();
75      builder.setComparable(super.convert());
76      ComparatorProtos.BitComparator.BitwiseOp bitwiseOpPb =
77        ComparatorProtos.BitComparator.BitwiseOp.valueOf(bitOperator.name());
78      builder.setBitwiseOp(bitwiseOpPb);
79      return builder.build().toByteArray();
80    }
81  
82    /**
83     * @param pbBytes A pb serialized {@link BitComparator} instance
84     * @return An instance of {@link BitComparator} made from <code>bytes</code>
85     * @throws DeserializationException
86     * @see #toByteArray
87     */
88    public static BitComparator parseFrom(final byte [] pbBytes)
89    throws DeserializationException {
90      ComparatorProtos.BitComparator proto;
91      try {
92        proto = ComparatorProtos.BitComparator.parseFrom(pbBytes);
93      } catch (InvalidProtocolBufferException e) {
94        throw new DeserializationException(e);
95      }
96      BitwiseOp bitwiseOp = BitwiseOp.valueOf(proto.getBitwiseOp().name());
97      return new BitComparator(proto.getComparable().getValue().toByteArray(),bitwiseOp);
98    }
99  
100   /**
101    * @param other
102    * @return true if and only if the fields of the comparator that are serialized
103    * are equal to the corresponding fields in other.  Used for testing.
104    */
105   boolean areSerializedFieldsEqual(ByteArrayComparable other) {
106     if (other == this) return true;
107     if (!(other instanceof BitComparator)) return false;
108 
109     BitComparator comparator = (BitComparator)other;
110     return super.areSerializedFieldsEqual(other)
111       && this.getOperator().equals(comparator.getOperator());
112   }
113 
114   @Override
115   public int compareTo(byte[] value, int offset, int length) {
116     if (length != this.value.length) {
117       return 1;
118     }
119     int b = 0;
120     //Iterating backwards is faster because we can quit after one non-zero byte.
121     for (int i = length - 1; i >= 0 && b == 0; i--) {
122       switch (bitOperator) {
123         case AND:
124           b = (this.value[i] & value[i+offset]) & 0xff;
125           break;
126         case OR:
127           b = (this.value[i] | value[i+offset]) & 0xff;
128           break;
129         case XOR:
130           b = (this.value[i] ^ value[i+offset]) & 0xff;
131           break;
132       }
133     }
134     return b == 0 ? 1 : 0;
135   }
136 
137   @Override
138   public int compareTo(ByteBuffer value, int offset, int length) {
139     if (length != this.value.length) {
140       return 1;
141     }
142     int b = 0;
143     //Iterating backwards is faster because we can quit after one non-zero byte.
144     for (int i = length - 1; i >= 0 && b == 0; i--) {
145       switch (bitOperator) {
146         case AND:
147           b = (this.value[i] & value.get(i + offset)) & 0xff;
148           break;
149         case OR:
150           b = (this.value[i] | value.get(i + offset)) & 0xff;
151           break;
152         case XOR:
153           b = (this.value[i] ^ value.get(i + offset)) & 0xff;
154           break;
155       }
156     }
157     return b == 0 ? 1 : 0;
158   }
159 }
160