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 */
019package org.apache.hadoop.hbase.filter;
020
021import java.io.IOException;
022import java.nio.ByteBuffer;
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.Iterator;
026import java.util.Optional;
027import org.apache.hadoop.hbase.ByteBufferExtendedCell;
028import org.apache.hadoop.hbase.Cell;
029import org.apache.hadoop.hbase.HConstants;
030import org.apache.hadoop.hbase.Tag;
031import org.apache.hadoop.hbase.exceptions.DeserializationException;
032import org.apache.hadoop.hbase.util.Bytes;
033import org.apache.hadoop.hbase.util.ClassSize;
034import org.apache.yetus.audience.InterfaceAudience;
035
036import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
037import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException;
038import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos;
039
040/**
041 * A filter that will only return the key component of each KV (the value will
042 * be rewritten as empty).
043 * <p>
044 * This filter can be used to grab all of the keys without having to also grab
045 * the values.
046 */
047@InterfaceAudience.Public
048public class KeyOnlyFilter extends FilterBase {
049
050  boolean lenAsVal;
051  public KeyOnlyFilter() { this(false); }
052  public KeyOnlyFilter(boolean lenAsVal) { this.lenAsVal = lenAsVal; }
053
054  @Override
055  public boolean filterRowKey(Cell cell) throws IOException {
056    // Impl in FilterBase might do unnecessary copy for Off heap backed Cells.
057    return false;
058  }
059
060  @Override
061  public Cell transformCell(Cell cell) {
062    return createKeyOnlyCell(cell);
063  }
064
065  private Cell createKeyOnlyCell(Cell c) {
066    if (c instanceof ByteBufferExtendedCell) {
067      return new KeyOnlyByteBufferExtendedCell((ByteBufferExtendedCell) c, lenAsVal);
068    } else {
069      return new KeyOnlyCell(c, lenAsVal);
070    }
071  }
072
073  @Deprecated
074  @Override
075  public ReturnCode filterKeyValue(final Cell ignored) throws IOException {
076    return filterCell(ignored);
077  }
078
079  @Override
080  public ReturnCode filterCell(final Cell ignored) throws IOException {
081    return ReturnCode.INCLUDE;
082  }
083
084  public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
085    Preconditions.checkArgument((filterArguments.isEmpty() || filterArguments.size() == 1),
086                                "Expected: 0 or 1 but got: %s", filterArguments.size());
087    KeyOnlyFilter filter = new KeyOnlyFilter();
088    if (filterArguments.size() == 1) {
089      filter.lenAsVal = ParseFilter.convertByteArrayToBoolean(filterArguments.get(0));
090    }
091    return filter;
092  }
093
094  /**
095   * @return The filter serialized using pb
096   */
097  @Override
098  public byte [] toByteArray() {
099    FilterProtos.KeyOnlyFilter.Builder builder =
100      FilterProtos.KeyOnlyFilter.newBuilder();
101    builder.setLenAsVal(this.lenAsVal);
102    return builder.build().toByteArray();
103  }
104
105  /**
106   * @param pbBytes A pb serialized {@link KeyOnlyFilter} instance
107   * @return An instance of {@link KeyOnlyFilter} made from <code>bytes</code>
108   * @throws DeserializationException
109   * @see #toByteArray
110   */
111  public static KeyOnlyFilter parseFrom(final byte [] pbBytes)
112  throws DeserializationException {
113    FilterProtos.KeyOnlyFilter proto;
114    try {
115      proto = FilterProtos.KeyOnlyFilter.parseFrom(pbBytes);
116    } catch (InvalidProtocolBufferException e) {
117      throw new DeserializationException(e);
118    }
119    return new KeyOnlyFilter(proto.getLenAsVal());
120  }
121
122  /**
123   * @param o the other filter to compare with
124   * @return true if and only if the fields of the filter that are serialized
125   * are equal to the corresponding fields in other.  Used for testing.
126   */
127  @Override
128  boolean areSerializedFieldsEqual(Filter o) {
129    if (o == this) return true;
130    if (!(o instanceof KeyOnlyFilter)) return false;
131
132    KeyOnlyFilter other = (KeyOnlyFilter)o;
133    return this.lenAsVal == other.lenAsVal;
134  }
135
136  static class KeyOnlyCell implements Cell {
137    private Cell cell;
138    private boolean lenAsVal;
139
140    public KeyOnlyCell(Cell c, boolean lenAsVal) {
141      this.cell = c;
142      this.lenAsVal = lenAsVal;
143    }
144
145    @Override
146    public byte[] getRowArray() {
147      return cell.getRowArray();
148    }
149
150    @Override
151    public int getRowOffset() {
152      return cell.getRowOffset();
153    }
154
155    @Override
156    public short getRowLength() {
157      return cell.getRowLength();
158    }
159
160    @Override
161    public byte[] getFamilyArray() {
162      return cell.getFamilyArray();
163    }
164
165    @Override
166    public int getFamilyOffset() {
167      return cell.getFamilyOffset();
168    }
169
170    @Override
171    public byte getFamilyLength() {
172      return cell.getFamilyLength();
173    }
174
175    @Override
176    public byte[] getQualifierArray() {
177      return cell.getQualifierArray();
178    }
179
180    @Override
181    public int getQualifierOffset() {
182      return cell.getQualifierOffset();
183    }
184
185    @Override
186    public int getQualifierLength() {
187      return cell.getQualifierLength();
188    }
189
190    @Override
191    public long getTimestamp() {
192      return cell.getTimestamp();
193    }
194
195    @Override
196    public byte getTypeByte() {
197      return cell.getTypeByte();
198    }
199
200    @Override
201    public Type getType() {
202      return cell.getType();
203    }
204
205
206    @Override
207    public long getSequenceId() {
208      return 0;
209    }
210
211    @Override
212    public byte[] getValueArray() {
213      if (lenAsVal) {
214        return Bytes.toBytes(cell.getValueLength());
215      } else {
216        return HConstants.EMPTY_BYTE_ARRAY;
217      }
218    }
219
220    @Override
221    public int getValueOffset() {
222      return 0;
223    }
224
225    @Override
226    public int getValueLength() {
227      if (lenAsVal) {
228        return Bytes.SIZEOF_INT;
229      } else {
230        return 0;
231      }
232    }
233
234    @Override
235    public byte[] getTagsArray() {
236      return HConstants.EMPTY_BYTE_ARRAY;
237    }
238
239    @Override
240    public int getTagsOffset() {
241      return 0;
242    }
243
244    @Override
245    public int getTagsLength() {
246      return 0;
247    }
248  }
249
250  static class KeyOnlyByteBufferExtendedCell extends ByteBufferExtendedCell {
251    public static final int FIXED_OVERHEAD = ClassSize.OBJECT + ClassSize.REFERENCE
252        + Bytes.SIZEOF_BOOLEAN;
253    private ByteBufferExtendedCell cell;
254    private boolean lenAsVal;
255
256    public KeyOnlyByteBufferExtendedCell(ByteBufferExtendedCell c, boolean lenAsVal) {
257      this.cell = c;
258      this.lenAsVal = lenAsVal;
259    }
260
261    @Override
262    public byte[] getRowArray() {
263      return cell.getRowArray();
264    }
265
266    @Override
267    public int getRowOffset() {
268      return cell.getRowOffset();
269    }
270
271    @Override
272    public short getRowLength() {
273      return cell.getRowLength();
274    }
275
276    @Override
277    public byte[] getFamilyArray() {
278      return cell.getFamilyArray();
279    }
280
281    @Override
282    public int getFamilyOffset() {
283      return cell.getFamilyOffset();
284    }
285
286    @Override
287    public byte getFamilyLength() {
288      return cell.getFamilyLength();
289    }
290
291    @Override
292    public byte[] getQualifierArray() {
293      return cell.getQualifierArray();
294    }
295
296    @Override
297    public int getQualifierOffset() {
298      return cell.getQualifierOffset();
299    }
300
301    @Override
302    public int getQualifierLength() {
303      return cell.getQualifierLength();
304    }
305
306    @Override
307    public long getTimestamp() {
308      return cell.getTimestamp();
309    }
310
311    @Override
312    public byte getTypeByte() {
313      return cell.getTypeByte();
314    }
315
316    @Override
317    public void setSequenceId(long seqId) throws IOException {
318      cell.setSequenceId(seqId);
319    }
320
321    @Override
322    public void setTimestamp(long ts) throws IOException {
323      cell.setTimestamp(ts);
324    }
325
326    @Override
327    public void setTimestamp(byte[] ts) throws IOException {
328      cell.setTimestamp(ts);
329    }
330
331    @Override
332    public long getSequenceId() {
333      return 0;
334    }
335
336    @Override
337    public Type getType() {
338      return cell.getType();
339    }
340
341    @Override
342    public byte[] getValueArray() {
343      if (lenAsVal) {
344        return Bytes.toBytes(cell.getValueLength());
345      } else {
346        return HConstants.EMPTY_BYTE_ARRAY;
347      }
348    }
349
350    @Override
351    public int getValueOffset() {
352      return 0;
353    }
354
355    @Override
356    public int getValueLength() {
357      if (lenAsVal) {
358        return Bytes.SIZEOF_INT;
359      } else {
360        return 0;
361      }
362    }
363
364    @Override
365    public byte[] getTagsArray() {
366      return HConstants.EMPTY_BYTE_ARRAY;
367    }
368
369    @Override
370    public int getTagsOffset() {
371      return 0;
372    }
373
374    @Override
375    public int getTagsLength() {
376      return 0;
377    }
378
379    @Override
380    public ByteBuffer getRowByteBuffer() {
381      return cell.getRowByteBuffer();
382    }
383
384    @Override
385    public int getRowPosition() {
386      return cell.getRowPosition();
387    }
388
389    @Override
390    public ByteBuffer getFamilyByteBuffer() {
391      return cell.getFamilyByteBuffer();
392    }
393
394    @Override
395    public int getFamilyPosition() {
396      return cell.getFamilyPosition();
397    }
398
399    @Override
400    public ByteBuffer getQualifierByteBuffer() {
401      return cell.getQualifierByteBuffer();
402    }
403
404    @Override
405    public int getQualifierPosition() {
406      return cell.getQualifierPosition();
407    }
408
409    @Override
410    public ByteBuffer getValueByteBuffer() {
411      if (lenAsVal) {
412        return ByteBuffer.wrap(Bytes.toBytes(cell.getValueLength()));
413      } else {
414        return HConstants.EMPTY_BYTE_BUFFER;
415      }
416    }
417
418    @Override
419    public int getValuePosition() {
420      return 0;
421    }
422
423    @Override
424    public ByteBuffer getTagsByteBuffer() {
425      return HConstants.EMPTY_BYTE_BUFFER;
426    }
427
428    @Override
429    public int getTagsPosition() {
430      return 0;
431    }
432
433    @Override
434    public Iterator<Tag> getTags() {
435      return Collections.emptyIterator();
436    }
437
438    @Override
439    public Optional<Tag> getTag(byte type) {
440      return Optional.empty();
441    }
442
443    @Override
444    public long heapSize() {
445      return ClassSize.align(FIXED_OVERHEAD + cell.heapSize());
446    }
447  }
448
449}