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;
020
021import java.io.IOException;
022import java.nio.ByteBuffer;
023import java.util.Collections;
024import java.util.Iterator;
025import java.util.Optional;
026import org.apache.hadoop.hbase.util.ByteBufferUtils;
027import org.apache.hadoop.hbase.util.Bytes;
028import org.apache.hadoop.hbase.util.ClassSize;
029import org.apache.yetus.audience.InterfaceAudience;
030
031/**
032 * This is a key only Cell implementation which is identical to {@link KeyValue.KeyOnlyKeyValue}
033 * with respect to key serialization but have its data in the form of Byte buffer
034 * (onheap and offheap).
035 */
036@InterfaceAudience.Private
037public class ByteBufferKeyOnlyKeyValue extends ByteBufferExtendedCell {
038  public static final int FIXED_OVERHEAD = ClassSize.OBJECT + ClassSize.REFERENCE
039      + (2 * Bytes.SIZEOF_INT) + Bytes.SIZEOF_SHORT;
040  private ByteBuffer buf;
041  private int offset = 0; // offset into buffer where key starts at
042  private int length = 0; // length of this.
043  private short rowLen;
044
045  /**
046   * Used in cases where we want to avoid lot of garbage by allocating new objects with different
047   * keys. Use the emtpy construtor and set the keys using {@link #setKey(ByteBuffer, int, int)}
048   */
049  public ByteBufferKeyOnlyKeyValue() {
050  }
051
052  public ByteBufferKeyOnlyKeyValue(ByteBuffer buf, int offset, int length) {
053    setKey(buf, offset, length);
054  }
055
056  /**
057   * A setter that helps to avoid object creation every time and whenever
058   * there is a need to create new OffheapKeyOnlyKeyValue.
059   * @param key
060   * @param offset
061   * @param length
062   */
063  public void setKey(ByteBuffer key, int offset, int length) {
064    this.buf = key;
065    this.offset = offset;
066    this.length = length;
067    this.rowLen = ByteBufferUtils.toShort(this.buf, this.offset);
068  }
069
070  @Override
071  public byte[] getRowArray() {
072    if (this.buf.hasArray()) {
073      return this.buf.array();
074    }
075    return CellUtil.cloneRow(this);
076  }
077
078  @Override
079  public int getRowOffset() {
080    if (this.buf.hasArray()) {
081      return getRowPosition() + this.buf.arrayOffset();
082    }
083    return 0;
084  }
085
086  @Override
087  public short getRowLength() {
088    return this.rowLen;
089  }
090
091  @Override
092  public byte[] getFamilyArray() {
093    if (this.buf.hasArray()) {
094      return this.buf.array();
095    }
096    return CellUtil.cloneFamily(this);
097  }
098
099  @Override
100  public int getFamilyOffset() {
101    if (this.buf.hasArray()) {
102      return getFamilyPosition() + this.buf.arrayOffset();
103    }
104    return 0;
105  }
106
107  @Override
108  public byte getFamilyLength() {
109    return getFamilyLength(getFamilyLengthPosition());
110  }
111
112  private byte getFamilyLength(int famLenPos) {
113    return ByteBufferUtils.toByte(this.buf, famLenPos);
114  }
115
116  @Override
117  public byte[] getQualifierArray() {
118    if (this.buf.hasArray()) {
119      return this.buf.array();
120    }
121    return CellUtil.cloneQualifier(this);
122  }
123
124  @Override
125  public int getQualifierOffset() {
126    if (this.buf.hasArray()) {
127      return getQualifierPosition() + this.buf.arrayOffset();
128    }
129    return 0;
130  }
131
132  @Override
133  public int getQualifierLength() {
134    return getQualifierLength(getRowLength(), getFamilyLength());
135  }
136
137  private int getQualifierLength(int rlength, int flength) {
138    return this.length - (int) KeyValue.getKeyDataStructureSize(rlength, flength, 0);
139  }
140
141  @Override
142  public long getTimestamp() {
143    return ByteBufferUtils.toLong(this.buf, getTimestampOffset());
144  }
145
146  private int getTimestampOffset() {
147    return this.offset + this.length - KeyValue.TIMESTAMP_TYPE_SIZE;
148  }
149
150  @Override
151  public byte getTypeByte() {
152    return ByteBufferUtils.toByte(this.buf, this.offset + this.length - 1);
153  }
154
155  @Override
156  public void setSequenceId(long seqId) throws IOException {
157    throw new IllegalArgumentException("This is a key only Cell");
158  }
159
160  @Override
161  public void setTimestamp(long ts) throws IOException {
162    throw new IllegalArgumentException("This is a key only Cell");
163  }
164
165  @Override
166  public void setTimestamp(byte[] ts) throws IOException {
167    throw new IllegalArgumentException("This is a key only Cell");
168  }
169
170  @Override
171  public long getSequenceId() {
172    return 0;
173  }
174
175  @Override
176  public byte[] getValueArray() {
177    throw new IllegalArgumentException("This is a key only Cell");
178  }
179
180  @Override
181  public int getValueOffset() {
182    return 0;
183  }
184
185  @Override
186  public int getValueLength() {
187    return 0;
188  }
189
190  @Override
191  public byte[] getTagsArray() {
192    throw new IllegalArgumentException("This is a key only Cell");
193  }
194
195  @Override
196  public int getTagsOffset() {
197    return 0;
198  }
199
200  @Override
201  public int getTagsLength() {
202    return 0;
203  }
204
205  @Override
206  public ByteBuffer getRowByteBuffer() {
207    return this.buf;
208  }
209
210  @Override
211  public int getRowPosition() {
212    return this.offset + Bytes.SIZEOF_SHORT;
213  }
214
215  @Override
216  public ByteBuffer getFamilyByteBuffer() {
217    return this.buf;
218  }
219
220  @Override
221  public int getFamilyPosition() {
222    return getFamilyLengthPosition() + Bytes.SIZEOF_BYTE;
223  }
224
225  // The position in BB where the family length is added.
226  private int getFamilyLengthPosition() {
227    return this.offset + Bytes.SIZEOF_SHORT + getRowLength();
228  }
229
230  @Override
231  public ByteBuffer getQualifierByteBuffer() {
232    return this.buf;
233  }
234
235  @Override
236  public int getQualifierPosition() {
237    int famLenPos = getFamilyLengthPosition();
238    return famLenPos + Bytes.SIZEOF_BYTE + getFamilyLength(famLenPos);
239  }
240
241  @Override
242  public ByteBuffer getValueByteBuffer() {
243    throw new IllegalArgumentException("This is a key only Cell");
244  }
245
246  @Override
247  public int getValuePosition() {
248    return 0;
249  }
250
251  @Override
252  public ByteBuffer getTagsByteBuffer() {
253    throw new IllegalArgumentException("This is a key only Cell");
254  }
255
256  @Override
257  public int getTagsPosition() {
258    return 0;
259  }
260
261  @Override
262  public String toString() {
263    return CellUtil.toString(this, false);
264  }
265
266  @Override
267  public Iterator<Tag> getTags() {
268    return Collections.emptyIterator();
269  }
270
271  @Override
272  public Optional<Tag> getTag(byte type) {
273    return Optional.empty();
274  }
275
276  @Override
277  public long heapSize() {
278    if (this.buf.hasArray()) {
279      return ClassSize.align(FIXED_OVERHEAD + length);
280    }
281    return ClassSize.align(FIXED_OVERHEAD);
282  }
283}