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