All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.netty.buffer.ArrowBuf Maven / Gradle / Ivy

There is a newer version: 18.2.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.netty.buffer;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.arrow.memory.AllocationManager;
import org.apache.arrow.memory.BaseAllocator;
import org.apache.arrow.memory.BaseAllocator.Verbosity;
import org.apache.arrow.memory.BoundsChecking;
import org.apache.arrow.memory.BufferLedger;
import org.apache.arrow.memory.BufferManager;
import org.apache.arrow.memory.ReferenceManager;
import org.apache.arrow.memory.util.HistoricalLog;
import org.apache.arrow.util.Preconditions;

import io.netty.util.internal.PlatformDependent;

/**
 * ArrowBuf serves as a facade over underlying memory by providing
 * several access APIs to read/write data into a chunk of direct
 * memory. All the accounting, ownership and reference management
 * is done by {@link ReferenceManager} and ArrowBuf can work
 * with a custom user provided implementation of ReferenceManager
 * 

* Two important instance variables of an ArrowBuf: * (1) address - starting virtual address in the underlying memory * chunk that this ArrowBuf has access to * (2) length - length (in bytes) in the underlying memory chunk * that this ArrowBuf has access to *

*

* The mangement (allocation, deallocation, reference counting etc) for * the memory chunk is not done by ArrowBuf. * Default implementation of ReferenceManager, allocation is in * {@link BaseAllocator}, {@link BufferLedger} and {@link AllocationManager} *

*/ public final class ArrowBuf implements AutoCloseable { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ArrowBuf.class); private static final int SHORT_SIZE = Short.BYTES; private static final int INT_SIZE = Integer.BYTES; private static final int FLOAT_SIZE = Float.BYTES; private static final int DOUBLE_SIZE = Double.BYTES; private static final int LONG_SIZE = Long.BYTES; private static final AtomicLong idGenerator = new AtomicLong(0); private static final int LOG_BYTES_PER_ROW = 10; private final long id = idGenerator.incrementAndGet(); private final ReferenceManager referenceManager; private final BufferManager bufferManager; private final long addr; private final boolean isEmpty; private int readerIndex; private int writerIndex; private final HistoricalLog historicalLog = BaseAllocator.DEBUG ? new HistoricalLog(BaseAllocator.DEBUG_LOG_LENGTH, "ArrowBuf[%d]", id) : null; private volatile int length; /** * Constructs a new ArrowBuf * @param referenceManager The memory manager to track memory usage and reference count of this buffer * @param length The byte length of this buffer * @param isEmpty Indicates if this buffer is empty which enables some optimizations. */ public ArrowBuf( final ReferenceManager referenceManager, final BufferManager bufferManager, final int length, final long memoryAddress, boolean isEmpty) { this.referenceManager = referenceManager; this.bufferManager = bufferManager; this.isEmpty = isEmpty; this.addr = memoryAddress; this.length = length; this.readerIndex = 0; this.writerIndex = 0; if (BaseAllocator.DEBUG) { historicalLog.recordEvent("create()"); } } public int refCnt() { return isEmpty ? 1 : referenceManager.getRefCount(); } /** * Allows a function to determine whether not reading a particular string of bytes is valid. * *

Will throw an exception if the memory is not readable for some reason. Only doesn't * something in the case that * AssertionUtil.BOUNDS_CHECKING_ENABLED is true. * * @param start The starting position of the bytes to be read. * @param end The exclusive endpoint of the bytes to be read. */ public void checkBytes(int start, int end) { if (BoundsChecking.BOUNDS_CHECKING_ENABLED) { checkIndexD(start, end - start); } } /** * For get/set operations, reference count should be >= 1. */ private void ensureAccessible() { if (this.refCnt() == 0) { throw new IllegalStateException("Ref count should be >= 1 for accessing the ArrowBuf"); } } /** * Get a wrapper buffer to comply with Netty interfaces and * can be used in RPC/RPC allocator code. * @return netty compliant {@link NettyArrowBuf} */ public NettyArrowBuf asNettyBuffer() { final NettyArrowBuf nettyArrowBuf = new NettyArrowBuf( this, isEmpty ? null : referenceManager.getAllocator().getAsByteBufAllocator(), length); nettyArrowBuf.readerIndex(readerIndex); nettyArrowBuf.writerIndex(writerIndex); return nettyArrowBuf; } /** * Get reference manager for this ArrowBuf. * @return user provided implementation of {@link ReferenceManager} */ public ReferenceManager getReferenceManager() { return referenceManager; } public boolean isEmpty() { return isEmpty; } public int capacity() { return length; } /** * Adjusts the capacity of this buffer. Size increases are NOT supported. * * @param newCapacity Must be in in the range [0, length). */ public synchronized ArrowBuf capacity(int newCapacity) { if (newCapacity == length) { return this; } Preconditions.checkArgument(newCapacity >= 0); if (newCapacity < length) { length = newCapacity; return this; } throw new UnsupportedOperationException("Buffers don't support resizing that increases the size."); } /** * Returns the byte order of elements in this buffer. */ public ByteOrder order() { return ByteOrder.LITTLE_ENDIAN; } /** * Returns the number of bytes still available to read in this buffer. */ public int readableBytes() { Preconditions.checkState(writerIndex >= readerIndex, "Writer index cannot be less than reader index"); return writerIndex - readerIndex; } /** * Returns the number of bytes still available to write into this buffer before capacity is reached. */ public int writableBytes() { return capacity() - writerIndex; } /** * Returns a slice of only the readable bytes in the buffer. */ public ArrowBuf slice() { return slice(readerIndex, readableBytes()); } /** * Returns a slice (view) starting at index with the given length. */ public ArrowBuf slice(int index, int length) { if (isEmpty) { return this; } Preconditions.checkPositionIndex(index, this.length); Preconditions.checkPositionIndex(index + length, this.length); /* * Re the behavior of reference counting, see http://netty.io/wiki/reference-counted-objects * .html#wiki-h3-5, which * explains that derived buffers share their reference count with their parent */ final ArrowBuf newBuf = referenceManager.deriveBuffer(this, index, length); newBuf.writerIndex(length); return newBuf; } public ByteBuffer nioBuffer() { return isEmpty ? ByteBuffer.allocateDirect(0) : asNettyBuffer().nioBuffer(); } public ByteBuffer nioBuffer(int index, int length) { return isEmpty ? ByteBuffer.allocateDirect(0) : asNettyBuffer().nioBuffer(index, length); } public long memoryAddress() { return this.addr; } @Override public String toString() { return String.format("ArrowBuf[%d], address:%d, length:%d", id, memoryAddress(), length); } @Override public int hashCode() { return System.identityHashCode(this); } @Override public boolean equals(Object obj) { // identity equals only. return this == obj; } /* * IMPORTANT NOTE * The data getters and setters work with a caller provided * index. This index is 0 based and since ArrowBuf has access * to a portion of underlying chunk of memory starting at * some address, we convert the given relative index into * absolute index as memory address + index. * * Example: * * Let's say we have an underlying chunk of memory of length 64 bytes * Now let's say we have an ArrowBuf that has access to the chunk * from offset 4 for length of 16 bytes. * * If the starting virtual address of chunk is MAR, then memory * address of this ArrowBuf is MAR + offset -- this is what is stored * in variable addr. See the BufferLedger and AllocationManager code * for the implementation of ReferenceManager that manages a * chunk of memory and creates ArrowBuf with access to a range of * bytes within the chunk (or the entire chunk) * * So now to get/set data, we will do => addr + index * This logic is put in method addr(index) and is frequently * used in get/set data methods to compute the absolute * byte address for get/set operation in the underlying chunk * * @param index the index at which we the user wants to read/write * @return the absolute address within the memory */ private long addr(int index) { return addr + index; } /*-------------------------------------------------* | Following are a set of fast path data set and | | get APIs to write/read data from ArrowBuf | | at a given index (0 based relative to this | | ArrowBuf and not relative to the underlying | | memory chunk). | | | *-------------------------------------------------*/ /** * Helper function to do bounds checking at a particular * index for particular length of data. * @param index index (0 based relative to this ArrowBuf) * @param length provided length of data for get/set */ private void chk(int index, int length) { if (BoundsChecking.BOUNDS_CHECKING_ENABLED) { checkIndexD(index, length); } } private void checkIndexD(int index, int fieldLength) { // check reference count ensureAccessible(); // check bounds Preconditions.checkArgument(fieldLength >= 0, "expecting non-negative data length"); if (index < 0 || index > capacity() - fieldLength) { if (BaseAllocator.DEBUG) { historicalLog.logHistory(logger); } throw new IndexOutOfBoundsException(String.format( "index: %d, length: %d (expected: range(0, %d))", index, fieldLength, capacity())); } } /** * Get long value stored at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be read from * @return 8 byte long value */ public long getLong(int index) { chk(index, LONG_SIZE); return PlatformDependent.getLong(addr(index)); } /** * Set long value at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be written * @param value value to write */ public void setLong(int index, long value) { chk(index, LONG_SIZE); PlatformDependent.putLong(addr(index), value); } /** * Get float value stored at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be read from * @return 4 byte float value */ public float getFloat(int index) { return Float.intBitsToFloat(getInt(index)); } /** * Set float value at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be written * @param value value to write */ public void setFloat(int index, float value) { chk(index, FLOAT_SIZE); PlatformDependent.putInt(addr(index), Float.floatToRawIntBits(value)); } /** * Get double value stored at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be read from * @return 8 byte double value */ public double getDouble(int index) { return Double.longBitsToDouble(getLong(index)); } /** * Set double value at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be written * @param value value to write */ public void setDouble(int index, double value) { chk(index, DOUBLE_SIZE); PlatformDependent.putLong(addr(index), Double.doubleToRawLongBits(value)); } /** * Get char value stored at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be read from * @return 2 byte char value */ public char getChar(int index) { return (char) getShort(index); } /** * Set char value at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be written * @param value value to write */ public void setChar(int index, int value) { chk(index, SHORT_SIZE); PlatformDependent.putShort(addr(index), (short) value); } /** * Get int value stored at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be read from * @return 4 byte int value */ public int getInt(int index) { chk(index, INT_SIZE); return PlatformDependent.getInt(addr(index)); } /** * Set int value at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be written * @param value value to write */ public void setInt(int index, int value) { chk(index, INT_SIZE); PlatformDependent.putInt(addr(index), value); } /** * Get short value stored at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be read from * @return 2 byte short value */ public short getShort(int index) { chk(index, SHORT_SIZE); return PlatformDependent.getShort(addr(index)); } /** * Set short value at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be written * @param value value to write */ public void setShort(int index, int value) { setShort(index, (short)value); } /** * Set short value at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be written * @param value value to write */ public void setShort(int index, short value) { chk(index, SHORT_SIZE); PlatformDependent.putShort(addr(index), value); } /** * Set byte value at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be written * @param value value to write */ public void setByte(int index, int value) { chk(index, 1); PlatformDependent.putByte(addr(index), (byte) value); } /** * Set byte value at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be written * @param value value to write */ public void setByte(int index, byte value) { chk(index, 1); PlatformDependent.putByte(addr(index), value); } /** * Get byte value stored at a particular index in the * underlying memory chunk this ArrowBuf has access to. * @param index index (0 based relative to this ArrowBuf) * where the value will be read from * @return byte value */ public byte getByte(int index) { chk(index, 1); return PlatformDependent.getByte(addr(index)); } /*--------------------------------------------------* | Following are another set of data set APIs | | that directly work with writerIndex | | | *--------------------------------------------------*/ /** * Helper function to do bound checking w.r.t writerIndex * by checking if we can set "length" bytes of data at the * writerIndex in this ArrowBuf. * @param length provided length of data for set */ private void ensureWritable(final int length) { if (BoundsChecking.BOUNDS_CHECKING_ENABLED) { Preconditions.checkArgument(length >= 0, "expecting non-negative length"); // check reference count this.ensureAccessible(); // check bounds if (length > writableBytes()) { throw new IndexOutOfBoundsException( String.format("writerIndex(%d) + length(%d) exceeds capacity(%d)", writerIndex, length, capacity())); } } } /** * Helper function to do bound checking w.r.t readerIndex * by checking if we can read "length" bytes of data at the * readerIndex in this ArrowBuf. * @param length provided length of data for get */ private void ensureReadable(final int length) { if (BoundsChecking.BOUNDS_CHECKING_ENABLED) { Preconditions.checkArgument(length >= 0, "expecting non-negative length"); // check reference count this.ensureAccessible(); // check bounds if (length > readableBytes()) { throw new IndexOutOfBoundsException( String.format("readerIndex(%d) + length(%d) exceeds writerIndex(%d)", readerIndex, length, writerIndex)); } } } /** * Read the byte at readerIndex. * @return byte value */ public byte readByte() { ensureReadable(1); final byte b = getByte(readerIndex); ++readerIndex; return b; } /** * Read dst.length bytes at readerIndex into dst byte array * @param dst byte array where the data will be written */ public void readBytes(byte[] dst) { Preconditions.checkArgument(dst != null, "expecting valid dst bytearray"); ensureReadable(dst.length); getBytes(readerIndex, dst, 0, dst.length); } /** * Set the provided byte value at the writerIndex. * @param value value to set */ public void writeByte(byte value) { ensureWritable(1); PlatformDependent.putByte(addr(writerIndex), value); ++writerIndex; } /** * Set the lower order byte for the provided value at * the writerIndex. * @param value value to be set */ public void writeByte(int value) { ensureWritable(1); PlatformDependent.putByte(addr(writerIndex), (byte)value); ++writerIndex; } /** * Write the bytes from given byte array into this * ArrowBuf starting at writerIndex. * @param src src byte array */ public void writeBytes(byte[] src) { Preconditions.checkArgument(src != null, "expecting valid src array"); writeBytes(src, 0, src.length); } /** * Write the bytes from given byte array starting at srcIndex * into this ArrowBuf starting at writerIndex. * @param src src byte array * @param srcIndex index in the byte array where the copy will being from * @param length length of data to copy */ public void writeBytes(byte[] src, int srcIndex, int length) { ensureWritable(length); setBytes(writerIndex, src, srcIndex, length); writerIndex += length; } /** * Set the provided int value as short at the writerIndex. * @param value value to set */ public void writeShort(int value) { ensureWritable(SHORT_SIZE); PlatformDependent.putShort(addr(writerIndex), (short) value); writerIndex += SHORT_SIZE; } /** * Set the provided int value at the writerIndex. * @param value value to set */ public void writeInt(int value) { ensureWritable(INT_SIZE); PlatformDependent.putInt(addr(writerIndex), value); writerIndex += INT_SIZE; } /** * Set the provided long value at the writerIndex. * @param value value to set */ public void writeLong(long value) { ensureWritable(LONG_SIZE); PlatformDependent.putLong(addr(writerIndex), value); writerIndex += LONG_SIZE; } /** * Set the provided float value at the writerIndex. * @param value value to set */ public void writeFloat(float value) { ensureWritable(FLOAT_SIZE); PlatformDependent.putInt(addr(writerIndex), Float.floatToRawIntBits(value)); writerIndex += FLOAT_SIZE; } /** * Set the provided double value at the writerIndex. * @param value value to set */ public void writeDouble(double value) { ensureWritable(DOUBLE_SIZE); PlatformDependent.putLong(addr(writerIndex), Double.doubleToRawLongBits(value)); writerIndex += DOUBLE_SIZE; } /*--------------------------------------------------* | Following are another set of data set/get APIs | | that read and write stream of bytes from/to byte | | arrays, ByteBuffer, ArrowBuf etc | | | *--------------------------------------------------*/ /** * Determine if the requested {@code index} and {@code length} will fit within {@code capacity}. * @param index The starting index. * @param length The length which will be utilized (starting from {@code index}). * @param capacity The capacity that {@code index + length} is allowed to be within. * @return {@code true} if the requested {@code index} and {@code length} will fit within {@code capacity}. * {@code false} if this would result in an index out of bounds exception. */ private static boolean isOutOfBounds(int index, int length, int capacity) { return (index | length | (index + length) | (capacity - (index + length))) < 0; } private void checkIndex(int index, int fieldLength) { // check reference count this.ensureAccessible(); // check bounds if (isOutOfBounds(index, fieldLength, this.capacity())) { throw new IndexOutOfBoundsException(String.format("index: %d, length: %d (expected: range(0, %d))", index, fieldLength, this.capacity())); } } /** * Copy data from this ArrowBuf at a given index in into destination * byte array. * @param index starting index (0 based relative to the portion of memory) * this ArrowBuf has access to * @param dst byte array to copy the data into */ public void getBytes(int index, byte[] dst) { getBytes(index, dst, 0, dst.length); } /** * Copy data from this ArrowBuf at a given index into destination byte array. * @param index index (0 based relative to the portion of memory * this ArrowBuf has access to) * @param dst byte array to copy the data into * @param dstIndex starting index in dst byte array to copy into * @param length length of data to copy from this ArrowBuf */ public void getBytes(int index, byte[] dst, int dstIndex, int length) { // bound check for this ArrowBuf where the data will be copied from checkIndex(index, length); // null check Preconditions.checkArgument(dst != null, "expecting a valid dst byte array"); // bound check for dst byte array where the data will be copied to if (isOutOfBounds(dstIndex, length, dst.length)) { // not enough space to copy "length" bytes into dst array from dstIndex onwards throw new IndexOutOfBoundsException("Not enough space to copy data into destination" + dstIndex); } if (length != 0) { // copy "length" bytes from this ArrowBuf starting at addr(index) address // into dst byte array at dstIndex onwards PlatformDependent.copyMemory(addr(index), dst, dstIndex, (long)length); } } /** * Copy data from a given byte array into this ArrowBuf starting at * a given index. * @param index starting index (0 based relative to the portion of memory) * this ArrowBuf has access to * @param src byte array to copy the data from */ public void setBytes(int index, byte[] src) { setBytes(index, src, 0, src.length); } /** * Copy data from a given byte array starting at the given source index into * this ArrowBuf at a given index. * @param index index (0 based relative to the portion of memory this ArrowBuf * has access to) * @param src src byte array to copy the data from * @param srcIndex index in the byte array where the copy will start from * @param length length of data to copy from byte array */ public void setBytes(int index, byte[] src, int srcIndex, int length) { // bound check for this ArrowBuf where the data will be copied into checkIndex(index, length); // null check Preconditions.checkArgument(src != null, "expecting a valid src byte array"); // bound check for src byte array where the data will be copied from if (isOutOfBounds(srcIndex, length, src.length)) { // not enough space to copy "length" bytes into dst array from dstIndex onwards throw new IndexOutOfBoundsException("Not enough space to copy data from byte array" + srcIndex); } if (length > 0) { // copy "length" bytes from src byte array at the starting index (srcIndex) // into this ArrowBuf starting at address "addr(index)" PlatformDependent.copyMemory(src, srcIndex, addr(index), (long)length); } } /** * Copy data from this ArrowBuf at a given index into the destination * ByteBuffer. * @param index index (0 based relative to the portion of memory this ArrowBuf * has access to) * @param dst dst ByteBuffer where the data will be copied into */ public void getBytes(int index, ByteBuffer dst) { // bound check for this ArrowBuf where the data will be copied from checkIndex(index, dst.remaining()); // dst.remaining() bytes of data will be copied into dst ByteBuffer if (dst.remaining() != 0) { // address in this ArrowBuf where the copy will begin from final long srcAddress = addr(index); if (dst.isDirect()) { if (dst.isReadOnly()) { throw new ReadOnlyBufferException(); } // copy dst.remaining() bytes of data from this ArrowBuf starting // at address srcAddress into the dst ByteBuffer starting at // address dstAddress final long dstAddress = PlatformDependent.directBufferAddress(dst) + (long)dst.position(); PlatformDependent.copyMemory(srcAddress, dstAddress, (long)dst.remaining()); // after copy, bump the next write position for the dst ByteBuffer dst.position(dst.position() + dst.remaining()); } else if (dst.hasArray()) { // copy dst.remaining() bytes of data from this ArrowBuf starting // at address srcAddress into the dst ByteBuffer starting at // index dstIndex final int dstIndex = dst.arrayOffset() + dst.position(); PlatformDependent.copyMemory(srcAddress, dst.array(), dstIndex, (long)dst.remaining()); // after copy, bump the next write position for the dst ByteBuffer dst.position(dst.position() + dst.remaining()); } else { throw new UnsupportedOperationException("Copy from this ArrowBuf to ByteBuffer is not supported"); } } } /** * Copy data into this ArrowBuf at a given index onwards from * a source ByteBuffer. * @param index index index (0 based relative to the portion of memory * this ArrowBuf has access to) * @param src src ByteBuffer where the data will be copied from */ public void setBytes(int index, ByteBuffer src) { // bound check for this ArrowBuf where the data will be copied into checkIndex(index, src.remaining()); // length of data to copy int length = src.remaining(); // address in this ArrowBuf where the data will be copied to long dstAddress = addr(index); if (length != 0) { if (src.isDirect()) { // copy src.remaining() bytes of data from src ByteBuffer starting at // address srcAddress into this ArrowBuf starting at address dstAddress final long srcAddress = PlatformDependent.directBufferAddress(src) + (long)src.position(); PlatformDependent.copyMemory(srcAddress, dstAddress, (long)length); // after copy, bump the next read position for the src ByteBuffer src.position(src.position() + length); } else if (src.hasArray()) { // copy src.remaining() bytes of data from src ByteBuffer starting at // index srcIndex into this ArrowBuf starting at address dstAddress final int srcIndex = src.arrayOffset() + src.position(); PlatformDependent.copyMemory(src.array(), srcIndex, dstAddress, (long)length); // after copy, bump the next read position for the src ByteBuffer src.position(src.position() + length); } else { // copy word at a time while (length >= LONG_SIZE) { PlatformDependent.putLong(dstAddress, src.getLong()); length -= LONG_SIZE; dstAddress += LONG_SIZE; } // copy last byte while (length > 0) { PlatformDependent.putByte(dstAddress, src.get()); --length; ++dstAddress; } } } } /** * Copy data into this ArrowBuf at a given index onwards from * a source ByteBuffer starting at a given srcIndex for a certain * length. * @param index index (0 based relative to the portion of memory * this ArrowBuf has access to) * @param src src ByteBuffer where the data will be copied from * @param srcIndex starting index in the src ByteBuffer where the data copy * will start from * @param length length of data to copy from src ByteBuffer */ public void setBytes(int index, ByteBuffer src, int srcIndex, int length) { // bound check for this ArrowBuf where the data will be copied into checkIndex(index, length); if (src.isDirect()) { // copy length bytes of data from src ByteBuffer starting at address // srcAddress into this ArrowBuf at address dstAddress final long srcAddress = PlatformDependent.directBufferAddress(src) + (long)srcIndex; final long dstAddress = addr(index); PlatformDependent.copyMemory(srcAddress, dstAddress, (long)length); } else { if (srcIndex == 0 && src.capacity() == length) { // copy the entire ByteBuffer from start to end of length setBytes(index, src); } else { ByteBuffer newBuf = src.duplicate(); newBuf.position(srcIndex); newBuf.limit(srcIndex + length); setBytes(index, newBuf); } } } /** * Copy a given length of data from this ArrowBuf starting at a given index * into a dst ArrowBuf at dstIndex. * @param index index (0 based relative to the portion of memory * this ArrowBuf has access to) * @param dst dst ArrowBuf where the data will be copied into * @param dstIndex index (0 based relative to the portion of memory * dst ArrowBuf has access to) * @param length length of data to copy */ public void getBytes(int index, ArrowBuf dst, int dstIndex, int length) { // bound check for this ArrowBuf where the data will be copied from checkIndex(index, length); // bound check for this ArrowBuf where the data will be copied into Preconditions.checkArgument(dst != null, "expecting a valid ArrowBuf"); // bound check for dst ArrowBuf if (isOutOfBounds(dstIndex, length, dst.capacity())) { throw new IndexOutOfBoundsException(String.format("index: %d, length: %d (expected: range(0, %d))", dstIndex, length, dst.capacity())); } if (length != 0) { // copy length bytes of data from this ArrowBuf starting at // address srcAddress into dst ArrowBuf starting at address // dstAddress final long srcAddress = addr(index); final long dstAddress = dst.memoryAddress() + (long)dstIndex; PlatformDependent.copyMemory(srcAddress, dstAddress, (long)length); } } /** * Copy data from src ArrowBuf starting at index srcIndex into this * ArrowBuf at given index. * @param index index index (0 based relative to the portion of memory * this ArrowBuf has access to) * @param src src ArrowBuf where the data will be copied from * @param srcIndex starting index in the src ArrowBuf where the copy * will begin from * @param length length of data to copy from src ArrowBuf */ public void setBytes(int index, ArrowBuf src, int srcIndex, int length) { // bound check for this ArrowBuf where the data will be copied into checkIndex(index, length); // null check Preconditions.checkArgument(src != null, "expecting a valid ArrowBuf"); // bound check for src ArrowBuf if (isOutOfBounds(srcIndex, length, src.capacity())) { throw new IndexOutOfBoundsException(String.format("index: %d, length: %d (expected: range(0, %d))", index, length, src.capacity())); } if (length != 0) { // copy length bytes of data from src ArrowBuf starting at // address srcAddress into this ArrowBuf starting at address // dstAddress final long srcAddress = src.memoryAddress() + (long)srcIndex; final long dstAddress = addr(index); PlatformDependent.copyMemory(srcAddress, dstAddress, (long)length); } } /** * Copy readableBytes() number of bytes from src ArrowBuf * starting from its readerIndex into this ArrowBuf starting * at the given index. * @param index index index (0 based relative to the portion of memory * this ArrowBuf has access to) * @param src src ArrowBuf where the data will be copied from */ public void setBytes(int index, ArrowBuf src) { // null check Preconditions.checkArgument(src != null, "expecting valid ArrowBuf"); final int length = src.readableBytes(); // bound check for this ArrowBuf where the data will be copied into checkIndex(index, length); final long srcAddress = src.memoryAddress() + (long)src.readerIndex; final long dstAddress = addr(index); PlatformDependent.copyMemory(srcAddress, dstAddress, (long)length); src.readerIndex(src.readerIndex + length); } /** * Copy a certain length of bytes from given InputStream * into this ArrowBuf at the provided index. * @param index index index (0 based relative to the portion of memory * this ArrowBuf has access to) * @param in src stream to copy from * @param length length of data to copy * @return number of bytes copied from stream into ArrowBuf * @throws IOException on failing to read from stream */ public int setBytes(int index, InputStream in, int length) throws IOException { Preconditions.checkArgument(in != null, "expecting valid input stream"); checkIndex(index, length); int readBytes = 0; if (length > 0) { byte[] tmp = new byte[length]; // read the data from input stream into tmp byte array readBytes = in.read(tmp); if (readBytes > 0) { // copy readBytes length of data from the tmp byte array starting // at srcIndex 0 into this ArrowBuf starting at address addr(index) PlatformDependent.copyMemory(tmp, 0, addr(index), readBytes); } } return readBytes; } /** * Copy a certain length of bytes from this ArrowBuf at a given * index into the given OutputStream. * @param index index index (0 based relative to the portion of memory * this ArrowBuf has access to) * @param out dst stream to copy data into * @param length length of data to copy * @throws IOException on failing to write to stream */ public void getBytes(int index, OutputStream out, int length) throws IOException { Preconditions.checkArgument(out != null, "expecting valid output stream"); checkIndex(index, length); if (length > 0) { // copy length bytes of data from this ArrowBuf starting at // address addr(index) into the tmp byte array starting at index 0 byte[] tmp = new byte[length]; PlatformDependent.copyMemory(addr(index), tmp, 0, length); // write the copied data to output stream out.write(tmp); } } @Override public void close() { referenceManager.release(); } /** * Returns the possible memory consumed by this ArrowBuf in the worse case scenario. * (not shared, connected to larger underlying buffer of allocated memory) * @return Size in bytes. */ public int getPossibleMemoryConsumed() { return isEmpty ? 0 : referenceManager.getSize(); } /** * Return that is Accounted for by this buffer (and its potentially shared siblings within the * context of the associated allocator). * @return Size in bytes. */ public int getActualMemoryConsumed() { return isEmpty ? 0 : referenceManager.getAccountedSize(); } /** * Return the buffer's byte contents in the form of a hex dump. * * @param start the starting byte index * @param length how many bytes to log * @return A hex dump in a String. */ public String toHexString(final int start, final int length) { final int roundedStart = (start / LOG_BYTES_PER_ROW) * LOG_BYTES_PER_ROW; final StringBuilder sb = new StringBuilder("buffer byte dump\n"); int index = roundedStart; for (int nLogged = 0; nLogged < length; nLogged += LOG_BYTES_PER_ROW) { sb.append(String.format(" [%05d-%05d]", index, index + LOG_BYTES_PER_ROW - 1)); for (int i = 0; i < LOG_BYTES_PER_ROW; ++i) { try { final byte b = getByte(index++); sb.append(String.format(" 0x%02x", b)); } catch (IndexOutOfBoundsException ioob) { sb.append(" "); } } sb.append('\n'); } return sb.toString(); } /** * Get the integer id assigned to this ArrowBuf for debugging purposes. * @return integer id */ public long getId() { return id; } /** * Prints information of this buffer into sb at the given * indentation and verbosity level. * *

It will include history if BaseAllocator.DEBUG is true and * the verbosity.includeHistoricalLog are true. * */ public void print(StringBuilder sb, int indent, Verbosity verbosity) { BaseAllocator.indent(sb, indent).append(toString()); if (BaseAllocator.DEBUG && !isEmpty && verbosity.includeHistoricalLog) { sb.append("\n"); historicalLog.buildHistory(sb, indent + 1, verbosity.includeStackTraces); } } /** * Get the index at which the next byte will be read from. * @return reader index */ public int readerIndex() { return readerIndex; } /** * Get the index at which next byte will be written to. * @return writer index */ public int writerIndex() { return writerIndex; } /** * Set the reader index for this ArrowBuf. * @param readerIndex new reader index * @return this ArrowBuf */ public ArrowBuf readerIndex(int readerIndex) { this.readerIndex = readerIndex; return this; } /** * Set the writer index for this ArrowBuf. * @param writerIndex new writer index * @return this ArrowBuf */ public ArrowBuf writerIndex(int writerIndex) { this.writerIndex = writerIndex; return this; } /** * Zero-out the bytes in this ArrowBuf starting at * the given index for the given length. * @param index index index (0 based relative to the portion of memory * this ArrowBuf has access to) * @param length length of bytes to zero-out * @return this ArrowBuf */ public ArrowBuf setZero(int index, int length) { if (length != 0) { this.checkIndex(index, length); PlatformDependent.setMemory(this.addr + index, length, (byte) 0); } return this; } /** * Returns this if size is less then {@link #capacity()}, otherwise * delegates to {@link BufferManager#replace(ArrowBuf, int)} to get a new buffer. */ public ArrowBuf reallocIfNeeded(final int size) { Preconditions.checkArgument(size >= 0, "reallocation size must be non-negative"); if (this.capacity() >= size) { return this; } if (bufferManager != null) { return bufferManager.replace(this, size); } else { throw new UnsupportedOperationException( "Realloc is only available in the context of operator's UDFs"); } } /** * Following are wrapper methods to keep this backward compatible. */ @Deprecated public void release() { referenceManager.release(); } @Deprecated public void release(int decrement) { referenceManager.release(decrement); } @Deprecated public void retain() { referenceManager.retain(); } @Deprecated public void retain(int increment) { referenceManager.retain(increment); } @Deprecated public ArrowBuf clear() { this.readerIndex = this.writerIndex = 0; return this; } /** * Initialize the reader and writer index. * @param readerIndex index to read from * @param writerIndex index to write to * @return this */ @Deprecated public ArrowBuf setIndex(int readerIndex, int writerIndex) { if (readerIndex >= 0 && readerIndex <= writerIndex && writerIndex <= this.capacity()) { this.readerIndex = readerIndex; this.writerIndex = writerIndex; return this; } else { throw new IndexOutOfBoundsException(String.format("readerIndex: %d, writerIndex: %d " + "(expected:0 <= readerIndex <= writerIndex <= capacity(%d))", readerIndex, writerIndex, this.capacity())); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy