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
;
26 import org
.apache
.hadoop
.hbase
.io
.ByteBuffAllocator
.Recycler
;
27 import org
.apache
.hadoop
.hbase
.unsafe
.HBasePlatformDependent
;
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
.yetus
.audience
.InterfaceAudience
;
34 * An implementation of ByteBuff where a single BB backs the BBI. This just acts as a wrapper over a
35 * normal BB - offheap or onheap
37 @InterfaceAudience.Private
38 public class SingleByteBuff
extends ByteBuff
{
40 private static final boolean UNSAFE_AVAIL
= HBasePlatformDependent
.isUnsafeAvailable();
41 private static final boolean UNSAFE_UNALIGNED
= HBasePlatformDependent
.unaligned();
44 private final ByteBuffer buf
;
46 // To access primitive values from underlying ByteBuffer using Unsafe
47 private long unsafeOffset
;
48 private Object unsafeRef
= null;
50 public SingleByteBuff(ByteBuffer buf
) {
54 public SingleByteBuff(Recycler recycler
, ByteBuffer buf
) {
55 this(new RefCnt(recycler
), buf
);
58 SingleByteBuff(RefCnt refCnt
, ByteBuffer buf
) {
62 this.unsafeOffset
= UnsafeAccess
.BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset();
63 this.unsafeRef
= buf
.array();
65 this.unsafeOffset
= UnsafeAccess
.directBufferAddress(buf
);
70 public int position() {
72 return this.buf
.position();
76 public SingleByteBuff
position(int position
) {
78 this.buf
.position(position
);
83 public SingleByteBuff
skip(int len
) {
85 this.buf
.position(this.buf
.position() + len
);
90 public SingleByteBuff
moveBack(int len
) {
92 this.buf
.position(this.buf
.position() - len
);
97 public int capacity() {
99 return this.buf
.capacity();
105 return this.buf
.limit();
109 public SingleByteBuff
limit(int limit
) {
111 this.buf
.limit(limit
);
116 public SingleByteBuff
rewind() {
123 public SingleByteBuff
mark() {
130 public ByteBuffer
asSubByteBuffer(int length
) {
132 // Just return the single BB that is available
137 public void asSubByteBuffer(int offset
, int length
, ObjectIntPair
<ByteBuffer
> pair
) {
139 // Just return the single BB that is available
140 pair
.setFirst(this.buf
);
141 pair
.setSecond(offset
);
145 public int remaining() {
147 return this.buf
.remaining();
151 public boolean hasRemaining() {
153 return buf
.hasRemaining();
157 public SingleByteBuff
reset() {
164 public SingleByteBuff
slice() {
166 return new SingleByteBuff(this.refCnt
, this.buf
.slice());
170 public SingleByteBuff
duplicate() {
172 return new SingleByteBuff(this.refCnt
, this.buf
.duplicate());
182 public byte get(int index
) {
185 return UnsafeAccess
.toByte(this.unsafeRef
, this.unsafeOffset
+ index
);
187 return this.buf
.get(index
);
191 public byte getByteAfterPosition(int offset
) {
193 return get(this.buf
.position() + offset
);
197 public SingleByteBuff
put(byte b
) {
204 public SingleByteBuff
put(int index
, byte b
) {
211 public void get(byte[] dst
, int offset
, int length
) {
213 ByteBufferUtils
.copyFromBufferToArray(dst
, buf
, buf
.position(), offset
, length
);
214 buf
.position(buf
.position() + length
);
218 public void get(int sourceOffset
, byte[] dst
, int offset
, int length
) {
220 ByteBufferUtils
.copyFromBufferToArray(dst
, buf
, sourceOffset
, offset
, length
);
224 public void get(byte[] dst
) {
225 get(dst
, 0, dst
.length
);
229 public SingleByteBuff
put(int offset
, ByteBuff src
, int srcOffset
, int length
) {
231 if (src
instanceof SingleByteBuff
) {
232 ByteBufferUtils
.copyFromBufferToBuffer(((SingleByteBuff
) src
).buf
, this.buf
, srcOffset
,
235 // TODO we can do some optimization here? Call to asSubByteBuffer might
237 ObjectIntPair
<ByteBuffer
> pair
= new ObjectIntPair
<>();
238 src
.asSubByteBuffer(srcOffset
, length
, pair
);
239 if (pair
.getFirst() != null) {
240 ByteBufferUtils
.copyFromBufferToBuffer(pair
.getFirst(), this.buf
, pair
.getSecond(), offset
,
248 public SingleByteBuff
put(byte[] src
, int offset
, int length
) {
250 ByteBufferUtils
.copyFromArrayToBuffer(this.buf
, src
, offset
, length
);
255 public SingleByteBuff
put(byte[] src
) {
257 return put(src
, 0, src
.length
);
261 public boolean hasArray() {
263 return this.buf
.hasArray();
267 public byte[] array() {
269 return this.buf
.array();
273 public int arrayOffset() {
275 return this.buf
.arrayOffset();
279 public short getShort() {
281 return this.buf
.getShort();
285 public short getShort(int index
) {
287 if (UNSAFE_UNALIGNED
) {
288 return UnsafeAccess
.toShort(unsafeRef
, unsafeOffset
+ index
);
290 return this.buf
.getShort(index
);
294 public short getShortAfterPosition(int offset
) {
296 return getShort(this.buf
.position() + offset
);
300 public int getInt() {
302 return this.buf
.getInt();
306 public SingleByteBuff
putInt(int value
) {
308 ByteBufferUtils
.putInt(this.buf
, value
);
313 public int getInt(int index
) {
315 if (UNSAFE_UNALIGNED
) {
316 return UnsafeAccess
.toInt(unsafeRef
, unsafeOffset
+ index
);
318 return this.buf
.getInt(index
);
322 public int getIntAfterPosition(int offset
) {
324 return getInt(this.buf
.position() + offset
);
328 public long getLong() {
330 return this.buf
.getLong();
334 public SingleByteBuff
putLong(long value
) {
336 ByteBufferUtils
.putLong(this.buf
, value
);
341 public long getLong(int index
) {
343 if (UNSAFE_UNALIGNED
) {
344 return UnsafeAccess
.toLong(unsafeRef
, unsafeOffset
+ index
);
346 return this.buf
.getLong(index
);
350 public long getLongAfterPosition(int offset
) {
352 return getLong(this.buf
.position() + offset
);
356 public byte[] toBytes(int offset
, int length
) {
358 byte[] output
= new byte[length
];
359 ByteBufferUtils
.copyFromBufferToArray(output
, buf
, offset
, 0, length
);
364 public void get(ByteBuffer out
, int sourceOffset
, int length
) {
366 ByteBufferUtils
.copyFromBufferToBuffer(buf
, out
, sourceOffset
, length
);
370 public int read(ReadableByteChannel channel
) throws IOException
{
372 return read(channel
, buf
, 0, CHANNEL_READER
);
376 public int read(FileChannel channel
, long offset
) throws IOException
{
378 return read(channel
, buf
, offset
, FILE_READER
);
382 public int write(FileChannel channel
, long offset
) throws IOException
{
385 while(buf
.hasRemaining()) {
386 int len
= channel
.write(buf
, offset
);
394 public ByteBuffer
[] nioByteBuffers() {
396 return new ByteBuffer
[] { this.buf
};
400 public boolean equals(Object obj
) {
401 if (!(obj
instanceof SingleByteBuff
)) {
404 return this.buf
.equals(((SingleByteBuff
) obj
).buf
);
408 public int hashCode() {
409 return this.buf
.hashCode();
413 public SingleByteBuff
retain() {