2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.nio
;
20 import static org
.apache
.hadoop
.hbase
.io
.ByteBuffAllocator
.NONE
;
22 import java
.io
.IOException
;
23 import java
.nio
.ByteBuffer
;
24 import java
.nio
.channels
.FileChannel
;
25 import java
.nio
.channels
.ReadableByteChannel
;
27 import org
.apache
.hadoop
.hbase
.io
.ByteBuffAllocator
.Recycler
;
28 import org
.apache
.hadoop
.hbase
.util
.ByteBufferUtils
;
29 import org
.apache
.hadoop
.hbase
.util
.ObjectIntPair
;
30 import org
.apache
.hadoop
.hbase
.util
.UnsafeAccess
;
31 import org
.apache
.hadoop
.hbase
.util
.UnsafeAvailChecker
;
32 import org
.apache
.yetus
.audience
.InterfaceAudience
;
34 import sun
.nio
.ch
.DirectBuffer
;
37 * An implementation of ByteBuff where a single BB backs the BBI. This just acts as a wrapper over a
38 * normal BB - offheap or onheap
40 @InterfaceAudience.Private
41 public class SingleByteBuff
extends ByteBuff
{
43 private static final boolean UNSAFE_AVAIL
= UnsafeAvailChecker
.isAvailable();
44 private static final boolean UNSAFE_UNALIGNED
= UnsafeAvailChecker
.unaligned();
47 private final ByteBuffer buf
;
49 // To access primitive values from underlying ByteBuffer using Unsafe
50 private long unsafeOffset
;
51 private Object unsafeRef
= null;
53 public SingleByteBuff(ByteBuffer buf
) {
57 public SingleByteBuff(Recycler recycler
, ByteBuffer buf
) {
58 this(new RefCnt(recycler
), buf
);
61 SingleByteBuff(RefCnt refCnt
, ByteBuffer buf
) {
65 this.unsafeOffset
= UnsafeAccess
.BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset();
66 this.unsafeRef
= buf
.array();
68 this.unsafeOffset
= ((DirectBuffer
) buf
).address();
73 public int position() {
75 return this.buf
.position();
79 public SingleByteBuff
position(int position
) {
81 this.buf
.position(position
);
86 public SingleByteBuff
skip(int len
) {
88 this.buf
.position(this.buf
.position() + len
);
93 public SingleByteBuff
moveBack(int len
) {
95 this.buf
.position(this.buf
.position() - len
);
100 public int capacity() {
102 return this.buf
.capacity();
108 return this.buf
.limit();
112 public SingleByteBuff
limit(int limit
) {
114 this.buf
.limit(limit
);
119 public SingleByteBuff
rewind() {
126 public SingleByteBuff
mark() {
133 public ByteBuffer
asSubByteBuffer(int length
) {
135 // Just return the single BB that is available
140 public void asSubByteBuffer(int offset
, int length
, ObjectIntPair
<ByteBuffer
> pair
) {
142 // Just return the single BB that is available
143 pair
.setFirst(this.buf
);
144 pair
.setSecond(offset
);
148 public int remaining() {
150 return this.buf
.remaining();
154 public boolean hasRemaining() {
156 return buf
.hasRemaining();
160 public SingleByteBuff
reset() {
167 public SingleByteBuff
slice() {
169 return new SingleByteBuff(this.refCnt
, this.buf
.slice());
173 public SingleByteBuff
duplicate() {
175 return new SingleByteBuff(this.refCnt
, this.buf
.duplicate());
185 public byte get(int index
) {
188 return UnsafeAccess
.toByte(this.unsafeRef
, this.unsafeOffset
+ index
);
190 return this.buf
.get(index
);
194 public byte getByteAfterPosition(int offset
) {
196 return get(this.buf
.position() + offset
);
200 public SingleByteBuff
put(byte b
) {
207 public SingleByteBuff
put(int index
, byte b
) {
214 public void get(byte[] dst
, int offset
, int length
) {
216 ByteBufferUtils
.copyFromBufferToArray(dst
, buf
, buf
.position(), offset
, length
);
217 buf
.position(buf
.position() + length
);
221 public void get(int sourceOffset
, byte[] dst
, int offset
, int length
) {
223 ByteBufferUtils
.copyFromBufferToArray(dst
, buf
, sourceOffset
, offset
, length
);
227 public void get(byte[] dst
) {
228 get(dst
, 0, dst
.length
);
232 public SingleByteBuff
put(int offset
, ByteBuff src
, int srcOffset
, int length
) {
234 if (src
instanceof SingleByteBuff
) {
235 ByteBufferUtils
.copyFromBufferToBuffer(((SingleByteBuff
) src
).buf
, this.buf
, srcOffset
,
238 // TODO we can do some optimization here? Call to asSubByteBuffer might
240 ObjectIntPair
<ByteBuffer
> pair
= new ObjectIntPair
<>();
241 src
.asSubByteBuffer(srcOffset
, length
, pair
);
242 if (pair
.getFirst() != null) {
243 ByteBufferUtils
.copyFromBufferToBuffer(pair
.getFirst(), this.buf
, pair
.getSecond(), offset
,
251 public SingleByteBuff
put(byte[] src
, int offset
, int length
) {
253 ByteBufferUtils
.copyFromArrayToBuffer(this.buf
, src
, offset
, length
);
258 public SingleByteBuff
put(byte[] src
) {
260 return put(src
, 0, src
.length
);
264 public boolean hasArray() {
266 return this.buf
.hasArray();
270 public byte[] array() {
272 return this.buf
.array();
276 public int arrayOffset() {
278 return this.buf
.arrayOffset();
282 public short getShort() {
284 return this.buf
.getShort();
288 public short getShort(int index
) {
290 if (UNSAFE_UNALIGNED
) {
291 return UnsafeAccess
.toShort(unsafeRef
, unsafeOffset
+ index
);
293 return this.buf
.getShort(index
);
297 public short getShortAfterPosition(int offset
) {
299 return getShort(this.buf
.position() + offset
);
303 public int getInt() {
305 return this.buf
.getInt();
309 public SingleByteBuff
putInt(int value
) {
311 ByteBufferUtils
.putInt(this.buf
, value
);
316 public int getInt(int index
) {
318 if (UNSAFE_UNALIGNED
) {
319 return UnsafeAccess
.toInt(unsafeRef
, unsafeOffset
+ index
);
321 return this.buf
.getInt(index
);
325 public int getIntAfterPosition(int offset
) {
327 return getInt(this.buf
.position() + offset
);
331 public long getLong() {
333 return this.buf
.getLong();
337 public SingleByteBuff
putLong(long value
) {
339 ByteBufferUtils
.putLong(this.buf
, value
);
344 public long getLong(int index
) {
346 if (UNSAFE_UNALIGNED
) {
347 return UnsafeAccess
.toLong(unsafeRef
, unsafeOffset
+ index
);
349 return this.buf
.getLong(index
);
353 public long getLongAfterPosition(int offset
) {
355 return getLong(this.buf
.position() + offset
);
359 public byte[] toBytes(int offset
, int length
) {
361 byte[] output
= new byte[length
];
362 ByteBufferUtils
.copyFromBufferToArray(output
, buf
, offset
, 0, length
);
367 public void get(ByteBuffer out
, int sourceOffset
, int length
) {
369 ByteBufferUtils
.copyFromBufferToBuffer(buf
, out
, sourceOffset
, length
);
373 public int read(ReadableByteChannel channel
) throws IOException
{
375 return read(channel
, buf
, 0, CHANNEL_READER
);
379 public int read(FileChannel channel
, long offset
) throws IOException
{
381 return read(channel
, buf
, offset
, FILE_READER
);
385 public int write(FileChannel channel
, long offset
) throws IOException
{
388 while(buf
.hasRemaining()) {
389 int len
= channel
.write(buf
, offset
);
397 public ByteBuffer
[] nioByteBuffers() {
399 return new ByteBuffer
[] { this.buf
};
403 public boolean equals(Object obj
) {
404 if (!(obj
instanceof SingleByteBuff
)) {
407 return this.buf
.equals(((SingleByteBuff
) obj
).buf
);
411 public int hashCode() {
412 return this.buf
.hashCode();
416 public SingleByteBuff
retain() {