Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,135 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
+
+import java.util.logging.Logger;
+
+/**
+ * Provides access to direct (native) memory.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+@SuppressWarnings("restriction")
+final class AllocateDirect {
+ static final Logger LOG =
Logger.getLogger(AllocateDirect.class.getCanonicalName());
+
+ private final Deallocator deallocator;
+ private final long nativeBaseOffset;
+ private final MemoryCleaner cleaner;
+
+ /**
+ * Base Constructor for allocate native memory.
+ *
+ * <p>Allocates and provides access to capacityBytes directly in native
(off-heap) memory
+ * leveraging the MemoryImpl interface.
+ * The allocated memory will be 8-byte aligned, but may not be page aligned.
+ * @param capacityBytes the the requested capacity of off-heap memory.
Cannot be zero.
+ */
+ AllocateDirect(final long capacityBytes) {
+ final boolean pageAligned = NioBits.isPageAligned();
+ final long pageSize = NioBits.pageSize();
+ final long allocationSize = capacityBytes + (pageAligned ? pageSize : 0);
+ NioBits.reserveMemory(allocationSize, capacityBytes);
+
+ final long nativeAddress;
+ try {
+ nativeAddress = unsafe.allocateMemory(allocationSize);
+ } catch (final OutOfMemoryError err) {
+ NioBits.unreserveMemory(allocationSize, capacityBytes);
+ throw new RuntimeException(err);
+ }
+ if (pageAligned && ((nativeAddress % pageSize) != 0)) {
+ //Round up to page boundary
+ nativeBaseOffset = (nativeAddress & ~(pageSize - 1L)) + pageSize;
+ } else {
+ nativeBaseOffset = nativeAddress;
+ }
+ deallocator = new Deallocator(nativeAddress, allocationSize,
capacityBytes);
+ cleaner = new MemoryCleaner(this, deallocator);
+ }
+
+ boolean doClose() {
+ try {
+ if (deallocator.deallocate(false)) {
+ // This Cleaner.clean() call effectively just removes the Cleaner from
the internal linked
+ // list of all cleaners. It will delegate to Deallocator.deallocate()
which will be a no-op
+ // because the valid state is already changed.
+ cleaner.clean();
+ return true;
+ }
+ return false;
+ } finally {
+ BaseStateImpl.reachabilityFence(this);
+ }
+ }
+
+ long getNativeBaseOffset() {
+ return nativeBaseOffset;
+ }
+
+ StepBoolean getValid() {
+ return deallocator.getValid();
+ }
+
+ static final class Deallocator implements Runnable {
+ //This is the only place the actual native address is kept for use by
unsafe.freeMemory();
+ private final long nativeAddress;
+ private final long allocationSize;
+ private final long capacity;
+ private final StepBoolean valid = new StepBoolean(true); //only place for
this
+
+ Deallocator(final long nativeAddress, final long allocationSize, final
long capacity) {
+ BaseStateImpl.currentDirectMemoryAllocations_.incrementAndGet();
+ BaseStateImpl.currentDirectMemoryAllocated_.addAndGet(capacity);
+ this.nativeAddress = nativeAddress;
+ this.allocationSize = allocationSize;
+ this.capacity = capacity;
+ assert (nativeAddress != 0);
+ }
+
+ StepBoolean getValid() {
+ return valid;
+ }
+
+ @Override
+ public void run() {
+ deallocate(true);
+ }
+
+ boolean deallocate(final boolean calledFromCleaner) {
+ if (valid.change()) {
+ if (calledFromCleaner) {
+ // Warn about non-deterministic resource cleanup.
+ LOG.warning("A WritableHandle was not closed manually");
+ }
+ unsafe.freeMemory(nativeAddress);
+ NioBits.unreserveMemory(allocationSize, capacity);
+ BaseStateImpl.currentDirectMemoryAllocations_.decrementAndGet();
+ BaseStateImpl.currentDirectMemoryAllocated_.addAndGet(-capacity);
+ return true;
+ }
+ return false;
+ }
+ }
+
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java
------------------------------------------------------------------------------
svn:executable = *
Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,316 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.logging.Logger;
+
+import org.apache.datasketches.memory.Map;
+import org.apache.datasketches.memory.MemoryCloseException;
+
+import sun.nio.ch.FileChannelImpl;
+
+/**
+ * Allocates direct memory used to memory map files for read operations.
+ * (including those > 2GB).
+ *
+ * <p>To understand how it works, reference native code for map0, unmap0:
+ * <a
href="http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/solaris/native/sun/nio/ch/FileChannelImpl.c">
+ * FileChannelImpl.c</a></p>
+ *
+ * <p>To understand how it works, reference native code for load0(),
isLoaded0(), and force0():
+ * <a
href="http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/solaris/native/java/nio/MappedByteBuffer.c">
+ * MappedByteBuffer.c</a></p>
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ * @author Praveenkumar Venkatesan
+ */
+@SuppressWarnings("restriction")
+class AllocateDirectMap implements Map {
+ static final Logger LOG =
Logger.getLogger(AllocateDirectMap.class.getCanonicalName());
+
+ private static final int MAP_RO = 0;
+ private static final int MAP_RW = 1;
+
+ private static final Method FILE_CHANNEL_IMPL_MAP0_METHOD;
+ static final Method FILE_CHANNEL_IMPL_UNMAP0_METHOD;
+
+ private static final Method MAPPED_BYTE_BUFFER_LOAD0_METHOD;
+ private static final Method MAPPED_BYTE_BUFFER_ISLOADED0_METHOD;
+ static final Method MAPPED_BYTE_BUFFER_FORCE0_METHOD;
+
+ static {
+ try { //The FileChannelImpl methods map0 and unmap0 still exist in 16
+ FILE_CHANNEL_IMPL_MAP0_METHOD = FileChannelImpl.class
+ .getDeclaredMethod("map0", int.class, long.class, long.class);
//JDK14 add boolean.class
+ FILE_CHANNEL_IMPL_MAP0_METHOD.setAccessible(true);
+
+ FILE_CHANNEL_IMPL_UNMAP0_METHOD = FileChannelImpl.class
+ .getDeclaredMethod("unmap0", long.class, long.class); //OK through
jDK16
+ FILE_CHANNEL_IMPL_UNMAP0_METHOD.setAccessible(true);
+
+
+ //The MappedByteBuffer methods load0, isLoaded0 and force0 are removed
in 15
+ MAPPED_BYTE_BUFFER_LOAD0_METHOD = MappedByteBuffer.class
+ .getDeclaredMethod("load0", long.class, long.class); //JDK15 removed
+ MAPPED_BYTE_BUFFER_LOAD0_METHOD.setAccessible(true);
+
+ MAPPED_BYTE_BUFFER_ISLOADED0_METHOD = MappedByteBuffer.class
+ .getDeclaredMethod("isLoaded0", long.class, long.class, int.class);
//JDK15 removed
+ MAPPED_BYTE_BUFFER_ISLOADED0_METHOD.setAccessible(true);
+
+ MAPPED_BYTE_BUFFER_FORCE0_METHOD = MappedByteBuffer.class
+ .getDeclaredMethod("force0", FileDescriptor.class, long.class,
long.class); //JDK15 removed
+ MAPPED_BYTE_BUFFER_FORCE0_METHOD.setAccessible(true);
+ } catch (final SecurityException | NoSuchMethodException e) {
+ throw new RuntimeException("Could not reflect static methods: " + e);
+ }
+ }
+
+ private final Deallocator deallocator;
+ private final MemoryCleaner cleaner;
+
+ final long capacityBytes;
+ final RandomAccessFile raf;
+ final long nativeBaseOffset;
+ final boolean resourceReadOnly;
+
+ //called from AllocateDirectWritableMap constructor
+ AllocateDirectMap(final File file, final long fileOffsetBytes, final long
capacityBytes,
+ final boolean localReadOnly) {
+ this.capacityBytes = capacityBytes;
+ resourceReadOnly = isFileReadOnly(file);
+ final long fileLength = file.length();
+ if ((localReadOnly || resourceReadOnly) && fileOffsetBytes + capacityBytes
> fileLength) {
+ throw new IllegalArgumentException(
+ "Read-only mode and requested map length is greater than current
file length: "
+ + "Requested Length = " + (fileOffsetBytes + capacityBytes)
+ + ", Current File Length = " + fileLength);
+ }
+ raf = mapper(file, fileOffsetBytes, capacityBytes, resourceReadOnly);
+ nativeBaseOffset = map(raf.getChannel(), resourceReadOnly,
fileOffsetBytes, capacityBytes);
+ deallocator = new Deallocator(nativeBaseOffset, capacityBytes, raf);
+ cleaner = new MemoryCleaner(this, deallocator);
+ }
+
+ //Map Interface
+
+ @Override
+ public void load() {
+ madvise();
+ // Performance optimization. Read a byte from each page to bring it into
memory.
+ final int ps = NioBits.pageSize();
+ final int count = NioBits.pageCount(capacityBytes);
+ long offset = nativeBaseOffset;
+ for (int i = 0; i < count; i++) {
+ unsafe.getByte(offset);
+ offset += ps;
+ }
+ }
+
+ @Override
+ public boolean isLoaded() {
+ try {
+ final int pageCount = NioBits.pageCount(capacityBytes);
+ return (boolean) MAPPED_BYTE_BUFFER_ISLOADED0_METHOD
+ //isLoaded0 is effectively static, so
ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is not modified
+ .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
+ nativeBaseOffset,
+ capacityBytes,
+ pageCount);
+ } catch (final IllegalAccessException | IllegalArgumentException |
InvocationTargetException e) {
+ throw new RuntimeException(
+ String.format("Encountered %s exception while loading",
e.getClass()));
+ }
+ }
+ // End Map Interface
+
+ @Override
+ public void close() {
+ doClose("AllocateDirectMap");
+ }
+
+ boolean doClose(final String resource) {
+ try {
+ if (deallocator.deallocate(false)) {
+ // This Cleaner.clean() call effectively just removes the Cleaner from
the internal linked
+ // list of all cleaners. It will delegate to Deallocator.deallocate()
which will be a no-op
+ // because the valid state is already changed.
+ cleaner.clean();
+ return true;
+ }
+ return false;
+ } catch (final Exception e) {
+ throw new MemoryCloseException(resource);
+ } finally {
+ BaseStateImpl.reachabilityFence(this);
+ }
+ }
+
+ StepBoolean getValid() {
+ return deallocator.getValid();
+ }
+
+ // Private methods
+ /**
+ * called by load(). Calls the native method load0 in MappedByteBuffer.java,
implemented
+ * in MappedByteBuffer.c. See reference at top of class. load0 allows
setting a mapping length
+ * of greater than 2GB.
+ */
+ private void madvise() {
+ try {
+ MAPPED_BYTE_BUFFER_LOAD0_METHOD
+ //load0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is
not modified
+ .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
+ nativeBaseOffset,
+ capacityBytes);
+ } catch (final IllegalAccessException | IllegalArgumentException |
InvocationTargetException e) {
+ throw new RuntimeException(
+ String.format("Encountered %s exception while loading",
e.getClass()));
+ }
+ }
+
+ //Does the actual mapping work, resourceReadOnly must already be set
+ private static RandomAccessFile mapper(final File file, final long
fileOffset,
+ final long capacityBytes, final boolean resourceReadOnly) {
+
+ final String mode = resourceReadOnly ? "r" : "rw";
+ final RandomAccessFile raf;
+ try {
+ raf = new RandomAccessFile(file, mode);
+ if (fileOffset + capacityBytes > raf.length()) {
+ raf.setLength(fileOffset + capacityBytes);
+ }
+ } catch (final IOException e) {
+ throw new RuntimeException(e);
+ }
+ return raf;
+ }
+
+ /**
+ * Creates a mapping of the FileChannel starting at position and of size
length to pages
+ * in the OS. This may throw OutOfMemory error if you have exhausted memory.
+ * You can try to force garbage collection and re-attempt.
+ *
+ * <p>map0 is a native method of FileChannelImpl.java implemented in
FileChannelImpl.c.
+ * See reference at top of class.</p>
+ *
+ * @param fileChannel the FileChannel
+ * @param position the offset in bytes into the FileChannel
+ * @param lengthBytes the length in bytes
+ * @return the native base offset address
+ * @throws RuntimeException Encountered an exception while mapping
+ */
+ private static long map(final FileChannel fileChannel, final boolean
resourceReadOnly,
+ final long position, final long lengthBytes) {
+ final int pagePosition = (int) (position % unsafe.pageSize());
+ final long mapPosition = position - pagePosition;
+ final long mapSize = lengthBytes + pagePosition;
+ final int mapMode = resourceReadOnly ? MAP_RO : MAP_RW;
+ //final boolean isSync = true; //required as of JDK14, but it is more
complex
+ try {
+ final long nativeBaseOffset = //JDK14 add isSync
+ (long) FILE_CHANNEL_IMPL_MAP0_METHOD.invoke(fileChannel, mapMode,
mapPosition, mapSize);
+ return nativeBaseOffset;
+ } catch (final InvocationTargetException e) {
+ throw new RuntimeException("Exception while mapping",
e.getTargetException());
+ } catch (final IllegalAccessException e) {
+ throw new RuntimeException("Exception while mapping", e);
+ }
+ }
+
+ public static boolean isFileReadOnly(final File file) {
+ return (!file.canWrite());
+ }
+
+ private static final class Deallocator implements Runnable {
+ private final RandomAccessFile myRaf;
+ private final FileChannel myFc;
+ //This is the only place the actual native offset is kept for use by
unsafe.freeMemory();
+ private final long actualNativeBaseOffset;
+ private final long myCapacity;
+ private final StepBoolean valid = new StepBoolean(true); //only place for
this
+
+ Deallocator(final long nativeBaseOffset, final long capacityBytes,
+ final RandomAccessFile raf) {
+ BaseStateImpl.currentDirectMemoryMapAllocations_.incrementAndGet();
+ BaseStateImpl.currentDirectMemoryMapAllocated_.addAndGet(capacityBytes);
+ myRaf = raf;
+ assert myRaf != null;
+ myFc = myRaf.getChannel();
+ actualNativeBaseOffset = nativeBaseOffset;
+ assert actualNativeBaseOffset != 0;
+ myCapacity = capacityBytes;
+ assert myCapacity != 0;
+ }
+
+ StepBoolean getValid() {
+ return valid;
+ }
+
+ @Override
+ public void run() {
+ deallocate(true);
+ }
+
+ boolean deallocate(final boolean calledFromCleaner) {
+ if (valid.change()) {
+ if (calledFromCleaner) {
+ // Warn about non-deterministic resource cleanup.
+ LOG.warning("A WritableMapHandleImpl was not closed manually");
+ }
+ try {
+ unmap();
+ }
+ finally {
+ BaseStateImpl.currentDirectMemoryMapAllocations_.decrementAndGet();
+
BaseStateImpl.currentDirectMemoryMapAllocated_.addAndGet(-myCapacity);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Removes existing mapping. <i>unmap0</i> is a native method in
FileChannelImpl.c. See
+ * reference at top of class.
+ */
+ private void unmap() throws RuntimeException {
+ try {
+ FILE_CHANNEL_IMPL_UNMAP0_METHOD.invoke(myFc, actualNativeBaseOffset,
myCapacity);
+ myRaf.close();
+ } catch (final IllegalAccessException | IllegalArgumentException |
InvocationTargetException | IOException e) {
+ throw new RuntimeException(
+ String.format("Encountered %s exception while freeing memory",
e.getClass()));
+ }
+ }
+ } //End of class Deallocator
+
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java
------------------------------------------------------------------------------
svn:executable = *
Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,63 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.WritableMap;
+
+/**
+ * Allocates direct memory used to memory map files for write operations
+ * (including those > 2GB).
+ *
+ * @author Lee Rhodes
+ * @author Roman Leventov
+ * @author Praveenkumar Venkatesan
+ */
+//Called from WritableMemoryImpl, implements combo of WritableMemoryImpl with
WritableMap resource
+final class AllocateDirectWritableMap extends AllocateDirectMap implements
WritableMap {
+
+ AllocateDirectWritableMap(final File file, final long fileOffsetBytes,
+ final long capacityBytes, final boolean localReadOnly) {
+ super(file, fileOffsetBytes, capacityBytes, localReadOnly);
+ }
+
+ //Added by WritableMap Interface
+
+ @Override
+ public void force() {
+ if (resourceReadOnly) {
+ throw new ReadOnlyException("MemoryImpl Mapped File is Read Only.");
+ }
+ try {
+ MAPPED_BYTE_BUFFER_FORCE0_METHOD
+ //force0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER
is not modified
+ .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
+ raf.getFD(),
+ nativeBaseOffset,
+ capacityBytes);
+ } catch (final IOException | IllegalAccessException |
IllegalArgumentException | InvocationTargetException e) {
+ throw new RuntimeException(String.format("Encountered %s exception in
force. " + e.getClass()));
+ }
+ }
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java
------------------------------------------------------------------------------
svn:executable = *
Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,117 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+
+/**
+ * Implementation of {@link WritableBuffer} for ByteBuffer, non-native byte
order.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+final class BBNonNativeWritableBufferImpl extends NonNativeWritableBufferImpl {
+ private static final int id = BUFFER | NONNATIVE | BYTEBUF;
+ private final Object unsafeObj;
+ private final long nativeBaseOffset; //used to compute cumBaseOffset
+ private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until
we are done with it.
+ private final MemoryRequestServer memReqSvr;
+ private final byte typeId;
+
+ BBNonNativeWritableBufferImpl(
+ final Object unsafeObj,
+ final long nativeBaseOffset,
+ final long regionOffset,
+ final long capacityBytes,
+ final int typeId,
+ final ByteBuffer byteBuf,
+ final MemoryRequestServer memReqSvr) {
+ super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+ this.unsafeObj = unsafeObj;
+ this.nativeBaseOffset = nativeBaseOffset;
+ this.byteBuf = byteBuf;
+ this.memReqSvr = memReqSvr;
+ this.typeId = (byte) (id | (typeId & 0x7));
+ }
+
+ @Override
+ BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long
capacityBytes,
+ final boolean readOnly, final ByteOrder byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly) | REGION;
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes),
capacityBytes, type, byteBuf, memReqSvr)
+ : new BBNonNativeWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes),
capacityBytes, type, byteBuf, memReqSvr);
+ }
+
+ @Override
+ BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder
byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr)
+ : new BBNonNativeWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr);
+ }
+
+ @Override
+ BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final
ByteOrder byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly);
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableMemoryImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr)
+ : new BBNonNativeWritableMemoryImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr);
+ }
+
+ @Override
+ public ByteBuffer getByteBuffer() {
+ assertValid();
+ return byteBuf;
+ }
+
+ @Override
+ public MemoryRequestServer getMemoryRequestServer() {
+ assertValid();
+ return memReqSvr;
+ }
+
+ @Override
+ long getNativeBaseOffset() {
+ return nativeBaseOffset;
+ }
+
+ @Override
+ int getTypeId() {
+ return typeId & 0xff;
+ }
+
+ @Override
+ Object getUnsafeObject() {
+ assertValid();
+ return unsafeObj;
+ }
+
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
------------------------------------------------------------------------------
svn:executable = *
Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,107 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+
+/**
+ * Implementation of {@link WritableMemory} for ByteBuffer, non-native byte
order.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+final class BBNonNativeWritableMemoryImpl extends NonNativeWritableMemoryImpl {
+ private static final int id = MEMORY | NONNATIVE | BYTEBUF;
+ private final Object unsafeObj;
+ private final long nativeBaseOffset; //used to compute cumBaseOffset
+ private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until
we are done with it.
+ private final MemoryRequestServer memReqSvr;
+ private final byte typeId;
+
+ BBNonNativeWritableMemoryImpl(
+ final Object unsafeObj,
+ final long nativeBaseOffset,
+ final long regionOffset,
+ final long capacityBytes,
+ final int typeId,
+ final ByteBuffer byteBuf,
+ final MemoryRequestServer memReqSvr) {
+ super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+ this.unsafeObj = unsafeObj;
+ this.nativeBaseOffset = nativeBaseOffset;
+ this.byteBuf = byteBuf;
+ this.memReqSvr = memReqSvr;
+ this.typeId = (byte) (id | (typeId & 0x7));
+ }
+
+ @Override
+ BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long
capacityBytes,
+ final boolean readOnly, final ByteOrder byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly) | REGION;
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableMemoryImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes),
capacityBytes, type, getByteBuffer(), memReqSvr)
+ : new BBNonNativeWritableMemoryImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes),
capacityBytes, type, getByteBuffer(), memReqSvr);
+ }
+
+ @Override
+ BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final
ByteOrder byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly);
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr)
+ : new BBNonNativeWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr);
+ }
+
+ @Override
+ public ByteBuffer getByteBuffer() {
+ assertValid();
+ return byteBuf;
+ }
+
+ @Override
+ public MemoryRequestServer getMemoryRequestServer() {
+ assertValid();
+ return memReqSvr;
+ }
+
+ @Override
+ long getNativeBaseOffset() {
+ return nativeBaseOffset;
+ }
+
+ @Override
+ int getTypeId() {
+ return typeId & 0xff;
+ }
+
+ @Override
+ Object getUnsafeObject() {
+ assertValid();
+ return unsafeObj;
+ }
+
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java
------------------------------------------------------------------------------
svn:executable = *
Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,117 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+
+/**
+ * Implementation of {@link WritableBuffer} for ByteBuffer, native byte order.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+final class BBWritableBufferImpl extends NativeWritableBufferImpl {
+ private static final int id = BUFFER | NATIVE | BYTEBUF;
+ private final Object unsafeObj;
+ private final long nativeBaseOffset; //used to compute cumBaseOffset
+ private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until
we are done with it.
+ private final MemoryRequestServer memReqSvr;
+ private final byte typeId;
+
+ BBWritableBufferImpl(
+ final Object unsafeObj,
+ final long nativeBaseOffset,
+ final long regionOffset,
+ final long capacityBytes,
+ final int typeId,
+ final ByteBuffer byteBuf,
+ final MemoryRequestServer memReqSvr) {
+ super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+ this.unsafeObj = unsafeObj;
+ this.nativeBaseOffset = nativeBaseOffset;
+ this.byteBuf = byteBuf;
+ this.memReqSvr = memReqSvr;
+ this.typeId = (byte) (id | (typeId & 0x7));
+ }
+
+ @Override
+ BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long
capacityBytes,
+ final boolean readOnly, final ByteOrder byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly) | REGION;
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes),
capacityBytes, type, byteBuf, memReqSvr)
+ : new BBNonNativeWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes),
capacityBytes, type, byteBuf, memReqSvr);
+ }
+
+ @Override
+ BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder
byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr)
+ : new BBNonNativeWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr);
+ }
+
+ @Override
+ BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final
ByteOrder byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly);
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableMemoryImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr)
+ : new BBNonNativeWritableMemoryImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr);
+ }
+
+ @Override
+ public ByteBuffer getByteBuffer() {
+ assertValid();
+ return byteBuf;
+ }
+
+ @Override
+ public MemoryRequestServer getMemoryRequestServer() {
+ assertValid();
+ return memReqSvr;
+ }
+
+ @Override
+ long getNativeBaseOffset() {
+ return nativeBaseOffset;
+ }
+
+ @Override
+ int getTypeId() {
+ return typeId & 0xff;
+ }
+
+ @Override
+ Object getUnsafeObject() {
+ assertValid();
+ return unsafeObj;
+ }
+
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
------------------------------------------------------------------------------
svn:executable = *
Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,107 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+
+/**
+ * Implementation of {@link WritableMemory} for ByteBuffer, native byte order.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+final class BBWritableMemoryImpl extends NativeWritableMemoryImpl {
+ private static final int id = MEMORY | NATIVE | BYTEBUF;
+ private final Object unsafeObj;
+ private final long nativeBaseOffset; //used to compute cumBaseOffset
+ private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until
we are done with it.
+ private final MemoryRequestServer memReqSvr;
+ private final byte typeId;
+
+ BBWritableMemoryImpl(
+ final Object unsafeObj,
+ final long nativeBaseOffset,
+ final long regionOffset,
+ final long capacityBytes,
+ final int typeId,
+ final ByteBuffer byteBuf,
+ final MemoryRequestServer memReqSvr) {
+ super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+ this.unsafeObj = unsafeObj;
+ this.nativeBaseOffset = nativeBaseOffset;
+ this.byteBuf = byteBuf;
+ this.memReqSvr = memReqSvr;
+ this.typeId = (byte) (id | (typeId & 0x7));
+ }
+
+ @Override
+ BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long
capacityBytes,
+ final boolean readOnly, final ByteOrder byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly) | REGION;
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableMemoryImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes),
capacityBytes, type, getByteBuffer(), memReqSvr)
+ : new BBNonNativeWritableMemoryImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes),
capacityBytes, type, getByteBuffer(), memReqSvr);
+ }
+
+ @Override
+ BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final
ByteOrder byteOrder) {
+ final int type = setReadOnlyType(typeId, readOnly);
+ return Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr)
+ : new BBNonNativeWritableBufferImpl(
+ unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(),
type, byteBuf, memReqSvr);
+ }
+
+ @Override
+ public ByteBuffer getByteBuffer() {
+ assertValid();
+ return byteBuf;
+ }
+
+ @Override
+ public MemoryRequestServer getMemoryRequestServer() {
+ assertValid();
+ return memReqSvr;
+ }
+
+ @Override
+ long getNativeBaseOffset() {
+ return nativeBaseOffset;
+ }
+
+ @Override
+ int getTypeId() {
+ return typeId & 0xff;
+ }
+
+ @Override
+ Object getUnsafeObject() {
+ assertValid();
+ return unsafeObj;
+ }
+
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java
------------------------------------------------------------------------------
svn:executable = *
Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseBufferImpl.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseBufferImpl.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseBufferImpl.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,218 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import org.apache.datasketches.memory.BaseBuffer;
+import org.apache.datasketches.memory.ReadOnlyException;
+
+/**
+ * A new positional API. This is different from and simpler than Java
BufferImpl positional approach.
+ * <ul><li>All based on longs instead of ints.</li>
+ * <li>Eliminated "mark". Rarely used and confusing with its silent side
effects.</li>
+ * <li>The invariants are {@code 0 <= start <= position <= end <=
capacity}.</li>
+ * <li>It always starts up as (0, 0, capacity, capacity).</li>
+ * <li>You set (start, position, end) in one call with
+ * {@link #setStartPositionEnd(long, long, long)}</li>
+ * <li>Position can be set directly or indirectly when using the positional
get/put methods.
+ * <li>Added incrementPosition(long), which is much easier when you know the
increment.</li>
+ * <li>This approach eliminated a number of methods and checks, and has no
unseen side effects,
+ * e.g., mark being invalidated.</li>
+ * <li>Clearer method naming (IMHO).</li>
+ * </ul>
+ *
+ * @author Lee Rhodes
+ */
+public abstract class BaseBufferImpl extends BaseStateImpl implements
BaseBuffer {
+ private long capacity;
+ private long start = 0;
+ private long pos = 0;
+ private long end;
+
+ //Pass-through ctor
+ BaseBufferImpl(final Object unsafeObj, final long nativeBaseOffset,
+ final long regionOffset, final long capacityBytes) {
+ super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+ capacity = end = capacityBytes;
+ }
+
+ @Override
+ public final BaseBufferImpl incrementPosition(final long increment) {
+ incrementAndAssertPositionForRead(pos, increment);
+ return this;
+ }
+
+ @Override
+ public final BaseBufferImpl incrementAndCheckPosition(final long increment) {
+ incrementAndCheckPositionForRead(pos, increment);
+ return this;
+ }
+
+ @Override
+ public final long getEnd() {
+ return end;
+ }
+
+ @Override
+ public final long getPosition() {
+ return pos;
+ }
+
+ @Override
+ public final long getStart() {
+ return start;
+ }
+
+ @Override
+ public final long getRemaining() {
+ return end - pos;
+ }
+
+ @Override
+ public final boolean hasRemaining() {
+ return (end - pos) > 0;
+ }
+
+ @Override
+ public final BaseBufferImpl resetPosition() {
+ pos = start;
+ return this;
+ }
+
+ @Override
+ public final BaseBufferImpl setPosition(final long position) {
+ assertInvariants(start, position, end, capacity);
+ pos = position;
+ return this;
+ }
+
+ @Override
+ public final BaseBufferImpl setAndCheckPosition(final long position) {
+ checkInvariants(start, position, end, capacity);
+ pos = position;
+ return this;
+ }
+
+ @Override
+ public final BaseBufferImpl setStartPositionEnd(final long start, final long
position,
+ final long end) {
+ assertInvariants(start, position, end, capacity);
+ this.start = start;
+ this.end = end;
+ pos = position;
+ return this;
+ }
+
+ @Override
+ public final BaseBufferImpl setAndCheckStartPositionEnd(final long start,
final long position,
+ final long end) {
+ checkInvariants(start, position, end, capacity);
+ this.start = start;
+ this.end = end;
+ pos = position;
+ return this;
+ }
+
+ //RESTRICTED
+ //Position checks are only used for Buffers
+ //asserts are used for primitives, not used at runtime
+ final void incrementAndAssertPositionForRead(final long position, final long
increment) {
+ assertValid();
+ final long newPos = position + increment;
+ assertInvariants(start, newPos, end, capacity);
+ pos = newPos;
+ }
+
+ final void incrementAndAssertPositionForWrite(final long position, final
long increment) {
+ assertValid();
+ assert !isReadOnly() : "BufferImpl is read-only.";
+ final long newPos = position + increment;
+ assertInvariants(start, newPos, end, capacity);
+ pos = newPos;
+ }
+
+ //checks are used for arrays and apply at runtime
+ final void incrementAndCheckPositionForRead(final long position, final long
increment) {
+ checkValid();
+ final long newPos = position + increment;
+ checkInvariants(start, newPos, end, capacity);
+ pos = newPos;
+ }
+
+ final void incrementAndCheckPositionForWrite(final long position, final long
increment) {
+ checkValidForWrite();
+ final long newPos = position + increment;
+ checkInvariants(start, newPos, end, capacity);
+ pos = newPos;
+ }
+
+ final void checkValidForWrite() {
+ checkValid();
+ if (isReadOnly()) {
+ throw new ReadOnlyException("BufferImpl is read-only.");
+ }
+ }
+
+ /**
+ * The invariants equation is: {@code 0 <= start <= position <= end <=
capacity}.
+ * If this equation is violated and assertions are enabled,
+ * an <i>AssertionError</i> will be thrown.
+ * @param start the lowest start position
+ * @param pos the current position
+ * @param end the highest position
+ * @param cap the capacity of the backing buffer.
+ */
+ static final void assertInvariants(final long start, final long pos, final
long end,
+ final long cap) {
+ assert (start | pos | end | cap | (pos - start) | (end - pos) | (cap -
end) ) >= 0L
+ : "Violation of Invariants: "
+ + "start: " + start
+ + " <= pos: " + pos
+ + " <= end: " + end
+ + " <= cap: " + cap
+ + "; (pos - start): " + (pos - start)
+ + ", (end - pos): " + (end - pos)
+ + ", (cap - end): " + (cap - end);
+ }
+
+ /**
+ * The invariants equation is: {@code 0 <= start <= position <= end <=
capacity}.
+ * If this equation is violated an <i>IllegalArgumentException</i> will be
thrown.
+ * @param start the lowest start position
+ * @param pos the current position
+ * @param end the highest position
+ * @param cap the capacity of the backing buffer.
+ */
+ static final void checkInvariants(final long start, final long pos, final
long end,
+ final long cap) {
+ if ((start | pos | end | cap | (pos - start) | (end - pos) | (cap - end) )
< 0L) {
+ throw new IllegalArgumentException(
+ "Violation of Invariants: "
+ + "start: " + start
+ + " <= pos: " + pos
+ + " <= end: " + end
+ + " <= cap: " + cap
+ + "; (pos - start): " + (pos - start)
+ + ", (end - pos): " + (end - pos)
+ + ", (cap - end): " + (cap - end)
+ );
+ }
+ }
+
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseBufferImpl.java
------------------------------------------------------------------------------
svn:executable = *
Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,495 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.UnsafeUtil.LS;
+import static org.apache.datasketches.memory.internal.UnsafeUtil.assertBounds;
+import static org.apache.datasketches.memory.internal.UnsafeUtil.checkBounds;
+import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.ReadOnlyException;
+
+/**
+ * Keeps key configuration state for MemoryImpl and BufferImpl plus some
common static variables
+ * and check methods.
+ *
+ * @author Lee Rhodes
+ */
+@SuppressWarnings("restriction")
+public abstract class BaseStateImpl implements BaseState {
+
+ //Monitoring
+ static final AtomicLong currentDirectMemoryAllocations_ = new AtomicLong();
+ static final AtomicLong currentDirectMemoryAllocated_ = new AtomicLong();
+ static final AtomicLong currentDirectMemoryMapAllocations_ = new
AtomicLong();
+ static final AtomicLong currentDirectMemoryMapAllocated_ = new AtomicLong();
+
+ //class type IDs. Do not change the bit orders
+ //The first 3 bits are set dynamically
+ // 0000 0XXX
+ static final int READONLY = 1;
+ static final int REGION = 2;
+ static final int DUPLICATE = 4;
+
+ //The following 4 bits are set by the 16 leaf nodes
+ // 000X X000
+ static final int HEAP = 0;
+ static final int DIRECT = 1 << 3;
+ static final int MAP = 2 << 3;
+ static final int BYTEBUF = 3 << 3;
+
+ // 00X0 0000
+ static final int NATIVE = 0;
+ static final int NONNATIVE = 1 << 5;
+
+ // 0X00 0000
+ static final int MEMORY = 0;
+ static final int BUFFER = 1 << 6;
+
+ private final long capacityBytes_;
+
+ /**
+ * This becomes the base offset used by all Unsafe calls. It is cumulative
in that in includes
+ * all offsets from regions, user-defined offsets when creating MemoryImpl,
and the array object
+ * header offset when creating MemoryImpl from primitive arrays.
+ */
+ private final long cumBaseOffset_;
+
+ /**
+ *
+ * @param unsafeObj The primitive backing array. It may be null. Used by
Unsafe calls.
+ * @param nativeBaseOffset The off-heap memory address including
DirectByteBuffer split offsets.
+ * @param regionOffset This offset defines address zero of this object
(usually a region)
+ * relative to address zero of the backing resource. It is used to compute
cumBaseOffset.
+ * This will be loaded from heap ByteBuffers, which have a similar field
used for slices.
+ * It is used by region() and writableRegion().
+ * This offset does not include the size of an object array header, if there
is one.
+ * @param capacityBytes the capacity of this object. Used by all methods
when checking bounds.
+ */
+ BaseStateImpl(final Object unsafeObj, final long nativeBaseOffset, final
long regionOffset,
+ final long capacityBytes) {
+ capacityBytes_ = capacityBytes;
+ cumBaseOffset_ = regionOffset + (unsafeObj == null
+ ? nativeBaseOffset
+ : UnsafeUtil.getArrayBaseOffset(unsafeObj.getClass()));
+ }
+
+ //Byte Order Related
+
+ @Override
+ public final ByteOrder getTypeByteOrder() {
+ return isNonNativeType() ? Util.NON_NATIVE_BYTE_ORDER :
ByteOrder.nativeOrder();
+ }
+
+ /**
+ * Returns true if the given byteOrder is the same as the native byte order.
+ * @param byteOrder the given byte order
+ * @return true if the given byteOrder is the same as the native byte order.
+ */
+ public static boolean isNativeByteOrder(final ByteOrder byteOrder) {
+ if (byteOrder == null) {
+ throw new IllegalArgumentException("ByteOrder parameter cannot be
null.");
+ }
+ return ByteOrder.nativeOrder() == byteOrder;
+ }
+
+ @Override
+ public final boolean isByteOrderCompatible(final ByteOrder byteOrder) {
+ final ByteOrder typeBO = getTypeByteOrder();
+ return typeBO == ByteOrder.nativeOrder() && typeBO == byteOrder;
+ }
+
+ @Override
+ public final boolean equals(final Object that) {
+ if (this == that) { return true; }
+ return that instanceof BaseStateImpl
+ ? CompareAndCopy.equals(this, (BaseStateImpl) that)
+ : false;
+ }
+
+ @Override
+ public final boolean equalTo(final long thisOffsetBytes, final Object that,
+ final long thatOffsetBytes, final long lengthBytes) {
+ return that instanceof BaseStateImpl
+ ? CompareAndCopy.equals(this, thisOffsetBytes, (BaseStateImpl) that,
thatOffsetBytes, lengthBytes)
+ : false;
+ }
+
+ //Overridden by ByteBuffer Leafs
+ @Override
+ public ByteBuffer getByteBuffer() {
+ return null;
+ }
+
+ @Override
+ public final long getCapacity() {
+ assertValid();
+ return capacityBytes_;
+ }
+
+ @Override
+ public final long getCumulativeOffset() {
+ assertValid();
+ return cumBaseOffset_;
+ }
+
+ @Override
+ public final long getCumulativeOffset(final long offsetBytes) {
+ assertValid();
+ return cumBaseOffset_ + offsetBytes;
+ }
+
+ //Documented in WritableMemory and WritableBuffer interfaces.
+ //Implemented in the Leaf nodes; Required here by toHex(...).
+ abstract MemoryRequestServer getMemoryRequestServer();
+
+ //Overridden by ByteBuffer, Direct and Map leafs
+ long getNativeBaseOffset() {
+ return 0;
+ }
+
+ @Override
+ public final long getRegionOffset() {
+ final Object unsafeObj = getUnsafeObject();
+ return unsafeObj == null
+ ? cumBaseOffset_ - getNativeBaseOffset()
+ : cumBaseOffset_ - UnsafeUtil.getArrayBaseOffset(unsafeObj.getClass());
+ }
+
+ @Override
+ public final long getRegionOffset(final long offsetBytes) {
+ return getRegionOffset() + offsetBytes;
+ }
+
+ //Overridden by all leafs
+ abstract int getTypeId();
+
+ //Overridden by Heap and ByteBuffer Leafs. Made public as getArray() in
WritableMemoryImpl and
+ // WritableBufferImpl
+ Object getUnsafeObject() {
+ return null;
+ }
+
+ @Override
+ public final boolean hasArray() {
+ assertValid();
+ return getUnsafeObject() != null;
+ }
+
+ @Override
+ public final int hashCode() {
+ return (int) xxHash64(0, capacityBytes_, 0); //xxHash64() calls
checkValid()
+ }
+
+ @Override
+ public final long xxHash64(final long offsetBytes, final long lengthBytes,
final long seed) {
+ checkValid();
+ return XxHash64.hash(getUnsafeObject(), cumBaseOffset_ + offsetBytes,
lengthBytes, seed);
+ }
+
+ @Override
+ public final long xxHash64(final long in, final long seed) {
+ return XxHash64.hash(in, seed);
+ }
+
+ @Override
+ public final boolean hasByteBuffer() {
+ assertValid();
+ return getByteBuffer() != null;
+ }
+
+ @Override
+ public final boolean isDirect() {
+ return getUnsafeObject() == null;
+ }
+
+ @Override
+ public final boolean isReadOnly() {
+ assertValid();
+ return isReadOnlyType();
+ }
+
+ @Override
+ public final boolean isSameResource(final Object that) {
+ checkValid();
+ if (that == null) { return false; }
+ final BaseStateImpl that1 = (BaseStateImpl) that;
+ that1.checkValid();
+ if (this == that1) { return true; }
+
+ return cumBaseOffset_ == that1.cumBaseOffset_
+ && capacityBytes_ == that1.capacityBytes_
+ && getUnsafeObject() == that1.getUnsafeObject()
+ && getByteBuffer() == that1.getByteBuffer();
+ }
+
+ //Overridden by Direct and Map leafs
+ @Override
+ public boolean isValid() {
+ return true;
+ }
+
+ //ASSERTS AND CHECKS
+ final void assertValid() {
+ assert isValid() : "MemoryImpl not valid.";
+ }
+
+ void checkValid() {
+ if (!isValid()) {
+ throw new IllegalStateException("MemoryImpl not valid.");
+ }
+ }
+
+ final void assertValidAndBoundsForRead(final long offsetBytes, final long
lengthBytes) {
+ assertValid();
+ // capacityBytes_ is intentionally read directly instead of calling
getCapacity()
+ // because the later can make JVM to not inline the assert code path (and
entirely remove it)
+ // even though it does nothing in production code path.
+ assertBounds(offsetBytes, lengthBytes, capacityBytes_);
+ }
+
+ final void assertValidAndBoundsForWrite(final long offsetBytes, final long
lengthBytes) {
+ assertValid();
+ // capacityBytes_ is intentionally read directly instead of calling
getCapacity()
+ // because the later can make JVM to not inline the assert code path (and
entirely remove it)
+ // even though it does nothing in production code path.
+ assertBounds(offsetBytes, lengthBytes, capacityBytes_);
+ assert !isReadOnly() : "MemoryImpl is read-only.";
+ }
+
+ @Override
+ public final void checkValidAndBounds(final long offsetBytes, final long
lengthBytes) {
+ checkValid();
+ //read capacityBytes_ directly to eliminate extra checkValid() call
+ checkBounds(offsetBytes, lengthBytes, capacityBytes_);
+ }
+
+ final void checkValidAndBoundsForWrite(final long offsetBytes, final long
lengthBytes) {
+ checkValid();
+ //read capacityBytes_ directly to eliminate extra checkValid() call
+ checkBounds(offsetBytes, lengthBytes, capacityBytes_);
+ if (isReadOnly()) {
+ throw new ReadOnlyException("MemoryImpl is read-only.");
+ }
+ }
+
+ //TYPE ID Management
+ final boolean isReadOnlyType() {
+ return (getTypeId() & READONLY) > 0;
+ }
+
+ final static byte setReadOnlyType(final byte type, final boolean readOnly) {
+ return (byte)((type & ~1) | (readOnly ? READONLY : 0));
+ }
+
+ final boolean isRegionType() {
+ return (getTypeId() & REGION) > 0;
+ }
+
+ final boolean isDuplicateType() {
+ return (getTypeId() & DUPLICATE) > 0;
+ }
+
+ //The following are set by the leaf nodes
+ final boolean isBufferType() {
+ return (getTypeId() & BUFFER) > 0;
+ }
+
+ final boolean isNonNativeType() {
+ return (getTypeId() & NONNATIVE) > 0;
+ }
+
+ final boolean isHeapType() {
+ return (getTypeId() >>> 3 & 3) == 0;
+ }
+
+ final boolean isDirectType() {
+ return (getTypeId() >>> 3 & 3) == 1;
+ }
+
+ final boolean isMapType() {
+ return (getTypeId() >>> 3 & 3) == 2;
+ }
+
+ final boolean isBBType() {
+ return (getTypeId() >>> 3 & 3) == 3;
+ }
+
+ //TO STRING
+ /**
+ * Decodes the resource type. This is primarily for debugging.
+ * @param typeId the given typeId
+ * @return a human readable string.
+ */
+ public static final String typeDecode(final int typeId) {
+ final StringBuilder sb = new StringBuilder();
+ final int group1 = typeId & 0x7;
+ switch (group1) {
+ case 1 : sb.append("ReadOnly, "); break;
+ case 2 : sb.append("Region, "); break;
+ case 3 : sb.append("ReadOnly Region, "); break;
+ case 4 : sb.append("Duplicate, "); break;
+ case 5 : sb.append("ReadOnly Duplicate, "); break;
+ case 6 : sb.append("Region Duplicate, "); break;
+ case 7 : sb.append("ReadOnly Region Duplicate, "); break;
+ default: break;
+ }
+ final int group2 = (typeId >>> 3) & 0x3;
+ switch (group2) {
+ case 0 : sb.append("Heap, "); break;
+ case 1 : sb.append("Direct, "); break;
+ case 2 : sb.append("Map, "); break;
+ case 3 : sb.append("ByteBuffer, "); break;
+ default: break;
+ }
+ final int group3 = (typeId >>> 5) & 0x1;
+ switch (group3) {
+ case 0 : sb.append("Native, "); break;
+ case 1 : sb.append("NonNative, "); break;
+ default: break;
+ }
+ final int group4 = (typeId >>> 6) & 0x1;
+ switch (group4) {
+ case 0 : sb.append("Memory"); break;
+ case 1 : sb.append("Buffer"); break;
+ default: break;
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public final String toHexString(final String header, final long offsetBytes,
+ final int lengthBytes) {
+ checkValid();
+ final String klass = this.getClass().getSimpleName();
+ final String s1 = String.format("(..., %d, %d)", offsetBytes, lengthBytes);
+ final long hcode = hashCode() & 0XFFFFFFFFL;
+ final String call = ".toHexString" + s1 + ", hashCode: " + hcode;
+ final StringBuilder sb = new StringBuilder();
+ sb.append("### ").append(klass).append(" SUMMARY ###").append(LS);
+ sb.append("Header Comment : ").append(header).append(LS);
+ sb.append("Call Parameters : ").append(call);
+ return toHex(this, sb.toString(), offsetBytes, lengthBytes);
+ }
+
+ /**
+ * Returns a formatted hex string of an area of this object.
+ * Used primarily for testing.
+ * @param state the BaseStateImpl
+ * @param preamble a descriptive header
+ * @param offsetBytes offset bytes relative to the MemoryImpl start
+ * @param lengthBytes number of bytes to convert to a hex string
+ * @return a formatted hex string in a human readable array
+ */
+ static final String toHex(final BaseStateImpl state, final String preamble,
final long offsetBytes,
+ final int lengthBytes) {
+ final long capacity = state.getCapacity();
+ UnsafeUtil.checkBounds(offsetBytes, lengthBytes, capacity);
+ final StringBuilder sb = new StringBuilder();
+ final Object uObj = state.getUnsafeObject();
+ final String uObjStr;
+ final long uObjHeader;
+ if (uObj == null) {
+ uObjStr = "null";
+ uObjHeader = 0;
+ } else {
+ uObjStr = uObj.getClass().getSimpleName() + ", " + (uObj.hashCode() &
0XFFFFFFFFL);
+ uObjHeader = UnsafeUtil.getArrayBaseOffset(uObj.getClass());
+ }
+ final ByteBuffer bb = state.getByteBuffer();
+ final String bbStr = bb == null ? "null"
+ : bb.getClass().getSimpleName() + ", " + (bb.hashCode() &
0XFFFFFFFFL);
+ final MemoryRequestServer memReqSvr = state.getMemoryRequestServer();
+ final String memReqStr = memReqSvr != null
+ ? memReqSvr.getClass().getSimpleName() + ", " + (memReqSvr.hashCode()
& 0XFFFFFFFFL)
+ : "null";
+ final long cumBaseOffset = state.getCumulativeOffset();
+ sb.append(preamble).append(LS);
+ sb.append("UnsafeObj, hashCode : ").append(uObjStr).append(LS);
+ sb.append("UnsafeObjHeader : ").append(uObjHeader).append(LS);
+ sb.append("ByteBuf, hashCode : ").append(bbStr).append(LS);
+ sb.append("RegionOffset :
").append(state.getRegionOffset()).append(LS);
+ sb.append("Capacity : ").append(capacity).append(LS);
+ sb.append("CumBaseOffset : ").append(cumBaseOffset).append(LS);
+ sb.append("MemReq, hashCode : ").append(memReqStr).append(LS);
+ sb.append("Valid : ").append(state.isValid()).append(LS);
+ sb.append("Read Only : ").append(state.isReadOnly()).append(LS);
+ sb.append("Type Byte Order :
").append(state.getTypeByteOrder().toString()).append(LS);
+ sb.append("Native Byte Order :
").append(ByteOrder.nativeOrder().toString()).append(LS);
+ sb.append("JDK Runtime Version : ").append(UnsafeUtil.JDK).append(LS);
+ //Data detail
+ sb.append("Data, littleEndian : 0 1 2 3 4 5 6 7");
+
+ for (long i = 0; i < lengthBytes; i++) {
+ final int b = unsafe.getByte(uObj, cumBaseOffset + offsetBytes + i) &
0XFF;
+ if (i % 8 == 0) { //row header
+ sb.append(String.format("%n%20s: ", offsetBytes + i));
+ }
+ sb.append(String.format("%02x ", b));
+ }
+ sb.append(LS);
+
+ return sb.toString();
+ }
+
+ //MONITORING
+
+ /**
+ * Gets the current number of active direct memory allocations.
+ * @return the current number of active direct memory allocations.
+ */
+ public static final long getCurrentDirectMemoryAllocations() {
+ return BaseStateImpl.currentDirectMemoryAllocations_.get();
+ }
+
+ /**
+ * Gets the current size of active direct memory allocated.
+ * @return the current size of active direct memory allocated.
+ */
+ public static final long getCurrentDirectMemoryAllocated() {
+ return BaseStateImpl.currentDirectMemoryAllocated_.get();
+ }
+
+ /**
+ * Gets the current number of active direct memory map allocations.
+ * @return the current number of active direct memory map allocations.
+ */
+ public static final long getCurrentDirectMemoryMapAllocations() {
+ return BaseStateImpl.currentDirectMemoryMapAllocations_.get();
+ }
+
+ /**
+ * Gets the current size of active direct memory map allocated.
+ * @return the current size of active direct memory map allocated.
+ */
+ public static final long getCurrentDirectMemoryMapAllocated() {
+ return BaseStateImpl.currentDirectMemoryMapAllocated_.get();
+ }
+
+ //REACHABILITY FENCE
+ static void reachabilityFence(final Object obj) { }
+
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java
------------------------------------------------------------------------------
svn:executable = *
Added:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
==============================================================================
---
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
(added)
+++
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
Tue May 21 21:11:49 2024
@@ -0,0 +1,431 @@
+/*
+ * 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 org.apache.datasketches.memory.internal;
+
+import static
org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_BOOLEAN_BASE_OFFSET;
+import static
org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_BOOLEAN_INDEX_SCALE;
+import static
org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_BYTE_BASE_OFFSET;
+import static
org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_BYTE_INDEX_SCALE;
+import static
org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_CHAR_INDEX_SCALE;
+import static
org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_INT_INDEX_SCALE;
+import static
org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_LONG_INDEX_SCALE;
+import static
org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_SHORT_INDEX_SCALE;
+import static org.apache.datasketches.memory.internal.UnsafeUtil.checkBounds;
+import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Objects;
+
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+
+/*
+ * Developer notes: The heavier methods, such as put/get arrays, duplicate,
region, clear, fill,
+ * compareTo, etc., use hard checks (check*() and incrementAndCheck*()
methods), which execute at
+ * runtime and throw exceptions if violated. The cost of the runtime checks
are minor compared to
+ * the rest of the work these methods are doing.
+ *
+ * <p>The light weight methods, such as put/get primitives, use asserts
(assert*() and
+ * incrementAndAssert*() methods), which only execute when asserts are enabled
and JIT will remove
+ * them entirely from production runtime code. The offset versions of the
light weight methods will
+ * simplify to a single unsafe call, which is further simplified by JIT to an
intrinsic that is
+ * often a single CPU instruction.
+ */
+
+/**
+ * Common base of native-ordered and non-native-ordered {@link WritableBuffer}
implementations.
+ * Contains methods which are agnostic to the byte order.
+ */
+@SuppressWarnings("restriction")
+public abstract class BaseWritableBufferImpl extends BaseBufferImpl implements
WritableBuffer {
+
+ //Pass-through ctor
+ BaseWritableBufferImpl(final Object unsafeObj, final long nativeBaseOffset,
+ final long regionOffset, final long capacityBytes) {
+ super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+ }
+
+ /**
+ * The static constructor that chooses the correct ByteBuffer leaf node
based on the byte order.
+ * @param byteBuf the ByteBuffer being wrapped
+ * @param localReadOnly the requested read-only state
+ * @param byteOrder the requested byteOrder
+ * @param memReqSvr the requested MemoryRequestServer, which may be null.
+ * @return this class constructed via the leaf node.
+ */
+ public static BaseWritableBufferImpl wrapByteBuffer(
+ final ByteBuffer byteBuf, final boolean localReadOnly, final ByteOrder
byteOrder,
+ final MemoryRequestServer memReqSvr) {
+ final AccessByteBuffer abb = new AccessByteBuffer(byteBuf);
+ final int typeId = (abb.resourceReadOnly || localReadOnly) ? READONLY : 0;
+ final BaseWritableBufferImpl bwbi = Util.isNativeByteOrder(byteOrder)
+ ? new BBWritableBufferImpl(abb.unsafeObj, abb.nativeBaseOffset,
+ abb.regionOffset, abb.capacityBytes, typeId, byteBuf, memReqSvr)
+ : new BBNonNativeWritableBufferImpl(abb.unsafeObj,
abb.nativeBaseOffset,
+ abb.regionOffset, abb.capacityBytes, typeId, byteBuf, memReqSvr);
+ bwbi.setStartPositionEnd(0, byteBuf.position(), byteBuf.limit());
+ return bwbi;
+ }
+
+ //REGIONS
+ @Override
+ public Buffer region() {
+ return writableRegionImpl(getPosition(), getEnd() - getPosition(), true,
getTypeByteOrder());
+ }
+
+ @Override
+ public Buffer region(final long offsetBytes, final long capacityBytes, final
ByteOrder byteOrder) {
+ final WritableBuffer buf = writableRegionImpl(offsetBytes, capacityBytes,
true, byteOrder);
+ buf.setAndCheckStartPositionEnd(0, 0, capacityBytes);
+ return buf;
+ }
+
+ @Override
+ public WritableBuffer writableRegion() {
+ return writableRegionImpl(getPosition(), getEnd() - getPosition(), false,
getTypeByteOrder());
+ }
+
+ @Override
+ public WritableBuffer writableRegion(final long offsetBytes, final long
capacityBytes, final ByteOrder byteOrder) {
+ final WritableBuffer wbuf = writableRegionImpl(offsetBytes, capacityBytes,
false, byteOrder);
+ wbuf.setAndCheckStartPositionEnd(0, 0, capacityBytes);
+ return wbuf;
+ }
+
+ WritableBuffer writableRegionImpl(final long offsetBytes, final long
capacityBytes,
+ final boolean localReadOnly, final ByteOrder byteOrder) {
+ if (isReadOnly() && !localReadOnly) {
+ throw new ReadOnlyException("Writable region of a read-only Buffer is
not allowed.");
+ }
+ checkValidAndBounds(offsetBytes, capacityBytes);
+ final boolean readOnly = isReadOnly() || localReadOnly;
+ final WritableBuffer wbuf = toWritableRegion(offsetBytes, capacityBytes,
readOnly, byteOrder);
+ wbuf.setStartPositionEnd(0, 0, capacityBytes);
+ return wbuf;
+ }
+
+ abstract BaseWritableBufferImpl toWritableRegion(
+ long offsetBytes, long capcityBytes, boolean readOnly, ByteOrder
byteOrder);
+
+ //DUPLICATES
+ @Override
+ public Buffer duplicate() {
+ return writableDuplicateImpl(true, getTypeByteOrder());
+ }
+
+ @Override
+ public Buffer duplicate(final ByteOrder byteOrder) {
+ return writableDuplicateImpl(true, byteOrder);
+ }
+
+ @Override
+ public WritableBuffer writableDuplicate() {
+ return writableDuplicateImpl(false, getTypeByteOrder());
+ }
+
+ @Override
+ public WritableBuffer writableDuplicate(final ByteOrder byteOrder) {
+ return writableDuplicateImpl(false, byteOrder);
+ }
+
+ WritableBuffer writableDuplicateImpl(final boolean localReadOnly, final
ByteOrder byteOrder) {
+ if (isReadOnly() && !localReadOnly) {
+ throw new ReadOnlyException("Writable duplicate of a read-only Buffer is
not allowed.");
+ }
+ final boolean readOnly = isReadOnly() || localReadOnly;
+ final WritableBuffer wbuf = toDuplicate(readOnly, byteOrder);
+ wbuf.setStartPositionEnd(getStart(), getPosition(), getEnd());
+ return wbuf;
+ }
+
+ abstract BaseWritableBufferImpl toDuplicate(boolean readOnly, ByteOrder
byteOrder);
+
+ //AS MEMORY
+ @Override
+ public Memory asMemory(final ByteOrder byteOrder) {
+ return asWritableMemory(true, byteOrder);
+ }
+
+ @Override
+ public WritableMemory asWritableMemory(final ByteOrder byteOrder) {
+ return asWritableMemory(false, byteOrder);
+ }
+
+ WritableMemory asWritableMemory(final boolean localReadOnly, final ByteOrder
byteOrder) {
+ Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
+ if (isReadOnly() && !localReadOnly) {
+ throw new ReadOnlyException(
+ "Converting a read-only Buffer to a writable Memory is not
allowed.");
+ }
+ final boolean readOnly = isReadOnly() || localReadOnly;
+ final WritableMemory wmem = toWritableMemory(readOnly, byteOrder);
+ return wmem;
+ }
+
+ abstract BaseWritableMemoryImpl toWritableMemory(boolean readOnly, ByteOrder
byteOrder);
+
+ //PRIMITIVE getX() and getXArray()
+ @Override
+ public final boolean getBoolean() {
+ final long pos = getPosition();
+ incrementAndAssertPositionForRead(pos, ARRAY_BOOLEAN_INDEX_SCALE);
+ return unsafe.getBoolean(getUnsafeObject(), getCumulativeOffset(pos));
+ }
+
+ @Override
+ public final boolean getBoolean(final long offsetBytes) {
+ assertValidAndBoundsForRead(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
+ return unsafe.getBoolean(getUnsafeObject(),
getCumulativeOffset(offsetBytes));
+ }
+
+ @Override
+ public final void getBooleanArray(final boolean[] dstArray, final int
dstOffsetBooleans,
+ final int lengthBooleans) {
+ final long pos = getPosition();
+ final long copyBytes = lengthBooleans;
+ incrementAndCheckPositionForRead(pos, copyBytes);
+ checkBounds(dstOffsetBooleans, lengthBooleans, dstArray.length);
+ CompareAndCopy.copyMemoryCheckingDifferentObject(
+ getUnsafeObject(),
+ getCumulativeOffset(pos),
+ dstArray,
+ ARRAY_BOOLEAN_BASE_OFFSET + dstOffsetBooleans,
+ copyBytes);
+ }
+
+ @Override
+ public final byte getByte() {
+ final long pos = getPosition();
+ incrementAndAssertPositionForRead(pos, ARRAY_BYTE_INDEX_SCALE);
+ return unsafe.getByte(getUnsafeObject(), getCumulativeOffset(pos));
+ }
+
+ @Override
+ public final byte getByte(final long offsetBytes) {
+ assertValidAndBoundsForRead(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
+ return unsafe.getByte(getUnsafeObject(), getCumulativeOffset(offsetBytes));
+ }
+
+ @Override
+ public final void getByteArray(final byte[] dstArray, final int
dstOffsetBytes,
+ final int lengthBytes) {
+ final long pos = getPosition();
+ final long copyBytes = lengthBytes;
+ incrementAndCheckPositionForRead(pos, copyBytes);
+ checkBounds(dstOffsetBytes, lengthBytes, dstArray.length);
+ CompareAndCopy.copyMemoryCheckingDifferentObject(
+ getUnsafeObject(),
+ getCumulativeOffset(pos),
+ dstArray,
+ ARRAY_BYTE_BASE_OFFSET + dstOffsetBytes,
+ copyBytes);
+ }
+
+ //PRIMITIVE getX() Native Endian (used by both endians)
+ final char getNativeOrderedChar() {
+ final long pos = getPosition();
+ incrementAndAssertPositionForRead(pos, ARRAY_CHAR_INDEX_SCALE);
+ return unsafe.getChar(getUnsafeObject(), getCumulativeOffset(pos));
+ }
+
+ final char getNativeOrderedChar(final long offsetBytes) {
+ assertValidAndBoundsForRead(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
+ return unsafe.getChar(getUnsafeObject(), getCumulativeOffset(offsetBytes));
+ }
+
+ final int getNativeOrderedInt() {
+ final long pos = getPosition();
+ incrementAndAssertPositionForRead(pos, ARRAY_INT_INDEX_SCALE);
+ return unsafe.getInt(getUnsafeObject(), getCumulativeOffset(pos));
+ }
+
+ final int getNativeOrderedInt(final long offsetBytes) {
+ assertValidAndBoundsForRead(offsetBytes, ARRAY_INT_INDEX_SCALE);
+ return unsafe.getInt(getUnsafeObject(), getCumulativeOffset(offsetBytes));
+ }
+
+ final long getNativeOrderedLong() {
+ final long pos = getPosition();
+ incrementAndAssertPositionForRead(pos, ARRAY_LONG_INDEX_SCALE);
+ return unsafe.getLong(getUnsafeObject(), getCumulativeOffset(pos));
+ }
+
+ final long getNativeOrderedLong(final long offsetBytes) {
+ assertValidAndBoundsForRead(offsetBytes, ARRAY_LONG_INDEX_SCALE);
+ return unsafe.getLong(getUnsafeObject(), getCumulativeOffset(offsetBytes));
+ }
+
+ final short getNativeOrderedShort() {
+ final long pos = getPosition();
+ incrementAndAssertPositionForRead(pos, ARRAY_SHORT_INDEX_SCALE);
+ return unsafe.getShort(getUnsafeObject(), getCumulativeOffset(pos));
+ }
+
+ final short getNativeOrderedShort(final long offsetBytes) {
+ assertValidAndBoundsForRead(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
+ return unsafe.getShort(getUnsafeObject(),
getCumulativeOffset(offsetBytes));
+ }
+
+ //OTHER PRIMITIVE READ METHODS: copyTo, compareTo
+ @Override
+ public final int compareTo(final long thisOffsetBytes, final long
thisLengthBytes,
+ final Buffer thatBuf, final long thatOffsetBytes, final long
thatLengthBytes) {
+ return CompareAndCopy.compare((BaseStateImpl)this, thisOffsetBytes,
thisLengthBytes,
+ (BaseStateImpl)thatBuf, thatOffsetBytes, thatLengthBytes);
+ }
+
+ /*
+ * Develper notes: There is no copyTo for Buffers because of the ambiguity
of what to do with
+ * the positional values. Switch to MemoryImpl view to do copyTo.
+ */
+
+ //PRIMITIVE putX() and putXArray() implementations
+ @Override
+ public final void putBoolean(final boolean value) {
+ final long pos = getPosition();
+ incrementAndAssertPositionForWrite(pos, ARRAY_BOOLEAN_INDEX_SCALE);
+ unsafe.putBoolean(getUnsafeObject(), getCumulativeOffset(pos), value);
+ }
+
+ @Override
+ public final void putBoolean(final long offsetBytes, final boolean value) {
+ assertValidAndBoundsForWrite(offsetBytes, ARRAY_BOOLEAN_INDEX_SCALE);
+ unsafe.putBoolean(getUnsafeObject(), getCumulativeOffset(offsetBytes),
value);
+ }
+
+ @Override
+ public final void putBooleanArray(final boolean[] srcArray, final int
srcOffsetBooleans,
+ final int lengthBooleans) {
+ final long pos = getPosition();
+ final long copyBytes = lengthBooleans;
+ incrementAndCheckPositionForWrite(pos, copyBytes);
+ checkBounds(srcOffsetBooleans, lengthBooleans, srcArray.length);
+ CompareAndCopy.copyMemoryCheckingDifferentObject(
+ srcArray,
+ ARRAY_BOOLEAN_BASE_OFFSET + srcOffsetBooleans,
+ getUnsafeObject(),
+ getCumulativeOffset(pos),
+ copyBytes);
+ }
+
+ @Override
+ public final void putByte(final byte value) {
+ final long pos = getPosition();
+ incrementAndAssertPositionForWrite(pos, ARRAY_BYTE_INDEX_SCALE);
+ unsafe.putByte(getUnsafeObject(), getCumulativeOffset(pos), value);
+ }
+
+ @Override
+ public final void putByte(final long offsetBytes, final byte value) {
+ assertValidAndBoundsForWrite(offsetBytes, ARRAY_BYTE_INDEX_SCALE);
+ unsafe.putByte(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
+ }
+
+ @Override
+ public final void putByteArray(final byte[] srcArray, final int
srcOffsetBytes,
+ final int lengthBytes) {
+ final long pos = getPosition();
+ final long copyBytes = lengthBytes;
+ incrementAndCheckPositionForWrite(pos, copyBytes);
+ checkBounds(srcOffsetBytes, lengthBytes, srcArray.length);
+ CompareAndCopy.copyMemoryCheckingDifferentObject(
+ srcArray,
+ ARRAY_BYTE_BASE_OFFSET + srcOffsetBytes,
+ getUnsafeObject(),
+ getCumulativeOffset(pos),
+ copyBytes);
+ }
+
+ //PRIMITIVE putX() Native Endian (used by both endians)
+ final void putNativeOrderedChar(final char value) {
+ final long pos = getPosition();
+ incrementAndAssertPositionForWrite(pos, ARRAY_CHAR_INDEX_SCALE);
+ unsafe.putChar(getUnsafeObject(), getCumulativeOffset(pos), value);
+ }
+
+ final void putNativeOrderedChar(final long offsetBytes, final char value) {
+ assertValidAndBoundsForWrite(offsetBytes, ARRAY_CHAR_INDEX_SCALE);
+ unsafe.putChar(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
+ }
+
+ final void putNativeOrderedInt(final int value) {
+ final long pos = getPosition();
+ incrementAndAssertPositionForWrite(pos, ARRAY_INT_INDEX_SCALE);
+ unsafe.putInt(getUnsafeObject(), getCumulativeOffset(pos), value);
+ }
+
+ final void putNativeOrderedInt(final long offsetBytes, final int value) {
+ assertValidAndBoundsForWrite(offsetBytes, ARRAY_INT_INDEX_SCALE);
+ unsafe.putInt(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
+ }
+
+ final void putNativeOrderedLong(final long value) {
+ final long pos = getPosition();
+ incrementAndAssertPositionForWrite(pos, ARRAY_LONG_INDEX_SCALE);
+ unsafe.putLong(getUnsafeObject(), getCumulativeOffset(pos), value);
+ }
+
+ final void putNativeOrderedLong(final long offsetBytes, final long value) {
+ assertValidAndBoundsForWrite(offsetBytes, ARRAY_LONG_INDEX_SCALE);
+ unsafe.putLong(getUnsafeObject(), getCumulativeOffset(offsetBytes), value);
+ }
+
+ final void putNativeOrderedShort(final short value) {
+ final long pos = getPosition();
+ incrementAndAssertPositionForWrite(pos, ARRAY_SHORT_INDEX_SCALE);
+ unsafe.putShort(getUnsafeObject(), getCumulativeOffset(pos), value);
+ }
+
+ final void putNativeOrderedShort(final long offsetBytes, final short value) {
+ assertValidAndBoundsForWrite(offsetBytes, ARRAY_SHORT_INDEX_SCALE);
+ unsafe.putShort(getUnsafeObject(), getCumulativeOffset(offsetBytes),
value);
+ }
+
+ //OTHER
+ @Override
+ public final Object getArray() {
+ assertValid();
+ return getUnsafeObject();
+ }
+
+ @Override
+ public final void clear() {
+ fill((byte)0);
+ }
+
+ @Override
+ public final void fill(final byte value) {
+ checkValidForWrite();
+ long pos = getPosition();
+ long len = getEnd() - pos;
+ checkInvariants(getStart(), pos + len, getEnd(), getCapacity());
+ while (len > 0) {
+ final long chunk = Math.min(len, Util.UNSAFE_COPY_THRESHOLD_BYTES);
+ unsafe.setMemory(getUnsafeObject(), getCumulativeOffset(pos), chunk,
value);
+ pos += chunk;
+ len -= chunk;
+ }
+ }
+}
Propchange:
dev/datasketches/memory/2.2.0-RC1/apache-datasketches-memory-2.2.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
------------------------------------------------------------------------------
svn:executable = *
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]