001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020package org.apache.hadoop.hbase.filter;
021
022import java.util.Random;
023
024import org.apache.hadoop.hbase.Cell;
025import org.apache.yetus.audience.InterfaceAudience;
026import org.apache.hadoop.hbase.exceptions.DeserializationException;
027import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos;
028
029import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException;
030
031/**
032 * A filter that includes rows based on a chance.
033 * 
034 */
035@InterfaceAudience.Public
036public class RandomRowFilter extends FilterBase {
037  protected static final Random random = new Random();
038
039  protected float chance;
040  protected boolean filterOutRow;
041
042  /**
043   * Create a new filter with a specified chance for a row to be included.
044   * 
045   * @param chance
046   */
047  public RandomRowFilter(float chance) {
048    this.chance = chance;
049  }
050
051  /**
052   * @return The chance that a row gets included.
053   */
054  public float getChance() {
055    return chance;
056  }
057
058  /**
059   * Set the chance that a row is included.
060   * 
061   * @param chance
062   */
063  public void setChance(float chance) {
064    this.chance = chance;
065  }
066
067  @Override
068  public boolean filterAllRemaining() {
069    return false;
070  }
071
072  @Deprecated
073  @Override
074  public ReturnCode filterKeyValue(final Cell c) {
075    return filterCell(c);
076  }
077
078  @Override
079  public ReturnCode filterCell(final Cell c) {
080    if (filterOutRow) {
081      return ReturnCode.NEXT_ROW;
082    }
083    return ReturnCode.INCLUDE;
084  }
085
086  @Override
087  public boolean filterRow() {
088    return filterOutRow;
089  }
090
091  @Override
092  public boolean hasFilterRow() {
093    return true;
094  }
095
096  @Override
097  public boolean filterRowKey(Cell firstRowCell) {
098    if (chance < 0) {
099      // with a zero chance, the rows is always excluded
100      filterOutRow = true;
101    } else if (chance > 1) {
102      // always included
103      filterOutRow = false;
104    } else {
105      // roll the dice
106      filterOutRow = !(random.nextFloat() < chance);
107    }
108    return filterOutRow;
109  }
110
111  @Override
112  public void reset() {
113    filterOutRow = false;
114  }
115
116  /**
117   * @return The filter serialized using pb
118   */
119  @Override
120  public byte [] toByteArray() {
121    FilterProtos.RandomRowFilter.Builder builder =
122      FilterProtos.RandomRowFilter.newBuilder();
123    builder.setChance(this.chance);
124    return builder.build().toByteArray();
125  }
126
127  /**
128   * @param pbBytes A pb serialized {@link RandomRowFilter} instance
129   * @return An instance of {@link RandomRowFilter} made from <code>bytes</code>
130   * @throws DeserializationException
131   * @see #toByteArray
132   */
133  public static RandomRowFilter parseFrom(final byte [] pbBytes)
134  throws DeserializationException {
135    FilterProtos.RandomRowFilter proto;
136    try {
137      proto = FilterProtos.RandomRowFilter.parseFrom(pbBytes);
138    } catch (InvalidProtocolBufferException e) {
139      throw new DeserializationException(e);
140    }
141    return new RandomRowFilter(proto.getChance());
142  }
143
144  /**
145   * @param o the other filter to compare with
146   * @return true if and only if the fields of the filter that are serialized
147   * are equal to the corresponding fields in other.  Used for testing.
148   */
149  @Override
150  boolean areSerializedFieldsEqual(Filter o) {
151    if (o == this) return true;
152    if (!(o instanceof RandomRowFilter)) return false;
153
154    RandomRowFilter other = (RandomRowFilter)o;
155    return this.getChance() == other.getChance();
156  }
157}