From c0f5bde577951fbf58745abd56526971d66901f2 Mon Sep 17 00:00:00 2001 From: Peter Levart Date: Sun, 28 Mar 2021 21:49:47 +0200 Subject: [PATCH] Allow building on JDK9+ by getting rid of DirectByteBuffer dependency Signed-off-by: Peter Levart --- pom.xml | 19 + .../common/columnar/TiBlockColumnVector.java | 146 ++--- .../datatypes/AutoGrowByteBuffer.java | 18 +- .../common/columnar/datatypes/CHType.java | 14 +- .../columnar/datatypes/CHTypeString.java | 29 +- .../java/org/tikv/common/util/MemoryUtil.java | 548 +----------------- 6 files changed, 132 insertions(+), 642 deletions(-) diff --git a/pom.xml b/pom.xml index 9bcc6461517..4e4cff5be70 100644 --- a/pom.xml +++ b/pom.xml @@ -519,4 +519,23 @@ + + + + jdk9plus + + + !1.8 + + + + javax.annotation + javax.annotation-api + 1.3.2 + provided + + + + + diff --git a/src/main/java/org/tikv/common/columnar/TiBlockColumnVector.java b/src/main/java/org/tikv/common/columnar/TiBlockColumnVector.java index beff8234f8f..0341447d5c8 100644 --- a/src/main/java/org/tikv/common/columnar/TiBlockColumnVector.java +++ b/src/main/java/org/tikv/common/columnar/TiBlockColumnVector.java @@ -15,12 +15,15 @@ package org.tikv.common.columnar; -import static org.tikv.common.util.MemoryUtil.EMPTY_BYTE_BUFFER_DIRECT; +import static org.tikv.common.util.MemoryUtil.EMPTY_BYTE_BUFFER; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.sql.Timestamp; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Objects; import org.joda.time.LocalDate; import org.tikv.common.columnar.datatypes.CHType; import org.tikv.common.types.AbstractDateTimeType; @@ -29,36 +32,34 @@ import org.tikv.common.util.MemoryUtil; public class TiBlockColumnVector extends TiColumnVector { - long offsetsAddr; - ByteBuffer offsets; - long nullMapAddr; - ByteBuffer nullMap; - long dataAddr; - ByteBuffer data; - private int fixedLength; + private final ByteBuffer offsets; + private final ByteBuffer nullMap; + private final ByteBuffer data; + private final int fixedLength; public TiBlockColumnVector(CHType type, ByteBuffer data, int numOfRows, int fixedLength) { super(type.toDataType(), numOfRows); - this.data = data; - this.dataAddr = MemoryUtil.getAddress(data); - fillEmptyNullMap(); - fillEmptyOffsets(); + this.data = Objects.requireNonNull(data); + this.nullMap = null; + this.offsets = null; this.fixedLength = fixedLength; } public TiBlockColumnVector(CHType type) { super(type.toDataType(), 0); + this.data = EMPTY_BYTE_BUFFER; + this.nullMap = null; + this.offsets = null; + this.fixedLength = -1; } public TiBlockColumnVector( CHType type, ByteBuffer nullMap, ByteBuffer data, int numOfRows, int fixedLength) { // chType -> data type super(type.toDataType(), numOfRows); - this.nullMap = nullMap; - this.nullMapAddr = MemoryUtil.getAddress(nullMap); - this.data = data; - this.dataAddr = MemoryUtil.getAddress(data); - fillEmptyOffsets(); + this.nullMap = Objects.requireNonNull(nullMap); + this.data = Objects.requireNonNull(data); + this.offsets = null; this.fixedLength = fixedLength; } @@ -67,25 +68,12 @@ public TiBlockColumnVector( CHType type, ByteBuffer nullMap, ByteBuffer offsets, ByteBuffer data, int numOfRows) { // chType -> data type super(type.toDataType(), numOfRows); - this.offsets = offsets; - this.offsetsAddr = MemoryUtil.getAddress(offsets); - this.nullMap = nullMap; - this.nullMapAddr = MemoryUtil.getAddress(nullMap); - this.data = data; - this.dataAddr = MemoryUtil.getAddress(data); + this.offsets = Objects.requireNonNull(offsets); + this.nullMap = nullMap; // may be null + this.data = Objects.requireNonNull(data); this.fixedLength = -1; } - private void fillEmptyNullMap() { - this.nullMap = EMPTY_BYTE_BUFFER_DIRECT; - this.nullMapAddr = MemoryUtil.getAddress(this.nullMap); - } - - private void fillEmptyOffsets() { - this.offsets = EMPTY_BYTE_BUFFER_DIRECT; - this.offsetsAddr = MemoryUtil.getAddress(this.offsets); - } - /** * Cleans up memory for this column vector. The column vector is not usable after this. * @@ -93,42 +81,37 @@ private void fillEmptyOffsets() { * in-memory and we don't expect any exception to happen during closing. */ @Override - public void close() { - if (dataAddr != 0) { - MemoryUtil.free(data); - } - - if (offsetsAddr != 0) { - MemoryUtil.free(offsets); - } - - if (nullMapAddr != 0) { - MemoryUtil.free(nullMap); - } - dataAddr = 0; - offsetsAddr = 0; - nullMapAddr = 0; - } + public void close() {} /** Returns true if this column vector contains any null values. */ @Override public boolean hasNull() { - return nullMap == null; + if (nullMap != null) { + byte[] array = nullMap.array(); + for (byte b : array) { + if (b != 0) return true; + } + } + return false; } /** Returns the number of nulls in this column vector. */ @Override public int numNulls() { - throw new UnsupportedOperationException("numNulls is not supported for TiBlockColumnVector"); + int n = 0; + if (nullMap != null) { + byte[] array = nullMap.array(); + for (byte b : array) { + if (b != 0) n++; + } + } + return n; } /** Returns whether the value at rowId is NULL. */ @Override public boolean isNullAt(int rowId) { - if (nullMap == EMPTY_BYTE_BUFFER_DIRECT) { - return false; - } - return MemoryUtil.getByte(nullMapAddr + rowId) != 0; + return nullMap != null && nullMap.get(rowId) != 0; } /** @@ -146,7 +129,7 @@ public boolean getBoolean(int rowId) { */ @Override public byte getByte(int rowId) { - return MemoryUtil.getByte(dataAddr + rowId); + return data.get(rowId); } /** @@ -155,7 +138,7 @@ public byte getByte(int rowId) { */ @Override public short getShort(int rowId) { - return MemoryUtil.getShort(dataAddr + (rowId << 1)); + return data.getShort(rowId << 1); } /** @@ -167,11 +150,12 @@ public int getInt(int rowId) { if (type instanceof DateType) { return (int) getTime(rowId); } - return MemoryUtil.getInt(dataAddr + (rowId << 2)); + return data.getInt(rowId << 2); } + // returns microseconds since epoch - fields are interpreted in current default timezone private long getDateTime(int rowId) { - long v = MemoryUtil.getLong(dataAddr + (rowId << 3)); + long v = data.getLong(rowId << 3); long ymdhms = v >>> 24; long ymd = ymdhms >>> 17; int day = (int) (ymd & ((1 << 5) - 1)); @@ -184,13 +168,15 @@ private long getDateTime(int rowId) { int minute = (hms >>> 6) & ((1 << 6) - 1); int hour = hms >>> 12; int microsec = (int) (v % (1 << 24)); - Timestamp ts = - new Timestamp(year - 1900, month - 1, day, hour, minute, second, microsec * 1000); - return ts.getTime() / 1000 * 1000000 + ts.getNanos() / 1000; + ZonedDateTime zdt = + ZonedDateTime.of( + year, month, day, hour, minute, second, microsec * 1000, ZoneId.systemDefault()); + Instant instant = zdt.toInstant(); + return instant.getEpochSecond() * 1000_000L + instant.getNano() / 1000; } private long getTime(int rowId) { - long v = MemoryUtil.getLong(dataAddr + (rowId << 3)); + long v = data.getLong(rowId << 3); long ymd = v >>> 41; long ym = ymd >>> 5; int year = (int) (ym / 13); @@ -215,7 +201,7 @@ public long getLong(int rowId) { } else if (fixedLength == 4) { return getInt(rowId); } else if (fixedLength == 8) { - return MemoryUtil.getLong(dataAddr + (rowId * fixedLength)); + return data.getLong(rowId << 3); } throw new UnsupportedOperationException( String.format("getting long with fixed length %d", fixedLength)); @@ -227,7 +213,7 @@ public long getLong(int rowId) { */ @Override public float getFloat(int rowId) { - return MemoryUtil.getFloat(dataAddr + (rowId * fixedLength)); + return data.getFloat(rowId * fixedLength); } /** @@ -236,7 +222,7 @@ public float getFloat(int rowId) { */ @Override public double getDouble(int rowId) { - return MemoryUtil.getDouble(dataAddr + (rowId * fixedLength)); + return data.getDouble(rowId * fixedLength); } /** @@ -244,28 +230,24 @@ public double getDouble(int rowId) { */ @Override public BigDecimal getDecimal(int rowId, int precision, int scale) { - long rowIdAddr = rowId * fixedLength + dataAddr; if (fixedLength == 4) { - return MemoryUtil.getDecimal32(rowIdAddr, scale); + return MemoryUtil.getDecimal32(data, rowId << 2, scale); } else if (fixedLength == 8) { - return MemoryUtil.getDecimal64(rowIdAddr, scale); + return MemoryUtil.getDecimal64(data, rowId << 3, scale); } else if (fixedLength == 16) { - return MemoryUtil.getDecimal128(rowIdAddr, scale); + return MemoryUtil.getDecimal128(data, rowId << 4, scale); } else { - return MemoryUtil.getDecimal256(rowIdAddr, scale); + return MemoryUtil.getDecimal256(data, rowId * fixedLength, scale); } } private long offsetAt(int i) { - return i == 0 ? 0 : MemoryUtil.getLong(offsetsAddr + ((i - 1) << 3)); + return i == 0 ? 0L : offsets.getLong((i - 1) << 3); } public int sizeAt(int i) { return (int) - (i == 0 - ? MemoryUtil.getLong(offsetsAddr) - : MemoryUtil.getLong(offsetsAddr + (i << 3)) - - MemoryUtil.getLong(offsetsAddr + ((i - 1) << 3))); + (i == 0 ? offsets.getLong(0) : offsets.getLong(i << 3) - offsets.getLong((i - 1) << 3)); } /** @@ -278,13 +260,13 @@ public String getUTF8String(int rowId) { // FixedString case if (fixedLength != -1) { byte[] chars = new byte[fixedLength]; - MemoryUtil.getBytes((int) (dataAddr + fixedLength * rowId), chars, 0, fixedLength); + data.get(chars, rowId * fixedLength, fixedLength); return new String(chars); } else { - long offset = (dataAddr + offsetAt(rowId)); + int offset = (int) offsetAt(rowId); int numBytes = sizeAt(rowId) - 1; byte[] chars = new byte[numBytes]; - MemoryUtil.getBytes(offset, chars, 0, numBytes); + data.get(chars, offset, numBytes); return new String(chars, StandardCharsets.UTF_8); } } @@ -295,10 +277,10 @@ public String getUTF8String(int rowId) { @Override public byte[] getBinary(int rowId) { if (type.equals(BytesType.BLOB) || type.equals(BytesType.TINY_BLOB)) { - long offset = (dataAddr + offsetAt(rowId)); + int offset = (int) offsetAt(rowId); int numBytes = sizeAt(rowId) - 1; byte[] ret = new byte[numBytes]; - MemoryUtil.getBytes(offset, ret, 0, numBytes); + data.get(ret, offset, numBytes); return ret; } else { throw new UnsupportedOperationException( diff --git a/src/main/java/org/tikv/common/columnar/datatypes/AutoGrowByteBuffer.java b/src/main/java/org/tikv/common/columnar/datatypes/AutoGrowByteBuffer.java index 70e59643323..7975d2cd25e 100644 --- a/src/main/java/org/tikv/common/columnar/datatypes/AutoGrowByteBuffer.java +++ b/src/main/java/org/tikv/common/columnar/datatypes/AutoGrowByteBuffer.java @@ -20,12 +20,10 @@ import org.tikv.common.util.MemoryUtil; public class AutoGrowByteBuffer { - private final ByteBuffer initBuf; private ByteBuffer buf; public AutoGrowByteBuffer(ByteBuffer initBuf) { initBuf.clear(); - this.initBuf = initBuf; this.buf = initBuf; } @@ -39,22 +37,12 @@ public ByteBuffer getByteBuffer() { private void beforeIncrease(int inc) { int minCap = buf.position() + inc; - if (minCap > buf.capacity()) { - int newCap = buf.capacity(); + int newCap = buf.capacity(); + if (minCap > newCap) { do { newCap = newCap << 1; } while (minCap > newCap); - - ByteBuffer newBuf = MemoryUtil.allocateDirect(newCap); - MemoryUtil.copyMemory( - MemoryUtil.getAddress(buf), MemoryUtil.getAddress(newBuf), buf.position()); - newBuf.position(buf.position()); - - if (buf != initBuf) { - MemoryUtil.free(buf); - } - - buf = newBuf; + buf = MemoryUtil.copyOf(buf, newCap); } } diff --git a/src/main/java/org/tikv/common/columnar/datatypes/CHType.java b/src/main/java/org/tikv/common/columnar/datatypes/CHType.java index 83ff5cd7802..3ec85c498d1 100644 --- a/src/main/java/org/tikv/common/columnar/datatypes/CHType.java +++ b/src/main/java/org/tikv/common/columnar/datatypes/CHType.java @@ -15,7 +15,7 @@ package org.tikv.common.columnar.datatypes; -import static org.tikv.common.util.MemoryUtil.allocateDirect; +import static org.tikv.common.util.MemoryUtil.allocate; import java.nio.ByteBuffer; import org.tikv.common.codec.CodecDataInput; @@ -41,7 +41,7 @@ public void setNullable(boolean nullable) { protected ByteBuffer decodeNullMap(CodecDataInput cdi, int size) { // read size * uint8 from cdi - ByteBuffer buffer = allocateDirect(size); + ByteBuffer buffer = allocate(size); MemoryUtil.readFully(buffer, cdi, size); buffer.clear(); return buffer; @@ -63,13 +63,13 @@ public TiBlockColumnVector decode(CodecDataInput cdi, int size) { } if (isNullable()) { ByteBuffer nullMap = decodeNullMap(cdi, size); - ByteBuffer buffer = allocateDirect(bufferSize(size)); + ByteBuffer data = allocate(bufferSize(size)); // read bytes from cdi to buffer(off-heap) - MemoryUtil.readFully(buffer, cdi, bufferSize(size)); - buffer.clear(); - return new TiBlockColumnVector(this, nullMap, buffer, size, length); + MemoryUtil.readFully(data, cdi, bufferSize(size)); + data.clear(); + return new TiBlockColumnVector(this, nullMap, data, size, length); } else { - ByteBuffer buffer = allocateDirect(bufferSize(size)); + ByteBuffer buffer = allocate(bufferSize(size)); MemoryUtil.readFully(buffer, cdi, bufferSize(size)); buffer.clear(); return new TiBlockColumnVector(this, buffer, size, length); diff --git a/src/main/java/org/tikv/common/columnar/datatypes/CHTypeString.java b/src/main/java/org/tikv/common/columnar/datatypes/CHTypeString.java index 9a91afbb531..bbaa542530a 100644 --- a/src/main/java/org/tikv/common/columnar/datatypes/CHTypeString.java +++ b/src/main/java/org/tikv/common/columnar/datatypes/CHTypeString.java @@ -15,8 +15,7 @@ package org.tikv.common.columnar.datatypes; -import static org.tikv.common.util.MemoryUtil.EMPTY_BYTE_BUFFER_DIRECT; -import static org.tikv.common.util.MemoryUtil.allocateDirect; +import static org.tikv.common.util.MemoryUtil.allocate; import com.google.common.base.Preconditions; import java.nio.ByteBuffer; @@ -31,7 +30,7 @@ public class CHTypeString extends CHType { // Use to prevent frequently reallocate the chars buffer. // ClickHouse does not pass a total length at the beginning, so sad... private static final ThreadLocal initBuffer = - ThreadLocal.withInitial(() -> allocateDirect(102400)); + ThreadLocal.withInitial(() -> allocate(102400)); public CHTypeString() { this.length = -1; @@ -57,12 +56,12 @@ public TiBlockColumnVector decode(CodecDataInput cdi, int size) { if (isNullable()) { nullMap = decodeNullMap(cdi, size); } else { - nullMap = EMPTY_BYTE_BUFFER_DIRECT; + nullMap = null; } - ByteBuffer offsets = allocateDirect(size << 3); - ByteBuffer initCharsBuf = initBuffer.get(); - AutoGrowByteBuffer autoGrowCharsBuf = new AutoGrowByteBuffer(initCharsBuf); + ByteBuffer offsets = allocate(size << 3); + ByteBuffer initDataBuf = initBuffer.get(); + AutoGrowByteBuffer autoGrowDataBuf = new AutoGrowByteBuffer(initDataBuf); int offset = 0; for (int i = 0; i < size; i++) { @@ -71,20 +70,18 @@ public TiBlockColumnVector decode(CodecDataInput cdi, int size) { offset += valueSize + 1; offsets.putLong(offset); - autoGrowCharsBuf.put(cdi, valueSize); - autoGrowCharsBuf.putByte((byte) 0); // terminating zero byte + autoGrowDataBuf.put(cdi, valueSize); + autoGrowDataBuf.putByte((byte) 0); // terminating zero byte } - Preconditions.checkState(offset == autoGrowCharsBuf.dataSize()); + Preconditions.checkState(offset == autoGrowDataBuf.dataSize()); - ByteBuffer chars = autoGrowCharsBuf.getByteBuffer(); - if (chars == initCharsBuf) { + ByteBuffer data = autoGrowDataBuf.getByteBuffer(); + if (data == initDataBuf) { // Copy out. - ByteBuffer newChars = allocateDirect(offset); - MemoryUtil.copyMemory(MemoryUtil.getAddress(chars), MemoryUtil.getAddress(newChars), offset); - chars = newChars; + data = MemoryUtil.copyOf(data, offset); } - return new TiBlockColumnVector(this, nullMap, offsets, chars, size); + return new TiBlockColumnVector(this, nullMap, offsets, data, size); } } diff --git a/src/main/java/org/tikv/common/util/MemoryUtil.java b/src/main/java/org/tikv/common/util/MemoryUtil.java index 5c5021cca0e..6a5c99c1bb4 100644 --- a/src/main/java/org/tikv/common/util/MemoryUtil.java +++ b/src/main/java/org/tikv/common/util/MemoryUtil.java @@ -16,270 +16,46 @@ package org.tikv.common.util; import com.google.common.primitives.UnsignedLong; -import com.sun.management.OperatingSystemMXBean; -import java.lang.management.ManagementFactory; -import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.BigInteger; -import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.channels.FileChannel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.Arrays; import org.tikv.common.codec.CodecDataInput; -import sun.misc.Cleaner; -import sun.misc.Unsafe; -import sun.nio.ch.DirectBuffer; -// Copied from io.indexr.util.MemoryUtil.java with some modifications. +// Copied from io.indexr.util.MemoryUtil.java with lots of modifications. public class MemoryUtil { - public static final ByteBuffer EMPTY_BYTE_BUFFER_DIRECT = allocateDirect(0); - public static final Unsafe unsafe; - private static final Logger logger = LoggerFactory.getLogger(MemoryUtil.class); - private static final long UNSAFE_COPY_THRESHOLD = 1024 * 1024L; // copied from java.nio.Bits - private static final Class DIRECT_BYTE_BUFFER_CLASS; - private static final long DIRECT_BYTE_BUFFER_ADDRESS_OFFSET; - private static final long DIRECT_BYTE_BUFFER_CAPACITY_OFFSET; - private static final long DIRECT_BYTE_BUFFER_LIMIT_OFFSET; - private static final long DIRECT_BYTE_BUFFER_POSITION_OFFSET; - private static final long DIRECT_BYTE_BUFFER_ATTACHMENT_OFFSET; - private static final long DIRECT_BYTE_BUFFER_CLEANER; - private static final Class BYTE_BUFFER_CLASS; - private static final long BYTE_BUFFER_OFFSET_OFFSET; - private static final long BYTE_BUFFER_HB_OFFSET; - private static final long BYTE_ARRAY_BASE_OFFSET; + public static final ByteBuffer EMPTY_BYTE_BUFFER = allocate(0); - private static final long STRING_VALUE_OFFSET; - - private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN); - private static int PAGE_SIZE = -1; - - private static boolean HDFS_READ_HACK_ENABLE; - private static long BlockReaderLocal_verifyChecksum; - private static long BlockReaderLocal_dataIn; - private static long DFSInputStream_verifyChecksum; - private static long DFSInputStream_blockReader; - - static { - // We support all in fact. - // if (BIG_ENDIAN) { - // throw new RuntimeException("We only support littel endian platform!"); - // } - try { - Field field = Unsafe.class.getDeclaredField("theUnsafe"); - field.setAccessible(true); - unsafe = (Unsafe) field.get(null); - - Class clazz = ByteBuffer.allocateDirect(0).getClass(); - DIRECT_BYTE_BUFFER_ADDRESS_OFFSET = - unsafe.objectFieldOffset(Buffer.class.getDeclaredField("address")); - DIRECT_BYTE_BUFFER_CAPACITY_OFFSET = - unsafe.objectFieldOffset(Buffer.class.getDeclaredField("capacity")); - DIRECT_BYTE_BUFFER_LIMIT_OFFSET = - unsafe.objectFieldOffset(Buffer.class.getDeclaredField("limit")); - DIRECT_BYTE_BUFFER_POSITION_OFFSET = - unsafe.objectFieldOffset(Buffer.class.getDeclaredField("position")); - DIRECT_BYTE_BUFFER_ATTACHMENT_OFFSET = - unsafe.objectFieldOffset(clazz.getDeclaredField("att")); - DIRECT_BYTE_BUFFER_CLEANER = unsafe.objectFieldOffset(clazz.getDeclaredField("cleaner")); - DIRECT_BYTE_BUFFER_CLASS = clazz; - - clazz = ByteBuffer.allocate(0).getClass(); - BYTE_BUFFER_OFFSET_OFFSET = - unsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("offset")); - BYTE_BUFFER_HB_OFFSET = unsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb")); - BYTE_BUFFER_CLASS = clazz; - - BYTE_ARRAY_BASE_OFFSET = unsafe.arrayBaseOffset(byte[].class); - - STRING_VALUE_OFFSET = - MemoryUtil.unsafe.objectFieldOffset(String.class.getDeclaredField("value")); - - try { - BlockReaderLocal_verifyChecksum = - unsafe.objectFieldOffset( - Class.forName("org.apache.hadoop.hdfs.BlockReaderLocal") - .getDeclaredField("verifyChecksum")); - BlockReaderLocal_dataIn = - unsafe.objectFieldOffset( - Class.forName("org.apache.hadoop.hdfs.BlockReaderLocal") - .getDeclaredField("dataIn")); - - DFSInputStream_verifyChecksum = - unsafe.objectFieldOffset( - Class.forName("org.apache.hadoop.hdfs.DFSInputStream") - .getDeclaredField("verifyChecksum")); - DFSInputStream_blockReader = - unsafe.objectFieldOffset( - Class.forName("org.apache.hadoop.hdfs.DFSInputStream") - .getDeclaredField("blockReader")); - - HDFS_READ_HACK_ENABLE = true; - } catch (Exception e) { - HDFS_READ_HACK_ENABLE = false; - logger.warn("hdfs read hack is off because of error: {}", e.getCause()); - } - } catch (Exception e) { - throw new AssertionError(e); - } - } - - public static boolean getBlockReaderLocal_verifyChecksum(Object br) { - return unsafe.getBoolean(br, BlockReaderLocal_verifyChecksum); - } - - public static void setBlockReaderLocal_verifyChecksum(Object br, boolean value) { - unsafe.putBoolean(br, BlockReaderLocal_verifyChecksum, value); - } - - public static FileChannel getBlockReaderLocal_dataIn(Object br) { - return (FileChannel) unsafe.getObject(br, BlockReaderLocal_dataIn); - } - - public static int pageSize() { - if (PAGE_SIZE == -1) { - PAGE_SIZE = unsafe.pageSize(); - } - return PAGE_SIZE; - } - - public static void setMemory(long addr, long size, byte v) { - unsafe.setMemory(addr, size, v); - } - - public static void setMemory(Object base, long offset, long size, byte v) { - unsafe.setMemory(base, offset, size, v); - } - - public static long getAddress(ByteBuffer buffer) { - assert buffer.getClass() == DIRECT_BYTE_BUFFER_CLASS; - return unsafe.getLong(buffer, DIRECT_BYTE_BUFFER_ADDRESS_OFFSET); - } - - public static int getCap(ByteBuffer buffer) { - assert buffer.getClass() == DIRECT_BYTE_BUFFER_CLASS; - return unsafe.getInt(buffer, DIRECT_BYTE_BUFFER_CAPACITY_OFFSET); - } - - public static long allocate(long size) { - // return Native.malloc(size); - return unsafe.allocateMemory(size); - } - - public static void free(long addr) { - // Native.free(addr); - unsafe.freeMemory(addr); - } - - /** Good manner to free a buffer before forget it. */ - public static void free(ByteBuffer buffer) { - if (buffer.isDirect()) { - Cleaner cleaner = ((DirectBuffer) buffer).cleaner(); - if (cleaner != null) { - cleaner.clean(); - } - } - } - - public static void setByte(long address, byte b) { - unsafe.putByte(address, b); - } - - public static void setShort(long address, short s) { - unsafe.putShort(address, s); - } - - public static void setInt(long address, int l) { - unsafe.putInt(address, l); - } - - public static void setDecimal(long address, BigDecimal v, int scale) { - BigDecimal bigDec = v; - BigInteger bigInt = bigDec.scaleByPowerOfTen(scale).toBigInteger(); - byte[] arr = bigInt.toByteArray(); - for (int i = 0; i < arr.length; i++) { - unsafe.putByte(address + i, arr[arr.length - 1 - i]); - } - } - - public static void setDecimal256(long address, BigDecimal v, int scale) { - BigDecimal bigDec = v; - BigInteger bigInt = bigDec.scaleByPowerOfTen(scale).toBigInteger(); - int sign = 0; - if (bigInt.signum() < 0) { - sign = 1; - bigInt = bigInt.abs(); - } - byte[] arr = bigInt.toByteArray(); - if (arr.length > 32) { - throw new RuntimeException("The inserting decimal is out of range: " + v.toString()); - } - int limbs = arr.length / 8; - if (arr.length % 8 > 0) { - limbs++; - } - - for (int i = 0; i < arr.length; i++) { - unsafe.putByte(address + i, arr[arr.length - 1 - i]); - } - unsafe.putShort(address + 32, (short) limbs); - unsafe.putShort(address + 34, (short) sign); - } - - public static void setLong(long address, long l) { - unsafe.putLong(address, l); - } - - public static void setFloat(long address, float v) { - unsafe.putFloat(address, v); - } - - public static void setDouble(long address, double v) { - unsafe.putDouble(address, v); - } - - public static byte getByte(long address) { - return unsafe.getByte(address); - } - - public static short getShort(long address) { - return (short) (unsafe.getShort(address) & 0xffff); - } - - public static int getInt(long address) { - return unsafe.getInt(address); - } - - public static BigDecimal getDecimal32(long address, int scale) { - int n = getInt(address); + public static BigDecimal getDecimal32(ByteBuffer data, int offset, int scale) { + int n = data.getInt(offset); BigInteger dec = BigInteger.valueOf(n); return new BigDecimal(dec, scale); } - public static BigDecimal getDecimal64(long address, int scale) { - long n = getLong(address); + public static BigDecimal getDecimal64(ByteBuffer data, int offset, int scale) { + long n = data.getLong(offset); BigInteger dec = BigInteger.valueOf(n); return new BigDecimal(dec, scale); } - public static BigDecimal getDecimal128(long address, int scale) { - UnsignedLong n0 = UnsignedLong.fromLongBits(getLong(address)); - long n1 = getLong(address + 8); + public static BigDecimal getDecimal128(ByteBuffer data, int offset, int scale) { + UnsignedLong n0 = UnsignedLong.fromLongBits(data.getLong(offset)); + long n1 = data.getLong(offset + 8); BigInteger dec = BigInteger.valueOf(n1); dec = dec.shiftLeft(64).add(n0.bigIntegerValue()); return new BigDecimal(dec, scale); } - public static BigDecimal getDecimal256(long address, int scale) { - int limbs = getShort(address + 32); + public static BigDecimal getDecimal256(ByteBuffer data, int offset, int scale) { + int limbs = data.getShort(offset + 32); BigInteger dec = BigInteger.ZERO; for (int i = limbs - 1; i >= 0; i--) { - UnsignedLong d = UnsignedLong.fromLongBits(unsafe.getLong(address + i * 8)); + UnsignedLong d = UnsignedLong.fromLongBits(data.getLong(offset + i * 8)); dec = dec.shiftLeft(64).add(d.bigIntegerValue()); } - int sign = unsafe.getByte(address + 34); + int sign = data.get(offset + 34); BigDecimal result = new BigDecimal(dec, scale); if (sign > 0) { return result.negate(); @@ -287,297 +63,25 @@ public static BigDecimal getDecimal256(long address, int scale) { return result; } - public static long getLong(long address) { - return unsafe.getLong(address); - } - - public static float getFloat(long address) { - return unsafe.getFloat(address); - } - - public static double getDouble(long address) { - return unsafe.getDouble(address); - } - - public static ByteBuffer getByteBuffer(long address, int length, boolean autoFree) { - ByteBuffer instance = getHollowDirectByteBuffer(); - if (autoFree) { - Cleaner cleaner = Cleaner.create(instance, new Deallocator(address)); - setByteBuffer(instance, address, length, cleaner); - } else { - setByteBuffer(instance, address, length, null); - } - instance.order(ByteOrder.nativeOrder()); - return instance; - } - - public static ByteBuffer getHollowDirectByteBuffer() { - ByteBuffer instance; - try { - instance = (ByteBuffer) unsafe.allocateInstance(DIRECT_BYTE_BUFFER_CLASS); - } catch (InstantiationException e) { - throw new AssertionError(e); - } - instance.order(ByteOrder.nativeOrder()); - return instance; - } - - public static void setByteBuffer(ByteBuffer instance, long address, int length, Cleaner cleaner) { - unsafe.putLong(instance, DIRECT_BYTE_BUFFER_ADDRESS_OFFSET, address); - unsafe.putInt(instance, DIRECT_BYTE_BUFFER_CAPACITY_OFFSET, length); - unsafe.putInt(instance, DIRECT_BYTE_BUFFER_LIMIT_OFFSET, length); - if (cleaner != null) { - unsafe.putObject(instance, DIRECT_BYTE_BUFFER_CLEANER, cleaner); - } - } - - public static Object getAttachment(ByteBuffer instance) { - assert instance.getClass() == DIRECT_BYTE_BUFFER_CLASS; - return unsafe.getObject(instance, DIRECT_BYTE_BUFFER_ATTACHMENT_OFFSET); - } - - public static void setAttachment(ByteBuffer instance, Object next) { - assert instance.getClass() == DIRECT_BYTE_BUFFER_CLASS; - unsafe.putObject(instance, DIRECT_BYTE_BUFFER_ATTACHMENT_OFFSET, next); - } - - public static ByteBuffer duplicateDirectByteBuffer(ByteBuffer source, ByteBuffer hollowBuffer) { - assert source.getClass() == DIRECT_BYTE_BUFFER_CLASS; - unsafe.putLong( - hollowBuffer, - DIRECT_BYTE_BUFFER_ADDRESS_OFFSET, - unsafe.getLong(source, DIRECT_BYTE_BUFFER_ADDRESS_OFFSET)); - unsafe.putInt( - hollowBuffer, - DIRECT_BYTE_BUFFER_POSITION_OFFSET, - unsafe.getInt(source, DIRECT_BYTE_BUFFER_POSITION_OFFSET)); - unsafe.putInt( - hollowBuffer, - DIRECT_BYTE_BUFFER_LIMIT_OFFSET, - unsafe.getInt(source, DIRECT_BYTE_BUFFER_LIMIT_OFFSET)); - unsafe.putInt( - hollowBuffer, - DIRECT_BYTE_BUFFER_CAPACITY_OFFSET, - unsafe.getInt(source, DIRECT_BYTE_BUFFER_CAPACITY_OFFSET)); - return hollowBuffer; - } - - public static ByteBuffer duplicateDirectByteBuffer(ByteBuffer source) { - return duplicateDirectByteBuffer(source, getHollowDirectByteBuffer()); - } - - public static long getLongByByte(long address) { - if (BIG_ENDIAN) { - return (((long) unsafe.getByte(address)) << 56) - | (((long) unsafe.getByte(address + 1) & 0xff) << 48) - | (((long) unsafe.getByte(address + 2) & 0xff) << 40) - | (((long) unsafe.getByte(address + 3) & 0xff) << 32) - | (((long) unsafe.getByte(address + 4) & 0xff) << 24) - | (((long) unsafe.getByte(address + 5) & 0xff) << 16) - | (((long) unsafe.getByte(address + 6) & 0xff) << 8) - | (((long) unsafe.getByte(address + 7) & 0xff)); - } else { - return (((long) unsafe.getByte(address + 7)) << 56) - | (((long) unsafe.getByte(address + 6) & 0xff) << 48) - | (((long) unsafe.getByte(address + 5) & 0xff) << 40) - | (((long) unsafe.getByte(address + 4) & 0xff) << 32) - | (((long) unsafe.getByte(address + 3) & 0xff) << 24) - | (((long) unsafe.getByte(address + 2) & 0xff) << 16) - | (((long) unsafe.getByte(address + 1) & 0xff) << 8) - | (((long) unsafe.getByte(address) & 0xff)); - } - } - - public static int getIntByByte(long address) { - if (BIG_ENDIAN) { - return (((int) unsafe.getByte(address)) << 24) - | (((int) unsafe.getByte(address + 1) & 0xff) << 16) - | (((int) unsafe.getByte(address + 2) & 0xff) << 8) - | (((int) unsafe.getByte(address + 3) & 0xff)); - } else { - return (((int) unsafe.getByte(address + 3)) << 24) - | (((int) unsafe.getByte(address + 2) & 0xff) << 16) - | (((int) unsafe.getByte(address + 1) & 0xff) << 8) - | (((int) unsafe.getByte(address) & 0xff)); - } - } - - public static int getShortByByte(long address) { - if (BIG_ENDIAN) { - return (((int) unsafe.getByte(address)) << 8) | (((int) unsafe.getByte(address + 1) & 0xff)); - } else { - return (((int) unsafe.getByte(address + 1)) << 8) | (((int) unsafe.getByte(address) & 0xff)); - } - } - - public static void putLongByByte(long address, long value) { - if (BIG_ENDIAN) { - unsafe.putByte(address, (byte) (value >> 56)); - unsafe.putByte(address + 1, (byte) (value >> 48)); - unsafe.putByte(address + 2, (byte) (value >> 40)); - unsafe.putByte(address + 3, (byte) (value >> 32)); - unsafe.putByte(address + 4, (byte) (value >> 24)); - unsafe.putByte(address + 5, (byte) (value >> 16)); - unsafe.putByte(address + 6, (byte) (value >> 8)); - unsafe.putByte(address + 7, (byte) (value)); - } else { - unsafe.putByte(address + 7, (byte) (value >> 56)); - unsafe.putByte(address + 6, (byte) (value >> 48)); - unsafe.putByte(address + 5, (byte) (value >> 40)); - unsafe.putByte(address + 4, (byte) (value >> 32)); - unsafe.putByte(address + 3, (byte) (value >> 24)); - unsafe.putByte(address + 2, (byte) (value >> 16)); - unsafe.putByte(address + 1, (byte) (value >> 8)); - unsafe.putByte(address, (byte) (value)); - } - } - - public static void putIntByByte(long address, int value) { - if (BIG_ENDIAN) { - unsafe.putByte(address, (byte) (value >> 24)); - unsafe.putByte(address + 1, (byte) (value >> 16)); - unsafe.putByte(address + 2, (byte) (value >> 8)); - unsafe.putByte(address + 3, (byte) (value)); - } else { - unsafe.putByte(address + 3, (byte) (value >> 24)); - unsafe.putByte(address + 2, (byte) (value >> 16)); - unsafe.putByte(address + 1, (byte) (value >> 8)); - unsafe.putByte(address, (byte) (value)); - } - } - - public static void setBytes(long address, ByteBuffer buffer) { - int start = buffer.position(); - int count = buffer.limit() - start; - if (count == 0) return; - - if (buffer.isDirect()) setBytes(((DirectBuffer) buffer).address() + start, address, count); - else setBytes(address, buffer.array(), buffer.arrayOffset() + start, count); - } - - /** - * Transfers objCount bytes from buffer to Memory - * - * @param address start offset in the memory - * @param buffer the data buffer - * @param bufferOffset start offset of the buffer - * @param count number of bytes to transfer - */ - public static void setBytes(long address, byte[] buffer, int bufferOffset, int count) { - assert buffer != null; - assert !(bufferOffset < 0 || count < 0 || bufferOffset + count > buffer.length); - setBytes(buffer, bufferOffset, address, count); - } - - public static void setBytes(long src, long trg, long count) { - while (count > 0) { - long size = Math.min(count, UNSAFE_COPY_THRESHOLD); - unsafe.copyMemory(src, trg, size); - count -= size; - src += size; - trg += size; - } - } - - public static void setBytes(byte[] src, int offset, long trg, long count) { - while (count > 0) { - long size = (count > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : count; - unsafe.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + offset, null, trg, size); - count -= size; - offset += size; - trg += size; - } - } - - /** - * Transfers objCount bytes from Memory starting at memoryOffset to buffer starting at - * bufferOffset - * - * @param address start offset in the memory - * @param buffer the data buffer - * @param bufferOffset start offset of the buffer - * @param count number of bytes to transfer - */ - public static void getBytes(long address, byte[] buffer, int bufferOffset, int count) { - if (buffer == null) throw new NullPointerException(); - else if (bufferOffset < 0 || count < 0 || count > buffer.length - bufferOffset) - throw new IndexOutOfBoundsException(); - else if (count == 0) return; - - unsafe.copyMemory(null, address, buffer, BYTE_ARRAY_BASE_OFFSET + bufferOffset, count); - } - - public static char[] getStringValue(String str) { - return (char[]) MemoryUtil.unsafe.getObject(str, STRING_VALUE_OFFSET); - } - - public static void copyMemory(long fromAddr, long toAddr, int count) { - copyMemory(null, fromAddr, null, toAddr, count); - } - - public static void copyMemory( - Object src, long srcOffset, Object dst, long dstOffset, long length) { - // Check if dstOffset is before or after srcOffset to determine if we should copy - // forward or backwards. This is necessary in case src and dst overlap. - if (dstOffset < srcOffset) { - while (length > 0) { - long size = Math.min(length, UNSAFE_COPY_THRESHOLD); - unsafe.copyMemory(src, srcOffset, dst, dstOffset, size); - length -= size; - srcOffset += size; - dstOffset += size; - } - } else { - srcOffset += length; - dstOffset += length; - while (length > 0) { - long size = Math.min(length, UNSAFE_COPY_THRESHOLD); - srcOffset -= size; - dstOffset -= size; - unsafe.copyMemory(src, srcOffset, dst, dstOffset, size); - length -= size; - } - } - } - - public static long getTotalPhysicalMemorySize() { - return ((OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean()) - .getTotalPhysicalMemorySize(); - } - - public static ByteBuffer allocateDirect(int cap) { - ByteBuffer bb = ByteBuffer.allocateDirect(cap); + public static ByteBuffer allocate(int cap) { + ByteBuffer bb = ByteBuffer.allocate(cap); // It make operation faster, but kill the cross platform ability. bb.order(ByteOrder.nativeOrder()); return bb; } - public static void readFully(ByteBuffer dst, CodecDataInput cdi, int length) { - // read bytes from cdi to buffer(off-heap) - long disAddr = MemoryUtil.getAddress(dst); - long bufPos = dst.position(); - for (int i = 0; i < length && !cdi.eof(); i++) { - byte b = cdi.readByte(); - MemoryUtil.setByte(disAddr + bufPos + i, b); - } - dst.position((int) (bufPos + length)); + public static ByteBuffer copyOf(ByteBuffer buf, int newCap) { + ByteBuffer newBuf = ByteBuffer.wrap(Arrays.copyOf(buf.array(), newCap)); + newBuf.position(buf.position()); + return newBuf; } - private static class Deallocator implements Runnable { - private long address; - - private Deallocator(long address) { - assert (address != 0); - this.address = address; - } - - @Override - public void run() { - if (address == 0) { - return; - } - free(address); - address = 0; + public static void readFully(ByteBuffer dst, CodecDataInput cdi, int length) { + int remaining; + for (remaining = length; remaining > 0 && !cdi.eof(); remaining--) { + byte b = cdi.readByte(); + dst.put(b); } + dst.position(dst.position() + remaining); } }