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 com.google.protobuf.InvalidProtocolBufferException;
23  import org.apache.hadoop.classification.InterfaceAudience;
24  import org.apache.hadoop.classification.InterfaceStability;
25  import org.apache.hadoop.hbase.KeyValue;
26  import org.apache.hadoop.hbase.exceptions.DeserializationException;
27  import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
28  
29  import java.util.Random;
30  
31  /**
32   * A filter that includes rows based on a chance.
33   * 
34   */
35  @InterfaceAudience.Public
36  @InterfaceStability.Stable
37  public class RandomRowFilter extends FilterBase {
38    protected static final Random random = new Random();
39  
40    protected float chance;
41    protected boolean filterOutRow;
42  
43    /**
44     * Create a new filter with a specified chance for a row to be included.
45     * 
46     * @param chance
47     */
48    public RandomRowFilter(float chance) {
49      this.chance = chance;
50    }
51  
52    /**
53     * @return The chance that a row gets included.
54     */
55    public float getChance() {
56      return chance;
57    }
58  
59    /**
60     * Set the chance that a row is included.
61     * 
62     * @param chance
63     */
64    public void setChance(float chance) {
65      this.chance = chance;
66    }
67  
68    @Override
69    public boolean filterAllRemaining() {
70      return false;
71    }
72  
73    @Override
74    public ReturnCode filterKeyValue(KeyValue v) {
75      if (filterOutRow) {
76        return ReturnCode.NEXT_ROW;
77      }
78      return ReturnCode.INCLUDE;
79    }
80  
81    @Override
82    public boolean filterRow() {
83      return filterOutRow;
84    }
85    
86    public boolean hasFilterRow() {
87      return true;
88    }
89  
90    @Override
91    public boolean filterRowKey(byte[] buffer, int offset, int length) {
92      if (chance < 0) {
93        // with a zero chance, the rows is always excluded
94        filterOutRow = true;
95      } else if (chance > 1) {
96        // always included
97        filterOutRow = false;
98      } else {
99        // roll the dice
100       filterOutRow = !(random.nextFloat() < chance);
101     }
102     return filterOutRow;
103   }
104 
105   @Override
106   public void reset() {
107     filterOutRow = false;
108   }
109 
110   /**
111    * @return The filter serialized using pb
112    */
113   public byte [] toByteArray() {
114     FilterProtos.RandomRowFilter.Builder builder =
115       FilterProtos.RandomRowFilter.newBuilder();
116     builder.setChance(this.chance);
117     return builder.build().toByteArray();
118   }
119 
120   /**
121    * @param pbBytes A pb serialized {@link RandomRowFilter} instance
122    * @return An instance of {@link RandomRowFilter} made from <code>bytes</code>
123    * @throws DeserializationException
124    * @see #toByteArray
125    */
126   public static RandomRowFilter parseFrom(final byte [] pbBytes)
127   throws DeserializationException {
128     FilterProtos.RandomRowFilter proto;
129     try {
130       proto = FilterProtos.RandomRowFilter.parseFrom(pbBytes);
131     } catch (InvalidProtocolBufferException e) {
132       throw new DeserializationException(e);
133     }
134     return new RandomRowFilter(proto.getChance());
135   }
136 
137   /**
138    * @param other
139    * @return true if and only if the fields of the filter that are serialized
140    * are equal to the corresponding fields in other.  Used for testing.
141    */
142   boolean areSerializedFieldsEqual(Filter o) {
143     if (o == this) return true;
144     if (!(o instanceof RandomRowFilter)) return false;
145 
146     RandomRowFilter other = (RandomRowFilter)o;
147     return this.getChance() == other.getChance();
148   }
149 }