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