org.apache.hadoop.hbase.nio.SingleByteBuff Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hbase-common Show documentation
Show all versions of hbase-common Show documentation
Common functionality for HBase
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.nio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import org.apache.hadoop.hbase.util.ByteBufferUtils;
import org.apache.hadoop.hbase.util.ObjectIntPair;
import org.apache.hadoop.hbase.util.UnsafeAccess;
import org.apache.hadoop.hbase.util.UnsafeAvailChecker;
import org.apache.yetus.audience.InterfaceAudience;
import sun.nio.ch.DirectBuffer;
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
/**
* An implementation of ByteBuff where a single BB backs the BBI. This just acts
* as a wrapper over a normal BB - offheap or onheap
*/
@InterfaceAudience.Private
public class SingleByteBuff extends ByteBuff {
private static final boolean UNSAFE_AVAIL = UnsafeAvailChecker.isAvailable();
private static final boolean UNSAFE_UNALIGNED = UnsafeAvailChecker.unaligned();
// Underlying BB
private final ByteBuffer buf;
// To access primitive values from underlying ByteBuffer using Unsafe
private long unsafeOffset;
private Object unsafeRef = null;
public SingleByteBuff(ByteBuffer buf) {
this.buf = buf;
if (buf.hasArray()) {
this.unsafeOffset = UnsafeAccess.BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset();
this.unsafeRef = buf.array();
} else {
this.unsafeOffset = ((DirectBuffer) buf).address();
}
}
@Override
public int position() {
return this.buf.position();
}
@Override
public SingleByteBuff position(int position) {
this.buf.position(position);
return this;
}
@Override
public SingleByteBuff skip(int len) {
this.buf.position(this.buf.position() + len);
return this;
}
@Override
public SingleByteBuff moveBack(int len) {
this.buf.position(this.buf.position() - len);
return this;
}
@Override
public int capacity() {
return this.buf.capacity();
}
@Override
public int limit() {
return this.buf.limit();
}
@Override
public SingleByteBuff limit(int limit) {
this.buf.limit(limit);
return this;
}
@Override
public SingleByteBuff rewind() {
this.buf.rewind();
return this;
}
@Override
public SingleByteBuff mark() {
this.buf.mark();
return this;
}
@Override
public ByteBuffer asSubByteBuffer(int length) {
// Just return the single BB that is available
return this.buf;
}
@Override
public void asSubByteBuffer(int offset, int length, ObjectIntPair pair) {
// Just return the single BB that is available
pair.setFirst(this.buf);
pair.setSecond(offset);
}
@Override
public int remaining() {
return this.buf.remaining();
}
@Override
public boolean hasRemaining() {
return buf.hasRemaining();
}
@Override
public SingleByteBuff reset() {
this.buf.reset();
return this;
}
@Override
public SingleByteBuff slice() {
return new SingleByteBuff(this.buf.slice());
}
@Override
public SingleByteBuff duplicate() {
return new SingleByteBuff(this.buf.duplicate());
}
@Override
public byte get() {
return buf.get();
}
@Override
public byte get(int index) {
if (UNSAFE_AVAIL) {
return UnsafeAccess.toByte(this.unsafeRef, this.unsafeOffset + index);
}
return this.buf.get(index);
}
@Override
public byte getByteAfterPosition(int offset) {
return get(this.buf.position() + offset);
}
@Override
public SingleByteBuff put(byte b) {
this.buf.put(b);
return this;
}
@Override
public SingleByteBuff put(int index, byte b) {
buf.put(index, b);
return this;
}
@Override
public void get(byte[] dst, int offset, int length) {
ByteBufferUtils.copyFromBufferToArray(dst, buf, buf.position(), offset, length);
buf.position(buf.position() + length);
}
@Override
public void get(int sourceOffset, byte[] dst, int offset, int length) {
ByteBufferUtils.copyFromBufferToArray(dst, buf, sourceOffset, offset, length);
}
@Override
public void get(byte[] dst) {
get(dst, 0, dst.length);
}
@Override
public SingleByteBuff put(int offset, ByteBuff src, int srcOffset, int length) {
if (src instanceof SingleByteBuff) {
ByteBufferUtils.copyFromBufferToBuffer(((SingleByteBuff) src).buf, this.buf, srcOffset,
offset, length);
} else {
// TODO we can do some optimization here? Call to asSubByteBuffer might
// create a copy.
ObjectIntPair pair = new ObjectIntPair<>();
src.asSubByteBuffer(srcOffset, length, pair);
if (pair.getFirst() != null) {
ByteBufferUtils.copyFromBufferToBuffer(pair.getFirst(), this.buf, pair.getSecond(), offset,
length);
}
}
return this;
}
@Override
public SingleByteBuff put(byte[] src, int offset, int length) {
ByteBufferUtils.copyFromArrayToBuffer(this.buf, src, offset, length);
return this;
}
@Override
public SingleByteBuff put(byte[] src) {
return put(src, 0, src.length);
}
@Override
public boolean hasArray() {
return this.buf.hasArray();
}
@Override
public byte[] array() {
return this.buf.array();
}
@Override
public int arrayOffset() {
return this.buf.arrayOffset();
}
@Override
public short getShort() {
return this.buf.getShort();
}
@Override
public short getShort(int index) {
if (UNSAFE_UNALIGNED) {
return UnsafeAccess.toShort(unsafeRef, unsafeOffset + index);
}
return this.buf.getShort(index);
}
@Override
public short getShortAfterPosition(int offset) {
return getShort(this.buf.position() + offset);
}
@Override
public int getInt() {
return this.buf.getInt();
}
@Override
public SingleByteBuff putInt(int value) {
ByteBufferUtils.putInt(this.buf, value);
return this;
}
@Override
public int getInt(int index) {
if (UNSAFE_UNALIGNED) {
return UnsafeAccess.toInt(unsafeRef, unsafeOffset + index);
}
return this.buf.getInt(index);
}
@Override
public int getIntAfterPosition(int offset) {
return getInt(this.buf.position() + offset);
}
@Override
public long getLong() {
return this.buf.getLong();
}
@Override
public SingleByteBuff putLong(long value) {
ByteBufferUtils.putLong(this.buf, value);
return this;
}
@Override
public long getLong(int index) {
if (UNSAFE_UNALIGNED) {
return UnsafeAccess.toLong(unsafeRef, unsafeOffset + index);
}
return this.buf.getLong(index);
}
@Override
public long getLongAfterPosition(int offset) {
return getLong(this.buf.position() + offset);
}
@Override
public byte[] toBytes(int offset, int length) {
byte[] output = new byte[length];
ByteBufferUtils.copyFromBufferToArray(output, buf, offset, 0, length);
return output;
}
@Override
public void get(ByteBuffer out, int sourceOffset, int length) {
ByteBufferUtils.copyFromBufferToBuffer(buf, out, sourceOffset, length);
}
@Override
public int read(ReadableByteChannel channel) throws IOException {
return channelRead(channel, buf);
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof SingleByteBuff)) return false;
return this.buf.equals(((SingleByteBuff)obj).buf);
}
@Override
public int hashCode() {
return this.buf.hashCode();
}
/**
* @return the ByteBuffer which this wraps.
*/
@VisibleForTesting
public ByteBuffer getEnclosingByteBuffer() {
return this.buf;
}
}