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.nio;
019
020import static org.apache.hadoop.hbase.io.ByteBuffAllocator.NONE;
021
022import java.io.IOException;
023import java.nio.ByteBuffer;
024import java.nio.channels.ReadableByteChannel;
025
026import org.apache.hadoop.hbase.io.ByteBuffAllocator.Recycler;
027import org.apache.hadoop.hbase.util.ByteBufferUtils;
028import org.apache.hadoop.hbase.util.ObjectIntPair;
029import org.apache.hadoop.hbase.util.UnsafeAccess;
030import org.apache.hadoop.hbase.util.UnsafeAvailChecker;
031import org.apache.yetus.audience.InterfaceAudience;
032
033import sun.nio.ch.DirectBuffer;
034
035/**
036 * An implementation of ByteBuff where a single BB backs the BBI. This just acts as a wrapper over a
037 * normal BB - offheap or onheap
038 */
039@InterfaceAudience.Private
040public class SingleByteBuff extends ByteBuff {
041
042  private static final boolean UNSAFE_AVAIL = UnsafeAvailChecker.isAvailable();
043  private static final boolean UNSAFE_UNALIGNED = UnsafeAvailChecker.unaligned();
044
045  // Underlying BB
046  private final ByteBuffer buf;
047
048  // To access primitive values from underlying ByteBuffer using Unsafe
049  private long unsafeOffset;
050  private Object unsafeRef = null;
051
052  public SingleByteBuff(ByteBuffer buf) {
053    this(NONE, buf);
054  }
055
056  public SingleByteBuff(Recycler recycler, ByteBuffer buf) {
057    this(new RefCnt(recycler), buf);
058  }
059
060  SingleByteBuff(RefCnt refCnt, ByteBuffer buf) {
061    this.refCnt = refCnt;
062    this.buf = buf;
063    if (buf.hasArray()) {
064      this.unsafeOffset = UnsafeAccess.BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset();
065      this.unsafeRef = buf.array();
066    } else {
067      this.unsafeOffset = ((DirectBuffer) buf).address();
068    }
069  }
070
071  @Override
072  public int position() {
073    checkRefCount();
074    return this.buf.position();
075  }
076
077  @Override
078  public SingleByteBuff position(int position) {
079    checkRefCount();
080    this.buf.position(position);
081    return this;
082  }
083
084  @Override
085  public SingleByteBuff skip(int len) {
086    checkRefCount();
087    this.buf.position(this.buf.position() + len);
088    return this;
089  }
090
091  @Override
092  public SingleByteBuff moveBack(int len) {
093    checkRefCount();
094    this.buf.position(this.buf.position() - len);
095    return this;
096  }
097
098  @Override
099  public int capacity() {
100    checkRefCount();
101    return this.buf.capacity();
102  }
103
104  @Override
105  public int limit() {
106    checkRefCount();
107    return this.buf.limit();
108  }
109
110  @Override
111  public SingleByteBuff limit(int limit) {
112    checkRefCount();
113    this.buf.limit(limit);
114    return this;
115  }
116
117  @Override
118  public SingleByteBuff rewind() {
119    checkRefCount();
120    this.buf.rewind();
121    return this;
122  }
123
124  @Override
125  public SingleByteBuff mark() {
126    checkRefCount();
127    this.buf.mark();
128    return this;
129  }
130
131  @Override
132  public ByteBuffer asSubByteBuffer(int length) {
133    checkRefCount();
134    // Just return the single BB that is available
135    return this.buf;
136  }
137
138  @Override
139  public void asSubByteBuffer(int offset, int length, ObjectIntPair<ByteBuffer> pair) {
140    checkRefCount();
141    // Just return the single BB that is available
142    pair.setFirst(this.buf);
143    pair.setSecond(offset);
144  }
145
146  @Override
147  public int remaining() {
148    checkRefCount();
149    return this.buf.remaining();
150  }
151
152  @Override
153  public boolean hasRemaining() {
154    checkRefCount();
155    return buf.hasRemaining();
156  }
157
158  @Override
159  public SingleByteBuff reset() {
160    checkRefCount();
161    this.buf.reset();
162    return this;
163  }
164
165  @Override
166  public SingleByteBuff slice() {
167    checkRefCount();
168    return new SingleByteBuff(this.refCnt, this.buf.slice());
169  }
170
171  @Override
172  public SingleByteBuff duplicate() {
173    checkRefCount();
174    return new SingleByteBuff(this.refCnt, this.buf.duplicate());
175  }
176
177  @Override
178  public byte get() {
179    checkRefCount();
180    return buf.get();
181  }
182
183  @Override
184  public byte get(int index) {
185    checkRefCount();
186    if (UNSAFE_AVAIL) {
187      return UnsafeAccess.toByte(this.unsafeRef, this.unsafeOffset + index);
188    }
189    return this.buf.get(index);
190  }
191
192  @Override
193  public byte getByteAfterPosition(int offset) {
194    checkRefCount();
195    return get(this.buf.position() + offset);
196  }
197
198  @Override
199  public SingleByteBuff put(byte b) {
200    checkRefCount();
201    this.buf.put(b);
202    return this;
203  }
204
205  @Override
206  public SingleByteBuff put(int index, byte b) {
207    checkRefCount();
208    buf.put(index, b);
209    return this;
210  }
211
212  @Override
213  public void get(byte[] dst, int offset, int length) {
214    checkRefCount();
215    ByteBufferUtils.copyFromBufferToArray(dst, buf, buf.position(), offset, length);
216    buf.position(buf.position() + length);
217  }
218
219  @Override
220  public void get(int sourceOffset, byte[] dst, int offset, int length) {
221    checkRefCount();
222    ByteBufferUtils.copyFromBufferToArray(dst, buf, sourceOffset, offset, length);
223  }
224
225  @Override
226  public void get(byte[] dst) {
227    get(dst, 0, dst.length);
228  }
229
230  @Override
231  public SingleByteBuff put(int offset, ByteBuff src, int srcOffset, int length) {
232    checkRefCount();
233    if (src instanceof SingleByteBuff) {
234      ByteBufferUtils.copyFromBufferToBuffer(((SingleByteBuff) src).buf, this.buf, srcOffset,
235        offset, length);
236    } else {
237      // TODO we can do some optimization here? Call to asSubByteBuffer might
238      // create a copy.
239      ObjectIntPair<ByteBuffer> pair = new ObjectIntPair<>();
240      src.asSubByteBuffer(srcOffset, length, pair);
241      if (pair.getFirst() != null) {
242        ByteBufferUtils.copyFromBufferToBuffer(pair.getFirst(), this.buf, pair.getSecond(), offset,
243          length);
244      }
245    }
246    return this;
247  }
248
249  @Override
250  public SingleByteBuff put(byte[] src, int offset, int length) {
251    checkRefCount();
252    ByteBufferUtils.copyFromArrayToBuffer(this.buf, src, offset, length);
253    return this;
254  }
255
256  @Override
257  public SingleByteBuff put(byte[] src) {
258    checkRefCount();
259    return put(src, 0, src.length);
260  }
261
262  @Override
263  public boolean hasArray() {
264    checkRefCount();
265    return this.buf.hasArray();
266  }
267
268  @Override
269  public byte[] array() {
270    checkRefCount();
271    return this.buf.array();
272  }
273
274  @Override
275  public int arrayOffset() {
276    checkRefCount();
277    return this.buf.arrayOffset();
278  }
279
280  @Override
281  public short getShort() {
282    checkRefCount();
283    return this.buf.getShort();
284  }
285
286  @Override
287  public short getShort(int index) {
288    checkRefCount();
289    if (UNSAFE_UNALIGNED) {
290      return UnsafeAccess.toShort(unsafeRef, unsafeOffset + index);
291    }
292    return this.buf.getShort(index);
293  }
294
295  @Override
296  public short getShortAfterPosition(int offset) {
297    checkRefCount();
298    return getShort(this.buf.position() + offset);
299  }
300
301  @Override
302  public int getInt() {
303    checkRefCount();
304    return this.buf.getInt();
305  }
306
307  @Override
308  public SingleByteBuff putInt(int value) {
309    checkRefCount();
310    ByteBufferUtils.putInt(this.buf, value);
311    return this;
312  }
313
314  @Override
315  public int getInt(int index) {
316    checkRefCount();
317    if (UNSAFE_UNALIGNED) {
318      return UnsafeAccess.toInt(unsafeRef, unsafeOffset + index);
319    }
320    return this.buf.getInt(index);
321  }
322
323  @Override
324  public int getIntAfterPosition(int offset) {
325    checkRefCount();
326    return getInt(this.buf.position() + offset);
327  }
328
329  @Override
330  public long getLong() {
331    checkRefCount();
332    return this.buf.getLong();
333  }
334
335  @Override
336  public SingleByteBuff putLong(long value) {
337    checkRefCount();
338    ByteBufferUtils.putLong(this.buf, value);
339    return this;
340  }
341
342  @Override
343  public long getLong(int index) {
344    checkRefCount();
345    if (UNSAFE_UNALIGNED) {
346      return UnsafeAccess.toLong(unsafeRef, unsafeOffset + index);
347    }
348    return this.buf.getLong(index);
349  }
350
351  @Override
352  public long getLongAfterPosition(int offset) {
353    checkRefCount();
354    return getLong(this.buf.position() + offset);
355  }
356
357  @Override
358  public byte[] toBytes(int offset, int length) {
359    checkRefCount();
360    byte[] output = new byte[length];
361    ByteBufferUtils.copyFromBufferToArray(output, buf, offset, 0, length);
362    return output;
363  }
364
365  @Override
366  public void get(ByteBuffer out, int sourceOffset, int length) {
367    checkRefCount();
368    ByteBufferUtils.copyFromBufferToBuffer(buf, out, sourceOffset, length);
369  }
370
371  @Override
372  public int read(ReadableByteChannel channel) throws IOException {
373    checkRefCount();
374    return channelRead(channel, buf);
375  }
376
377  @Override
378  public ByteBuffer[] nioByteBuffers() {
379    checkRefCount();
380    return new ByteBuffer[] { this.buf };
381  }
382
383  @Override
384  public boolean equals(Object obj) {
385    if (!(obj instanceof SingleByteBuff)) {
386      return false;
387    }
388    return this.buf.equals(((SingleByteBuff) obj).buf);
389  }
390
391  @Override
392  public int hashCode() {
393    return this.buf.hashCode();
394  }
395
396  @Override
397  public SingleByteBuff retain() {
398    refCnt.retain();
399    return this;
400  }
401}