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