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