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.util; 019 020import java.nio.ByteBuffer; 021import org.apache.hadoop.hbase.ByteBufferExtendedCell; 022import org.apache.hadoop.hbase.Cell; 023import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent; 024import org.apache.yetus.audience.InterfaceAudience; 025 026/** 027 * Utility methods for reading and writing little-endian integers from byte[] and ByteBuffer. Used 028 * by hashing components to perform fast, low-level LE conversions with optional Unsafe 029 * acceleration. 030 */ 031@InterfaceAudience.Private 032public final class LittleEndianBytes { 033 final static boolean UNSAFE_UNALIGNED = HBasePlatformDependent.unaligned(); 034 035 static abstract class Converter { 036 abstract int toInt(byte[] bytes, int offset); 037 038 abstract int toInt(ByteBuffer buffer, int offset); 039 040 abstract int putInt(byte[] bytes, int offset, int val); 041 } 042 043 static class ConverterHolder { 044 static final String UNSAFE_CONVERTER_NAME = 045 ConverterHolder.class.getName() + "$UnsafeConverter"; 046 static final Converter BEST_CONVERTER = getBestConverter(); 047 048 static Converter getBestConverter() { 049 try { 050 Class<? extends Converter> theClass = 051 Class.forName(UNSAFE_CONVERTER_NAME).asSubclass(Converter.class); 052 return theClass.getConstructor().newInstance(); 053 } catch (Throwable t) { 054 return PureJavaConverter.INSTANCE; 055 } 056 } 057 058 static final class PureJavaConverter extends Converter { 059 static final PureJavaConverter INSTANCE = new PureJavaConverter(); 060 061 private PureJavaConverter() { 062 } 063 064 @Override 065 int toInt(byte[] bytes, int offset) { 066 return (bytes[offset] & 0xFF) | ((bytes[offset + 1] & 0xFF) << 8) 067 | ((bytes[offset + 2] & 0xFF) << 16) | ((bytes[offset + 3] & 0xFF) << 24); 068 } 069 070 @Override 071 int toInt(ByteBuffer buffer, int offset) { 072 return (buffer.get(offset) & 0xFF) | ((buffer.get(offset + 1) & 0xFF) << 8) 073 | ((buffer.get(offset + 2) & 0xFF) << 16) | ((buffer.get(offset + 3) & 0xFF) << 24); 074 } 075 076 @Override 077 int putInt(byte[] bytes, int offset, int val) { 078 bytes[offset] = (byte) val; 079 bytes[offset + 1] = (byte) (val >>> 8); 080 bytes[offset + 2] = (byte) (val >>> 16); 081 bytes[offset + 3] = (byte) (val >>> 24); 082 return offset + Bytes.SIZEOF_INT; 083 } 084 } 085 086 static final class UnsafeConverter extends Converter { 087 static final UnsafeConverter INSTANCE = new UnsafeConverter(); 088 089 public UnsafeConverter() { 090 } 091 092 static { 093 if (!UNSAFE_UNALIGNED) { 094 throw new Error(); 095 } 096 } 097 098 @Override 099 int toInt(byte[] bytes, int offset) { 100 return UnsafeAccess.toIntLE(bytes, offset); 101 } 102 103 @Override 104 int toInt(ByteBuffer buffer, int offset) { 105 return UnsafeAccess.toIntLE(buffer, offset); 106 } 107 108 @Override 109 int putInt(byte[] bytes, int offset, int val) { 110 return UnsafeAccess.putIntLE(bytes, offset, val); 111 } 112 } 113 } 114 115 /* 116 * Writes an int in little-endian order. Caller must ensure bounds; no checks are performed. 117 */ 118 public static void putInt(byte[] bytes, int offset, int val) { 119 assert offset >= 0 && bytes.length - offset >= Bytes.SIZEOF_INT; 120 ConverterHolder.BEST_CONVERTER.putInt(bytes, offset, val); 121 } 122 123 /* 124 * Reads an int in little-endian order. Caller must ensure bounds; no checks are performed. 125 */ 126 public static int toInt(byte[] bytes, int offset) { 127 assert offset >= 0 && bytes.length - offset >= Bytes.SIZEOF_INT; 128 return ConverterHolder.BEST_CONVERTER.toInt(bytes, offset); 129 } 130 131 /* 132 * Reads an int in little-endian order from ByteBuffer. Caller must ensure bounds; no checks are 133 * performed. 134 */ 135 public static int toInt(ByteBuffer buffer, int offset) { 136 assert offset >= 0 && buffer.capacity() - offset >= Bytes.SIZEOF_INT; 137 return ConverterHolder.BEST_CONVERTER.toInt(buffer, offset); 138 } 139 140 /* 141 * Reads an int in little-endian order from the row portion of the Cell, at the given offset. 142 */ 143 public static int getRowAsInt(Cell cell, int offset) { 144 if (cell instanceof ByteBufferExtendedCell) { 145 ByteBufferExtendedCell bbCell = (ByteBufferExtendedCell) cell; 146 return toInt(bbCell.getRowByteBuffer(), bbCell.getRowPosition() + offset); 147 } 148 return toInt(cell.getRowArray(), cell.getRowOffset() + offset); 149 } 150 151 /* 152 * Reads an int in little-endian order from the qualifier portion of the Cell, at the given 153 * offset. 154 */ 155 public static int getQualifierAsInt(Cell cell, int offset) { 156 if (cell instanceof ByteBufferExtendedCell) { 157 ByteBufferExtendedCell bbCell = (ByteBufferExtendedCell) cell; 158 return toInt(bbCell.getQualifierByteBuffer(), bbCell.getQualifierPosition() + offset); 159 } 160 return toInt(cell.getQualifierArray(), cell.getQualifierOffset() + offset); 161 } 162 163 private LittleEndianBytes() { 164 } 165}