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