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