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