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.Objects; 023import java.util.Random; 024 025import org.apache.hadoop.hbase.Cell; 026import org.apache.yetus.audience.InterfaceAudience; 027import org.apache.hadoop.hbase.exceptions.DeserializationException; 028import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos; 029 030import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException; 031 032/** 033 * A filter that includes rows based on a chance. 034 * 035 */ 036@InterfaceAudience.Public 037public class RandomRowFilter extends FilterBase { 038 protected static final Random random = new Random(); 039 040 protected float chance; 041 protected boolean filterOutRow; 042 043 /** 044 * Create a new filter with a specified chance for a row to be included. 045 * 046 * @param chance 047 */ 048 public RandomRowFilter(float chance) { 049 this.chance = chance; 050 } 051 052 /** 053 * @return The chance that a row gets included. 054 */ 055 public float getChance() { 056 return chance; 057 } 058 059 /** 060 * Set the chance that a row is included. 061 * 062 * @param chance 063 */ 064 public void setChance(float chance) { 065 this.chance = chance; 066 } 067 068 @Override 069 public boolean filterAllRemaining() { 070 return false; 071 } 072 073 @Deprecated 074 @Override 075 public ReturnCode filterKeyValue(final Cell c) { 076 return filterCell(c); 077 } 078 079 @Override 080 public ReturnCode filterCell(final Cell c) { 081 if (filterOutRow) { 082 return ReturnCode.NEXT_ROW; 083 } 084 return ReturnCode.INCLUDE; 085 } 086 087 @Override 088 public boolean filterRow() { 089 return filterOutRow; 090 } 091 092 @Override 093 public boolean hasFilterRow() { 094 return true; 095 } 096 097 @Override 098 public boolean filterRowKey(Cell firstRowCell) { 099 if (chance < 0) { 100 // with a zero chance, the rows is always excluded 101 filterOutRow = true; 102 } else if (chance > 1) { 103 // always included 104 filterOutRow = false; 105 } else { 106 // roll the dice 107 filterOutRow = !(random.nextFloat() < chance); 108 } 109 return filterOutRow; 110 } 111 112 @Override 113 public void reset() { 114 filterOutRow = false; 115 } 116 117 /** 118 * @return The filter serialized using pb 119 */ 120 @Override 121 public byte [] toByteArray() { 122 FilterProtos.RandomRowFilter.Builder builder = 123 FilterProtos.RandomRowFilter.newBuilder(); 124 builder.setChance(this.chance); 125 return builder.build().toByteArray(); 126 } 127 128 /** 129 * @param pbBytes A pb serialized {@link RandomRowFilter} instance 130 * @return An instance of {@link RandomRowFilter} made from <code>bytes</code> 131 * @throws DeserializationException 132 * @see #toByteArray 133 */ 134 public static RandomRowFilter parseFrom(final byte [] pbBytes) 135 throws DeserializationException { 136 FilterProtos.RandomRowFilter proto; 137 try { 138 proto = FilterProtos.RandomRowFilter.parseFrom(pbBytes); 139 } catch (InvalidProtocolBufferException e) { 140 throw new DeserializationException(e); 141 } 142 return new RandomRowFilter(proto.getChance()); 143 } 144 145 /** 146 * @param o the other filter to compare with 147 * @return true if and only if the fields of the filter that are serialized 148 * are equal to the corresponding fields in other. Used for testing. 149 */ 150 @Override 151 boolean areSerializedFieldsEqual(Filter o) { 152 if (o == this) return true; 153 if (!(o instanceof RandomRowFilter)) return false; 154 155 RandomRowFilter other = (RandomRowFilter)o; 156 return this.getChance() == other.getChance(); 157 } 158 159 @Override 160 public boolean equals(Object obj) { 161 return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj); 162 } 163 164 @Override 165 public int hashCode() { 166 return Objects.hash(this.getChance()); 167 } 168}