001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.filter; 019 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.Objects; 023import org.apache.hadoop.hbase.Cell; 024import org.apache.hadoop.hbase.exceptions.DeserializationException; 025import org.apache.yetus.audience.InterfaceAudience; 026 027import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 028import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException; 029 030import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos; 031 032/** 033 * Implementation of Filter interface that limits results to a specific page size. It terminates 034 * scanning once the number of filter-passed rows is > the given page size. 035 * <p> 036 * Note that this filter cannot guarantee that the number of results returned to a client are <= 037 * page size. This is because the filter is applied separately on different region servers. It does 038 * however optimize the scan of individual HRegions by making sure that the page size is never 039 * exceeded locally. 040 */ 041@InterfaceAudience.Public 042public class PageFilter extends FilterBase { 043 private long pageSize = Long.MAX_VALUE; 044 private int rowsAccepted = 0; 045 046 /** 047 * Constructor that takes a maximum page size. 048 * @param pageSize Maximum result size. 049 */ 050 public PageFilter(final long pageSize) { 051 Preconditions.checkArgument(pageSize >= 0, "must be positive %s", pageSize); 052 this.pageSize = pageSize; 053 } 054 055 public long getPageSize() { 056 return pageSize; 057 } 058 059 @Override 060 public boolean filterRowKey(Cell cell) throws IOException { 061 // Impl in FilterBase might do unnecessary copy for Off heap backed Cells. 062 if (filterAllRemaining()) return true; 063 return false; 064 } 065 066 @Deprecated 067 @Override 068 public ReturnCode filterKeyValue(final Cell c) throws IOException { 069 return filterCell(c); 070 } 071 072 @Override 073 public ReturnCode filterCell(final Cell ignored) throws IOException { 074 return ReturnCode.INCLUDE; 075 } 076 077 @Override 078 public boolean filterAllRemaining() { 079 return this.rowsAccepted >= this.pageSize; 080 } 081 082 @Override 083 public boolean filterRow() { 084 this.rowsAccepted++; 085 return this.rowsAccepted > this.pageSize; 086 } 087 088 @Override 089 public boolean hasFilterRow() { 090 return true; 091 } 092 093 public static Filter createFilterFromArguments(ArrayList<byte[]> filterArguments) { 094 Preconditions.checkArgument(filterArguments.size() == 1, "Expected 1 but got: %s", 095 filterArguments.size()); 096 long pageSize = ParseFilter.convertByteArrayToLong(filterArguments.get(0)); 097 return new PageFilter(pageSize); 098 } 099 100 /** Returns The filter serialized using pb */ 101 @Override 102 public byte[] toByteArray() { 103 FilterProtos.PageFilter.Builder builder = FilterProtos.PageFilter.newBuilder(); 104 builder.setPageSize(this.pageSize); 105 return builder.build().toByteArray(); 106 } 107 108 /** 109 * Parse a serialized representation of {@link PageFilter} 110 * @param pbBytes A pb serialized {@link PageFilter} instance 111 * @return An instance of {@link PageFilter} made from <code>bytes</code> 112 * @throws DeserializationException if an error occurred 113 * @see #toByteArray 114 */ 115 public static PageFilter parseFrom(final byte[] pbBytes) throws DeserializationException { 116 FilterProtos.PageFilter proto; 117 try { 118 proto = FilterProtos.PageFilter.parseFrom(pbBytes); 119 } catch (InvalidProtocolBufferException e) { 120 throw new DeserializationException(e); 121 } 122 return new PageFilter(proto.getPageSize()); 123 } 124 125 /** 126 * Returns true if and only if the fields of the filter that are serialized are equal to the 127 * corresponding fields in other. Used for testing. 128 */ 129 @Override 130 boolean areSerializedFieldsEqual(Filter o) { 131 if (o == this) { 132 return true; 133 } 134 if (!(o instanceof PageFilter)) { 135 return false; 136 } 137 138 PageFilter other = (PageFilter) o; 139 return this.getPageSize() == other.getPageSize(); 140 } 141 142 @Override 143 public String toString() { 144 return this.getClass().getSimpleName() + " " + this.pageSize; 145 } 146 147 @Override 148 public boolean equals(Object obj) { 149 return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj); 150 } 151 152 @Override 153 public int hashCode() { 154 return Objects.hash(this.pageSize); 155 } 156}