From 64131438110116c86dc7f5a97fd46b2a2b0df92e Mon Sep 17 00:00:00 2001 From: Chris Vest Date: Wed, 1 Sep 2021 11:16:31 +0200 Subject: [PATCH] Update with recent Netty 5 changes --- Dockerfile | 3 +- buffer-api/pom.xml | 43 - .../io/netty/buffer/api/AllocatorControl.java | 62 - .../main/java/io/netty/buffer/api/Buffer.java | 682 ------ .../io/netty/buffer/api/BufferAccessors.java | 614 ----- .../io/netty/buffer/api/BufferAllocator.java | 134 -- .../buffer/api/BufferClosedException.java | 27 - .../io/netty/buffer/api/BufferHolder.java | 149 -- .../buffer/api/BufferReadOnlyException.java | 27 - .../java/io/netty/buffer/api/BufferRef.java | 74 - .../java/io/netty/buffer/api/ByteCursor.java | 108 - .../io/netty/buffer/api/CompositeBuffer.java | 2016 ----------------- .../main/java/io/netty/buffer/api/Drop.java | 40 - .../buffer/api/ManagedBufferAllocator.java | 67 - .../io/netty/buffer/api/MemoryManager.java | 31 - .../io/netty/buffer/api/MemoryManagers.java | 110 - .../main/java/io/netty/buffer/api/Owned.java | 38 - .../netty/buffer/api/ReadableComponent.java | 100 - .../api/ReadableComponentProcessor.java | 40 - .../java/io/netty/buffer/api/Resource.java | 56 - .../api/ResourceDisposeFailedException.java | 23 - .../main/java/io/netty/buffer/api/Scope.java | 60 - .../main/java/io/netty/buffer/api/Send.java | 129 -- .../netty/buffer/api/WritableComponent.java | 74 - .../api/WritableComponentProcessor.java | 40 - .../api/adaptor/BufferIntegratable.java | 25 - .../buffer/api/adaptor/ByteBufAdaptor.java | 1710 -------------- .../api/adaptor/ByteBufAllocatorAdaptor.java | 159 -- .../buffer/api/adaptor/package-info.java | 20 - .../bytebuffer/ByteBufferMemoryManager.java | 90 - .../bytebuffer/ByteBufferMemoryManagers.java | 41 - .../buffer/api/bytebuffer/NioBuffer.java | 1275 ----------- .../buffer/api/bytebuffer/package-info.java | 20 - .../io/netty/buffer/api/internal/ArcDrop.java | 115 - .../buffer/api/internal/CleanerDrop.java | 79 - .../buffer/api/internal/LifecycleTracer.java | 195 -- .../api/internal/MemoryManagersOverride.java | 53 - .../buffer/api/internal/ResourceSupport.java | 231 -- .../io/netty/buffer/api/internal/Statics.java | 190 -- .../buffer/api/internal/TransferSend.java | 69 - .../buffer/api/internal/package-info.java | 20 - .../io/netty/buffer/api/package-info.java | 20 - .../api/pool/BufferAllocatorMetric.java | 25 - .../pool/BufferAllocatorMetricProvider.java | 26 - .../buffer/api/pool/LongLongHashMap.java | 129 -- .../buffer/api/pool/LongPriorityQueue.java | 107 - .../io/netty/buffer/api/pool/PoolArena.java | 471 ---- .../buffer/api/pool/PoolArenaMetric.java | 114 - .../io/netty/buffer/api/pool/PoolChunk.java | 662 ------ .../netty/buffer/api/pool/PoolChunkList.java | 250 -- .../buffer/api/pool/PoolChunkListMetric.java | 32 - .../buffer/api/pool/PoolChunkMetric.java | 37 - .../io/netty/buffer/api/pool/PoolSubpage.java | 287 --- .../buffer/api/pool/PoolSubpageMetric.java | 42 - .../buffer/api/pool/PoolThreadCache.java | 393 ---- .../api/pool/PooledAllocatorControl.java | 38 - .../api/pool/PooledBufferAllocator.java | 558 ----- .../api/pool/PooledBufferAllocatorMetric.java | 92 - .../io/netty/buffer/api/pool/PooledDrop.java | 40 - .../io/netty/buffer/api/pool/SizeClasses.java | 478 ---- .../buffer/api/pool/SizeClassesMetric.java | 87 - .../api/pool/UnpooledUnthetheredMemory.java | 45 - .../netty/buffer/api/pool/package-info.java | 19 - .../netty/buffer/api/unsafe/CleanerDrop.java | 55 - .../netty/buffer/api/unsafe/UnsafeBuffer.java | 1690 -------------- .../netty/buffer/api/unsafe/UnsafeMemory.java | 32 - .../api/unsafe/UnsafeMemoryManager.java | 102 - .../api/unsafe/UnsafeMemoryManagers.java | 51 - .../netty/buffer/api/unsafe/package-info.java | 20 - buffer-api/src/main/java/module-info.java | 41 - buffer-memseg-dummy/pom.xml | 30 - .../src/main/java/module-info.java | 19 - buffer-memseg/pom.xml | 4 - .../memseg/AbstractMemorySegmentManager.java | 81 - .../api/memseg/HeapMemorySegmentManager.java | 32 - .../netty/buffer/api/memseg/MemSegBuffer.java | 126 +- .../memseg/NativeMemorySegmentManager.java | 67 - .../api/memseg/ReduceNativeMemoryUsage.java | 21 + .../api/memseg/SegmentMemoryManagers.java | 87 +- buffer-memseg/src/main/java/module-info.java | 5 +- .../benchmarks/MemSegBufAccessBenchmark.java | 6 +- ...MemorySegmentClosedByCleanerBenchmark.java | 8 +- buffer-tests/pom.xml | 33 +- buffer-tests/src/main/java/module-info.java | 5 +- .../api/tests/BufferBulkAccessTest.java | 118 +- .../BufferByteOffsettedAccessorsTest.java | 5 - .../BufferCharOffsettedAccessorsTest.java | 3 - .../buffer/api/tests/BufferCleanerTest.java | 24 +- .../buffer/api/tests/BufferCompactTest.java | 5 +- .../tests/BufferComponentIterationTest.java | 34 +- .../api/tests/BufferCompositionTest.java | 179 +- .../BufferDoubleOffsettedAccessorsTest.java | 3 - .../api/tests/BufferEnsureWritableTest.java | 2 +- .../BufferFloatOffsettedAccessorsTest.java | 3 - .../BufferIntOffsettedAccessorsTest.java | 5 - ...tingTest.java => BufferLifeCycleTest.java} | 151 +- .../BufferLongOffsettedAccessorsTest.java | 3 - .../BufferMediumOffsettedAccessorsTest.java | 5 - .../buffer/api/tests/BufferOffsetsTest.java | 12 +- .../BufferPrimitiveRelativeAccessorsTest.java | 25 - .../buffer/api/tests/BufferReadOnlyTest.java | 34 +- .../netty/buffer/api/tests/BufferRefTest.java | 36 +- .../buffer/api/tests/BufferSendTest.java | 8 +- .../BufferShortOffsettedAccessorsTest.java | 5 - .../buffer/api/tests/BufferTestSupport.java | 457 ++-- .../BufferWriteBytesCombinationsTest.java | 20 - .../io/netty/buffer/api/tests/EchoIT.java | 13 +- .../io/netty/buffer/api/tests/Fixture.java | 12 +- .../io/netty/buffer/api/tests/ScopeTest.java | 79 - .../tests/adaptor/AbstractByteBufTest.java | 59 +- .../api/tests/adaptor/ByteBufAdaptorTest.java | 10 +- .../tests/adaptor/NioByteBufAdaptorTest.java | 25 - .../adaptor/UnsafeByteBufAdaptorTest.java | 25 - .../benchmarks/ByteIterationBenchmark.java | 14 +- .../api/tests/benchmarks/SendBenchmark.java | 4 +- .../api/tests/examples/AsyncExample.java | 2 +- .../ComposingAndSplittingExample.java | 3 +- .../api/tests/examples/FileCopyExample.java | 2 +- .../api/tests/examples/SendExample.java | 6 +- .../AlternativeMessageDecoder.java | 7 +- .../AlternativeMessageDecoderTest.java | 5 +- .../ByteToMessageDecoder.java | 100 +- .../ByteToMessageDecoderTest.java | 87 +- .../api/tests/examples/echo/EchoClient.java | 6 +- .../examples/echo/EchoClientHandler.java | 4 +- .../api/tests/examples/echo/EchoServer.java | 6 +- .../examples/http/snoop/HttpSnoopClient.java | 2 +- .../http/snoop/HttpSnoopClientHandler.java | 6 +- .../examples/http/snoop/HttpSnoopServer.java | 2 +- .../http/snoop/HttpSnoopServerHandler.java | 4 +- .../http/upload/HttpUploadClient.java | 11 +- .../http/upload/HttpUploadClientHandler.java | 7 +- .../http/upload/HttpUploadServer.java | 2 +- .../http/upload/HttpUploadServerHandler.java | 11 +- pom.xml | 30 +- 135 files changed, 690 insertions(+), 16497 deletions(-) delete mode 100644 buffer-api/pom.xml delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/AllocatorControl.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/Buffer.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/BufferAccessors.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/BufferAllocator.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/BufferClosedException.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/BufferHolder.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/BufferReadOnlyException.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/BufferRef.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/ByteCursor.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/CompositeBuffer.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/Drop.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/ManagedBufferAllocator.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/MemoryManager.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/MemoryManagers.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/Owned.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/ReadableComponent.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/ReadableComponentProcessor.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/Resource.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/ResourceDisposeFailedException.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/Scope.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/Send.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/WritableComponent.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/WritableComponentProcessor.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/adaptor/BufferIntegratable.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAdaptor.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAllocatorAdaptor.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/adaptor/package-info.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManager.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManagers.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/NioBuffer.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/package-info.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/internal/ArcDrop.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/internal/CleanerDrop.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/internal/LifecycleTracer.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/internal/MemoryManagersOverride.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/internal/ResourceSupport.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/internal/TransferSend.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/internal/package-info.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/package-info.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetric.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetricProvider.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/LongLongHashMap.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/LongPriorityQueue.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArena.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArenaMetric.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunk.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkList.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkListMetric.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkMetric.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpage.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpageMetric.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PoolThreadCache.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PooledAllocatorControl.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocator.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocatorMetric.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/PooledDrop.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClasses.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClassesMetric.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/UnpooledUnthetheredMemory.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/pool/package-info.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/unsafe/CleanerDrop.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeBuffer.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemory.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemoryManager.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemoryManagers.java delete mode 100644 buffer-api/src/main/java/io/netty/buffer/api/unsafe/package-info.java delete mode 100644 buffer-api/src/main/java/module-info.java delete mode 100644 buffer-memseg-dummy/pom.xml delete mode 100644 buffer-memseg-dummy/src/main/java/module-info.java delete mode 100644 buffer-memseg/src/main/java/io/netty/buffer/api/memseg/AbstractMemorySegmentManager.java delete mode 100644 buffer-memseg/src/main/java/io/netty/buffer/api/memseg/HeapMemorySegmentManager.java delete mode 100644 buffer-memseg/src/main/java/io/netty/buffer/api/memseg/NativeMemorySegmentManager.java create mode 100644 buffer-memseg/src/main/java/io/netty/buffer/api/memseg/ReduceNativeMemoryUsage.java rename buffer-tests/src/test/java/io/netty/buffer/api/tests/{BufferReferenceCountingTest.java => BufferLifeCycleTest.java} (88%) delete mode 100644 buffer-tests/src/test/java/io/netty/buffer/api/tests/ScopeTest.java delete mode 100644 buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/NioByteBufAdaptorTest.java delete mode 100644 buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/UnsafeByteBufAdaptorTest.java diff --git a/Dockerfile b/Dockerfile index b55f483..3124921 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,7 @@ RUN curl https://downloads.apache.org/maven/maven-3/3.6.3/binaries/apache-maven- ENV PATH=/home/build/apache-maven-3.6.3/bin:$PATH # Prepare a snapshot of Netty 5 -RUN git clone --depth 1 -b master https://github.com/netty/netty.git netty \ +RUN git clone --depth 1 -b main https://github.com/netty/netty.git netty \ && cd netty \ && mvn install -DskipTests -T1C -B -am \ && cd .. \ @@ -31,7 +31,6 @@ RUN git clone --depth 1 -b master https://github.com/netty/netty.git netty \ # Prepare our own build RUN mkdir buffer-api && mkdir buffer-memseg && mkdir buffer-tests COPY pom.xml pom.xml -COPY buffer-api/pom.xml buffer-api/pom.xml COPY buffer-memseg/pom.xml buffer-memseg/pom.xml COPY buffer-tests/pom.xml buffer-tests/pom.xml RUN mvn install dependency:go-offline surefire:test checkstyle:check -ntp diff --git a/buffer-api/pom.xml b/buffer-api/pom.xml deleted file mode 100644 index a78b473..0000000 --- a/buffer-api/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - 4.0.0 - - - io.netty.incubator - netty-incubator-buffer-parent - 0.0.1.Final-SNAPSHOT - - - netty-incubator-buffer-api - 0.0.1.Final-SNAPSHOT - Netty/Incubator/Buffer - jar - - - - io.netty - netty-common - - - io.netty - netty-buffer - - - \ No newline at end of file diff --git a/buffer-api/src/main/java/io/netty/buffer/api/AllocatorControl.java b/buffer-api/src/main/java/io/netty/buffer/api/AllocatorControl.java deleted file mode 100644 index 7cf7ca8..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/AllocatorControl.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -/** - * Methods for accessing and controlling the internals of an allocator. - * This interface is intended to be used by implementors of the {@link BufferAllocator}, {@link Buffer} and - * {@link MemoryManager} interfaces. - */ -public interface AllocatorControl { - /** - * Allocate a buffer that is not tethered to any particular {@link Buffer} object, - * and return the recoverable memory object from it. - *

- * This allows a buffer to implement {@link Buffer#ensureWritable(int)} by having new memory allocated to it, - * without that memory being attached to some other lifetime. - * - * @param originator The buffer that originated the request for an untethered memory allocated. - * @param size The size of the requested memory allocation, in bytes. - * @return A {@link UntetheredMemory} object that is the requested allocation. - */ - UntetheredMemory allocateUntethered(Buffer originator, int size); - - /** - * Return memory to the allocator, after it has been untethered from it's lifetime. - * This either happens if the memory has leaked and been re-captured, or if it is no longer in use by a buffer - * through {@link Buffer#ensureWritable(int)}. - * - * @param memory The untethered memory to return to the allocator. - */ - void recoverMemory(Object memory); - - /** - * Memory that isn't attached to any particular buffer. - */ - interface UntetheredMemory { - /** - * Produce the recoverable memory object associated with this piece of untethered memory. - * @implNote This method should only be called once, since it might be expensive. - */ - Memory memory(); - - /** - * Produce the drop instance associated with this piece of untethered memory. - * @implNote This method should only be called once, since it might be expensive, or interact with Cleaners. - */ - Drop drop(); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Buffer.java b/buffer-api/src/main/java/io/netty/buffer/api/Buffer.java deleted file mode 100644 index 665a986..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/Buffer.java +++ /dev/null @@ -1,682 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * A reference counted buffer of memory, with separate reader and writer offsets. - *

- * A buffer is a sequential stretch of memory with a certain capacity, an offset for writing, and an offset for reading. - * - *

Creating a buffer

- * - * Buffers are created by {@linkplain BufferAllocator allocators}, and their {@code allocate} family of methods. - * A number of standard allocators exist, and ara available through static methods on the {@code BufferAllocator} - * interface. - * - *

Life cycle and reference counting

- * - * The buffer has a life cycle, where it is allocated, used, and deallocated. - * When the buffer is initially allocated, a pairing {@link #close()} call will deallocate it. - * If a buffer is {@linkplain #send() sent} elsewhere, the {@linkplain #close() close} method on the given instance - * will become a no-op. - * The buffer can be thought of as a view onto memory, and calling {@link #send()} on the buffer will effectively close - * that view, and recreate it upon reception at its destination. - * - *

Thread-safety

- * - * Buffers are not thread-safe. - * The {@linkplain #isAccessible() accessibility state} implied by the {@link Resource} interface is itself not - * thread-safe, and buffers additionally contain other mutable data that is not thread-safe. - * - *

Accessing data

- * - * Data access methods fall into two classes: - *
    - *
  1. Access that are based on, and updates, the read or write offset positions.
  2. - * - *
  3. Access that take offsets as arguments, and do not update read or write offset positions.
  4. - * - *
- * - * A buffer contains two mutable offset positions: one for reading and one for writing. - * These positions use zero-based indexing, - * such that the first byte of data in the buffer is placed at offset {@code 0}, - * and the last byte in the buffer is at offset {@link #capacity() capacity - 1}. - * The {@link #readerOffset()} is the offset into the buffer from which the next read will take place, - * and is initially zero. - * The reader offset must always be less than or equal to the {@link #writerOffset()}. - * The {@link #writerOffset()} is likewise the offset into the buffer where the next write will take place. - * The writer offset is also initially zero, and must be less than or equal to the {@linkplain #capacity() capacity}. - *

- * This carves the buffer into three regions, as demonstrated by this diagram: - *

- *      +-------------------+------------------+------------------+
- *      | discardable bytes |  readable bytes  |  writable bytes  |
- *      |                   |     (CONTENT)    |                  |
- *      +-------------------+------------------+------------------+
- *      |                   |                  |                  |
- *      0      <=     readerOffset  <=   writerOffset    <=    capacity
- * 
- * - *

Splitting buffers

- * - * The {@link #split()} method breaks a buffer into two. - * The two buffers will share the underlying memory, but their regions will not overlap, ensuring that the memory is - * safely shared between the two. - *

- * Splitting a buffer is useful for when you want to hand over a region of a buffer to some other, - * perhaps unknown, piece of code, and relinquish your ownership of that buffer region in the process. - * Examples include aggregating messages into an accumulator buffer, and sending messages down the pipeline for - * further processing, as split buffer regions, once their data has been received in its entirety. - * - * If you instead wish to temporarily share a region of a buffer, you will have to pass offset and length along with the - * buffer, or you will have to make a copy of the region. - * - *

Buffers as constants

- * - * Sometimes, the same bit of data will be processed or transmitted over and over again. In such cases, it can be - * tempting to allocate and fill a buffer once, and then reuse it. - * Such reuse must be done carefully, however, to avoid a number of bugs. - * The {@link BufferAllocator} has a {@link BufferAllocator#constBufferSupplier(byte[])} method that solves this, and - * prevents these bugs from occurring. - */ -public interface Buffer extends Resource, BufferAccessors { - /** - * Change the default byte order of this buffer, and return this buffer. - * - * @param order The new default byte order, used by accessor methods that don't use an explicit byte order. - * @return This buffer instance. - */ - Buffer order(ByteOrder order); - - /** - * The default byte order of this buffer. - * @return The default byte order of this buffer. - */ - ByteOrder order(); - - /** - * The capacity of this buffer, that is, the maximum number of bytes it can contain. - * - * @return The capacity in bytes. - */ - int capacity(); - - /** - * Get the current reader offset. The next read will happen from this byte offset into the buffer. - * - * @return The current reader offset. - */ - int readerOffset(); - - /** - * Set the reader offset. Make the next read happen from the given offset into the buffer. - * - * @param offset The reader offset to set. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the specified {@code offset} is less than zero or greater than the current - * {@link #writerOffset()}. - */ - Buffer readerOffset(int offset); - - /** - * Get the current writer offset. The next write will happen at this byte offset into the byffer. - * - * @return The current writer offset. - */ - int writerOffset(); - - /** - * Set the writer offset. Make the next write happen at the given offset. - * - * @param offset The writer offset to set. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the specified {@code offset} is less than the current - * {@link #readerOffset()} or greater than {@link #capacity()}. - * @throws BufferClosedException if this buffer is closed. - * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}. - */ - Buffer writerOffset(int offset); - - /** - * Returns the number of readable bytes which is equal to {@code (writerOffset() - readerOffset())}. - */ - default int readableBytes() { - return writerOffset() - readerOffset(); - } - - /** - * Returns the number of writable bytes which is equal to {@code (capacity() - writerOffset())}. - */ - default int writableBytes() { - return capacity() - writerOffset(); - } - - /** - * Fill the buffer with the given byte value. This method does not respect the {@link #readerOffset()} or {@link - * #writerOffset()}, but copies the full capacity of the buffer. The {@link #readerOffset()} and {@link - * #writerOffset()} are not modified. - * - * @param value The byte value to write at every position in the buffer. - * @return This Buffer. - * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}. - */ - Buffer fill(byte value); - - /** - * Give the native memory address backing this buffer, or return 0 if this buffer has no native memory address. - * @return The native memory address, if any, otherwise 0. - */ - long nativeAddress(); - - /** - * Make this buffer read-only. - * This is irreversible. - * - * @return this buffer. - */ - Buffer makeReadOnly(); - - /** - * Query if this buffer is read-only or not. - * - * @return {@code true} if this buffer is read-only, {@code false} otherwise. - */ - boolean readOnly(); - - /** - * Copies the given length of data from this buffer into the given destination array, beginning at the given source - * position in this buffer, and the given destination position in the destination array. - *

- * This method does not read or modify the {@linkplain #writerOffset() write offset} or the - * {@linkplain #readerOffset() read offset}. - * - * @param srcPos The byte offset into this buffer wherefrom the copying should start; the byte at this offset in - * this buffer will be copied to the {@code destPos} index in the {@code dest} array. - * @param dest The destination byte array. - * @param destPos The index into the {@code dest} array wherefrom the copying should start. - * @param length The number of bytes to copy. - * @throws NullPointerException if the destination array is null. - * @throws IndexOutOfBoundsException if the source or destination positions, or the length, are negative, - * or if the resulting end positions reaches beyond the end of either this buffer, or the destination array. - */ - void copyInto(int srcPos, byte[] dest, int destPos, int length); - - /** - * Copies the given length of data from this buffer into the given destination byte buffer, beginning at the given - * source position in this buffer, and the given destination position in the destination byte buffer. - *

- * This method does not read or modify the {@linkplain #writerOffset() write offset} or the - * {@linkplain #readerOffset() read offset}, nor is the position of the destination buffer changed. - *

- * The position and limit of the destination byte buffer are also ignored, and do not influence {@code destPos} - * or {@code length}. - * - * @param srcPos The byte offset into this buffer wherefrom the copying should start; the byte at this offset in - * this buffer will be copied to the {@code destPos} index in the {@code dest} array. - * @param dest The destination byte buffer. - * @param destPos The index into the {@code dest} array wherefrom the copying should start. - * @param length The number of bytes to copy. - * @throws NullPointerException if the destination array is null. - * @throws IndexOutOfBoundsException if the source or destination positions, or the length, are negative, - * or if the resulting end positions reaches beyond the end of either this buffer, or the destination array. - */ - void copyInto(int srcPos, ByteBuffer dest, int destPos, int length); - - /** - * Copies the given length of data from this buffer into the given destination buffer, beginning at the given - * source position in this buffer, and the given destination position in the destination buffer. - *

- * This method does not read or modify the {@linkplain #writerOffset() write offset} or the - * {@linkplain #readerOffset() read offset} on this buffer, nor on the destination buffer. - *

- * The read and write offsets of the destination buffer are also ignored, and do not influence {@code destPos} - * or {@code length}. - * - * @param srcPos The byte offset into this buffer wherefrom the copying should start; the byte at this offset in - * this buffer will be copied to the {@code destPos} index in the {@code dest} array. - * @param dest The destination buffer. - * @param destPos The index into the {@code dest} array wherefrom the copying should start. - * @param length The number of bytes to copy. - * @throws NullPointerException if the destination array is null. - * @throws IndexOutOfBoundsException if the source or destination positions, or the length, are negative, - * or if the resulting end positions reaches beyond the end of either this buffer, or the destination array. - */ - void copyInto(int srcPos, Buffer dest, int destPos, int length); - - /** - * Write into this buffer, all the readable bytes from the given buffer. - * This updates the {@linkplain #writerOffset() write offset} of this buffer, and the - * {@linkplain #readerOffset() reader offset} of the given buffer. - * - * @param source The buffer to read from. - * @return This buffer. - */ - default Buffer writeBytes(Buffer source) { - int size = source.readableBytes(); - int woff = writerOffset(); - writerOffset(woff + size); - source.copyInto(source.readerOffset(), this, woff, size); - source.readerOffset(source.readerOffset() + size); - return this; - } - - /** - * Write into this buffer, all the bytes from the given byte array. - * This updates the {@linkplain #writerOffset() write offset} of this buffer by the length of the array. - * - * @param source The byte array to read from. - * @return This buffer. - */ - default Buffer writeBytes(byte[] source) { - int size = source.length; - int woff = writerOffset(); - writerOffset(woff + size); - for (int i = 0; i < size; i++) { - setByte(woff + i, source[i]); - } - return this; - } - - /** - * Resets the {@linkplain #readerOffset() read offset} and the {@linkplain #writerOffset() write offset} on this - * buffer to their initial values. - */ - default Buffer reset() { - readerOffset(0); - writerOffset(0); - return this; - } - - /** - * Open a cursor to iterate the readable bytes of this buffer. The {@linkplain #readerOffset() reader offset} and - * {@linkplain #writerOffset() witer offset} are not modified by the cursor. - *

- * Care should be taken to ensure that the buffer's lifetime extends beyond the cursor and the iteration, and that - * the {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() writer offset} are not modified - * while the iteration takes place. Otherwise, unpredictable behaviour might result. - * - * @return A {@link ByteCursor} for iterating the readable bytes of this buffer. - */ - ByteCursor openCursor(); - - /** - * Open a cursor to iterate the given number bytes of this buffer, starting at the given offset. - * The {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() witer offset} are not modified by - * the cursor. - *

- * Care should be taken to ensure that the buffer's lifetime extends beyond the cursor and the iteration, and that - * the {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() writer offset} are not modified - * while the iteration takes place. Otherwise, unpredictable behaviour might result. - * - * @param fromOffset The offset into the buffer where iteration should start. - * The first byte read from the iterator will be the byte at this offset. - * @param length The number of bytes to iterate. - * @return A {@link ByteCursor} for the given stretch of bytes of this buffer. - * @throws IllegalArgumentException if the length is negative, or if the region given by the {@code fromOffset} and - * the {@code length} reaches outside the bounds of this buffer. - */ - ByteCursor openCursor(int fromOffset, int length); - - /** - * Open a cursor to iterate the readable bytes of this buffer, in reverse. - * The {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() witer offset} are not modified by - * the cursor. - *

- * Care should be taken to ensure that the buffer's lifetime extends beyond the cursor and the iteration, and that - * the {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() writer offset} are not modified - * while the iteration takes place. Otherwise, unpredictable behaviour might result. - * - * @return A {@link ByteCursor} for the readable bytes of this buffer. - */ - default ByteCursor openReverseCursor() { - int woff = writerOffset(); - return openReverseCursor(woff == 0? 0 : woff - 1, readableBytes()); - } - - /** - * Open a cursor to iterate the given number bytes of this buffer, in reverse, starting at the given offset. - * The {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() witer offset} are not modified by - * the cursor. - *

- * Care should be taken to ensure that the buffer's lifetime extends beyond the cursor and the iteration, and that - * the {@linkplain #readerOffset() reader offset} and {@linkplain #writerOffset() writer offset} are not modified - * while the iteration takes place. Otherwise, unpredictable behaviour might result. - * - * @param fromOffset The offset into the buffer where iteration should start. - * The first byte read from the iterator will be the byte at this offset. - * @param length The number of bytes to iterate. - * @return A {@link ByteCursor} for the given stretch of bytes of this buffer. - * @throws IllegalArgumentException if the length is negative, or if the region given by the {@code fromOffset} and - * the {@code length} reaches outside the bounds of this buffer. - */ - ByteCursor openReverseCursor(int fromOffset, int length); - - /** - * Ensure that this buffer has {@linkplain #writableBytes() available space for writing} the given number of - * bytes. - * If this buffer already has the necessary space, then this method returns immediately. - * If this buffer does not already have the necessary space, then it will be expanded using the - * {@link BufferAllocator} the buffer was created with. - * This method is the same as calling {@link #ensureWritable(int, int, boolean)} where {@code allowCompaction} is - * {@code false}. - * - * @param size The requested number of bytes of space that should be available for writing. - * @throws IllegalStateException if this buffer is in a bad state. - * @throws BufferClosedException if this buffer is closed. - * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}. - */ - default void ensureWritable(int size) { - ensureWritable(size, 1, true); - } - - /** - * Ensure that this buffer has {@linkplain #writableBytes() available space for writing} the given number of - * bytes. - * If this buffer already has the necessary space, then this method returns immediately. - * If this buffer does not already have the necessary space, then space will be made available in one or all of - * the following available ways: - * - *

- * - * @param size The requested number of bytes of space that should be available for writing. - * @param minimumGrowth The minimum number of bytes to grow by. If it is determined that memory should be allocated - * and copied, make sure that the new memory allocation is bigger than the old one by at least - * this many bytes. This way, the buffer can grow by more than what is immediately necessary, - * thus amortising the costs of allocating and copying. - * @param allowCompaction {@code true} if the method is allowed to modify the - * {@linkplain #readerOffset() reader offset} and - * {@linkplain #writerOffset() writer offset}, otherwise {@code false}. - * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}. - * @throws IllegalArgumentException if {@code size} or {@code minimumGrowth} are negative. - * @throws IllegalStateException if this buffer is in a bad state. - */ - void ensureWritable(int size, int minimumGrowth, boolean allowCompaction); - - /** - * Returns a copy of this buffer's readable bytes. - * Modifying the content of the returned buffer will not affect this buffers contents. - * The two buffers will maintain separate offsets. This method is identical to - * {@code buf.copy(buf.readerOffset(), buf.readableBytes())}. - * This method does not modify {@link #readerOffset()} or {@link #writerOffset()} of this buffer. - *

- * The copy is created with a {@linkplain #writerOffset() write offset} equal to the length of the copied data, - * so that the entire contents of the copy is ready to be read. - * - * @return A new buffer instance, with independent {@link #readerOffset()} and {@link #writerOffset()}, - * that contains a copy of the readable region of this buffer. - */ - default Buffer copy() { - int offset = readerOffset(); - int length = readableBytes(); - return copy(offset, length); - } - - /** - * Returns a copy of the given region of this buffer. - * Modifying the content of the returned buffer will not affect this buffers contents. - * The two buffers will maintain separate offsets. - * This method does not modify {@link #readerOffset()} or {@link #writerOffset()} of this buffer. - *

- * The copy is created with a {@linkplain #writerOffset() write offset} equal to the length of the copy, - * so that the entire contents of the copy is ready to be read. - * - * @return A new buffer instance, with independent {@link #readerOffset()} and {@link #writerOffset()}, - * that contains a copy of the given region of this buffer. - */ - Buffer copy(int offset, int length); - - /** - * Split the buffer into two, at the {@linkplain #writerOffset() write offset} position. - *

- * The region of this buffer that contain the read and readable bytes, will be captured and returned in a new - * buffer, that will hold its own ownership of that region. This allows the returned buffer to be independently - * {@linkplain #send() sent} to other threads. - *

- * The returned buffer will adopt the {@link #readerOffset()} of this buffer, and have its {@link #writerOffset()} - * and {@link #capacity()} both set to the equal to the write-offset of this buffer. - *

- * The memory region in the returned buffer will become inaccessible through this buffer. This buffer will have its - * capacity reduced by the capacity of the returned buffer, and the read and write offsets of this buffer will both - * become zero, even though their position in memory remain unchanged. - *

- * Effectively, the following transformation takes place: - *

{@code
-     *         This buffer:
-     *          +------------------------------------------+
-     *         0|   |r/o                  |w/o             |cap
-     *          +---+---------------------+----------------+
-     *         /   /                     / \               \
-     *        /   /                     /   \               \
-     *       /   /                     /     \               \
-     *      /   /                     /       \               \
-     *     /   /                     /         \               \
-     *    +---+---------------------+           +---------------+
-     *    |   |r/o                  |w/o & cap  |r/o & w/o      |cap
-     *    +---+---------------------+           +---------------+
-     *    Returned buffer.                      This buffer.
-     * }
- * When the buffers are in this state, both of the split parts retain an atomic reference count on the - * underlying memory. This means that shared underlying memory will not be deallocated or returned to a pool, until - * all the split parts have been closed. - *

- * Composite buffers have it a little easier, in that at most only one of the constituent buffers will actually be - * split. If the split point lands perfectly between two constituent buffers, then a composite buffer can - * simply split its internal array in two. - *

- * Split buffers support all operations that normal buffers do, including {@link #ensureWritable(int)}. - *

- * See the Splitting buffers section for details. - * - * @return A new buffer with independent and exclusive ownership over the read and readable bytes from this buffer. - */ - default Buffer split() { - return split(writerOffset()); - } - - /** - * Split the buffer into two, at the given {@code splitOffset}. - *

- * The region of this buffer that precede the {@code splitOffset}, will be captured and returned in a new - * buffer, that will hold its own ownership of that region. This allows the returned buffer to be independently - * {@linkplain #send() sent} to other threads. - *

- * The returned buffer will adopt the {@link #readerOffset()} and {@link #writerOffset()} of this buffer, - * but truncated to fit within the capacity dictated by the {@code splitOffset}. - *

- * The memory region in the returned buffer will become inaccessible through this buffer. If the - * {@link #readerOffset()} or {@link #writerOffset()} of this buffer lie prior to the {@code splitOffset}, - * then those offsets will be moved forward, so they land on offset 0 after the split. - *

- * Effectively, the following transformation takes place: - *

{@code
-     *         This buffer:
-     *          +--------------------------------+
-     *         0|               |splitOffset     |cap
-     *          +---------------+----------------+
-     *         /               / \               \
-     *        /               /   \               \
-     *       /               /     \               \
-     *      /               /       \               \
-     *     /               /         \               \
-     *    +---------------+           +---------------+
-     *    |               |cap        |               |cap
-     *    +---------------+           +---------------+
-     *    Returned buffer.            This buffer.
-     * }
- * When the buffers are in this state, both of the split parts retain an atomic reference count on the - * underlying memory. This means that shared underlying memory will not be deallocated or returned to a pool, until - * all the split parts have been closed. - *

- * Composite buffers have it a little easier, in that at most only one of the constituent buffers will actually be - * split. If the split point lands perfectly between two constituent buffers, then a composite buffer can - * simply split its internal array in two. - *

- * Split buffers support all operations that normal buffers do, including {@link #ensureWritable(int)}. - *

- * See the Splitting buffers section for details. - * - * @return A new buffer with independent and exclusive ownership over the bytes from the beginning to the given - * offset of this buffer. - */ - Buffer split(int splitOffset); - - /** - * Discards the read bytes, and moves the buffer contents to the beginning of the buffer. - * - * @throws BufferReadOnlyException if this buffer is {@linkplain #readOnly() read-only}. - * @throws IllegalStateException if this buffer is in a bad state. - */ - void compact(); - - /** - * Get the number of "components" in this buffer. For composite buffers, this is the number of transitive - * constituent buffers, while non-composite buffers only have one component. - * - * @return The number of components in this buffer. - */ - int countComponents(); - - /** - * Get the number of "components" in this buffer, that are readable. These are the components that would be - * processed by {@link #forEachReadable(int, ReadableComponentProcessor)}. For composite buffers, this is the - * number of transitive constituent buffers that are readable, while non-composite buffers only have at most one - * readable component. - *

- * The number of readable components may be less than the {@link #countComponents() component count}, if not all of - * them have readable data. - * - * @return The number of readable components in this buffer. - */ - int countReadableComponents(); - - /** - * Get the number of "components" in this buffer, that are writable. These are the components that would be - * processed by {@link #forEachWritable(int, WritableComponentProcessor)}. For composite buffers, this is the - * number of transitive constituent buffers that are writable, while non-composite buffers only have at most one - * writable component. - *

- * The number of writable components may be less than the {@link #countComponents() component count}, if not all of - * them have space for writing. - * - * @return The number of writable components in this buffer. - */ - int countWritableComponents(); - - /** - * Process all readable components of this buffer, and return the number of components processed. - *

- * The given {@linkplain ReadableComponentProcessor processor} is called for each readable component in this buffer, - * and passed a component index, for the given component in the iteration, and a {@link ReadableComponent} object - * for accessing the data within the given component. - *

- * The component index is specific to the particular invokation of this method. The first call to the consumer will - * be passed the given initial index, and the next call will be passed the initial index plus one, and so on. - *

- * The {@linkplain ReadableComponentProcessor component processor} may stop the iteration at any time by returning - * {@code false}. - * This will cause the number of components processed to be returned as a negative number (to signal early return), - * and the number of components processed may then be less than the - * {@linkplain #countReadableComponents() readable component count}. - *

- * Note that the {@link ReadableComponent} instance passed to the consumer could be reused for - * multiple calls, so the data must be extracted from the component in the context of the iteration. - *

- * The {@link ByteBuffer} instances obtained from the component, share lifetime with that internal component. - * This means they can be accessed as long as the internal memory store remain unchanged. Methods that may cause - * such changes are {@link #split(int)}, {@link #split()}, {@link #compact()}, {@link #ensureWritable(int)}, - * {@link #ensureWritable(int, int, boolean)}, and {@link #send()}. - *

- * The best way to ensure this doesn't cause any trouble, is to use the buffers directly as part of the iteration, - * or immediately after the iteration while we are still in the scope of the method that triggered the iteration. - *

- * Note that the arrays, memory addresses, and byte buffers exposed as components by this method, - * should not be used for changing the buffer contents. Doing so may cause undefined behaviour. - *

- * Changes to position and limit of the byte buffers exposed via the processed components, are not reflected back to - * this buffer instance. - * - * @param initialIndex The initial index of the iteration, and the index that will be passed to the first call to - * the {@linkplain ReadableComponentProcessor#process(int, ReadableComponent) processor}. - * @param processor The processor that will be used to process the buffer components. - * @return The number of readable components processed, as a positive number of all readable components were - * processed, or as a negative number if the iteration was stopped because - * {@link ReadableComponentProcessor#process(int, ReadableComponent)} returned {@code false}. - * In any case, the number of components processed may be less than {@link #countComponents()}. - */ - int forEachReadable(int initialIndex, ReadableComponentProcessor processor) throws E; - - /** - * Process all writable components of this buffer, and return the number of components processed. - *

- * The given {@linkplain WritableComponentProcessor processor} is called for each writable component in this buffer, - * and passed a component index, for the given component in the iteration, and a {@link WritableComponent} object - * for accessing the data within the given component. - *

- * The component index is specific to the particular invokation of this method. The first call to the consumer will - * be passed the given initial index, and the next call will be passed the initial index plus one, and so on. - *

- * The {@link WritableComponentProcessor component processor} may stop the iteration at any time by returning - * {@code false}. - * This will cause the number of components processed to be returned as a negative number (to signal early return), - * and the number of components processed may then be less than the - * {@linkplain #countReadableComponents() readable component count}. - *

- * Note that the {@link WritableComponent} instance passed to the consumer could be reused for - * multiple calls, so the data must be extracted from the component in the context of the iteration. - *

- * The {@link ByteBuffer} instances obtained from the component, share lifetime with that internal component. - * This means they can be accessed as long as the internal memory store remain unchanged. Methods that may cause - * such changes are {@link #split(int)}, {@link #split()}, {@link #compact()}, {@link #ensureWritable(int)}, - * {@link #ensureWritable(int, int, boolean)}, and {@link #send()}. - *

- * The best way to ensure this doesn't cause any trouble, is to use the buffers directly as part of the iteration, - * or immediately after the iteration while we are still in the scope of the method that triggered the iteration. - *

- * Changes to position and limit of the byte buffers exposed via the processed components, are not reflected back to - * this buffer instance. - * - * @param initialIndex The initial index of the iteration, and the index that will be passed to the first call to - * the {@linkplain WritableComponentProcessor#process(int, WritableComponent) processor}. - * @param processor The processor that will be used to process the buffer components. - * @return The number of writable components processed, as a positive number of all writable components were - * processed, or as a negative number if the iteration was stopped because - * {@link WritableComponentProcessor#process(int, WritableComponent)} returned {@code false}. - * In any case, the number of components processed may be less than {@link #countComponents()}. - */ - int forEachWritable(int initialIndex, WritableComponentProcessor processor) throws E; -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferAccessors.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferAccessors.java deleted file mode 100644 index 2ff30fe..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/BufferAccessors.java +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -/** - * This interface is just the primitive data accessor methods that {@link Buffer} exposes. - * It can be useful if you only need the data access methods, and perhaps wish to decorate or modify their behaviour. - * Usually, you'd use the {@link Buffer} interface directly, since this lets you properly control the buffer reference - * count. - */ -public interface BufferAccessors { - // - /** - * Get the byte value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by {@link Byte#BYTES}. - * The value is read using a two's complement 8-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The byte value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Byte#BYTES}. - */ - byte readByte(); - - /** - * Get the byte value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using a two's complement 8-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The byte value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Byte#BYTES}. - */ - byte getByte(int roff); - - /** - * Get the unsigned byte value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by {@link Byte#BYTES}. - * The value is read using an unsigned two's complement 8-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The unsigned byte value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Byte#BYTES}. - */ - int readUnsignedByte(); - - /** - * Get the unsigned byte value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using an unsigned two's complement 8-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The unsigned byte value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Byte#BYTES}. - */ - int getUnsignedByte(int roff); - - /** - * Set the given byte value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by {@link Byte#BYTES}. - * The value is written using a two's complement 8-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The byte value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Byte#BYTES}. - */ - Buffer writeByte(byte value); - - /** - * Set the given byte value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using a two's complement 8-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The byte value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Byte#BYTES}. - */ - Buffer setByte(int woff, byte value); - - /** - * Set the given unsigned byte value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by {@link Byte#BYTES}. - * The value is written using an unsigned two's complement 8-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Byte#BYTES}. - */ - Buffer writeUnsignedByte(int value); - - /** - * Set the given unsigned byte value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using an unsigned two's complement 8-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Byte#BYTES}. - */ - Buffer setUnsignedByte(int woff, int value); - - /** - * Get the char value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by 2. - * The value is read using a 2-byte UTF-16 encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The char value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than 2. - */ - char readChar(); - - /** - * Get the char value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using a 2-byte UTF-16 encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The char value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus 2. - */ - char getChar(int roff); - - /** - * Set the given char value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by 2. - * The value is written using a 2-byte UTF-16 encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The char value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than 2. - */ - Buffer writeChar(char value); - - /** - * Set the given char value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using a 2-byte UTF-16 encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The char value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus 2. - */ - Buffer setChar(int woff, char value); - - /** - * Get the short value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by {@link Short#BYTES}. - * The value is read using a two's complement 16-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The short value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Short#BYTES}. - */ - short readShort(); - - /** - * Get the short value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using a two's complement 16-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The short value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Short#BYTES}. - */ - short getShort(int roff); - - /** - * Get the unsigned short value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by {@link Short#BYTES}. - * The value is read using an unsigned two's complement 16-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The unsigned short value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Short#BYTES}. - */ - int readUnsignedShort(); - - /** - * Get the unsigned short value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using an unsigned two's complement 16-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The unsigned short value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Short#BYTES}. - */ - int getUnsignedShort(int roff); - - /** - * Set the given short value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by {@link Short#BYTES}. - * The value is written using a two's complement 16-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The short value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Short#BYTES}. - */ - Buffer writeShort(short value); - - /** - * Set the given short value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using a two's complement 16-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The short value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Short#BYTES}. - */ - Buffer setShort(int woff, short value); - - /** - * Set the given unsigned short value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by {@link Short#BYTES}. - * The value is written using an unsigned two's complement 16-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Short#BYTES}. - */ - Buffer writeUnsignedShort(int value); - - /** - * Set the given unsigned short value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using an unsigned two's complement 16-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Short#BYTES}. - */ - Buffer setUnsignedShort(int woff, int value); - - /** - * Get the int value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by 3. - * The value is read using a two's complement 24-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The int value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than 3. - */ - int readMedium(); - - /** - * Get the int value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using a two's complement 24-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The int value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus 3. - */ - int getMedium(int roff); - - /** - * Get the unsigned int value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by 3. - * The value is read using an unsigned two's complement 24-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The unsigned int value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than 3. - */ - int readUnsignedMedium(); - - /** - * Get the unsigned int value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using an unsigned two's complement 24-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The unsigned int value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus 3. - */ - int getUnsignedMedium(int roff); - - /** - * Set the given int value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by 3. - * The value is written using a two's complement 24-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than 3. - */ - Buffer writeMedium(int value); - - /** - * Set the given int value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using a two's complement 24-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus 3. - */ - Buffer setMedium(int woff, int value); - - /** - * Set the given unsigned int value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by 3. - * The value is written using an unsigned two's complement 24-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than 3. - */ - Buffer writeUnsignedMedium(int value); - - /** - * Set the given unsigned int value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using an unsigned two's complement 24-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus 3. - */ - Buffer setUnsignedMedium(int woff, int value); - - /** - * Get the int value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by {@link Integer#BYTES}. - * The value is read using a two's complement 32-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The int value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Integer#BYTES}. - */ - int readInt(); - - /** - * Get the int value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using a two's complement 32-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The int value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Integer#BYTES}. - */ - int getInt(int roff); - - /** - * Get the unsigned int value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by {@link Integer#BYTES}. - * The value is read using an unsigned two's complement 32-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The unsigned int value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Integer#BYTES}. - */ - long readUnsignedInt(); - - /** - * Get the unsigned int value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using an unsigned two's complement 32-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The unsigned int value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Integer#BYTES}. - */ - long getUnsignedInt(int roff); - - /** - * Set the given int value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by {@link Integer#BYTES}. - * The value is written using a two's complement 32-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Integer#BYTES}. - */ - Buffer writeInt(int value); - - /** - * Set the given int value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using a two's complement 32-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The int value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Integer#BYTES}. - */ - Buffer setInt(int woff, int value); - - /** - * Set the given unsigned int value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by {@link Integer#BYTES}. - * The value is written using an unsigned two's complement 32-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The long value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Integer#BYTES}. - */ - Buffer writeUnsignedInt(long value); - - /** - * Set the given unsigned int value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using an unsigned two's complement 32-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The long value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Integer#BYTES}. - */ - Buffer setUnsignedInt(int woff, long value); - - /** - * Get the float value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by {@link Float#BYTES}. - * The value is read using a 32-bit IEEE floating point encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The float value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Float#BYTES}. - */ - float readFloat(); - - /** - * Get the float value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using a 32-bit IEEE floating point encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The float value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Float#BYTES}. - */ - float getFloat(int roff); - - /** - * Set the given float value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by {@link Float#BYTES}. - * The value is written using a 32-bit IEEE floating point encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The float value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Float#BYTES}. - */ - Buffer writeFloat(float value); - - /** - * Set the given float value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using a 32-bit IEEE floating point encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The float value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Float#BYTES}. - */ - Buffer setFloat(int woff, float value); - - /** - * Get the long value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by {@link Long#BYTES}. - * The value is read using a two's complement 64-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The long value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Long#BYTES}. - */ - long readLong(); - - /** - * Get the long value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using a two's complement 64-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The long value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Long#BYTES}. - */ - long getLong(int roff); - - /** - * Set the given long value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by {@link Long#BYTES}. - * The value is written using a two's complement 64-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The long value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Long#BYTES}. - */ - Buffer writeLong(long value); - - /** - * Set the given long value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using a two's complement 64-bit encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The long value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Long#BYTES}. - */ - Buffer setLong(int woff, long value); - - /** - * Get the double value at the current {@link Buffer#readerOffset()}, - * and increases the reader offset by {@link Double#BYTES}. - * The value is read using a 64-bit IEEE floating point encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @return The double value at the current reader offset. - * @throws IndexOutOfBoundsException If {@link Buffer#readableBytes} is less than {@link Double#BYTES}. - */ - double readDouble(); - - /** - * Get the double value at the given reader offset. - * The {@link Buffer#readerOffset()} is not modified. - * The value is read using a 64-bit IEEE floating point encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param roff The read offset, an absolute offset into this buffer, to read from. - * @return The double value at the given offset. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Double#BYTES}. - */ - double getDouble(int roff); - - /** - * Set the given double value at the current {@link Buffer#writerOffset()}, - * and increase the writer offset by {@link Double#BYTES}. - * The value is written using a 64-bit IEEE floating point encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param value The double value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException If {@link Buffer#writableBytes} is less than {@link Double#BYTES}. - */ - Buffer writeDouble(double value); - - /** - * Set the given double value at the given write offset. The {@link Buffer#writerOffset()} is not modified. - * The value is written using a 64-bit IEEE floating point encoding, - * with the {@link Buffer#order() configured} default byte order. - * - * @param woff The write offset, an absolute offset into this buffer to write to. - * @param value The double value to write. - * @return This Buffer. - * @throws IndexOutOfBoundsException if the given offset is out of bounds of the buffer, that is, less than 0 or - * greater than {@link Buffer#capacity()} minus {@link Double#BYTES}. - */ - Buffer setDouble(int woff, double value); - // -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferAllocator.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferAllocator.java deleted file mode 100644 index 16e847b..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/BufferAllocator.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import io.netty.buffer.api.pool.PooledBufferAllocator; - -import java.nio.ByteOrder; -import java.util.function.Supplier; - -/** - * Interface for {@link Buffer} allocators. - */ -public interface BufferAllocator extends AutoCloseable { - /** - * Check that the given {@code size} argument is a valid buffer size, or throw an {@link IllegalArgumentException}. - * - * @param size The size to check. - * @throws IllegalArgumentException if the size is not positive, or if the size is too big (over ~2 GB) for a - * buffer to accommodate. - */ - static void checkSize(long size) { - if (size < 1) { - throw new IllegalArgumentException("Buffer size must be positive, but was " + size + '.'); - } - // We use max array size because on-heap buffers will be backed by byte-arrays. - int maxArraySize = Integer.MAX_VALUE - 8; - if (size > maxArraySize) { - throw new IllegalArgumentException( - "Buffer size cannot be greater than " + maxArraySize + ", but was " + size + '.'); - } - } - - /** - * Allocate a {@link Buffer} of the given size in bytes. This method may throw an {@link OutOfMemoryError} if there - * is not enough free memory available to allocate a {@link Buffer} of the requested size. - *

- * The buffer will use the current platform native byte order by default, for accessor methods that don't have an - * explicit byte order. - * - * @param size The size of {@link Buffer} to allocate. - * @return The newly allocated {@link Buffer}. - */ - Buffer allocate(int size); - - /** - * Allocate a {@link Buffer} of the given size in bytes. This method may throw an {@link OutOfMemoryError} if there - * is not enough free memory available to allocate a {@link Buffer} of the requested size. - *

- * The buffer will use the given byte order by default. - * - * @param size The size of {@link Buffer} to allocate. - * @param order The default byte order used by the accessor methods that don't have an explicit byte order. - * @return The newly allocated {@link Buffer}. - */ - default Buffer allocate(int size, ByteOrder order) { - return allocate(size).order(order); - } - - /** - * Create a supplier of "constant" {@linkplain Buffer Buffers} from this allocator, that all have the given - * byte contents. The buffer has the same capacity as the byte array length, and its write offset is placed at the - * end, and its read offset is at the beginning, such that the entire buffer contents are readable. - *

- * The buffers produced by the supplier will each have their own independent life-cycle, and closing them will - * make them {@linkplain Buffer#isAccessible() inaccessible}, just like normally allocated buffers. - *

- * The buffers produced are "constants", in the sense that they are {@linkplain Buffer#readOnly() read-only}. - *

- * It can generally be expected, but is not guaranteed, that the returned supplier is more resource efficient than - * allocating and copying memory with other available APIs. In such optimised implementations, the underlying memory - * baking the buffers will be shared among all the buffers produced by the supplier. - *

- * The primary use case for this API, is when you need to repeatedly produce buffers with the same contents, and - * you perhaps wish to keep a {@code static final} field with these contents. This use case has previously been - * solved by allocating a read-only buffer with the given contents, and then slicing or duplicating it on every use. - * This approach had several problems. For instance, if you forget to slice, the offsets of the buffer can change - * in unexpected ways, since the same buffer instance is shared and accessed from many places. The buffer could also - * be deallocated, making the data inaccessible. The supplier-based API solves all of these problems, by enforcing - * that each usage get their own distinct buffer instance. - * - * @param bytes The byte contents of the buffers produced by the returned supplier. - * @return A supplier of read-only buffers with the given contents. - */ - default Supplier constBufferSupplier(byte[] bytes) { - byte[] safeCopy = bytes.clone(); // Prevent modifying the bytes after creating the supplier. - return () -> allocate(bytes.length).writeBytes(safeCopy).makeReadOnly(); - } - - /** - * Close this allocator, freeing all of its internal resources. - *

- * Existing (currently in-use) allocated buffers will not be impacted by calling this method. - * If this is a pooling or caching allocator, then existing buffers will be immediately freed when they are closed, - * instead of being pooled or cached. - *

- * The allocator can still be used to allocate more buffers after calling this method. - * However, if this is a pooling or caching allocator, then the pooling and caching functionality will be - * effectively disabled after calling this method. - *

- * If this allocator does not perform any pooling or caching, then calling this method likely has no effect. - */ - @Override - default void close() { - } - - static BufferAllocator heap() { - return new ManagedBufferAllocator(MemoryManagers.getManagers().getHeapMemoryManager()); - } - - static BufferAllocator direct() { - return new ManagedBufferAllocator(MemoryManagers.getManagers().getNativeMemoryManager()); - } - - static BufferAllocator pooledHeap() { - return new PooledBufferAllocator(MemoryManagers.getManagers().getHeapMemoryManager()); - } - - static BufferAllocator pooledDirect() { - return new PooledBufferAllocator(MemoryManagers.getManagers().getNativeMemoryManager()); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferClosedException.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferClosedException.java deleted file mode 100644 index a47058e..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/BufferClosedException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -/** - * An exception thrown when an operation is attempted on a {@link Buffer} when it has been closed. - */ -public final class BufferClosedException extends UnsupportedOperationException { - private static final long serialVersionUID = 85913332711192868L; - - public BufferClosedException(final String message) { - super(message); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferHolder.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferHolder.java deleted file mode 100644 index 751f43a..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/BufferHolder.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import io.netty.buffer.api.internal.ResourceSupport; -import io.netty.buffer.api.internal.Statics; - -import java.lang.invoke.VarHandle; -import java.util.Objects; - -import static java.lang.invoke.MethodHandles.lookup; - -/** - * The {@link BufferHolder} is an abstract class that simplifies the implementation of objects that themselves contain - * a {@link Buffer} instance. - *

- * The {@link BufferHolder} can only hold on to a single buffer, so objects and classes that need to hold on to multiple - * buffers will have to do their implementation from scratch, though they can use the code of the {@link BufferHolder} - * as inspiration. - *

- * If you just want an object that is a reference to a buffer, then the {@link BufferRef} can be used for that purpose. - * If you have an advanced use case where you wish to implement {@link Resource}, and tightly control lifetimes, then - * {@link ResourceSupport} can be of help. - * - * @param The concrete {@link BufferHolder} type. - */ -public abstract class BufferHolder> implements Resource { - private static final VarHandle BUF = Statics.findVarHandle(lookup(), BufferHolder.class, "buf", Buffer.class); - private Buffer buf; - - /** - * Create a new {@link BufferHolder} to hold the given {@linkplain Buffer buffer}. - *

- * Note: this increases the reference count of the given buffer. - * - * @param buf The {@linkplain Buffer buffer} to be held by this holder. - */ - protected BufferHolder(Buffer buf) { - this.buf = Objects.requireNonNull(buf, "The buffer cannot be null."); - } - - /** - * Create a new {@link BufferHolder} to hold the {@linkplain Buffer buffer} received from the given {@link Send}. - *

- * The {@link BufferHolder} will then be holding exclusive ownership of the buffer. - * - * @param send The {@linkplain Buffer buffer} to be held by this holder. - */ - protected BufferHolder(Send send) { - buf = Objects.requireNonNull(send, "The send cannot be null.").receive(); - } - - @Override - public void close() { - buf.close(); - } - - @SuppressWarnings("unchecked") - @Override - public Send send() { - return buf.send().map((Class) getClass(), this::receive); - } - - /** - * Called when a {@linkplain #send() sent} {@link BufferHolder} is received by the recipient. - * The {@link BufferHolder} should return a new concrete instance, that wraps the given {@link Buffer} object. - * - * @param buf The {@link Buffer} that is {@linkplain Send#receive() received} by the recipient, - * and needs to be wrapped in a new {@link BufferHolder} instance. - * @return A new {@linkplain T buffer holder} instance, containing the given {@linkplain Buffer buffer}. - */ - protected abstract T receive(Buffer buf); - - /** - * Replace the underlying referenced buffer with the given buffer. - *

- * This method is protected to permit advanced use cases of {@link BufferHolder} sub-class implementations. - *

- * Note: this method decreases the reference count of the current buffer, - * and takes exclusive ownership of the sent buffer. - *

- * The buffer assignment is performed using a plain store. - * - * @param send The new {@link Buffer} instance that is replacing the currently held buffer. - */ - protected final void replaceBuffer(Send send) { - Buffer received = send.receive(); - buf.close(); - buf = received; - } - - /** - * Replace the underlying referenced buffer with the given buffer. - *

- * This method is protected to permit advanced use cases of {@link BufferHolder} sub-class implementations. - *

- * Note: this method decreases the reference count of the current buffer, - * and takes exclusive ownership of the sent buffer. - *

- * The buffer assignment is performed using a volatile store. - * - * @param send The {@link Send} with the new {@link Buffer} instance that is replacing the currently held buffer. - */ - protected final void replaceBufferVolatile(Send send) { - Buffer received = send.receive(); - var prev = (Buffer) BUF.getAndSet(this, received); - prev.close(); - } - - /** - * Access the held {@link Buffer} instance. - *

- * The access is performed using a plain load. - * - * @return The {@link Buffer} instance being held by this {@linkplain T buffer holder}. - */ - protected final Buffer getBuffer() { - return buf; - } - - /** - * Access the held {@link Buffer} instance. - *

- * The access is performed using a volatile load. - * - * @return The {@link Buffer} instance being held by this {@linkplain T buffer holder}. - */ - protected final Buffer getBufferVolatile() { - return (Buffer) BUF.getVolatile(this); - } - - @Override - public boolean isAccessible() { - return buf.isAccessible(); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferReadOnlyException.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferReadOnlyException.java deleted file mode 100644 index aaf712a..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/BufferReadOnlyException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -/** - * An exception thrown when an operation is attempted on a {@linkplain Buffer#readOnly() read-only} {@link Buffer}. - */ -public final class BufferReadOnlyException extends UnsupportedOperationException { - private static final long serialVersionUID = 4855825594125231593L; - - public BufferReadOnlyException(final String message) { - super(message); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/BufferRef.java b/buffer-api/src/main/java/io/netty/buffer/api/BufferRef.java deleted file mode 100644 index 3a87c6f..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/BufferRef.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import java.lang.invoke.VarHandle; - -/** - * A mutable reference to a buffer. - */ -public final class BufferRef extends BufferHolder { - /** - * Create a reference to the given {@linkplain Buffer buffer}. - * This increments the reference count of the buffer. - * - * @param buf The buffer to reference. - */ - private BufferRef(Buffer buf) { - super(buf); - // BufferRef is meant to be atomic, so we need to add a fence to get the semantics of a volatile store. - VarHandle.fullFence(); - } - - /** - * Create a reference that holds the exclusive ownership of the sent buffer. - * - * @param send The {@linkplain Send sent} buffer to take ownership of. - */ - public BufferRef(Send send) { - super(send); - // BufferRef is meant to be atomic, so we need to add a fence to get the semantics of a volatile store. - VarHandle.fullFence(); - } - - @Override - protected BufferRef receive(Buffer buf) { - return new BufferRef(buf); - } - - /** - * Replace the underlying referenced buffer with the given buffer. - *

- * Note: this method decreases the reference count of the current buffer, - * and takes exclusive ownership of the sent buffer. - *

- * The buffer assignment is performed using a volatile store. - * - * @param send The {@link Send} with the new {@link Buffer} instance that is replacing the currently held buffer. - */ - public void replace(Send send) { - replaceBufferVolatile(send); - } - - /** - * Access the buffer in this reference. - * - * @return The buffer held by the reference. - */ - public Buffer contents() { - return getBufferVolatile(); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ByteCursor.java b/buffer-api/src/main/java/io/netty/buffer/api/ByteCursor.java deleted file mode 100644 index 3c85ad5..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/ByteCursor.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import io.netty.util.ByteProcessor; - -/** - * The ByteCursor scans through a sequence of bytes. - * This is similar to {@link ByteProcessor}, but for external iteration rather than internal iteration. - * The external iteration allows the callers to control the pace of the iteration. - * The API includes methods for reading {@code long}s as a batch of 8 bytes. - * The long values are always in big-endian format, so that the highest-order byte in the long value, contain the byte - * that would otherwise have been returned by the next call to {@link #getByte()}. - */ -public interface ByteCursor { - /** - * Check if the iterator has at least 8 bytes left, and if so, read those 8 bytes and move the cursor forward. - * The bytes are packed as a {@code long} value in big-endian format, such that the highest-order byte - * in the long, is the byte that would otherwise have been returned by the next call to {@link #getByte()}, - * after a call to {@link #readByte()}. - * The bytes (as a {@code long}) will then be available through the {@link #getLong()} method. - *

- * Note that when this method returns {@code false}, the {@link #readByte()} can still return {@code true}. - * It is recommended to have any long-processing loop be followed by a byte-processing loop for the 7 or fewer - * bytes that might form a tail in the cursor. - *

- * Also note that this method will not influence what is returned the {@link #getByte()} method. - * - * @return {@code true} if the cursor read 8 bytes and moved forward, otherwise {@code false}. - */ - boolean readLong(); - - /** - * Return the last 8 bytes read by {@link #readLong()}. - * If {@link #readLong()} has not been called on this cursor before, then {@code -1} is returned. - *

- * The long value is in the big-endian format, such that the highest-order by of the long value, is the byte that - * would otherwise have been produced by a {@link #readByte()} / {@link #getByte()} pair. - * This means that cursors that iterate in reverse, e.g. from {@link Buffer#openReverseCursor()}, return longs in a - * "mirrored" or "reversed" big-endian format. - * - * @return The 8 bytes, in big-endian format, that was read by the most recent successful call to - * {@link #readLong()}. - */ - long getLong(); - - /** - * Check if the iterator has at least one byte left, and if so, read that byte and move the cursor forward. - * The byte will then be available through the {@link #getByte()}. - *

- * Note that this method will not influence what is returned from the {@link #getLong()} method. - * - * @return {@code true} if the cursor read a byte and moved forward, otherwise {@code false}. - */ - boolean readByte(); - - /** - * Return the last byte that was read by {@link #readByte()}. - * If {@link #readByte()} has not been called on this cursor before, then {@code -1} is returned. - * - * @return The next byte that was read by the most recent successful call to {@link #readByte()}. - */ - byte getByte(); - - /** - * The current position of this iterator into the underlying sequence of bytes. - * For instance, if we are iterating a buffer, this would be the iterators current offset into the buffer. - * - * @return The current iterator offset into the underlying sequence of bytes. - */ - int currentOffset(); - - /** - * Get the current number of bytes left in the iterator. - * - * @return The number of bytes left in the iterator. - */ - int bytesLeft(); - - /** - * Process the remaining bytes in this iterator with the given {@link ByteProcessor}. - * This method consumes the iterator. - * - * @param processor The processor to use for processing the bytes in the iterator. - * @return The number of bytes processed, if the {@link ByteProcessor#process(byte) process} method returned - * {@code false}, or {@code -1} if the whole iterator was processed. - */ - default int process(ByteProcessor processor) { - boolean requestMore = true; - int count = 0; - while (readByte() && (requestMore = processor.process(getByte()))) { - count++; - } - return requestMore? -1 : count; - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/CompositeBuffer.java b/buffer-api/src/main/java/io/netty/buffer/api/CompositeBuffer.java deleted file mode 100644 index c5c56e2..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/CompositeBuffer.java +++ /dev/null @@ -1,2016 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import io.netty.buffer.api.internal.ResourceSupport; -import io.netty.buffer.api.internal.Statics; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Stream; - -import static io.netty.buffer.api.internal.Statics.bufferIsClosed; -import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly; - -/** - * The {@code CompositeBuffer} is a concrete {@link Buffer} implementation that make a number of other buffers appear - * as one. A composite buffer behaves the same as a normal, non-composite buffer in every way, so you normally don't - * need to handle them specially. - *

- * A composite buffer is constructed using one of the {@code compose} methods: - *

- * Composite buffers can later be extended with internally allocated components, with {@link #ensureWritable(int)}, - * or with externally allocated buffers, using {@link #extendWith(Send)}. - * - *

Constituent buffer requirements

- * - * The buffers that a being composed to form the composite buffer, need to live up to a number of requirements. - * Basically, if we imagine that the constituent buffers have their memory regions concatenated together, then the - * result needs to make sense. - *

- * All the constituent buffers must have the same {@linkplain Buffer#order() byte order}. - * An exception will be thrown if you attempt to compose buffers that have different byte orders, - * and changing the byte order of the constituent buffers so that they become inconsistent after construction, - * will result in unspecified behaviour. - *

- * The read and write offsets of the constituent buffers must be arranged such that there are no "gaps" when viewed - * as a single connected chunk of memory. - * Specifically, there can be at most one buffer whose write offset is neither zero nor at capacity, - * and all buffers prior to it must have their write offsets at capacity, and all buffers after it must have a - * write-offset of zero. - * Likewise, there can be at most one buffer whose read offset is neither zero nor at capacity, - * and all buffers prior to it must have their read offsets at capacity, and all buffers after it must have a read - * offset of zero. - * Furthermore, the sum of the read offsets must be less than or equal to the sum of the write-offsets. - *

- * Reads and writes to the composite buffer that modifies the read or write offsets, will also modify the relevant - * offsets in the constituent buffers. - *

- * It is not a requirement that the buffers have the same size. - *

- * It is not a requirement that the buffers are allocated by this allocator, but if - * {@link Buffer#ensureWritable(int)} is called on the composed buffer, and the composed buffer needs to be - * expanded, then this allocator instance will be used for allocation the extra memory. - * - *

Ownership and Send

- * - * {@linkplain Resource#send() Sending} a composite buffer implies sending all of its constituent buffers. - * For sending to be possible, both the composite buffer itself, and all of its constituent buffers, must be in a - * state that permits them being sent. This should be the case by default, as it shouldn't be possible to create - * composite buffers that can't be sent. - */ -public final class CompositeBuffer extends ResourceSupport implements Buffer { - /** - * The max array size is JVM implementation dependant, but most seem to settle on {@code Integer.MAX_VALUE - 8}. - * We set the max composite buffer capacity to the same, since it would otherwise be impossible to create a - * non-composite copy of the buffer. - */ - private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8; - private static final Drop COMPOSITE_DROP = new Drop() { - @Override - public void drop(CompositeBuffer buf) { - for (Buffer b : buf.bufs) { - b.close(); - } - buf.makeInaccessible(); - } - - @Override - public String toString() { - return "COMPOSITE_DROP"; - } - }; - private static final Buffer[] EMPTY_BUFFER_ARRAY = new Buffer[0]; - - private final BufferAllocator allocator; - private final TornBufferAccessors tornBufAccessors; - private Buffer[] bufs; - private int[] offsets; // The offset, for the composite buffer, where each constituent buffer starts. - private int capacity; - private int roff; - private int woff; - private int subOffset; // The next offset *within* a consituent buffer to read from or write to. - private ByteOrder order; - private boolean closed; - private boolean readOnly; - - /** - * Compose the given sequence of sends of buffers and present them as a single buffer. - *

- * Note: The composite buffer holds a reference to all the constituent buffers, - * until the composite buffer is deallocated. - * This means the constituent buffers must still have their outside-reference count decremented as normal. - * If the buffers are allocated for the purpose of participating in the composite buffer, - * then they should be closed as soon as the composite buffer has been created, like in this example: - *

{@code
-     *     try (Buffer a = allocator.allocate(size);
-     *          Buffer b = allocator.allocate(size)) {
-     *         return allocator.compose(a, b); // Reference counts for 'a' and 'b' incremented here.
-     *     } // Reference count for 'a' and 'b' decremented here; composite buffer now holds the last references.
-     * }
- *

- * See the class documentation for more information on what is required of the given buffers for composition to be - * allowed. - * - * @param allocator The allocator for the composite buffer. This allocator will be used e.g. to service - * {@link #ensureWritable(int)} calls. - * @param sends The sent buffers to compose into a single buffer view. - * @return A buffer composed of, and backed by, the given buffers. - * @throws IllegalArgumentException if the given buffers have an inconsistent - * {@linkplain Buffer#order() byte order}. - * @throws IllegalStateException if one of the sends have already been received. The remaining buffers and sends - * will be closed and discarded, respectively. - */ - @SafeVarargs - public static CompositeBuffer compose(BufferAllocator allocator, Send... sends) { - Buffer[] bufs = new Buffer[sends.length]; - IllegalStateException ise = null; - for (int i = 0; i < sends.length; i++) { - if (ise != null) { - sends[i].discard(); - } else { - try { - bufs[i] = sends[i].receive(); - } catch (IllegalStateException e) { - ise = e; - for (int j = 0; j < i; j++) { - bufs[j].close(); - } - } - } - } - if (ise != null) { - throw ise; - } - return new CompositeBuffer(allocator, filterExternalBufs(Arrays.stream(bufs)), COMPOSITE_DROP); - } - - /** - * Create an empty composite buffer, that has no components. The buffer can be extended with components using either - * {@link #ensureWritable(int)} or {@link #extendWith(Send)}. - * - * @param allocator The allocator for the composite buffer. This allocator will be used e.g. to service - * {@link #ensureWritable(int)} calls. - * @return A composite buffer that has no components, and has a capacity of zero. - */ - public static CompositeBuffer compose(BufferAllocator allocator) { - return new CompositeBuffer(allocator, EMPTY_BUFFER_ARRAY, COMPOSITE_DROP); - } - - /** - * Check if the given buffer is a {@linkplain #compose(BufferAllocator, Send...) composite} buffer or not. - * @param composite The buffer to check. - * @return {@code true} if the given buffer was created with {@link #compose(BufferAllocator, Send...)}, - * {@code false} otherwise. - */ - public static boolean isComposite(Buffer composite) { - return composite.getClass() == CompositeBuffer.class; - } - - private static Buffer[] filterExternalBufs(Stream refs) { - // We filter out all zero-capacity buffers because they wouldn't contribute to the composite buffer anyway, - // and also, by ensuring that all constituent buffers contribute to the size of the composite buffer, - // we make sure that the number of composite buffers will never become greater than the number of bytes in - // the composite buffer. - // This restriction guarantees that methods like countComponents, forEachReadable and forEachWritable, - // will never overflow their component counts. - // Allocating a new array unconditionally also prevents external modification of the array. - Buffer[] bufs = refs - .filter(CompositeBuffer::discardEmpty) - .flatMap(CompositeBuffer::flattenBuffer) - .toArray(Buffer[]::new); - // Make sure there are no duplicates among the buffers. - Set duplicatesCheck = Collections.newSetFromMap(new IdentityHashMap<>()); - duplicatesCheck.addAll(Arrays.asList(bufs)); - if (duplicatesCheck.size() < bufs.length) { - for (Buffer buf : bufs) { - buf.close(); // Undo the increment we did with Deref.get(). - } - throw new IllegalArgumentException( - "Cannot create composite buffer with duplicate constituent buffer components."); - } - return bufs; - } - - private static boolean discardEmpty(Buffer buf) { - if (buf.capacity() > 0) { - return true; - } else { - // If we filter a buffer out, then we must make sure to close it since we incremented the reference count - // with Deref.get() earlier. - buf.close(); - return false; - } - } - - private static Stream flattenBuffer(Buffer buf) { - if (buf instanceof CompositeBuffer) { - // Extract components and move our reference count from the composite onto the components. - var composite = (CompositeBuffer) buf; - var bufs = composite.bufs; - return Stream.of(bufs); - } - return Stream.of(buf); - } - - private CompositeBuffer(BufferAllocator allocator, Buffer[] bufs, Drop drop) { - super(drop); - this.allocator = allocator; - try { - if (bufs.length > 0) { - ByteOrder targetOrder = bufs[0].order(); - for (Buffer buf : bufs) { - if (buf.order() != targetOrder) { - throw new IllegalArgumentException("Constituent buffers have inconsistent byte order."); - } - } - order = bufs[0].order(); - - boolean targetReadOnly = bufs[0].readOnly(); - for (Buffer buf : bufs) { - if (buf.readOnly() != targetReadOnly) { - throw new IllegalArgumentException("Constituent buffers have inconsistent read-only state."); - } - } - readOnly = targetReadOnly; - } else { - order = ByteOrder.nativeOrder(); - } - this.bufs = bufs; - computeBufferOffsets(); - tornBufAccessors = new TornBufferAccessors(this); - } catch (Exception e) { - // Always close bufs on exception, regardless of acquireBufs value. - // If acquireBufs is false, it just means the ref count increments happened prior to this constructor call. - for (Buffer buf : bufs) { - buf.close(); - } - throw e; - } - } - - private void computeBufferOffsets() { - if (bufs.length > 0) { - int woff = 0; - int roff = 0; - boolean woffMidpoint = false; - for (Buffer buf : bufs) { - if (buf.writableBytes() == 0) { - woff += buf.capacity(); - } else if (!woffMidpoint) { - woff += buf.writerOffset(); - woffMidpoint = true; - } else if (buf.writerOffset() != 0) { - throw new IllegalArgumentException( - "The given buffers cannot be composed because they leave an unwritten gap: " + - Arrays.toString(bufs) + '.'); - } - } - boolean roffMidpoint = false; - for (Buffer buf : bufs) { - if (buf.readableBytes() == 0 && buf.writableBytes() == 0) { - roff += buf.capacity(); - } else if (!roffMidpoint) { - roff += buf.readerOffset(); - roffMidpoint = true; - } else if (buf.readerOffset() != 0) { - throw new IllegalArgumentException( - "The given buffers cannot be composed because they leave an unread gap: " + - Arrays.toString(bufs) + '.'); - } - } - assert roff <= woff: - "The given buffers place the read offset ahead of the write offset: " + Arrays.toString(bufs) + '.'; - // Commit computed offsets. - this.woff = woff; - this.roff = roff; - } - - offsets = new int[bufs.length]; - long cap = 0; - for (int i = 0; i < bufs.length; i++) { - offsets[i] = (int) cap; - cap += bufs[i].capacity(); - } - if (cap > MAX_CAPACITY) { - throw new IllegalArgumentException( - "Combined size of the constituent buffers is too big. " + - "The maximum buffer capacity is " + MAX_CAPACITY + " (Integer.MAX_VALUE - 8), " + - "but the sum of the constituent buffer capacities was " + cap + '.'); - } - capacity = (int) cap; - } - - @Override - public String toString() { - return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + capacity + ']'; - } - - @Override - protected RuntimeException createResourceClosedException() { - return bufferIsClosed(this); - } - - @Override - public CompositeBuffer order(ByteOrder order) { - if (this.order != order) { - this.order = order; - for (Buffer buf : bufs) { - buf.order(order); - } - } - return this; - } - - @Override - public ByteOrder order() { - return order; - } - - @Override - public int capacity() { - return capacity; - } - - @Override - public int readerOffset() { - return roff; - } - - @Override - public CompositeBuffer readerOffset(int index) { - prepRead(index, 0); - int indexLeft = index; - for (Buffer buf : bufs) { - buf.readerOffset(Math.min(indexLeft, buf.capacity())); - indexLeft = Math.max(0, indexLeft - buf.capacity()); - } - roff = index; - return this; - } - - @Override - public int writerOffset() { - return woff; - } - - @Override - public CompositeBuffer writerOffset(int index) { - checkWriteBounds(index, 0); - int indexLeft = index; - for (Buffer buf : bufs) { - buf.writerOffset(Math.min(indexLeft, buf.capacity())); - indexLeft = Math.max(0, indexLeft - buf.capacity()); - } - woff = index; - return this; - } - - @Override - public CompositeBuffer fill(byte value) { - for (Buffer buf : bufs) { - buf.fill(value); - } - return this; - } - - @Override - public long nativeAddress() { - return 0; - } - - @Override - public CompositeBuffer makeReadOnly() { - for (Buffer buf : bufs) { - buf.makeReadOnly(); - } - readOnly = true; - return this; - } - - @Override - public boolean readOnly() { - return readOnly; - } - - @Override - public CompositeBuffer copy(int offset, int length) { - checkWriteBounds(offset, length); - if (offset < 0 || length < 0) { - throw new IllegalArgumentException( - "Offset and length cannot be negative, but offset was " + - offset + ", and length was " + length + '.'); - } - Buffer choice = (Buffer) chooseBuffer(offset, 0); - Buffer[] copies; - - if (length > 0) { - copies = new Buffer[bufs.length]; - int off = subOffset; - int cap = length; - int i; - for (i = searchOffsets(offset); cap > 0; i++) { - var buf = bufs[i]; - int avail = buf.capacity() - off; - copies[i] = buf.copy(off, Math.min(cap, avail)); - cap -= avail; - off = 0; - } - copies = Arrays.copyOf(copies, i); - } else { - // Specialize for length == 0, since we must copy from at least one constituent buffer. - copies = new Buffer[] { choice.copy(subOffset, 0) }; - } - - return new CompositeBuffer(allocator, copies, COMPOSITE_DROP); - } - - @Override - public void copyInto(int srcPos, byte[] dest, int destPos, int length) { - copyInto(srcPos, (b, s, d, l) -> b.copyInto(s, dest, d, l), destPos, length); - } - - @Override - public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) { - copyInto(srcPos, (b, s, d, l) -> b.copyInto(s, dest, d, l), destPos, length); - } - - private void copyInto(int srcPos, CopyInto dest, int destPos, int length) { - if (length < 0) { - throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.'); - } - if (srcPos < 0) { - throw indexOutOfBounds(srcPos, false); - } - if (srcPos + length > capacity) { - throw indexOutOfBounds(srcPos + length, false); - } - while (length > 0) { - var buf = (Buffer) chooseBuffer(srcPos, 0); - int toCopy = Math.min(buf.capacity() - subOffset, length); - dest.copyInto(buf, subOffset, destPos, toCopy); - srcPos += toCopy; - destPos += toCopy; - length -= toCopy; - } - } - - @FunctionalInterface - private interface CopyInto { - void copyInto(Buffer src, int srcPos, int destPos, int length); - } - - @Override - public void copyInto(int srcPos, Buffer dest, int destPos, int length) { - if (length < 0) { - throw new IndexOutOfBoundsException("Length cannot be negative: " + length + '.'); - } - if (srcPos < 0) { - throw indexOutOfBounds(srcPos, false); - } - if (srcPos + length > capacity) { - throw indexOutOfBounds(srcPos + length, false); - } - - // Iterate in reverse to account for src and dest buffer overlap. - // todo optimise by delegating to constituent buffers. - var cursor = openReverseCursor(srcPos + length - 1, length); - ByteOrder prevOrder = dest.order(); - // We read longs in BE, in reverse, so they need to be flipped for writing. - dest.order(ByteOrder.LITTLE_ENDIAN); - try { - while (cursor.readLong()) { - length -= Long.BYTES; - dest.setLong(destPos + length, cursor.getLong()); - } - while (cursor.readByte()) { - dest.setByte(destPos + --length, cursor.getByte()); - } - } finally { - dest.order(prevOrder); - } - } - - @Override - public ByteCursor openCursor() { - return openCursor(readerOffset(), readableBytes()); - } - - @Override - public ByteCursor openCursor(int fromOffset, int length) { - if (fromOffset < 0) { - throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.'); - } - if (length < 0) { - throw new IllegalArgumentException("The length cannot be negative: " + length + '.'); - } - if (capacity < fromOffset + length) { - throw new IllegalArgumentException("The fromOffset+length is beyond the end of the buffer: " + - "fromOffset=" + fromOffset + ", length=" + length + '.'); - } - int startBufferIndex = searchOffsets(fromOffset); - int off = fromOffset - offsets[startBufferIndex]; - Buffer startBuf = bufs[startBufferIndex]; - ByteCursor startCursor = startBuf.openCursor(off, Math.min(startBuf.capacity() - off, length)); - return new ByteCursor() { - int index = fromOffset; - final int end = fromOffset + length; - int bufferIndex = startBufferIndex; - int initOffset = startCursor.currentOffset(); - ByteCursor cursor = startCursor; - long longValue = -1; - byte byteValue = -1; - - @Override - public boolean readLong() { - if (cursor.readLong()) { - longValue = cursor.getLong(); - return true; - } - if (bytesLeft() >= Long.BYTES) { - longValue = nextLongFromBytes(); - return true; - } - return false; - } - - private long nextLongFromBytes() { - if (cursor.bytesLeft() == 0) { - nextCursor(); - if (cursor.readLong()) { - return cursor.getLong(); - } - } - long val = 0; - for (int i = 0; i < 8; i++) { - readByte(); - val <<= 8; - val |= getByte(); - } - return val; - } - - @Override - public long getLong() { - return longValue; - } - - @Override - public boolean readByte() { - if (cursor.readByte()) { - byteValue = cursor.getByte(); - return true; - } - if (bytesLeft() > 0) { - nextCursor(); - cursor.readByte(); - byteValue = cursor.getByte(); - return true; - } - return false; - } - - private void nextCursor() { - bufferIndex++; - Buffer nextBuf = bufs[bufferIndex]; - cursor = nextBuf.openCursor(0, Math.min(nextBuf.capacity(), bytesLeft())); - initOffset = 0; - } - - @Override - public byte getByte() { - return byteValue; - } - - @Override - public int currentOffset() { - int currOff = cursor.currentOffset(); - index += currOff - initOffset; - initOffset = currOff; - return index; - } - - @Override - public int bytesLeft() { - return end - currentOffset(); - } - }; - } - - @Override - public ByteCursor openReverseCursor(int fromOffset, int length) { - if (fromOffset < 0) { - throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.'); - } - if (length < 0) { - throw new IllegalArgumentException("The length cannot be negative: " + length + '.'); - } - if (fromOffset - length < -1) { - throw new IllegalArgumentException("The fromOffset-length would underflow the buffer: " + - "fromOffset=" + fromOffset + ", length=" + length + '.'); - } - int startBufferIndex = searchOffsets(fromOffset); - int off = fromOffset - offsets[startBufferIndex]; - Buffer startBuf = bufs[startBufferIndex]; - ByteCursor startCursor = startBuf.openReverseCursor(off, Math.min(off + 1, length)); - return new ByteCursor() { - int index = fromOffset; - final int end = fromOffset - length; - int bufferIndex = startBufferIndex; - int initOffset = startCursor.currentOffset(); - ByteCursor cursor = startCursor; - long longValue = -1; - byte byteValue = -1; - - @Override - public boolean readLong() { - if (cursor.readLong()) { - longValue = cursor.getLong(); - return true; - } - if (bytesLeft() >= Long.BYTES) { - longValue = nextLongFromBytes(); - return true; - } - return false; - } - - private long nextLongFromBytes() { - if (cursor.bytesLeft() == 0) { - nextCursor(); - if (cursor.readLong()) { - return cursor.getLong(); - } - } - long val = 0; - for (int i = 0; i < 8; i++) { - readByte(); - val <<= 8; - val |= getByte(); - } - return val; - } - - @Override - public long getLong() { - return longValue; - } - - @Override - public boolean readByte() { - if (cursor.readByte()) { - byteValue = cursor.getByte(); - return true; - } - if (bytesLeft() > 0) { - nextCursor(); - cursor.readByte(); - byteValue = cursor.getByte(); - return true; - } - return false; - } - - private void nextCursor() { - bufferIndex--; - Buffer nextBuf = bufs[bufferIndex]; - int length = Math.min(nextBuf.capacity(), bytesLeft()); - int offset = nextBuf.capacity() - 1; - cursor = nextBuf.openReverseCursor(offset, length); - initOffset = offset; - } - - @Override - public byte getByte() { - return byteValue; - } - - @Override - public int currentOffset() { - int currOff = cursor.currentOffset(); - index -= initOffset - currOff; - initOffset = currOff; - return index; - } - - @Override - public int bytesLeft() { - return currentOffset() - end; - } - }; - } - - @Override - public void ensureWritable(int size, int minimumGrowth, boolean allowCompaction) { - if (!isAccessible()) { - throw bufferIsClosed(this); - } - if (!isOwned()) { - throw new IllegalStateException("Buffer is not owned. Only owned buffers can call ensureWritable."); - } - if (size < 0) { - throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.'); - } - if (minimumGrowth < 0) { - throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.'); - } - if (readOnly) { - throw bufferIsReadOnly(this); - } - if (writableBytes() >= size) { - // We already have enough space. - return; - } - - if (allowCompaction && size <= roff) { - // Let's see if we can solve some or all of the requested size with compaction. - // We always compact as much as is possible, regardless of size. This amortizes our work. - int compactableBuffers = 0; - for (Buffer buf : bufs) { - if (buf.capacity() != buf.readerOffset()) { - break; - } - compactableBuffers++; - } - if (compactableBuffers > 0) { - Buffer[] compactable; - if (compactableBuffers < bufs.length) { - compactable = new Buffer[compactableBuffers]; - System.arraycopy(bufs, 0, compactable, 0, compactable.length); - System.arraycopy(bufs, compactable.length, bufs, 0, bufs.length - compactable.length); - System.arraycopy(compactable, 0, bufs, bufs.length - compactable.length, compactable.length); - } else { - compactable = bufs; - } - for (Buffer buf : compactable) { - buf.reset(); - } - computeBufferOffsets(); - if (writableBytes() >= size) { - // Now we have enough space. - return; - } - } else if (bufs.length == 1) { - // If we only have a single component buffer, then we can safely compact that in-place. - bufs[0].compact(); - computeBufferOffsets(); - if (writableBytes() >= size) { - // Now we have enough space. - return; - } - } - } - - int growth = Math.max(size - writableBytes(), minimumGrowth); - BufferAllocator.checkSize(capacity() + (long) growth); - Buffer extension = allocator.allocate(growth, order()); - unsafeExtendWith(extension); - } - - /** - * Extend this composite buffer with the given extension buffer. - * This works as if the extension had originally been included at the end of the list of constituent buffers when - * the composite buffer was created. - * The extension buffer is added to the end of this composite buffer, which is modified in-place. - * - * @see #compose(BufferAllocator, Send...) - * @param extension The buffer to extend the composite buffer with. - */ - public void extendWith(Send extension) { - Objects.requireNonNull(extension, "Extension buffer cannot be null."); - Buffer buffer = extension.receive(); - if (!isAccessible() || !isOwned()) { - buffer.close(); - if (!isAccessible()) { - throw bufferIsClosed(this); - } - throw new IllegalStateException("This buffer cannot be extended because it is not in an owned state."); - } - if (bufs.length > 0 && buffer.order() != order()) { - buffer.close(); - throw new IllegalArgumentException( - "This buffer uses " + order() + " byte order, and cannot be extended with " + - "a buffer that uses " + buffer.order() + " byte order."); - } - if (bufs.length > 0 && buffer.readOnly() != readOnly()) { - buffer.close(); - throw new IllegalArgumentException( - "This buffer is " + (readOnly? "read-only" : "writable") + ", " + - "and cannot be extended with a buffer that is " + - (buffer.readOnly()? "read-only." : "writable.")); - } - - long extensionCapacity = buffer.capacity(); - if (extensionCapacity == 0) { - // Extending by a zero-sized buffer makes no difference. Especially since it's not allowed to change the - // capacity of buffers that are constiuents of composite buffers. - // This also ensures that methods like countComponents, and forEachReadable, do not have to worry about - // overflow in their component counters. - buffer.close(); - return; - } - - long newSize = capacity() + extensionCapacity; - BufferAllocator.checkSize(newSize); - - Buffer[] restoreTemp = bufs; // We need this to restore our buffer array, in case offset computations fail. - try { - if (buffer instanceof CompositeBuffer) { - // If the extension is itself a composite buffer, then extend this one by all the constituent - // component buffers. - CompositeBuffer compositeExtension = (CompositeBuffer) buffer; - Buffer[] addedBuffers = compositeExtension.bufs; - Set duplicatesCheck = Collections.newSetFromMap(new IdentityHashMap<>()); - duplicatesCheck.addAll(Arrays.asList(bufs)); - duplicatesCheck.addAll(Arrays.asList(addedBuffers)); - if (duplicatesCheck.size() < bufs.length + addedBuffers.length) { - throw extensionDuplicatesException(); - } - int extendAtIndex = bufs.length; - bufs = Arrays.copyOf(bufs, extendAtIndex + addedBuffers.length); - System.arraycopy(addedBuffers, 0, bufs, extendAtIndex, addedBuffers.length); - computeBufferOffsets(); - } else { - for (Buffer buf : restoreTemp) { - if (buf == buffer) { - throw extensionDuplicatesException(); - } - } - unsafeExtendWith(buffer); - } - if (restoreTemp.length == 0) { - order = buffer.order(); - readOnly = buffer.readOnly(); - } - } catch (Exception e) { - bufs = restoreTemp; - throw e; - } - } - - private static IllegalArgumentException extensionDuplicatesException() { - return new IllegalArgumentException( - "The composite buffer cannot be extended with the given extension," + - " as it would cause the buffer to have duplicate constituent buffers."); - } - - private void unsafeExtendWith(Buffer extension) { - bufs = Arrays.copyOf(bufs, bufs.length + 1); - bufs[bufs.length - 1] = extension; - computeBufferOffsets(); - } - - private void checkSplit(int splitOffset) { - if (splitOffset < 0) { - throw new IllegalArgumentException("The split offset cannot be negative: " + splitOffset + '.'); - } - if (capacity() < splitOffset) { - throw new IllegalArgumentException("The split offset cannot be greater than the buffer capacity, " + - "but the split offset was " + splitOffset + ", and capacity is " + capacity() + '.'); - } - if (!isAccessible()) { - throw attachTrace(bufferIsClosed(this)); - } - if (!isOwned()) { - throw new IllegalStateException("Cannot split a buffer that is not owned."); - } - } - - @Override - public CompositeBuffer split(int splitOffset) { - checkSplit(splitOffset); - if (bufs.length == 0) { - // Splitting a zero-length buffer is trivial. - return new CompositeBuffer(allocator, bufs, unsafeGetDrop()).order(order); - } - - int i = searchOffsets(splitOffset); - int off = splitOffset - offsets[i]; - Buffer[] splits = Arrays.copyOf(bufs, off == 0? i : 1 + i); - bufs = Arrays.copyOfRange(bufs, off == bufs[i].capacity()? 1 + i : i, bufs.length); - if (off > 0 && splits.length > 0 && off < splits[splits.length - 1].capacity()) { - splits[splits.length - 1] = bufs[0].split(off); - } - computeBufferOffsets(); - return buildSplitBuffer(splits); - } - - private CompositeBuffer buildSplitBuffer(Buffer[] splits) { - var compositeBuf = new CompositeBuffer(allocator, splits, unsafeGetDrop()); - compositeBuf.order = order; // Preserve byte order even if splits array is empty. - return compositeBuf; - } - - /** - * Split this buffer at a component boundary that is less than or equal to the given offset. - *

- * This method behaves the same as {@link #split(int)}, except no components are split. - * - * @param splitOffset The maximum split offset. The real split offset will be at a component boundary that is less - * than or equal to this offset. - * @return A new buffer with independent and exclusive ownership over the bytes from the beginning to a component - * boundary less than or equal to the given offset of this buffer. - */ - public CompositeBuffer splitComponentsFloor(int splitOffset) { - checkSplit(splitOffset); - if (bufs.length == 0) { - // Splitting a zero-length buffer is trivial. - return new CompositeBuffer(allocator, bufs, unsafeGetDrop()).order(order); - } - - int i = searchOffsets(splitOffset); - int off = splitOffset - offsets[i]; - if (off == bufs[i].capacity()) { - i++; - } - Buffer[] splits = Arrays.copyOf(bufs, i); - bufs = Arrays.copyOfRange(bufs, i, bufs.length); - computeBufferOffsets(); - return buildSplitBuffer(splits); - } - - /** - * Split this buffer at a component boundary that is greater than or equal to the given offset. - *

- * This method behaves the same as {@link #split(int)}, except no components are split. - * - * @param splitOffset The minimum split offset. The real split offset will be at a component boundary that is - * greater than or equal to this offset. - * @return A new buffer with independent and exclusive ownership over the bytes from the beginning to a component - * boundary greater than or equal to the given offset of this buffer. - */ - public CompositeBuffer splitComponentsCeil(int splitOffset) { - checkSplit(splitOffset); - if (bufs.length == 0) { - // Splitting a zero-length buffer is trivial. - return new CompositeBuffer(allocator, bufs, unsafeGetDrop()).order(order); - } - - int i = searchOffsets(splitOffset); - int off = splitOffset - offsets[i]; - if (0 < off && off <= bufs[i].capacity()) { - i++; - } - Buffer[] splits = Arrays.copyOf(bufs, i); - bufs = Arrays.copyOfRange(bufs, i, bufs.length); - computeBufferOffsets(); - return buildSplitBuffer(splits); - } - - @Override - public void compact() { - if (!isOwned()) { - throw new IllegalStateException("Buffer must be owned in order to compact."); - } - if (readOnly()) { - throw new BufferReadOnlyException("Buffer must be writable in order to compact, but was read-only."); - } - int distance = roff; - if (distance == 0) { - return; - } - int pos = 0; - var oldOrder = order; - order = ByteOrder.BIG_ENDIAN; - try { - var cursor = openCursor(); - while (cursor.readLong()) { - setLong(pos, cursor.getLong()); - pos += Long.BYTES; - } - while (cursor.readByte()) { - setByte(pos, cursor.getByte()); - pos++; - } - } finally { - order = oldOrder; - } - readerOffset(0); - writerOffset(woff - distance); - } - - @Override - public int countComponents() { - int sum = 0; - for (Buffer buf : bufs) { - sum += buf.countComponents(); - } - return sum; - } - - @Override - public int countReadableComponents() { - int sum = 0; - for (Buffer buf : bufs) { - sum += buf.countReadableComponents(); - } - return sum; - } - - @Override - public int countWritableComponents() { - int sum = 0; - for (Buffer buf : bufs) { - sum += buf.countWritableComponents(); - } - return sum; - } - - @Override - public int forEachReadable(int initialIndex, ReadableComponentProcessor processor) - throws E { - checkReadBounds(readerOffset(), Math.max(1, readableBytes())); - int visited = 0; - for (Buffer buf : bufs) { - if (buf.readableBytes() > 0) { - int count = buf.forEachReadable(visited + initialIndex, processor); - if (count > 0) { - visited += count; - } else { - visited = -visited + count; - break; - } - } - } - return visited; - } - - @Override - public int forEachWritable(int initialIndex, WritableComponentProcessor processor) - throws E { - checkWriteBounds(writerOffset(), Math.max(1, writableBytes())); - int visited = 0; - for (Buffer buf : bufs) { - if (buf.writableBytes() > 0) { - int count = buf.forEachWritable(visited + initialIndex, processor); - if (count > 0) { - visited += count; - } else { - visited = -visited + count; - break; - } - } - } - return visited; - } - - // - @Override - public byte readByte() { - return prepRead(Byte.BYTES).readByte(); - } - - @Override - public byte getByte(int roff) { - return prepGet(roff, Byte.BYTES).getByte(subOffset); - } - - @Override - public int readUnsignedByte() { - return prepRead(Byte.BYTES).readUnsignedByte(); - } - - @Override - public int getUnsignedByte(int roff) { - return prepGet(roff, Byte.BYTES).getUnsignedByte(subOffset); - } - - @Override - public CompositeBuffer writeByte(byte value) { - prepWrite(Byte.BYTES).writeByte(value); - return this; - } - - @Override - public CompositeBuffer setByte(int woff, byte value) { - prepWrite(woff, Byte.BYTES).setByte(subOffset, value); - return this; - } - - @Override - public CompositeBuffer writeUnsignedByte(int value) { - prepWrite(Byte.BYTES).writeUnsignedByte(value); - return this; - } - - @Override - public CompositeBuffer setUnsignedByte(int woff, int value) { - prepWrite(woff, Byte.BYTES).setUnsignedByte(subOffset, value); - return this; - } - - @Override - public char readChar() { - return prepRead(2).readChar(); - } - - @Override - public char getChar(int roff) { - return prepGet(roff, 2).getChar(subOffset); - } - - @Override - public CompositeBuffer writeChar(char value) { - prepWrite(2).writeChar(value); - return this; - } - - @Override - public CompositeBuffer setChar(int woff, char value) { - prepWrite(woff, 2).setChar(subOffset, value); - return this; - } - - @Override - public short readShort() { - return prepRead(Short.BYTES).readShort(); - } - - @Override - public short getShort(int roff) { - return prepGet(roff, Short.BYTES).getShort(subOffset); - } - - @Override - public int readUnsignedShort() { - return prepRead(Short.BYTES).readShort(); - } - - @Override - public int getUnsignedShort(int roff) { - return prepGet(roff, Short.BYTES).getUnsignedShort(subOffset); - } - - @Override - public CompositeBuffer writeShort(short value) { - prepWrite(Short.BYTES).writeShort(value); - return this; - } - - @Override - public CompositeBuffer setShort(int woff, short value) { - prepWrite(woff, Short.BYTES).setShort(subOffset, value); - return this; - } - - @Override - public CompositeBuffer writeUnsignedShort(int value) { - prepWrite(Short.BYTES).writeUnsignedShort(value); - return this; - } - - @Override - public CompositeBuffer setUnsignedShort(int woff, int value) { - prepWrite(woff, Short.BYTES).setUnsignedShort(subOffset, value); - return this; - } - - @Override - public int readMedium() { - return prepRead(3).readMedium(); - } - - @Override - public int getMedium(int roff) { - return prepGet(roff, 3).getMedium(subOffset); - } - - @Override - public int readUnsignedMedium() { - return prepRead(3).readMedium(); - } - - @Override - public int getUnsignedMedium(int roff) { - return prepGet(roff, 3).getMedium(subOffset); - } - - @Override - public CompositeBuffer writeMedium(int value) { - prepWrite(3).writeMedium(value); - return this; - } - - @Override - public CompositeBuffer setMedium(int woff, int value) { - prepWrite(woff, 3).setMedium(subOffset, value); - return this; - } - - @Override - public CompositeBuffer writeUnsignedMedium(int value) { - prepWrite(3).writeUnsignedMedium(value); - return this; - } - - @Override - public CompositeBuffer setUnsignedMedium(int woff, int value) { - prepWrite(woff, 3).setUnsignedMedium(subOffset, value); - return this; - } - - @Override - public int readInt() { - return prepRead(Integer.BYTES).readInt(); - } - - @Override - public int getInt(int roff) { - return prepGet(roff, Integer.BYTES).getInt(subOffset); - } - - @Override - public long readUnsignedInt() { - return prepRead(Integer.BYTES).readUnsignedInt(); - } - - @Override - public long getUnsignedInt(int roff) { - return prepGet(roff, Integer.BYTES).getUnsignedInt(subOffset); - } - - @Override - public CompositeBuffer writeInt(int value) { - prepWrite(Integer.BYTES).writeInt(value); - return this; - } - - @Override - public CompositeBuffer setInt(int woff, int value) { - prepWrite(woff, Integer.BYTES).setInt(subOffset, value); - return this; - } - - @Override - public CompositeBuffer writeUnsignedInt(long value) { - prepWrite(Integer.BYTES).writeUnsignedInt(value); - return this; - } - - @Override - public CompositeBuffer setUnsignedInt(int woff, long value) { - prepWrite(woff, Integer.BYTES).setUnsignedInt(subOffset, value); - return this; - } - - @Override - public float readFloat() { - return prepRead(Float.BYTES).readFloat(); - } - - @Override - public float getFloat(int roff) { - return prepGet(roff, Float.BYTES).getFloat(subOffset); - } - - @Override - public CompositeBuffer writeFloat(float value) { - prepWrite(Float.BYTES).writeFloat(value); - return this; - } - - @Override - public CompositeBuffer setFloat(int woff, float value) { - prepWrite(woff, Float.BYTES).setFloat(subOffset, value); - return this; - } - - @Override - public long readLong() { - return prepRead(Long.BYTES).readLong(); - } - - @Override - public long getLong(int roff) { - return prepGet(roff, Long.BYTES).getLong(subOffset); - } - - @Override - public CompositeBuffer writeLong(long value) { - prepWrite(Long.BYTES).writeLong(value); - return this; - } - - @Override - public CompositeBuffer setLong(int woff, long value) { - prepWrite(woff, Long.BYTES).setLong(subOffset, value); - return this; - } - - @Override - public double readDouble() { - return prepRead(Double.BYTES).readDouble(); - } - - @Override - public double getDouble(int roff) { - return prepGet(roff, Double.BYTES).getDouble(subOffset); - } - - @Override - public CompositeBuffer writeDouble(double value) { - prepWrite(Double.BYTES).writeDouble(value); - return this; - } - - @Override - public CompositeBuffer setDouble(int woff, double value) { - prepWrite(woff, Double.BYTES).setDouble(subOffset, value); - return this; - } - // - - @Override - protected Owned prepareSend() { - @SuppressWarnings("unchecked") - Send[] sends = new Send[bufs.length]; - try { - for (int i = 0; i < bufs.length; i++) { - sends[i] = bufs[i].send(); - } - } catch (Throwable throwable) { - // Repair our bufs array. - for (int i = 0; i < sends.length; i++) { - if (sends[i] != null) { - try { - bufs[i] = sends[i].receive(); - } catch (Exception e) { - throwable.addSuppressed(e); - } - } - } - throw throwable; - } - boolean readOnly = this.readOnly; - makeInaccessible(); - return new Owned() { - @Override - public CompositeBuffer transferOwnership(Drop drop) { - Buffer[] received = new Buffer[sends.length]; - for (int i = 0; i < sends.length; i++) { - received[i] = sends[i].receive(); - } - var composite = new CompositeBuffer(allocator, received, drop); - composite.readOnly = readOnly; - drop.attach(composite); - return composite; - } - }; - } - - void makeInaccessible() { - capacity = 0; - roff = 0; - woff = 0; - readOnly = false; - closed = true; - } - - @Override - protected boolean isOwned() { - return super.isOwned() && allConstituentsAreOwned(); - } - - private boolean allConstituentsAreOwned() { - boolean result = true; - for (Buffer buf : bufs) { - result &= Statics.isOwned((ResourceSupport) buf); - } - return result; - } - - long readPassThrough() { - var buf = choosePassThroughBuffer(subOffset++); - assert buf != tornBufAccessors: "Recursive call to torn buffer."; - return buf.readUnsignedByte(); - } - - void writePassThrough(int value) { - var buf = choosePassThroughBuffer(subOffset++); - assert buf != tornBufAccessors: "Recursive call to torn buffer."; - buf.writeUnsignedByte(value); - } - - long getPassThrough(int roff) { - var buf = chooseBuffer(roff, 1); - assert buf != tornBufAccessors: "Recursive call to torn buffer."; - return buf.getUnsignedByte(subOffset); - } - - void setPassThrough(int woff, int value) { - var buf = chooseBuffer(woff, 1); - assert buf != tornBufAccessors: "Recursive call to torn buffer."; - buf.setUnsignedByte(subOffset, value); - } - - private BufferAccessors prepRead(int size) { - var buf = prepRead(roff, size); - roff += size; - return buf; - } - - private BufferAccessors prepRead(int index, int size) { - checkReadBounds(index, size); - return chooseBuffer(index, size); - } - - private void checkReadBounds(int index, int size) { - if (index < 0 || woff < index + size) { - throw indexOutOfBounds(index, false); - } - } - - private BufferAccessors prepGet(int index, int size) { - checkGetBounds(index, size); - return chooseBuffer(index, size); - } - - private void checkGetBounds(int index, int size) { - if (index < 0 || capacity < index + size) { - throw indexOutOfBounds(index, false); - } - } - - private BufferAccessors prepWrite(int size) { - var buf = prepWrite(woff, size); - woff += size; - return buf; - } - - private BufferAccessors prepWrite(int index, int size) { - checkWriteBounds(index, size); - return chooseBuffer(index, size); - } - - private void checkWriteBounds(int index, int size) { - if (index < 0 || capacity < index + size) { - throw indexOutOfBounds(index, true); - } - } - - private RuntimeException indexOutOfBounds(int index, boolean write) { - if (closed) { - return bufferIsClosed(this); - } - if (write && readOnly) { - return bufferIsReadOnly(this); - } - return new IndexOutOfBoundsException( - "Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " + - capacity + "]."); - } - - private BufferAccessors chooseBuffer(int index, int size) { - int i = searchOffsets(index); - if (i == bufs.length) { - // This happens when the read/write offsets are parked 1 byte beyond the end of the buffer. - // In that case it should not matter what buffer is returned, because it shouldn't be used anyway. - return null; - } - int off = index - offsets[i]; - Buffer candidate = bufs[i]; - if (off + size <= candidate.capacity()) { - subOffset = off; - return candidate; - } - subOffset = index; - return tornBufAccessors; - } - - private BufferAccessors choosePassThroughBuffer(int index) { - int i = searchOffsets(index); - return bufs[i]; - } - - private int searchOffsets(int index) { - int i = Arrays.binarySearch(offsets, index); - return i < 0? -(i + 2) : i; - } - - // - private static final class TornBufferAccessors implements BufferAccessors { - private final CompositeBuffer buf; - - private TornBufferAccessors(CompositeBuffer buf) { - this.buf = buf; - } - - @Override - public byte readByte() { - throw new AssertionError("Method should not be used."); - } - - @Override - public byte getByte(int roff) { - throw new AssertionError("Method should not be used."); - } - - @Override - public int readUnsignedByte() { - throw new AssertionError("Method should not be used."); - } - - @Override - public int getUnsignedByte(int roff) { - throw new AssertionError("Method should not be used."); - } - - @Override - public Buffer writeByte(byte value) { - throw new AssertionError("Method should not be used."); - } - - @Override - public Buffer setByte(int woff, byte value) { - throw new AssertionError("Method should not be used."); - } - - @Override - public Buffer writeUnsignedByte(int value) { - throw new AssertionError("Method should not be used."); - } - - @Override - public Buffer setUnsignedByte(int woff, int value) { - throw new AssertionError("Method should not be used."); - } - - @Override - public char readChar() { - if (bigEndian()) { - return (char) (read() << 8 | read()); - } else { - return (char) (read() | read() << 8); - } - } - - @Override - public char getChar(int roff) { - if (bigEndian()) { - return (char) (read(roff) << 8 | read(roff + 1)); - } else { - return (char) (read(roff) | read(roff + 1) << 8); - } - } - - @Override - public Buffer writeChar(char value) { - if (bigEndian()) { - write(value >>> 8); - write(value & 0xFF); - } else { - write(value & 0xFF); - write(value >>> 8); - } - return buf; - } - - @Override - public Buffer setChar(int woff, char value) { - if (bigEndian()) { - write(woff, value >>> 8); - write(woff + 1, value & 0xFF); - } else { - write(woff, value & 0xFF); - write(woff + 1, value >>> 8); - } - return buf; - } - - @Override - public short readShort() { - if (bigEndian()) { - return (short) (read() << 8 | read()); - } else { - return (short) (read() | read() << 8); - } - } - - @Override - public short getShort(int roff) { - if (bigEndian()) { - return (short) (read(roff) << 8 | read(roff + 1)); - } else { - return (short) (read(roff) | read(roff + 1) << 8); - } - } - - @Override - public int readUnsignedShort() { - if (bigEndian()) { - return (int) (read() << 8 | read()) & 0xFFFF; - } else { - return (int) (read() | read() << 8) & 0xFFFF; - } - } - - @Override - public int getUnsignedShort(int roff) { - if (bigEndian()) { - return (int) (read(roff) << 8 | read(roff + 1)) & 0xFFFF; - } else { - return (int) (read(roff) | read(roff + 1) << 8) & 0xFFFF; - } - } - - @Override - public Buffer writeShort(short value) { - if (bigEndian()) { - write(value >>> 8); - write(value & 0xFF); - } else { - write(value & 0xFF); - write(value >>> 8); - } - return buf; - } - - @Override - public Buffer setShort(int woff, short value) { - if (bigEndian()) { - write(woff, value >>> 8); - write(woff + 1, value & 0xFF); - } else { - write(woff, value & 0xFF); - write(woff + 1, value >>> 8); - } - return buf; - } - - @Override - public Buffer writeUnsignedShort(int value) { - if (bigEndian()) { - write(value >>> 8); - write(value & 0xFF); - } else { - write(value & 0xFF); - write(value >>> 8); - } - return buf; - } - - @Override - public Buffer setUnsignedShort(int woff, int value) { - if (bigEndian()) { - write(woff, value >>> 8); - write(woff + 1, value & 0xFF); - } else { - write(woff, value & 0xFF); - write(woff + 1, value >>> 8); - } - return buf; - } - - @Override - public int readMedium() { - if (bigEndian()) { - return (int) (read() << 16 | read() << 8 | read()); - } else { - return (int) (read() | read() << 8 | read() << 16); - } - } - - @Override - public int getMedium(int roff) { - if (bigEndian()) { - return (int) (read(roff) << 16 | read(roff + 1) << 8 | read(roff + 2)); - } else { - return (int) (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16); - } - } - - @Override - public int readUnsignedMedium() { - if (bigEndian()) { - return (int) (read() << 16 | read() << 8 | read()) & 0xFFFFFF; - } else { - return (int) (read() | read() << 8 | read() << 16) & 0xFFFFFF; - } - } - - @Override - public int getUnsignedMedium(int roff) { - if (bigEndian()) { - return (int) (read(roff) << 16 | read(roff + 1) << 8 | read(roff + 2)) & 0xFFFFFF; - } else { - return (int) (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16) & 0xFFFFFF; - } - } - - @Override - public Buffer writeMedium(int value) { - if (bigEndian()) { - write(value >>> 16); - write(value >>> 8 & 0xFF); - write(value & 0xFF); - } else { - write(value & 0xFF); - write(value >>> 8 & 0xFF); - write(value >>> 16); - } - return buf; - } - - @Override - public Buffer setMedium(int woff, int value) { - if (bigEndian()) { - write(woff, value >>> 16); - write(woff + 1, value >>> 8 & 0xFF); - write(woff + 2, value & 0xFF); - } else { - write(woff, value & 0xFF); - write(woff + 1, value >>> 8 & 0xFF); - write(woff + 2, value >>> 16); - } - return buf; - } - - @Override - public Buffer writeUnsignedMedium(int value) { - if (bigEndian()) { - write(value >>> 16); - write(value >>> 8 & 0xFF); - write(value & 0xFF); - } else { - write(value & 0xFF); - write(value >>> 8 & 0xFF); - write(value >>> 16); - } - return buf; - } - - @Override - public Buffer setUnsignedMedium(int woff, int value) { - if (bigEndian()) { - write(woff, value >>> 16); - write(woff + 1, value >>> 8 & 0xFF); - write(woff + 2, value & 0xFF); - } else { - write(woff, value & 0xFF); - write(woff + 1, value >>> 8 & 0xFF); - write(woff + 2, value >>> 16); - } - return buf; - } - - @Override - public int readInt() { - if (bigEndian()) { - return (int) (read() << 24 | read() << 16 | read() << 8 | read()); - } else { - return (int) (read() | read() << 8 | read() << 16 | read() << 24); - } - } - - @Override - public int getInt(int roff) { - if (bigEndian()) { - return (int) (read(roff) << 24 | read(roff + 1) << 16 | read(roff + 2) << 8 | read(roff + 3)); - } else { - return (int) (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16 | read(roff + 3) << 24); - } - } - - @Override - public long readUnsignedInt() { - if (bigEndian()) { - return (read() << 24 | read() << 16 | read() << 8 | read()) & 0xFFFFFFFFL; - } else { - return (read() | read() << 8 | read() << 16 | read() << 24) & 0xFFFFFFFFL; - } - } - - @Override - public long getUnsignedInt(int roff) { - if (bigEndian()) { - return (read(roff) << 24 | read(roff + 1) << 16 | read(roff + 2) << 8 | read(roff + 3)) & 0xFFFFFFFFL; - } else { - return (read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16 | read(roff + 3) << 24) & 0xFFFFFFFFL; - } - } - - @Override - public Buffer writeInt(int value) { - if (bigEndian()) { - write(value >>> 24); - write(value >>> 16 & 0xFF); - write(value >>> 8 & 0xFF); - write(value & 0xFF); - } else { - write(value & 0xFF); - write(value >>> 8 & 0xFF); - write(value >>> 16 & 0xFF); - write(value >>> 24); - } - return buf; - } - - @Override - public Buffer setInt(int woff, int value) { - if (bigEndian()) { - write(woff, value >>> 24); - write(woff + 1, value >>> 16 & 0xFF); - write(woff + 2, value >>> 8 & 0xFF); - write(woff + 3, value & 0xFF); - } else { - write(woff, value & 0xFF); - write(woff + 1, value >>> 8 & 0xFF); - write(woff + 2, value >>> 16 & 0xFF); - write(woff + 3, value >>> 24); - } - return buf; - } - - @Override - public Buffer writeUnsignedInt(long value) { - if (bigEndian()) { - write((int) (value >>> 24)); - write((int) (value >>> 16 & 0xFF)); - write((int) (value >>> 8 & 0xFF)); - write((int) (value & 0xFF)); - } else { - write((int) (value & 0xFF)); - write((int) (value >>> 8 & 0xFF)); - write((int) (value >>> 16 & 0xFF)); - write((int) (value >>> 24)); - } - return buf; - } - - @Override - public Buffer setUnsignedInt(int woff, long value) { - if (bigEndian()) { - write(woff, (int) (value >>> 24)); - write(woff + 1, (int) (value >>> 16 & 0xFF)); - write(woff + 2, (int) (value >>> 8 & 0xFF)); - write(woff + 3, (int) (value & 0xFF)); - } else { - write(woff, (int) (value & 0xFF)); - write(woff + 1, (int) (value >>> 8 & 0xFF)); - write(woff + 2, (int) (value >>> 16 & 0xFF)); - write(woff + 3, (int) (value >>> 24)); - } - return buf; - } - - @Override - public float readFloat() { - return Float.intBitsToFloat(readInt()); - } - - @Override - public float getFloat(int roff) { - return Float.intBitsToFloat(getInt(roff)); - } - - @Override - public Buffer writeFloat(float value) { - return writeUnsignedInt(Float.floatToRawIntBits(value)); - } - - @Override - public Buffer setFloat(int woff, float value) { - return setUnsignedInt(woff, Float.floatToRawIntBits(value)); - } - - @Override - public long readLong() { - if (bigEndian()) { - return read() << 56 | read() << 48 | read() << 40 | read() << 32 | - read() << 24 | read() << 16 | read() << 8 | read(); - } else { - return read() | read() << 8 | read() << 16 | read() << 24 | - read() << 32 | read() << 40 | read() << 48 | read() << 56; - } - } - - @Override - public long getLong(int roff) { - if (bigEndian()) { - return read(roff) << 56 | read(roff + 1) << 48 | read(roff + 2) << 40 | read(roff + 3) << 32 | - read(roff + 4) << 24 | read(roff + 5) << 16 | read(roff + 6) << 8 | read(roff + 7); - } else { - return read(roff) | read(roff + 1) << 8 | read(roff + 2) << 16 | read(roff + 3) << 24 | - read(roff + 4) << 32 | read(roff + 5) << 40 | read(roff + 6) << 48 | read(roff + 7) << 56; - } - } - - @Override - public Buffer writeLong(long value) { - if (bigEndian()) { - write((int) (value >>> 56)); - write((int) (value >>> 48 & 0xFF)); - write((int) (value >>> 40 & 0xFF)); - write((int) (value >>> 32 & 0xFF)); - write((int) (value >>> 24 & 0xFF)); - write((int) (value >>> 16 & 0xFF)); - write((int) (value >>> 8 & 0xFF)); - write((int) (value & 0xFF)); - } else { - write((int) (value & 0xFF)); - write((int) (value >>> 8 & 0xFF)); - write((int) (value >>> 16 & 0xFF)); - write((int) (value >>> 24)); - write((int) (value >>> 32)); - write((int) (value >>> 40)); - write((int) (value >>> 48)); - write((int) (value >>> 56)); - } - return buf; - } - - @Override - public Buffer setLong(int woff, long value) { - if (bigEndian()) { - write(woff, (int) (value >>> 56)); - write(woff + 1, (int) (value >>> 48 & 0xFF)); - write(woff + 2, (int) (value >>> 40 & 0xFF)); - write(woff + 3, (int) (value >>> 32 & 0xFF)); - write(woff + 4, (int) (value >>> 24 & 0xFF)); - write(woff + 5, (int) (value >>> 16 & 0xFF)); - write(woff + 6, (int) (value >>> 8 & 0xFF)); - write(woff + 7, (int) (value & 0xFF)); - } else { - write(woff, (int) (value & 0xFF)); - write(woff + 1, (int) (value >>> 8 & 0xFF)); - write(woff + 2, (int) (value >>> 16 & 0xFF)); - write(woff + 3, (int) (value >>> 24)); - write(woff + 4, (int) (value >>> 32)); - write(woff + 5, (int) (value >>> 40)); - write(woff + 6, (int) (value >>> 48)); - write(woff + 7, (int) (value >>> 56)); - } - return buf; - } - - @Override - public double readDouble() { - return Double.longBitsToDouble(readLong()); - } - - @Override - public double getDouble(int roff) { - return Double.longBitsToDouble(getLong(roff)); - } - - @Override - public Buffer writeDouble(double value) { - return writeLong(Double.doubleToRawLongBits(value)); - } - - @Override - public Buffer setDouble(int woff, double value) { - return setLong(woff, Double.doubleToRawLongBits(value)); - } - - private boolean bigEndian() { - return buf.order() == ByteOrder.BIG_ENDIAN; - } - - private long read() { - return buf.readPassThrough(); - } - - private void write(int value) { - buf.writePassThrough(value); - } - - private long read(int roff) { - return buf.getPassThrough(roff); - } - - private void write(int woff, int value) { - buf.setPassThrough(woff, value); - } - } - // -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Drop.java b/buffer-api/src/main/java/io/netty/buffer/api/Drop.java deleted file mode 100644 index 1461620..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/Drop.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -/** - * The Drop interface is used by {@link Resource} instances to implement their resource disposal mechanics. - * The {@link #drop(Object)} method will be called by the resource when they are closed. - * - * @param - */ -@FunctionalInterface -public interface Drop { - /** - * Dispose of the resources in the given {@link Resource} instance. - * - * @param obj The {@link Resource} instance being dropped. - */ - void drop(T obj); - - /** - * Called when the resource changes owner. - * - * @param obj The new {@link Resource} instance with the new owner. - */ - default void attach(T obj) { - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ManagedBufferAllocator.java b/buffer-api/src/main/java/io/netty/buffer/api/ManagedBufferAllocator.java deleted file mode 100644 index a132772..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/ManagedBufferAllocator.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import io.netty.buffer.api.internal.Statics; - -import java.util.function.Supplier; - -import static io.netty.buffer.api.internal.Statics.NO_OP_DROP; - -class ManagedBufferAllocator implements BufferAllocator, AllocatorControl { - private final MemoryManager manager; - - ManagedBufferAllocator(MemoryManager manager) { - this.manager = manager; - } - - @Override - public Buffer allocate(int size) { - BufferAllocator.checkSize(size); - return manager.allocateShared(this, size, manager.drop(), Statics.CLEANER); - } - - @Override - public Supplier constBufferSupplier(byte[] bytes) { - Buffer constantBuffer = manager.allocateShared(this, bytes.length, manager.drop(), Statics.CLEANER); - constantBuffer.writeBytes(bytes).makeReadOnly(); - return () -> manager.allocateConstChild(constantBuffer); - } - - @SuppressWarnings("unchecked") - @Override - public UntetheredMemory allocateUntethered(Buffer originator, int size) { - BufferAllocator.checkSize(size); - var buf = manager.allocateShared(this, size, NO_OP_DROP, Statics.CLEANER); - return new UntetheredMemory() { - @Override - public Memory memory() { - return (Memory) manager.unwrapRecoverableMemory(buf); - } - - @Override - public Drop drop() { - return (Drop) manager.drop(); - } - }; - } - - @Override - public void recoverMemory(Object memory) { - // Free the recovered memory. - manager.recoverMemory(this, memory, manager.drop()).close(); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/MemoryManager.java b/buffer-api/src/main/java/io/netty/buffer/api/MemoryManager.java deleted file mode 100644 index 730b0ca..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/MemoryManager.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import java.lang.ref.Cleaner; - -public interface MemoryManager { - boolean isNative(); - Buffer allocateShared(AllocatorControl allocatorControl, long size, Drop drop, Cleaner cleaner); - Buffer allocateConstChild(Buffer readOnlyConstParent); - Drop drop(); - Object unwrapRecoverableMemory(Buffer buf); - int capacityOfRecoverableMemory(Object memory); - void discardRecoverableMemory(Object recoverableMemory); - // todo should recoverMemory re-attach a cleaner? - Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop drop); - Object sliceMemory(Object memory, int offset, int length); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/MemoryManagers.java b/buffer-api/src/main/java/io/netty/buffer/api/MemoryManagers.java deleted file mode 100644 index c9a4af4..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/MemoryManagers.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import io.netty.buffer.api.internal.MemoryManagersOverride; - -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.function.Supplier; -import java.util.stream.Stream; - -/** - * The MemoryManagers interface is the handle through which {@link BufferAllocator buffer allocators} access the low - * level memory management APIs. - *

- * This is hidden behind this interface in order to make allocation and pool agnostic and reusable across buffer and - * memory implementations. - */ -public interface MemoryManagers { - /** - * Get the default, or currently configured, memory managers instance. - * @return A MemoryManagers instance. - */ - static MemoryManagers getManagers() { - return MemoryManagersOverride.getManagers(); - } - - /** - * Temporarily override the default configured memory managers instance. - *

- * Calls to {@link #getManagers()} from within the given supplier will get the given managers instance. - * - * @param managers Override the default configured managers instance with this instance. - * @param supplier The supplier function to be called while the override is in place. - * @param The result type from the supplier. - * @return The result from the supplier. - */ - static T using(MemoryManagers managers, Supplier supplier) { - return MemoryManagersOverride.using(managers, supplier); - } - - /** - * Get a lazy-loading stream of all available memory managers. - *

- * Note: All available {@link MemoryManagers} instances are service loaded and instantiated on every call. - * - * @return A stream of providers of memory managers instances. - */ - static Stream> getAllManagers() { - var loader = ServiceLoader.load(MemoryManagers.class); - return loader.stream(); - } - - /** - * Find a {@link MemoryManagers} implementation by its {@linkplain #getImplementationName() implementation name}. - *

- * Note: All available {@link MemoryManagers} instances are service loaded and instantiated every time this - * method is called. - * - * @param implementationName The named implementation to look for. - * @return A {@link MemoryManagers} implementation, if any was found. - */ - static Optional lookupImplementation(String implementationName) { - return getAllManagers() - .flatMap(provider -> { - try { - return Stream.ofNullable(provider.get()); - } catch (Exception e) { - return Stream.empty(); - } - }) - .filter(impl -> implementationName.equals(impl.getImplementationName())) - .findFirst(); - } - - /** - * Get a {@link MemoryManager} instance that is suitable for allocating on-heap {@link Buffer} instances. - * - * @return An on-heap {@link MemoryManager}. - */ - MemoryManager getHeapMemoryManager(); - - /** - * Get a {@link MemoryManager} instance that is suitable for allocating off-heap {@link Buffer} instances. - * - * @return An off-heap {@link MemoryManager}. - */ - MemoryManager getNativeMemoryManager(); - - /** - * Get the name for this implementation, which can be used for finding this particular implementation via the - * {@link #lookupImplementation(String)} method. - * - * @return The name of this memory managers implementation. - */ - String getImplementationName(); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Owned.java b/buffer-api/src/main/java/io/netty/buffer/api/Owned.java deleted file mode 100644 index 9f22ecc..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/Owned.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -/** - * This interface encapsulates the ownership of a {@link Resource}, and exposes a method that may be used to transfer - * this ownership to the specified recipient thread. - * - * @param The concrete type of {@link Resource} that is owned. - */ -@SuppressWarnings("InterfaceMayBeAnnotatedFunctional") -public interface Owned { - /** - * Transfer the ownership of the resource, to the calling thread. The resource instance is invalidated but without - * disposing of its internal state. Then a new resource instance with the given owner is produced in its stead. - *

- * This method is called by {@link Send} implementations. These implementations will ensure that the transfer of - * ownership (the calling of this method) happens-before the new owner begins accessing the new object. This ensures - * that the new resource instanec is safely published to the new owners. - * - * @param drop The drop object that knows how to dispose of the state represented by this {@link Resource}. - * @return A new resource instance that is exactly the same as this resource. - */ - T transferOwnership(Drop drop); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponent.java b/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponent.java deleted file mode 100644 index bdcc045..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponent.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import java.nio.ByteBuffer; - -/** - * A view onto the buffer component being processed in a given iteration of - * {@link Buffer#forEachReadable(int, ReadableComponentProcessor)}. - */ -public interface ReadableComponent { - - /** - * Check if this component is backed by a cached byte array than can be accessed cheaply. - *

- * Note that regardless of what this method returns, the array should not be used to modify the - * contents of this buffer component. - * - * @return {@code true} if {@link #readableArray()} is a cheap operation, otherwise {@code false}. - */ - boolean hasReadableArray(); - - /** - * Get a byte array of the contents of this component. - *

- * Note that the array is meant to be read-only. It may either be a direct reference to the - * concrete array instance that is backing this component, or it is a fresh copy. Writing to the array may produce - * undefined behaviour. - * - * @return A byte array of the contents of this component. - * @throws UnsupportedOperationException if {@link #hasReadableArray()} returns {@code false}. - * @see #readableArrayOffset() - * @see #readableArrayLength() - */ - byte[] readableArray(); - - /** - * An offset into the {@link #readableArray()} where this component starts. - * - * @return An offset into {@link #readableArray()}. - * @throws UnsupportedOperationException if {@link #hasReadableArray()} returns {@code false}. - */ - int readableArrayOffset(); - - /** - * The number of bytes in the {@link #readableArray()} that belong to this component. - * - * @return The number of bytes, from the {@link #readableArrayOffset()} into the {@link #readableArray()}, - * that belong to this component. - * @throws UnsupportedOperationException if {@link #hasReadableArray()} returns {@code false}. - */ - int readableArrayLength(); - - /** - * Give the native memory address backing this buffer, or return 0 if this buffer has no native memory address. - *

- * Note that the address should not be used for writing to the buffer memory, and doing so may - * produce undefined behaviour. - * - * @return The native memory address, if any, otherwise 0. - */ - long readableNativeAddress(); - - /** - * Get a {@link ByteBuffer} instance for this memory component. - *

- * Note that the {@link ByteBuffer} is read-only, to prevent write accesses to the memory, - * when the buffer component is obtained through {@link Buffer#forEachReadable(int, ReadableComponentProcessor)}. - * - * @return A new {@link ByteBuffer}, with its own position and limit, for this memory component. - */ - ByteBuffer readableBuffer(); - - /** - * Open a cursor to iterate the readable bytes of this component. - * Any offsets internal to the component are not modified by the cursor. - *

- * Care should be taken to ensure that the buffers lifetime extends beyond the cursor and the iteration, and that - * the internal offsets of the component (such as {@link Buffer#readerOffset()} and {@link Buffer#writerOffset()}) - * are not modified while the iteration takes place. Otherwise unpredictable behaviour might result. - * - * @return A {@link ByteCursor} for iterating the readable bytes of this buffer. - * @see Buffer#openCursor() - */ - ByteCursor openCursor(); - // todo for Unsafe-based impl, DBB.attachment needs to keep underlying memory alive -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponentProcessor.java b/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponentProcessor.java deleted file mode 100644 index 74232d4..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/ReadableComponentProcessor.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import java.nio.ByteBuffer; - -/** - * A processor of {@linkplain ReadableComponent readable components}. - */ -@FunctionalInterface -public interface ReadableComponentProcessor { - /** - * Process the given component at the given index in the - * {@link Buffer#forEachReadable(int, ReadableComponentProcessor) iteration}. - *

- * The component object itself is only valid during this call, but the {@link ByteBuffer byte buffers}, arrays, and - * native address pointers obtained from it, will be valid until any operation is performed on the buffer, which - * changes the internal memory. - * - * @param index The current index of the given buffer component, based on the initial index passed to the - * {@link Buffer#forEachReadable(int, ReadableComponentProcessor)} method. - * @param component The current buffer component being processed. - * @return {@code true} if the iteration should continue and more components should be processed, otherwise - * {@code false} to stop the iteration early. - */ - boolean process(int index, ReadableComponent component) throws E; -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Resource.java b/buffer-api/src/main/java/io/netty/buffer/api/Resource.java deleted file mode 100644 index 73604ec..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/Resource.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -/** - * A resource that has a life-time, and can be {@linkplain #close() closed}. - * Resources are initially {@linkplain #isAccessible() accessible}, but closing them makes them inaccessible. - */ -public interface Resource> extends AutoCloseable { - /** - * Send this object instance to another Thread, transferring the ownership to the recipient. - *

- * The object must be in a state where it can be sent, which includes at least being - * {@linkplain #isAccessible() accessible}. - *

- * When sent, this instance will immediately become inaccessible, as if by {@linkplain #close() closing} it. - * All attempts at accessing an object that has been sent, even if that object has not yet been received, should - * cause an exception to be thrown. - *

- * Calling {@link #close()} on an object that has been sent will have no effect, so this method is safe to call - * within a try-with-resources statement. - */ - Send send(); - - /** - * Close the resource, making it inaccessible. - *

- * Note, this method is not thread-safe unless otherwise specific. - * - * @throws IllegalStateException If this {@code Resource} has already been closed. - */ - @Override - void close(); - - /** - * Check if this object is accessible. - * - * @return {@code true} if this object is still valid and can be accessed, - * otherwise {@code false} if, for instance, this object has been dropped/deallocated, - * or been {@linkplain #send() sent} elsewhere. - */ - boolean isAccessible(); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/ResourceDisposeFailedException.java b/buffer-api/src/main/java/io/netty/buffer/api/ResourceDisposeFailedException.java deleted file mode 100644 index 5206af2..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/ResourceDisposeFailedException.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -/** - * Thrown when resource disposal fails while closing a resource pool. - */ -public class ResourceDisposeFailedException extends RuntimeException { - private static final long serialVersionUID = -1413426368835341993L; -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Scope.java b/buffer-api/src/main/java/io/netty/buffer/api/Scope.java deleted file mode 100644 index ce746d3..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/Scope.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import java.util.ArrayDeque; - -/** - * A scope is a convenient mechanism for capturing the life cycles of multiple reference counted objects. Once the scope - * is closed, all the added objects will also be closed in reverse insert order. That is, the most recently added - * object will be closed first. - *

- * Scopes can be reused. After a scope has been closed, new objects can be added to it, and they will be closed when the - * scope is closed again. - *

- * Objects will not be closed multiple times if the scope is closed multiple times, unless said objects are also added - * multiple times. - *

- * Note that scopes are not thread-safe. They are intended to be used from a single thread. - */ -public final class Scope implements AutoCloseable { - private final ArrayDeque> deque = new ArrayDeque<>(); - - /** - * Add the given reference counted object to this scope, so that it will be {@linkplain Resource#close() closed} - * when this scope is {@linkplain #close() closed}. - * - * @param obj The reference counted object to add to this scope. - * @param The type of the reference counted object. - * @return The same exact object that was added; further operations can be chained on the object after this method - * call. - */ - public > T add(T obj) { - deque.addLast(obj); - return obj; - } - - /** - * Close this scope and all the reference counted object it contains. - */ - @Override - public void close() { - Resource obj; - while ((obj = deque.pollLast()) != null) { - obj.close(); - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/Send.java b/buffer-api/src/main/java/io/netty/buffer/api/Send.java deleted file mode 100644 index 0b414b7..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/Send.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * A {@code Send} object is a temporary holder of a {@link Resource}, used for transferring the ownership of the - * resource from one thread to another. - *

- * Prior to the {@code Send} being created, the originating resource is invalidated, to prevent access while it is being - * sent. This means it cannot be accessed, closed, or disposed of, while it is in-flight. Once the resource is - * {@linkplain #receive() received}, the new ownership is established. - *

- * Care must be taken to ensure that the resource is always received by some thread. - * Failure to do so can result in a resource leak. - * - * @param - */ -public interface Send> { - /** - * Construct a {@link Send} based on the given {@link Supplier}. - * The supplier will be called only once, in the receiving thread. - * - * @param concreteObjectType The concrete type of the object being sent. Specifically, the object returned from the - * {@link Supplier#get()} method must be an instance of this class. - * @param supplier The supplier of the object being sent, which will be called when the object is ready to be - * received. - * @param The type of object being sent. - * @return A {@link Send} which will deliver an object of the given type, from the supplier. - */ - static > Send sending(Class concreteObjectType, Supplier supplier) { - return new Send() { - private final AtomicBoolean gate = new AtomicBoolean(); - - @Override - public T receive() { - if (gate.getAndSet(true)) { - throw new IllegalStateException("This object has already been received."); - } - return supplier.get(); - } - - @Override - public boolean referentIsInstanceOf(Class cls) { - return cls.isAssignableFrom(concreteObjectType); - } - - @Override - public void discard() { - if (!gate.getAndSet(true)) { - supplier.get().close(); - } - } - }; - } - - /** - * Determine if the given candidate object is an instance of a {@link Send} from which an object of the given type - * can be received. - * - * @param type The type of object we wish to receive. - * @param candidate The candidate object that might be a {@link Send} of an object of the given type. - * @return {@code true} if the candidate object is a {@link Send} that would deliver an object of the given type, - * otherwise {@code false}. - */ - static boolean isSendOf(Class type, Object candidate) { - return candidate instanceof Send && ((Send) candidate).referentIsInstanceOf(type); - } - - /** - * Receive the {@link Resource} instance being sent, and bind its ownership to the calling thread. - * The invalidation of the sent resource in the sending thread happens-before the return of this method. - *

- * This method can only be called once, and will throw otherwise. - * - * @return The sent resource instance. - * @throws IllegalStateException If this method is called more than once. - */ - T receive(); - - /** - * Apply a mapping function to the object being sent. The mapping will occur when the object is received. - * - * @param type The result type of the mapping function. - * @param mapper The mapping function to apply to the object being sent. - * @param The result type of the mapping function. - * @return A new {@link Send} instance that will deliver an object that is the result of the mapping. - */ - default > Send map(Class type, Function mapper) { - return sending(type, () -> mapper.apply(receive())); - } - - /** - * Discard this {@link Send} and the object it contains. - * This has no effect if the send object has already been received. - */ - default void discard() { - try { - receive().close(); - } catch (IllegalStateException ignore) { - // Don't do anything if the "Send" has already been consumed. - } - } - - /** - * Determine if the object received from this {@code Send} is an instance of the given class. - * - * @param cls The type to check. - * @return {@code true} if the object received from this {@code Send} can be assigned fields or variables of the - * given type, otherwise false. - */ - boolean referentIsInstanceOf(Class cls); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/WritableComponent.java b/buffer-api/src/main/java/io/netty/buffer/api/WritableComponent.java deleted file mode 100644 index 4ee6c92..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/WritableComponent.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import java.nio.ByteBuffer; - -/** - * A view onto the buffer component being processed in a given iteration of - * {@link Buffer#forEachWritable(int, WritableComponentProcessor)}. - */ -public interface WritableComponent { - - /** - * Check if this component is backed by a cached byte array than can be accessed cheaply. - * - * @return {@code true} if {@link #writableArray()} is a cheap operation, otherwise {@code false}. - */ - boolean hasWritableArray(); - - /** - * Get a byte array of the contents of this component. - * - * @return A byte array of the contents of this component. - * @throws UnsupportedOperationException if {@link #hasWritableArray()} returns {@code false}. - * @see #writableArrayOffset() - * @see #writableArrayLength() - */ - byte[] writableArray(); - - /** - * An offset into the {@link #writableArray()} where this component starts. - * - * @return An offset into {@link #writableArray()}. - * @throws UnsupportedOperationException if {@link #hasWritableArray()} returns {@code false}. - */ - int writableArrayOffset(); - - /** - * The number of bytes in the {@link #writableArray()} that belong to this component. - * - * @return The number of bytes, from the {@link #writableArrayOffset()} into the {@link #writableArray()}, - * that belong to this component. - * @throws UnsupportedOperationException if {@link #hasWritableArray()} returns {@code false}. - */ - int writableArrayLength(); - - /** - * Give the native memory address backing this buffer, or return 0 if this buffer has no native memory address. - * - * @return The native memory address, if any, otherwise 0. - */ - long writableNativeAddress(); - - /** - * Get a {@link ByteBuffer} instance for this memory component, which can be used for modifying the buffer - * contents. - * - * @return A new {@link ByteBuffer}, with its own position and limit, for this memory component. - */ - ByteBuffer writableBuffer(); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/WritableComponentProcessor.java b/buffer-api/src/main/java/io/netty/buffer/api/WritableComponentProcessor.java deleted file mode 100644 index d4000d3..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/WritableComponentProcessor.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api; - -import java.nio.ByteBuffer; - -/** - * A processor of {@linkplain WritableComponent writable components}. - */ -@FunctionalInterface -public interface WritableComponentProcessor { - /** - * Process the given component at the given index in the - * {@link Buffer#forEachWritable(int, WritableComponentProcessor)} iteration}. - *

- * The component object itself is only valid during this call, but the {@link ByteBuffer byte buffers}, arrays, and - * native address pointers obtained from it, will be valid until any {@link Buffer#isOwned() ownership} requiring - * operation is performed on the buffer. - * - * @param index The current index of the given buffer component, based on the initial index passed to the - * {@link Buffer#forEachWritable(int, WritableComponentProcessor)} method. - * @param component The current buffer component being processed. - * @return {@code true} if the iteration should continue and more components should be processed, otherwise - * {@code false} to stop the iteration early. - */ - boolean process(int index, WritableComponent component) throws E; -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/BufferIntegratable.java b/buffer-api/src/main/java/io/netty/buffer/api/adaptor/BufferIntegratable.java deleted file mode 100644 index fe9a73d..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/BufferIntegratable.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.adaptor; - -import io.netty.buffer.ByteBufConvertible; -import io.netty.util.ReferenceCounted; - -/** - * Interfaces that are required for an object to stand-in for a {@link io.netty.buffer.ByteBuf} in Netty. - */ -public interface BufferIntegratable extends ByteBufConvertible, ReferenceCounted { -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAdaptor.java b/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAdaptor.java deleted file mode 100644 index 3ada76d..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAdaptor.java +++ /dev/null @@ -1,1710 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.adaptor; - -import io.netty.buffer.ByteBufConvertible; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.DuplicatedByteBuf; -import io.netty.buffer.SlicedByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.buffer.api.BufferAllocator; -import io.netty.buffer.api.BufferClosedException; -import io.netty.buffer.api.BufferReadOnlyException; -import io.netty.buffer.api.internal.Statics; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.internal.ResourceSupport; -import io.netty.util.ByteProcessor; -import io.netty.util.IllegalReferenceCountException; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.FileChannel; -import java.nio.channels.GatheringByteChannel; -import java.nio.channels.ScatteringByteChannel; -import java.nio.charset.Charset; -import java.util.concurrent.atomic.AtomicReference; - -import static io.netty.buffer.api.internal.Statics.acquire; -import static io.netty.buffer.api.internal.Statics.isOwned; - -public final class ByteBufAdaptor extends ByteBuf { - private final ByteBufAllocatorAdaptor alloc; - private final Buffer buffer; - private final boolean hasMemoryAddress; - - public ByteBufAdaptor(ByteBufAllocatorAdaptor alloc, Buffer buffer) { - this.alloc = alloc; - this.buffer = buffer; - hasMemoryAddress = buffer.nativeAddress() != 0; - } - - /** - * Extracts the underlying {@link Buffer} instance that is backing this {@link ByteBuf}, if any. - * This is similar to {@link #unwrap()} except the return type is a {@link Buffer}. - * If this {@link ByteBuf} does not wrap a {@link Buffer}, then {@code null} is returned. - * - * @param byteBuf The {@link ByteBuf} to extract the {@link Buffer} from. - * @return The {@link Buffer} instance that is backing the given {@link ByteBuf}, or {@code null} if the given - * {@link ByteBuf} is not backed by a {@link Buffer}. - */ - public static Buffer extract(ByteBuf byteBuf) { - if (byteBuf instanceof ByteBufAdaptor) { - ByteBufAdaptor bba = (ByteBufAdaptor) byteBuf; - return bba.buffer; - } - return null; - } - - @Override - public int capacity() { - return buffer.capacity(); - } - - @Override - public ByteBuf capacity(int newCapacity) { - int diff = newCapacity - capacity() - buffer.writableBytes(); - if (diff > 0) { - try { - buffer.ensureWritable(diff); - } catch (IllegalStateException e) { - if (!isOwned((ResourceSupport) buffer)) { - throw new UnsupportedOperationException(e); - } - throw e; - } - } - return this; - } - - @Override - public int maxCapacity() { - return capacity(); - } - - @Override - public ByteBufAllocator alloc() { - return alloc; - } - - @Override - public ByteOrder order() { - return buffer.order(); - } - - @Override - public ByteBuf order(ByteOrder endianness) { - buffer.order(endianness); - return this; - } - - @Override - public ByteBuf unwrap() { - return null; - } - - @Override - public boolean isDirect() { - return hasMemoryAddress; - } - - @Override - public boolean isReadOnly() { - return buffer.readOnly(); - } - - @Override - public ByteBuf asReadOnly() { - return Unpooled.unreleasableBuffer(this); - } - - @Override - public int readerIndex() { - return buffer.readerOffset(); - } - - @Override - public ByteBuf readerIndex(int readerIndex) { - buffer.readerOffset(readerIndex); - return this; - } - - @Override - public int writerIndex() { - return buffer.writerOffset(); - } - - @Override - public ByteBuf writerIndex(int writerIndex) { - buffer.writerOffset(writerIndex); - return this; - } - - @Override - public ByteBuf setIndex(int readerIndex, int writerIndex) { - buffer.reset().writerOffset(writerIndex).readerOffset(readerIndex); - return this; - } - - @Override - public int readableBytes() { - return buffer.readableBytes(); - } - - @Override - public int writableBytes() { - return buffer.writableBytes(); - } - - @Override - public int maxWritableBytes() { - return writableBytes(); - } - - @Override - public boolean isReadable() { - return readableBytes() > 0; - } - - @Override - public boolean isReadable(int size) { - return readableBytes() >= size; - } - - @Override - public boolean isWritable() { - return writableBytes() > 0; - } - - @Override - public boolean isWritable(int size) { - return writableBytes() >= size; - } - - @Override - public ByteBuf clear() { - return setIndex(0, 0); - } - - @Override - public ByteBuf discardReadBytes() { - checkAccess(); - buffer.compact(); - return this; - } - - @Override - public ByteBuf discardSomeReadBytes() { - return discardReadBytes(); - } - - @Override - public ByteBuf ensureWritable(int minWritableBytes) { - checkAccess(); - if (writableBytes() < minWritableBytes) { - try { - if (isOwned((ResourceSupport) buffer)) { - // Good place. - buffer.ensureWritable(minWritableBytes); - } else { - // Highly questionable place, but ByteBuf technically allows this, so we have to emulate. - int borrows = countBorrows(); - release(borrows); - try { - buffer.ensureWritable(minWritableBytes); - } finally { - retain(borrows); - } - } - } catch (IllegalArgumentException e) { - throw new IndexOutOfBoundsException(e.getMessage()); - } - } - return this; - } - - @Override - public int ensureWritable(int minWritableBytes, boolean force) { - ensureWritable(minWritableBytes); - return minWritableBytes; - } - - @Override - public boolean getBoolean(int index) { - return getByte(index) != 0; - } - - @Override - public byte getByte(int index) { - try { - return buffer.getByte(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public short getUnsignedByte(int index) { - try { - return (short) buffer.getUnsignedByte(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public short getShort(int index) { - try { - return buffer.getShort(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public short getShortLE(int index) { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).getShort(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public int getUnsignedShort(int index) { - try { - return buffer.getUnsignedShort(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public int getUnsignedShortLE(int index) { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).getUnsignedShort(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public int getMedium(int index) { - try { - return buffer.getMedium(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public int getMediumLE(int index) { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).getMedium(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public int getUnsignedMedium(int index) { - try { - return buffer.getUnsignedMedium(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public int getUnsignedMediumLE(int index) { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).getUnsignedMedium(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public int getInt(int index) { - try { - return buffer.getInt(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public int getIntLE(int index) { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).getInt(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public long getUnsignedInt(int index) { - try { - return buffer.getUnsignedInt(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public long getUnsignedIntLE(int index) { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).getUnsignedInt(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public long getLong(int index) { - try { - return buffer.getLong(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public long getLongLE(int index) { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).getLong(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public char getChar(int index) { - try { - return buffer.getChar(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public float getFloat(int index) { - try { - return buffer.getFloat(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public double getDouble(int index) { - try { - return buffer.getDouble(index); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public ByteBuf getBytes(int index, ByteBuf dst) { - while (dst.isWritable()) { - dst.writeByte(getByte(index++)); - } - return this; - } - - @Override - public ByteBuf getBytes(int index, ByteBuf dst, int length) { - for (int i = 0; i < length; i++) { - dst.writeByte(getByte(index + i)); - } - return this; - } - - @Override - public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { - for (int i = 0; i < length; i++) { - dst.setByte(dstIndex + i, getByte(index + i)); - } - return this; - } - - @Override - public ByteBuf getBytes(int index, byte[] dst) { - return getBytes(index, dst, 0, dst.length); - } - - @Override - public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { - checkAccess(); - if (index < 0 || capacity() < index + length || dst.length < dstIndex + length) { - throw new IndexOutOfBoundsException(); - } - for (int i = 0; i < length; i++) { - dst[dstIndex + i] = getByte(index + i); - } - return this; - } - - @Override - public ByteBuf getBytes(int index, ByteBuffer dst) { - checkAccess(); - if (index < 0 || capacity() < index + dst.remaining()) { - throw new IndexOutOfBoundsException(); - } - while (dst.hasRemaining()) { - dst.put(getByte(index)); - index++; - } - return this; - } - - @Override - public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { - for (int i = 0; i < length; i++) { - out.write(getByte(index + i)); - } - return this; - } - - @Override - public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { - checkAccess(); - ByteBuffer transfer = ByteBuffer.allocate(length); - buffer.copyInto(index, transfer, 0, length); - return out.write(transfer); - } - - @Override - public int getBytes(int index, FileChannel out, long position, int length) throws IOException { - checkAccess(); - ByteBuffer transfer = ByteBuffer.allocate(length); - buffer.copyInto(index, transfer, 0, length); - return out.write(transfer, position); - } - - @Override - public CharSequence getCharSequence(int index, int length, Charset charset) { - byte[] bytes = new byte[length]; - getBytes(index, bytes); - return new String(bytes, charset); - } - - @Override - public ByteBuf setBoolean(int index, boolean value) { - return setByte(index, value? 1 : 0); - } - - @Override - public ByteBuf setByte(int index, int value) { - try { - buffer.setByte(index, (byte) value); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - return this; - } - - @Override - public ByteBuf setShort(int index, int value) { - try { - buffer.setShort(index, (short) value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public ByteBuf setShortLE(int index, int value) { - ByteOrder originalOrder = buffer.order(); - try { - buffer.order(ByteOrder.LITTLE_ENDIAN).setShort(index, (short) value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public ByteBuf setMedium(int index, int value) { - try { - buffer.setMedium(index, value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public ByteBuf setMediumLE(int index, int value) { - ByteOrder originalOrder = buffer.order(); - try { - buffer.order(ByteOrder.LITTLE_ENDIAN).setMedium(index, value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public ByteBuf setInt(int index, int value) { - try { - buffer.setInt(index, value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public ByteBuf setIntLE(int index, int value) { - ByteOrder originalOrder = buffer.order(); - try { - buffer.order(ByteOrder.LITTLE_ENDIAN).setInt(index, value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public ByteBuf setLong(int index, long value) { - try { - buffer.setLong(index, value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public ByteBuf setLongLE(int index, long value) { - ByteOrder originalOrder = buffer.order(); - try { - buffer.order(ByteOrder.LITTLE_ENDIAN).setLong(index, value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public ByteBuf setChar(int index, int value) { - try { - buffer.setChar(index, (char) value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public ByteBuf setFloat(int index, float value) { - try { - buffer.setFloat(index, value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public ByteBuf setDouble(int index, double value) { - try { - buffer.setDouble(index, value); - return this; - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public ByteBuf setBytes(int index, ByteBuf src) { - checkAccess(); - while (src.isReadable() && index < capacity()) { - setByte(index++, src.readByte()); - } - return this; - } - - @Override - public ByteBuf setBytes(int index, ByteBuf src, int length) { - checkAccess(); - for (int i = 0; i < length; i++) { - setByte(index + i, src.readByte()); - } - return this; - } - - @Override - public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { - for (int i = 0; i < length; i++) { - setByte(index + i, src.getByte(srcIndex + i)); - } - return this; - } - - @Override - public ByteBuf setBytes(int index, byte[] src) { - return setBytes(index, src, 0, src.length); - } - - @Override - public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { - for (int i = 0; i < length; i++) { - setByte(index + i, src[srcIndex + i]); - } - return this; - } - - @Override - public ByteBuf setBytes(int index, ByteBuffer src) { - while (src.hasRemaining()) { - setByte(index, src.get()); - index++; - } - return this; - } - - @Override - public int setBytes(int index, InputStream in, int length) throws IOException { - checkAccess(); - byte[] bytes = in.readNBytes(length); - setBytes(index, bytes, 0, length); - return bytes.length; - } - - @Override - public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { - checkAccess(); - ByteBuffer transfer = ByteBuffer.allocate(length); - int bytes = in.read(transfer); - transfer.flip(); - setBytes(index, transfer); - return bytes; - } - - @Override - public int setBytes(int index, FileChannel in, long position, int length) throws IOException { - checkAccess(); - ByteBuffer transfer = ByteBuffer.allocate(length); - int bytes = in.read(transfer, position); - transfer.flip(); - setBytes(index, transfer); - return bytes; - } - - @Override - public ByteBuf setZero(int index, int length) { - for (int i = 0; i < length; i++) { - setByte(index + i, 0); - } - return this; - } - - @Override - public int setCharSequence(int index, CharSequence sequence, Charset charset) { - byte[] bytes = sequence.toString().getBytes(charset); - for (int i = 0; i < bytes.length; i++) { - setByte(index + i, bytes[i]); - } - return bytes.length; - } - - @Override - public boolean readBoolean() { - return readByte() != 0; - } - - @Override - public byte readByte() { - try { - return buffer.readByte(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public short readUnsignedByte() { - try { - return (short) buffer.readUnsignedByte(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public short readShort() { - try { - return buffer.readShort(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public short readShortLE() { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).readShort(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public int readUnsignedShort() { - try { - return buffer.readUnsignedShort(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public int readUnsignedShortLE() { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).readUnsignedShort(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public int readMedium() { - try { - return buffer.readMedium(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public int readMediumLE() { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).readMedium(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public int readUnsignedMedium() { - try { - return buffer.readUnsignedMedium(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public int readUnsignedMediumLE() { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).readUnsignedMedium(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public int readInt() { - try { - return buffer.readInt(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public int readIntLE() { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).readInt(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public long readUnsignedInt() { - try { - return buffer.readUnsignedInt(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public long readUnsignedIntLE() { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).readUnsignedInt(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public long readLong() { - try { - return buffer.readLong(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public long readLongLE() { - ByteOrder originalOrder = buffer.order(); - try { - return buffer.order(ByteOrder.LITTLE_ENDIAN).readLong(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } finally { - buffer.order(originalOrder); - } - } - - @Override - public char readChar() { - try { - return buffer.readChar(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public float readFloat() { - try { - return buffer.readFloat(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public double readDouble() { - try { - return buffer.readDouble(); - } catch (IllegalStateException | BufferClosedException e) { - throw new IllegalReferenceCountException(e); - } - } - - @Override - public ByteBuf readBytes(int length) { - checkAccess(); - Buffer copy = preferredBufferAllocator().allocate(length); - buffer.copyInto(readerIndex(), copy, 0, length); - readerIndex(readerIndex() + length); - return wrap(copy).writerIndex(length); - } - - @Override - public ByteBuf readSlice(int length) { - ByteBuf slice = slice(readerIndex(), length); - buffer.readerOffset(buffer.readerOffset() + length); - return slice; - } - - @Override - public ByteBuf readRetainedSlice(int length) { - ByteBuf slice = retainedSlice(readerIndex(), length); - buffer.readerOffset(buffer.readerOffset() + length); - return slice; - } - - @Override - public ByteBuf readBytes(ByteBuf dst) { - while (dst.isWritable()) { - dst.writeByte(readByte()); - } - return this; - } - - @Override - public ByteBuf readBytes(ByteBuf dst, int length) { - for (int i = 0; i < length; i++) { - dst.writeByte(readByte()); - } - return this; - } - - @Override - public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) { - for (int i = 0; i < length; i++) { - dst.setByte(dstIndex + i, readByte()); - } - return this; - } - - @Override - public ByteBuf readBytes(byte[] dst) { - return readBytes(dst, 0, dst.length); - } - - @Override - public ByteBuf readBytes(byte[] dst, int dstIndex, int length) { - for (int i = 0; i < length; i++) { - dst[dstIndex + i] = readByte(); - } - return this; - } - - @Override - public ByteBuf readBytes(ByteBuffer dst) { - while (dst.hasRemaining()) { - dst.put(readByte()); - } - return this; - } - - @Override - public ByteBuf readBytes(OutputStream out, int length) throws IOException { - for (int i = 0; i < length; i++) { - out.write(readByte()); - } - return this; - } - - @Override - public int readBytes(GatheringByteChannel out, int length) throws IOException { - checkAccess(); - ByteBuffer[] components = new ByteBuffer[buffer.countReadableComponents()]; - buffer.forEachReadable(0, (i, component) -> { - components[i] = component.readableBuffer(); - return true; - }); - int written = (int) out.write(components); - skipBytes(written); - return written; - } - - @Override - public CharSequence readCharSequence(int length, Charset charset) { - byte[] bytes = new byte[length]; - readBytes(bytes); - return new String(bytes, charset); - } - - @Override - public int readBytes(FileChannel out, long position, int length) throws IOException { - ByteBuffer[] components = new ByteBuffer[buffer.countReadableComponents()]; - buffer.forEachReadable(0, (i, component) -> { - components[i] = component.readableBuffer(); - return true; - }); - int written = 0; - for (ByteBuffer component : components) { - written += out.write(component, position + written); - if (component.hasRemaining()) { - break; - } - } - skipBytes(written); - return written; - } - - @Override - public ByteBuf skipBytes(int length) { - buffer.readerOffset(length + buffer.readerOffset()); - return this; - } - - @Override - public ByteBuf writeBoolean(boolean value) { - return writeByte(value? 1 : 0); - } - - @Override - public ByteBuf writeByte(int value) { - ensureWritable(1); - buffer.writeByte((byte) value); - return this; - } - - @Override - public ByteBuf writeShort(int value) { - ensureWritable(2); - buffer.writeShort((short) value); - return this; - } - - @Override - public ByteBuf writeShortLE(int value) { - ensureWritable(2); - ByteOrder originalOrder = buffer.order(); - try { - buffer.order(ByteOrder.LITTLE_ENDIAN).writeShort((short) value); - return this; - } finally { - buffer.order(originalOrder); - } - } - - @Override - public ByteBuf writeMedium(int value) { - ensureWritable(3); - buffer.writeMedium(value); - return this; - } - - @Override - public ByteBuf writeMediumLE(int value) { - ensureWritable(3); - ByteOrder originalOrder = buffer.order(); - try { - buffer.order(ByteOrder.LITTLE_ENDIAN).writeMedium(value); - return this; - } finally { - buffer.order(originalOrder); - } - } - - @Override - public ByteBuf writeInt(int value) { - ensureWritable(4); - buffer.writeInt(value); - return this; - } - - @Override - public ByteBuf writeIntLE(int value) { - ensureWritable(4); - ByteOrder originalOrder = buffer.order(); - try { - buffer.order(ByteOrder.LITTLE_ENDIAN).writeInt(value); - return this; - } finally { - buffer.order(originalOrder); - } - } - - @Override - public ByteBuf writeLong(long value) { - ensureWritable(8); - buffer.writeLong(value); - return this; - } - - @Override - public ByteBuf writeLongLE(long value) { - ensureWritable(8); - ByteOrder originalOrder = buffer.order(); - try { - buffer.order(ByteOrder.LITTLE_ENDIAN).writeLong(value); - return this; - } finally { - buffer.order(originalOrder); - } - } - - @Override - public ByteBuf writeChar(int value) { - ensureWritable(2); - buffer.writeChar((char) value); - return this; - } - - @Override - public ByteBuf writeFloat(float value) { - ensureWritable(4); - buffer.writeFloat(value); - return this; - } - - @Override - public ByteBuf writeDouble(double value) { - ensureWritable(8); - buffer.writeDouble(value); - return this; - } - - @Override - public ByteBuf writeBytes(ByteBuf src) { - return writeBytes(src, src.readableBytes()); - } - - @Override - public ByteBuf writeBytes(ByteBuf src, int length) { - ensureWritable(length); - for (int i = 0; i < length; i++) { - writeByte(src.readByte()); - } - return this; - } - - @Override - public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) { - ensureWritable(length); - for (int i = 0; i < length; i++) { - writeByte(src.getByte(srcIndex + i)); - } - return this; - } - - @Override - public ByteBuf writeBytes(byte[] src) { - ensureWritable(src.length); - for (byte b : src) { - writeByte(b); - } - return this; - } - - @Override - public ByteBuf writeBytes(byte[] src, int srcIndex, int length) { - ensureWritable(length); - for (int i = 0; i < length; i++) { - writeByte(src[srcIndex + i]); - } - return this; - } - - @Override - public ByteBuf writeBytes(ByteBuffer src) { - ensureWritable(src.remaining()); - while (src.hasRemaining()) { - writeByte(src.get()); - } - return this; - } - - @Override - public int writeBytes(InputStream in, int length) throws IOException { - byte[] bytes = in.readNBytes(length); - writeBytes(bytes); - return bytes.length; - } - - @Override - public int writeBytes(ScatteringByteChannel in, int length) throws IOException { - ensureWritable(length); - ByteBuffer[] components = new ByteBuffer[buffer.countWritableComponents()]; - buffer.forEachWritable(0, (i, component) -> { - components[i] = component.writableBuffer(); - return true; - }); - - int read = (int) in.read(components); - - if (read > 0) { - writerIndex(read + writerIndex()); - } - return read; - } - - @Override - public int writeBytes(FileChannel in, long position, int length) throws IOException { - ensureWritable(length); - ByteBuffer[] components = new ByteBuffer[buffer.countWritableComponents()]; - buffer.forEachWritable(0, (i, component) -> { - components[i] = component.writableBuffer(); - return true; - }); - int read = 0; - for (ByteBuffer component : components) { - int r = in.read(component, position + read); - if (r > 0) { - read += r; - } - if (component.hasRemaining()) { - break; - } - } - writerIndex(read + writerIndex()); - return read; - } - - @Override - public ByteBuf writeZero(int length) { - if (length < 0) { - throw new IllegalArgumentException(); - } - ensureWritable(length); - for (int i = 0; i < length; i++) { - writeByte(0); - } - return this; - } - - @Override - public int writeCharSequence(CharSequence sequence, Charset charset) { - byte[] bytes = sequence.toString().getBytes(charset); - writeBytes(bytes); - return bytes.length; - } - - @Override - public int indexOf(int fromIndex, int toIndex, byte value) { - if (!buffer.isAccessible()) { - return -1; - } - if (fromIndex <= toIndex) { - if (fromIndex < 0) { - fromIndex = 0; // Required to pass regression tests. - } - if (capacity() < toIndex) { - throw new IndexOutOfBoundsException(); - } - for (; fromIndex < toIndex; fromIndex++) { - if (getByte(fromIndex) == value) { - return fromIndex; - } - } - } else { - if (capacity() < fromIndex) { - fromIndex = capacity(); // Required to pass regression tests. - } - fromIndex--; - if (toIndex < 0) { - throw new IndexOutOfBoundsException(); - } - for (; fromIndex > toIndex; fromIndex--) { - if (getByte(fromIndex) == value) { - return fromIndex; - } - } - } - return -1; - } - - @Override - public int bytesBefore(byte value) { - return bytesBefore(readerIndex(), writerIndex(), value); - } - - @Override - public int bytesBefore(int length, byte value) { - return bytesBefore(readerIndex(), readerIndex() + length, value); - } - - @Override - public int bytesBefore(int index, int length, byte value) { - int i = indexOf(index, index + length, value); - if (i != -1) { - i -= index; - } - return i; - } - - @Override - public int forEachByte(ByteProcessor processor) { - checkAccess(); - int index = readerIndex(); - int bytes = buffer.openCursor().process(processor); - return bytes == -1 ? -1 : index + bytes; - } - - @Override - public int forEachByte(int index, int length, ByteProcessor processor) { - checkAccess(); - int bytes = buffer.openCursor(index, length).process(processor); - return bytes == -1 ? -1 : index + bytes; - } - - @Override - public int forEachByteDesc(ByteProcessor processor) { - checkAccess(); - int index = readerIndex(); - int bytes = buffer.openReverseCursor().process(processor); - return bytes == -1 ? -1 : index - bytes; - } - - @Override - public int forEachByteDesc(int index, int length, ByteProcessor processor) { - checkAccess(); - int bytes = buffer.openReverseCursor(index + length - 1, length).process(processor); - return bytes == -1 ? -1 : index - bytes; - } - - @Override - public ByteBuf copy() { - return copy(readerIndex(), readableBytes()); - } - - @Override - public ByteBuf copy(int index, int length) { - checkAccess(); - try { - BufferAllocator allocator = preferredBufferAllocator(); - Buffer copy = allocator.allocate(length); - buffer.copyInto(index, copy, 0, length); - copy.order(buffer.order()); - copy.writerOffset(length); - return wrap(copy); - } catch (IllegalArgumentException e) { - throw new IndexOutOfBoundsException(e.getMessage()); - } - } - - @Override - public ByteBuf slice() { - return slice(readerIndex(), readableBytes()); - } - - @Override - public ByteBuf retainedSlice() { - return retainedSlice(readerIndex(), readableBytes()); - } - - @Override - public ByteBuf slice(int index, int length) { - checkAccess(); - return new Slice(this, index, length); - } - - @Override - public ByteBuf retainedSlice(int index, int length) { - checkAccess(); - Slice slice = new Slice(this, index, length); - retain(); - return slice; - } - - private static final class Slice extends SlicedByteBuf { - private final int indexAdjustment; - private final int lengthAdjustment; - - Slice(ByteBuf buffer, int index, int length) { - super(buffer, index, length); - indexAdjustment = index; - lengthAdjustment = length; - } - - @Override - public ByteBuf retainedDuplicate() { - return new Slice(unwrap().retainedDuplicate(), indexAdjustment, lengthAdjustment) - .setIndex(readerIndex(), writerIndex()); - } - - @Override - public ByteBuf retainedSlice(int index, int length) { - checkIndex(index, length); - return unwrap().retainedSlice(indexAdjustment + index, length); - } - } - - private static final class Duplicate extends DuplicatedByteBuf { - Duplicate(ByteBufAdaptor byteBuf) { - super(byteBuf); - } - - @Override - public ByteBuf duplicate() { - ((ByteBufAdaptor) unwrap()).checkAccess(); - return new Duplicate((ByteBufAdaptor) unwrap()) - .setIndex(readerIndex(), writerIndex()); - } - - @Override - public ByteBuf retainedDuplicate() { - return unwrap().retainedDuplicate(); - } - - @Override - public ByteBuf retainedSlice(int index, int length) { - return unwrap().retainedSlice(index, length); - } - } - - @Override - public ByteBuf duplicate() { - checkAccess(); - Duplicate duplicatedByteBuf = new Duplicate(this); - return duplicatedByteBuf.setIndex(readerIndex(), writerIndex()); - } - - @Override - public ByteBuf retainedDuplicate() { - checkAccess(); - retain(); - Duplicate duplicatedByteBuf = new Duplicate(this); - return duplicatedByteBuf.setIndex(readerIndex(), writerIndex()); - } - - @Override - public int nioBufferCount() { - return 1; - } - - @Override - public ByteBuffer nioBuffer() { - return nioBuffer(readerIndex(), readableBytes()); - } - - @Override - public ByteBuffer nioBuffer(int index, int length) { - checkAccess(); - ByteBuffer copy = isDirect() ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length); - while (index < length) { - copy.put(getByte(index++)); - } - return copy.flip(); - } - - @Override - public ByteBuffer internalNioBuffer(int index, int length) { - checkAccess(); - if (readerIndex() <= index && index < writerIndex() && length <= readableBytes()) { - // We wish to read from the internal buffer. - if (buffer.countReadableComponents() != 1) { - throw new UnsupportedOperationException( - "Unsupported number of readable components: " + buffer.countReadableComponents() + '.'); - } - AtomicReference bufRef = new AtomicReference<>(); - buffer.forEachReadable(0, (i, component) -> { - bufRef.set(component.readableBuffer()); - return false; - }); - ByteBuffer buffer = bufRef.get(); - if (index != readerIndex() || length != readableBytes()) { - buffer = Statics.bbslice(buffer, index - readerIndex(), length); - } - return buffer; - } else if (writerIndex() <= index && length <= writableBytes()) { - // We wish to write to the internal buffer. - if (buffer.countWritableComponents() != 1) { - throw new UnsupportedOperationException( - "Unsupported number of writable components: " + buffer.countWritableComponents() + '.'); - } - AtomicReference bufRef = new AtomicReference<>(); - buffer.forEachWritable(0, (i, component) -> { - bufRef.set(component.writableBuffer()); - return false; - }); - ByteBuffer buffer = bufRef.get(); - if (index != writerIndex() || length != writableBytes()) { - buffer = Statics.bbslice(buffer, index - writerIndex(), length); - } - return buffer; - } else { - String message = "Cannot provide internal NIO buffer for range from " + index + " for length " + length + - ", when writerIndex() is " + writerIndex() + " and writable bytes are " + writableBytes() + - ", and readerIndex() is " + readerIndex() + " and readable bytes are " + readableBytes() + - ". The requested range must fall within EITHER the readable area OR the writable area. " + - "Straddling the two areas, or reaching outside of their bounds, is not allowed."; - throw new UnsupportedOperationException(message); - } - } - - @Override - public ByteBuffer[] nioBuffers() { - return new ByteBuffer[] { nioBuffer() }; - } - - @Override - public ByteBuffer[] nioBuffers(int index, int length) { - return new ByteBuffer[] { internalNioBuffer(index, length) }; - } - - @Override - public boolean hasArray() { - return false; - } - - @Override - public byte[] array() { - throw new UnsupportedOperationException("This buffer has no array."); - } - - @Override - public int arrayOffset() { - throw new UnsupportedOperationException("This buffer has no array."); - } - - @Override - public boolean hasMemoryAddress() { - return hasMemoryAddress; - } - - @Override - public long memoryAddress() { - if (!hasMemoryAddress()) { - throw new UnsupportedOperationException("No memory address associated with this buffer."); - } - return buffer.nativeAddress(); - } - - @Override - public String toString(Charset charset) { - return toString(readerIndex(), readableBytes(), charset); - } - - @Override - public String toString(int index, int length, Charset charset) { - byte[] bytes = new byte[length]; - getBytes(index, bytes); - return new String(bytes, charset); - } - - @Override - public int hashCode() { - return ByteBufUtil.hashCode(this); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ByteBufConvertible) { - ByteBuf other = ((ByteBufConvertible) obj).asByteBuf(); - return this == other || ByteBufUtil.equals(this, other); - } - return false; - } - - @Override - public int compareTo(ByteBuf buffer) { - ByteOrder orderThis = order(); - ByteOrder orderThat = buffer.order(); - try { - // Little-ending implementation of the compare seems to be broken. - return ByteBufUtil.compare(order(ByteOrder.BIG_ENDIAN), buffer.order(ByteOrder.BIG_ENDIAN)); - } finally { - order(orderThis); - buffer.order(orderThat); - } - } - - @Override - public String toString() { - return "ByteBuf(" + readerIndex() + ", " + writerIndex() + ", " + capacity() + ')'; - } - - @Override - public ByteBuf retain(int increment) { - for (int i = 0; i < increment; i++) { - acquire((ResourceSupport) buffer); - } - return this; - } - - @Override - public int refCnt() { - return 1 + countBorrows(); - } - - private int countBorrows() { - if (!buffer.isAccessible()) { - return -1; - } - if (buffer instanceof ResourceSupport) { - var rc = (ResourceSupport) buffer; - return Statics.countBorrows(rc); - } - return isOwned((ResourceSupport) buffer)? 0 : 1; - } - - @Override - public ByteBuf retain() { - return retain(1); - } - - @Override - public ByteBuf touch() { - return this; - } - - @Override - public ByteBuf touch(Object hint) { - return this; - } - - @Override - public boolean release() { - return release(1); - } - - @Override - public boolean release(int decrement) { - int refCount = 1 + Statics.countBorrows((ResourceSupport) buffer); - if (!buffer.isAccessible() || decrement > refCount) { - throw new IllegalReferenceCountException(refCount, -decrement); - } - for (int i = 0; i < decrement; i++) { - try { - buffer.close(); - } catch (RuntimeException e) { - throw new IllegalReferenceCountException(e); - } - } - return !buffer.isAccessible(); - } - - private void checkAccess() { - if (!buffer.isAccessible()) { - throw new IllegalReferenceCountException(); - } - } - - private ByteBufAdaptor wrap(Buffer copy) { - return new ByteBufAdaptor(alloc, copy); - } - - private BufferAllocator preferredBufferAllocator() { - return isDirect()? alloc.getOffHeap() : alloc.getOnHeap(); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAllocatorAdaptor.java b/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAllocatorAdaptor.java deleted file mode 100644 index bd65fca..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/ByteBufAllocatorAdaptor.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.adaptor; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.CompositeByteBuf; -import io.netty.buffer.api.BufferAllocator; - -import static java.nio.ByteOrder.BIG_ENDIAN; - -public class ByteBufAllocatorAdaptor implements ByteBufAllocator, AutoCloseable { - private final BufferAllocator onheap; - private final BufferAllocator offheap; - private boolean closed; - - public ByteBufAllocatorAdaptor() { - this(BufferAllocator.pooledHeap(), BufferAllocator.pooledDirect()); - } - - public ByteBufAllocatorAdaptor(BufferAllocator onheap, BufferAllocator offheap) { - this.onheap = onheap; - this.offheap = offheap; - } - - @Override - public ByteBuf buffer() { - return buffer(256); - } - - public BufferAllocator getOnHeap() { - return onheap; - } - - public BufferAllocator getOffHeap() { - return offheap; - } - - public boolean isClosed() { - return closed; - } - - @Override - public ByteBuf buffer(int initialCapacity) { - return new ByteBufAdaptor(this, onheap.allocate(initialCapacity).order(BIG_ENDIAN)); - } - - @Override - public ByteBuf buffer(int initialCapacity, int maxCapacity) { - return buffer(maxCapacity); - } - - @Override - public ByteBuf ioBuffer() { - return directBuffer(); - } - - @Override - public ByteBuf ioBuffer(int initialCapacity) { - return directBuffer(initialCapacity); - } - - @Override - public ByteBuf ioBuffer(int initialCapacity, int maxCapacity) { - return directBuffer(initialCapacity, maxCapacity); - } - - @Override - public ByteBuf heapBuffer() { - return buffer(); - } - - @Override - public ByteBuf heapBuffer(int initialCapacity) { - return buffer(initialCapacity); - } - - @Override - public ByteBuf heapBuffer(int initialCapacity, int maxCapacity) { - return buffer(initialCapacity, maxCapacity); - } - - @Override - public ByteBuf directBuffer() { - return directBuffer(256); - } - - @Override - public ByteBuf directBuffer(int initialCapacity) { - return new ByteBufAdaptor(this, offheap.allocate(initialCapacity).order(BIG_ENDIAN)); - } - - @Override - public ByteBuf directBuffer(int initialCapacity, int maxCapacity) { - return directBuffer(maxCapacity); - } - - @Override - public CompositeByteBuf compositeBuffer() { - return compositeHeapBuffer(); - } - - @Override - public CompositeByteBuf compositeBuffer(int maxNumComponents) { - return compositeHeapBuffer(maxNumComponents); - } - - @Override - public CompositeByteBuf compositeHeapBuffer() { - return compositeHeapBuffer(1024); - } - - @Override - public CompositeByteBuf compositeHeapBuffer(int maxNumComponents) { - return new CompositeByteBuf(this, false, maxNumComponents, heapBuffer()); - } - - @Override - public CompositeByteBuf compositeDirectBuffer() { - return compositeDirectBuffer(1024); - } - - @Override - public CompositeByteBuf compositeDirectBuffer(int maxNumComponents) { - return new CompositeByteBuf(this, true, maxNumComponents, directBuffer()); - } - - @Override - public boolean isDirectBufferPooled() { - return true; - } - - @Override - public int calculateNewCapacity(int minNewCapacity, int maxCapacity) { - return 0; - } - - @Override - public void close() throws Exception { - try (onheap) { - try (offheap) { - closed = true; - } - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/adaptor/package-info.java deleted file mode 100644 index 1296415..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/adaptor/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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. - */ - -/** - * Helpers for integrating with the existing {@link io.netty.buffer.ByteBuf} API. - */ -package io.netty.buffer.api.adaptor; diff --git a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManager.java b/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManager.java deleted file mode 100644 index f4925a0..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManager.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.bytebuffer; - -import io.netty.buffer.api.AllocatorControl; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.MemoryManager; -import io.netty.buffer.api.internal.Statics; - -import java.lang.ref.Cleaner; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import static io.netty.buffer.api.internal.Statics.bbslice; -import static io.netty.buffer.api.internal.Statics.convert; - -public class ByteBufferMemoryManager implements MemoryManager { - private final boolean direct; - - public ByteBufferMemoryManager(boolean direct) { - this.direct = direct; - } - - @Override - public boolean isNative() { - return direct; - } - - @Override - public Buffer allocateShared(AllocatorControl allocatorControl, long size, Drop drop, Cleaner cleaner) { - int capacity = Math.toIntExact(size); - ByteBuffer buffer = direct? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity); - buffer.order(ByteOrder.nativeOrder()); - return new NioBuffer(buffer, buffer, allocatorControl, convert(drop)); - } - - @Override - public Buffer allocateConstChild(Buffer readOnlyConstParent) { - assert readOnlyConstParent.readOnly(); - NioBuffer buf = (NioBuffer) readOnlyConstParent; - return new NioBuffer(buf); - } - - @Override - public Drop drop() { - return Statics.NO_OP_DROP; - } - - @Override - public Object unwrapRecoverableMemory(Buffer buf) { - return ((NioBuffer) buf).recoverable(); - } - - @Override - public int capacityOfRecoverableMemory(Object memory) { - //noinspection OverlyStrongTypeCast - return ((ByteBuffer) memory).capacity(); - } - - @Override - public void discardRecoverableMemory(Object recoverableMemory) { - // ByteBuffers have their memory released by the GC, so there is nothing for us to do. - } - - @Override - public Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop drop) { - ByteBuffer memory = (ByteBuffer) recoverableMemory; - return new NioBuffer(memory, memory, allocatorControl, convert(drop)); - } - - @Override - public Object sliceMemory(Object memory, int offset, int length) { - var buffer = (ByteBuffer) memory; - return bbslice(buffer, offset, length); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManagers.java b/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManagers.java deleted file mode 100644 index 56e731f..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/ByteBufferMemoryManagers.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.bytebuffer; - -import io.netty.buffer.api.MemoryManager; -import io.netty.buffer.api.MemoryManagers; - -public class ByteBufferMemoryManagers implements MemoryManagers { - @Override - public MemoryManager getHeapMemoryManager() { - return new ByteBufferMemoryManager(false); - } - - @Override - public MemoryManager getNativeMemoryManager() { - return new ByteBufferMemoryManager(true); - } - - @Override - public String getImplementationName() { - return "ByteBuffer"; - } - - @Override - public String toString() { - return "BB"; - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/NioBuffer.java b/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/NioBuffer.java deleted file mode 100644 index 6b1342d..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/NioBuffer.java +++ /dev/null @@ -1,1275 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.bytebuffer; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.api.AllocatorControl; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.BufferAllocator; -import io.netty.buffer.api.BufferReadOnlyException; -import io.netty.buffer.api.ByteCursor; -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.Owned; -import io.netty.buffer.api.adaptor.BufferIntegratable; -import io.netty.buffer.api.adaptor.ByteBufAdaptor; -import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor; -import io.netty.buffer.api.internal.ResourceSupport; -import io.netty.buffer.api.ReadableComponent; -import io.netty.buffer.api.ReadableComponentProcessor; -import io.netty.buffer.api.WritableComponent; -import io.netty.buffer.api.WritableComponentProcessor; -import io.netty.buffer.api.internal.ArcDrop; -import io.netty.buffer.api.internal.Statics; -import io.netty.util.IllegalReferenceCountException; -import io.netty.util.ReferenceCounted; -import io.netty.util.internal.PlatformDependent; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.ReadOnlyBufferException; - -import static io.netty.buffer.api.internal.Statics.bbput; -import static io.netty.buffer.api.internal.Statics.bbslice; -import static io.netty.buffer.api.internal.Statics.bufferIsClosed; -import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly; - -class NioBuffer extends ResourceSupport implements Buffer, ReadableComponent, WritableComponent, - BufferIntegratable { - private static final ByteBuffer CLOSED_BUFFER = ByteBuffer.allocate(0); - - private final AllocatorControl control; - private ByteBuffer base; - private ByteBuffer rmem; // For reading. - private ByteBuffer wmem; // For writing. - - private int roff; - private int woff; - private boolean constBuffer; - - NioBuffer(ByteBuffer base, ByteBuffer memory, AllocatorControl control, Drop drop) { - super(new MakeInaccessibleOnDrop(ArcDrop.wrap(drop))); - this.base = base; - rmem = memory; - wmem = memory; - this.control = control; - } - - /** - * Constructor for {@linkplain BufferAllocator#constBufferSupplier(byte[]) const buffers}. - */ - NioBuffer(NioBuffer parent) { - super(new MakeInaccessibleOnDrop(new ArcDrop<>(ArcDrop.acquire(parent.unsafeGetDrop())))); - control = parent.control; - base = parent.base; - rmem = bbslice(parent.rmem, 0, parent.rmem.capacity()); // Need to slice to get independent byte orders. - assert parent.wmem == CLOSED_BUFFER; - wmem = CLOSED_BUFFER; - roff = parent.roff; - woff = parent.woff; - order(parent.order()); - constBuffer = true; - } - - private static final class MakeInaccessibleOnDrop implements Drop { - final Drop delegate; - - private MakeInaccessibleOnDrop(Drop delegate) { - this.delegate = delegate; - } - - @Override - public void drop(NioBuffer buf) { - try { - delegate.drop(buf); - } finally { - buf.makeInaccessible(); - } - } - - @Override - public void attach(NioBuffer buf) { - delegate.attach(buf); - } - - @Override - public String toString() { - return "MakeInaccessibleOnDrop(" + delegate + ')'; - } - } - - @Override - protected Drop unsafeGetDrop() { - MakeInaccessibleOnDrop drop = (MakeInaccessibleOnDrop) super.unsafeGetDrop(); - return drop.delegate; - } - - @Override - protected void unsafeSetDrop(Drop replacement) { - super.unsafeSetDrop(new MakeInaccessibleOnDrop(replacement)); - } - - @Override - public String toString() { - return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + rmem.capacity() + ']'; - } - - @Override - protected RuntimeException createResourceClosedException() { - return bufferIsClosed(this); - } - - @Override - public Buffer order(ByteOrder order) { - rmem.order(order); - return this; - } - - @Override - public ByteOrder order() { - return rmem.order(); - } - - @Override - public int capacity() { - return rmem.capacity(); - } - - @Override - public int readerOffset() { - return roff; - } - - @Override - public Buffer readerOffset(int offset) { - checkRead(offset, 0); - roff = offset; - return this; - } - - @Override - public int writerOffset() { - return woff; - } - - @Override - public Buffer writerOffset(int offset) { - checkWrite(offset, 0); - woff = offset; - return this; - } - - @Override - public Buffer fill(byte value) { - int capacity = capacity(); - checkSet(0, capacity); - if (rmem == CLOSED_BUFFER) { - throw bufferIsClosed(this); - } - for (int i = 0; i < capacity; i++) { - wmem.put(i, value); - } - return this; - } - - @Override - public long nativeAddress() { - return rmem.isDirect() && PlatformDependent.hasUnsafe()? PlatformDependent.directBufferAddress(rmem) : 0; - } - - @Override - public Buffer makeReadOnly() { - wmem = CLOSED_BUFFER; - return this; - } - - @Override - public boolean readOnly() { - return wmem == CLOSED_BUFFER && rmem != CLOSED_BUFFER; - } - - @Override - public Buffer copy(int offset, int length) { - checkGet(offset, length); - int allocSize = Math.max(length, 1); // Allocators don't support allocating zero-sized buffers. - AllocatorControl.UntetheredMemory memory = control.allocateUntethered(this, allocSize); - ByteBuffer base = memory.memory(); - ByteBuffer buffer = length == 0? bbslice(base, 0, 0) : base; - Buffer copy = new NioBuffer(base, buffer, control, memory.drop()); - copyInto(offset, copy, 0, length); - copy.writerOffset(length).order(order()); - if (readOnly()) { - copy = copy.makeReadOnly(); - } - return copy; - } - - @Override - public void copyInto(int srcPos, byte[] dest, int destPos, int length) { - copyInto(srcPos, ByteBuffer.wrap(dest), destPos, length); - } - - @Override - public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) { - if (rmem == CLOSED_BUFFER) { - throw bufferIsClosed(this); - } - if (srcPos < 0) { - throw new IllegalArgumentException("The srcPos cannot be negative: " + srcPos + '.'); - } - if (length < 0) { - throw new IllegalArgumentException("The length cannot be negative: " + length + '.'); - } - if (capacity() < srcPos + length) { - throw new IllegalArgumentException("The srcPos + length is beyond the end of the buffer: " + - "srcPos = " + srcPos + ", length = " + length + '.'); - } - dest = dest.duplicate().clear(); - bbput(dest, destPos, rmem, srcPos, length); - } - - @Override - public void copyInto(int srcPos, Buffer dest, int destPos, int length) { - if (dest instanceof NioBuffer) { - var nb = (NioBuffer) dest; - nb.checkSet(destPos, length); - copyInto(srcPos, nb.wmem, destPos, length); - return; - } - - Statics.copyToViaReverseCursor(this, srcPos, dest, destPos, length); - } - - @Override - public ByteCursor openCursor() { - return openCursor(readerOffset(), readableBytes()); - } - - @Override - public ByteCursor openCursor(int fromOffset, int length) { - if (rmem == CLOSED_BUFFER) { - throw bufferIsClosed(this); - } - if (fromOffset < 0) { - throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.'); - } - if (length < 0) { - throw new IllegalArgumentException("The length cannot be negative: " + length + '.'); - } - if (capacity() < fromOffset + length) { - throw new IllegalArgumentException("The fromOffset + length is beyond the end of the buffer: " + - "fromOffset = " + fromOffset + ", length = " + length + '.'); - } - return new ByteCursor() { - // Duplicate source buffer to keep our own byte order state. - final ByteBuffer buffer = rmem.duplicate().order(ByteOrder.BIG_ENDIAN); - int index = fromOffset; - final int end = index + length; - long longValue = -1; - byte byteValue = -1; - - @Override - public boolean readLong() { - if (index + Long.BYTES <= end) { - longValue = buffer.getLong(index); - index += Long.BYTES; - return true; - } - return false; - } - - @Override - public long getLong() { - return longValue; - } - - @Override - public boolean readByte() { - if (index < end) { - byteValue = buffer.get(index); - index++; - return true; - } - return false; - } - - @Override - public byte getByte() { - return byteValue; - } - - @Override - public int currentOffset() { - return index; - } - - @Override - public int bytesLeft() { - return end - index; - } - }; - } - - @Override - public ByteCursor openReverseCursor(int fromOffset, int length) { - if (rmem == CLOSED_BUFFER) { - throw bufferIsClosed(this); - } - if (fromOffset < 0) { - throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.'); - } - if (length < 0) { - throw new IllegalArgumentException("The length cannot be negative: " + length + '.'); - } - if (capacity() <= fromOffset) { - throw new IllegalArgumentException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.'); - } - if (fromOffset - length < -1) { - throw new IllegalArgumentException("The fromOffset - length would underflow the buffer: " + - "fromOffset = " + fromOffset + ", length = " + length + '.'); - } - return new ByteCursor() { - final ByteBuffer buffer = rmem.duplicate().order(ByteOrder.LITTLE_ENDIAN); - int index = fromOffset; - final int end = index - length; - long longValue = -1; - byte byteValue = -1; - - @Override - public boolean readLong() { - if (index - Long.BYTES >= end) { - index -= 7; - longValue = buffer.getLong(index); - index--; - return true; - } - return false; - } - - @Override - public long getLong() { - return longValue; - } - - @Override - public boolean readByte() { - if (index > end) { - byteValue = buffer.get(index); - index--; - return true; - } - return false; - } - - @Override - public byte getByte() { - return byteValue; - } - - @Override - public int currentOffset() { - return index; - } - - @Override - public int bytesLeft() { - return index - end; - } - }; - } - - @Override - public void ensureWritable(int size, int minimumGrowth, boolean allowCompaction) { - if (!isAccessible()) { - throw bufferIsClosed(this); - } - if (!isOwned()) { - throw attachTrace(new IllegalStateException( - "Buffer is not owned. Only owned buffers can call ensureWritable.")); - } - if (size < 0) { - throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.'); - } - if (minimumGrowth < 0) { - throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.'); - } - if (rmem != wmem) { - throw bufferIsReadOnly(this); - } - if (writableBytes() >= size) { - // We already have enough space. - return; - } - - if (allowCompaction && writableBytes() + readerOffset() >= size) { - // We can solve this with compaction. - compact(); - return; - } - - // Allocate a bigger buffer. - long newSize = capacity() + (long) Math.max(size - writableBytes(), minimumGrowth); - BufferAllocator.checkSize(newSize); - var untethered = control.allocateUntethered(this, (int) newSize); - ByteBuffer buffer = untethered.memory(); - buffer.order(order()); - - // Copy contents. - copyInto(0, buffer, 0, capacity()); - - // Release the old memory and install the new: - Drop drop = untethered.drop(); - disconnectDrop(drop); - attachNewBuffer(buffer, drop); - } - - private void disconnectDrop(Drop newDrop) { - var drop = (Drop) unsafeGetDrop(); - int roff = this.roff; - int woff = this.woff; - drop.drop(this); - unsafeSetDrop(new ArcDrop<>(newDrop)); - this.roff = roff; - this.woff = woff; - } - - private void attachNewBuffer(ByteBuffer buffer, Drop drop) { - base = buffer; - rmem = buffer; - wmem = buffer; - constBuffer = false; - drop.attach(this); - } - - @Override - public Buffer split(int splitOffset) { - if (splitOffset < 0) { - throw new IllegalArgumentException("The split offset cannot be negative: " + splitOffset + '.'); - } - if (capacity() < splitOffset) { - throw new IllegalArgumentException("The split offset cannot be greater than the buffer capacity, " + - "but the split offset was " + splitOffset + ", and capacity is " + capacity() + '.'); - } - if (!isAccessible()) { - throw attachTrace(bufferIsClosed(this)); - } - if (!isOwned()) { - throw attachTrace(new IllegalStateException("Cannot split a buffer that is not owned.")); - } - var drop = (ArcDrop) unsafeGetDrop(); - unsafeSetDrop(new ArcDrop<>(drop)); - var splitByteBuffer = bbslice(rmem, 0, splitOffset); - // TODO maybe incrementing the existing ArcDrop is enough; maybe we don't need to wrap it in another ArcDrop. - var splitBuffer = new NioBuffer(base, splitByteBuffer, control, new ArcDrop<>(drop.increment())); - splitBuffer.woff = Math.min(woff, splitOffset); - splitBuffer.roff = Math.min(roff, splitOffset); - ByteOrder order = order(); - splitBuffer.order(order); - boolean readOnly = readOnly(); - if (readOnly) { - splitBuffer.makeReadOnly(); - } - // Split preserves const-state. - splitBuffer.constBuffer = constBuffer; - rmem = bbslice(rmem, splitOffset, rmem.capacity() - splitOffset); - if (!readOnly) { - wmem = rmem; - } - woff = Math.max(woff, splitOffset) - splitOffset; - roff = Math.max(roff, splitOffset) - splitOffset; - order(order); - return splitBuffer; - } - - @Override - public void compact() { - if (!isOwned()) { - throw attachTrace(new IllegalStateException("Buffer must be owned in order to compact.")); - } - if (readOnly()) { - throw new BufferReadOnlyException("Buffer must be writable in order to compact, but was read-only."); - } - if (roff == 0) { - return; - } - rmem.limit(woff).position(roff).compact().clear(); - woff -= roff; - roff = 0; - } - - @Override - public int countComponents() { - return 1; - } - - @Override - public int countReadableComponents() { - return readableBytes() > 0? 1 : 0; - } - - @Override - public int countWritableComponents() { - return writableBytes() > 0? 1 : 0; - } - - // - @Override - public boolean hasReadableArray() { - return rmem.hasArray(); - } - - @Override - public byte[] readableArray() { - return rmem.array(); - } - - @Override - public int readableArrayOffset() { - return rmem.arrayOffset() + roff; - } - - @Override - public int readableArrayLength() { - return woff - roff; - } - - @Override - public long readableNativeAddress() { - return nativeAddress(); - } - - @Override - public ByteBuffer readableBuffer() { - return bbslice(rmem.asReadOnlyBuffer(), readerOffset(), readableBytes()).order(order()); - } - - @Override - public boolean hasWritableArray() { - return wmem.hasArray(); - } - - @Override - public byte[] writableArray() { - return wmem.array(); - } - - @Override - public int writableArrayOffset() { - return wmem.arrayOffset() + woff; - } - - @Override - public int writableArrayLength() { - return capacity() - woff; - } - - @Override - public long writableNativeAddress() { - return nativeAddress(); - } - - @Override - public ByteBuffer writableBuffer() { - return bbslice(wmem, writerOffset(), writableBytes()).order(order()); - } - // - - @Override - public int forEachReadable(int initialIndex, ReadableComponentProcessor processor) - throws E { - checkRead(readerOffset(), Math.max(1, readableBytes())); - return processor.process(initialIndex, this)? 1 : -1; - } - - @Override - public int forEachWritable(int initialIndex, WritableComponentProcessor processor) - throws E { - checkWrite(writerOffset(), Math.max(1, writableBytes())); - return processor.process(initialIndex, this)? 1 : -1; - } - - // - @Override - public byte readByte() { - checkRead(roff, Byte.BYTES); - var value = rmem.get(roff); - roff += Byte.BYTES; - return value; - } - - @Override - public byte getByte(int roff) { - checkGet(roff, Byte.BYTES); - return rmem.get(roff); - } - - @Override - public int readUnsignedByte() { - return readByte() & 0xFF; - } - - @Override - public int getUnsignedByte(int roff) { - return getByte(roff) & 0xFF; - } - - @Override - public Buffer writeByte(byte value) { - try { - wmem.put(woff, value); - woff += Byte.BYTES; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setByte(int woff, byte value) { - try { - wmem.put(woff, value); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer writeUnsignedByte(int value) { - try { - wmem.put(woff, (byte) (value & 0xFF)); - woff += Byte.BYTES; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setUnsignedByte(int woff, int value) { - try { - wmem.put(woff, (byte) (value & 0xFF)); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public char readChar() { - checkRead(roff, 2); - var value = rmem.getChar(roff); - roff += 2; - return value; - } - - @Override - public char getChar(int roff) { - checkGet(roff, 2); - return rmem.getChar(roff); - } - - @Override - public Buffer writeChar(char value) { - try { - wmem.putChar(woff, value); - woff += 2; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setChar(int woff, char value) { - try { - wmem.putChar(woff, value); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public short readShort() { - checkRead(roff, Short.BYTES); - var value = rmem.getShort(roff); - roff += 2; - return value; - } - - @Override - public short getShort(int roff) { - checkGet(roff, Short.BYTES); - return rmem.getShort(roff); - } - - @Override - public int readUnsignedShort() { - checkRead(roff, Short.BYTES); - var value = rmem.getShort(roff) & 0xFFFF; - roff += 2; - return value; - } - - @Override - public int getUnsignedShort(int roff) { - checkGet(roff, Short.BYTES); - return rmem.getShort(roff) & 0xFFFF; - } - - @Override - public Buffer writeShort(short value) { - try { - wmem.putShort(woff, value); - woff += Short.BYTES; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setShort(int woff, short value) { - try { - wmem.putShort(woff, value); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer writeUnsignedShort(int value) { - try { - wmem.putShort(woff, (short) (value & 0xFFFF)); - woff += Short.BYTES; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setUnsignedShort(int woff, int value) { - try { - wmem.putShort(woff, (short) (value & 0xFFFF)); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public int readMedium() { - checkRead(roff, 3); - int value = order() == ByteOrder.BIG_ENDIAN? - rmem.get(roff) << 16 | - (rmem.get(roff + 1) & 0xFF) << 8 | - rmem.get(roff + 2) & 0xFF : - rmem.get(roff) & 0xFF | - (rmem.get(roff + 1) & 0xFF) << 8 | - rmem.get(roff + 2) << 16; - roff += 3; - return value; - } - - @Override - public int getMedium(int roff) { - checkGet(roff, 3); - return order() == ByteOrder.BIG_ENDIAN? - rmem.get(roff) << 16 | - (rmem.get(roff + 1) & 0xFF) << 8 | - rmem.get(roff + 2) & 0xFF : - rmem.get(roff) & 0xFF | - (rmem.get(roff + 1) & 0xFF) << 8 | - rmem.get(roff + 2) << 16; - } - - @Override - public int readUnsignedMedium() { - checkRead(roff, 3); - int value = order() == ByteOrder.BIG_ENDIAN? - (rmem.get(roff) << 16 | - (rmem.get(roff + 1) & 0xFF) << 8 | - rmem.get(roff + 2) & 0xFF) & 0xFFFFFF : - (rmem.get(roff) & 0xFF | - (rmem.get(roff + 1) & 0xFF) << 8 | - rmem.get(roff + 2) << 16) & 0xFFFFFF; - roff += 3; - return value; - } - - @Override - public int getUnsignedMedium(int roff) { - checkGet(roff, 3); - return order() == ByteOrder.BIG_ENDIAN? - (rmem.get(roff) << 16 | - (rmem.get(roff + 1) & 0xFF) << 8 | - rmem.get(roff + 2) & 0xFF) & 0xFFFFFF : - (rmem.get(roff) & 0xFF | - (rmem.get(roff + 1) & 0xFF) << 8 | - rmem.get(roff + 2) << 16) & 0xFFFFFF; - } - - @Override - public Buffer writeMedium(int value) { - checkWrite(woff, 3); - if (order() == ByteOrder.BIG_ENDIAN) { - wmem.put(woff, (byte) (value >> 16)); - wmem.put(woff + 1, (byte) (value >> 8 & 0xFF)); - wmem.put(woff + 2, (byte) (value & 0xFF)); - } else { - wmem.put(woff, (byte) (value & 0xFF)); - wmem.put(woff + 1, (byte) (value >> 8 & 0xFF)); - wmem.put(woff + 2, (byte) (value >> 16 & 0xFF)); - } - woff += 3; - return this; - } - - @Override - public Buffer setMedium(int woff, int value) { - checkSet(woff, 3); - if (order() == ByteOrder.BIG_ENDIAN) { - wmem.put(woff, (byte) (value >> 16)); - wmem.put(woff + 1, (byte) (value >> 8 & 0xFF)); - wmem.put(woff + 2, (byte) (value & 0xFF)); - } else { - wmem.put(woff, (byte) (value & 0xFF)); - wmem.put(woff + 1, (byte) (value >> 8 & 0xFF)); - wmem.put(woff + 2, (byte) (value >> 16 & 0xFF)); - } - return this; - } - - @Override - public Buffer writeUnsignedMedium(int value) { - checkWrite(woff, 3); - if (order() == ByteOrder.BIG_ENDIAN) { - wmem.put(woff, (byte) (value >> 16)); - wmem.put(woff + 1, (byte) (value >> 8 & 0xFF)); - wmem.put(woff + 2, (byte) (value & 0xFF)); - } else { - wmem.put(woff, (byte) (value & 0xFF)); - wmem.put(woff + 1, (byte) (value >> 8 & 0xFF)); - wmem.put(woff + 2, (byte) (value >> 16 & 0xFF)); - } - woff += 3; - return this; - } - - @Override - public Buffer setUnsignedMedium(int woff, int value) { - checkSet(woff, 3); - if (order() == ByteOrder.BIG_ENDIAN) { - wmem.put(woff, (byte) (value >> 16)); - wmem.put(woff + 1, (byte) (value >> 8 & 0xFF)); - wmem.put(woff + 2, (byte) (value & 0xFF)); - } else { - wmem.put(woff, (byte) (value & 0xFF)); - wmem.put(woff + 1, (byte) (value >> 8 & 0xFF)); - wmem.put(woff + 2, (byte) (value >> 16 & 0xFF)); - } - return this; - } - - @Override - public int readInt() { - checkRead(roff, Integer.BYTES); - var value = rmem.getInt(roff); - roff += Integer.BYTES; - return value; - } - - @Override - public int getInt(int roff) { - checkGet(roff, Integer.BYTES); - return rmem.getInt(roff); - } - - @Override - public long readUnsignedInt() { - checkRead(roff, Integer.BYTES); - var value = rmem.getInt(roff) & 0xFFFFFFFFL; - roff += Integer.BYTES; - return value; - } - - @Override - public long getUnsignedInt(int roff) { - checkGet(roff, Integer.BYTES); - return rmem.getInt(roff) & 0xFFFFFFFFL; - } - - @Override - public Buffer writeInt(int value) { - try { - wmem.putInt(woff, value); - woff += Integer.BYTES; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setInt(int woff, int value) { - try { - wmem.putInt(woff, value); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, this.woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer writeUnsignedInt(long value) { - try { - wmem.putInt(woff, (int) (value & 0xFFFFFFFFL)); - woff += Integer.BYTES; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setUnsignedInt(int woff, long value) { - try { - wmem.putInt(woff, (int) (value & 0xFFFFFFFFL)); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, this.woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public float readFloat() { - checkRead(roff, Float.BYTES); - var value = rmem.getFloat(roff); - roff += Float.BYTES; - return value; - } - - @Override - public float getFloat(int roff) { - checkGet(roff, Float.BYTES); - return rmem.getFloat(roff); - } - - @Override - public Buffer writeFloat(float value) { - try { - wmem.putFloat(woff, value); - woff += Float.BYTES; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setFloat(int woff, float value) { - try { - wmem.putFloat(woff, value); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public long readLong() { - checkRead(roff, Long.BYTES); - var value = rmem.getLong(roff); - roff += Long.BYTES; - return value; - } - - @Override - public long getLong(int roff) { - checkGet(roff, Long.BYTES); - return rmem.getLong(roff); - } - - @Override - public Buffer writeLong(long value) { - try { - wmem.putLong(woff, value); - woff += Long.BYTES; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setLong(int woff, long value) { - try { - wmem.putLong(woff, value); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public double readDouble() { - checkRead(roff, Double.BYTES); - var value = rmem.getDouble(roff); - roff += Double.BYTES; - return value; - } - - @Override - public double getDouble(int roff) { - checkGet(roff, Double.BYTES); - return rmem.getDouble(roff); - } - - @Override - public Buffer writeDouble(double value) { - try { - wmem.putDouble(woff, value); - woff += Double.BYTES; - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - - @Override - public Buffer setDouble(int woff, double value) { - try { - wmem.putDouble(woff, value); - return this; - } catch (IndexOutOfBoundsException e) { - throw checkWriteState(e, woff); - } catch (ReadOnlyBufferException e) { - throw bufferIsReadOnly(this); - } - } - // - - @Override - protected Owned prepareSend() { - var order = order(); - var roff = this.roff; - var woff = this.woff; - var readOnly = readOnly(); - var isConst = constBuffer; - ByteBuffer base = this.base; - ByteBuffer rmem = this.rmem; - makeInaccessible(); - return new Owned() { - @Override - public NioBuffer transferOwnership(Drop drop) { - NioBuffer copy = new NioBuffer(base, rmem, control, drop); - copy.order(order); - copy.roff = roff; - copy.woff = woff; - if (readOnly) { - copy.makeReadOnly(); - } - copy.constBuffer = isConst; - return copy; - } - }; - } - - void makeInaccessible() { - base = CLOSED_BUFFER; - rmem = CLOSED_BUFFER; - wmem = CLOSED_BUFFER; - roff = 0; - woff = 0; - } - - @Override - public boolean isOwned() { - return super.isOwned() && ((ArcDrop) unsafeGetDrop()).isOwned(); - } - - @Override - public int countBorrows() { - return super.countBorrows() + ((ArcDrop) unsafeGetDrop()).countBorrows(); - } - - private void checkRead(int index, int size) { - if (index < 0 || woff < index + size) { - throw readAccessCheckException(index); - } - } - - private void checkGet(int index, int size) { - if (index < 0 || capacity() < index + size) { - throw readAccessCheckException(index); - } - } - - private void checkWrite(int index, int size) { - if (index < roff || wmem.capacity() < index + size) { - throw writeAccessCheckException(index); - } - } - - private void checkSet(int index, int size) { - if (index < 0 || wmem.capacity() < index + size) { - throw writeAccessCheckException(index); - } - } - - private RuntimeException checkWriteState(IndexOutOfBoundsException ioobe, int offset) { - if (rmem == CLOSED_BUFFER) { - return bufferIsClosed(this); - } - if (wmem != rmem) { - return bufferIsReadOnly(this); - } - - IndexOutOfBoundsException exception = outOfBounds(offset); - exception.addSuppressed(ioobe); - return exception; - } - - private RuntimeException readAccessCheckException(int index) { - if (rmem == CLOSED_BUFFER) { - throw bufferIsClosed(this); - } - return outOfBounds(index); - } - - private RuntimeException writeAccessCheckException(int index) { - if (rmem == CLOSED_BUFFER) { - throw bufferIsClosed(this); - } - if (wmem != rmem) { - return bufferIsReadOnly(this); - } - return outOfBounds(index); - } - - private IndexOutOfBoundsException outOfBounds(int index) { - return new IndexOutOfBoundsException( - "Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " + - rmem.capacity() + "]."); - } - - ByteBuffer recoverable() { - return base; - } - - // - private ByteBufAdaptor adaptor; - @Override - public ByteBuf asByteBuf() { - ByteBufAdaptor bba = adaptor; - if (bba == null) { - ByteBufAllocatorAdaptor alloc = new ByteBufAllocatorAdaptor( - BufferAllocator.heap(), BufferAllocator.direct()); - return adaptor = new ByteBufAdaptor(alloc, this); - } - return bba; - } - - @Override - public int refCnt() { - return isAccessible()? 1 + countBorrows() : 0; - } - - @Override - public ReferenceCounted retain() { - return retain(1); - } - - @Override - public ReferenceCounted retain(int increment) { - for (int i = 0; i < increment; i++) { - acquire(); - } - return this; - } - - @Override - public ReferenceCounted touch() { - return this; - } - - @Override - public ReferenceCounted touch(Object hint) { - return this; - } - - @Override - public boolean release() { - return release(1); - } - - @Override - public boolean release(int decrement) { - int refCount = 1 + countBorrows(); - if (!isAccessible() || decrement > refCount) { - throw new IllegalReferenceCountException(refCount, -decrement); - } - for (int i = 0; i < decrement; i++) { - try { - close(); - } catch (RuntimeException e) { - throw new IllegalReferenceCountException(e); - } - } - return !isAccessible(); - } - // -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/package-info.java deleted file mode 100644 index b49f818..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/bytebuffer/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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. - */ - -/** - * Safe ByteBuffer based implementation. - */ -package io.netty.buffer.api.bytebuffer; diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/ArcDrop.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/ArcDrop.java deleted file mode 100644 index b2acd10..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/internal/ArcDrop.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.internal; - -import io.netty.buffer.api.Drop; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; - -public final class ArcDrop implements Drop { - private static final VarHandle COUNT; - static { - try { - COUNT = MethodHandles.lookup().findVarHandle(ArcDrop.class, "count", int.class); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } - } - - private final Drop delegate; - @SuppressWarnings("FieldMayBeFinal") - private volatile int count; - - public ArcDrop(Drop delegate) { - this.delegate = delegate; - count = 1; - } - - public static Drop wrap(Drop drop) { - if (drop.getClass() == ArcDrop.class) { - return drop; - } - return new ArcDrop(drop); - } - - public static Drop acquire(Drop drop) { - if (drop.getClass() == ArcDrop.class) { - ((ArcDrop) drop).increment(); - return drop; - } - return new ArcDrop(drop); - } - - public ArcDrop increment() { - int c; - do { - c = count; - checkValidState(c); - } while (!COUNT.compareAndSet(this, c, c + 1)); - return this; - } - - @Override - public void drop(T obj) { - int c; - int n; - do { - c = count; - n = c - 1; - checkValidState(c); - } while (!COUNT.compareAndSet(this, c, n)); - if (n == 0) { - delegate.drop(obj); - } - } - - @Override - public void attach(T obj) { - delegate.attach(obj); - } - - public boolean isOwned() { - return count <= 1; - } - - public int countBorrows() { - return count - 1; - } - - public Drop unwrap() { - return delegate; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder() - .append("ArcDrop@") - .append(Integer.toHexString(System.identityHashCode(this))) - .append('(').append(count).append(", "); - Drop drop = this; - while ((drop = ((ArcDrop) drop).unwrap()) instanceof ArcDrop) { - builder.append(((ArcDrop) drop).count).append(", "); - } - return builder.append(drop).append(')').toString(); - } - - private static void checkValidState(int count) { - if (count == 0) { - throw new IllegalStateException("Underlying resources have already been freed."); - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/CleanerDrop.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/CleanerDrop.java deleted file mode 100644 index 75eae0c..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/internal/CleanerDrop.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.internal; - -import io.netty.buffer.api.Drop; - -import java.lang.ref.Cleaner; -import java.util.concurrent.atomic.AtomicReference; - -/** - * A drop implementation that delegates to another drop instance, either when called directly, or when it becomes - * cleanable. This ensures that objects are dropped even if they leak. - */ -public final class CleanerDrop implements Drop { - private Cleaner.Cleanable cleanable; - private GatedRunner runner; - - /** - * Wrap the given drop instance, and produce a new drop instance that will also call the delegate drop instance if - * it becomes cleanable. - */ - public static Drop wrap(Drop drop) { - CleanerDrop cleanerDrop = new CleanerDrop<>(); - GatedRunner runner = new GatedRunner<>(drop); - cleanerDrop.cleanable = Statics.CLEANER.register(cleanerDrop, runner); - cleanerDrop.runner = runner; - return cleanerDrop; - } - - private CleanerDrop() { - } - - @Override - public void attach(T obj) { - runner.set(obj); - runner.drop.attach(obj); - } - - @Override - public void drop(T obj) { - attach(obj); - cleanable.clean(); - } - - @Override - public String toString() { - return "CleanerDrop(" + runner.drop + ')'; - } - - private static final class GatedRunner extends AtomicReference implements Runnable { - private static final long serialVersionUID = 2685535951915798850L; - final Drop drop; - - private GatedRunner(Drop drop) { - this.drop = drop; - } - - @Override - public void run() { - T obj = getAndSet(null); // Make absolutely sure we only delegate once. - if (obj != null) { - drop.drop(obj); - } - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/LifecycleTracer.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/LifecycleTracer.java deleted file mode 100644 index 4dace3a..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/internal/LifecycleTracer.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.internal; - -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.Owned; -import io.netty.buffer.api.Resource; - -import java.util.ArrayDeque; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Stream; - -public abstract class LifecycleTracer { - public static LifecycleTracer get() { - if (Trace.TRACE_LIFECYCLE_DEPTH == 0) { - return NoOpTracer.INSTANCE; - } - StackTracer stackTracer = new StackTracer(); - stackTracer.addTrace(StackTracer.WALKER.walk(new Trace("allocate", 0))); - return stackTracer; - } - - public abstract void acquire(int acquires); - - public abstract void drop(int acquires); - - public abstract void close(int acquires); - - public abstract , T extends ResourceSupport> Owned send(Owned send, int acquires); - - public abstract E attachTrace(E throwable); - - private static final class NoOpTracer extends LifecycleTracer { - private static final NoOpTracer INSTANCE = new NoOpTracer(); - - @Override - public void acquire(int acquires) { - } - - @Override - public void drop(int acquires) { - } - - @Override - public void close(int acquires) { - } - - @Override - public , T extends ResourceSupport> Owned send(Owned send, int acquires) { - return send; - } - - @Override - public E attachTrace(E throwable) { - return throwable; - } - } - - private static final class StackTracer extends LifecycleTracer { - private static final int MAX_TRACE_POINTS = Math.min(Integer.getInteger("MAX_TRACE_POINTS", 50), 1000); - private static final StackWalker WALKER; - static { - int depth = Trace.TRACE_LIFECYCLE_DEPTH; - WALKER = depth > 0 ? StackWalker.getInstance(Set.of(), depth + 2) : null; - } - - private final ArrayDeque traces = new ArrayDeque<>(); - private boolean dropped; - - @Override - public void acquire(int acquires) { - Trace trace = WALKER.walk(new Trace("acquire", acquires)); - addTrace(trace); - } - - void addTrace(Trace trace) { - synchronized (traces) { - if (traces.size() == MAX_TRACE_POINTS) { - traces.pollFirst(); - } - traces.addLast(trace); - } - } - - @Override - public void drop(int acquires) { - dropped = true; - addTrace(WALKER.walk(new Trace("drop", acquires))); - } - - @Override - public void close(int acquires) { - if (!dropped) { - addTrace(WALKER.walk(new Trace("close", acquires))); - } - } - - @Override - public , T extends ResourceSupport> Owned send(Owned send, int acquires) { - Trace sendTrace = new Trace("send", acquires); - sendTrace.sent = true; - addTrace(WALKER.walk(sendTrace)); - return new Owned() { - @Override - public T transferOwnership(Drop drop) { - sendTrace.received = WALKER.walk(new Trace("received", acquires)); - return send.transferOwnership(drop); - } - }; - } - - @Override - public E attachTrace(E throwable) { - synchronized (traces) { - long timestamp = System.nanoTime(); - for (Trace trace : traces) { - trace.attach(throwable, timestamp); - } - } - return throwable; - } - } - - private static final class Trace implements Function, Trace> { - private static final int TRACE_LIFECYCLE_DEPTH; - static { - int traceDefault = 0; - //noinspection AssertWithSideEffects - assert (traceDefault = 10) > 0; - TRACE_LIFECYCLE_DEPTH = Math.max(Integer.getInteger("TRACE_LIFECYCLE_DEPTH", traceDefault), 0); - } - - final String name; - final int acquires; - final long timestamp; - boolean sent; - volatile Trace received; - StackWalker.StackFrame[] frames; - - Trace(String name, int acquires) { - this.name = name; - this.acquires = acquires; - timestamp = System.nanoTime(); - } - - @Override - public Trace apply(Stream frames) { - this.frames = frames.limit(TRACE_LIFECYCLE_DEPTH + 1).toArray(StackWalker.StackFrame[]::new); - return this; - } - - public void attach(E throwable, long timestamp) { - Trace recv = received; - String message = sent && recv == null ? name + " (sent but not received)" : name; - message += " (current acquires = " + acquires + ") T" + (this.timestamp - timestamp) / 1000 + "µs."; - Traceback exception = new Traceback(message); - StackTraceElement[] stackTrace = new StackTraceElement[frames.length]; - for (int i = 0; i < frames.length; i++) { - stackTrace[i] = frames[i].toStackTraceElement(); - } - exception.setStackTrace(stackTrace); - if (recv != null) { - recv.attach(exception, timestamp); - } - throwable.addSuppressed(exception); - } - } - - private static final class Traceback extends Throwable { - private static final long serialVersionUID = 941453986194634605L; - - Traceback(String message) { - super(message); - } - - @Override - public synchronized Throwable fillInStackTrace() { - return this; - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/MemoryManagersOverride.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/MemoryManagersOverride.java deleted file mode 100644 index e4b0255..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/internal/MemoryManagersOverride.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.internal; - -import io.netty.buffer.api.MemoryManagers; -import io.netty.buffer.api.bytebuffer.ByteBufferMemoryManagers; - -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; - -public final class MemoryManagersOverride { - private static final MemoryManagers DEFAULT = new ByteBufferMemoryManagers(); - private static final AtomicInteger OVERRIDES_AVAILABLE = new AtomicInteger(); - private static final Map OVERRIDES = Collections.synchronizedMap(new IdentityHashMap<>()); - - private MemoryManagersOverride() { - } - - public static MemoryManagers getManagers() { - if (OVERRIDES_AVAILABLE.get() > 0) { - return OVERRIDES.getOrDefault(Thread.currentThread(), DEFAULT); - } - return DEFAULT; - } - - public static T using(MemoryManagers managers, Supplier supplier) { - Thread thread = Thread.currentThread(); - OVERRIDES.put(thread, managers); - OVERRIDES_AVAILABLE.incrementAndGet(); - try { - return supplier.get(); - } finally { - OVERRIDES_AVAILABLE.decrementAndGet(); - OVERRIDES.remove(thread); - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/ResourceSupport.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/ResourceSupport.java deleted file mode 100644 index 6def829..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/internal/ResourceSupport.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.internal; - -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.Owned; -import io.netty.buffer.api.Resource; -import io.netty.buffer.api.Send; - -import java.util.Objects; - -/** - * Internal support class for resources. - * - * @param The public interface for the resource. - * @param The concrete implementation of the resource. - */ -public abstract class ResourceSupport, T extends ResourceSupport> implements Resource { - private int acquires; // Closed if negative. - private Drop drop; - private final LifecycleTracer tracer; - - protected ResourceSupport(Drop drop) { - this.drop = drop; - tracer = LifecycleTracer.get(); - } - - /** - * Encapsulation bypass for calling {@link #acquire()} on the given object. - *

- * Note: this {@code acquire} method does not check the type of the return value from acquire at compile time. - * The type is instead checked at runtime, and will cause a {@link ClassCastException} to be thrown if done - * incorrectly. - * - * @param obj The object we wish to acquire (increment reference count) on. - * @param The type of the acquired object, given by target-typing. - * @return The acquired object. - */ - @SuppressWarnings("unchecked") - static T acquire(ResourceSupport obj) { - return (T) obj.acquire(); - } - - /** - * Increment the reference count. - *

- * Note, this method is not thread-safe because Resources are meant to thread-confined. - * - * @return This {@link Resource} instance. - */ - protected final I acquire() { - if (acquires < 0) { - throw attachTrace(createResourceClosedException()); - } - if (acquires == Integer.MAX_VALUE) { - throw new IllegalStateException("Cannot acquire more references; counter would overflow."); - } - acquires++; - tracer.acquire(acquires); - return self(); - } - - protected abstract RuntimeException createResourceClosedException(); - - /** - * Decrement the reference count, and despose of the resource if the last reference is closed. - *

- * Note, this method is not thread-safe because Resources are meant to be thread-confined. - * - * @throws IllegalStateException If this Resource has already been closed. - */ - @Override - public final void close() { - if (acquires == -1) { - throw attachTrace(new IllegalStateException("Double-free: Resource already closed and dropped.")); - } - if (acquires == 0) { - tracer.drop(acquires); - drop.drop(impl()); - } - acquires--; - tracer.close(acquires); - } - - /** - * Send this Resource instance to another Thread, transferring the ownership to the recipient. - * This method can be used when the receiving thread is not known up front. - *

- * This instance immediately becomes inaccessible, and all attempts at accessing this resource will throw. - * Calling {@link #close()} will have no effect, so this method is safe to call within a try-with-resources - * statement. - * - * @throws IllegalStateException if this object has any outstanding acquires; that is, if this object has been - * {@link #acquire() acquired} more times than it has been {@link #close() closed}. - */ - @Override - public final Send send() { - if (acquires < 0) { - throw attachTrace(createResourceClosedException()); - } - if (!isOwned()) { - throw notSendableException(); - } - var owned = tracer.send(prepareSend(), acquires); - acquires = -2; // Close without dropping. This also ignore future double-free attempts. - return new TransferSend(owned, drop, getClass()); - } - - /** - * Attach a trace of the life-cycle of this object as suppressed exceptions to the given throwable. - * - * @param throwable The throwable to attach a life-cycle trace to. - * @param The concrete exception type. - * @return The given exception, which can then be thrown. - */ - protected E attachTrace(E throwable) { - return tracer.attachTrace(throwable); - } - - /** - * Create an {@link IllegalStateException} with a custom message, tailored to this particular - * {@link Resource} instance, for when the object cannot be sent for some reason. - * @return An {@link IllegalStateException} to be thrown when this object cannot be sent. - */ - protected IllegalStateException notSendableException() { - return new IllegalStateException( - "Cannot send() a reference counted object with " + countBorrows() + " borrows: " + this + '.'); - } - - /** - * Encapsulation bypass to call {@link #isOwned()} on the given object. - * - * @param obj The object to query the ownership state on. - * @return {@code true} if the given object is owned, otherwise {@code false}. - */ - static boolean isOwned(ResourceSupport obj) { - return obj.isOwned(); - } - - /** - * Query if this object is in an "owned" state, which means no other references have been - * {@linkplain #acquire() acquired} to it. - * - * This would usually be the case, since there are no public methods for acquiring references to these objects. - * - * @return {@code true} if this object is in an owned state, otherwise {@code false}. - */ - protected boolean isOwned() { - return acquires == 0; - } - - /** - * Encapsulation bypass to call {@link #countBorrows()} on the given object. - * - * @param obj The object to count borrows on. - * @return The number of borrows, or outstanding {@linkplain #acquire() acquires}, if any, of the given object. - */ - static int countBorrows(ResourceSupport obj) { - return obj.countBorrows(); - } - - /** - * Count the number of borrows of this object. - * Note that even if the number of borrows is {@code 0}, this object might not be {@linkplain #isOwned() owned} - * because there could be other restrictions involved in ownership. - * - * @return The number of borrows, if any, of this object. - */ - protected int countBorrows() { - return Math.max(acquires, 0); - } - - @Override - public boolean isAccessible() { - return acquires >= 0; - } - - /** - * Prepare this instance for ownsership transfer. This method is called from {@link #send()} in the sending thread. - * This method should put this resource in a deactivated state where it is no longer accessible from the currently - * owning thread. - * In this state, the resource instance should only allow a call to {@link Owned#transferOwnership(Drop)} in the - * recipient thread. - * - * @return This resource instance in a deactivated state. - */ - protected abstract Owned prepareSend(); - - /** - * Get access to the underlying {@link Drop} object. - * This method is unsafe because it open the possibility of bypassing and overriding resource lifetimes. - * - * @return The {@link Drop} object used by this reference counted object. - */ - protected Drop unsafeGetDrop() { - return drop; - } - - /** - * Replace the current underlying {@link Drop} object with the given one. - * This method is unsafe because it open the possibility of bypassing and overring resource lifetimes. - * - * @param replacement The new {@link Drop} object to use instead of the current one. - */ - protected void unsafeSetDrop(Drop replacement) { - drop = Objects.requireNonNull(replacement, "Replacement drop cannot be null."); - } - - @SuppressWarnings("unchecked") - private I self() { - return (I) this; - } - - @SuppressWarnings("unchecked") - private T impl() { - return (T) this; - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java deleted file mode 100644 index ab01fc2..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.internal; - -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.BufferClosedException; -import io.netty.buffer.api.BufferReadOnlyException; -import io.netty.buffer.api.Drop; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; -import java.lang.invoke.VarHandle; -import java.lang.ref.Cleaner; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.concurrent.atomic.LongAdder; - -public interface Statics { - LongAdder MEM_USAGE_NATIVE = new LongAdder(); - Cleaner CLEANER = Cleaner.create(); - Drop NO_OP_DROP = new Drop() { - @Override - public void drop(Buffer obj) { - } - - @Override - public String toString() { - return "NO_OP_DROP"; - } - }; - MethodHandle BB_SLICE_OFFSETS = getByteBufferSliceOffsetsMethodHandle(); - MethodHandle BB_PUT_OFFSETS = getByteBufferPutOffsetsMethodHandle(); - - static MethodHandle getByteBufferSliceOffsetsMethodHandle() { - try { - Lookup lookup = MethodHandles.lookup(); - MethodType type = MethodType.methodType(ByteBuffer.class, int.class, int.class); - return lookup.findVirtual(ByteBuffer.class, "slice", type); - } catch (Exception ignore) { - return null; - } - } - - @SuppressWarnings("JavaLangInvokeHandleSignature") - static MethodHandle getByteBufferPutOffsetsMethodHandle() { - try { - Lookup lookup = MethodHandles.lookup(); - MethodType type = MethodType.methodType(ByteBuffer.class, int.class, ByteBuffer.class, int.class, int.class); - return lookup.findVirtual(ByteBuffer.class, "put", type); - } catch (Exception ignore) { - return null; - } - } - - @SuppressWarnings({"unchecked", "unused"}) - static Drop noOpDrop() { - return (Drop) NO_OP_DROP; - } - - static VarHandle findVarHandle(Lookup lookup, Class recv, String name, Class type) { - try { - return lookup.findVarHandle(recv, name, type); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } - } - - @SuppressWarnings("unchecked") - static Drop convert(Drop drop) { - return (Drop) drop; - } - - static void copyToViaReverseCursor(Buffer src, int srcPos, Buffer dest, int destPos, int length) { - // Iterate in reverse to account for src and dest buffer overlap. - var itr = src.openReverseCursor(srcPos + length - 1, length); - ByteOrder prevOrder = dest.order(); - // We read longs in BE, in reverse, so they need to be flipped for writing. - dest.order(ByteOrder.LITTLE_ENDIAN); - try { - while (itr.readLong()) { - long val = itr.getLong(); - length -= Long.BYTES; - dest.setLong(destPos + length, val); - } - while (itr.readByte()) { - dest.setByte(destPos + --length, itr.getByte()); - } - } finally { - dest.order(prevOrder); - } - } - - /** - * The ByteBuffer slice-with-offset-and-length method is only available from Java 13 and onwards, but we need to - * support Java 11. - */ - static ByteBuffer bbslice(ByteBuffer buffer, int fromOffset, int length) { - if (BB_SLICE_OFFSETS != null) { - return bbsliceJdk13(buffer, fromOffset, length); - } - return bbsliceFallback(buffer, fromOffset, length); - } - - private static ByteBuffer bbsliceJdk13(ByteBuffer buffer, int fromOffset, int length) { - try { - return (ByteBuffer) BB_SLICE_OFFSETS.invokeExact(buffer, fromOffset, length); - } catch (RuntimeException re) { - throw re; - } catch (Throwable throwable) { - throw new LinkageError("Unexpected exception from ByteBuffer.slice(int,int).", throwable); - } - } - - private static ByteBuffer bbsliceFallback(ByteBuffer buffer, int fromOffset, int length) { - if (fromOffset < 0) { - throw new IndexOutOfBoundsException("The fromOffset must be positive: " + fromOffset + '.'); - } - int newLimit = fromOffset + length; - if (newLimit > buffer.capacity()) { - throw new IndexOutOfBoundsException( - "The limit of " + newLimit + " would be greater than capacity: " + buffer.capacity() + '.'); - } - try { - return buffer.position(fromOffset).limit(newLimit).slice(); - } finally { - buffer.clear(); - } - } - - /** - * The ByteBuffer put-buffer-with-offset-and-length method is not available in Java 11. - */ - static void bbput(ByteBuffer dest, int destPos, ByteBuffer src, int srcPos, int length) { - if (BB_PUT_OFFSETS != null) { - bbputJdk16(dest, destPos, src, srcPos, length); - } else { - bbputFallback(dest, destPos, src, srcPos, length); - } - } - - private static void bbputJdk16(ByteBuffer dest, int destPos, ByteBuffer src, int srcPos, int length) { - try { - @SuppressWarnings("unused") // We need to cast the return type in order to invokeExact. - ByteBuffer ignore = (ByteBuffer) BB_PUT_OFFSETS.invokeExact(dest, destPos, src, srcPos, length); - } catch (RuntimeException re) { - throw re; - } catch (Throwable throwable) { - throw new LinkageError("Unexpected exception from ByteBuffer.put(int,ByteBuffer,int,int).", throwable); - } - } - - private static void bbputFallback(ByteBuffer dest, int destPos, ByteBuffer src, int srcPos, int length) { - dest.position(destPos).put(bbslice(src, srcPos, length)); - } - - static BufferClosedException bufferIsClosed(Buffer buffer) { - return new BufferClosedException("This buffer is closed: " + buffer); - } - - static BufferReadOnlyException bufferIsReadOnly(Buffer buffer) { - return new BufferReadOnlyException("This buffer is read-only: " + buffer); - } - - static T acquire(ResourceSupport obj) { - return ResourceSupport.acquire(obj); - } - - static boolean isOwned(ResourceSupport obj) { - return ResourceSupport.isOwned(obj); - } - - static int countBorrows(ResourceSupport obj) { - return ResourceSupport.countBorrows(obj); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/TransferSend.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/TransferSend.java deleted file mode 100644 index 0e806a1..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/internal/TransferSend.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.internal; - -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.Owned; -import io.netty.buffer.api.Resource; -import io.netty.buffer.api.Send; - -import java.lang.invoke.VarHandle; - -import static java.lang.invoke.MethodHandles.lookup; - -public class TransferSend, T extends ResourceSupport> implements Send { - private static final VarHandle RECEIVED = Statics.findVarHandle(lookup(), TransferSend.class, "received", boolean.class); - private final Owned outgoing; - private final Drop drop; - private final Class concreteType; - @SuppressWarnings("unused") - private volatile boolean received; // Accessed via VarHandle - - public TransferSend(Owned outgoing, Drop drop, Class concreteType) { - this.outgoing = outgoing; - this.drop = drop; - this.concreteType = concreteType; - } - - @SuppressWarnings("unchecked") - @Override - public I receive() { - gateReception(); - var copy = outgoing.transferOwnership(drop); - drop.attach(copy); - return (I) copy; - } - - private void gateReception() { - if ((boolean) RECEIVED.getAndSet(this, true)) { - throw new IllegalStateException("This object has already been received."); - } - } - - @Override - public boolean referentIsInstanceOf(Class cls) { - return cls.isAssignableFrom(concreteType); - } - - @Override - public void discard() { - if (!(boolean) RECEIVED.getAndSet(this, true)) { - var copy = outgoing.transferOwnership(drop); - drop.attach(copy); - copy.close(); - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/package-info.java deleted file mode 100644 index dcf90af..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/internal/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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. - */ - -/** - * Internal implementation details that can be shared among Buffer implementations. - */ -package io.netty.buffer.api.internal; diff --git a/buffer-api/src/main/java/io/netty/buffer/api/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/package-info.java deleted file mode 100644 index e38b44c..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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. - */ - -/** - * Incubating {@code Buffer} API, as a proposed alternative to {@code ByteBuf}. - */ -package io.netty.buffer.api; diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetric.java deleted file mode 100644 index eeaa676..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetric.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.BufferAllocator; - -public interface BufferAllocatorMetric { - /** - * Returns the number of bytes of heap memory used by a {@link BufferAllocator} or {@code -1} if unknown. - */ - long usedMemory(); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetricProvider.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetricProvider.java deleted file mode 100644 index 1b19e73..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/BufferAllocatorMetricProvider.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.BufferAllocator; - -public interface BufferAllocatorMetricProvider { - - /** - * Returns a {@link BufferAllocatorMetric} for a {@link BufferAllocator}. - */ - BufferAllocatorMetric metric(); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/LongLongHashMap.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/LongLongHashMap.java deleted file mode 100644 index 35e3a3b..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/LongLongHashMap.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -/** - * Internal primitive map implementation that is specifically optimised for the runs availability map use case in - * {@link PoolChunk}. - */ -final class LongLongHashMap { - private static final int MASK_TEMPLATE = ~1; - private int mask; - private long[] array; - private int maxProbe; - private long zeroVal; - private final long emptyVal; - - LongLongHashMap(long emptyVal) { - this.emptyVal = emptyVal; - zeroVal = emptyVal; - int initialSize = 32; - array = new long[initialSize]; - mask = initialSize - 1; - computeMaskAndProbe(); - } - - public long put(long key, long value) { - if (key == 0) { - long prev = zeroVal; - zeroVal = value; - return prev; - } - - for (;;) { - int index = index(key); - for (int i = 0; i < maxProbe; i++) { - long existing = array[index]; - if (existing == key || existing == 0) { - long prev = existing == 0? emptyVal : array[index + 1]; - array[index] = key; - array[index + 1] = value; - for (; i < maxProbe; i++) { // Nerf any existing misplaced entries. - index = index + 2 & mask; - if (array[index] == key) { - array[index] = 0; - prev = array[index + 1]; - break; - } - } - return prev; - } - index = index + 2 & mask; - } - expand(); // Grow array and re-hash. - } - } - - public void remove(long key) { - if (key == 0) { - zeroVal = emptyVal; - return; - } - int index = index(key); - for (int i = 0; i < maxProbe; i++) { - long existing = array[index]; - if (existing == key) { - array[index] = 0; - break; - } - index = index + 2 & mask; - } - } - - public long get(long key) { - if (key == 0) { - return zeroVal; - } - int index = index(key); - for (int i = 0; i < maxProbe; i++) { - long existing = array[index]; - if (existing == key) { - return array[index + 1]; - } - index = index + 2 & mask; - } - return emptyVal; - } - - private int index(long key) { - // Hash with murmur64, and mask. - key ^= key >>> 33; - key *= 0xff51afd7ed558ccdL; - key ^= key >>> 33; - key *= 0xc4ceb9fe1a85ec53L; - key ^= key >>> 33; - return (int) key & mask; - } - - private void expand() { - long[] prev = array; - array = new long[prev.length * 2]; - computeMaskAndProbe(); - for (int i = 0; i < prev.length; i += 2) { - long key = prev[i]; - if (key != 0) { - long val = prev[i + 1]; - put(key, val); - } - } - } - - private void computeMaskAndProbe() { - int length = array.length; - mask = length - 1 & MASK_TEMPLATE; - maxProbe = (int) Math.log(length); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/LongPriorityQueue.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/LongPriorityQueue.java deleted file mode 100644 index 2d9aa54..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/LongPriorityQueue.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import java.util.Arrays; - -/** - * Internal primitive priority queue, used by {@link PoolChunk}. - * The implementation is based on the binary heap, as described in Algorithms by Sedgewick and Wayne. - */ -final class LongPriorityQueue { - public static final int NO_VALUE = -1; - private long[] array = new long[9]; - private int size; - - public void offer(long handle) { - if (handle == NO_VALUE) { - throw new IllegalArgumentException("The NO_VALUE (" + NO_VALUE + ") cannot be added to the queue."); - } - size++; - if (size == array.length) { - // Grow queue capacity. - array = Arrays.copyOf(array, 1 + (array.length - 1) * 2); - } - array[size] = handle; - lift(size); - } - - public void remove(long value) { - for (int i = 1; i <= size; i++) { - if (array[i] == value) { - array[i] = array[size--]; - lift(i); - sink(i); - return; - } - } - } - - public long peek() { - if (size == 0) { - return NO_VALUE; - } - return array[1]; - } - - public long poll() { - if (size == 0) { - return NO_VALUE; - } - long val = array[1]; - array[1] = array[size]; - array[size] = 0; - size--; - sink(1); - return val; - } - - public boolean isEmpty() { - return size == 0; - } - - private void lift(int index) { - int parentIndex; - while (index > 1 && subord(parentIndex = index >> 1, index)) { - swap(index, parentIndex); - index = parentIndex; - } - } - - private void sink(int index) { - int child; - while ((child = index << 1) <= size) { - if (child < size && subord(child, child + 1)) { - child++; - } - if (!subord(index, child)) { - break; - } - swap(index, child); - index = child; - } - } - - private boolean subord(int a, int b) { - return array[a] > array[b]; - } - - private void swap(int a, int b) { - long value = array[a]; - array[a] = array[b]; - array[b] = value; - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArena.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArena.java deleted file mode 100644 index fa4cc90..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArena.java +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.AllocatorControl; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.MemoryManager; -import io.netty.util.internal.StringUtil; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.LongAdder; - -import static io.netty.buffer.api.pool.PoolChunk.isSubpage; -import static java.lang.Math.max; - -class PoolArena extends SizeClasses implements PoolArenaMetric, AllocatorControl { - private static final VarHandle SUBPAGE_ARRAY = MethodHandles.arrayElementVarHandle(PoolSubpage[].class); - enum SizeClass { - Small, - Normal - } - - final PooledBufferAllocator parent; - final MemoryManager manager; - - final int numSmallSubpagePools; - final int directMemoryCacheAlignment; - private final PoolSubpage[] smallSubpagePools; - - private final PoolChunkList q050; - private final PoolChunkList q025; - private final PoolChunkList q000; - private final PoolChunkList qInit; - private final PoolChunkList q075; - private final PoolChunkList q100; - - private final List chunkListMetrics; - - // Metrics for allocations and deallocations - private long allocationsNormal; - - // We need to use the LongAdder here as this is not guarded via synchronized block. - private final LongAdder allocationsSmall = new LongAdder(); - private final LongAdder allocationsHuge = new LongAdder(); - private final LongAdder activeBytesHuge = new LongAdder(); - - private long deallocationsSmall; - private long deallocationsNormal; - - // We need to use the LongAdder here as this is not guarded via synchronized block. - private final LongAdder deallocationsHuge = new LongAdder(); - - // Number of thread caches backed by this arena. - final AtomicInteger numThreadCaches = new AtomicInteger(); - - protected PoolArena(PooledBufferAllocator parent, MemoryManager manager, int pageSize, - int pageShifts, int chunkSize, int cacheAlignment) { - super(pageSize, pageShifts, chunkSize, cacheAlignment); - this.parent = parent; - this.manager = manager; - directMemoryCacheAlignment = cacheAlignment; - - numSmallSubpagePools = nSubpages; - smallSubpagePools = newSubpagePoolArray(numSmallSubpagePools); - - q100 = new PoolChunkList(this, null, 100, Integer.MAX_VALUE, chunkSize); - q075 = new PoolChunkList(this, q100, 75, 100, chunkSize); - q050 = new PoolChunkList(this, q075, 50, 100, chunkSize); - q025 = new PoolChunkList(this, q050, 25, 75, chunkSize); - q000 = new PoolChunkList(this, q025, 1, 50, chunkSize); - qInit = new PoolChunkList(this, q000, Integer.MIN_VALUE, 25, chunkSize); - - q100.prevList(q075); - q075.prevList(q050); - q050.prevList(q025); - q025.prevList(q000); - q000.prevList(null); - qInit.prevList(qInit); - - chunkListMetrics = List.of(qInit, q000, q025, q050, q075, q100); - } - - private static PoolSubpage newSubpagePoolHead() { - PoolSubpage head = new PoolSubpage(); - head.prev = head; - head.next = head; - return head; - } - - private static PoolSubpage[] newSubpagePoolArray(int size) { - return new PoolSubpage[size]; - } - - UntetheredMemory allocate(PooledAllocatorControl control, PoolThreadCache cache, int size) { - final int sizeIdx = size2SizeIdx(size); - - if (sizeIdx <= smallMaxSizeIdx) { - return tcacheAllocateSmall(control, cache, size, sizeIdx); - } else if (sizeIdx < nSizes) { - return tcacheAllocateNormal(control, cache, size, sizeIdx); - } else { - int normCapacity = directMemoryCacheAlignment > 0 - ? normalizeSize(size) : size; - // Huge allocations are never served via the cache so just call allocateHuge - return allocateHuge(normCapacity); - } - } - - private UntetheredMemory tcacheAllocateSmall(PooledAllocatorControl control, PoolThreadCache cache, final int size, - final int sizeIdx) { - UntetheredMemory memory = cache.allocateSmall(control, size, sizeIdx); - if (memory != null) { - // was able to allocate out of the cache so move on - return memory; - } - - /* - * Synchronize on the head. This is needed as {@link PoolChunk#allocateSubpage(int)} and - * {@link PoolChunk#free(long)} may modify the doubly linked list as well. - */ - PoolSubpage head = findSubpagePoolHead(sizeIdx); - final boolean needsNormalAllocation; - synchronized (head) { - final PoolSubpage s = head.next; - needsNormalAllocation = s == head; - if (!needsNormalAllocation) { - assert s.doNotDestroy && s.elemSize == sizeIdx2size(sizeIdx); - long handle = s.allocate(); - assert handle >= 0; - memory = s.chunk.allocateBufferWithSubpage(handle, size, cache, control); - } - } - - if (needsNormalAllocation) { - synchronized (this) { - memory = allocateNormal(size, sizeIdx, cache, control); - } - } - - incSmallAllocation(); - return memory; - } - - private UntetheredMemory tcacheAllocateNormal( - PooledAllocatorControl control, PoolThreadCache cache, int size, int sizeIdx) { - UntetheredMemory memory = cache.allocateNormal(this, control, size, sizeIdx); - if (memory != null) { - // was able to allocate out of the cache so move on - return memory; - } - synchronized (this) { - memory = allocateNormal(size, sizeIdx, cache, control); - allocationsNormal++; - } - return memory; - } - - // Method must be called inside synchronized(this) { ... } block - private UntetheredMemory allocateNormal( - int size, int sizeIdx, PoolThreadCache threadCache, PooledAllocatorControl control) { - UntetheredMemory memory = q050.allocate(size, sizeIdx, threadCache, control); - if (memory != null) { - return memory; - } - memory = q025.allocate(size, sizeIdx, threadCache, control); - if (memory != null) { - return memory; - } - memory = q000.allocate(size, sizeIdx, threadCache, control); - if (memory != null) { - return memory; - } - memory = qInit.allocate(size, sizeIdx, threadCache, control); - if (memory != null) { - return memory; - } - memory = q075.allocate(size, sizeIdx, threadCache, control); - if (memory != null) { - return memory; - } - - // Add a new chunk. - PoolChunk c = newChunk(pageSize, nPSizes, pageShifts, chunkSize); - memory = c.allocate(size, sizeIdx, threadCache, control); - assert memory != null; - qInit.add(c); - return memory; - } - - private void incSmallAllocation() { - allocationsSmall.increment(); - } - - private UntetheredMemory allocateHuge(int size) { - activeBytesHuge.add(size); - allocationsHuge.increment(); - return new UnpooledUnthetheredMemory(parent, manager, size); - } - - void free(PoolChunk chunk, long handle, int normCapacity, PoolThreadCache cache) { - SizeClass sizeClass = sizeClass(handle); - if (cache != null && cache.add(this, chunk, handle, normCapacity, sizeClass)) { - // cached so not free it. - return; - } - freeChunk(chunk, handle, normCapacity, sizeClass); - } - - private static SizeClass sizeClass(long handle) { - return isSubpage(handle) ? SizeClass.Small : SizeClass.Normal; - } - - void freeChunk(PoolChunk chunk, long handle, int normCapacity, SizeClass sizeClass) { - final boolean destroyChunk; - synchronized (this) { - if (sizeClass == SizeClass.Normal) { - ++deallocationsNormal; - } else if (sizeClass == SizeClass.Small) { - ++deallocationsSmall; - } else { - throw new AssertionError("Unexpected size class: " + sizeClass); - } - destroyChunk = !chunk.parent.free(chunk, handle, normCapacity); - } - if (destroyChunk) { - // destroyChunk not need to be called while holding the synchronized lock. - chunk.destroy(); - } - } - - PoolSubpage findSubpagePoolHead(int sizeIdx) { - PoolSubpage head = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(smallSubpagePools, sizeIdx); - if (head == null) { - head = newSubpagePoolHead(); - if (!SUBPAGE_ARRAY.compareAndSet(smallSubpagePools, sizeIdx, null, head)) { - // We lost the race. Read the winning value. - head = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(smallSubpagePools, sizeIdx); - } - } - return head; - } - - @Override - public UntetheredMemory allocateUntethered(Buffer originator, int size) { - throw new AssertionError("PoolChunk base buffers should never need to reallocate."); - } - - @Override - public void recoverMemory(Object memory) { - // This means we've lost all strong references to a PoolChunk. - // Probably means we don't need it anymore, so just free its memory. - manager.discardRecoverableMemory(memory); - } - - @Override - public int numThreadCaches() { - return numThreadCaches.get(); - } - - @Override - public int numSmallSubpages() { - return smallSubpagePools.length; - } - - @Override - public int numChunkLists() { - return chunkListMetrics.size(); - } - - @Override - public List smallSubpages() { - return subPageMetricList(smallSubpagePools); - } - - @Override - public List chunkLists() { - return chunkListMetrics; - } - - private static List subPageMetricList(PoolSubpage[] pages) { - List metrics = new ArrayList<>(); - for (int i = 0, len = pages.length; i < len; i++) { - PoolSubpage head = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(pages, i); - if (head == null || head.next == head) { - continue; - } - PoolSubpage s = head.next; - do { - metrics.add(s); - s = s.next; - } while (s != head); - } - return metrics; - } - - @Override - public long numAllocations() { - final long allocsNormal; - synchronized (this) { - allocsNormal = allocationsNormal; - } - - return allocationsSmall.longValue() + allocsNormal + allocationsHuge.longValue(); - } - - @Override - public long numSmallAllocations() { - return allocationsSmall.longValue(); - } - - @Override - public synchronized long numNormalAllocations() { - return allocationsNormal; - } - - @Override - public long numDeallocations() { - final long deallocs; - synchronized (this) { - deallocs = deallocationsSmall + deallocationsNormal; - } - return deallocs + deallocationsHuge.longValue(); - } - - @Override - public synchronized long numSmallDeallocations() { - return deallocationsSmall; - } - - @Override - public synchronized long numNormalDeallocations() { - return deallocationsNormal; - } - - @Override - public long numHugeAllocations() { - return allocationsHuge.longValue(); - } - - @Override - public long numHugeDeallocations() { - return deallocationsHuge.longValue(); - } - - @Override - public long numActiveAllocations() { - long val = allocationsSmall.longValue() + allocationsHuge.longValue() - - deallocationsHuge.longValue(); - synchronized (this) { - val += allocationsNormal - (deallocationsSmall + deallocationsNormal); - } - return max(val, 0); - } - - @Override - public long numActiveSmallAllocations() { - return max(numSmallAllocations() - numSmallDeallocations(), 0); - } - - @Override - public long numActiveNormalAllocations() { - final long val; - synchronized (this) { - val = allocationsNormal - deallocationsNormal; - } - return max(val, 0); - } - - @Override - public long numActiveHugeAllocations() { - return max(numHugeAllocations() - numHugeDeallocations(), 0); - } - - @Override - public long numActiveBytes() { - long val = activeBytesHuge.longValue(); - synchronized (this) { - for (int i = 0; i < chunkListMetrics.size(); i++) { - for (PoolChunkMetric m: chunkListMetrics.get(i)) { - val += m.chunkSize(); - } - } - } - return max(0, val); - } - - protected final PoolChunk newChunk(int pageSize, int maxPageIdx, int pageShifts, int chunkSize) { - return new PoolChunk(this, pageSize, pageShifts, chunkSize, maxPageIdx); - } - - @Override - public synchronized String toString() { - StringBuilder buf = new StringBuilder() - .append("Chunk(s) at 0~25%:") - .append(StringUtil.NEWLINE) - .append(qInit) - .append(StringUtil.NEWLINE) - .append("Chunk(s) at 0~50%:") - .append(StringUtil.NEWLINE) - .append(q000) - .append(StringUtil.NEWLINE) - .append("Chunk(s) at 25~75%:") - .append(StringUtil.NEWLINE) - .append(q025) - .append(StringUtil.NEWLINE) - .append("Chunk(s) at 50~100%:") - .append(StringUtil.NEWLINE) - .append(q050) - .append(StringUtil.NEWLINE) - .append("Chunk(s) at 75~100%:") - .append(StringUtil.NEWLINE) - .append(q075) - .append(StringUtil.NEWLINE) - .append("Chunk(s) at 100%:") - .append(StringUtil.NEWLINE) - .append(q100) - .append(StringUtil.NEWLINE) - .append("small subpages:"); - appendPoolSubPages(buf, smallSubpagePools); - buf.append(StringUtil.NEWLINE); - - return buf.toString(); - } - - private static void appendPoolSubPages(StringBuilder buf, PoolSubpage[] subpages) { - for (int i = 0; i < subpages.length; i ++) { - PoolSubpage head = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(subpages, i); - if (head == null || head.next == head) { - continue; - } - - buf.append(StringUtil.NEWLINE) - .append(i) - .append(": "); - PoolSubpage s = head.next; - do { - buf.append(s); - s = s.next; - } while (s != head); - } - } - - public void close() { - for (int i = 0, len = smallSubpagePools.length; i < len; i++) { - PoolSubpage page = (PoolSubpage) SUBPAGE_ARRAY.getVolatile(smallSubpagePools, i); - if (page != null) { - page.destroy(); - } - } - for (PoolChunkList list : new PoolChunkList[] {qInit, q000, q025, q050, q100}) { - list.destroy(); - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArenaMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArenaMetric.java deleted file mode 100644 index 754dd7d..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolArenaMetric.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import java.util.List; - -/** - * Expose metrics for an arena. - */ -public interface PoolArenaMetric extends SizeClassesMetric { - - /** - * Returns the number of thread caches backed by this arena. - */ - int numThreadCaches(); - - /** - * Returns the number of small sub-pages for the arena. - */ - int numSmallSubpages(); - - /** - * Returns the number of chunk lists for the arena. - */ - int numChunkLists(); - - /** - * Returns an unmodifiable {@link List} which holds {@link PoolSubpageMetric}s for small sub-pages. - */ - List smallSubpages(); - - /** - * Returns an unmodifiable {@link List} which holds {@link PoolChunkListMetric}s. - */ - List chunkLists(); - - /** - * Return the number of allocations done via the arena. This includes all sizes. - */ - long numAllocations(); - - /** - * Return the number of small allocations done via the arena. - */ - long numSmallAllocations(); - - /** - * Return the number of normal allocations done via the arena. - */ - long numNormalAllocations(); - - /** - * Return the number of huge allocations done via the arena. - */ - long numHugeAllocations(); - - /** - * Return the number of deallocations done via the arena. This includes all sizes. - */ - long numDeallocations(); - - /** - * Return the number of small deallocations done via the arena. - */ - long numSmallDeallocations(); - - /** - * Return the number of normal deallocations done via the arena. - */ - long numNormalDeallocations(); - - /** - * Return the number of huge deallocations done via the arena. - */ - long numHugeDeallocations(); - - /** - * Return the number of currently active allocations. - */ - long numActiveAllocations(); - - /** - * Return the number of currently active small allocations. - */ - long numActiveSmallAllocations(); - - /** - * Return the number of currently active normal allocations. - */ - long numActiveNormalAllocations(); - - /** - * Return the number of currently active huge allocations. - */ - long numActiveHugeAllocations(); - - /** - * Return the number of active bytes that are currently allocated by the arena. - */ - long numActiveBytes(); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunk.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunk.java deleted file mode 100644 index 7b98ade..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunk.java +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.internal.CleanerDrop; -import io.netty.buffer.api.AllocatorControl.UntetheredMemory; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.MemoryManager; -import io.netty.buffer.api.internal.ArcDrop; -import io.netty.buffer.api.internal.Statics; - -import java.util.PriorityQueue; - -/** - * Description of algorithm for PageRun/PoolSubpage allocation from PoolChunk - * - * Notation: The following terms are important to understand the code - * > page - a page is the smallest unit of memory chunk that can be allocated - * > run - a run is a collection of pages - * > chunk - a chunk is a collection of runs - * > in this code chunkSize = maxPages * pageSize - * - * To begin we allocate a byte array of size = chunkSize - * Whenever a ByteBuf of given size needs to be created we search for the first position - * in the byte array that has enough empty space to accommodate the requested size and - * return a (long) handle that encodes this offset information, (this memory segment is then - * marked as reserved, so it is always used by exactly one ByteBuf and no more) - * - * For simplicity all sizes are normalized according to {@link PoolArena#size2SizeIdx(int)} method. - * This ensures that when we request for memory segments of size > pageSize the normalizedCapacity - * equals the next nearest size in {@link SizeClasses}. - * - * - * A chunk has the following layout: - * - * /-----------------\ - * | run | - * | | - * | | - * |-----------------| - * | run | - * | | - * |-----------------| - * | unalloctated | - * | (freed) | - * | | - * |-----------------| - * | subpage | - * |-----------------| - * | unallocated | - * | (freed) | - * | ... | - * | ... | - * | ... | - * | | - * | | - * | | - * \-----------------/ - * - * - * handle: - * ------- - * a handle is a long number, the bit layout of a run looks like: - * - * oooooooo ooooooos ssssssss ssssssue bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb - * - * o: runOffset (page offset in the chunk), 15bit - * s: size (number of pages) of this run, 15bit - * u: isUsed?, 1bit - * e: isSubpage?, 1bit - * b: bitmapIdx of subpage, zero if it's not subpage, 32bit - * - * runsAvailMap: - * ------ - * a map which manages all runs (used and not in used). - * For each run, the first runOffset and last runOffset are stored in runsAvailMap. - * key: runOffset - * value: handle - * - * runsAvail: - * ---------- - * an array of {@link PriorityQueue}. - * Each queue manages same size of runs. - * Runs are sorted by offset, so that we always allocate runs with smaller offset. - * - * - * Algorithm: - * ---------- - * - * As we allocate runs, we update values stored in runsAvailMap and runsAvail so that the property is maintained. - * - * Initialization - - * In the beginning we store the initial run which is the whole chunk. - * The initial run: - * runOffset = 0 - * size = chunkSize - * isUsed = no - * isSubpage = no - * bitmapIdx = 0 - * - * - * Algorithm: [allocateRun(size)] - * ---------- - * 1) find the first avail run using in runsAvails according to size - * 2) if pages of run is larger than request pages then split it, and save the tailing run - * for later using - * - * Algorithm: [allocateSubpage(size)] - * ---------- - * 1) find a not full subpage according to size. - * if it already exists just return, otherwise allocate a new PoolSubpage and call init() - * note that this subpage object is added to subpagesPool in the PoolArena when we init() it - * 2) call subpage.allocate() - * - * Algorithm: [free(handle, length, nioBuffer)] - * ---------- - * 1) if it is a subpage, return the slab back into this subpage - * 2) if the subpage is not used, or it is a run, then start free this run - * 3) merge continuous avail runs - * 4) save the merged run - * - */ -final class PoolChunk implements PoolChunkMetric { - private static final int SIZE_BIT_LENGTH = 15; - private static final int INUSED_BIT_LENGTH = 1; - private static final int SUBPAGE_BIT_LENGTH = 1; - private static final int BITMAP_IDX_BIT_LENGTH = 32; - - static final int IS_SUBPAGE_SHIFT = BITMAP_IDX_BIT_LENGTH; - static final int IS_USED_SHIFT = SUBPAGE_BIT_LENGTH + IS_SUBPAGE_SHIFT; - static final int SIZE_SHIFT = INUSED_BIT_LENGTH + IS_USED_SHIFT; - static final int RUN_OFFSET_SHIFT = SIZE_BIT_LENGTH + SIZE_SHIFT; - - final PoolArena arena; - final Buffer base; // The buffer that is the source of the memory. Closing it will free the memory. - final Object memory; - final Drop baseDrop; // An ArcDrop that manages references to the base Buffer. - - /** - * store the first page and last page of each avail run - */ - private final LongLongHashMap runsAvailMap; - - /** - * manage all avail runs - */ - private final LongPriorityQueue[] runsAvail; - - /** - * manage all subpages in this chunk - */ - private final PoolSubpage[] subpages; - - private final int pageSize; - private final int pageShifts; - private final int chunkSize; - - int freeBytes; - - PoolChunkList parent; - PoolChunk prev; - PoolChunk next; - - PoolChunk(PoolArena arena, int pageSize, int pageShifts, int chunkSize, - int maxPageIdx) { - this.arena = arena; - MemoryManager manager = arena.manager; - base = manager.allocateShared(arena, chunkSize, manager.drop(), Statics.CLEANER); - memory = manager.unwrapRecoverableMemory(base); - baseDrop = ArcDrop.wrap(Buffer::close); - this.pageSize = pageSize; - this.pageShifts = pageShifts; - this.chunkSize = chunkSize; - freeBytes = chunkSize; - - runsAvail = newRunsAvailqueueArray(maxPageIdx); - runsAvailMap = new LongLongHashMap(-1); - subpages = new PoolSubpage[chunkSize >> pageShifts]; - - //insert initial run, offset = 0, pages = chunkSize / pageSize - int pages = chunkSize >> pageShifts; - long initHandle = (long) pages << SIZE_SHIFT; - insertAvailRun(0, pages, initHandle); - } - - private static LongPriorityQueue[] newRunsAvailqueueArray(int size) { - LongPriorityQueue[] queueArray = new LongPriorityQueue[size]; - for (int i = 0; i < queueArray.length; i++) { - queueArray[i] = new LongPriorityQueue(); - } - return queueArray; - } - - private void insertAvailRun(int runOffset, int pages, long handle) { - int pageIdxFloor = arena.pages2pageIdxFloor(pages); - LongPriorityQueue queue = runsAvail[pageIdxFloor]; - queue.offer(handle); - - //insert first page of run - insertAvailRun0(runOffset, handle); - if (pages > 1) { - //insert last page of run - insertAvailRun0(lastPage(runOffset, pages), handle); - } - } - - private void insertAvailRun0(int runOffset, long handle) { - long pre = runsAvailMap.put(runOffset, handle); - assert pre == -1; - } - - private void removeAvailRun(long handle) { - int pageIdxFloor = arena.pages2pageIdxFloor(runPages(handle)); - LongPriorityQueue queue = runsAvail[pageIdxFloor]; - removeAvailRun(queue, handle); - } - - private void removeAvailRun(LongPriorityQueue queue, long handle) { - queue.remove(handle); - - int runOffset = runOffset(handle); - int pages = runPages(handle); - //remove first page of run - runsAvailMap.remove(runOffset); - if (pages > 1) { - //remove last page of run - runsAvailMap.remove(lastPage(runOffset, pages)); - } - } - - private static int lastPage(int runOffset, int pages) { - return runOffset + pages - 1; - } - - private long getAvailRunByOffset(int runOffset) { - return runsAvailMap.get(runOffset); - } - - @Override - public int usage() { - final int freeBytes; - synchronized (arena) { - freeBytes = this.freeBytes; - } - return usage(freeBytes); - } - - private int usage(int freeBytes) { - if (freeBytes == 0) { - return 100; - } - - int freePercentage = (int) (freeBytes * 100L / chunkSize); - if (freePercentage == 0) { - return 99; - } - return 100 - freePercentage; - } - - UntetheredMemory allocate(int size, int sizeIdx, PoolThreadCache cache, PooledAllocatorControl control) { - final long handle; - if (sizeIdx <= arena.smallMaxSizeIdx) { - // small - handle = allocateSubpage(sizeIdx); - if (handle < 0) { - return null; - } - assert isSubpage(handle); - } else { - // normal - // runSize must be multiple of pageSize - int runSize = arena.sizeIdx2size(sizeIdx); - handle = allocateRun(runSize); - if (handle < 0) { - return null; - } - } - - return allocateBuffer(handle, size, cache, control); - } - - private long allocateRun(int runSize) { - int pages = runSize >> pageShifts; - int pageIdx = arena.pages2pageIdx(pages); - - synchronized (runsAvail) { - //find first queue which has at least one big enough run - int queueIdx = runFirstBestFit(pageIdx); - if (queueIdx == -1) { - return -1; - } - - //get run with min offset in this queue - LongPriorityQueue queue = runsAvail[queueIdx]; - long handle = queue.poll(); - - assert handle != LongPriorityQueue.NO_VALUE && !isUsed(handle) : "invalid handle: " + handle; - - removeAvailRun(queue, handle); - - if (handle != -1) { - handle = splitLargeRun(handle, pages); - } - - freeBytes -= runSize(pageShifts, handle); - return handle; - } - } - - private int calculateRunSize(int sizeIdx) { - int maxElements = 1 << pageShifts - SizeClasses.LOG2_QUANTUM; - int runSize = 0; - int nElements; - - final int elemSize = arena.sizeIdx2size(sizeIdx); - - // Find the lowest common multiple of pageSize and elemSize - do { - runSize += pageSize; - nElements = runSize / elemSize; - } while (nElements < maxElements && runSize != nElements * elemSize); - - while (nElements > maxElements) { - runSize -= pageSize; - nElements = runSize / elemSize; - } - - assert nElements > 0; - assert runSize <= chunkSize; - assert runSize >= elemSize; - - return runSize; - } - - private int runFirstBestFit(int pageIdx) { - if (freeBytes == chunkSize) { - return arena.nPSizes - 1; - } - for (int i = pageIdx; i < arena.nPSizes; i++) { - LongPriorityQueue queue = runsAvail[i]; - if (queue != null && !queue.isEmpty()) { - return i; - } - } - return -1; - } - - private long splitLargeRun(long handle, int needPages) { - assert needPages > 0; - - int totalPages = runPages(handle); - assert needPages <= totalPages; - - int remPages = totalPages - needPages; - - if (remPages > 0) { - int runOffset = runOffset(handle); - - // keep track of trailing unused pages for later use - int availOffset = runOffset + needPages; - long availRun = toRunHandle(availOffset, remPages, 0); - insertAvailRun(availOffset, remPages, availRun); - - // not avail - return toRunHandle(runOffset, needPages, 1); - } - - //mark it as used - handle |= 1L << IS_USED_SHIFT; - return handle; - } - - /** - * Create / initialize a new PoolSubpage of normCapacity. Any PoolSubpage created / initialized here is added to - * subpage pool in the PoolArena that owns this PoolChunk - * - * @param sizeIdx sizeIdx of normalized size - * - * @return index in memoryMap - */ - private long allocateSubpage(int sizeIdx) { - // Obtain the head of the PoolSubPage pool that is owned by the PoolArena and synchronize on it. - // This is need as we may add it back and so alter the linked-list structure. - PoolSubpage head = arena.findSubpagePoolHead(sizeIdx); - synchronized (head) { - //allocate a new run - int runSize = calculateRunSize(sizeIdx); - //runSize must be multiples of pageSize - long runHandle = allocateRun(runSize); - if (runHandle < 0) { - return -1; - } - - int runOffset = runOffset(runHandle); - assert subpages[runOffset] == null; - int elemSize = arena.sizeIdx2size(sizeIdx); - - PoolSubpage subpage = new PoolSubpage(head, this, pageShifts, runOffset, - runSize(pageShifts, runHandle), elemSize); - - subpages[runOffset] = subpage; - return subpage.allocate(); - } - } - - /** - * Free a subpage, or a run of pages When a subpage is freed from PoolSubpage, it might be added back to subpage - * pool of the owning PoolArena. If the subpage pool in PoolArena has at least one other PoolSubpage of given - * elemSize, we can completely free the owning Page, so it is available for subsequent allocations. - * - * @param handle handle to free - */ - void free(long handle, int normCapacity) { - baseDrop.drop(base); // Decrement reference count. - if (isSubpage(handle)) { - int sizeIdx = arena.size2SizeIdx(normCapacity); - PoolSubpage head = arena.findSubpagePoolHead(sizeIdx); - - int sIdx = runOffset(handle); - PoolSubpage subpage = subpages[sIdx]; - assert subpage != null && subpage.doNotDestroy; - - // Obtain the head of the PoolSubPage pool that is owned by the PoolArena and synchronize on it. - // This is need as we may add it back and so alter the linked-list structure. - synchronized (head) { - if (subpage.free(head, bitmapIdx(handle))) { - //the subpage is still used, do not free it - return; - } - assert !subpage.doNotDestroy; - // Null out slot in the array as it was freed, and we should not use it anymore. - subpages[sIdx] = null; - } - } - - //start free run - int pages = runPages(handle); - - synchronized (runsAvail) { - // collapse continuous runs, successfully collapsed runs - // will be removed from runsAvail and runsAvailMap - long finalRun = collapseRuns(handle); - - //set run as not used - finalRun &= ~(1L << IS_USED_SHIFT); - //if it is a subpage, set it to run - finalRun &= ~(1L << IS_SUBPAGE_SHIFT); - - insertAvailRun(runOffset(finalRun), runPages(finalRun), finalRun); - freeBytes += pages << pageShifts; - } - } - - private long collapseRuns(long handle) { - return collapseNext(collapsePast(handle)); - } - - private long collapsePast(long handle) { - for (;;) { - int runOffset = runOffset(handle); - int runPages = runPages(handle); - - long pastRun = getAvailRunByOffset(runOffset - 1); - if (pastRun == -1) { - return handle; - } - - int pastOffset = runOffset(pastRun); - int pastPages = runPages(pastRun); - - //is continuous - if (pastRun != handle && pastOffset + pastPages == runOffset) { - //remove past run - removeAvailRun(pastRun); - handle = toRunHandle(pastOffset, pastPages + runPages, 0); - } else { - return handle; - } - } - } - - private long collapseNext(long handle) { - for (;;) { - int runOffset = runOffset(handle); - int runPages = runPages(handle); - - long nextRun = getAvailRunByOffset(runOffset + runPages); - if (nextRun == -1) { - return handle; - } - - int nextOffset = runOffset(nextRun); - int nextPages = runPages(nextRun); - - //is continuous - if (nextRun != handle && runOffset + runPages == nextOffset) { - //remove next run - removeAvailRun(nextRun); - handle = toRunHandle(runOffset, runPages + nextPages, 0); - } else { - return handle; - } - } - } - - private static long toRunHandle(int runOffset, int runPages, int inUsed) { - return (long) runOffset << RUN_OFFSET_SHIFT - | (long) runPages << SIZE_SHIFT - | (long) inUsed << IS_USED_SHIFT; - } - - UntetheredMemory allocateBuffer(long handle, int size, PoolThreadCache threadCache, - PooledAllocatorControl control) { - if (isRun(handle)) { - int offset = runOffset(handle) << pageShifts; - int maxLength = runSize(pageShifts, handle); - PoolThreadCache poolThreadCache = arena.parent.threadCache(); - initAllocatorControl(control, poolThreadCache, handle, maxLength); - ArcDrop.acquire(baseDrop); - return new UntetheredChunkAllocation( - memory, this, poolThreadCache, handle, maxLength, offset, size); - } else { - return allocateBufferWithSubpage(handle, size, threadCache, control); - } - } - - UntetheredMemory allocateBufferWithSubpage(long handle, int size, PoolThreadCache threadCache, - PooledAllocatorControl control) { - int runOffset = runOffset(handle); - int bitmapIdx = bitmapIdx(handle); - - PoolSubpage s = subpages[runOffset]; - assert s.doNotDestroy; - assert size <= s.elemSize; - - int offset = (runOffset << pageShifts) + bitmapIdx * s.elemSize; - initAllocatorControl(control, threadCache, handle, s.elemSize); - ArcDrop.acquire(baseDrop); - return new UntetheredChunkAllocation(memory, this, threadCache, handle, s.elemSize, offset, size); - } - - @SuppressWarnings("unchecked") - private static final class UntetheredChunkAllocation implements UntetheredMemory { - private final Object memory; - private final PoolChunk chunk; - private final PoolThreadCache threadCache; - private final long handle; - private final int maxLength; - private final int offset; - private final int size; - - private UntetheredChunkAllocation( - Object memory, PoolChunk chunk, PoolThreadCache threadCache, - long handle, int maxLength, int offset, int size) { - this.memory = memory; - this.chunk = chunk; - this.threadCache = threadCache; - this.handle = handle; - this.maxLength = maxLength; - this.offset = offset; - this.size = size; - } - - @Override - public Memory memory() { - return (Memory) chunk.arena.manager.sliceMemory(memory, offset, size); - } - - @Override - public Drop drop() { - PooledDrop pooledDrop = new PooledDrop(chunk.arena, chunk, threadCache, handle, maxLength); - return (Drop) CleanerDrop.wrap(pooledDrop); - } - } - - private void initAllocatorControl(PooledAllocatorControl control, PoolThreadCache threadCache, long handle, - int normSize) { - control.arena = arena; - control.chunk = this; - control.threadCache = threadCache; - control.handle = handle; - control.normSize = normSize; - } - - @Override - public int chunkSize() { - return chunkSize; - } - - @Override - public int freeBytes() { - synchronized (arena) { - return freeBytes; - } - } - - @Override - public String toString() { - final int freeBytes; - synchronized (arena) { - freeBytes = this.freeBytes; - } - - return new StringBuilder() - .append("Chunk(") - .append(Integer.toHexString(System.identityHashCode(this))) - .append(": ") - .append(usage(freeBytes)) - .append("%, ") - .append(chunkSize - freeBytes) - .append('/') - .append(chunkSize) - .append(')') - .toString(); - } - - void destroy() { - baseDrop.drop(base); // Decrement reference count from the chunk (allocated buffers may keep the base alive) - } - - static int runOffset(long handle) { - return (int) (handle >> RUN_OFFSET_SHIFT); - } - - static int runSize(int pageShifts, long handle) { - return runPages(handle) << pageShifts; - } - - static int runPages(long handle) { - return (int) (handle >> SIZE_SHIFT & 0x7fff); - } - - static boolean isUsed(long handle) { - return (handle >> IS_USED_SHIFT & 1) == 1L; - } - - static boolean isRun(long handle) { - return !isSubpage(handle); - } - - static boolean isSubpage(long handle) { - return (handle >> IS_SUBPAGE_SHIFT & 1) == 1L; - } - - static int bitmapIdx(long handle) { - return (int) handle; - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkList.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkList.java deleted file mode 100644 index 03347f6..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkList.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.AllocatorControl.UntetheredMemory; -import io.netty.util.internal.StringUtil; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import static java.lang.Math.max; -import static java.lang.Math.min; - -final class PoolChunkList implements PoolChunkListMetric { - private static final Iterator EMPTY_METRICS = Collections.emptyIterator(); - private final PoolArena arena; - private final PoolChunkList nextList; - private final int minUsage; - private final int maxUsage; - private final int maxCapacity; - private PoolChunk head; - private final int freeMinThreshold; - private final int freeMaxThreshold; - - // This is only update once when create the linked like list of PoolChunkList in PoolArena constructor. - private PoolChunkList prevList; - - PoolChunkList(PoolArena arena, PoolChunkList nextList, int minUsage, int maxUsage, int chunkSize) { - assert minUsage <= maxUsage; - this.arena = arena; - this.nextList = nextList; - this.minUsage = minUsage; - this.maxUsage = maxUsage; - maxCapacity = calculateMaxCapacity(minUsage, chunkSize); - - // the thresholds are aligned with PoolChunk.usage() logic: - // 1) basic logic: usage() = 100 - freeBytes * 100L / chunkSize - // so, for example: (usage() >= maxUsage) condition can be transformed in the following way: - // 100 - freeBytes * 100L / chunkSize >= maxUsage - // freeBytes <= chunkSize * (100 - maxUsage) / 100 - // let freeMinThreshold = chunkSize * (100 - maxUsage) / 100, then freeBytes <= freeMinThreshold - // - // 2) usage() returns an int value and has a floor rounding during a calculation, - // to be aligned absolute thresholds should be shifted for "the rounding step": - // freeBytes * 100 / chunkSize < 1 - // the condition can be converted to: freeBytes < 1 * chunkSize / 100 - // this is why we have + 0.99999999 shifts. A example why just +1 shift cannot be used: - // freeBytes = 16777216 == freeMaxThreshold: 16777216, usage = 0 < minUsage: 1, chunkSize: 16777216 - // At the same time we want to have zero thresholds in case of (maxUsage == 100) and (minUsage == 100). - // - freeMinThreshold = maxUsage == 100 ? 0 : (int) (chunkSize * (100.0 - maxUsage + 0.99999999) / 100L); - freeMaxThreshold = minUsage == 100 ? 0 : (int) (chunkSize * (100.0 - minUsage + 0.99999999) / 100L); - } - - /** - * Calculates the maximum capacity of a buffer that will ever be possible to allocate out of the {@link PoolChunk}s - * that belong to the {@link PoolChunkList} with the given {@code minUsage} and {@code maxUsage} settings. - */ - private static int calculateMaxCapacity(int minUsage, int chunkSize) { - minUsage = minUsage0(minUsage); - - if (minUsage == 100) { - // If the minUsage is 100 we can not allocate anything out of this list. - return 0; - } - - // Calculate the maximum amount of bytes that can be allocated from a PoolChunk in this PoolChunkList. - // - // As an example: - // - If a PoolChunkList has minUsage == 25 we are allowed to allocate at most 75% of the chunkSize because - // this is the maximum amount available in any PoolChunk in this PoolChunkList. - return (int) (chunkSize * (100L - minUsage) / 100L); - } - - void prevList(PoolChunkList prevList) { - assert this.prevList == null; - this.prevList = prevList; - } - - UntetheredMemory allocate(int size, int sizeIdx, PoolThreadCache threadCache, PooledAllocatorControl control) { - int normCapacity = arena.sizeIdx2size(sizeIdx); - if (normCapacity > maxCapacity) { - // Either this PoolChunkList is empty, or the requested capacity is larger than the capacity which can - // be handled by the PoolChunks that are contained in this PoolChunkList. - return null; - } - - for (PoolChunk cur = head; cur != null; cur = cur.next) { - UntetheredMemory memory = cur.allocate(size, sizeIdx, threadCache, control); - if (memory != null) { - if (cur.freeBytes <= freeMinThreshold) { - remove(cur); - nextList.add(cur); - } - return memory; - } - } - return null; - } - - boolean free(PoolChunk chunk, long handle, int normCapacity) { - chunk.free(handle, normCapacity); - if (chunk.freeBytes > freeMaxThreshold) { - remove(chunk); - // Move the PoolChunk down the PoolChunkList linked-list. - return move0(chunk); - } - return true; - } - - private boolean move(PoolChunk chunk) { - if (chunk.freeBytes > freeMaxThreshold) { - // Move the PoolChunk down the PoolChunkList linked-list. - return move0(chunk); - } - - // PoolChunk fits into this PoolChunkList, adding it here. - add0(chunk); - return true; - } - - /** - * Moves the {@link PoolChunk} down the {@link PoolChunkList} linked-list, so it will end up in the right - * {@link PoolChunkList} that has the correct minUsage / maxUsage in respect to {@link PoolChunk#usage()}. - */ - private boolean move0(PoolChunk chunk) { - if (prevList == null) { - // There is no previous PoolChunkList so return false which result in having the PoolChunk destroyed and - // all memory associated with the PoolChunk will be released. - return false; - } - return prevList.move(chunk); - } - - void add(PoolChunk chunk) { - if (chunk.freeBytes <= freeMinThreshold) { - nextList.add(chunk); - return; - } - add0(chunk); - } - - /** - * Adds the {@link PoolChunk} to this {@link PoolChunkList}. - */ - void add0(PoolChunk chunk) { - chunk.parent = this; - if (head == null) { - head = chunk; - chunk.prev = null; - chunk.next = null; - } else { - chunk.prev = null; - chunk.next = head; - head.prev = chunk; - head = chunk; - } - } - - private void remove(PoolChunk cur) { - if (cur == head) { - head = cur.next; - if (head != null) { - head.prev = null; - } - } else { - PoolChunk next = cur.next; - cur.prev.next = next; - if (next != null) { - next.prev = cur.prev; - } - } - } - - @Override - public int minUsage() { - return minUsage0(minUsage); - } - - @Override - public int maxUsage() { - return min(maxUsage, 100); - } - - private static int minUsage0(int value) { - return max(1, value); - } - - @Override - public Iterator iterator() { - synchronized (arena) { - if (head == null) { - return EMPTY_METRICS; - } - List metrics = new ArrayList<>(); - for (PoolChunk cur = head;;) { - metrics.add(cur); - cur = cur.next; - if (cur == null) { - break; - } - } - return metrics.iterator(); - } - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - synchronized (arena) { - if (head == null) { - return "none"; - } - - for (PoolChunk cur = head;;) { - buf.append(cur); - cur = cur.next; - if (cur == null) { - break; - } - buf.append(StringUtil.NEWLINE); - } - } - return buf.toString(); - } - - void destroy() { - PoolChunk chunk = head; - while (chunk != null) { - chunk.destroy(); - chunk = chunk.next; - } - head = null; - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkListMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkListMetric.java deleted file mode 100644 index 9a60e1d..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkListMetric.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -/** - * Metrics for a list of chunks. - */ -public interface PoolChunkListMetric extends Iterable { - - /** - * Return the minimum usage of the chunk list before which chunks are promoted to the previous list. - */ - int minUsage(); - - /** - * Return the maximum usage of the chunk list after which chunks are promoted to the next list. - */ - int maxUsage(); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkMetric.java deleted file mode 100644 index 8a90384..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolChunkMetric.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -/** - * Metrics for a chunk. - */ -public interface PoolChunkMetric { - - /** - * Return the percentage of the current usage of the chunk. - */ - int usage(); - - /** - * Return the size of the chunk in bytes, this is the maximum of bytes that can be served out of the chunk. - */ - int chunkSize(); - - /** - * Return the number of free bytes in the chunk. - */ - int freeBytes(); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpage.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpage.java deleted file mode 100644 index c0b558d..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpage.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import static io.netty.buffer.api.pool.PoolChunk.RUN_OFFSET_SHIFT; -import static io.netty.buffer.api.pool.PoolChunk.SIZE_SHIFT; -import static io.netty.buffer.api.pool.PoolChunk.IS_USED_SHIFT; -import static io.netty.buffer.api.pool.PoolChunk.IS_SUBPAGE_SHIFT; -import static io.netty.buffer.api.pool.SizeClasses.LOG2_QUANTUM; - -final class PoolSubpage implements PoolSubpageMetric { - final PoolChunk chunk; - private final int pageShifts; - private final int runOffset; - private final int runSize; - private final long[] bitmap; - - PoolSubpage prev; - PoolSubpage next; - - boolean doNotDestroy; - int elemSize; - private int maxNumElems; - private int bitmapLength; - private int nextAvail; - private int numAvail; - - /** Special constructor that creates a linked list head */ - PoolSubpage() { - chunk = null; - pageShifts = -1; - runOffset = -1; - elemSize = -1; - runSize = -1; - bitmap = null; - } - - PoolSubpage(PoolSubpage head, PoolChunk chunk, int pageShifts, int runOffset, int runSize, int elemSize) { - this.chunk = chunk; - this.pageShifts = pageShifts; - this.runOffset = runOffset; - this.runSize = runSize; - this.elemSize = elemSize; - bitmap = new long[runSize >>> 6 + LOG2_QUANTUM]; // runSize / 64 / QUANTUM - - doNotDestroy = true; - if (elemSize != 0) { - maxNumElems = numAvail = runSize / elemSize; - nextAvail = 0; - bitmapLength = maxNumElems >>> 6; - if ((maxNumElems & 63) != 0) { - bitmapLength ++; - } - - for (int i = 0; i < bitmapLength; i ++) { - bitmap[i] = 0; - } - } - addToPool(head); - } - - /** - * Returns the bitmap index of the subpage allocation. - */ - long allocate() { - if (numAvail == 0 || !doNotDestroy) { - return -1; - } - - final int bitmapIdx = getNextAvail(); - int q = bitmapIdx >>> 6; - int r = bitmapIdx & 63; - assert (bitmap[q] >>> r & 1) == 0; - bitmap[q] |= 1L << r; - - if (-- numAvail == 0) { - removeFromPool(); - } - - return toHandle(bitmapIdx); - } - - /** - * @return {@code true} if this subpage is in use. - * {@code false} if this subpage is not used by its chunk and thus it's OK to be released. - */ - boolean free(PoolSubpage head, int bitmapIdx) { - if (elemSize == 0) { - return true; - } - int q = bitmapIdx >>> 6; - int r = bitmapIdx & 63; - assert (bitmap[q] >>> r & 1) != 0; - bitmap[q] ^= 1L << r; - - setNextAvail(bitmapIdx); - - if (numAvail++ == 0) { - addToPool(head); - // When maxNumElems == 1, the maximum numAvail is also 1. - // Each of these PoolSubpages will go in here when they do free operation. - // If they return true directly from here, then the rest of the code will be unreachable, - // and they will not actually be recycled. So return true only on maxNumElems > 1. - if (maxNumElems > 1) { - return true; - } - } - - if (numAvail != maxNumElems) { - return true; - } else { - // Subpage not in use (numAvail == maxNumElems) - if (prev == next) { - // Do not remove if this subpage is the only one left in the pool. - return true; - } - - // Remove this subpage from the pool if there are other subpages left in the pool. - doNotDestroy = false; - removeFromPool(); - return false; - } - } - - private void addToPool(PoolSubpage head) { - assert prev == null && next == null; - prev = head; - next = head.next; - next.prev = this; - head.next = this; - } - - private void removeFromPool() { - assert prev != null && next != null; - prev.next = next; - next.prev = prev; - next = null; - prev = null; - } - - private void setNextAvail(int bitmapIdx) { - nextAvail = bitmapIdx; - } - - private int getNextAvail() { - int nextAvail = this.nextAvail; - if (nextAvail >= 0) { - this.nextAvail = -1; - return nextAvail; - } - return findNextAvail(); - } - - private int findNextAvail() { - final long[] bitmap = this.bitmap; - final int bitmapLength = this.bitmapLength; - for (int i = 0; i < bitmapLength; i ++) { - long bits = bitmap[i]; - if (~bits != 0) { - return findNextAvail0(i, bits); - } - } - return -1; - } - - private int findNextAvail0(int i, long bits) { - final int maxNumElems = this.maxNumElems; - final int baseVal = i << 6; - - for (int j = 0; j < 64; j ++) { - if ((bits & 1) == 0) { - int val = baseVal | j; - if (val < maxNumElems) { - return val; - } else { - break; - } - } - bits >>>= 1; - } - return -1; - } - - private long toHandle(int bitmapIdx) { - int pages = runSize >> pageShifts; - return (long) runOffset << RUN_OFFSET_SHIFT - | (long) pages << SIZE_SHIFT - | 1L << IS_USED_SHIFT - | 1L << IS_SUBPAGE_SHIFT - | bitmapIdx; - } - - @Override - public String toString() { - final boolean doNotDestroy; - final int maxNumElems; - final int numAvail; - final int elemSize; - if (chunk == null) { - // This is the head so there is no need to synchronize at all as these never change. - doNotDestroy = true; - maxNumElems = 0; - numAvail = 0; - elemSize = -1; - } else { - synchronized (chunk.arena) { - if (!this.doNotDestroy) { - doNotDestroy = false; - // Not used for creating the String. - maxNumElems = numAvail = elemSize = -1; - } else { - doNotDestroy = true; - maxNumElems = this.maxNumElems; - numAvail = this.numAvail; - elemSize = this.elemSize; - } - } - } - - if (!doNotDestroy) { - return "(" + runOffset + ": not in use)"; - } - - return "(" + runOffset + ": " + (maxNumElems - numAvail) + '/' + maxNumElems + - ", offset: " + runOffset + ", length: " + runSize + ", elemSize: " + elemSize + ')'; - } - - @Override - public int maxNumElements() { - if (chunk == null) { - // It's the head. - return 0; - } - - synchronized (chunk.arena) { - return maxNumElems; - } - } - - @Override - public int numAvailable() { - if (chunk == null) { - // It's the head. - return 0; - } - - synchronized (chunk.arena) { - return numAvail; - } - } - - @Override - public int elementSize() { - if (chunk == null) { - // It's the head. - return -1; - } - - synchronized (chunk.arena) { - return elemSize; - } - } - - @Override - public int pageSize() { - return 1 << pageShifts; - } - - void destroy() { - if (chunk != null) { - chunk.destroy(); - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpageMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpageMetric.java deleted file mode 100644 index 5793a0a..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolSubpageMetric.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -/** - * Metrics for a sub-page. - */ -public interface PoolSubpageMetric { - - /** - * Return the number of maximal elements that can be allocated out of the sub-page. - */ - int maxNumElements(); - - /** - * Return the number of available elements to be allocated. - */ - int numAvailable(); - - /** - * Return the size (in bytes) of the elements that will be allocated. - */ - int elementSize(); - - /** - * Return the page size (in bytes) of this page. - */ - int pageSize(); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolThreadCache.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolThreadCache.java deleted file mode 100644 index 2771b7f..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PoolThreadCache.java +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.AllocatorControl.UntetheredMemory; -import io.netty.buffer.api.pool.PoolArena.SizeClass; -import io.netty.util.internal.MathUtil; -import io.netty.util.internal.ObjectPool; -import io.netty.util.internal.ObjectPool.Handle; -import io.netty.util.internal.PlatformDependent; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Queue; - -import static io.netty.buffer.api.pool.PoolArena.SizeClass.Normal; -import static io.netty.buffer.api.pool.PoolArena.SizeClass.Small; -import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero; - -/** - * Acts a Thread cache for allocations. This implementation is modelled after - * jemalloc and the described - * techniques of - * - * Scalable memory allocation using jemalloc. - */ -final class PoolThreadCache { - - private static final InternalLogger logger = InternalLoggerFactory.getInstance(PoolThreadCache.class); - private static final int INTEGER_SIZE_MINUS_ONE = Integer.SIZE - 1; - - final PoolArena arena; - - // Hold the caches for the different size classes, which are tiny, small and normal. - private final MemoryRegionCache[] smallSubPageCaches; - private final MemoryRegionCache[] normalCaches; - - private final int freeSweepAllocationThreshold; - - private int allocations; - - PoolThreadCache(PoolArena arena, - int smallCacheSize, int normalCacheSize, int maxCachedBufferCapacity, - int freeSweepAllocationThreshold) { - checkPositiveOrZero(maxCachedBufferCapacity, "maxCachedBufferCapacity"); - this.freeSweepAllocationThreshold = freeSweepAllocationThreshold; - this.arena = arena; - if (arena != null) { - // Create the caches for the heap allocations - smallSubPageCaches = createSubPageCaches( - smallCacheSize, arena.numSmallSubpagePools); - - normalCaches = createNormalCaches( - normalCacheSize, maxCachedBufferCapacity, arena); - - arena.numThreadCaches.getAndIncrement(); - } else { - // No heapArea is configured so just null out all caches - smallSubPageCaches = null; - normalCaches = null; - } - - // Only check if there are caches in use. - if ((smallSubPageCaches != null || normalCaches != null) - && freeSweepAllocationThreshold < 1) { - throw new IllegalArgumentException("freeSweepAllocationThreshold: " - + freeSweepAllocationThreshold + " (expected: > 0)"); - } - } - - private static MemoryRegionCache[] createSubPageCaches( - int cacheSize, int numCaches) { - if (cacheSize > 0 && numCaches > 0) { - MemoryRegionCache[] cache = new MemoryRegionCache[numCaches]; - for (int i = 0; i < cache.length; i++) { - // TODO: maybe use cacheSize / cache.length - cache[i] = new SubPageMemoryRegionCache(cacheSize); - } - return cache; - } else { - return null; - } - } - - private static MemoryRegionCache[] createNormalCaches( - int cacheSize, int maxCachedBufferCapacity, PoolArena area) { - if (cacheSize > 0 && maxCachedBufferCapacity > 0) { - int max = Math.min(area.chunkSize, maxCachedBufferCapacity); - - // Create as many normal caches as we support based on how many sizeIdx we have and what the upper - // bound is that we want to cache in general. - List cache = new ArrayList<>() ; - for (int idx = area.numSmallSubpagePools; idx < area.nSizes && area.sizeIdx2size(idx) <= max ; idx++) { - cache.add(new NormalMemoryRegionCache(cacheSize)); - } - return cache.toArray(MemoryRegionCache[]::new); - } else { - return null; - } - } - - // val > 0 - static int log2(int val) { - return INTEGER_SIZE_MINUS_ONE - Integer.numberOfLeadingZeros(val); - } - - /** - * Try to allocate a small buffer out of the cache. Returns {@code true} if successful {@code false} otherwise - */ - UntetheredMemory allocateSmall(PooledAllocatorControl control, int size, int sizeIdx) { - return allocate(cacheForSmall(sizeIdx), control, size); - } - - /** - * Try to allocate a normal buffer out of the cache. Returns {@code true} if successful {@code false} otherwise - */ - UntetheredMemory allocateNormal(PoolArena area, PooledAllocatorControl control, int size, int sizeIdx) { - return allocate(cacheForNormal(area, sizeIdx), control, size); - } - - private UntetheredMemory allocate(MemoryRegionCache cache, PooledAllocatorControl control, int size) { - if (cache == null) { - // no cache found so just return false here - return null; - } - UntetheredMemory allocated = cache.allocate(size, this, control); - if (++allocations >= freeSweepAllocationThreshold) { - allocations = 0; - trim(); - } - return allocated; - } - - /** - * Add {@link PoolChunk} and {@code handle} to the cache if there is enough room. - * Returns {@code true} if it fit into the cache {@code false} otherwise. - */ - boolean add(PoolArena area, PoolChunk chunk, - long handle, int normCapacity, SizeClass sizeClass) { - int sizeIdx = area.size2SizeIdx(normCapacity); - MemoryRegionCache cache = cache(area, sizeIdx, sizeClass); - if (cache == null) { - return false; - } - return cache.add(chunk, handle, normCapacity); - } - - private MemoryRegionCache cache(PoolArena area, int sizeIdx, SizeClass sizeClass) { - if (sizeClass == Normal) { - return cacheForNormal(area, sizeIdx); - } - if (sizeClass == Small) { - return cacheForSmall(sizeIdx); - } - throw new AssertionError("Unexpected size class: " + sizeClass); - } - - /** - * Should be called if the Thread that uses this cache is about to exist to release resources out of the cache - */ - void free() { - int numFreed = free(smallSubPageCaches) + free(normalCaches); - - if (numFreed > 0 && logger.isDebugEnabled()) { - logger.debug("Freed {} thread-local buffer(s) from thread: {}", numFreed, - Thread.currentThread().getName()); - } - - if (arena != null) { - arena.numThreadCaches.getAndDecrement(); - } - } - - private static int free(MemoryRegionCache[] caches) { - if (caches == null) { - return 0; - } - - int numFreed = 0; - for (MemoryRegionCache c: caches) { - numFreed += free(c); - } - return numFreed; - } - - private static int free(MemoryRegionCache cache) { - if (cache == null) { - return 0; - } - return cache.free(); - } - - void trim() { - trim(smallSubPageCaches); - trim(normalCaches); - } - - private static void trim(MemoryRegionCache[] caches) { - if (caches == null) { - return; - } - for (MemoryRegionCache c: caches) { - trim(c); - } - } - - private static void trim(MemoryRegionCache cache) { - if (cache == null) { - return; - } - cache.trim(); - } - - private MemoryRegionCache cacheForSmall(int sizeIdx) { - return cache(smallSubPageCaches, sizeIdx); - } - - private MemoryRegionCache cacheForNormal(PoolArena area, int sizeIdx) { - // We need to substract area.numSmallSubpagePools as sizeIdx is the overall index for all sizes. - int idx = sizeIdx - area.numSmallSubpagePools; - return cache(normalCaches, idx); - } - - private static MemoryRegionCache cache(MemoryRegionCache[] cache, int sizeIdx) { - if (cache == null || sizeIdx > cache.length - 1) { - return null; - } - return cache[sizeIdx]; - } - - /** - * Cache used for buffers which are backed by SMALL size. - */ - private static final class SubPageMemoryRegionCache extends MemoryRegionCache { - SubPageMemoryRegionCache(int size) { - super(size, Small); - } - - @Override - protected UntetheredMemory allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache, - PooledAllocatorControl control) { - return chunk.allocateBufferWithSubpage(handle, size, threadCache, control); - } - } - - /** - * Cache used for buffers which are backed by NORMAL size. - */ - private static final class NormalMemoryRegionCache extends MemoryRegionCache { - NormalMemoryRegionCache(int size) { - super(size, Normal); - } - - @Override - protected UntetheredMemory allocBuf(PoolChunk chunk, long handle, int size, PoolThreadCache threadCache, - PooledAllocatorControl control) { - return chunk.allocateBuffer(handle, size, threadCache, control); - } - } - - private abstract static class MemoryRegionCache { - private final int size; - private final Queue queue; - private final SizeClass sizeClass; - private int allocations; - - MemoryRegionCache(int size, SizeClass sizeClass) { - this.size = MathUtil.safeFindNextPositivePowerOfTwo(size); - queue = PlatformDependent.newFixedMpscQueue(this.size); - this.sizeClass = sizeClass; - } - - /** - * Allocate a new {@link UntetheredMemory} using the provided chunk and handle with the capacity restrictions. - */ - protected abstract UntetheredMemory allocBuf( - PoolChunk chunk, long handle, int size, PoolThreadCache threadCache, PooledAllocatorControl control); - - /** - * Add to cache if not already full. - */ - public final boolean add(PoolChunk chunk, long handle, int normCapacity) { - Entry entry = newEntry(chunk, handle, normCapacity); - boolean queued = queue.offer(entry); - if (!queued) { - // If it was not possible to cache the chunk, immediately recycle the entry - entry.recycle(); - } - - return queued; - } - - /** - * Allocate something out of the cache if possible and remove the entry from the cache. - */ - public final UntetheredMemory allocate(int size, PoolThreadCache threadCache, PooledAllocatorControl control) { - Entry entry = queue.poll(); - if (entry == null) { - return null; - } - UntetheredMemory buffer = allocBuf(entry.chunk, entry.handle, size, threadCache, control); - entry.recycle(); - - // allocations are not thread-safe which is fine as this is only called from the same thread all time. - allocations++; - return buffer; - } - - /** - * Clear out this cache and free up all previous cached {@link PoolChunk}s and {@code handle}s. - */ - public final int free() { - return free(Integer.MAX_VALUE); - } - - private int free(int max) { - int numFreed = 0; - for (; numFreed < max; numFreed++) { - Entry entry = queue.poll(); - if (entry != null) { - freeEntry(entry); - } else { - // all cleared - return numFreed; - } - } - return numFreed; - } - - /** - * Free up cached {@link PoolChunk}s if not allocated frequently enough. - */ - public final void trim() { - int free = size - allocations; - allocations = 0; - - // We not even allocated all the number that are - if (free > 0) { - free(free); - } - } - - private void freeEntry(Entry entry) { - PoolChunk chunk = entry.chunk; - long handle = entry.handle; - - entry.recycle(); - chunk.arena.freeChunk(chunk, handle, entry.normCapacity, sizeClass); - } - - static final class Entry { - final Handle recyclerHandle; - PoolChunk chunk; - long handle = -1; - int normCapacity; - - Entry(Handle recyclerHandle) { - this.recyclerHandle = recyclerHandle; - } - - void recycle() { - chunk = null; - handle = -1; - recyclerHandle.recycle(this); - } - } - - private static Entry newEntry(PoolChunk chunk, long handle, int normCapacity) { - Entry entry = RECYCLER.get(); - entry.chunk = chunk; - entry.handle = handle; - entry.normCapacity = normCapacity; - return entry; - } - - private static final ObjectPool RECYCLER = ObjectPool.newPool(handle -> new Entry(handle)); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledAllocatorControl.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledAllocatorControl.java deleted file mode 100644 index 2e177c8..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledAllocatorControl.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.AllocatorControl; -import io.netty.buffer.api.Buffer; - -class PooledAllocatorControl implements AllocatorControl { - public PooledBufferAllocator parent; - public PoolArena arena; - public PoolChunk chunk; - public PoolThreadCache threadCache; - public long handle; - public int normSize; - - @Override - public UntetheredMemory allocateUntethered(Buffer originator, int size) { - return parent.allocate(this, size); - } - - @Override - public void recoverMemory(Object memory) { - arena.free(chunk, handle, normSize, threadCache); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocator.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocator.java deleted file mode 100644 index c8ae60b..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocator.java +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.AllocatorControl.UntetheredMemory; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.BufferAllocator; -import io.netty.buffer.api.MemoryManager; -import io.netty.util.NettyRuntime; -import io.netty.util.concurrent.EventExecutor; -import io.netty.util.concurrent.FastThreadLocal; -import io.netty.util.concurrent.FastThreadLocalThread; -import io.netty.util.internal.PlatformDependent; -import io.netty.util.internal.StringUtil; -import io.netty.util.internal.SystemPropertyUtil; -import io.netty.util.internal.ThreadExecutorMap; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; - -import java.nio.ByteOrder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero; -import static java.util.Objects.requireNonNull; - -public class PooledBufferAllocator implements BufferAllocator, BufferAllocatorMetricProvider { - - private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledBufferAllocator.class); - private static final int DEFAULT_NUM_HEAP_ARENA; - private static final int DEFAULT_NUM_DIRECT_ARENA; - - private static final int DEFAULT_PAGE_SIZE; - private static final int DEFAULT_MAX_ORDER; // 8192 << 9 = 4 MiB per chunk - private static final int DEFAULT_SMALL_CACHE_SIZE; - private static final int DEFAULT_NORMAL_CACHE_SIZE; - static final int DEFAULT_MAX_CACHED_BUFFER_CAPACITY; - private static final int DEFAULT_CACHE_TRIM_INTERVAL; - private static final long DEFAULT_CACHE_TRIM_INTERVAL_MILLIS; - private static final boolean DEFAULT_USE_CACHE_FOR_ALL_THREADS; - private static final int DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT; - static final int DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK; - - private static final int MIN_PAGE_SIZE = 4096; - private static final int MAX_CHUNK_SIZE = (int) (((long) Integer.MAX_VALUE + 1) / 2); - - private final Runnable trimTask = this::trimCurrentThreadCache; - - static { - int defaultAlignment = SystemPropertyUtil.getInt( - "io.netty.allocator.directMemoryCacheAlignment", 0); - int defaultPageSize = SystemPropertyUtil.getInt("io.netty.allocator.pageSize", 8192); - Throwable pageSizeFallbackCause = null; - try { - validateAndCalculatePageShifts(defaultPageSize, defaultAlignment); - } catch (Throwable t) { - pageSizeFallbackCause = t; - defaultPageSize = 8192; - defaultAlignment = 0; - } - DEFAULT_PAGE_SIZE = defaultPageSize; - DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT = defaultAlignment; - - int defaultMaxOrder = SystemPropertyUtil.getInt("io.netty.allocator.maxOrder", 9); - Throwable maxOrderFallbackCause = null; - try { - validateAndCalculateChunkSize(DEFAULT_PAGE_SIZE, defaultMaxOrder); - } catch (Throwable t) { - maxOrderFallbackCause = t; - defaultMaxOrder = 11; - } - DEFAULT_MAX_ORDER = defaultMaxOrder; - - // Determine reasonable default for nHeapArena and nDirectArena. - // Assuming each arena has 3 chunks, the pool should not consume more than 50% of max memory. - final Runtime runtime = Runtime.getRuntime(); - - /* - * We use 2 * available processors by default to reduce contention as we use 2 * available processors for the - * number of EventLoops in NIO and EPOLL as well. If we choose a smaller number we will run into hot spots as - * allocation and de-allocation needs to be synchronized on the PoolArena. - * - * See https://github.com/netty/netty/issues/3888. - */ - final int defaultMinNumArena = NettyRuntime.availableProcessors() * 2; - final int defaultChunkSize = DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER; - DEFAULT_NUM_HEAP_ARENA = Math.max(0, - SystemPropertyUtil.getInt( - "io.netty.allocator.numArenas", - (int) Math.min( - defaultMinNumArena, - runtime.maxMemory() / defaultChunkSize / 2 / 3))); - DEFAULT_NUM_DIRECT_ARENA = Math.max(0, - SystemPropertyUtil.getInt( - "io.netty.allocator.numDirectArenas", - (int) Math.min( - defaultMinNumArena, - PlatformDependent.maxDirectMemory() / defaultChunkSize / 2 / 3))); - - // cache sizes - DEFAULT_SMALL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.smallCacheSize", 256); - DEFAULT_NORMAL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.normalCacheSize", 64); - - // 32 kb is the default maximum capacity of the cached buffer. Similar to what is explained in - // 'Scalable memory allocation using jemalloc' - DEFAULT_MAX_CACHED_BUFFER_CAPACITY = SystemPropertyUtil.getInt( - "io.netty.allocator.maxCachedBufferCapacity", 32 * 1024); - - // the number of threshold of allocations when cached entries will be freed up if not frequently used - DEFAULT_CACHE_TRIM_INTERVAL = SystemPropertyUtil.getInt( - "io.netty.allocator.cacheTrimInterval", 8192); - - DEFAULT_CACHE_TRIM_INTERVAL_MILLIS = SystemPropertyUtil.getLong( - "io.netty.allocator.cacheTrimIntervalMillis", 0); - - DEFAULT_USE_CACHE_FOR_ALL_THREADS = SystemPropertyUtil.getBoolean( - "io.netty.allocator.useCacheForAllThreads", false); - - // Use 1023 by default as we use an ArrayDeque as backing storage which will then allocate an internal array - // of 1024 elements. Otherwise, we would allocate 2048 and only use 1024 which is wasteful. - DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK = SystemPropertyUtil.getInt( - "io.netty.allocator.maxCachedByteBuffersPerChunk", 1023); - - if (logger.isDebugEnabled()) { - logger.debug("-Dio.netty.allocator.numArenas: {}", DEFAULT_NUM_HEAP_ARENA); - logger.debug("-Dio.netty.allocator.numDirectArenas: {}", DEFAULT_NUM_DIRECT_ARENA); - if (pageSizeFallbackCause == null) { - logger.debug("-Dio.netty.allocator.pageSize: {}", DEFAULT_PAGE_SIZE); - } else { - logger.debug("-Dio.netty.allocator.pageSize: {}", DEFAULT_PAGE_SIZE, pageSizeFallbackCause); - } - if (maxOrderFallbackCause == null) { - logger.debug("-Dio.netty.allocator.maxOrder: {}", DEFAULT_MAX_ORDER); - } else { - logger.debug("-Dio.netty.allocator.maxOrder: {}", DEFAULT_MAX_ORDER, maxOrderFallbackCause); - } - logger.debug("-Dio.netty.allocator.chunkSize: {}", DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER); - logger.debug("-Dio.netty.allocator.smallCacheSize: {}", DEFAULT_SMALL_CACHE_SIZE); - logger.debug("-Dio.netty.allocator.normalCacheSize: {}", DEFAULT_NORMAL_CACHE_SIZE); - logger.debug("-Dio.netty.allocator.maxCachedBufferCapacity: {}", DEFAULT_MAX_CACHED_BUFFER_CAPACITY); - logger.debug("-Dio.netty.allocator.cacheTrimInterval: {}", DEFAULT_CACHE_TRIM_INTERVAL); - logger.debug("-Dio.netty.allocator.cacheTrimIntervalMillis: {}", DEFAULT_CACHE_TRIM_INTERVAL_MILLIS); - logger.debug("-Dio.netty.allocator.useCacheForAllThreads: {}", DEFAULT_USE_CACHE_FOR_ALL_THREADS); - logger.debug("-Dio.netty.allocator.maxCachedByteBuffersPerChunk: {}", - DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK); - } - } - - private final MemoryManager manager; - private final PoolArena[] arenas; - private final int smallCacheSize; - private final int normalCacheSize; - private final List arenaMetrics; - private final List arenaMetricsView; - private final PoolThreadLocalCache threadCache; - private final int chunkSize; - private final PooledBufferAllocatorMetric metric; - - public PooledBufferAllocator(MemoryManager manager) { - this(manager, manager.isNative()? DEFAULT_NUM_DIRECT_ARENA : DEFAULT_NUM_HEAP_ARENA, - DEFAULT_PAGE_SIZE, DEFAULT_MAX_ORDER, DEFAULT_SMALL_CACHE_SIZE, - DEFAULT_NORMAL_CACHE_SIZE, DEFAULT_USE_CACHE_FOR_ALL_THREADS, - DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT); - } - - public PooledBufferAllocator(MemoryManager manager, int numArenas, int pageSize, int maxOrder) { - this(manager, numArenas, pageSize, maxOrder, DEFAULT_SMALL_CACHE_SIZE, - DEFAULT_NORMAL_CACHE_SIZE, DEFAULT_USE_CACHE_FOR_ALL_THREADS, - DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT); - } - - public PooledBufferAllocator(MemoryManager manager, int numArenas, int pageSize, int maxOrder, - int smallCacheSize, int normalCacheSize, - boolean useCacheForAllThreads) { - this(manager, numArenas, pageSize, maxOrder, - smallCacheSize, normalCacheSize, - useCacheForAllThreads, DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT); - } - - public PooledBufferAllocator(MemoryManager manager, int numArenas, int pageSize, int maxOrder, - int smallCacheSize, int normalCacheSize, - boolean useCacheForAllThreads, int directMemoryCacheAlignment) { - this.manager = requireNonNull(manager, "MemoryManager"); - threadCache = new PoolThreadLocalCache(useCacheForAllThreads); - this.smallCacheSize = smallCacheSize; - this.normalCacheSize = normalCacheSize; - - if (directMemoryCacheAlignment != 0) { - if (!PlatformDependent.hasAlignDirectByteBuffer()) { - throw new UnsupportedOperationException("Buffer alignment is not supported. " + - "Either Unsafe or ByteBuffer.alignSlice() must be available."); - } - - // Ensure page size is a whole multiple of the alignment, or bump it to the next whole multiple. - pageSize = (int) PlatformDependent.align(pageSize, directMemoryCacheAlignment); - } - - chunkSize = validateAndCalculateChunkSize(pageSize, maxOrder); - - checkPositiveOrZero(numArenas, "numArenas"); - - checkPositiveOrZero(directMemoryCacheAlignment, "directMemoryCacheAlignment"); - if (directMemoryCacheAlignment > 0 && !isDirectMemoryCacheAlignmentSupported()) { - throw new IllegalArgumentException("directMemoryCacheAlignment is not supported"); - } - - if ((directMemoryCacheAlignment & -directMemoryCacheAlignment) != directMemoryCacheAlignment) { - throw new IllegalArgumentException("directMemoryCacheAlignment: " - + directMemoryCacheAlignment + " (expected: power of two)"); - } - - int pageShifts = validateAndCalculatePageShifts(pageSize, directMemoryCacheAlignment); - - if (numArenas > 0) { - arenas = newArenaArray(numArenas); - List metrics = new ArrayList<>(arenas.length); - for (int i = 0; i < arenas.length; i ++) { - PoolArena arena = new PoolArena(this, manager, - pageSize, pageShifts, chunkSize, - directMemoryCacheAlignment); - arenas[i] = arena; - metrics.add(arena); - } - arenaMetrics = metrics; - arenaMetricsView = Collections.unmodifiableList(metrics); - } else { - arenas = null; - arenaMetrics = new ArrayList<>(1); - arenaMetricsView = Collections.emptyList(); - } - - metric = new PooledBufferAllocatorMetric(this); - } - - private static PoolArena[] newArenaArray(int size) { - return new PoolArena[size]; - } - - private static int validateAndCalculatePageShifts(int pageSize, int alignment) { - if (pageSize < MIN_PAGE_SIZE) { - throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: " + MIN_PAGE_SIZE + ')'); - } - - if ((pageSize & pageSize - 1) != 0) { - throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: power of 2)"); - } - - if (pageSize < alignment) { - throw new IllegalArgumentException("Alignment cannot be greater than page size. " + - "Alignment: " + alignment + ", page size: " + pageSize + '.'); - } - - // Logarithm base 2. At this point we know that pageSize is a power of two. - return Integer.SIZE - 1 - Integer.numberOfLeadingZeros(pageSize); - } - - private static int validateAndCalculateChunkSize(int pageSize, int maxOrder) { - if (maxOrder > 14) { - throw new IllegalArgumentException("maxOrder: " + maxOrder + " (expected: 0-14)"); - } - - // Ensure the resulting chunkSize does not overflow. - int chunkSize = pageSize; - for (int i = maxOrder; i > 0; i--) { - if (chunkSize > MAX_CHUNK_SIZE / 2) { - throw new IllegalArgumentException(String.format( - "pageSize (%d) << maxOrder (%d) must not exceed %d", pageSize, maxOrder, MAX_CHUNK_SIZE)); - } - chunkSize <<= 1; - } - return chunkSize; - } - - @Override - public Buffer allocate(int size) { - if (size < 1) { - throw new IllegalArgumentException("Allocation size must be positive, but was " + size + '.'); - } - PooledAllocatorControl control = new PooledAllocatorControl(); - control.parent = this; - UntetheredMemory memory = allocate(control, size); - Buffer buffer = manager.recoverMemory(control, memory.memory(), memory.drop()); - return buffer.fill((byte) 0).order(ByteOrder.nativeOrder()); - } - - UntetheredMemory allocate(PooledAllocatorControl control, int size) { - PoolThreadCache cache = threadCache.get(); - PoolArena arena = cache.arena; - - if (arena != null) { - return arena.allocate(control, cache, size); - } - return allocateUnpooled(size); - } - - private UntetheredMemory allocateUnpooled(int size) { - return new UnpooledUnthetheredMemory(this, manager, size); - } - - @Override - public void close() { - trimCurrentThreadCache(); - threadCache.remove(); - for (int i = 0, arenasLength = arenas.length; i < arenasLength; i++) { - PoolArena arena = arenas[i]; - if (arena != null) { - arena.close(); - arenas[i] = null; - } - } - arenaMetrics.clear(); - } - - /** - * Default number of heap arenas - System Property: io.netty.allocator.numHeapArenas - default 2 * cores - */ - public static int defaultNumHeapArena() { - return DEFAULT_NUM_HEAP_ARENA; - } - - /** - * Default number of direct arenas - System Property: io.netty.allocator.numDirectArenas - default 2 * cores - */ - public static int defaultNumDirectArena() { - return DEFAULT_NUM_DIRECT_ARENA; - } - - /** - * Default buffer page size - System Property: io.netty.allocator.pageSize - default 8192 - */ - public static int defaultPageSize() { - return DEFAULT_PAGE_SIZE; - } - - /** - * Default maximum order - System Property: io.netty.allocator.maxOrder - default 11 - */ - public static int defaultMaxOrder() { - return DEFAULT_MAX_ORDER; - } - - /** - * Default thread caching behavior - System Property: io.netty.allocator.useCacheForAllThreads - default true - */ - public static boolean defaultUseCacheForAllThreads() { - return DEFAULT_USE_CACHE_FOR_ALL_THREADS; - } - - /** - * Default prefer direct - System Property: io.netty.noPreferDirect - default false - */ - public static boolean defaultPreferDirect() { - return PlatformDependent.directBufferPreferred(); - } - - /** - * Default small cache size - System Property: io.netty.allocator.smallCacheSize - default 256 - */ - public static int defaultSmallCacheSize() { - return DEFAULT_SMALL_CACHE_SIZE; - } - - /** - * Default normal cache size - System Property: io.netty.allocator.normalCacheSize - default 64 - */ - public static int defaultNormalCacheSize() { - return DEFAULT_NORMAL_CACHE_SIZE; - } - - /** - * Return {@code true} if direct memory cache alignment is supported, {@code false} otherwise. - */ - public static boolean isDirectMemoryCacheAlignmentSupported() { - return PlatformDependent.hasUnsafe(); - } - - public boolean isDirectBufferPooled() { - return manager.isNative(); - } - - public int numArenas() { - return arenas.length; - } - - final class PoolThreadLocalCache extends FastThreadLocal { - private final boolean useCacheForAllThreads; - - PoolThreadLocalCache(boolean useCacheForAllThreads) { - this.useCacheForAllThreads = useCacheForAllThreads; - } - - @Override - protected synchronized PoolThreadCache initialValue() { - final PoolArena arena = leastUsedArena(arenas); - - final Thread current = Thread.currentThread(); - if (useCacheForAllThreads || current instanceof FastThreadLocalThread) { - final PoolThreadCache cache = new PoolThreadCache( - arena, smallCacheSize, normalCacheSize, - DEFAULT_MAX_CACHED_BUFFER_CAPACITY, DEFAULT_CACHE_TRIM_INTERVAL); - - if (DEFAULT_CACHE_TRIM_INTERVAL_MILLIS > 0) { - final EventExecutor executor = ThreadExecutorMap.currentExecutor(); - if (executor != null) { - executor.scheduleAtFixedRate(trimTask, DEFAULT_CACHE_TRIM_INTERVAL_MILLIS, - DEFAULT_CACHE_TRIM_INTERVAL_MILLIS, TimeUnit.MILLISECONDS); - } - } - return cache; - } - // No caching so just use 0 as sizes. - return new PoolThreadCache(null, 0, 0, 0, 0); - } - - @Override - protected void onRemoval(PoolThreadCache threadCache) { - threadCache.free(); - } - } - - static PoolArena leastUsedArena(PoolArena[] arenas) { - if (arenas == null || arenas.length == 0) { - return null; - } - - PoolArena minArena = arenas[0]; - for (int i = 1; i < arenas.length; i++) { - PoolArena arena = arenas[i]; - if (arena.numThreadCaches.get() < minArena.numThreadCaches.get()) { - minArena = arena; - } - } - - return minArena; - } - - @Override - public PooledBufferAllocatorMetric metric() { - return metric; - } - - /** - * Return a {@link List} of all heap {@link PoolArenaMetric}s that are provided by this pool. - */ - List arenaMetrics() { - return arenaMetricsView; - } - - /** - * Return the number of thread local caches used by this {@link PooledBufferAllocator}. - */ - int numThreadLocalCaches() { - if (arenas == null) { - return 0; - } - - int total = 0; - for (PoolArena arena : arenas) { - total += arena.numThreadCaches.get(); - } - - return total; - } - - /** - * Return the size of the small cache. - */ - int smallCacheSize() { - return smallCacheSize; - } - - /** - * Return the size of the normal cache. - */ - int normalCacheSize() { - return normalCacheSize; - } - - /** - * Return the chunk size for an arena. - */ - final int chunkSize() { - return chunkSize; - } - - final long usedMemory() { - return usedMemory(arenas); - } - - private static long usedMemory(PoolArena[] arenas) { - if (arenas == null) { - return -1; - } - long used = 0; - for (PoolArena arena : arenas) { - used += arena.numActiveBytes(); - if (used < 0) { - return Long.MAX_VALUE; - } - } - return used; - } - - final PoolThreadCache threadCache() { - PoolThreadCache cache = threadCache.get(); - assert cache != null; - return cache; - } - - /** - * Trim thread local cache for the current {@link Thread}, which will give back any cached memory that was not - * allocated frequently since the last trim operation. - * - * Returns {@code true} if a cache for the current {@link Thread} exists and so was trimmed, false otherwise. - */ - public boolean trimCurrentThreadCache() { - PoolThreadCache cache = threadCache.getIfExists(); - if (cache != null) { - cache.trim(); - return true; - } - return false; - } - - /** - * Returns the status of the allocator (which contains all metrics) as string. Be aware this may be expensive - * and so should not be called too frequently. - */ - public String dumpStats() { - int heapArenasLen = arenas == null ? 0 : arenas.length; - StringBuilder buf = new StringBuilder(512) - .append(heapArenasLen) - .append(" arena(s):") - .append(StringUtil.NEWLINE); - if (heapArenasLen > 0) { - for (PoolArena a: arenas) { - buf.append(a); - } - } - - return buf.toString(); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocatorMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocatorMetric.java deleted file mode 100644 index e4d4f04..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledBufferAllocatorMetric.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.util.internal.StringUtil; - -import java.util.List; - -/** - * Exposed metric for {@link PooledBufferAllocator}. - */ -final class PooledBufferAllocatorMetric implements BufferAllocatorMetric { - - private final PooledBufferAllocator allocator; - - PooledBufferAllocatorMetric(PooledBufferAllocator allocator) { - this.allocator = allocator; - } - - /** - * Return the number of arenas. - */ - public int numArenas() { - return allocator.numArenas(); - } - - /** - * Return a {@link List} of all {@link PoolArenaMetric}s that are provided by this pool. - */ - public List arenaMetrics() { - return allocator.arenaMetrics(); - } - - /** - * Return the number of thread local caches used by this {@link PooledBufferAllocator}. - */ - public int numThreadLocalCaches() { - return allocator.numThreadLocalCaches(); - } - - /** - * Return the size of the small cache. - */ - public int smallCacheSize() { - return allocator.smallCacheSize(); - } - - /** - * Return the size of the normal cache. - */ - public int normalCacheSize() { - return allocator.normalCacheSize(); - } - - /** - * Return the chunk size for an arena. - */ - public int chunkSize() { - return allocator.chunkSize(); - } - - @Override - public long usedMemory() { - return allocator.usedMemory(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(256); - sb.append(StringUtil.simpleClassName(this)) - .append("(usedMemory: ").append(usedMemory()) - .append("; numArenas: ").append(numArenas()) - .append("; smallCacheSize: ").append(smallCacheSize()) - .append("; normalCacheSize: ").append(normalCacheSize()) - .append("; numThreadLocalCaches: ").append(numThreadLocalCaches()) - .append("; chunkSize: ").append(chunkSize()).append(')'); - return sb.toString(); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledDrop.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledDrop.java deleted file mode 100644 index a3191a2..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/PooledDrop.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.Drop; - -class PooledDrop implements Drop { - private final PoolArena arena; - private final PoolChunk chunk; - private final PoolThreadCache threadCache; - private final long handle; - private final int normSize; - - PooledDrop(PoolArena arena, PoolChunk chunk, PoolThreadCache threadCache, long handle, int normSize) { - this.arena = arena; - this.chunk = chunk; - this.threadCache = threadCache; - this.handle = handle; - this.normSize = normSize; - } - - @Override - public void drop(Buffer obj) { - arena.free(chunk, handle, normSize, threadCache); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClasses.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClasses.java deleted file mode 100644 index 534cdf1..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClasses.java +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import java.util.concurrent.ConcurrentHashMap; - -/** - * SizeClasses requires {@code pageShifts} to be defined prior to inclusion, - * and it in turn defines: - *

- * LOG2_SIZE_CLASS_GROUP: Log of size class count for each size doubling. - * LOG2_MAX_LOOKUP_SIZE: Log of max size class in the lookup table. - * sizeClasses: Complete table of [index, log2Group, log2Delta, nDelta, isMultiPageSize, - * isSubPage, log2DeltaLookup] tuples. - * index: Size class index. - * log2Group: Log of group base size (no deltas added). - * log2Delta: Log of delta to previous size class. - * nDelta: Delta multiplier. - * isMultiPageSize: 'yes' if a multiple of the page size, 'no' otherwise. - * isSubPage: 'yes' if a subpage size class, 'no' otherwise. - * log2DeltaLookup: Same as log2Delta if a lookup table size class, 'no' - * otherwise. - *

- * nSubpages: Number of subpages size classes. - * nSizes: Number of size classes. - * nPSizes: Number of size classes that are multiples of pageSize. - * - * smallMaxSizeIdx: Maximum small size class index. - * - * lookupMaxclass: Maximum size class included in lookup table. - * log2NormalMinClass: Log of minimum normal size class. - *

- * The first size class and spacing are 1 << LOG2_QUANTUM. - * Each group has 1 << LOG2_SIZE_CLASS_GROUP of size classes. - * - * size = 1 << log2Group + nDelta * (1 << log2Delta) - * - * The first size class has an unusual encoding, because the size has to be - * split between group and delta*nDelta. - * - * If pageShift = 13, sizeClasses looks like this: - * - * (index, log2Group, log2Delta, nDelta, isMultiPageSize, isSubPage, log2DeltaLookup) - *

- * ( 0, 4, 4, 0, no, yes, 4) - * ( 1, 4, 4, 1, no, yes, 4) - * ( 2, 4, 4, 2, no, yes, 4) - * ( 3, 4, 4, 3, no, yes, 4) - *

- * ( 4, 6, 4, 1, no, yes, 4) - * ( 5, 6, 4, 2, no, yes, 4) - * ( 6, 6, 4, 3, no, yes, 4) - * ( 7, 6, 4, 4, no, yes, 4) - *

- * ( 8, 7, 5, 1, no, yes, 5) - * ( 9, 7, 5, 2, no, yes, 5) - * ( 10, 7, 5, 3, no, yes, 5) - * ( 11, 7, 5, 4, no, yes, 5) - * ... - * ... - * ( 72, 23, 21, 1, yes, no, no) - * ( 73, 23, 21, 2, yes, no, no) - * ( 74, 23, 21, 3, yes, no, no) - * ( 75, 23, 21, 4, yes, no, no) - *

- * ( 76, 24, 22, 1, yes, no, no) - */ -abstract class SizeClasses implements SizeClassesMetric { - private static final ConcurrentHashMap CACHE = - new ConcurrentHashMap(); - - static final int LOG2_QUANTUM = 4; - - private static final int LOG2_SIZE_CLASS_GROUP = 2; - private static final int LOG2_MAX_LOOKUP_SIZE = 12; - - private static final int LOG2GROUP_IDX = 1; - private static final int LOG2DELTA_IDX = 2; - private static final int NDELTA_IDX = 3; - private static final int PAGESIZE_IDX = 4; - private static final int SUBPAGE_IDX = 5; - private static final int LOG2_DELTA_LOOKUP_IDX = 6; - - private static final byte no = 0, yes = 1; - - protected SizeClasses(int pageSize, int pageShifts, int chunkSize, int directMemoryCacheAlignment) { - this.pageSize = pageSize; - this.pageShifts = pageShifts; - this.chunkSize = chunkSize; - this.directMemoryCacheAlignment = directMemoryCacheAlignment; - - SizeClassValue value = CACHE.computeIfAbsent( - new SizeClassKey(pageSize, pageShifts, chunkSize, directMemoryCacheAlignment), - SizeClassValue::new); - nSizes = value.nSizes; - nSubpages = value.nSubpages; - nPSizes = value.nPSizes; - smallMaxSizeIdx = value.smallMaxSizeIdx; - lookupMaxSize = value.lookupMaxSize; - pageIdx2sizeTab = value.pageIdx2sizeTab; - sizeIdx2sizeTab = value.sizeIdx2sizeTab; - size2idxTab = value.size2idxTab; - } - - protected final int pageSize; - protected final int pageShifts; - protected final int chunkSize; - protected final int directMemoryCacheAlignment; - - final int nSizes; - final int nSubpages; - final int nPSizes; - final int smallMaxSizeIdx; - - private final int lookupMaxSize; - private final int[] pageIdx2sizeTab; - - // lookup table for sizeIdx <= smallMaxSizeIdx - private final int[] sizeIdx2sizeTab; - - // lookup table used for size <= lookupMaxclass - // spacing is 1 << LOG2_QUANTUM, so the size of array is lookupMaxclass >> LOG2_QUANTUM - private final int[] size2idxTab; - - @Override - public int sizeIdx2size(int sizeIdx) { - return sizeIdx2sizeTab[sizeIdx]; - } - - @Override - public int sizeIdx2sizeCompute(int sizeIdx) { - int group = sizeIdx >> LOG2_SIZE_CLASS_GROUP; - int mod = sizeIdx & (1 << LOG2_SIZE_CLASS_GROUP) - 1; - - int groupSize = group == 0? 0 : - 1 << LOG2_QUANTUM + LOG2_SIZE_CLASS_GROUP - 1 << group; - - int shift = group == 0? 1 : group; - int lgDelta = shift + LOG2_QUANTUM - 1; - int modSize = mod + 1 << lgDelta; - - return groupSize + modSize; - } - - @Override - public long pageIdx2size(int pageIdx) { - return pageIdx2sizeTab[pageIdx]; - } - - @Override - public long pageIdx2sizeCompute(int pageIdx) { - int group = pageIdx >> LOG2_SIZE_CLASS_GROUP; - int mod = pageIdx & (1 << LOG2_SIZE_CLASS_GROUP) - 1; - - long groupSize = group == 0? 0 : - 1L << pageShifts + LOG2_SIZE_CLASS_GROUP - 1 << group; - - int shift = group == 0? 1 : group; - int log2Delta = shift + pageShifts - 1; - int modSize = mod + 1 << log2Delta; - - return groupSize + modSize; - } - - @Override - public int size2SizeIdx(int size) { - if (size == 0) { - return 0; - } - if (size > chunkSize) { - return nSizes; - } - - if (directMemoryCacheAlignment > 0) { - size = alignSize(size); - } - - if (size <= lookupMaxSize) { - //size-1 / MIN_TINY - return size2idxTab[size - 1 >> LOG2_QUANTUM]; - } - - int x = PoolThreadCache.log2((size << 1) - 1); - int shift = x < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM + 1 - ? 0 : x - (LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM); - - int group = shift << LOG2_SIZE_CLASS_GROUP; - - int log2Delta = x < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM + 1 - ? LOG2_QUANTUM : x - LOG2_SIZE_CLASS_GROUP - 1; - - int deltaInverseMask = -1 << log2Delta; - int mod = (size - 1 & deltaInverseMask) >> log2Delta & - (1 << LOG2_SIZE_CLASS_GROUP) - 1; - - return group + mod; - } - - @Override - public int pages2pageIdx(int pages) { - return pages2pageIdxCompute(pages, false); - } - - @Override - public int pages2pageIdxFloor(int pages) { - return pages2pageIdxCompute(pages, true); - } - - private int pages2pageIdxCompute(int pages, boolean floor) { - int pageSize = pages << pageShifts; - if (pageSize > chunkSize) { - return nPSizes; - } - - int x = PoolThreadCache.log2((pageSize << 1) - 1); - - int shift = x < LOG2_SIZE_CLASS_GROUP + pageShifts - ? 0 : x - (LOG2_SIZE_CLASS_GROUP + pageShifts); - - int group = shift << LOG2_SIZE_CLASS_GROUP; - - int log2Delta = x < LOG2_SIZE_CLASS_GROUP + pageShifts + 1? - pageShifts : x - LOG2_SIZE_CLASS_GROUP - 1; - - int deltaInverseMask = -1 << log2Delta; - int mod = (pageSize - 1 & deltaInverseMask) >> log2Delta & - (1 << LOG2_SIZE_CLASS_GROUP) - 1; - - int pageIdx = group + mod; - - if (floor && pageIdx2sizeTab[pageIdx] > pages << pageShifts) { - pageIdx--; - } - - return pageIdx; - } - - // Round size up to the nearest multiple of alignment. - private int alignSize(int size) { - int delta = size & directMemoryCacheAlignment - 1; - return delta == 0? size : size + directMemoryCacheAlignment - delta; - } - - @Override - public int normalizeSize(int size) { - if (size == 0) { - return sizeIdx2sizeTab[0]; - } - if (directMemoryCacheAlignment > 0) { - size = alignSize(size); - } - - if (size <= lookupMaxSize) { - int ret = sizeIdx2sizeTab[size2idxTab[size - 1 >> LOG2_QUANTUM]]; - assert ret == normalizeSizeCompute(size); - return ret; - } - return normalizeSizeCompute(size); - } - - private static int normalizeSizeCompute(int size) { - int x = PoolThreadCache.log2((size << 1) - 1); - int log2Delta = x < LOG2_SIZE_CLASS_GROUP + LOG2_QUANTUM + 1 - ? LOG2_QUANTUM : x - LOG2_SIZE_CLASS_GROUP - 1; - int delta = 1 << log2Delta; - int delta_mask = delta - 1; - return size + delta_mask & ~delta_mask; - } - - private static final class SizeClassKey { - final int pageSize; - final int pageShifts; - final int chunkSize; - final int directMemoryCacheAlignment; - - private SizeClassKey(int pageSize, int pageShifts, int chunkSize, int directMemoryCacheAlignment) { - this.pageSize = pageSize; - this.pageShifts = pageShifts; - this.chunkSize = chunkSize; - this.directMemoryCacheAlignment = directMemoryCacheAlignment; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SizeClassKey that = (SizeClassKey) o; - - if (pageSize != that.pageSize) { - return false; - } - if (pageShifts != that.pageShifts) { - return false; - } - if (chunkSize != that.chunkSize) { - return false; - } - return directMemoryCacheAlignment == that.directMemoryCacheAlignment; - } - - @Override - public int hashCode() { - int result = pageSize; - result = 31 * result + pageShifts; - result = 31 * result + chunkSize; - result = 31 * result + directMemoryCacheAlignment; - return result; - } - } - - private static final class SizeClassValue { - final SizeClassKey key; - final int nSizes; - int nSubpages; - int nPSizes; - int smallMaxSizeIdx; - int lookupMaxSize; - final short[][] sizeClasses; - final int[] pageIdx2sizeTab; - final int[] sizeIdx2sizeTab; - final int[] size2idxTab; - - SizeClassValue(SizeClassKey key) { - this.key = key; - int group = PoolThreadCache.log2(key.chunkSize) + 1 - LOG2_QUANTUM; - - //generate size classes - //[index, log2Group, log2Delta, nDelta, isMultiPageSize, isSubPage, log2DeltaLookup] - sizeClasses = new short[group << LOG2_SIZE_CLASS_GROUP][7]; - nSizes = sizeClasses(); - - //generate lookup table - sizeIdx2sizeTab = new int[nSizes]; - pageIdx2sizeTab = new int[nPSizes]; - idx2SizeTab(sizeIdx2sizeTab, pageIdx2sizeTab); - - size2idxTab = new int[lookupMaxSize >> LOG2_QUANTUM]; - size2idxTab(size2idxTab); - } - - private int sizeClasses() { - int normalMaxSize = -1; - - int index = 0; - int size = 0; - - int log2Group = LOG2_QUANTUM; - int log2Delta = LOG2_QUANTUM; - int ndeltaLimit = 1 << LOG2_SIZE_CLASS_GROUP; - - //First small group, nDelta start at 0. - //first size class is 1 << LOG2_QUANTUM - int nDelta = 0; - while (nDelta < ndeltaLimit) { - size = sizeClass(index++, log2Group, log2Delta, nDelta++); - } - log2Group += LOG2_SIZE_CLASS_GROUP; - - //All remaining groups, nDelta start at 1. - while (size < key.chunkSize) { - nDelta = 1; - - while (nDelta <= ndeltaLimit && size < key.chunkSize) { - size = sizeClass(index++, log2Group, log2Delta, nDelta++); - normalMaxSize = size; - } - - log2Group++; - log2Delta++; - } - - //chunkSize must be normalMaxSize - assert key.chunkSize == normalMaxSize; - - //return number of size index - return index; - } - - //calculate size class - private int sizeClass(int index, int log2Group, int log2Delta, int nDelta) { - short isMultiPageSize; - if (log2Delta >= key.pageShifts) { - isMultiPageSize = yes; - } else { - int pageSize = 1 << key.pageShifts; - int size = (1 << log2Group) + (1 << log2Delta) * nDelta; - - isMultiPageSize = size == size / pageSize * pageSize? yes : no; - } - - int log2Ndelta = nDelta == 0? 0 : PoolThreadCache.log2(nDelta); - - byte remove = 1 << log2Ndelta < nDelta? yes : no; - - int log2Size = log2Delta + log2Ndelta == log2Group? log2Group + 1 : log2Group; - if (log2Size == log2Group) { - remove = yes; - } - - short isSubpage = log2Size < key.pageShifts + LOG2_SIZE_CLASS_GROUP? yes : no; - - int log2DeltaLookup = log2Size < LOG2_MAX_LOOKUP_SIZE || - log2Size == LOG2_MAX_LOOKUP_SIZE && remove == no - ? log2Delta : no; - - short[] sz = { - (short) index, (short) log2Group, (short) log2Delta, - (short) nDelta, isMultiPageSize, isSubpage, (short) log2DeltaLookup - }; - - sizeClasses[index] = sz; - int size = (1 << log2Group) + (nDelta << log2Delta); - - if (sz[PAGESIZE_IDX] == yes) { - nPSizes++; - } - if (sz[SUBPAGE_IDX] == yes) { - nSubpages++; - smallMaxSizeIdx = index; - } - if (sz[LOG2_DELTA_LOOKUP_IDX] != no) { - lookupMaxSize = size; - } - return size; - } - - private void idx2SizeTab(int[] sizeIdx2sizeTab, int[] pageIdx2sizeTab) { - int pageIdx = 0; - - for (int i = 0; i < nSizes; i++) { - short[] sizeClass = sizeClasses[i]; - int log2Group = sizeClass[LOG2GROUP_IDX]; - int log2Delta = sizeClass[LOG2DELTA_IDX]; - int nDelta = sizeClass[NDELTA_IDX]; - - int size = (1 << log2Group) + (nDelta << log2Delta); - sizeIdx2sizeTab[i] = size; - - if (sizeClass[PAGESIZE_IDX] == yes) { - pageIdx2sizeTab[pageIdx++] = size; - } - } - } - - private void size2idxTab(int[] size2idxTab) { - int idx = 0; - int size = 0; - - for (int i = 0; size <= lookupMaxSize; i++) { - int log2Delta = sizeClasses[i][LOG2DELTA_IDX]; - int times = 1 << log2Delta - LOG2_QUANTUM; - - while (size <= lookupMaxSize && times-- > 0) { - size2idxTab[idx++] = i; - size = idx + 1 << LOG2_QUANTUM; - } - } - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClassesMetric.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClassesMetric.java deleted file mode 100644 index 3f3ac3e..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/SizeClassesMetric.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -/** - * Expose metrics for an SizeClasses. - */ -public interface SizeClassesMetric { - - /** - * Computes size from lookup table according to sizeIdx. - * - * @return size - */ - int sizeIdx2size(int sizeIdx); - - /** - * Computes size according to sizeIdx. - * - * @return size - */ - int sizeIdx2sizeCompute(int sizeIdx); - - /** - * Computes size from lookup table according to pageIdx. - * - * @return size which is multiples of pageSize. - */ - long pageIdx2size(int pageIdx); - - /** - * Computes size according to pageIdx. - * - * @return size which is multiples of pageSize - */ - long pageIdx2sizeCompute(int pageIdx); - - /** - * Normalizes request size up to the nearest size class. - * - * @param size request size - * - * @return sizeIdx of the size class - */ - int size2SizeIdx(int size); - - /** - * Normalizes request size up to the nearest pageSize class. - * - * @param pages multiples of pageSizes - * - * @return pageIdx of the pageSize class - */ - int pages2pageIdx(int pages); - - /** - * Normalizes request size down to the nearest pageSize class. - * - * @param pages multiples of pageSizes - * - * @return pageIdx of the pageSize class - */ - int pages2pageIdxFloor(int pages); - - /** - * Normalizes usable size that would result from allocating an object with the - * specified size and alignment. - * - * @param size request size - * - * @return normalized size - */ - int normalizeSize(int size); -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/UnpooledUnthetheredMemory.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/UnpooledUnthetheredMemory.java deleted file mode 100644 index 475087f..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/UnpooledUnthetheredMemory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.pool; - -import io.netty.buffer.api.AllocatorControl; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.MemoryManager; -import io.netty.buffer.api.internal.Statics; - -@SuppressWarnings("unchecked") -class UnpooledUnthetheredMemory implements AllocatorControl.UntetheredMemory { - private final MemoryManager manager; - private final Buffer buffer; - - UnpooledUnthetheredMemory(PooledBufferAllocator allocator, MemoryManager manager, int size) { - this.manager = manager; - PooledAllocatorControl allocatorControl = new PooledAllocatorControl(); - allocatorControl.parent = allocator; - buffer = manager.allocateShared(allocatorControl, size, manager.drop(), Statics.CLEANER); - } - - @Override - public Memory memory() { - return (Memory) manager.unwrapRecoverableMemory(buffer); - } - - @Override - public Drop drop() { - return (Drop) manager.drop(); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/pool/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/pool/package-info.java deleted file mode 100644 index ce60c3b..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/pool/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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. - */ -/** - * A pooling {@link io.netty.buffer.api.BufferAllocator} implementation based on jemalloc. - */ -package io.netty.buffer.api.pool; diff --git a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/CleanerDrop.java b/buffer-api/src/main/java/io/netty/buffer/api/unsafe/CleanerDrop.java deleted file mode 100644 index d252936..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/CleanerDrop.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.unsafe; - -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.Drop; -import io.netty.util.internal.PlatformDependent; - -import java.lang.ref.Cleaner; - -public class CleanerDrop implements Drop { - private final Drop drop; - - public CleanerDrop(UnsafeMemory memory, Drop drop, Cleaner cleaner) { - this.drop = drop; - long address = memory.address; - cleaner.register(memory, new FreeAddress(address)); - } - - @Override - public void drop(Buffer obj) { - drop.drop(obj); - } - - @Override - public void attach(Buffer obj) { - drop.attach(obj); - } - - private static class FreeAddress implements Runnable { - private final long address; - - FreeAddress(long address) { - this.address = address; - } - - @Override - public void run() { - PlatformDependent.freeMemory(address); - } - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeBuffer.java b/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeBuffer.java deleted file mode 100644 index d0920e9..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeBuffer.java +++ /dev/null @@ -1,1690 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.unsafe; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.api.BufferAllocator; -import io.netty.buffer.api.AllocatorControl; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.BufferReadOnlyException; -import io.netty.buffer.api.ByteCursor; -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.Owned; -import io.netty.buffer.api.adaptor.BufferIntegratable; -import io.netty.buffer.api.adaptor.ByteBufAdaptor; -import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor; -import io.netty.buffer.api.internal.ResourceSupport; -import io.netty.buffer.api.ReadableComponent; -import io.netty.buffer.api.ReadableComponentProcessor; -import io.netty.buffer.api.WritableComponent; -import io.netty.buffer.api.WritableComponentProcessor; -import io.netty.buffer.api.internal.ArcDrop; -import io.netty.buffer.api.internal.Statics; -import io.netty.util.IllegalReferenceCountException; -import io.netty.util.ReferenceCounted; -import io.netty.util.internal.PlatformDependent; - -import java.lang.ref.Reference; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import static io.netty.buffer.api.internal.Statics.bbslice; -import static io.netty.buffer.api.internal.Statics.bufferIsClosed; -import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly; -import static io.netty.util.internal.PlatformDependent.BIG_ENDIAN_NATIVE_ORDER; - -class UnsafeBuffer extends ResourceSupport implements Buffer, ReadableComponent, - WritableComponent, BufferIntegratable { - private static final int CLOSED_SIZE = -1; - private static final boolean ACCESS_UNALIGNED = PlatformDependent.isUnaligned(); - private UnsafeMemory memory; // The memory liveness; monitored by Cleaner. - private Object base; // On-heap address reference object, or null for off-heap. - private long baseOffset; // Offset of this buffer into the memory. - private long address; // Resolved address (baseOffset + memory.address). - private int rsize; - private int wsize; - private final AllocatorControl control; - private ByteOrder order; - private boolean flipBytes; - private boolean readOnly; - private int roff; - private int woff; - private boolean constBuffer; - - UnsafeBuffer(UnsafeMemory memory, long offset, int size, AllocatorControl allocatorControl, - Drop drop) { - super(new MakeInaccessibleOnDrop(ArcDrop.wrap(drop))); - this.memory = memory; - base = memory.base; - baseOffset = offset; - address = memory.address + offset; - rsize = size; - wsize = size; - control = allocatorControl; - order = ByteOrder.nativeOrder(); - } - - UnsafeBuffer(UnsafeBuffer parent) { - super(new MakeInaccessibleOnDrop(new ArcDrop<>(ArcDrop.acquire(parent.unsafeGetDrop())))); - control = parent.control; - memory = parent.memory; - base = parent.base; - baseOffset = parent.baseOffset; - address = parent.address; - rsize = parent.rsize; - wsize = parent.wsize; - order = parent.order; - flipBytes = parent.flipBytes; - readOnly = parent.readOnly; - roff = parent.roff; - woff = parent.woff; - constBuffer = true; - } - - @Override - public String toString() { - return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + rsize + ']'; - } - - @Override - protected RuntimeException createResourceClosedException() { - return bufferIsClosed(this); - } - - @Override - public Buffer order(ByteOrder order) { - this.order = order; - flipBytes = order != ByteOrder.nativeOrder(); - return this; - } - - @Override - public ByteOrder order() { - return order; - } - - @Override - public int capacity() { - return Math.max(0, rsize); // Use Math.max to make capacity of closed buffer equal to zero. - } - - @Override - public int readerOffset() { - return roff; - } - - @Override - public Buffer readerOffset(int offset) { - checkRead(offset, 0); - roff = offset; - return this; - } - - @Override - public int writerOffset() { - return woff; - } - - @Override - public Buffer writerOffset(int offset) { - checkWrite(offset, 0); - woff = offset; - return this; - } - - @Override - public Buffer fill(byte value) { - checkSet(0, capacity()); - if (rsize == CLOSED_SIZE) { - throw bufferIsClosed(this); - } - try { - PlatformDependent.setMemory(base, address, rsize, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public long nativeAddress() { - return base == null? address : 0; - } - - @Override - public Buffer makeReadOnly() { - readOnly = true; - wsize = CLOSED_SIZE; - return this; - } - - @Override - public boolean readOnly() { - return readOnly; - } - - @Override - public Buffer copy(int offset, int length) { - checkGet(offset, length); - int allocSize = Math.max(length, 1); // Allocators don't support allocating zero-sized buffers. - AllocatorControl.UntetheredMemory memory = control.allocateUntethered(this, allocSize); - UnsafeMemory unsafeMemory = memory.memory(); - Buffer copy = new UnsafeBuffer(unsafeMemory, 0, length, control, memory.drop()); - copyInto(offset, copy, 0, length); - copy.writerOffset(length).order(order); - if (readOnly) { - copy = copy.makeReadOnly(); - } - return copy; - } - - @Override - public void copyInto(int srcPos, byte[] dest, int destPos, int length) { - checkCopyIntoArgs(srcPos, length, destPos, dest.length); - copyIntoArray(srcPos, dest, destPos, length); - } - - private void copyIntoArray(int srcPos, byte[] dest, int destPos, int length) { - long destOffset = PlatformDependent.byteArrayBaseOffset(); - try { - PlatformDependent.copyMemory(base, address + srcPos, dest, destOffset + destPos, length); - } finally { - Reference.reachabilityFence(memory); - Reference.reachabilityFence(dest); - } - } - - @Override - public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) { - checkCopyIntoArgs(srcPos, length, destPos, dest.capacity()); - if (dest.hasArray()) { - copyIntoArray(srcPos, dest.array(), dest.arrayOffset() + destPos, length); - } else { - assert dest.isDirect(); - long destAddr = PlatformDependent.directBufferAddress(dest); - try { - PlatformDependent.copyMemory(base, address + srcPos, null, destAddr + destPos, length); - } finally { - Reference.reachabilityFence(memory); - Reference.reachabilityFence(dest); - } - } - } - - private void checkCopyIntoArgs(int srcPos, int length, int destPos, int destLength) { - if (rsize == CLOSED_SIZE) { - throw bufferIsClosed(this); - } - if (srcPos < 0) { - throw new IllegalArgumentException("The srcPos cannot be negative: " + srcPos + '.'); - } - if (length < 0) { - throw new IllegalArgumentException("The length cannot be negative: " + length + '.'); - } - if (rsize < srcPos + length) { - throw new IllegalArgumentException("The srcPos + length is beyond the end of the buffer: " + - "srcPos = " + srcPos + ", length = " + length + '.'); - } - if (destPos < 0) { - throw new IllegalArgumentException("The destPos cannot be negative: " + destPos + '.'); - } - if (destLength < destPos + length) { - throw new IllegalArgumentException("The destPos + length is beyond the end of the destination: " + - "destPos = " + destPos + ", length = " + length + '.'); - } - } - - @Override - public void copyInto(int srcPos, Buffer dest, int destPos, int length) { - checkCopyIntoArgs(srcPos, length, destPos, dest.capacity()); - if (dest.readOnly()) { - throw bufferIsReadOnly(this); - } - long nativeAddress = dest.nativeAddress(); - try { - if (nativeAddress != 0) { - PlatformDependent.copyMemory(base, address + srcPos, null, nativeAddress + destPos, length); - } else if (dest instanceof UnsafeBuffer) { - UnsafeBuffer destUnsafe = (UnsafeBuffer) dest; - PlatformDependent.copyMemory( - base, address + srcPos, destUnsafe.base, destUnsafe.address + destPos, length); - } else { - Statics.copyToViaReverseCursor(this, srcPos, dest, destPos, length); - } - } finally { - Reference.reachabilityFence(memory); - Reference.reachabilityFence(dest); - } - } - - @Override - public ByteCursor openCursor() { - return openCursor(readerOffset(), readableBytes()); - } - - @Override - public ByteCursor openCursor(int fromOffset, int length) { - if (rsize == CLOSED_SIZE) { - throw bufferIsClosed(this); - } - if (fromOffset < 0) { - throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.'); - } - if (length < 0) { - throw new IllegalArgumentException("The length cannot be negative: " + length + '.'); - } - if (capacity() < fromOffset + length) { - throw new IllegalArgumentException("The fromOffset + length is beyond the end of the buffer: " + - "fromOffset = " + fromOffset + ", length = " + length + '.'); - } - return new ByteCursor() { - final UnsafeMemory memory = UnsafeBuffer.this.memory; // Keep memory alive. - final Object baseObj = base; - final long baseAddress = address; - int index = fromOffset; - final int end = index + length; - long longValue = -1; - byte byteValue = -1; - - @Override - public boolean readLong() { - if (index + Long.BYTES <= end) { - try { - long value = PlatformDependent.getLong(baseObj, baseAddress + index); - longValue = BIG_ENDIAN_NATIVE_ORDER? value : Long.reverseBytes(value); - } finally { - Reference.reachabilityFence(memory); - } - index += Long.BYTES; - return true; - } - return false; - } - - @Override - public long getLong() { - return longValue; - } - - @Override - public boolean readByte() { - if (index < end) { - try { - byteValue = PlatformDependent.getByte(baseObj, baseAddress + index); - } finally { - Reference.reachabilityFence(memory); - } - index++; - return true; - } - return false; - } - - @Override - public byte getByte() { - return byteValue; - } - - @Override - public int currentOffset() { - return index; - } - - @Override - public int bytesLeft() { - return end - index; - } - }; - } - - @Override - public ByteCursor openReverseCursor(int fromOffset, int length) { - if (rsize == CLOSED_SIZE) { - throw bufferIsClosed(this); - } - if (fromOffset < 0) { - throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.'); - } - if (length < 0) { - throw new IllegalArgumentException("The length cannot be negative: " + length + '.'); - } - if (capacity() <= fromOffset) { - throw new IllegalArgumentException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.'); - } - if (fromOffset - length < -1) { - throw new IllegalArgumentException("The fromOffset - length would underflow the buffer: " + - "fromOffset = " + fromOffset + ", length = " + length + '.'); - } - return new ByteCursor() { - final UnsafeMemory memory = UnsafeBuffer.this.memory; // Keep memory alive. - final Object baseObj = base; - final long baseAddress = address; - int index = fromOffset; - final int end = index - length; - long longValue = -1; - byte byteValue = -1; - - @Override - public boolean readLong() { - if (index - Long.BYTES >= end) { - index -= 7; - try { - long value = PlatformDependent.getLong(baseObj, baseAddress + index); - longValue = BIG_ENDIAN_NATIVE_ORDER? Long.reverseBytes(value) : value; - } finally { - Reference.reachabilityFence(memory); - } - index--; - return true; - } - return false; - } - - @Override - public long getLong() { - return longValue; - } - - @Override - public boolean readByte() { - if (index > end) { - try { - byteValue = PlatformDependent.getByte(baseObj, baseAddress + index); - } finally { - Reference.reachabilityFence(memory); - } - index--; - return true; - } - return false; - } - - @Override - public byte getByte() { - return byteValue; - } - - @Override - public int currentOffset() { - return index; - } - - @Override - public int bytesLeft() { - return index - end; - } - }; - } - - @Override - public void ensureWritable(int size, int minimumGrowth, boolean allowCompaction) { - if (!isAccessible()) { - throw bufferIsClosed(this); - } - if (!isOwned()) { - throw attachTrace(new IllegalStateException( - "Buffer is not owned. Only owned buffers can call ensureWritable.")); - } - if (size < 0) { - throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.'); - } - if (minimumGrowth < 0) { - throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.'); - } - if (rsize != wsize) { - throw bufferIsReadOnly(this); - } - if (writableBytes() >= size) { - // We already have enough space. - return; - } - - if (allowCompaction && writableBytes() + readerOffset() >= size) { - // We can solve this with compaction. - compact(); - return; - } - - // Allocate a bigger buffer. - long newSize = capacity() + (long) Math.max(size - writableBytes(), minimumGrowth); - BufferAllocator.checkSize(newSize); - var untethered = control.allocateUntethered(this, (int) newSize); - UnsafeMemory memory = untethered.memory(); - - // Copy contents. - try { - PlatformDependent.copyMemory(base, address, memory.base, memory.address, rsize); - } finally { - Reference.reachabilityFence(this.memory); - Reference.reachabilityFence(memory); - } - - // Release the old memory, and install the new memory: - Drop drop = untethered.drop(); - disconnectDrop(drop); - attachNewMemory(memory, drop); - } - - private Drop disconnectDrop(Drop newDrop) { - var drop = (Drop) unsafeGetDrop(); - int roff = this.roff; - int woff = this.woff; - drop.drop(this); - unsafeSetDrop(new ArcDrop<>(newDrop)); - this.roff = roff; - this.woff = woff; - return drop; - } - - private void attachNewMemory(UnsafeMemory memory, Drop drop) { - this.memory = memory; - base = memory.base; - baseOffset = 0; - address = memory.address; - rsize = memory.size; - wsize = memory.size; - constBuffer = false; - drop.attach(this); - } - - @Override - public Buffer split(int splitOffset) { - if (splitOffset < 0) { - throw new IllegalArgumentException("The split offset cannot be negative: " + splitOffset + '.'); - } - if (capacity() < splitOffset) { - throw new IllegalArgumentException("The split offset cannot be greater than the buffer capacity, " + - "but the split offset was " + splitOffset + ", and capacity is " + capacity() + '.'); - } - if (!isAccessible()) { - throw attachTrace(bufferIsClosed(this)); - } - if (!isOwned()) { - throw attachTrace(new IllegalStateException("Cannot split a buffer that is not owned.")); - } - var drop = (ArcDrop) unsafeGetDrop(); - unsafeSetDrop(new ArcDrop<>(drop)); - // TODO maybe incrementing the existing ArcDrop is enough; maybe we don't need to wrap it in another ArcDrop. - var splitBuffer = new UnsafeBuffer(memory, baseOffset, splitOffset, control, new ArcDrop<>(drop.increment())); - splitBuffer.woff = Math.min(woff, splitOffset); - splitBuffer.roff = Math.min(roff, splitOffset); - splitBuffer.order(order()); - boolean readOnly = readOnly(); - if (readOnly) { - splitBuffer.makeReadOnly(); - } - // Split preserves const-state. - splitBuffer.constBuffer = constBuffer; - rsize -= splitOffset; - baseOffset += splitOffset; - address += splitOffset; - if (!readOnly) { - wsize = rsize; - } - woff = Math.max(woff, splitOffset) - splitOffset; - roff = Math.max(roff, splitOffset) - splitOffset; - return splitBuffer; - } - - @Override - public void compact() { - if (!isOwned()) { - throw attachTrace(new IllegalStateException("Buffer must be owned in order to compact.")); - } - if (readOnly()) { - throw new BufferReadOnlyException("Buffer must be writable in order to compact, but was read-only."); - } - if (roff == 0) { - return; - } - try { - PlatformDependent.copyMemory(base, address + roff, base, address, woff - roff); - } finally { - Reference.reachabilityFence(memory); - } - woff -= roff; - roff = 0; - } - - @Override - public int countComponents() { - return 1; - } - - @Override - public int countReadableComponents() { - return readableBytes() > 0? 1 : 0; - } - - @Override - public int countWritableComponents() { - return writableBytes() > 0? 1 : 0; - } - - // - @Override - public boolean hasReadableArray() { - return base instanceof byte[]; - } - - @Override - public byte[] readableArray() { - checkHasReadableArray(); - return (byte[]) base; - } - - @Override - public int readableArrayOffset() { - checkHasReadableArray(); - return Math.toIntExact(address + roff - PlatformDependent.byteArrayBaseOffset()); - } - - private void checkHasReadableArray() { - if (!hasReadableArray()) { - throw new UnsupportedOperationException("No readable array available."); - } - } - - @Override - public int readableArrayLength() { - return woff - roff; - } - - @Override - public long readableNativeAddress() { - return nativeAddress(); - } - - @Override - public ByteBuffer readableBuffer() { - final ByteBuffer buf; - if (hasReadableArray()) { - buf = bbslice(ByteBuffer.wrap(readableArray()), readableArrayOffset(), readableArrayLength()); - } else { - buf = PlatformDependent.directBuffer(address + roff, readableBytes()); - } - return buf.asReadOnlyBuffer().order(order()); - } - - @Override - public boolean hasWritableArray() { - return hasReadableArray(); - } - - @Override - public byte[] writableArray() { - checkHasWritableArray(); - return (byte[]) base; - } - - @Override - public int writableArrayOffset() { - checkHasWritableArray(); - return Math.toIntExact(address + woff - PlatformDependent.byteArrayBaseOffset()); - } - - private void checkHasWritableArray() { - if (!hasReadableArray()) { - throw new UnsupportedOperationException("No writable array available."); - } - } - - @Override - public int writableArrayLength() { - return capacity() - woff; - } - - @Override - public long writableNativeAddress() { - return nativeAddress(); - } - - @Override - public ByteBuffer writableBuffer() { - final ByteBuffer buf; - if (hasWritableArray()) { - buf = bbslice(ByteBuffer.wrap(writableArray()), writableArrayOffset(), writableArrayLength()); - } else { - buf = PlatformDependent.directBuffer(address + woff, writableBytes()); - } - return buf.order(order()); - } - // - - @Override - public int forEachReadable(int initialIndex, ReadableComponentProcessor processor) - throws E { - checkRead(readerOffset(), Math.max(1, readableBytes())); - return processor.process(initialIndex, this)? 1 : -1; - } - - @Override - public int forEachWritable(int initialIndex, WritableComponentProcessor processor) - throws E { - checkWrite(writerOffset(), Math.max(1, writableBytes())); - return processor.process(initialIndex, this)? 1 : -1; - } - - // - @Override - public byte readByte() { - checkRead(roff, Byte.BYTES); - try { - var value = loadByte(address + roff); - roff += Byte.BYTES; - return value; - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public byte getByte(int roff) { - checkGet(roff, Byte.BYTES); - try { - return loadByte(address + roff); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public int readUnsignedByte() { - return readByte() & 0xFF; - } - - @Override - public int getUnsignedByte(int roff) { - return getByte(roff) & 0xFF; - } - - @Override - public Buffer writeByte(byte value) { - checkWrite(woff, Byte.BYTES); - long offset = address + woff; - woff += Byte.BYTES; - try { - storeByte(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setByte(int woff, byte value) { - checkSet(woff, Byte.BYTES); - long offset = address + woff; - try { - storeByte(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer writeUnsignedByte(int value) { - checkWrite(woff, Byte.BYTES); - long offset = address + woff; - woff += Byte.BYTES; - try { - storeByte(offset, (byte) (value & 0xFF)); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setUnsignedByte(int woff, int value) { - checkSet(woff, Byte.BYTES); - long offset = address + woff; - try { - storeByte(offset, (byte) (value & 0xFF)); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public char readChar() { - checkRead(roff, Character.BYTES); - try { - long offset = address + roff; - roff += Character.BYTES; - return loadChar(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public char getChar(int roff) { - checkGet(roff, Character.BYTES); - try { - long offset = address + roff; - return loadChar(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public Buffer writeChar(char value) { - checkWrite(woff, Character.BYTES); - long offset = address + woff; - woff += Character.BYTES; - try { - storeChar(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setChar(int woff, char value) { - checkSet(woff, Character.BYTES); - long offset = address + woff; - try { - storeChar(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public short readShort() { - checkRead(roff, Short.BYTES); - try { - long offset = address + roff; - roff += Short.BYTES; - return loadShort(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public short getShort(int roff) { - checkGet(roff, Short.BYTES); - try { - long offset = address + roff; - return loadShort(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public int readUnsignedShort() { - return readShort() & 0xFFFF; - } - - @Override - public int getUnsignedShort(int roff) { - return getShort(roff) & 0xFFFF; - } - - @Override - public Buffer writeShort(short value) { - checkWrite(woff, Short.BYTES); - long offset = address + woff; - woff += Short.BYTES; - try { - storeShort(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setShort(int woff, short value) { - checkSet(woff, Short.BYTES); - long offset = address + woff; - try { - storeShort(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer writeUnsignedShort(int value) { - checkWrite(woff, Short.BYTES); - long offset = address + woff; - woff += Short.BYTES; - try { - storeShort(offset, (short) (value & 0xFFFF)); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setUnsignedShort(int woff, int value) { - checkSet(woff, Short.BYTES); - long offset = address + woff; - try { - storeShort(offset, (short) (value & 0xFFFF)); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public int readMedium() { - checkRead(roff, 3); - long offset = address + roff; - int value = order() == ByteOrder.BIG_ENDIAN ? - loadByte(offset) << 16 | - (loadByte(offset + 1) & 0xFF) << 8 | - loadByte(offset + 2) & 0xFF : - loadByte(offset) & 0xFF | - (loadByte(offset + 1) & 0xFF) << 8 | - loadByte(offset + 2) << 16; - roff += 3; - return value; - } - - @Override - public int getMedium(int roff) { - checkGet(roff, 3); - long offset = address + roff; - return order() == ByteOrder.BIG_ENDIAN? - loadByte(offset) << 16 | - (loadByte(offset + 1) & 0xFF) << 8 | - loadByte(offset + 2) & 0xFF : - loadByte(offset) & 0xFF | - (loadByte(offset + 1) & 0xFF) << 8 | - loadByte(offset + 2) << 16; - } - - @Override - public int readUnsignedMedium() { - checkRead(roff, 3); - long offset = address + roff; - int value = order() == ByteOrder.BIG_ENDIAN? - (loadByte(offset) << 16 | - (loadByte(offset + 1) & 0xFF) << 8 | - loadByte(offset + 2) & 0xFF) & 0xFFFFFF : - (loadByte(offset) & 0xFF | - (loadByte(offset + 1) & 0xFF) << 8 | - loadByte(offset + 2) << 16) & 0xFFFFFF; - roff += 3; - return value; - } - - @Override - public int getUnsignedMedium(int roff) { - checkGet(roff, 3); - long offset = address + roff; - return order() == ByteOrder.BIG_ENDIAN? - (loadByte(offset) << 16 | - (loadByte(offset + 1) & 0xFF) << 8 | - loadByte(offset + 2) & 0xFF) & 0xFFFFFF : - (loadByte(offset) & 0xFF | - (loadByte(offset + 1) & 0xFF) << 8 | - loadByte(offset + 2) << 16) & 0xFFFFFF; - } - - @Override - public Buffer writeMedium(int value) { - checkWrite(woff, 3); - long offset = address + woff; - if (order() == ByteOrder.BIG_ENDIAN) { - storeByte(offset, (byte) (value >> 16)); - storeByte(offset + 1, (byte) (value >> 8 & 0xFF)); - storeByte(offset + 2, (byte) (value & 0xFF)); - } else { - storeByte(offset, (byte) (value & 0xFF)); - storeByte(offset + 1, (byte) (value >> 8 & 0xFF)); - storeByte(offset + 2, (byte) (value >> 16 & 0xFF)); - } - woff += 3; - return this; - } - - @Override - public Buffer setMedium(int woff, int value) { - checkSet(woff, 3); - long offset = address + woff; - if (order() == ByteOrder.BIG_ENDIAN) { - storeByte(offset, (byte) (value >> 16)); - storeByte(offset + 1, (byte) (value >> 8 & 0xFF)); - storeByte(offset + 2, (byte) (value & 0xFF)); - } else { - storeByte(offset, (byte) (value & 0xFF)); - storeByte(offset + 1, (byte) (value >> 8 & 0xFF)); - storeByte(offset + 2, (byte) (value >> 16 & 0xFF)); - } - return this; - } - - @Override - public Buffer writeUnsignedMedium(int value) { - checkWrite(woff, 3); - long offset = address + woff; - if (order() == ByteOrder.BIG_ENDIAN) { - storeByte(offset, (byte) (value >> 16)); - storeByte(offset + 1, (byte) (value >> 8 & 0xFF)); - storeByte(offset + 2, (byte) (value & 0xFF)); - } else { - storeByte(offset, (byte) (value & 0xFF)); - storeByte(offset + 1, (byte) (value >> 8 & 0xFF)); - storeByte(offset + 2, (byte) (value >> 16 & 0xFF)); - } - woff += 3; - return this; - } - - @Override - public Buffer setUnsignedMedium(int woff, int value) { - checkSet(woff, 3); - long offset = address + woff; - if (order() == ByteOrder.BIG_ENDIAN) { - storeByte(offset, (byte) (value >> 16)); - storeByte(offset + 1, (byte) (value >> 8 & 0xFF)); - storeByte(offset + 2, (byte) (value & 0xFF)); - } else { - storeByte(offset, (byte) (value & 0xFF)); - storeByte(offset + 1, (byte) (value >> 8 & 0xFF)); - storeByte(offset + 2, (byte) (value >> 16 & 0xFF)); - } - return this; - } - - @Override - public int readInt() { - checkRead(roff, Integer.BYTES); - try { - long offset = address + roff; - roff += Integer.BYTES; - return loadInt(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public int getInt(int roff) { - checkGet(roff, Integer.BYTES); - try { - long offset = address + roff; - return loadInt(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public long readUnsignedInt() { - return readInt() & 0x0000_0000_FFFF_FFFFL; - } - - @Override - public long getUnsignedInt(int roff) { - return getInt(roff) & 0x0000_0000_FFFF_FFFFL; - } - - @Override - public Buffer writeInt(int value) { - checkWrite(woff, Integer.BYTES); - long offset = address + woff; - woff += Integer.BYTES; - try { - storeInt(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setInt(int woff, int value) { - checkSet(woff, Integer.BYTES); - long offset = address + woff; - try { - storeInt(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer writeUnsignedInt(long value) { - checkWrite(woff, Integer.BYTES); - long offset = address + woff; - woff += Integer.BYTES; - try { - storeInt(offset, (int) (value & 0xFFFF_FFFFL)); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setUnsignedInt(int woff, long value) { - checkSet(woff, Integer.BYTES); - long offset = address + woff; - try { - storeInt(offset, (int) (value & 0xFFFF_FFFFL)); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public float readFloat() { - checkRead(roff, Float.BYTES); - try { - long offset = address + roff; - roff += Float.BYTES; - return loadFloat(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public float getFloat(int roff) { - checkGet(roff, Float.BYTES); - try { - long offset = address + roff; - return loadFloat(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public Buffer writeFloat(float value) { - checkWrite(woff, Float.BYTES); - long offset = address + woff; - woff += Float.BYTES; - try { - storeFloat(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setFloat(int woff, float value) { - checkSet(woff, Float.BYTES); - long offset = address + woff; - try { - storeFloat(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public long readLong() { - checkRead(roff, Long.BYTES); - try { - long offset = address + roff; - roff += Long.BYTES; - return loadLong(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public long getLong(int roff) { - checkGet(roff, Long.BYTES); - try { - long offset = address + roff; - return loadLong(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public Buffer writeLong(long value) { - checkWrite(woff, Long.BYTES); - long offset = address + woff; - woff += Long.BYTES; - try { - storeLong(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setLong(int woff, long value) { - checkSet(woff, Long.BYTES); - long offset = address + woff; - try { - storeLong(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public double readDouble() { - checkRead(roff, Double.BYTES); - try { - long offset = address + roff; - roff += Double.BYTES; - return loadDouble(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public double getDouble(int roff) { - checkGet(roff, Double.BYTES); - try { - long offset = address + roff; - return loadDouble(offset); - } finally { - Reference.reachabilityFence(memory); - } - } - - @Override - public Buffer writeDouble(double value) { - checkWrite(woff, Double.BYTES); - long offset = address + woff; - woff += Double.BYTES; - try { - storeDouble(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - - @Override - public Buffer setDouble(int woff, double value) { - checkSet(woff, Double.BYTES); - long offset = address + woff; - try { - storeDouble(offset, value); - } finally { - Reference.reachabilityFence(memory); - } - return this; - } - // - - @Override - protected Owned prepareSend() { - var order = order(); - var roff = this.roff; - var woff = this.woff; - var readOnly = readOnly(); - var isConst = constBuffer; - UnsafeMemory memory = this.memory; - AllocatorControl control = this.control; - long baseOffset = this.baseOffset; - int rsize = this.rsize; - makeInaccessible(); - return new Owned() { - @Override - public UnsafeBuffer transferOwnership(Drop drop) { - UnsafeBuffer copy = new UnsafeBuffer(memory, baseOffset, rsize, control, drop); - copy.order(order); - copy.roff = roff; - copy.woff = woff; - if (readOnly) { - copy.makeReadOnly(); - } - copy.constBuffer = isConst; - return copy; - } - }; - } - - @Override - protected Drop unsafeGetDrop() { - MakeInaccessibleOnDrop drop = (MakeInaccessibleOnDrop) super.unsafeGetDrop(); - return drop.delegate; - } - - @Override - protected void unsafeSetDrop(Drop replacement) { - super.unsafeSetDrop(new MakeInaccessibleOnDrop(replacement)); - } - - private static final class MakeInaccessibleOnDrop implements Drop { - final Drop delegate; - - private MakeInaccessibleOnDrop(Drop delegate) { - this.delegate = delegate; - } - - @Override - public void drop(UnsafeBuffer buf) { - try { - delegate.drop(buf); - } finally { - buf.makeInaccessible(); - } - } - - @Override - public void attach(UnsafeBuffer buf) { - delegate.attach(buf); - } - - @Override - public String toString() { - return "MakeInaccessibleOnDrop(" + delegate + ')'; - } - } - - void makeInaccessible() { - roff = 0; - woff = 0; - rsize = CLOSED_SIZE; - wsize = CLOSED_SIZE; - readOnly = false; - } - - @Override - public boolean isOwned() { - return super.isOwned() && ((ArcDrop) unsafeGetDrop()).isOwned(); - } - - @Override - public int countBorrows() { - return super.countBorrows() + ((ArcDrop) unsafeGetDrop()).countBorrows(); - } - - private void checkRead(int index, int size) { - if (index < 0 || woff < index + size) { - throw readAccessCheckException(index); - } - } - - private void checkGet(int index, int size) { - if (index < 0 || rsize < index + size) { - throw readAccessCheckException(index); - } - } - - private void checkWrite(int index, int size) { - if (index < roff || wsize < index + size) { - throw writeAccessCheckException(index); - } - } - - private void checkSet(int index, int size) { - if (index < 0 || wsize < index + size) { - throw writeAccessCheckException(index); - } - } - - private RuntimeException readAccessCheckException(int index) { - if (rsize == CLOSED_SIZE) { - throw bufferIsClosed(this); - } - return outOfBounds(index); - } - - private RuntimeException writeAccessCheckException(int index) { - if (rsize == CLOSED_SIZE) { - throw bufferIsClosed(this); - } - if (wsize != rsize) { - return bufferIsReadOnly(this); - } - return outOfBounds(index); - } - - private IndexOutOfBoundsException outOfBounds(int index) { - return new IndexOutOfBoundsException( - "Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " + - rsize + "]."); - } - - private byte loadByte(long off) { - return PlatformDependent.getByte(base, off); - } - - private char loadChar(long offset) { - if (ACCESS_UNALIGNED) { - var value = PlatformDependent.getChar(base, offset); - return flipBytes? Character.reverseBytes(value) : value; - } - return loadCharUnaligned(offset); - } - - private char loadCharUnaligned(long offset) { - final char value; - Object b = base; - if ((offset & 1) == 0) { - value = PlatformDependent.getChar(b, offset); - } else { - value = (char) (PlatformDependent.getByte(b, offset) << 8 | - PlatformDependent.getByte(b, offset + 1)); - } - return flipBytes? Character.reverseBytes(value) : value; - } - - private short loadShort(long offset) { - if (ACCESS_UNALIGNED) { - var value = PlatformDependent.getShort(base, offset); - return flipBytes? Short.reverseBytes(value) : value; - } - return loadShortUnaligned(offset); - } - - private short loadShortUnaligned(long offset) { - final short value; - Object b = base; - if ((offset & 1) == 0) { - value = PlatformDependent.getShort(b, offset); - } else { - value = (short) (PlatformDependent.getByte(b, offset) << 8 | - PlatformDependent.getByte(b, offset + 1)); - } - return flipBytes? Short.reverseBytes(value) : value; - } - - private int loadInt(long offset) { - if (ACCESS_UNALIGNED) { - var value = PlatformDependent.getInt(base, offset); - return flipBytes? Integer.reverseBytes(value) : value; - } - return loadIntUnaligned(offset); - } - - private int loadIntUnaligned(long offset) { - final int value; - Object b = base; - if ((offset & 3) == 0) { - value = PlatformDependent.getInt(b, offset); - } else if ((offset & 1) == 0) { - value = PlatformDependent.getShort(b, offset) << 16 | - PlatformDependent.getShort(b, offset + 2); - } else { - value = PlatformDependent.getByte(b, offset) << 24 | - PlatformDependent.getByte(b, offset + 1) << 16 | - PlatformDependent.getByte(b, offset + 2) << 8 | - PlatformDependent.getByte(b, offset + 3); - } - return flipBytes? Integer.reverseBytes(value) : value; - } - - private float loadFloat(long offset) { - if (ACCESS_UNALIGNED) { - if (flipBytes) { - var value = PlatformDependent.getInt(base, offset); - return Float.intBitsToFloat(Integer.reverseBytes(value)); - } - return PlatformDependent.getFloat(base, offset); - } - return loadFloatUnaligned(offset); - } - - private float loadFloatUnaligned(long offset) { - return Float.intBitsToFloat(loadIntUnaligned(offset)); - } - - private long loadLong(long offset) { - if (ACCESS_UNALIGNED) { - var value = PlatformDependent.getLong(base, offset); - return flipBytes? Long.reverseBytes(value) : value; - } - return loadLongUnaligned(offset); - } - - private long loadLongUnaligned(long offset) { - final long value; - Object b = base; - if ((offset & 7) == 0) { - value = PlatformDependent.getLong(b, offset); - } else if ((offset & 3) == 0) { - value = (long) PlatformDependent.getInt(b, offset) << 32 | - PlatformDependent.getInt(b, offset + 4); - } else if ((offset & 1) == 0) { - value = (long) PlatformDependent.getShort(b, offset) << 48 | - (long) PlatformDependent.getShort(b, offset + 2) << 32 | - (long) PlatformDependent.getShort(b, offset + 4) << 16 | - PlatformDependent.getShort(b, offset + 6); - } else { - value = (long) PlatformDependent.getByte(b, offset) << 54 | - (long) PlatformDependent.getByte(b, offset + 1) << 48 | - (long) PlatformDependent.getByte(b, offset + 2) << 40 | - (long) PlatformDependent.getByte(b, offset + 3) << 32 | - (long) PlatformDependent.getByte(b, offset + 4) << 24 | - (long) PlatformDependent.getByte(b, offset + 5) << 16 | - (long) PlatformDependent.getByte(b, offset + 6) << 8 | - PlatformDependent.getByte(b, offset + 7); - } - return flipBytes? Long.reverseBytes(value) : value; - } - - private double loadDouble(long offset) { - if (ACCESS_UNALIGNED) { - if (flipBytes) { - var value = PlatformDependent.getLong(base, offset); - return Double.longBitsToDouble(Long.reverseBytes(value)); - } - return PlatformDependent.getDouble(base, offset); - } - return loadDoubleUnaligned(offset); - } - - private double loadDoubleUnaligned(long offset) { - return Double.longBitsToDouble(loadLongUnaligned(offset)); - } - - private void storeByte(long offset, byte value) { - PlatformDependent.putByte(base, offset, value); - } - - private void storeChar(long offset, char value) { - if (flipBytes) { - value = Character.reverseBytes(value); - } - if (ACCESS_UNALIGNED) { - PlatformDependent.putChar(base, offset, value); - } else { - storeCharUnaligned(offset, value); - } - } - - private void storeCharUnaligned(long offset, char value) { - Object b = base; - if ((offset & 1) == 0) { - PlatformDependent.putChar(b, offset, value); - } else { - PlatformDependent.putByte(b, offset, (byte) (value >> 8)); - PlatformDependent.putByte(b, offset + 1, (byte) value); - } - } - - private void storeShort(long offset, short value) { - if (flipBytes) { - value = Short.reverseBytes(value); - } - if (ACCESS_UNALIGNED) { - PlatformDependent.putShort(base, offset, value); - } else { - storeShortUnaligned(offset, value); - } - } - - private void storeShortUnaligned(long offset, short value) { - Object b = base; - if ((offset & 1) == 0) { - PlatformDependent.putShort(b, offset, value); - } else { - PlatformDependent.putByte(b, offset, (byte) (value >> 8)); - PlatformDependent.putByte(b, offset + 1, (byte) value); - } - } - - private void storeInt(long offset, int value) { - if (flipBytes) { - value = Integer.reverseBytes(value); - } - if (ACCESS_UNALIGNED) { - PlatformDependent.putInt(base, offset, value); - } else { - storeIntUnaligned(offset, value); - } - } - - private void storeIntUnaligned(long offset, int value) { - Object b = base; - if ((offset & 3) == 0) { - PlatformDependent.putInt(b, offset, value); - } else if ((offset & 1) == 0) { - PlatformDependent.putShort(b, offset, (short) (value >> 16)); - PlatformDependent.putShort(b, offset + 2, (short) value); - } else { - PlatformDependent.putByte(b, offset, (byte) (value >> 24)); - PlatformDependent.putByte(b, offset + 1, (byte) (value >> 16)); - PlatformDependent.putByte(b, offset + 2, (byte) (value >> 8)); - PlatformDependent.putByte(b, offset + 3, (byte) value); - } - } - - private void storeFloat(long offset, float value) { - storeInt(offset, Float.floatToRawIntBits(value)); - } - - private void storeLong(long offset, long value) { - if (flipBytes) { - value = Long.reverseBytes(value); - } - if (ACCESS_UNALIGNED) { - PlatformDependent.putLong(base, offset, value); - } else { - storeLongUnaligned(offset, value); - } - } - - private void storeLongUnaligned(long offset, long value) { - Object b = base; - if ((offset & 7) == 0) { - PlatformDependent.putLong(b, offset, value); - } else if ((offset & 3) == 0) { - PlatformDependent.putInt(b, offset, (int) (value >> 32)); - PlatformDependent.putInt(b, offset + 4, (int) value); - } else if ((offset & 1) == 0) { - PlatformDependent.putShort(b, offset, (short) (value >> 48)); - PlatformDependent.putShort(b, offset + 16, (short) (value >> 32)); - PlatformDependent.putShort(b, offset + 32, (short) (value >> 16)); - PlatformDependent.putShort(b, offset + 48, (short) value); - } else { - PlatformDependent.putByte(b, offset, (byte) (value >> 56)); - PlatformDependent.putByte(b, offset + 1, (byte) (value >> 48)); - PlatformDependent.putByte(b, offset + 2, (byte) (value >> 40)); - PlatformDependent.putByte(b, offset + 3, (byte) (value >> 32)); - PlatformDependent.putByte(b, offset + 4, (byte) (value >> 24)); - PlatformDependent.putByte(b, offset + 5, (byte) (value >> 16)); - PlatformDependent.putByte(b, offset + 6, (byte) (value >> 8)); - PlatformDependent.putByte(b, offset + 7, (byte) value); - } - } - - private void storeDouble(long offset, double value) { - storeLong(offset, Double.doubleToRawLongBits(value)); - } - - Object recover() { - return memory; - } - - // - private ByteBufAdaptor adaptor; - @Override - public ByteBuf asByteBuf() { - ByteBufAdaptor bba = adaptor; - if (bba == null) { - ByteBufAllocatorAdaptor alloc = new ByteBufAllocatorAdaptor( - BufferAllocator.heap(), BufferAllocator.direct()); - return adaptor = new ByteBufAdaptor(alloc, this); - } - return bba; - } - - @Override - public int refCnt() { - return isAccessible()? 1 + countBorrows() : 0; - } - - @Override - public ReferenceCounted retain() { - return retain(1); - } - - @Override - public ReferenceCounted retain(int increment) { - for (int i = 0; i < increment; i++) { - acquire(); - } - return this; - } - - @Override - public ReferenceCounted touch() { - return this; - } - - @Override - public ReferenceCounted touch(Object hint) { - return this; - } - - @Override - public boolean release() { - return release(1); - } - - @Override - public boolean release(int decrement) { - int refCount = 1 + countBorrows(); - if (!isAccessible() || decrement > refCount) { - throw new IllegalReferenceCountException(refCount, -decrement); - } - for (int i = 0; i < decrement; i++) { - try { - close(); - } catch (RuntimeException e) { - throw new IllegalReferenceCountException(e); - } - } - return !isAccessible(); - } - // -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemory.java b/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemory.java deleted file mode 100644 index 27de302..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemory.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.unsafe; - -class UnsafeMemory { - final Object base; - final long address; - final int size; - - UnsafeMemory(Object base, long address, int size) { - this.base = base; - this.address = address; - this.size = size; - } - - public UnsafeMemory slice(int offset, int length) { - return new UnsafeMemory(base, address + offset, length); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemoryManager.java b/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemoryManager.java deleted file mode 100644 index bb51202..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemoryManager.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.unsafe; - -import io.netty.buffer.api.AllocatorControl; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.MemoryManager; -import io.netty.buffer.api.internal.Statics; -import io.netty.util.internal.PlatformDependent; - -import java.lang.ref.Cleaner; - -import static io.netty.buffer.api.internal.Statics.convert; - -public class UnsafeMemoryManager implements MemoryManager { - private final boolean offheap; - - public UnsafeMemoryManager(boolean offheap) { - this.offheap = offheap; - } - - @Override - public boolean isNative() { - return offheap; - } - - @Override - public Buffer allocateShared(AllocatorControl allocatorControl, long size, Drop drop, Cleaner cleaner) { - final Object base; - final long address; - final UnsafeMemory memory; - final int size32 = Math.toIntExact(size); - if (cleaner == null) { - cleaner = Statics.CLEANER; - } - if (offheap) { - base = null; - address = PlatformDependent.allocateMemory(size); - PlatformDependent.setMemory(address, size, (byte) 0); - memory = new UnsafeMemory(base, address, size32); - drop = new CleanerDrop(memory, drop, cleaner); - } else { - base = new byte[size32]; - address = PlatformDependent.byteArrayBaseOffset(); - memory = new UnsafeMemory(base, address, size32); - } - return new UnsafeBuffer(memory, 0, size32, allocatorControl, convert(drop)); - } - - @Override - public Buffer allocateConstChild(Buffer readOnlyConstParent) { - assert readOnlyConstParent.readOnly(); - UnsafeBuffer buf = (UnsafeBuffer) readOnlyConstParent; - return new UnsafeBuffer(buf); - } - - @Override - public Drop drop() { - // We cannot reliably drop unsafe memory. We have to rely on the cleaner to do that. - return Statics.NO_OP_DROP; - } - - @Override - public Object unwrapRecoverableMemory(Buffer buf) { - return ((UnsafeBuffer) buf).recover(); - } - - @Override - public int capacityOfRecoverableMemory(Object memory) { - return ((UnsafeMemory) memory).size; - } - - @Override - public void discardRecoverableMemory(Object recoverableMemory) { - // We cannot reliably drop unsafe memory. We have to rely on the cleaner to do that. - } - - @Override - public Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop drop) { - UnsafeMemory memory = (UnsafeMemory) recoverableMemory; - return new UnsafeBuffer(memory, 0, memory.size, allocatorControl, convert(drop)); - } - - @Override - public Object sliceMemory(Object memory, int offset, int length) { - return ((UnsafeMemory) memory).slice(offset, length); - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemoryManagers.java b/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemoryManagers.java deleted file mode 100644 index 41a11ae..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/UnsafeMemoryManagers.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.unsafe; - -import io.netty.buffer.api.MemoryManager; -import io.netty.buffer.api.MemoryManagers; -import io.netty.util.internal.PlatformDependent; - -public class UnsafeMemoryManagers implements MemoryManagers { - public UnsafeMemoryManagers() { - if (!PlatformDependent.hasUnsafe()) { - throw new UnsupportedOperationException("Unsafe is not available."); - } - if (!PlatformDependent.hasDirectBufferNoCleanerConstructor()) { - throw new UnsupportedOperationException("DirectByteBuffer internal constructor is not available."); - } - } - - @Override - public MemoryManager getHeapMemoryManager() { - return new UnsafeMemoryManager(false); - } - - @Override - public MemoryManager getNativeMemoryManager() { - return new UnsafeMemoryManager(true); - } - - @Override - public String getImplementationName() { - return "Unsafe"; - } - - @Override - public String toString() { - return "US"; - } -} diff --git a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/package-info.java b/buffer-api/src/main/java/io/netty/buffer/api/unsafe/package-info.java deleted file mode 100644 index 3fd081a..0000000 --- a/buffer-api/src/main/java/io/netty/buffer/api/unsafe/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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. - */ - -/** - * A {@link io.netty.buffer.api.Buffer} implementation that is based on {@code sun.misc.Unsafe}. - */ -package io.netty.buffer.api.unsafe; diff --git a/buffer-api/src/main/java/module-info.java b/buffer-api/src/main/java/module-info.java deleted file mode 100644 index 3c7185a..0000000 --- a/buffer-api/src/main/java/module-info.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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. - */ -import io.netty.buffer.api.MemoryManagers; -import io.netty.buffer.api.bytebuffer.ByteBufferMemoryManagers; -import io.netty.buffer.api.unsafe.UnsafeMemoryManagers; - -module netty.incubator.buffer { - requires io.netty.common; - requires io.netty.buffer; - - // Optional dependencies, needed for some examples. - requires static java.logging;//todo remove - - exports io.netty.buffer.api; - exports io.netty.buffer.api.adaptor; - - uses MemoryManagers; - - // Permit reflective access to non-public members. - // Also means we don't have to make all test methods etc. public for JUnit to access them. - opens io.netty.buffer.api; - exports io.netty.buffer.api.internal; - opens io.netty.buffer.api.internal;//todo remove - - provides MemoryManagers with - ByteBufferMemoryManagers, - UnsafeMemoryManagers; -} diff --git a/buffer-memseg-dummy/pom.xml b/buffer-memseg-dummy/pom.xml deleted file mode 100644 index 1c1a759..0000000 --- a/buffer-memseg-dummy/pom.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - 4.0.0 - - - io.netty.incubator - netty-incubator-buffer-parent - 0.0.1.Final-SNAPSHOT - - - netty-incubator-buffer-memseg-dummy - 0.0.1.Final-SNAPSHOT - diff --git a/buffer-memseg-dummy/src/main/java/module-info.java b/buffer-memseg-dummy/src/main/java/module-info.java deleted file mode 100644 index bc63aed..0000000 --- a/buffer-memseg-dummy/src/main/java/module-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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. - */ -module netty.incubator.buffer.memseg { - // Java 11 compatible stand-in module for the memory segment implementation. - // We need this module in order for the tests module to pull in the memseg module. -} diff --git a/buffer-memseg/pom.xml b/buffer-memseg/pom.xml index 3bd4f08..4aeceb4 100644 --- a/buffer-memseg/pom.xml +++ b/buffer-memseg/pom.xml @@ -44,10 +44,6 @@ - - io.netty.incubator - netty-incubator-buffer-api - io.netty netty-common diff --git a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/AbstractMemorySegmentManager.java b/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/AbstractMemorySegmentManager.java deleted file mode 100644 index df68f16..0000000 --- a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/AbstractMemorySegmentManager.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.memseg; - -import io.netty.buffer.api.internal.ArcDrop; -import io.netty.buffer.api.internal.Statics; -import io.netty.buffer.api.AllocatorControl; -import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.MemoryManager; -import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.ResourceScope; - -import java.lang.ref.Cleaner; - -public abstract class AbstractMemorySegmentManager implements MemoryManager { - @Override - public Buffer allocateShared(AllocatorControl allocatorControl, long size, Drop drop, Cleaner cleaner) { - var segment = createSegment(size, cleaner); - return new MemSegBuffer(segment, segment, Statics.convert(drop), allocatorControl); - } - - @Override - public Buffer allocateConstChild(Buffer readOnlyConstParent) { - assert readOnlyConstParent.readOnly(); - MemSegBuffer buf = (MemSegBuffer) readOnlyConstParent; - return new MemSegBuffer(buf); - } - - protected abstract MemorySegment createSegment(long size, Cleaner cleaner); - - @Override - public Drop drop() { - return Statics.convert(MemSegBuffer.SEGMENT_CLOSE); - } - - @Override - public Object unwrapRecoverableMemory(Buffer buf) { - var b = (MemSegBuffer) buf; - return b.recoverableMemory(); - } - - @Override - public int capacityOfRecoverableMemory(Object memory) { - return (int) ((MemorySegment) memory).byteSize(); - } - - @Override - public void discardRecoverableMemory(Object recoverableMemory) { - var segment = (MemorySegment) recoverableMemory; - ResourceScope scope = segment.scope(); - if (!scope.isImplicit()) { - scope.close(); - } - } - - @Override - public Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop drop) { - var segment = (MemorySegment) recoverableMemory; - return new MemSegBuffer(segment, segment, Statics.convert(ArcDrop.acquire(drop)), allocatorControl); - } - - @Override - public Object sliceMemory(Object memory, int offset, int length) { - var segment = (MemorySegment) memory; - return segment.asSlice(offset, length); - } -} diff --git a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/HeapMemorySegmentManager.java b/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/HeapMemorySegmentManager.java deleted file mode 100644 index d52900d..0000000 --- a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/HeapMemorySegmentManager.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.memseg; - -import jdk.incubator.foreign.MemorySegment; - -import java.lang.ref.Cleaner; - -public class HeapMemorySegmentManager extends AbstractMemorySegmentManager { - @Override - protected MemorySegment createSegment(long size, Cleaner cleaner) { - return MemorySegment.ofArray(new byte[Math.toIntExact(size)]); - } - - @Override - public boolean isNative() { - return false; - } -} diff --git a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/MemSegBuffer.java b/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/MemSegBuffer.java index 140969d..2d57f7b 100644 --- a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/MemSegBuffer.java +++ b/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/MemSegBuffer.java @@ -15,25 +15,21 @@ */ package io.netty.buffer.api.memseg; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.api.BufferAllocator; -import io.netty.buffer.api.BufferReadOnlyException; -import io.netty.buffer.api.adaptor.BufferIntegratable; -import io.netty.buffer.api.adaptor.ByteBufAdaptor; -import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor; -import io.netty.buffer.api.internal.ArcDrop; -import io.netty.buffer.api.internal.Statics; import io.netty.buffer.api.AllocatorControl; import io.netty.buffer.api.Buffer; +import io.netty.buffer.api.BufferAllocator; +import io.netty.buffer.api.BufferReadOnlyException; import io.netty.buffer.api.ByteCursor; +import io.netty.buffer.api.Drop; +import io.netty.buffer.api.Owned; import io.netty.buffer.api.ReadableComponent; import io.netty.buffer.api.ReadableComponentProcessor; import io.netty.buffer.api.WritableComponent; import io.netty.buffer.api.WritableComponentProcessor; -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.Owned; -import io.netty.buffer.api.internal.ResourceSupport; -import io.netty.util.IllegalReferenceCountException; +import io.netty.buffer.api.adaptor.BufferIntegratable; +import io.netty.buffer.api.internal.AdaptableBuffer; +import io.netty.buffer.api.internal.ArcDrop; +import io.netty.buffer.api.internal.Statics; import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; @@ -57,7 +53,7 @@ import static jdk.incubator.foreign.MemoryAccess.setIntAtOffset; import static jdk.incubator.foreign.MemoryAccess.setLongAtOffset; import static jdk.incubator.foreign.MemoryAccess.setShortAtOffset; -class MemSegBuffer extends ResourceSupport implements Buffer, ReadableComponent, +class MemSegBuffer extends AdaptableBuffer implements Buffer, ReadableComponent, WritableComponent, BufferIntegratable { private static final MemorySegment CLOSED_SEGMENT; private static final MemorySegment ZERO_OFFHEAP_SEGMENT; @@ -105,7 +101,7 @@ class MemSegBuffer extends ResourceSupport implements Buff this.base = base; seg = view; wseg = view; - order = ByteOrder.nativeOrder(); + order = ByteOrder.BIG_ENDIAN; } /** @@ -120,7 +116,6 @@ class MemSegBuffer extends ResourceSupport implements Buff order = parent.order; roff = parent.roff; woff = parent.woff; - adaptor = null; constBuffer = true; } @@ -172,17 +167,6 @@ class MemSegBuffer extends ResourceSupport implements Buff return bufferIsClosed(this); } - @Override - public Buffer order(ByteOrder order) { - this.order = order; - return this; - } - - @Override - public ByteOrder order() { - return order; - } - @Override public int capacity() { return (int) seg.byteSize(); @@ -333,7 +317,7 @@ class MemSegBuffer extends ResourceSupport implements Buff MemorySegment segment = memory.memory(); Buffer copy = new MemSegBuffer(segment, segment, memory.drop(), control); copyInto(offset, copy, 0, length); - copy.writerOffset(length).order(order()); + copy.writerOffset(length); if (readOnly()) { copy = copy.makeReadOnly(); } @@ -369,14 +353,13 @@ class MemSegBuffer extends ResourceSupport implements Buff @Override public void copyInto(int srcPos, Buffer dest, int destPos, int length) { - if (dest instanceof MemSegBuffer) { - var memSegBuf = (MemSegBuffer) dest; + if (dest instanceof MemSegBuffer memSegBuf) { memSegBuf.checkSet(destPos, length); copyInto(srcPos, memSegBuf.seg, destPos, length); return; } - Statics.copyToViaReverseCursor(this, srcPos, dest, destPos, length); + Statics.copyToViaReverseLoop(this, srcPos, dest, destPos, length); } @Override @@ -406,7 +389,6 @@ class MemSegBuffer extends ResourceSupport implements Buff long longValue = -1; byte byteValue = -1; - @Override public boolean readLong() { if (index + Long.BYTES <= end) { longValue = getLongAtOffset(segment, index, ByteOrder.BIG_ENDIAN); @@ -416,7 +398,6 @@ class MemSegBuffer extends ResourceSupport implements Buff return false; } - @Override public long getLong() { return longValue; } @@ -479,7 +460,6 @@ class MemSegBuffer extends ResourceSupport implements Buff long longValue = -1; byte byteValue = -1; - @Override public boolean readLong() { if (index - Long.BYTES >= end) { index -= 7; @@ -490,7 +470,6 @@ class MemSegBuffer extends ResourceSupport implements Buff return false; } - @Override public long getLong() { return longValue; } @@ -523,7 +502,7 @@ class MemSegBuffer extends ResourceSupport implements Buff } @Override - public void ensureWritable(int size, int minimumGrowth, boolean allowCompaction) { + public Buffer ensureWritable(int size, int minimumGrowth, boolean allowCompaction) { if (!isAccessible()) { throw bufferIsClosed(this); } @@ -542,18 +521,17 @@ class MemSegBuffer extends ResourceSupport implements Buff } if (writableBytes() >= size) { // We already have enough space. - return; + return this; } if (allowCompaction && writableBytes() + readerOffset() >= size) { // We can solve this with compaction. - compact(); - return; + return compact(); } // Allocate a bigger buffer. long newSize = capacity() + (long) Math.max(size - writableBytes(), minimumGrowth); - BufferAllocator.checkSize(newSize); + Statics.assertValidBufferSize(newSize); var untethered = control.allocateUntethered(this, (int) newSize); MemorySegment newSegment = untethered.memory(); @@ -564,6 +542,7 @@ class MemSegBuffer extends ResourceSupport implements Buff Drop drop = untethered.drop(); disconnectDrop(drop); attachNewMemorySegment(newSegment, drop); + return this; } private void disconnectDrop(Drop newDrop) { @@ -606,7 +585,6 @@ class MemSegBuffer extends ResourceSupport implements Buff var splitBuffer = new MemSegBuffer(base, splitSegment, new ArcDrop<>(drop.increment()), control); splitBuffer.woff = Math.min(woff, splitOffset); splitBuffer.roff = Math.min(roff, splitOffset); - splitBuffer.order(order); boolean readOnly = readOnly(); if (readOnly) { splitBuffer.makeReadOnly(); @@ -623,7 +601,7 @@ class MemSegBuffer extends ResourceSupport implements Buff } @Override - public void compact() { + public Buffer compact() { if (!isOwned()) { throw attachTrace(new IllegalStateException("Buffer must be owned in order to compact.")); } @@ -632,11 +610,12 @@ class MemSegBuffer extends ResourceSupport implements Buff } int distance = roff; if (distance == 0) { - return; + return this; } seg.copyFrom(seg.asSlice(roff, woff - roff)); roff -= distance; woff -= distance; + return this; } @Override @@ -1238,67 +1217,4 @@ class MemSegBuffer extends ResourceSupport implements Buff Object recoverableMemory() { return base; } - - // - private ByteBufAdaptor adaptor; - @Override - public ByteBuf asByteBuf() { - ByteBufAdaptor bba = adaptor; - if (bba == null) { - ByteBufAllocatorAdaptor alloc = new ByteBufAllocatorAdaptor( - BufferAllocator.heap(), BufferAllocator.direct()); - return adaptor = new ByteBufAdaptor(alloc, this); - } - return bba; - } - - @Override - public MemSegBuffer retain(int increment) { - for (int i = 0; i < increment; i++) { - acquire(); - } - return this; - } - - @Override - public int refCnt() { - return isAccessible()? 1 + countBorrows() : 0; - } - - @Override - public MemSegBuffer retain() { - return retain(1); - } - - @Override - public MemSegBuffer touch() { - return this; - } - - @Override - public MemSegBuffer touch(Object hint) { - return this; - } - - @Override - public boolean release() { - return release(1); - } - - @Override - public boolean release(int decrement) { - int refCount = 1 + countBorrows(); - if (!isAccessible() || decrement > refCount) { - throw new IllegalReferenceCountException(refCount, -decrement); - } - for (int i = 0; i < decrement; i++) { - try { - close(); - } catch (RuntimeException e) { - throw new IllegalReferenceCountException(e); - } - } - return !isAccessible(); - } - // } diff --git a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/NativeMemorySegmentManager.java b/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/NativeMemorySegmentManager.java deleted file mode 100644 index 55b1c8c..0000000 --- a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/NativeMemorySegmentManager.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.memseg; - -import io.netty.buffer.api.internal.Statics; -import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.ResourceScope; - -import java.lang.ref.Cleaner; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; - -import static jdk.incubator.foreign.ResourceScope.newSharedScope; - -public class NativeMemorySegmentManager extends AbstractMemorySegmentManager { - private static final ConcurrentHashMap CLEANUP_ACTIONS = new ConcurrentHashMap<>(); - private static final Function CLEANUP_ACTION_MAKER = s -> new ReduceNativeMemoryUsage(s); - - static Runnable getCleanupAction(long size) { - return CLEANUP_ACTIONS.computeIfAbsent(size, CLEANUP_ACTION_MAKER); - } - - private static final class ReduceNativeMemoryUsage implements Runnable { - private final long size; - - private ReduceNativeMemoryUsage(long size) { - this.size = size; - } - - @Override - public void run() { - Statics.MEM_USAGE_NATIVE.add(-size); - } - - @Override - public String toString() { - return "ReduceNativeMemoryUsage(by " + size + " bytes)"; - } - } - - @Override - public boolean isNative() { - return true; - } - - @Override - protected MemorySegment createSegment(long size, Cleaner cleaner) { - final ResourceScope scope = cleaner == null ? newSharedScope() : newSharedScope(cleaner); - scope.addCloseAction(getCleanupAction(size)); - var segment = MemorySegment.allocateNative(size, scope); - Statics.MEM_USAGE_NATIVE.add(size); - return segment; - } -} diff --git a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/ReduceNativeMemoryUsage.java b/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/ReduceNativeMemoryUsage.java new file mode 100644 index 0000000..e998d61 --- /dev/null +++ b/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/ReduceNativeMemoryUsage.java @@ -0,0 +1,21 @@ +package io.netty.buffer.api.memseg; + +import io.netty.buffer.api.internal.Statics; + +final class ReduceNativeMemoryUsage implements Runnable { + private final long size; + + ReduceNativeMemoryUsage(long size) { + this.size = size; + } + + @Override + public void run() { + Statics.MEM_USAGE_NATIVE.add(-size); + } + + @Override + public String toString() { + return "ReduceNativeMemoryUsage(by " + size + " bytes)"; + } +} diff --git a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/SegmentMemoryManagers.java b/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/SegmentMemoryManagers.java index 9d1d6dc..898a16d 100644 --- a/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/SegmentMemoryManagers.java +++ b/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/SegmentMemoryManagers.java @@ -15,27 +15,88 @@ */ package io.netty.buffer.api.memseg; +import io.netty.buffer.api.AllocationType; +import io.netty.buffer.api.AllocatorControl; +import io.netty.buffer.api.Buffer; +import io.netty.buffer.api.Drop; import io.netty.buffer.api.MemoryManager; -import io.netty.buffer.api.MemoryManagers; +import io.netty.buffer.api.StandardAllocationTypes; +import io.netty.buffer.api.internal.ArcDrop; +import io.netty.buffer.api.internal.Statics; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.ResourceScope; -public class SegmentMemoryManagers implements MemoryManagers { - @Override - public MemoryManager getHeapMemoryManager() { - return new HeapMemorySegmentManager(); +import java.lang.ref.Cleaner; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +import static jdk.incubator.foreign.ResourceScope.newSharedScope; + +public class SegmentMemoryManagers implements MemoryManager { + private static final ConcurrentHashMap CLEANUP_ACTIONS = new ConcurrentHashMap<>(); + private static final Function CLEANUP_ACTION_MAKER = s -> new ReduceNativeMemoryUsage(s); + + static Runnable getCleanupAction(long size) { + return CLEANUP_ACTIONS.computeIfAbsent(size, CLEANUP_ACTION_MAKER); + } + + private static MemorySegment createHeapSegment(long size) { + return MemorySegment.ofArray(new byte[Math.toIntExact(size)]); + } + + private static MemorySegment createNativeSegment(long size, Cleaner cleaner) { + final ResourceScope scope = cleaner == null ? newSharedScope() : newSharedScope(cleaner); + scope.addCloseAction(getCleanupAction(size)); + var segment = MemorySegment.allocateNative(size, scope); + Statics.MEM_USAGE_NATIVE.add(size); + return segment; } @Override - public MemoryManager getNativeMemoryManager() { - return new NativeMemorySegmentManager(); + public Buffer allocateShared(AllocatorControl allocatorControl, long size, Drop drop, Cleaner cleaner, + AllocationType type) { + if (type instanceof StandardAllocationTypes stype) { + var segment = switch (stype) { + case ON_HEAP -> createHeapSegment(size); + case OFF_HEAP -> createNativeSegment(size, cleaner); + }; + return new MemSegBuffer(segment, segment, Statics.convert(drop), allocatorControl); + } + throw new IllegalArgumentException("Unknown allocation type: " + type); } @Override - public String getImplementationName() { + public Buffer allocateConstChild(Buffer readOnlyConstParent) { + assert readOnlyConstParent.readOnly(); + MemSegBuffer buf = (MemSegBuffer) readOnlyConstParent; + return new MemSegBuffer(buf); + } + + @Override + public Drop drop() { + return Statics.convert(MemSegBuffer.SEGMENT_CLOSE); + } + + @Override + public Object unwrapRecoverableMemory(Buffer buf) { + var b = (MemSegBuffer) buf; + return b.recoverableMemory(); + } + + @Override + public Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop drop) { + var segment = (MemorySegment) recoverableMemory; + return new MemSegBuffer(segment, segment, Statics.convert(ArcDrop.acquire(drop)), allocatorControl); + } + + @Override + public Object sliceMemory(Object memory, int offset, int length) { + var segment = (MemorySegment) memory; + return segment.asSlice(offset, length); + } + + @Override + public String implementationName() { return "MemorySegment"; } - - @Override - public String toString() { - return "MS"; - } } diff --git a/buffer-memseg/src/main/java/module-info.java b/buffer-memseg/src/main/java/module-info.java index 52f0beb..bd8288a 100644 --- a/buffer-memseg/src/main/java/module-info.java +++ b/buffer-memseg/src/main/java/module-info.java @@ -13,14 +13,13 @@ * License for the specific language governing permissions and limitations * under the License. */ -import io.netty.buffer.api.MemoryManagers; +import io.netty.buffer.api.MemoryManager; import io.netty.buffer.api.memseg.SegmentMemoryManagers; module netty.incubator.buffer.memseg { requires jdk.incubator.foreign; requires io.netty.common; requires io.netty.buffer; - requires netty.incubator.buffer; // Optional dependencies, needed for some examples. requires static java.logging; @@ -29,6 +28,6 @@ module netty.incubator.buffer.memseg { // Also means we don't have to make all test methods etc. public for JUnit to access them. opens io.netty.buffer.api.memseg; - provides MemoryManagers with + provides MemoryManager with SegmentMemoryManagers; } diff --git a/buffer-memseg/src/test/java/io/netty/buffer/api/memseg/benchmarks/MemSegBufAccessBenchmark.java b/buffer-memseg/src/test/java/io/netty/buffer/api/memseg/benchmarks/MemSegBufAccessBenchmark.java index f55b809..e79dff2 100644 --- a/buffer-memseg/src/test/java/io/netty/buffer/api/memseg/benchmarks/MemSegBufAccessBenchmark.java +++ b/buffer-memseg/src/test/java/io/netty/buffer/api/memseg/benchmarks/MemSegBufAccessBenchmark.java @@ -15,8 +15,8 @@ */ package io.netty.buffer.api.memseg.benchmarks; -import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.Buffer; +import io.netty.buffer.api.BufferAllocator; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -43,13 +43,13 @@ public class MemSegBufAccessBenchmark { DIRECT { @Override Buffer newBuffer() { - return BufferAllocator.direct().allocate(64); + return BufferAllocator.offHeapUnpooled().allocate(64); } }, HEAP { @Override Buffer newBuffer() { - return BufferAllocator.heap().allocate(64); + return BufferAllocator.onHeapUnpooled().allocate(64); } }, // COMPOSITE { diff --git a/buffer-memseg/src/test/java/io/netty/buffer/api/memseg/benchmarks/MemorySegmentClosedByCleanerBenchmark.java b/buffer-memseg/src/test/java/io/netty/buffer/api/memseg/benchmarks/MemorySegmentClosedByCleanerBenchmark.java index 601400c..2a535c5 100644 --- a/buffer-memseg/src/test/java/io/netty/buffer/api/memseg/benchmarks/MemorySegmentClosedByCleanerBenchmark.java +++ b/buffer-memseg/src/test/java/io/netty/buffer/api/memseg/benchmarks/MemorySegmentClosedByCleanerBenchmark.java @@ -16,9 +16,9 @@ package io.netty.buffer.api.memseg.benchmarks; import io.netty.buffer.api.BufferAllocator; +import io.netty.buffer.api.MemoryManager; import io.netty.buffer.api.memseg.SegmentMemoryManagers; import io.netty.buffer.api.Buffer; -import io.netty.buffer.api.MemoryManagers; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -64,9 +64,9 @@ public class MemorySegmentClosedByCleanerBenchmark { } } - var allocs = MemoryManagers.using(new SegmentMemoryManagers(), () -> { - return new Allocators(BufferAllocator.heap(), BufferAllocator.pooledHeap(), - BufferAllocator.direct(), BufferAllocator.pooledDirect()); + var allocs = MemoryManager.using(new SegmentMemoryManagers(), () -> { + return new Allocators(BufferAllocator.onHeapUnpooled(), BufferAllocator.onHeapPooled(), + BufferAllocator.offHeapUnpooled(), BufferAllocator.offHeapPooled()); }); heap = allocs.heap; diff --git a/buffer-tests/pom.xml b/buffer-tests/pom.xml index 66c5707..f522dd6 100644 --- a/buffer-tests/pom.xml +++ b/buffer-tests/pom.xml @@ -127,9 +127,13 @@ + + io.netty + netty-buffer + io.netty.incubator - netty-incubator-buffer-api + netty-incubator-buffer-memseg org.junit.jupiter @@ -189,31 +193,4 @@ jmh-generator-annprocess - - - - Java 17 support - - 17 - - - - io.netty.incubator - netty-incubator-buffer-memseg - - - - - Java 11 support for tests - - !17 - - - - io.netty.incubator - netty-incubator-buffer-memseg-dummy - - - - \ No newline at end of file diff --git a/buffer-tests/src/main/java/module-info.java b/buffer-tests/src/main/java/module-info.java index 2560866..04b6d20 100644 --- a/buffer-tests/src/main/java/module-info.java +++ b/buffer-tests/src/main/java/module-info.java @@ -1,3 +1,5 @@ +import io.netty.buffer.api.MemoryManager; + /* * Copyright 2021 The Netty Project * @@ -20,8 +22,7 @@ open module netty.incubator.buffer.tests { // Optional dependencies, needed for some examples. requires static java.logging; - requires netty.incubator.buffer; // We need to require memseg in order for its implementation to be service loaded. // Just having it on the module path is not enough. - requires netty.incubator.buffer.memseg; + requires static netty.incubator.buffer.memseg; } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferBulkAccessTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferBulkAccessTest.java index 3458687..ba9a495 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferBulkAccessTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferBulkAccessTest.java @@ -17,15 +17,12 @@ package io.netty.buffer.api.tests; import io.netty.buffer.api.Buffer; import io.netty.buffer.api.BufferAllocator; -import io.netty.buffer.api.CompositeBuffer; -import io.netty.buffer.api.Scope; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import java.nio.ByteBuffer; -import static java.nio.ByteOrder.BIG_ENDIAN; -import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static io.netty.buffer.api.CompositeBuffer.compose; import static org.assertj.core.api.Assertions.assertThat; public class BufferBulkAccessTest extends BufferTestSupport { @@ -46,18 +43,14 @@ public class BufferBulkAccessTest extends BufferTestSupport { void copyIntoByteArray(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN).writeLong(0x0102030405060708L); + buf.writeLong(0x0102030405060708L); byte[] array = new byte[8]; buf.copyInto(0, array, 0, array.length); assertThat(array).containsExactly(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08); - buf.writerOffset(0).order(LITTLE_ENDIAN).writeLong(0x0102030405060708L); - buf.copyInto(0, array, 0, array.length); - assertThat(array).containsExactly(0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01); - array = new byte[6]; buf.copyInto(1, array, 1, 3); - assertThat(array).containsExactly(0x00, 0x07, 0x06, 0x05, 0x00, 0x00); + assertThat(array).containsExactly(0x00, 0x02, 0x03, 0x04, 0x00, 0x00); } } @@ -76,26 +69,26 @@ public class BufferBulkAccessTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") void copyIntoOnHeapBuf(Fixture fixture) { - testCopyIntoBuf(fixture, BufferAllocator.heap()::allocate); + testCopyIntoBuf(fixture, BufferAllocator.onHeapUnpooled()::allocate); } @ParameterizedTest @MethodSource("allocators") void copyIntoOffHeapBuf(Fixture fixture) { - testCopyIntoBuf(fixture, BufferAllocator.direct()::allocate); + testCopyIntoBuf(fixture, BufferAllocator.offHeapUnpooled()::allocate); } @ParameterizedTest @MethodSource("allocators") void copyIntoCompositeOnHeapOnHeapBuf(Fixture fixture) { - try (var a = BufferAllocator.heap(); - var b = BufferAllocator.heap()) { + try (var a = BufferAllocator.onHeapUnpooled(); + var b = BufferAllocator.onHeapUnpooled()) { testCopyIntoBuf(fixture, size -> { int first = size / 2; int second = size - first; try (var bufFirst = a.allocate(first); var bufSecond = b.allocate(second)) { - return CompositeBuffer.compose(a, bufFirst.send(), bufSecond.send()); + return compose(a, bufFirst.send(), bufSecond.send()); } }); } @@ -104,14 +97,14 @@ public class BufferBulkAccessTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") void copyIntoCompositeOnHeapOffHeapBuf(Fixture fixture) { - try (var a = BufferAllocator.heap(); - var b = BufferAllocator.direct()) { + try (var a = BufferAllocator.onHeapUnpooled(); + var b = BufferAllocator.offHeapUnpooled()) { testCopyIntoBuf(fixture, size -> { int first = size / 2; int second = size - first; try (var bufFirst = a.allocate(first); var bufSecond = b.allocate(second)) { - return CompositeBuffer.compose(a, bufFirst.send(), bufSecond.send()); + return compose(a, bufFirst.send(), bufSecond.send()); } }); } @@ -120,14 +113,14 @@ public class BufferBulkAccessTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") void copyIntoCompositeOffHeapOnHeapBuf(Fixture fixture) { - try (var a = BufferAllocator.direct(); - var b = BufferAllocator.heap()) { + try (var a = BufferAllocator.offHeapUnpooled(); + var b = BufferAllocator.onHeapUnpooled()) { testCopyIntoBuf(fixture, size -> { int first = size / 2; int second = size - first; try (var bufFirst = a.allocate(first); var bufSecond = b.allocate(second)) { - return CompositeBuffer.compose(a, bufFirst.send(), bufSecond.send()); + return compose(a, bufFirst.send(), bufSecond.send()); } }); } @@ -136,14 +129,14 @@ public class BufferBulkAccessTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") void copyIntoCompositeOffHeapOffHeapBuf(Fixture fixture) { - try (var a = BufferAllocator.direct(); - var b = BufferAllocator.direct()) { + try (var a = BufferAllocator.offHeapUnpooled(); + var b = BufferAllocator.offHeapUnpooled()) { testCopyIntoBuf(fixture, size -> { int first = size / 2; int second = size - first; try (var bufFirst = a.allocate(first); var bufSecond = b.allocate(second)) { - return CompositeBuffer.compose(a, bufFirst.send(), bufSecond.send()); + return compose(a, bufFirst.send(), bufSecond.send()); } }); } @@ -152,15 +145,14 @@ public class BufferBulkAccessTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") void copyIntoCompositeOnHeapOnHeapBufCopy(Fixture fixture) { - try (var a = BufferAllocator.heap(); - var b = BufferAllocator.heap(); - var scope = new Scope()) { + try (var a = BufferAllocator.onHeapUnpooled(); + var b = BufferAllocator.onHeapUnpooled()) { testCopyIntoBuf(fixture, size -> { int first = size / 2; int second = size - first; try (var bufFirst = a.allocate(first); var bufSecond = b.allocate(second)) { - return scope.add(CompositeBuffer.compose(a, bufFirst.send(), bufSecond.send())).writerOffset(size).copy(); + return compose(a, bufFirst.send(), bufSecond.send()).writerOffset(size).copy(); } }); } @@ -169,15 +161,14 @@ public class BufferBulkAccessTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") void copyIntoCompositeOnHeapOffHeapBufCopy(Fixture fixture) { - try (var a = BufferAllocator.heap(); - var b = BufferAllocator.direct(); - var scope = new Scope()) { + try (var a = BufferAllocator.onHeapUnpooled(); + var b = BufferAllocator.offHeapUnpooled()) { testCopyIntoBuf(fixture, size -> { int first = size / 2; int second = size - first; try (var bufFirst = a.allocate(first); var bufSecond = b.allocate(second)) { - return scope.add(CompositeBuffer.compose(a, bufFirst.send(), bufSecond.send())).writerOffset(size).copy(); + return compose(a, bufFirst.send(), bufSecond.send()).writerOffset(size).copy(); } }); } @@ -186,15 +177,14 @@ public class BufferBulkAccessTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") void copyIntoCompositeOffHeapOnHeapBufCopy(Fixture fixture) { - try (var a = BufferAllocator.direct(); - var b = BufferAllocator.heap(); - var scope = new Scope()) { + try (var a = BufferAllocator.offHeapUnpooled(); + var b = BufferAllocator.onHeapUnpooled()) { testCopyIntoBuf(fixture, size -> { int first = size / 2; int second = size - first; try (var bufFirst = a.allocate(first); var bufSecond = b.allocate(second)) { - return scope.add(CompositeBuffer.compose(a, bufFirst.send(), bufSecond.send())).writerOffset(size).copy(); + return compose(a, bufFirst.send(), bufSecond.send()).writerOffset(size).copy(); } }); } @@ -203,15 +193,14 @@ public class BufferBulkAccessTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") void copyIntoCompositeOffHeapOffHeapBufCopy(Fixture fixture) { - try (var a = BufferAllocator.direct(); - var b = BufferAllocator.direct(); - var scope = new Scope()) { + try (var a = BufferAllocator.offHeapUnpooled(); + var b = BufferAllocator.offHeapUnpooled()) { testCopyIntoBuf(fixture, size -> { int first = size / 2; int second = size - first; try (var bufFirst = a.allocate(first); var bufSecond = b.allocate(second)) { - return scope.add(CompositeBuffer.compose(a, bufFirst.send(), bufSecond.send())).writerOffset(size).copy(); + return compose(a, bufFirst.send(), bufSecond.send()).writerOffset(size).copy(); } }); } @@ -219,48 +208,22 @@ public class BufferBulkAccessTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") - void byteIterationOfBigEndianBuffers(Fixture fixture) { + void byteIterationOfBuffers(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(0x28)) { - buf.order(BIG_ENDIAN); // The byte order should have no impact. + Buffer buf = allocator.allocate(8)) { checkByteIteration(buf); - buf.reset(); + buf.resetOffsets(); checkByteIterationOfRegion(buf); } } @ParameterizedTest @MethodSource("allocators") - void byteIterationOfLittleEndianBuffers(Fixture fixture) { + void reverseByteIterationOfBuffers(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(0x28)) { - buf.order(LITTLE_ENDIAN); // The byte order should have no impact. - checkByteIteration(buf); - buf.reset(); - checkByteIterationOfRegion(buf); - } - } - - @ParameterizedTest - @MethodSource("allocators") - void reverseByteIterationOfBigEndianBuffers(Fixture fixture) { - try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(0x28)) { - buf.order(BIG_ENDIAN); // The byte order should have no impact. checkReverseByteIteration(buf); - buf.reset(); - checkReverseByteIterationOfRegion(buf); - } - } - - @ParameterizedTest - @MethodSource("allocators") - void reverseByteIterationOfLittleEndianBuffers(Fixture fixture) { - try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(0x28)) { - buf.order(LITTLE_ENDIAN); // The byte order should have no impact. - checkReverseByteIteration(buf); - buf.reset(); + buf.resetOffsets(); checkReverseByteIterationOfRegion(buf); } } @@ -295,4 +258,17 @@ public class BufferBulkAccessTest extends BufferTestSupport { assertThat(toByteArray(buffer)).containsExactly(1, 2, 3, 4, 5, 6, 7, 0); } } + + @ParameterizedTest + @MethodSource("allocators") + public void writeBytesWithOffsetMustWriteAllBytesFromByteArray(Fixture fixture) { + try (BufferAllocator allocator = fixture.createAllocator(); + Buffer buffer = allocator.allocate(3)) { + buffer.writeByte((byte) 1); + buffer.writeBytes(new byte[] {2, 3, 4, 5, 6, 7}, 1, 2); + assertThat(buffer.writerOffset()).isEqualTo(3); + assertThat(buffer.readerOffset()).isZero(); + assertThat(toByteArray(buffer)).containsExactly(1, 3, 4); + } + } } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferByteOffsettedAccessorsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferByteOffsettedAccessorsTest.java index 294940c..d8c000c 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferByteOffsettedAccessorsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferByteOffsettedAccessorsTest.java @@ -20,7 +20,6 @@ import io.netty.buffer.api.BufferAllocator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferByteOffsettedAccessorsTest extends BufferTestSupport { @@ -59,7 +58,6 @@ public class BufferByteOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfByteMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); byte value = 0x01; buf.writeByte(value); buf.setByte(0, (byte) 0x10); @@ -159,7 +157,6 @@ public class BufferByteOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfUnsignedByteMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x01; buf.writeUnsignedByte(value); buf.setByte(0, (byte) 0x10); @@ -278,7 +275,6 @@ public class BufferByteOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfByteMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); byte value = 0x01; buf.setByte(0, value); buf.writerOffset(Long.BYTES); @@ -326,7 +322,6 @@ public class BufferByteOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfUnsignedByteMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x01; buf.setUnsignedByte(0, value); buf.writerOffset(Long.BYTES); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCharOffsettedAccessorsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCharOffsettedAccessorsTest.java index 183be45..216ab6e 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCharOffsettedAccessorsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCharOffsettedAccessorsTest.java @@ -20,7 +20,6 @@ import io.netty.buffer.api.BufferAllocator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferCharOffsettedAccessorsTest extends BufferTestSupport { @@ -58,7 +57,6 @@ public class BufferCharOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfCharMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); char value = 0x0102; buf.writeChar(value); buf.setByte(0, (byte) 0x10); @@ -175,7 +173,6 @@ public class BufferCharOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfCharMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); char value = 0x0102; buf.setChar(0, value); buf.writerOffset(Long.BYTES); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCleanerTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCleanerTest.java index 4487549..c40153d 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCleanerTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCleanerTest.java @@ -15,39 +15,35 @@ */ package io.netty.buffer.api.tests; -import io.netty.buffer.api.MemoryManagers; +import io.netty.buffer.api.MemoryManager; import io.netty.buffer.api.internal.Statics; -import org.junit.jupiter.api.condition.DisabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; -import static io.netty.buffer.api.MemoryManagers.using; +import static io.netty.buffer.api.MemoryManager.using; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeTrue; public class BufferCleanerTest extends BufferTestSupport { - @SuppressWarnings("OptionalGetWithoutIsPresent") - static Fixture[] memorySegmentAllocators() { - MemoryManagers managers = MemoryManagers.getAllManagers() - .map(p -> p.get()) - .filter(mm -> "MS".equals(mm.toString())) - .findFirst().get(); + static Fixture[] unsafeAllocators() { + Optional maybeManager = MemoryManager.lookupImplementation("Unsafe"); + assumeTrue(maybeManager.isPresent()); + MemoryManager manager = maybeManager.get(); List initFixtures = initialAllocators().stream().flatMap(f -> { Stream.Builder builder = Stream.builder(); - builder.add(new Fixture(f + "/" + managers, () -> using(managers, f), f.getProperties())); + builder.add(new Fixture(f + "/" + manager, () -> using(manager, f), f.getProperties())); return builder.build(); }).collect(Collectors.toList()); return fixtureCombinations(initFixtures).filter(f -> f.isDirect()).toArray(Fixture[]::new); } - // Only run this one on JDK 17. - @DisabledForJreRange(min = JRE.JAVA_11, max = JRE.JAVA_16) @ParameterizedTest - @MethodSource("memorySegmentAllocators") + @MethodSource("unsafeAllocators") public void bufferMustBeClosedByCleaner(Fixture fixture) throws InterruptedException { var initial = Statics.MEM_USAGE_NATIVE.sum(); int allocationSize = 1024; diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCompactTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCompactTest.java index cc45689..f0c4840 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCompactTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCompactTest.java @@ -22,7 +22,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import static io.netty.buffer.api.internal.Statics.acquire; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferCompactTest extends BufferTestSupport { @@ -31,7 +30,7 @@ public class BufferCompactTest extends BufferTestSupport { @MethodSource("allocators") public void compactMustDiscardReadBytes(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(16, BIG_ENDIAN)) { + Buffer buf = allocator.allocate(16)) { buf.writeLong(0x0102030405060708L).writeInt(0x090A0B0C); assertEquals(0x01020304, buf.readInt()); assertEquals(12, buf.writerOffset()); @@ -53,7 +52,7 @@ public class BufferCompactTest extends BufferTestSupport { @MethodSource("allocators") public void compactMustThrowForUnownedBuffer(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(8, BIG_ENDIAN)) { + Buffer buf = allocator.allocate(8)) { buf.writeLong(0x0102030405060708L); assertEquals((byte) 0x01, buf.readByte()); try (Buffer ignore = acquire((ResourceSupport) buf)) { diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferComponentIterationTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferComponentIterationTest.java index ab4c78e..509c943 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferComponentIterationTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferComponentIterationTest.java @@ -31,8 +31,6 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import static java.nio.ByteOrder.BIG_ENDIAN; -import static java.nio.ByteOrder.LITTLE_ENDIAN; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -70,7 +68,7 @@ public class BufferComponentIterationTest extends BufferTestSupport { @Test public void compositeBufferComponentCountMustBeTransitiveSum() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { Buffer buf; try (Buffer a = allocator.allocate(8); Buffer b = allocator.allocate(8); @@ -107,20 +105,16 @@ public class BufferComponentIterationTest extends BufferTestSupport { public void forEachReadableMustVisitBuffer(Fixture fixture) { long value = 0x0102030405060708L; try (BufferAllocator allocator = fixture.createAllocator(); - Buffer bufBERW = allocator.allocate(8).order(BIG_ENDIAN).writeLong(value); - Buffer bufLERW = allocator.allocate(8).order(LITTLE_ENDIAN).writeLong(value); - Buffer bufBERO = allocator.allocate(8).order(BIG_ENDIAN).writeLong(value).makeReadOnly(); - Buffer bufLERO = allocator.allocate(8).order(LITTLE_ENDIAN).writeLong(value).makeReadOnly()) { + Buffer bufBERW = allocator.allocate(8).writeLong(value); + Buffer bufBERO = allocator.allocate(8).writeLong(value).makeReadOnly()) { verifyForEachReadableSingleComponent(fixture, bufBERW); - verifyForEachReadableSingleComponent(fixture, bufLERW); verifyForEachReadableSingleComponent(fixture, bufBERO); - verifyForEachReadableSingleComponent(fixture, bufLERO); } } @Test public void forEachReadableMustVisitAllReadableConstituentBuffersInOrder() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { Buffer composite; try (Buffer a = allocator.allocate(4); Buffer b = allocator.allocate(4); @@ -157,7 +151,7 @@ public class BufferComponentIterationTest extends BufferTestSupport { @Test public void forEachReadableMustStopIterationWhenProcessorReturnsFalse() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { Buffer composite; try (Buffer a = allocator.allocate(4); Buffer b = allocator.allocate(4); @@ -228,21 +222,18 @@ public class BufferComponentIterationTest extends BufferTestSupport { @MethodSource("allocators") public void forEachReadableMustExposeByteCursors(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(32).order(BIG_ENDIAN)) { + Buffer buf = allocator.allocate(32)) { buf.writeLong(0x0102030405060708L); buf.writeLong(0x1112131415161718L); assertEquals(0x01020304, buf.readInt()); - try (Buffer actualData = allocator.allocate(buf.readableBytes()).order(BIG_ENDIAN); - Buffer expectedData = allocator.allocate(12).order(BIG_ENDIAN)) { + try (Buffer actualData = allocator.allocate(buf.readableBytes()); + Buffer expectedData = allocator.allocate(12)) { expectedData.writeInt(0x05060708); expectedData.writeInt(0x11121314); expectedData.writeInt(0x15161718); buf.forEachReadable(0, (i, component) -> { ByteCursor forward = component.openCursor(); - while (forward.readLong()) { - actualData.writeLong(forward.getLong()); - } while (forward.readByte()) { actualData.writeByte(forward.getByte()); } @@ -261,23 +252,20 @@ public class BufferComponentIterationTest extends BufferTestSupport { @MethodSource("nonCompositeAllocators") public void forEachWritableMustVisitBuffer(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer bufBERW = allocator.allocate(8).order(BIG_ENDIAN); - Buffer bufLERW = allocator.allocate(8).order(LITTLE_ENDIAN)) { + Buffer bufBERW = allocator.allocate(8)) { verifyForEachWritableSingleComponent(fixture, bufBERW); - verifyForEachWritableSingleComponent(fixture, bufLERW); } } @Test public void forEachWritableMustVisitAllWritableConstituentBuffersInOrder() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { Buffer buf; try (Buffer a = allocator.allocate(8); Buffer b = allocator.allocate(8); Buffer c = allocator.allocate(8)) { buf = CompositeBuffer.compose(allocator, a.send(), b.send(), c.send()); } - buf.order(BIG_ENDIAN); buf.forEachWritable(0, (index, component) -> { component.writableBuffer().putLong(0x0102030405060708L + 0x1010101010101010L * index); return true; @@ -317,7 +305,7 @@ public class BufferComponentIterationTest extends BufferTestSupport { @MethodSource("allocators") public void forEachWritableChangesMadeToByteBufferComponentMustBeReflectedInBuffer(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(9).order(BIG_ENDIAN)) { + Buffer buf = allocator.allocate(9)) { buf.writeByte((byte) 0xFF); AtomicInteger writtenCounter = new AtomicInteger(); buf.forEachWritable(0, (index, component) -> { diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCompositionTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCompositionTest.java index 2814b77..1736ebb 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCompositionTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferCompositionTest.java @@ -26,12 +26,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import java.nio.ByteOrder; - import static io.netty.buffer.api.internal.Statics.acquire; import static io.netty.buffer.api.internal.Statics.isOwned; -import static java.nio.ByteOrder.BIG_ENDIAN; -import static java.nio.ByteOrder.LITTLE_ENDIAN; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -39,7 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class BufferCompositionTest extends BufferTestSupport { @Test public void compositeBuffersCannotHaveDuplicateComponents() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { Send a = allocator.allocate(4).send(); var e = assertThrows(IllegalStateException.class, () -> CompositeBuffer.compose(allocator, a, a)); assertThat(e).hasMessageContaining("already been received"); @@ -54,7 +50,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void compositeBufferFromSends() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); Buffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send(), @@ -66,13 +62,13 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void compositeBufferMustNotBeAllowedToContainThemselves() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { CompositeBuffer bufA = CompositeBuffer.compose(allocator, allocator.allocate(4).send()); Send sendA = bufA.send(); try { assertThrows(BufferClosedException.class, () -> bufA.extendWith(sendA)); } finally { - sendA.discard(); + sendA.close(); } CompositeBuffer bufB = CompositeBuffer.compose(allocator, allocator.allocate(4).send()); @@ -80,7 +76,7 @@ public class BufferCompositionTest extends BufferTestSupport { try (CompositeBuffer compositeBuffer = CompositeBuffer.compose(allocator, sendB)) { assertThrows(IllegalStateException.class, () -> compositeBuffer.extendWith(sendB)); } finally { - sendB.discard(); + sendB.close(); } } } @@ -90,7 +86,7 @@ public class BufferCompositionTest extends BufferTestSupport { public void ensureWritableOnCompositeBuffersMustRespectExistingBigEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator()) { Buffer composite; - try (Buffer a = allocator.allocate(4, BIG_ENDIAN)) { + try (Buffer a = allocator.allocate(4)) { composite = CompositeBuffer.compose(allocator, a.send()); } try (composite) { @@ -102,29 +98,9 @@ public class BufferCompositionTest extends BufferTestSupport { } } - @ParameterizedTest - @MethodSource("allocators") - public void ensureWritableOnCompositeBuffersMustRespectExistingLittleEndianByteOrder(Fixture fixture) { - try (BufferAllocator allocator = fixture.createAllocator(); - Buffer composite = CompositeBuffer.compose(allocator, allocator.allocate(4, LITTLE_ENDIAN).send())) { - composite.writeInt(0x05060708); - composite.ensureWritable(4); - composite.writeInt(0x01020304); - assertEquals(0x0102030405060708L, composite.readLong()); - } - } - - @Test - public void emptyCompositeBufferMustUseNativeByteOrder() { - try (BufferAllocator allocator = BufferAllocator.heap(); - Buffer composite = CompositeBuffer.compose(allocator)) { - assertThat(composite.order()).isEqualTo(ByteOrder.nativeOrder()); - } - } - @Test public void extendOnNonCompositeBufferMustThrow() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); Buffer a = allocator.allocate(8); Buffer b = allocator.allocate(8)) { assertThrows(ClassCastException.class, () -> ((CompositeBuffer) a).extendWith(b.send())); @@ -133,7 +109,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void extendingNonOwnedCompositeBufferMustThrow() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); Buffer a = allocator.allocate(8); Buffer b = allocator.allocate(8); CompositeBuffer composed = CompositeBuffer.compose(allocator, a.send())) { @@ -146,7 +122,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void extendingCompositeBufferWithItselfMustThrow() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { CompositeBuffer composite; try (Buffer a = allocator.allocate(8)) { composite = CompositeBuffer.compose(allocator, a.send()); @@ -159,13 +135,13 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void extendingWithZeroCapacityBufferHasNoEffect() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator)) { composite.extendWith(CompositeBuffer.compose(allocator).send()); assertThat(composite.capacity()).isZero(); assertThat(composite.countComponents()).isZero(); } - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { Buffer a = allocator.allocate(1); CompositeBuffer composite = CompositeBuffer.compose(allocator, a.send()); assertTrue(isOwned(composite)); @@ -182,18 +158,18 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void extendingCompositeBufferWithNullMustThrow() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator)) { assertThrows(NullPointerException.class, () -> composite.extendWith(null)); } } @Test - public void extendingCompositeBufferMustIncreaseCapacityByGivenBigEndianBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap(); + public void extendingCompositeBufferMustIncreaseCapacityByGivenBuffer() { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator)) { assertThat(composite.capacity()).isZero(); - try (Buffer buf = allocator.allocate(8, BIG_ENDIAN)) { + try (Buffer buf = allocator.allocate(8)) { composite.extendWith(buf.send()); } assertThat(composite.capacity()).isEqualTo(8); @@ -203,72 +179,12 @@ public class BufferCompositionTest extends BufferTestSupport { } @Test - public void extendingCompositeBufferMustIncreaseCapacityByGivenLittleEndianBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap(); - CompositeBuffer composite = CompositeBuffer.compose(allocator)) { - assertThat(composite.capacity()).isZero(); - try (Buffer buf = allocator.allocate(8, LITTLE_ENDIAN)) { - composite.extendWith(buf.send()); - } - assertThat(composite.capacity()).isEqualTo(8); - composite.writeLong(0x0102030405060708L); - assertThat(composite.readLong()).isEqualTo(0x0102030405060708L); - } - } - - @Test - public void extendingBigEndianCompositeBufferMustThrowIfExtensionIsLittleEndian() { - try (BufferAllocator allocator = BufferAllocator.heap()) { - CompositeBuffer composite; - try (Buffer a = allocator.allocate(8, BIG_ENDIAN)) { - composite = CompositeBuffer.compose(allocator, a.send()); - } - try (composite) { - try (Buffer b = allocator.allocate(8, LITTLE_ENDIAN)) { - var exc = assertThrows(IllegalArgumentException.class, - () -> composite.extendWith(b.send())); - assertThat(exc).hasMessageContaining("byte order"); - } - } - } - } - - @Test - public void extendingLittleEndianCompositeBufferMustThrowIfExtensionIsBigEndian() { - try (BufferAllocator allocator = BufferAllocator.heap()) { - CompositeBuffer composite; - try (Buffer a = allocator.allocate(8, LITTLE_ENDIAN)) { - composite = CompositeBuffer.compose(allocator, a.send()); - } - try (composite) { - try (Buffer b = allocator.allocate(8, BIG_ENDIAN)) { - var exc = assertThrows(IllegalArgumentException.class, - () -> composite.extendWith(b.send())); - assertThat(exc).hasMessageContaining("byte order"); - } - } - } - } - - @Test - public void emptyCompositeBufferMustAllowExtendingWithBufferWithBigEndianByteOrder() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + public void emptyCompositeBufferMustAllowExtendingWithBuffer() { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { try (CompositeBuffer composite = CompositeBuffer.compose(allocator)) { - try (Buffer b = allocator.allocate(8, BIG_ENDIAN)) { + try (Buffer b = allocator.allocate(8)) { composite.extendWith(b.send()); - assertThat(composite.order()).isEqualTo(BIG_ENDIAN); - } - } - } - } - - @Test - public void emptyCompositeBufferMustAllowExtendingWithBufferWithLittleEndianByteOrder() { - try (BufferAllocator allocator = BufferAllocator.heap()) { - try (CompositeBuffer composite = CompositeBuffer.compose(allocator)) { - try (Buffer b = allocator.allocate(8, LITTLE_ENDIAN)) { - composite.extendWith(b.send()); - assertThat(composite.order()).isEqualTo(LITTLE_ENDIAN); + assertThat(composite.capacity()).isEqualTo(8); } } } @@ -276,7 +192,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void emptyCompositeBufferMustAllowExtendingWithReadOnlyBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { try (CompositeBuffer composite = CompositeBuffer.compose(allocator)) { try (Buffer b = allocator.allocate(8).makeReadOnly()) { composite.extendWith(b.send()); @@ -288,7 +204,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void whenExtendingCompositeBufferWithWriteOffsetAtCapacityExtensionWriteOffsetCanBeNonZero() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { CompositeBuffer composite; try (Buffer a = allocator.allocate(8)) { composite = CompositeBuffer.compose(allocator, a.send()); @@ -307,7 +223,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void whenExtendingCompositeBufferWithWriteOffsetLessThanCapacityExtensionWriteOffsetMustZero() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { CompositeBuffer composite; try (Buffer a = allocator.allocate(8)) { composite = CompositeBuffer.compose(allocator, a.send()); @@ -332,7 +248,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void whenExtendingCompositeBufferWithReadOffsetAtCapacityExtensionReadOffsetCanBeNonZero() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { CompositeBuffer composite; try (Buffer a = allocator.allocate(8)) { composite = CompositeBuffer.compose(allocator, a.send()); @@ -353,7 +269,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void whenExtendingCompositeBufferWithReadOffsetLessThanCapacityExtensionReadOffsetMustZero() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send())) { composite.writeLong(0); composite.readInt(); @@ -375,18 +291,9 @@ public class BufferCompositionTest extends BufferTestSupport { } } - @Test - public void composeMustThrowWhenBuffersHaveMismatchedByteOrder() { - try (BufferAllocator allocator = BufferAllocator.heap(); - Buffer a = allocator.allocate(4, BIG_ENDIAN); - Buffer b = allocator.allocate(4, LITTLE_ENDIAN)) { - assertThrows(IllegalArgumentException.class, () -> CompositeBuffer.compose(allocator, a.send(), b.send())); - } - } - @Test public void composingReadOnlyBuffersMustCreateReadOnlyCompositeBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); Buffer a = allocator.allocate(4).makeReadOnly(); Buffer b = allocator.allocate(4).makeReadOnly(); Buffer composite = CompositeBuffer.compose(allocator, a.send(), b.send())) { @@ -397,14 +304,16 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void composingReadOnlyAndWritableBuffersMustThrow() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { try (Buffer a = allocator.allocate(8).makeReadOnly(); Buffer b = allocator.allocate(8)) { - assertThrows(IllegalArgumentException.class, () -> CompositeBuffer.compose(allocator, a.send(), b.send())); + assertThrows(IllegalArgumentException.class, + () -> CompositeBuffer.compose(allocator, a.send(), b.send())); } try (Buffer a = allocator.allocate(8).makeReadOnly(); Buffer b = allocator.allocate(8)) { - assertThrows(IllegalArgumentException.class, () -> CompositeBuffer.compose(allocator, b.send(), a.send())); + assertThrows(IllegalArgumentException.class, + () -> CompositeBuffer.compose(allocator, b.send(), a.send())); } try (Buffer a = allocator.allocate(8).makeReadOnly(); Buffer b = allocator.allocate(8); @@ -423,7 +332,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void compositeWritableBufferCannotBeExtendedWithReadOnlyBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { CompositeBuffer composite; try (Buffer a = allocator.allocate(8)) { composite = CompositeBuffer.compose(allocator, a.send()); @@ -436,7 +345,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void compositeReadOnlyBufferCannotBeExtendedWithWritableBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { CompositeBuffer composite; try (Buffer a = allocator.allocate(8).makeReadOnly()) { composite = CompositeBuffer.compose(allocator, a.send()); @@ -449,7 +358,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsFloorMustThrowOnOutOfBounds() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -464,7 +373,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsCeilMustThrowOnOutOfBounds() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -479,7 +388,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsFloorMustGiveEmptyBufferForOffsetInFirstComponent() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -497,7 +406,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsFloorMustGiveEmptyBufferForOffsetLastByteInFirstComponent() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -515,7 +424,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsFloorMustGiveBufferWithFirstComponentForOffsetInSecondComponent() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -533,7 +442,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsFloorMustGiveBufferWithFirstComponentForOffsetOnFirstByteInSecondComponent() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -551,7 +460,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsCeilMustGiveBufferWithFirstComponentForOffsetInFirstComponent() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -569,7 +478,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsCeilMustGiveBufferWithFirstComponentFofOffsetOnLastByteInFirstComponent() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -587,7 +496,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsCeilMustGiveBufferWithFirstAndSecondComponentForfOffsetInSecondComponent() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -602,7 +511,7 @@ public class BufferCompositionTest extends BufferTestSupport { } } - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send(), @@ -621,7 +530,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsCeilMustGiveBufferWithFirstComponentForfOffsetOnFirstByteInSecondComponent() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { @@ -639,7 +548,7 @@ public class BufferCompositionTest extends BufferTestSupport { @Test public void splitComponentsCeilMustGiveEmptyBufferForOffsetOnFirstByteInFirstComponent() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); CompositeBuffer composite = CompositeBuffer.compose(allocator, allocator.allocate(8).send(), allocator.allocate(8).send())) { diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferDoubleOffsettedAccessorsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferDoubleOffsettedAccessorsTest.java index 12d6ea6..151e13d 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferDoubleOffsettedAccessorsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferDoubleOffsettedAccessorsTest.java @@ -20,7 +20,6 @@ import io.netty.buffer.api.BufferAllocator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferDoubleOffsettedAccessorsTest extends BufferTestSupport { @@ -58,7 +57,6 @@ public class BufferDoubleOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfDoubleMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); double value = Double.longBitsToDouble(0x0102030405060708L); buf.writeDouble(value); buf.setByte(0, (byte) 0x10); @@ -157,7 +155,6 @@ public class BufferDoubleOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfDoubleMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); double value = Double.longBitsToDouble(0x0102030405060708L); buf.setDouble(0, value); buf.writerOffset(Long.BYTES); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferEnsureWritableTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferEnsureWritableTest.java index 18b428e..ccf4556 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferEnsureWritableTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferEnsureWritableTest.java @@ -77,7 +77,7 @@ public class BufferEnsureWritableTest extends BufferTestSupport { @Test public void ensureWritableMustExpandCapacityOfEmptyCompositeBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); Buffer buf = CompositeBuffer.compose(allocator)) { assertThat(buf.writableBytes()).isEqualTo(0); buf.ensureWritable(8); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferFloatOffsettedAccessorsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferFloatOffsettedAccessorsTest.java index 837718d..0c63692 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferFloatOffsettedAccessorsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferFloatOffsettedAccessorsTest.java @@ -20,7 +20,6 @@ import io.netty.buffer.api.BufferAllocator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferFloatOffsettedAccessorsTest extends BufferTestSupport { @@ -59,7 +58,6 @@ public class BufferFloatOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfFloatMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); float value = Float.intBitsToFloat(0x01020304); buf.writeFloat(value); buf.setByte(0, (byte) 0x10); @@ -176,7 +174,6 @@ public class BufferFloatOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfFloatMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); float value = Float.intBitsToFloat(0x01020304); buf.setFloat(0, value); buf.writerOffset(Long.BYTES); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferIntOffsettedAccessorsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferIntOffsettedAccessorsTest.java index ed41ad0..95b6246 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferIntOffsettedAccessorsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferIntOffsettedAccessorsTest.java @@ -20,7 +20,6 @@ import io.netty.buffer.api.BufferAllocator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferIntOffsettedAccessorsTest extends BufferTestSupport { @@ -58,7 +57,6 @@ public class BufferIntOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfIntMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x01020304; buf.writeInt(value); buf.setByte(0, (byte) 0x10); @@ -158,7 +156,6 @@ public class BufferIntOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfUnsignedIntMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); long value = 0x01020304; buf.writeUnsignedInt(value); buf.setByte(0, (byte) 0x10); @@ -277,7 +274,6 @@ public class BufferIntOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfIntMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x01020304; buf.setInt(0, value); buf.writerOffset(Long.BYTES); @@ -325,7 +321,6 @@ public class BufferIntOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfUnsignedIntMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); long value = 0x01020304; buf.setUnsignedInt(0, value); buf.writerOffset(Long.BYTES); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReferenceCountingTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferLifeCycleTest.java similarity index 88% rename from buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReferenceCountingTest.java rename to buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferLifeCycleTest.java index b534719..3e3e990 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReferenceCountingTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferLifeCycleTest.java @@ -20,23 +20,23 @@ import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.BufferClosedException; import io.netty.buffer.api.CompositeBuffer; import io.netty.buffer.api.internal.ResourceSupport; +import io.netty.util.internal.EmptyArrays; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import java.util.concurrent.Future; import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Supplier; import static io.netty.buffer.api.internal.Statics.acquire; import static io.netty.buffer.api.internal.Statics.isOwned; -import static java.nio.ByteOrder.BIG_ENDIAN; -import static java.nio.ByteOrder.LITTLE_ENDIAN; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -public class BufferReferenceCountingTest extends BufferTestSupport { +public class BufferLifeCycleTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") void allocateAndAccessingBuffer(Fixture fixture) { @@ -72,6 +72,25 @@ public class BufferReferenceCountingTest extends BufferTestSupport { } } + @ParameterizedTest + @MethodSource("initialCombinations") + public void allocatingZeroSizedBuffer(Fixture fixture) { + try (BufferAllocator allocator = fixture.createAllocator()) { + Supplier supplier = allocator.constBufferSupplier(EmptyArrays.EMPTY_BYTES); + + try (Buffer empty = supplier.get()) { + assertThat(empty.capacity()).isZero(); + assertTrue(empty.readOnly()); + } + + try (Buffer empty = allocator.allocate(0)) { + assertThat(empty.capacity()).isZero(); + empty.ensureWritable(8); + assertThat(empty.capacity()).isGreaterThanOrEqualTo(8); + } + } + } + @ParameterizedTest @MethodSource("allocators") void acquireOnClosedBufferMustThrow(Fixture fixture) { @@ -171,10 +190,10 @@ public class BufferReferenceCountingTest extends BufferTestSupport { try (Buffer copy = buf.copy()) { assertTrue(isOwned((ResourceSupport) buf)); assertTrue(isOwned((ResourceSupport) copy)); - copy.send().discard(); + copy.send().close(); } assertTrue(isOwned((ResourceSupport) buf)); - buf.send().discard(); + buf.send().close(); } } @@ -186,10 +205,10 @@ public class BufferReferenceCountingTest extends BufferTestSupport { try (Buffer copy = buf.copy(0, 8)) { assertTrue(isOwned((ResourceSupport) buf)); assertTrue(isOwned((ResourceSupport) copy)); - copy.send().discard(); + copy.send().close(); } assertTrue(isOwned((ResourceSupport) buf)); - buf.send().discard(); + buf.send().close(); } } @@ -198,15 +217,10 @@ public class BufferReferenceCountingTest extends BufferTestSupport { void copyWithoutOffsetAndSizeHasSameEndianAsParent(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); buf.writeLong(0x0102030405060708L); try (Buffer copy = buf.copy()) { assertEquals(0x0102030405060708L, copy.readLong()); } - buf.order(LITTLE_ENDIAN); - try (Buffer copy = buf.copy()) { - assertEquals(0x0807060504030201L, copy.readLong()); - } } } @@ -215,15 +229,10 @@ public class BufferReferenceCountingTest extends BufferTestSupport { void copyWithOffsetAndSizeHasSameEndianAsParent(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); buf.writeLong(0x0102030405060708L); try (Buffer copy = buf.copy(0, 8)) { assertEquals(0x0102030405060708L, copy.readLong()); } - buf.order(LITTLE_ENDIAN); - try (Buffer copy = buf.copy(0, 8)) { - assertEquals(0x0807060504030201L, copy.readLong()); - } } } @@ -234,7 +243,7 @@ public class BufferReferenceCountingTest extends BufferTestSupport { Buffer buf = allocator.allocate(8)) { try (Buffer copy = buf.copy()) { assertTrue(isOwned((ResourceSupport) buf)); - copy.send().discard(); + copy.send().close(); } // Verify that the copy is closed properly afterwards. assertTrue(isOwned((ResourceSupport) buf)); @@ -249,7 +258,7 @@ public class BufferReferenceCountingTest extends BufferTestSupport { Buffer buf = allocator.allocate(8)) { try (Buffer copy = buf.copy(0, 8)) { assertTrue(isOwned((ResourceSupport) buf)); - copy.send().discard(); + copy.send().close(); } // Verify that the copy is closed properly afterwards. assertTrue(isOwned((ResourceSupport) buf)); @@ -305,7 +314,7 @@ public class BufferReferenceCountingTest extends BufferTestSupport { @ParameterizedTest @MethodSource("allocators") - public void copyMustBeOwned(Fixture fixture) { + void copyMustBeOwned(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator()) { Buffer buf = allocator.allocate(8); buf.writeInt(42); @@ -323,6 +332,17 @@ public class BufferReferenceCountingTest extends BufferTestSupport { } } + @ParameterizedTest + @MethodSource("allocators") + public void copyOfLastByte(Fixture fixture) { + try (BufferAllocator allocator = fixture.createAllocator(); + Buffer buf = allocator.allocate(8).writeLong(0x0102030405060708L); + Buffer copy = buf.copy(7, 1)) { + assertThat(copy.capacity()).isOne(); + assertEquals((byte) 0x08, copy.readByte()); + } + } + @ParameterizedTest @MethodSource("allocators") public void pooledBuffersMustResetStateBeforeReuse(Fixture fixture) { @@ -335,13 +355,11 @@ public class BufferReferenceCountingTest extends BufferTestSupport { assertEquals(expected.readerOffset(), buf.readerOffset()); assertEquals(expected.writableBytes(), buf.writableBytes()); assertEquals(expected.writerOffset(), buf.writerOffset()); - assertThat(buf.order()).isEqualTo(expected.order()); byte[] bytes = new byte[8]; buf.copyInto(0, bytes, 0, 8); assertThat(bytes).containsExactly(0, 0, 0, 0, 0, 0, 0, 0); var tlr = ThreadLocalRandom.current(); - buf.order(tlr.nextBoolean()? LITTLE_ENDIAN : BIG_ENDIAN); for (int j = 0; j < tlr.nextInt(0, 8); j++) { buf.writeByte((byte) 1); } @@ -439,7 +457,7 @@ public class BufferReferenceCountingTest extends BufferTestSupport { @MethodSource("allocators") public void splitPartMustContainFirstHalfOfBuffer(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(16).order(BIG_ENDIAN)) { + Buffer buf = allocator.allocate(16)) { buf.writeLong(0x0102030405060708L); assertThat(buf.readByte()).isEqualTo((byte) 0x01); try (Buffer split = buf.split()) { @@ -475,7 +493,7 @@ public class BufferReferenceCountingTest extends BufferTestSupport { @MethodSource("allocators") public void splitPartsMustBeIndividuallySendable(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(16).order(BIG_ENDIAN)) { + Buffer buf = allocator.allocate(16)) { buf.writeLong(0x0102030405060708L); assertThat(buf.readByte()).isEqualTo((byte) 0x01); try (Buffer sentSplit = buf.split().send().receive()) { @@ -504,7 +522,7 @@ public class BufferReferenceCountingTest extends BufferTestSupport { @MethodSource("allocators") public void mustBePossibleToSplitMoreThanOnce(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(16).order(BIG_ENDIAN)) { + Buffer buf = allocator.allocate(16)) { buf.writeLong(0x0102030405060708L); try (Buffer a = buf.split()) { a.writerOffset(4); @@ -532,14 +550,14 @@ public class BufferReferenceCountingTest extends BufferTestSupport { @MethodSource("allocators") public void mustBePossibleToSplitCopies(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator()) { - Buffer buf = allocator.allocate(16).order(BIG_ENDIAN); + Buffer buf = allocator.allocate(16); buf.writeLong(0x0102030405060708L); try (Buffer copy = buf.copy()) { buf.close(); assertTrue(isOwned((ResourceSupport) copy)); try (Buffer split = copy.split(4)) { - split.reset().ensureWritable(Long.BYTES); - copy.reset().ensureWritable(Long.BYTES); + split.resetOffsets().ensureWritable(Long.BYTES); + copy.resetOffsets().ensureWritable(Long.BYTES); assertThat(split.capacity()).isEqualTo(Long.BYTES); assertThat(copy.capacity()).isEqualTo(Long.BYTES); assertThat(split.getLong(0)).isEqualTo(0x01020304_00000000L); @@ -549,41 +567,6 @@ public class BufferReferenceCountingTest extends BufferTestSupport { } } - @ParameterizedTest - @MethodSource("allocators") - public void splitBufferMustHaveSameByteOrderAsParent(Fixture fixture) { - try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(8).order(BIG_ENDIAN)) { - buf.writeLong(0x0102030405060708L); - try (Buffer a = buf.split()) { - assertThat(a.order()).isEqualTo(BIG_ENDIAN); - a.order(LITTLE_ENDIAN); - a.writerOffset(4); - try (Buffer b = a.split()) { - assertThat(b.order()).isEqualTo(LITTLE_ENDIAN); - assertThat(buf.order()).isEqualTo(BIG_ENDIAN); - } - } - } - } - - @ParameterizedTest - @MethodSource("allocators") - public void splitMustPreserveByteOrder(Fixture fixture) { - try (BufferAllocator allocator = fixture.createAllocator()) { - try (Buffer a = allocator.allocate(8).order(BIG_ENDIAN); - Buffer b = a.split(4)) { - assertThat(a.order()).isEqualTo(BIG_ENDIAN); - assertThat(b.order()).isEqualTo(BIG_ENDIAN); - } - try (Buffer a = allocator.allocate(8).order(LITTLE_ENDIAN); - Buffer b = a.split(4)) { - assertThat(a.order()).isEqualTo(LITTLE_ENDIAN); - assertThat(b.order()).isEqualTo(LITTLE_ENDIAN); - } - } - } - @ParameterizedTest @MethodSource("allocators") public void ensureWritableOnSplitBuffers(Fixture fixture) { @@ -607,7 +590,7 @@ public class BufferReferenceCountingTest extends BufferTestSupport { @MethodSource("allocators") public void ensureWritableOnSplitBuffersWithOddOffsets(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(10).order(BIG_ENDIAN)) { + Buffer buf = allocator.allocate(10)) { buf.writeLong(0x0102030405060708L); buf.writeByte((byte) 0x09); buf.readByte(); @@ -625,17 +608,9 @@ public class BufferReferenceCountingTest extends BufferTestSupport { } @Test - public void splitOnEmptyBigEndianCompositeBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap(); - Buffer buf = CompositeBuffer.compose(allocator).order(BIG_ENDIAN)) { - verifySplitEmptyCompositeBuffer(buf); - } - } - - @Test - public void splitOnEmptyLittleEndianCompositeBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap(); - Buffer buf = CompositeBuffer.compose(allocator).order(LITTLE_ENDIAN)) { + public void splitOnEmptyCompositeBuffer() { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); + Buffer buf = CompositeBuffer.compose(allocator)) { verifySplitEmptyCompositeBuffer(buf); } } @@ -672,19 +647,6 @@ public class BufferReferenceCountingTest extends BufferTestSupport { } } - @ParameterizedTest - @MethodSource("allocators") - public void copyOfReadOnlyBufferMustBeReadOnly(Fixture fixture) { - try (BufferAllocator allocator = fixture.createAllocator(); - Buffer buf = allocator.allocate(8)) { - buf.writeLong(0x0102030405060708L); - buf.makeReadOnly(); - try (Buffer copy = buf.copy()) { - assertTrue(copy.readOnly()); - } - } - } - @ParameterizedTest @MethodSource("allocators") public void splitOfReadOnlyBufferMustBeReadOnly(Fixture fixture) { @@ -698,4 +660,17 @@ public class BufferReferenceCountingTest extends BufferTestSupport { } } } + + @ParameterizedTest + @MethodSource("allocators") + public void allocatingOnClosedAllocatorMustThrow(Fixture fixture) { + BufferAllocator allocator = fixture.createAllocator(); + Supplier supplier = allocator.constBufferSupplier(new byte[8]); + allocator.close(); + assertThrows(IllegalStateException.class, () -> allocator.allocate(8)); + assertThrows(IllegalStateException.class, () -> allocator.constBufferSupplier(EmptyArrays.EMPTY_BYTES)); + assertThrows(IllegalStateException.class, () -> allocator.constBufferSupplier(new byte[8])); + // Existing const suppliers continue to work because they hold on to static memory allocation. + supplier.get().close(); + } } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferLongOffsettedAccessorsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferLongOffsettedAccessorsTest.java index 9495bd4..1df9eaf 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferLongOffsettedAccessorsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferLongOffsettedAccessorsTest.java @@ -20,7 +20,6 @@ import io.netty.buffer.api.BufferAllocator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferLongOffsettedAccessorsTest extends BufferTestSupport { @@ -58,7 +57,6 @@ public class BufferLongOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfLongMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); long value = 0x0102030405060708L; buf.writeLong(value); buf.setByte(0, (byte) 0x10); @@ -157,7 +155,6 @@ public class BufferLongOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfLongMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); long value = 0x0102030405060708L; buf.setLong(0, value); buf.writerOffset(Long.BYTES); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferMediumOffsettedAccessorsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferMediumOffsettedAccessorsTest.java index d380fa7..30edd9e 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferMediumOffsettedAccessorsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferMediumOffsettedAccessorsTest.java @@ -20,7 +20,6 @@ import io.netty.buffer.api.BufferAllocator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferMediumOffsettedAccessorsTest extends BufferTestSupport { @@ -58,7 +57,6 @@ public class BufferMediumOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfMediumMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x010203; buf.writeMedium(value); buf.setByte(0, (byte) 0x10); @@ -178,7 +176,6 @@ public class BufferMediumOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfUnsignedMediumMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x010203; buf.writeUnsignedMedium(value); buf.setByte(0, (byte) 0x10); @@ -297,7 +294,6 @@ public class BufferMediumOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfMediumMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x010203; buf.setMedium(0, value); buf.writerOffset(Long.BYTES); @@ -345,7 +341,6 @@ public class BufferMediumOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfUnsignedMediumMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x010203; buf.setUnsignedMedium(0, value); buf.writerOffset(Long.BYTES); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferOffsetsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferOffsetsTest.java index 7dd9b40..c700094 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferOffsetsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferOffsetsTest.java @@ -26,15 +26,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferOffsetsTest extends BufferTestSupport { @ParameterizedTest - @MethodSource("initialAllocators") - void mustThrowWhenAllocatingZeroSizedBuffer(Fixture fixture) { - try (BufferAllocator allocator = fixture.createAllocator()) { - assertThrows(IllegalArgumentException.class, () -> allocator.allocate(0)); - } - } - - @ParameterizedTest - @MethodSource("allocators") + @MethodSource("initialCombinations") void mustThrowWhenAllocatingNegativeSizedBuffer(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator()) { assertThrows(IllegalArgumentException.class, () -> allocator.allocate(-1)); @@ -169,7 +161,7 @@ public class BufferOffsetsTest extends BufferTestSupport { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { buf.writeInt(0).readShort(); - buf.reset(); + buf.resetOffsets(); assertEquals(0, buf.readerOffset()); assertEquals(0, buf.writerOffset()); } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferPrimitiveRelativeAccessorsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferPrimitiveRelativeAccessorsTest.java index b950a5f..840eeba 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferPrimitiveRelativeAccessorsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferPrimitiveRelativeAccessorsTest.java @@ -20,7 +20,6 @@ import io.netty.buffer.api.BufferAllocator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { @@ -46,7 +45,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfByteMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); byte value = 0x01; @@ -97,7 +95,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfUnsignedByteMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); int value = 0x01; @@ -164,7 +161,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfByteMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); byte value = 0x01; buf.writeByte(value); buf.writerOffset(Long.BYTES); @@ -199,7 +195,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfUnsignedByteMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x01; buf.writeUnsignedByte(value); buf.writerOffset(Long.BYTES); @@ -235,7 +230,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfCharMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); char value = 0x0102; @@ -302,7 +296,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfCharMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); char value = 0x0102; buf.writeChar(value); buf.writerOffset(Long.BYTES); @@ -338,7 +331,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfShortMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); short value = 0x0102; @@ -406,7 +398,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfUnsignedShortMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); int value = 0x0102; @@ -473,7 +464,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfShortMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); short value = 0x0102; buf.writeShort(value); buf.writerOffset(Long.BYTES); @@ -508,7 +498,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfUnsignedShortMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x0102; buf.writeUnsignedShort(value); buf.writerOffset(Long.BYTES); @@ -544,7 +533,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfMediumMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); int value = 0x010203; @@ -612,7 +600,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfUnsignedMediumMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); int value = 0x010203; @@ -679,7 +666,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfMediumMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x010203; buf.writeMedium(value); buf.writerOffset(Long.BYTES); @@ -714,7 +700,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfUnsignedMediumMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x010203; buf.writeUnsignedMedium(value); buf.writerOffset(Long.BYTES); @@ -750,7 +735,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfIntMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); int value = 0x01020304; @@ -818,7 +802,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfUnsignedIntMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); long value = 0x01020304; @@ -885,7 +868,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfIntMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x01020304; buf.writeInt(value); buf.writerOffset(Long.BYTES); @@ -920,7 +902,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfUnsignedIntMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); long value = 0x01020304; buf.writeUnsignedInt(value); buf.writerOffset(Long.BYTES); @@ -956,7 +937,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfFloatMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); float value = Float.intBitsToFloat(0x01020304); @@ -1023,7 +1003,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfFloatMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); float value = Float.intBitsToFloat(0x01020304); buf.writeFloat(value); buf.writerOffset(Long.BYTES); @@ -1059,7 +1038,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfLongMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); long value = 0x0102030405060708L; @@ -1126,7 +1104,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfLongMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); long value = 0x0102030405060708L; buf.writeLong(value); buf.writerOffset(Long.BYTES); @@ -1162,7 +1139,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeReadOfDoubleMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); assertEquals(0, buf.readableBytes()); assertEquals(Long.BYTES, buf.writableBytes()); double value = Double.longBitsToDouble(0x0102030405060708L); @@ -1229,7 +1205,6 @@ public class BufferPrimitiveRelativeAccessorsTest extends BufferTestSupport { void relativeWriteOfDoubleMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); double value = Double.longBitsToDouble(0x0102030405060708L); buf.writeDouble(value); buf.writerOffset(Long.BYTES); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReadOnlyTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReadOnlyTest.java index edffd70..e0731c6 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReadOnlyTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReadOnlyTest.java @@ -25,11 +25,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import java.nio.ByteOrder; import java.util.function.Supplier; import static io.netty.buffer.api.internal.Statics.isOwned; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -92,7 +90,7 @@ public class BufferReadOnlyTest extends BufferTestSupport { @Test public void readOnlyBufferMustRemainReadOnlyAfterSendForEmptyCompositeBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); Buffer buf = CompositeBuffer.compose(allocator)) { buf.makeReadOnly(); var send = buf.send(); @@ -144,6 +142,7 @@ public class BufferReadOnlyTest extends BufferTestSupport { dest.makeReadOnly(); try (Buffer src = allocator.allocate(8)) { assertThrows(BufferReadOnlyException.class, () -> src.copyInto(0, dest, 0, 1)); + assertThrows(BufferReadOnlyException.class, () -> src.copyInto(0, dest, 0, 0)); } } } @@ -158,12 +157,11 @@ public class BufferReadOnlyTest extends BufferTestSupport { } @ParameterizedTest - @MethodSource("initialNoConstAllocators") + @MethodSource("initialCombinations") public void constBufferInitialState(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.constBufferSupplier(new byte[] {1, 2, 3, 4}).get()) { assertTrue(buf.readOnly()); - assertThat(buf.order()).isEqualTo(ByteOrder.nativeOrder()); assertThat(buf.readerOffset()).isZero(); assertThat(buf.capacity()).isEqualTo(4); assertThat(buf.writerOffset()).isEqualTo(4); @@ -178,7 +176,7 @@ public class BufferReadOnlyTest extends BufferTestSupport { } @ParameterizedTest - @MethodSource("initialNoConstAllocators") + @MethodSource("initialCombinations") public void constBuffersCanBeSplit(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator()) { Supplier supplier = allocator.constBufferSupplier(new byte[16]); @@ -198,7 +196,7 @@ public class BufferReadOnlyTest extends BufferTestSupport { assertThat(a.capacity()).isEqualTo(8); assertThat(b.capacity()).isEqualTo(8); try (Buffer c = b.copy()) { - assertTrue(c.readOnly()); + assertFalse(c.readOnly()); // Buffer copies are never read-only. assertTrue(isOwned((ResourceSupport) c)); assertTrue(isOwned((ResourceSupport) b)); assertThat(c.capacity()).isEqualTo(8); @@ -207,7 +205,7 @@ public class BufferReadOnlyTest extends BufferTestSupport { } @ParameterizedTest - @MethodSource("initialNoConstAllocators") + @MethodSource("initialCombinations") public void compactOnConstBufferMustNotImpactSiblings(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator()) { Supplier supplier = allocator.constBufferSupplier(new byte[] {1, 2, 3, 4}); @@ -228,7 +226,7 @@ public class BufferReadOnlyTest extends BufferTestSupport { assertEquals(1, c.readByte()); assertEquals(2, c.readByte()); - assertThrows(BufferReadOnlyException.class, () -> c.compact()); // Can't compact read-only buffer. + c.compact(); // Copies are not read-only, so we can compact this one. assertEquals(3, c.readByte()); assertEquals(4, c.readByte()); } @@ -236,7 +234,7 @@ public class BufferReadOnlyTest extends BufferTestSupport { } @ParameterizedTest - @MethodSource("initialNoConstAllocators") + @MethodSource("initialCombinations") public void constBuffersMustBeSendable(Fixture fixture) throws Exception { try (BufferAllocator allocator = fixture.createAllocator()) { Supplier supplier = allocator.constBufferSupplier(new byte[] {1, 2, 3, 4}); @@ -244,11 +242,25 @@ public class BufferReadOnlyTest extends BufferTestSupport { Send send = buffer.send(); var future = executor.submit(() -> { try (Buffer receive = send.receive()) { - return receive.order(BIG_ENDIAN).readInt(); + return receive.readInt(); } }); assertEquals(0x01020304, future.get()); } } } + + @ParameterizedTest + @MethodSource("allocators") + public void copyOfReadOnlyBufferIsNotReadOnly(Fixture fixture) { + try (BufferAllocator allocator = fixture.createAllocator(); + Buffer buf = allocator.allocate(8).writeLong(0x0102030405060708L).makeReadOnly(); + Buffer copy = buf.copy()) { + assertFalse(copy.readOnly()); + assertReadableEquals(buf, copy); + assertEquals(8, copy.readerOffset()); + copy.setLong(0, 0xA1A2A3A4A5A6A7A8L); + assertEquals(0xA1A2A3A4A5A6A7A8L, copy.getLong(0)); + } + } } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferRefTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferRefTest.java index d5d8a55..d4521ad 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferRefTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferRefTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Netty Project + * Copyright 2021 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance @@ -30,33 +30,33 @@ import static org.junit.jupiter.api.Assertions.assertThrows; class BufferRefTest { @Test public void closingBufRefMustCloseOwnedBuf() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { BufferRef ref; try (Buffer b = allocator.allocate(8)) { ref = new BufferRef(b.send()); } - ref.contents().writeInt(42); - assertThat(ref.contents().readInt()).isEqualTo(42); + ref.content().writeInt(42); + assertThat(ref.content().readInt()).isEqualTo(42); ref.close(); - assertThrows(BufferClosedException.class, () -> ref.contents().writeInt(32)); + assertThrows(BufferClosedException.class, () -> ref.content().writeInt(32)); } } @Test public void closingBufRefMustCloseOwnedBufFromSend() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); Buffer buf = allocator.allocate(8)) { BufferRef ref = new BufferRef(buf.send()); - ref.contents().writeInt(42); - assertThat(ref.contents().readInt()).isEqualTo(42); + ref.content().writeInt(42); + assertThat(ref.content().readInt()).isEqualTo(42); ref.close(); - assertThrows(BufferClosedException.class, () -> ref.contents().writeInt(32)); + assertThrows(BufferClosedException.class, () -> ref.content().writeInt(32)); } } @Test public void mustCloseOwnedBufferWhenReplacedFromSend() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { AtomicReference orig = new AtomicReference<>(); BufferRef ref; Send s = allocator.allocate(8).send(); @@ -67,29 +67,29 @@ class BufferRefTest { })); orig.get().writeInt(42); - assertThat(ref.contents().readInt()).isEqualTo(42); + assertThat(ref.content().readInt()).isEqualTo(42); try (Buffer buf = allocator.allocate(8)) { ref.replace(buf.send()); // Pass replacement via send(). } assertThrows(BufferClosedException.class, () -> orig.get().writeInt(32)); - ref.contents().writeInt(42); - assertThat(ref.contents().readInt()).isEqualTo(42); + ref.content().writeInt(42); + assertThat(ref.content().readInt()).isEqualTo(42); ref.close(); - assertThrows(BufferClosedException.class, () -> ref.contents().writeInt(32)); + assertThrows(BufferClosedException.class, () -> ref.content().writeInt(32)); } } @Test public void sendingRefMustSendBuffer() { - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); BufferRef refA = new BufferRef(allocator.allocate(8).send())) { - refA.contents().writeInt(42); + refA.content().writeInt(42); Send send = refA.send(); - assertThrows(BufferClosedException.class, () -> refA.contents().readInt()); + assertThrows(BufferClosedException.class, () -> refA.content().readInt()); try (BufferRef refB = send.receive()) { - assertThat(refB.contents().readInt()).isEqualTo(42); + assertThat(refB.content().readInt()).isEqualTo(42); } } } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferSendTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferSendTest.java index 21ecb0c..e7c6015 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferSendTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferSendTest.java @@ -100,7 +100,7 @@ public class BufferSendTest extends BufferTestSupport { var send = orig.send(); verifyInaccessible(orig); try (Buffer receive = send.receive()) { - assertEquals(42, receive.readInt()); + assertEquals(42, receive.readLong()); } } } @@ -143,7 +143,7 @@ public class BufferSendTest extends BufferTestSupport { @Test public void isSendOfMustCheckObjectTypes() { - try (BufferAllocator allocator = BufferAllocator.heap()) { + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled()) { Send bufferSend = allocator.allocate(8).send(); Send bufferRefSend = new BufferRef(allocator.allocate(8).send()).send(); try { @@ -154,8 +154,8 @@ public class BufferSendTest extends BufferTestSupport { assertFalse(Send.isSendOf(Buffer.class, new Object())); assertFalse(Send.isSendOf(Object.class, new Object())); } finally { - bufferSend.discard(); - bufferRefSend.discard(); + bufferSend.close(); + bufferRefSend.close(); } // Type checks must still pass after the sends have been received. assertTrue(Send.isSendOf(Buffer.class, bufferSend)); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferShortOffsettedAccessorsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferShortOffsettedAccessorsTest.java index 2cded12..d9eb8c8 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferShortOffsettedAccessorsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferShortOffsettedAccessorsTest.java @@ -20,7 +20,6 @@ import io.netty.buffer.api.BufferAllocator; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import static java.nio.ByteOrder.BIG_ENDIAN; import static org.junit.jupiter.api.Assertions.assertThrows; public class BufferShortOffsettedAccessorsTest extends BufferTestSupport { @@ -58,7 +57,6 @@ public class BufferShortOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfShortMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); short value = 0x0102; buf.writeShort(value); buf.setByte(0, (byte) 0x10); @@ -176,7 +174,6 @@ public class BufferShortOffsettedAccessorsTest extends BufferTestSupport { void offsettedGetOfUnsignedShortMustReadWithDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x0102; buf.writeUnsignedShort(value); buf.setByte(0, (byte) 0x10); @@ -295,7 +292,6 @@ public class BufferShortOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfShortMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); short value = 0x0102; buf.setShort(0, value); buf.writerOffset(Long.BYTES); @@ -343,7 +339,6 @@ public class BufferShortOffsettedAccessorsTest extends BufferTestSupport { void offsettedSetOfUnsignedShortMustHaveDefaultEndianByteOrder(Fixture fixture) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN); int value = 0x0102; buf.setUnsignedShort(0, value); buf.writerOffset(Long.BYTES); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferTestSupport.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferTestSupport.java index 9a5ccff..ca24c90 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferTestSupport.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferTestSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Netty Project + * Copyright 2021 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance @@ -19,8 +19,10 @@ import io.netty.buffer.api.Buffer; import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.BufferClosedException; import io.netty.buffer.api.CompositeBuffer; -import io.netty.buffer.api.MemoryManagers; +import io.netty.buffer.api.MemoryManager; import io.netty.buffer.api.internal.ResourceSupport; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -33,6 +35,7 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.ServiceConfigurationError; import java.util.SplittableRandom; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -40,13 +43,16 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.Stream.Builder; import static io.netty.buffer.api.internal.Statics.acquire; +import static io.netty.buffer.api.tests.Fixture.Properties.DIRECT; +import static io.netty.buffer.api.tests.Fixture.Properties.HEAP; +import static io.netty.buffer.api.tests.Fixture.Properties.POOLED; import static java.nio.ByteOrder.BIG_ENDIAN; -import static java.nio.ByteOrder.LITTLE_ENDIAN; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -54,50 +60,32 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; public abstract class BufferTestSupport { + private static final InternalLogger logger = InternalLoggerFactory.getInstance(BufferTestSupport.class); public static ExecutorService executor; - private static final Memoize INITIAL_NO_CONST = new Memoize<>( - () -> initialFixturesForEachImplementation().stream().filter(f -> !f.isConst()).toArray(Fixture[]::new)); + private static final Memoize INITIAL_COMBINATIONS = new Memoize<>( + () -> initialFixturesForEachImplementation().toArray(Fixture[]::new)); private static final Memoize ALL_COMBINATIONS = new Memoize<>( () -> fixtureCombinations(initialFixturesForEachImplementation()).toArray(Fixture[]::new)); private static final Memoize ALL_ALLOCATORS = new Memoize<>( () -> Arrays.stream(ALL_COMBINATIONS.get()) - .filter(sample()) .toArray(Fixture[]::new)); private static final Memoize NON_COMPOSITE = new Memoize<>( () -> Arrays.stream(ALL_COMBINATIONS.get()) .filter(f -> !f.isComposite()) - .filter(sample()) .toArray(Fixture[]::new)); private static final Memoize HEAP_ALLOCS = new Memoize<>( () -> Arrays.stream(ALL_COMBINATIONS.get()) .filter(f -> f.isHeap()) - .filter(sample()) .toArray(Fixture[]::new)); private static final Memoize DIRECT_ALLOCS = new Memoize<>( () -> Arrays.stream(ALL_COMBINATIONS.get()) .filter(f -> f.isDirect()) - .filter(sample()) .toArray(Fixture[]::new)); private static final Memoize POOLED_ALLOCS = new Memoize<>( () -> Arrays.stream(ALL_COMBINATIONS.get()) .filter(f -> f.isPooled()) - .filter(sample()) .toArray(Fixture[]::new)); - private static final Memoize POOLED_DIRECT_ALLOCS = new Memoize<>( - () -> Arrays.stream(ALL_COMBINATIONS.get()) - .filter(f -> f.isPooled() && f.isDirect()) - .filter(sample()) - .toArray(Fixture[]::new)); - - private static Predicate sample() { - String sampleSetting = System.getProperty("sample"); - if ("nosample".equalsIgnoreCase(sampleSetting)) { - return fixture -> true; - } - // Filter out 85% of tests. - return filterOfTheDay(15); - } protected static Predicate filterOfTheDay(int percentage) { Instant today = Instant.now().truncatedTo(ChronoUnit.DAYS); // New seed every day. @@ -126,40 +114,65 @@ public abstract class BufferTestSupport { return POOLED_ALLOCS.get(); } - static Fixture[] pooledDirectAllocators() { - return POOLED_DIRECT_ALLOCS.get(); - } - - static Fixture[] initialNoConstAllocators() { - return INITIAL_NO_CONST.get(); + static Fixture[] initialCombinations() { + return INITIAL_COMBINATIONS.get(); } static List initialAllocators() { return List.of( - new Fixture("heap", BufferAllocator::heap, Fixture.Properties.HEAP), - new Fixture("direct", BufferAllocator::direct, Fixture.Properties.DIRECT, Fixture.Properties.CLEANER), - new Fixture("pooledHeap", BufferAllocator::pooledHeap, Fixture.Properties.POOLED, Fixture.Properties.HEAP), - new Fixture("pooledDirect", BufferAllocator::pooledDirect, Fixture.Properties.POOLED, Fixture.Properties.DIRECT, Fixture.Properties.CLEANER)); + new Fixture("heap", BufferAllocator::onHeapUnpooled, HEAP), + new Fixture("direct", BufferAllocator::offHeapUnpooled, DIRECT), + new Fixture("pooledHeap", BufferAllocator::onHeapPooled, POOLED, HEAP), + new Fixture("pooledDirect", BufferAllocator::offHeapPooled, POOLED, DIRECT)); } static List initialFixturesForEachImplementation() { List initFixtures = initialAllocators(); // Multiply by all MemoryManagers. - List loadableManagers = new ArrayList<>(); - MemoryManagers.getAllManagers().forEach(provider -> { - loadableManagers.add(provider.get()); + List failedManagers = new ArrayList<>(); + List loadableManagers = new ArrayList<>(); + MemoryManager.availableManagers().forEach(provider -> { + try { + loadableManagers.add(provider.get()); + } catch (ServiceConfigurationError | Exception e) { + logger.debug("Could not load implementation for testing", e); + failedManagers.add(e); + } }); + if (loadableManagers.isEmpty()) { + AssertionError error = new AssertionError("Failed to load any memory managers implementations."); + for (Throwable failure : failedManagers) { + error.addSuppressed(failure); + } + throw error; + } initFixtures = initFixtures.stream().flatMap(f -> { Builder builder = Stream.builder(); - for (MemoryManagers managers : loadableManagers) { - builder.add(new Fixture(f + "/" + managers, () -> MemoryManagers.using(managers, f), f.getProperties())); + for (MemoryManager managers : loadableManagers) { + char[] chars = managers.implementationName().toCharArray(); + for (int i = 1, j = 1; i < chars.length; i++) { + if (Character.isUpperCase(chars[i])) { + chars[j++] = chars[i]; + } + } + String managersName = String.valueOf(chars, 0, 2); + builder.add(new Fixture(f + "/" + managersName, + () -> MemoryManager.using(managers, f), f.getProperties())); } return builder.build(); }).collect(Collectors.toList()); return initFixtures; } + private abstract static class TestAllocator implements BufferAllocator { + @Override + public Supplier constBufferSupplier(byte[] bytes) { + Buffer base = allocate(bytes.length).writeBytes(bytes).makeReadOnly(); + return () -> base; // Technically off-spec. + } + } + static Stream fixtureCombinations(List initFixtures) { Builder builder = Stream.builder(); initFixtures.forEach(builder); @@ -168,13 +181,11 @@ public abstract class BufferTestSupport { for (Fixture first : initFixtures) { for (Fixture second : initFixtures) { builder.add(new Fixture("compose(" + first + ", " + second + ')', () -> { - return new BufferAllocator() { - BufferAllocator a; - BufferAllocator b; + return new TestAllocator() { + final BufferAllocator a = first.get(); + final BufferAllocator b = second.get(); @Override public Buffer allocate(int size) { - a = first.get(); - b = second.get(); int half = size / 2; try (Buffer firstHalf = a.allocate(half); Buffer secondHalf = b.allocate(size - half)) { @@ -184,14 +195,8 @@ public abstract class BufferTestSupport { @Override public void close() { - if (a != null) { - a.close(); - a = null; - } - if (b != null) { - b.close(); - b = null; - } + a.close(); + b.close(); } }; }, Fixture.Properties.COMPOSITE)); @@ -200,11 +205,10 @@ public abstract class BufferTestSupport { // Also add a 3-way composite buffer. builder.add(new Fixture("compose(heap,heap,heap)", () -> { - return new BufferAllocator() { - BufferAllocator alloc; + return new TestAllocator() { + final BufferAllocator alloc = BufferAllocator.onHeapUnpooled(); @Override public Buffer allocate(int size) { - alloc = BufferAllocator.heap(); int part = size / 3; try (Buffer a = alloc.allocate(part); Buffer b = alloc.allocate(part); @@ -215,21 +219,17 @@ public abstract class BufferTestSupport { @Override public void close() { - if (alloc != null) { - alloc.close(); - alloc = null; - } + alloc.close(); } }; }, Fixture.Properties.COMPOSITE)); for (Fixture fixture : initFixtures) { builder.add(new Fixture(fixture + ".ensureWritable", () -> { - return new BufferAllocator() { - BufferAllocator allocator; + return new TestAllocator() { + final BufferAllocator allocator = fixture.createAllocator(); @Override public Buffer allocate(int size) { - allocator = fixture.createAllocator(); if (size < 2) { return allocator.allocate(size); } @@ -240,19 +240,15 @@ public abstract class BufferTestSupport { @Override public void close() { - if (allocator != null) { - allocator.close(); - allocator = null; - } + allocator.close(); } }; }, fixture.getProperties())); builder.add(new Fixture(fixture + ".compose.ensureWritable", () -> { - return new BufferAllocator() { - BufferAllocator allocator; + return new TestAllocator() { + final BufferAllocator allocator = fixture.createAllocator(); @Override public Buffer allocate(int size) { - allocator = fixture.createAllocator(); if (size < 2) { return allocator.allocate(size); } @@ -263,10 +259,7 @@ public abstract class BufferTestSupport { @Override public void close() { - if (allocator != null) { - allocator.close(); - allocator = null; - } + allocator.close(); } }; }, Fixture.Properties.COMPOSITE)); @@ -280,11 +273,10 @@ public abstract class BufferTestSupport { Builder builder = Stream.builder(); builder.add(f); builder.add(new Fixture(f + ".split", () -> { - return new BufferAllocator() { - BufferAllocator allocatorBase; + return new TestAllocator() { + final BufferAllocator allocatorBase = f.get(); @Override public Buffer allocate(int size) { - allocatorBase = f.get(); try (Buffer buf = allocatorBase.allocate(size + 1)) { buf.writerOffset(size); return buf.split().writerOffset(0); @@ -293,10 +285,7 @@ public abstract class BufferTestSupport { @Override public void close() { - if (allocatorBase != null) { - allocatorBase.close(); - allocatorBase = null; - } + allocatorBase.close(); } }; }, f.getProperties())); @@ -326,7 +315,7 @@ public abstract class BufferTestSupport { verifyWriteInaccessible(buf, BufferClosedException.class); - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); Buffer target = allocator.allocate(24)) { assertThrows(BufferClosedException.class, () -> buf.copyInto(0, target, 0, 1)); assertThrows(BufferClosedException.class, () -> buf.copyInto(0, new byte[1], 0, 1)); @@ -403,16 +392,19 @@ public abstract class BufferTestSupport { assertThrows(expected, () -> buf.ensureWritable(1)); assertThrows(expected, () -> buf.fill((byte) 0)); - try (BufferAllocator allocator = BufferAllocator.heap(); + try (BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); Buffer source = allocator.allocate(8)) { assertThrows(expected, () -> source.copyInto(0, buf, 0, 1)); + if (expected == BufferClosedException.class) { + assertThrows(expected, () -> buf.copyInto(0, source, 0, 1)); + } } } public static void testCopyIntoByteBuffer(Fixture fixture, Function bbAlloc) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN).writeLong(0x0102030405060708L); + buf.writeLong(0x0102030405060708L); ByteBuffer buffer = bbAlloc.apply(8); buf.copyInto(0, buffer, 0, buffer.capacity()); assertEquals((byte) 0x01, buffer.get()); @@ -425,24 +417,12 @@ public abstract class BufferTestSupport { assertEquals((byte) 0x08, buffer.get()); buffer.clear(); - buf.writerOffset(0).order(LITTLE_ENDIAN).writeLong(0x0102030405060708L); - buf.copyInto(0, buffer, 0, buffer.capacity()); - assertEquals((byte) 0x08, buffer.get()); - assertEquals((byte) 0x07, buffer.get()); - assertEquals((byte) 0x06, buffer.get()); - assertEquals((byte) 0x05, buffer.get()); - assertEquals((byte) 0x04, buffer.get()); - assertEquals((byte) 0x03, buffer.get()); - assertEquals((byte) 0x02, buffer.get()); - assertEquals((byte) 0x01, buffer.get()); - buffer.clear(); - buffer = bbAlloc.apply(6); buf.copyInto(1, buffer, 1, 3); assertEquals((byte) 0x00, buffer.get()); - assertEquals((byte) 0x07, buffer.get()); - assertEquals((byte) 0x06, buffer.get()); - assertEquals((byte) 0x05, buffer.get()); + assertEquals((byte) 0x02, buffer.get()); + assertEquals((byte) 0x03, buffer.get()); + assertEquals((byte) 0x04, buffer.get()); assertEquals((byte) 0x00, buffer.get()); assertEquals((byte) 0x00, buffer.get()); buffer.clear(); @@ -454,73 +434,64 @@ public abstract class BufferTestSupport { assertEquals(3, buffer.limit()); buffer.clear(); assertEquals((byte) 0x00, buffer.get()); - assertEquals((byte) 0x07, buffer.get()); - assertEquals((byte) 0x06, buffer.get()); - assertEquals((byte) 0x05, buffer.get()); + assertEquals((byte) 0x02, buffer.get()); + assertEquals((byte) 0x03, buffer.get()); + assertEquals((byte) 0x04, buffer.get()); assertEquals((byte) 0x00, buffer.get()); assertEquals((byte) 0x00, buffer.get()); + + var roBuffer = bbAlloc.apply(6).asReadOnlyBuffer(); + assertThrows(ReadOnlyBufferException.class, () -> buf.copyInto(0, roBuffer, 0, 1)); + assertThrows(ReadOnlyBufferException.class, () -> buf.copyInto(0, roBuffer, 0, 0)); } } public static void testCopyIntoBuf(Fixture fixture, Function bbAlloc) { try (BufferAllocator allocator = fixture.createAllocator(); Buffer buf = allocator.allocate(8)) { - buf.order(BIG_ENDIAN).writeLong(0x0102030405060708L); - Buffer buffer = bbAlloc.apply(8); - buffer.writerOffset(8); - buf.copyInto(0, buffer, 0, buffer.capacity()); - assertEquals((byte) 0x01, buffer.readByte()); - assertEquals((byte) 0x02, buffer.readByte()); - assertEquals((byte) 0x03, buffer.readByte()); - assertEquals((byte) 0x04, buffer.readByte()); - assertEquals((byte) 0x05, buffer.readByte()); - assertEquals((byte) 0x06, buffer.readByte()); - assertEquals((byte) 0x07, buffer.readByte()); - assertEquals((byte) 0x08, buffer.readByte()); - buffer.reset(); + buf.writeLong(0x0102030405060708L); + try (Buffer buffer = bbAlloc.apply(8)) { + buffer.writerOffset(8); + buf.copyInto(0, buffer, 0, buffer.capacity()); + assertEquals((byte) 0x01, buffer.readByte()); + assertEquals((byte) 0x02, buffer.readByte()); + assertEquals((byte) 0x03, buffer.readByte()); + assertEquals((byte) 0x04, buffer.readByte()); + assertEquals((byte) 0x05, buffer.readByte()); + assertEquals((byte) 0x06, buffer.readByte()); + assertEquals((byte) 0x07, buffer.readByte()); + assertEquals((byte) 0x08, buffer.readByte()); + buffer.resetOffsets(); + } - buf.writerOffset(0).order(LITTLE_ENDIAN).writeLong(0x0102030405060708L); - buf.copyInto(0, buffer, 0, buffer.capacity()); - buffer.writerOffset(8); - assertEquals((byte) 0x08, buffer.readByte()); - assertEquals((byte) 0x07, buffer.readByte()); - assertEquals((byte) 0x06, buffer.readByte()); - assertEquals((byte) 0x05, buffer.readByte()); - assertEquals((byte) 0x04, buffer.readByte()); - assertEquals((byte) 0x03, buffer.readByte()); - assertEquals((byte) 0x02, buffer.readByte()); - assertEquals((byte) 0x01, buffer.readByte()); - buffer.reset(); + try (Buffer buffer = bbAlloc.apply(6)) { + buf.copyInto(1, buffer, 1, 3); + buffer.writerOffset(6); + assertEquals((byte) 0x00, buffer.readByte()); + assertEquals((byte) 0x02, buffer.readByte()); + assertEquals((byte) 0x03, buffer.readByte()); + assertEquals((byte) 0x04, buffer.readByte()); + assertEquals((byte) 0x00, buffer.readByte()); + assertEquals((byte) 0x00, buffer.readByte()); + } - buffer.close(); - buffer = bbAlloc.apply(6); - buf.copyInto(1, buffer, 1, 3); - buffer.writerOffset(6); - assertEquals((byte) 0x00, buffer.readByte()); - assertEquals((byte) 0x07, buffer.readByte()); - assertEquals((byte) 0x06, buffer.readByte()); - assertEquals((byte) 0x05, buffer.readByte()); - assertEquals((byte) 0x00, buffer.readByte()); - assertEquals((byte) 0x00, buffer.readByte()); + try (Buffer buffer = bbAlloc.apply(6)) { + buffer.writerOffset(3).readerOffset(3); + buf.copyInto(1, buffer, 1, 3); + assertEquals(3, buffer.readerOffset()); + assertEquals(3, buffer.writerOffset()); + buffer.resetOffsets(); + buffer.writerOffset(6); + assertEquals((byte) 0x00, buffer.readByte()); + assertEquals((byte) 0x02, buffer.readByte()); + assertEquals((byte) 0x03, buffer.readByte()); + assertEquals((byte) 0x04, buffer.readByte()); + assertEquals((byte) 0x00, buffer.readByte()); + assertEquals((byte) 0x00, buffer.readByte()); + } - buffer.close(); - buffer = bbAlloc.apply(6); - buffer.writerOffset(3).readerOffset(3); - buf.copyInto(1, buffer, 1, 3); - assertEquals(3, buffer.readerOffset()); - assertEquals(3, buffer.writerOffset()); - buffer.reset(); - buffer.writerOffset(6); - assertEquals((byte) 0x00, buffer.readByte()); - assertEquals((byte) 0x07, buffer.readByte()); - assertEquals((byte) 0x06, buffer.readByte()); - assertEquals((byte) 0x05, buffer.readByte()); - assertEquals((byte) 0x00, buffer.readByte()); - assertEquals((byte) 0x00, buffer.readByte()); - buffer.close(); - - buf.reset(); - buf.order(BIG_ENDIAN).writeLong(0x0102030405060708L); + buf.resetOffsets(); + buf.writeLong(0x0102030405060708L); // Testing copyInto for overlapping writes: // // 0x0102030405060708 @@ -536,60 +507,31 @@ public abstract class BufferTestSupport { public static void checkByteIteration(Buffer buf) { var cursor = buf.openCursor(); assertFalse(cursor.readByte()); - assertFalse(cursor.readLong()); assertEquals(0, cursor.bytesLeft()); assertEquals((byte) -1, cursor.getByte()); - assertEquals(-1L, cursor.getLong()); - for (int i = 0; i < 0x27; i++) { - buf.writeByte((byte) (i + 1)); - } + buf.writeBytes(new byte[] {1, 2, 3, 4}); int roff = buf.readerOffset(); int woff = buf.writerOffset(); cursor = buf.openCursor(); - assertEquals(0x27, cursor.bytesLeft()); - assertTrue(cursor.readByte()); - assertEquals((byte) 0x01, cursor.getByte()); - assertEquals((byte) 0x01, cursor.getByte()); - assertTrue(cursor.readLong()); - assertEquals(0x0203040506070809L, cursor.getLong()); - assertEquals(0x0203040506070809L, cursor.getLong()); - assertEquals(0x1E, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x0A0B0C0D0E0F1011L, cursor.getLong()); - assertEquals(0x16, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x1213141516171819L, cursor.getLong()); - assertEquals(0x0E, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x1A1B1C1D1E1F2021L, cursor.getLong()); - assertEquals(6, cursor.bytesLeft()); - assertFalse(cursor.readLong()); - assertEquals(6, cursor.bytesLeft()); - assertEquals(0x1A1B1C1D1E1F2021L, cursor.getLong()); - assertTrue(cursor.readByte()); - assertEquals((byte) 0x22, cursor.getByte()); - assertEquals((byte) 0x22, cursor.getByte()); - assertEquals(5, cursor.bytesLeft()); - assertTrue(cursor.readByte()); - assertEquals((byte) 0x23, cursor.getByte()); assertEquals(4, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x24, cursor.getByte()); + assertEquals((byte) 0x01, cursor.getByte()); + assertEquals((byte) 0x01, cursor.getByte()); assertEquals(3, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x25, cursor.getByte()); + assertEquals((byte) 0x02, cursor.getByte()); + assertEquals((byte) 0x02, cursor.getByte()); assertEquals(2, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x26, cursor.getByte()); + assertEquals((byte) 0x03, cursor.getByte()); assertEquals(1, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x27, cursor.getByte()); + assertEquals((byte) 0x04, cursor.getByte()); assertEquals(0, cursor.bytesLeft()); assertFalse(cursor.readByte()); - assertEquals((byte) 0x27, cursor.getByte()); - assertEquals((byte) 0x27, cursor.getByte()); - assertFalse(cursor.readLong()); + assertEquals((byte) 0x04, cursor.getByte()); + assertEquals((byte) 0x04, cursor.getByte()); assertEquals(roff, buf.readerOffset()); assertEquals(woff, buf.writerOffset()); } @@ -603,65 +545,41 @@ public abstract class BufferTestSupport { var cursor = buf.openCursor(1, 0); assertFalse(cursor.readByte()); - assertFalse(cursor.readLong()); assertEquals(0, cursor.bytesLeft()); assertEquals((byte) -1, cursor.getByte()); - assertEquals(-1L, cursor.getLong()); - for (int i = 0; i < 0x27; i++) { - buf.writeByte((byte) (i + 1)); - } + buf.writeBytes(new byte[] {1, 2, 3, 4, 5, 6}); int roff = buf.readerOffset(); int woff = buf.writerOffset(); cursor = buf.openCursor(buf.readerOffset() + 1, buf.readableBytes() - 2); - assertEquals(0x25, cursor.bytesLeft()); - assertTrue(cursor.readByte()); - assertEquals((byte) 0x02, cursor.getByte()); - assertEquals((byte) 0x02, cursor.getByte()); - assertTrue(cursor.readLong()); - assertEquals(0x030405060708090AL, cursor.getLong()); - assertEquals(0x1C, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x0B0C0D0E0F101112L, cursor.getLong()); - assertEquals(0x14, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x131415161718191AL, cursor.getLong()); - assertEquals(0x0C, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x1B1C1D1E1F202122L, cursor.getLong()); assertEquals(4, cursor.bytesLeft()); - assertFalse(cursor.readLong()); - assertEquals(4, cursor.bytesLeft()); - assertEquals(0x1B1C1D1E1F202122L, cursor.getLong()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x23, cursor.getByte()); + assertEquals((byte) 2, cursor.getByte()); + assertEquals((byte) 2, cursor.getByte()); assertEquals(3, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x24, cursor.getByte()); + assertEquals((byte) 3, cursor.getByte()); assertEquals(2, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x25, cursor.getByte()); + assertEquals((byte) 4, cursor.getByte()); assertEquals(1, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x26, cursor.getByte()); + assertEquals((byte) 5, cursor.getByte()); + assertEquals(0, cursor.bytesLeft()); assertEquals(0, cursor.bytesLeft()); assertFalse(cursor.readByte()); assertEquals(0, cursor.bytesLeft()); - assertEquals(0x1B1C1D1E1F202122L, cursor.getLong()); - assertEquals((byte) 0x26, cursor.getByte()); + assertEquals((byte) 5, cursor.getByte()); cursor = buf.openCursor(buf.readerOffset() + 1, 2); assertEquals(2, cursor.bytesLeft()); - assertFalse(cursor.readLong()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x02, cursor.getByte()); + assertEquals((byte) 2, cursor.getByte()); assertEquals(1, cursor.bytesLeft()); - assertFalse(cursor.readLong()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x03, cursor.getByte()); + assertEquals((byte) 3, cursor.getByte()); assertEquals(0, cursor.bytesLeft()); assertFalse(cursor.readByte()); - assertFalse(cursor.readLong()); assertEquals(roff, buf.readerOffset()); assertEquals(woff, buf.writerOffset()); } @@ -669,59 +587,31 @@ public abstract class BufferTestSupport { public static void checkReverseByteIteration(Buffer buf) { var cursor = buf.openReverseCursor(); assertFalse(cursor.readByte()); - assertFalse(cursor.readLong()); assertEquals(0, cursor.bytesLeft()); assertEquals((byte) -1, cursor.getByte()); - assertEquals(-1L, cursor.getLong()); - for (int i = 0; i < 0x27; i++) { - buf.writeByte((byte) (i + 1)); - } + buf.writeBytes(new byte[] {1, 2, 3, 4}); int roff = buf.readerOffset(); int woff = buf.writerOffset(); cursor = buf.openReverseCursor(); - assertEquals(0x27, cursor.bytesLeft()); - assertTrue(cursor.readByte()); - assertEquals((byte) 0x27, cursor.getByte()); - assertEquals((byte) 0x27, cursor.getByte()); - assertTrue(cursor.readLong()); - assertEquals(0x262524232221201FL, cursor.getLong()); - assertEquals(0x1E, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x1E1D1C1B1A191817L, cursor.getLong()); - assertEquals(0x16, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x161514131211100FL, cursor.getLong()); - assertEquals(0x0E, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x0E0D0C0B0A090807L, cursor.getLong()); - assertEquals(6, cursor.bytesLeft()); - assertFalse(cursor.readLong()); - assertEquals(6, cursor.bytesLeft()); - assertEquals(0x0E0D0C0B0A090807L, cursor.getLong()); - assertTrue(cursor.readByte()); - assertEquals((byte) 0x06, cursor.getByte()); - assertEquals(5, cursor.bytesLeft()); - assertTrue(cursor.readByte()); - assertEquals((byte) 0x05, cursor.getByte()); assertEquals(4, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x04, cursor.getByte()); + assertEquals((byte) 4, cursor.getByte()); + assertEquals((byte) 4, cursor.getByte()); assertEquals(3, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x03, cursor.getByte()); + assertEquals((byte) 3, cursor.getByte()); assertEquals(2, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x02, cursor.getByte()); + assertEquals((byte) 2, cursor.getByte()); assertEquals(1, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x01, cursor.getByte()); + assertEquals((byte) 1, cursor.getByte()); assertEquals(0, cursor.bytesLeft()); assertFalse(cursor.readByte()); - assertEquals((byte) 0x01, cursor.getByte()); + assertEquals((byte) 1, cursor.getByte()); assertFalse(cursor.readByte()); assertEquals(0, cursor.bytesLeft()); - assertEquals(0x0E0D0C0B0A090807L, cursor.getLong()); assertEquals(roff, buf.readerOffset()); assertEquals(woff, buf.writerOffset()); } @@ -735,66 +625,44 @@ public abstract class BufferTestSupport { var cursor = buf.openReverseCursor(1, 0); assertFalse(cursor.readByte()); - assertFalse(cursor.readLong()); assertEquals(0, cursor.bytesLeft()); assertEquals((byte) -1, cursor.getByte()); - assertEquals(-1L, cursor.getLong()); - for (int i = 0; i < 0x27; i++) { - buf.writeByte((byte) (i + 1)); - } + buf.writeBytes(new byte[] {1, 2, 3, 4, 5, 6, 7}); int roff = buf.readerOffset(); int woff = buf.writerOffset(); cursor = buf.openReverseCursor(buf.writerOffset() - 2, buf.readableBytes() - 2); - assertEquals(0x25, cursor.bytesLeft()); + assertEquals(5, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x26, cursor.getByte()); - assertEquals((byte) 0x26, cursor.getByte()); - assertTrue(cursor.readLong()); - assertEquals(0x2524232221201F1EL, cursor.getLong()); - assertEquals(0x1C, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x1D1C1B1A19181716L, cursor.getLong()); - assertEquals(0x14, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x1514131211100F0EL, cursor.getLong()); - assertEquals(0x0C, cursor.bytesLeft()); - assertTrue(cursor.readLong()); - assertEquals(0x0D0C0B0A09080706L, cursor.getLong()); + assertEquals((byte) 6, cursor.getByte()); + assertEquals((byte) 6, cursor.getByte()); assertEquals(4, cursor.bytesLeft()); - assertFalse(cursor.readLong()); - assertEquals(4, cursor.bytesLeft()); - assertEquals(0x0D0C0B0A09080706L, cursor.getLong()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x05, cursor.getByte()); + assertEquals((byte) 5, cursor.getByte()); assertEquals(3, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x04, cursor.getByte()); + assertEquals((byte) 4, cursor.getByte()); assertEquals(2, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x03, cursor.getByte()); + assertEquals((byte) 3, cursor.getByte()); assertEquals(1, cursor.bytesLeft()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x02, cursor.getByte()); + assertEquals((byte) 2, cursor.getByte()); assertEquals(0, cursor.bytesLeft()); assertFalse(cursor.readByte()); - assertEquals((byte) 0x02, cursor.getByte()); + assertEquals((byte) 2, cursor.getByte()); assertFalse(cursor.readByte()); assertEquals(0, cursor.bytesLeft()); - assertEquals(0x0D0C0B0A09080706L, cursor.getLong()); cursor = buf.openReverseCursor(buf.readerOffset() + 2, 2); assertEquals(2, cursor.bytesLeft()); - assertFalse(cursor.readLong()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x03, cursor.getByte()); + assertEquals((byte) 3, cursor.getByte()); assertEquals(1, cursor.bytesLeft()); - assertFalse(cursor.readLong()); assertTrue(cursor.readByte()); - assertEquals((byte) 0x02, cursor.getByte()); + assertEquals((byte) 2, cursor.getByte()); assertEquals(0, cursor.bytesLeft()); assertFalse(cursor.readByte()); - assertFalse(cursor.readLong()); assertEquals(roff, buf.readerOffset()); assertEquals(woff, buf.writerOffset()); } @@ -807,7 +675,6 @@ public abstract class BufferTestSupport { buf.writeInt(2); assertEquals(1, a.readInt()); assertEquals(2, buf.readInt()); - assertThat(a.order()).isEqualTo(buf.order()); } } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferWriteBytesCombinationsTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferWriteBytesCombinationsTest.java index 500344c..9eb63ce 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferWriteBytesCombinationsTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferWriteBytesCombinationsTest.java @@ -22,8 +22,6 @@ import org.junit.jupiter.params.provider.MethodSource; import java.util.Arrays; -import static java.nio.ByteOrder.BIG_ENDIAN; -import static java.nio.ByteOrder.LITTLE_ENDIAN; import static org.assertj.core.api.Assertions.assertThat; public class BufferWriteBytesCombinationsTest extends BufferTestSupport { @@ -40,24 +38,6 @@ public class BufferWriteBytesCombinationsTest extends BufferTestSupport { try (BufferAllocator alloc2 = otherFixture.createAllocator(); Buffer target = alloc1.allocate(37); Buffer source = alloc2.allocate(35)) { - // BE to BE - target.order(BIG_ENDIAN); - source.order(BIG_ENDIAN); - verifyWriteBytes(target, source); - - // LE to BE - target.fill((byte) 0).reset().order(BIG_ENDIAN); - source.fill((byte) 0).reset().order(LITTLE_ENDIAN); - verifyWriteBytes(target, source); - - // BE to LE - target.fill((byte) 0).reset().order(LITTLE_ENDIAN); - source.fill((byte) 0).reset().order(BIG_ENDIAN); - verifyWriteBytes(target, source); - - // LE to LE - target.fill((byte) 0).reset().order(LITTLE_ENDIAN); - source.fill((byte) 0).reset().order(BIG_ENDIAN); verifyWriteBytes(target, source); } catch (Exception e) { e.addSuppressed(new RuntimeException("other fixture was: " + otherFixture)); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/EchoIT.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/EchoIT.java index 6009a9c..2a8ce67 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/EchoIT.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/EchoIT.java @@ -22,7 +22,6 @@ import io.netty.buffer.api.Buffer; import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor; import io.netty.buffer.api.tests.examples.echo.EchoServerHandler; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; @@ -69,8 +68,8 @@ public class EchoIT { }); // Start the server. - ChannelFuture bind = server.bind("localhost", 0).sync(); - InetSocketAddress serverAddress = (InetSocketAddress) bind.channel().localAddress(); + var bind = server.bind("localhost", 0).sync().getNow(); + InetSocketAddress serverAddress = (InetSocketAddress) bind.localAddress(); // Configure the client. EventLoopGroup group = new MultithreadEventLoopGroup(NioHandler.newFactory()); @@ -89,17 +88,17 @@ public class EchoIT { }); // Start the client. - ChannelFuture f = b.connect(serverAddress).sync(); + var channel = b.connect(serverAddress).sync().getNow(); // Wait until the connection is closed. - f.channel().closeFuture().sync(); + channel.closeFuture().sync(); } finally { // Shut down the event loop to terminate all threads. group.shutdownGracefully(); } // Shut down the server. - bind.channel().close().sync(); + bind.close().sync(); } finally { // Shut down all event loops to terminate all threads. bossGroup.shutdownGracefully(); @@ -116,7 +115,7 @@ public class EchoIT { * Creates a client-side handler. */ EchoClientHandler() { - firstMessage = BufferAllocator.heap().allocate(SIZE); + firstMessage = BufferAllocator.onHeapUnpooled().allocate(SIZE); for (int i = 0; i < SIZE; i++) { firstMessage.writeByte((byte) i); } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/Fixture.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/Fixture.java index 3d3e5e5..ebbf609 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/Fixture.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/Fixture.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Netty Project + * Copyright 2021 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance @@ -66,20 +66,10 @@ public final class Fixture implements Supplier { return properties.contains(Properties.POOLED); } - public boolean isCleaner() { - return properties.contains(Properties.CLEANER); - } - - public boolean isConst() { - return properties.contains(Properties.CONST); - } - public enum Properties { HEAP, DIRECT, - CONST, COMPOSITE, - CLEANER, POOLED } } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/ScopeTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/ScopeTest.java deleted file mode 100644 index 99030e0..0000000 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/ScopeTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2020 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.tests; - -import io.netty.buffer.api.Drop; -import io.netty.buffer.api.Owned; -import io.netty.buffer.api.internal.ResourceSupport; -import io.netty.buffer.api.Scope; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class ScopeTest { - @Test - void scopeMustCloseContainedRecouresInReverseInsertOrder() { - ArrayList closeOrder = new ArrayList<>(); - try (Scope scope = new Scope()) { - scope.add(new SomeResource(new OrderingDrop(1, closeOrder))); - scope.add(new SomeResource(new OrderingDrop(2, closeOrder))); - scope.add(new SomeResource(new OrderingDrop(3, closeOrder))); - } - var itr = closeOrder.iterator(); - assertTrue(itr.hasNext()); - assertEquals(3, (int) itr.next()); - assertTrue(itr.hasNext()); - assertEquals(2, (int) itr.next()); - assertTrue(itr.hasNext()); - assertEquals(1, (int) itr.next()); - assertFalse(itr.hasNext()); - } - - private static final class SomeResource extends ResourceSupport { - SomeResource(Drop drop) { - super(drop); - } - - @Override - protected RuntimeException createResourceClosedException() { - return new IllegalStateException("This resource is closed: " + this); - } - - @Override - protected Owned prepareSend() { - return null; - } - } - - private static final class OrderingDrop implements Drop { - private final int order; - private final ArrayList list; - - private OrderingDrop(int order, ArrayList list) { - this.order = order; - this.list = list; - } - - @Override - public void drop(SomeResource obj) { - list.add(order); - } - } -} diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/AbstractByteBufTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/AbstractByteBufTest.java index 77fa14e..f45da25 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/AbstractByteBufTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/AbstractByteBufTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 The Netty Project + * Copyright 2021 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance @@ -2746,12 +2746,14 @@ public abstract class AbstractByteBufTest { @Test public void testGetBytesAfterRelease7() throws IOException { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().getBytes(0, new ByteArrayOutputStream(), 1)); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().getBytes(0, new ByteArrayOutputStream(), 1)); } @Test public void testGetBytesAfterRelease8() throws IOException { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().getBytes(0, new DevNullGatheringByteChannel(), 1)); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().getBytes(0, new DevNullGatheringByteChannel(), 1)); } @Test @@ -2857,12 +2859,14 @@ public abstract class AbstractByteBufTest { @Test public void testSetUsAsciiCharSequenceAfterRelease() { - assertThrows(IllegalReferenceCountException.class, () -> testSetCharSequenceAfterRelease0(CharsetUtil.US_ASCII)); + assertThrows(IllegalReferenceCountException.class, + () -> testSetCharSequenceAfterRelease0(CharsetUtil.US_ASCII)); } @Test public void testSetIso88591CharSequenceAfterRelease() { - assertThrows(IllegalReferenceCountException.class, () -> testSetCharSequenceAfterRelease0(CharsetUtil.ISO_8859_1)); + assertThrows(IllegalReferenceCountException.class, + () -> testSetCharSequenceAfterRelease0(CharsetUtil.ISO_8859_1)); } @Test @@ -2896,12 +2900,14 @@ public abstract class AbstractByteBufTest { @Test public void testSetBytesAfterRelease7() throws IOException { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().setBytes(0, new ByteArrayInputStream(new byte[8]), 1)); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().setBytes(0, new ByteArrayInputStream(new byte[8]), 1)); } @Test public void testSetBytesAfterRelease8() throws IOException { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().setBytes(0, new TestScatteringByteChannel(), 1)); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().setBytes(0, new TestScatteringByteChannel(), 1)); } @Test @@ -3077,17 +3083,20 @@ public abstract class AbstractByteBufTest { @Test public void testReadBytesAfterRelease8() throws IOException { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().readBytes(new ByteArrayOutputStream(), 1)); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().readBytes(new ByteArrayOutputStream(), 1)); } @Test public void testReadBytesAfterRelease9() throws IOException { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().readBytes(new ByteArrayOutputStream(), 1)); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().readBytes(new ByteArrayOutputStream(), 1)); } @Test public void testReadBytesAfterRelease10() throws IOException { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().readBytes(new DevNullGatheringByteChannel(), 1)); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().readBytes(new DevNullGatheringByteChannel(), 1)); } @Test @@ -3218,12 +3227,14 @@ public abstract class AbstractByteBufTest { @Test public void testWriteBytesAfterRelease7() throws IOException { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().writeBytes(new ByteArrayInputStream(new byte[8]), 1)); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().writeBytes(new ByteArrayInputStream(new byte[8]), 1)); } @Test public void testWriteBytesAfterRelease8() throws IOException { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().writeBytes(new TestScatteringByteChannel(), 1)); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().writeBytes(new TestScatteringByteChannel(), 1)); } @Test @@ -3233,22 +3244,26 @@ public abstract class AbstractByteBufTest { @Test public void testWriteUsAsciiCharSequenceAfterRelease() { - assertThrows(IllegalReferenceCountException.class, () -> testWriteCharSequenceAfterRelease0(CharsetUtil.US_ASCII)); + assertThrows(IllegalReferenceCountException.class, + () -> testWriteCharSequenceAfterRelease0(CharsetUtil.US_ASCII)); } @Test public void testWriteIso88591CharSequenceAfterRelease() { - assertThrows(IllegalReferenceCountException.class, () -> testWriteCharSequenceAfterRelease0(CharsetUtil.ISO_8859_1)); + assertThrows(IllegalReferenceCountException.class, + () -> testWriteCharSequenceAfterRelease0(CharsetUtil.ISO_8859_1)); } @Test public void testWriteUtf8CharSequenceAfterRelease() { - assertThrows(IllegalReferenceCountException.class, () -> testWriteCharSequenceAfterRelease0(CharsetUtil.UTF_8)); + assertThrows(IllegalReferenceCountException.class, + () -> testWriteCharSequenceAfterRelease0(CharsetUtil.UTF_8)); } @Test public void testWriteUtf16CharSequenceAfterRelease() { - assertThrows(IllegalReferenceCountException.class, () -> testWriteCharSequenceAfterRelease0(CharsetUtil.UTF_16)); + assertThrows(IllegalReferenceCountException.class, + () -> testWriteCharSequenceAfterRelease0(CharsetUtil.UTF_16)); } private void testWriteCharSequenceAfterRelease0(Charset charset) { @@ -3257,22 +3272,26 @@ public abstract class AbstractByteBufTest { @Test public void testForEachByteAfterRelease() { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().forEachByte(new TestByteProcessor())); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().forEachByte(new TestByteProcessor())); } @Test public void testForEachByteAfterRelease1() { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().forEachByte(0, 1, new TestByteProcessor())); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().forEachByte(0, 1, new TestByteProcessor())); } @Test public void testForEachByteDescAfterRelease() { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().forEachByteDesc(new TestByteProcessor())); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().forEachByteDesc(new TestByteProcessor())); } @Test public void testForEachByteDescAfterRelease1() { - assertThrows(IllegalReferenceCountException.class, () -> releasedBuffer().forEachByteDesc(0, 1, new TestByteProcessor())); + assertThrows(IllegalReferenceCountException.class, + () -> releasedBuffer().forEachByteDesc(0, 1, new TestByteProcessor())); } @Test diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/ByteBufAdaptorTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/ByteBufAdaptorTest.java index 6b83159..8fd4ee9 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/ByteBufAdaptorTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/ByteBufAdaptorTest.java @@ -17,7 +17,7 @@ package io.netty.buffer.api.tests.adaptor; import io.netty.buffer.ByteBuf; import io.netty.buffer.api.BufferAllocator; -import io.netty.buffer.api.MemoryManagers; +import io.netty.buffer.api.MemoryManager; import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Disabled; @@ -30,10 +30,10 @@ public abstract class ByteBufAdaptorTest extends AbstractByteBufTest { static ByteBufAllocatorAdaptor alloc; static void setUpAllocator(String name) { - Optional managers = MemoryManagers.lookupImplementation(name); + Optional managers = MemoryManager.lookupImplementation(name); assumeTrue(managers.isPresent(), () -> "Memory implementation '" + name + "' not found."); - BufferAllocator onheap = MemoryManagers.using(managers.get(), BufferAllocator::pooledHeap); - BufferAllocator offheap = MemoryManagers.using(managers.get(), BufferAllocator::pooledHeap); + BufferAllocator onheap = MemoryManager.using(managers.get(), BufferAllocator::onHeapPooled); + BufferAllocator offheap = MemoryManager.using(managers.get(), BufferAllocator::onHeapPooled); alloc = new ByteBufAllocatorAdaptor(onheap, offheap); } @@ -46,7 +46,7 @@ public abstract class ByteBufAdaptorTest extends AbstractByteBufTest { @Override protected ByteBuf newBuffer(int capacity, int maxCapacity) { - return alloc.buffer(capacity, capacity); + return alloc.buffer(capacity, maxCapacity); } @Disabled("This test codifies that asking to reading 0 bytes from an empty but unclosed stream should return -1, " + diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/NioByteBufAdaptorTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/NioByteBufAdaptorTest.java deleted file mode 100644 index de0f4e1..0000000 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/NioByteBufAdaptorTest.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.tests.adaptor; - -import org.junit.jupiter.api.BeforeAll; - -public class NioByteBufAdaptorTest extends ByteBufAdaptorTest { - @BeforeAll - public static void setUpAllocator() { - setUpAllocator("ByteBuffer"); - } -} diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/UnsafeByteBufAdaptorTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/UnsafeByteBufAdaptorTest.java deleted file mode 100644 index ae56013..0000000 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/adaptor/UnsafeByteBufAdaptorTest.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2021 The Netty Project - * - * The Netty Project 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: - * - * https://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.api.tests.adaptor; - -import org.junit.jupiter.api.BeforeAll; - -public class UnsafeByteBufAdaptorTest extends ByteBufAdaptorTest { - @BeforeAll - public static void setUpAllocator() { - setUpAllocator("Unsafe"); - } -} diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/benchmarks/ByteIterationBenchmark.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/benchmarks/ByteIterationBenchmark.java index 3fc06e3..cecf3d1 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/benchmarks/ByteIterationBenchmark.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/benchmarks/ByteIterationBenchmark.java @@ -52,22 +52,22 @@ public class ByteIterationBenchmark { public void setUp() { switch (type) { case "heap": - allocator = BufferAllocator.heap(); + allocator = BufferAllocator.onHeapUnpooled(); buf = allocator.allocate(SIZE); break; case "direct": - allocator = BufferAllocator.direct(); + allocator = BufferAllocator.offHeapUnpooled(); buf = allocator.allocate(SIZE); break; case "composite-heap": - allocator = BufferAllocator.heap(); + allocator = BufferAllocator.onHeapUnpooled(); try (var a = allocator.allocate(SIZE / 2); var b = allocator.allocate(SIZE / 2)) { buf = CompositeBuffer.compose(allocator, a.send(), b.send()); } break; case "composite-direct": - allocator = BufferAllocator.direct(); + allocator = BufferAllocator.offHeapUnpooled(); try (var a = allocator.allocate(SIZE / 2); var b = allocator.allocate(SIZE / 2)) { buf = CompositeBuffer.compose(allocator, a.send(), b.send()); @@ -95,9 +95,6 @@ public class ByteIterationBenchmark { public long sum() { var itr = buf.openCursor(); long sum = 0; - while (itr.readLong()) { - sum += itr.getLong(); - } while (itr.readByte()) { sum += itr.getByte(); } @@ -108,9 +105,6 @@ public class ByteIterationBenchmark { public long sumReverse() { var itr = buf.openReverseCursor(); long sum = 0; - while (itr.readLong()) { - sum += itr.getLong(); - } while (itr.readByte()) { sum += itr.getByte(); } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/benchmarks/SendBenchmark.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/benchmarks/SendBenchmark.java index 4cbdd3e..b6baf0e 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/benchmarks/SendBenchmark.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/benchmarks/SendBenchmark.java @@ -40,8 +40,8 @@ import static java.util.concurrent.CompletableFuture.completedFuture; @OutputTimeUnit(TimeUnit.MICROSECONDS) @State(Scope.Benchmark) public class SendBenchmark { - private static final BufferAllocator NON_POOLED = BufferAllocator.heap(); - private static final BufferAllocator POOLED = BufferAllocator.pooledHeap(); + private static final BufferAllocator NON_POOLED = BufferAllocator.onHeapUnpooled(); + private static final BufferAllocator POOLED = BufferAllocator.onHeapPooled(); private static final Function, Send> BUFFER_BOUNCE = send -> { try (Buffer buf = send.receive()) { return buf.send(); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/AsyncExample.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/AsyncExample.java index c9d0f28..32fe1f4 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/AsyncExample.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/AsyncExample.java @@ -23,7 +23,7 @@ import static java.util.concurrent.CompletableFuture.completedFuture; public final class AsyncExample { public static void main(String[] args) throws Exception { - try (BufferAllocator allocator = BufferAllocator.pooledDirect(); + try (BufferAllocator allocator = BufferAllocator.offHeapPooled(); Buffer startBuf = allocator.allocate(16)) { startBuf.writeLong(threadId()); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/ComposingAndSplittingExample.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/ComposingAndSplittingExample.java index a05b2a1..354747e 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/ComposingAndSplittingExample.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/ComposingAndSplittingExample.java @@ -18,13 +18,12 @@ package io.netty.buffer.api.tests.examples; import io.netty.buffer.api.Buffer; import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.CompositeBuffer; -import io.netty.buffer.api.Scope; import java.util.concurrent.ThreadLocalRandom; public final class ComposingAndSplittingExample { public static void main(String[] args) { - try (BufferAllocator allocator = BufferAllocator.pooledDirect(); + try (BufferAllocator allocator = BufferAllocator.offHeapPooled(); Buffer buf = createBigBuffer(allocator)) { ThreadLocalRandom tlr = ThreadLocalRandom.current(); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/FileCopyExample.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/FileCopyExample.java index e6cea50..70ee5a5 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/FileCopyExample.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/FileCopyExample.java @@ -35,7 +35,7 @@ public final class FileCopyExample { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newFixedThreadPool(2); ArrayBlockingQueue> queue = new ArrayBlockingQueue<>(8); - try (BufferAllocator allocator = BufferAllocator.pooledDirect(); + try (BufferAllocator allocator = BufferAllocator.offHeapPooled(); var input = FileChannel.open(Path.of("/dev/urandom"), READ); var output = FileChannel.open(Path.of("random.bin"), CREATE, TRUNCATE_EXISTING, WRITE)) { Send done = CompositeBuffer.compose(allocator).send(); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/SendExample.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/SendExample.java index bc2f785..ecc2bff 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/SendExample.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/SendExample.java @@ -31,7 +31,7 @@ public class SendExample { public static void main(String[] args) throws Exception { ExecutorService executor = newSingleThreadExecutor(); - BufferAllocator allocator = BufferAllocator.heap(); + BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); var future = beginTask(executor, allocator); future.get(); @@ -68,7 +68,7 @@ public class SendExample { static final class Ex2 { public static void main(String[] args) throws Exception { ExecutorService executor = newSingleThreadExecutor(); - BufferAllocator allocator = BufferAllocator.heap(); + BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); var future = beginTask(executor, allocator); future.get(); @@ -105,7 +105,7 @@ public class SendExample { static final class Ex3 { public static void main(String[] args) throws Exception { ExecutorService executor = newFixedThreadPool(4); - BufferAllocator allocator = BufferAllocator.heap(); + BufferAllocator allocator = BufferAllocator.onHeapUnpooled(); try (Buffer buf = allocator.allocate(4096)) { var futA = executor.submit(new Task(buf.writerOffset(1024).split().send())); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/AlternativeMessageDecoder.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/AlternativeMessageDecoder.java index dcf42d6..f84c005 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/AlternativeMessageDecoder.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/AlternativeMessageDecoder.java @@ -15,10 +15,10 @@ */ package io.netty.buffer.api.tests.examples.bytetomessagedecoder; +import io.netty.buffer.api.Buffer; import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.CompositeBuffer; import io.netty.buffer.api.Send; -import io.netty.buffer.api.Buffer; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; @@ -35,7 +35,7 @@ public abstract class AlternativeMessageDecoder extends ChannelHandlerAdapter { } protected BufferAllocator initAllocator() { - return BufferAllocator.heap(); + return BufferAllocator.onHeapUnpooled(); } protected Buffer initCollector(BufferAllocator allocator, int defaultChunkSize) { @@ -85,8 +85,7 @@ public abstract class AlternativeMessageDecoder extends ChannelHandlerAdapter { private void processRead(ChannelHandlerContext ctx, Buffer input) { if (CompositeBuffer.isComposite(collector) && (collector.writableBytes() == 0 || input.writerOffset() == 0) - && (collector.readableBytes() == 0 || input.readerOffset() == 0) - && collector.order() == input.order()) { + && (collector.readableBytes() == 0 || input.readerOffset() == 0)) { ((CompositeBuffer) collector).extendWith(input.send()); drainCollector(ctx); return; diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/AlternativeMessageDecoderTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/AlternativeMessageDecoderTest.java index e4c1375..751dd69 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/AlternativeMessageDecoderTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/AlternativeMessageDecoderTest.java @@ -15,8 +15,8 @@ */ package io.netty.buffer.api.tests.examples.bytetomessagedecoder; -import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.Buffer; +import io.netty.buffer.api.BufferAllocator; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.embedded.EmbeddedChannel; import org.junit.jupiter.api.Test; @@ -27,7 +27,6 @@ import java.util.List; import java.util.SplittableRandom; import static io.netty.buffer.api.tests.BufferTestSupport.readByteArray; -import static io.netty.buffer.api.tests.BufferTestSupport.toByteArray; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -59,7 +58,7 @@ public class AlternativeMessageDecoderTest { }); List messages = new ArrayList<>(); - Buffer messagesBuffer = BufferAllocator.heap().allocate(132 * 1024); + Buffer messagesBuffer = BufferAllocator.onHeapUnpooled().allocate(132 * 1024); SplittableRandom rng = new SplittableRandom(42); for (int i = 0; i < 1000; i++) { byte[] message = new byte[rng.nextInt(4, 256)]; diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/ByteToMessageDecoder.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/ByteToMessageDecoder.java index 14a14f5..527df35 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/ByteToMessageDecoder.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/ByteToMessageDecoder.java @@ -16,18 +16,15 @@ package io.netty.buffer.api.tests.examples.bytetomessagedecoder; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.api.Buffer; import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.CompositeBuffer; -import io.netty.buffer.api.Buffer; import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelProgressivePromise; -import io.netty.channel.ChannelPromise; import io.netty.channel.socket.ChannelInputShutdownEvent; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.DelimiterBasedFrameDecoder; @@ -37,6 +34,8 @@ import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.util.Attribute; import io.netty.util.AttributeKey; import io.netty.util.concurrent.EventExecutor; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.Promise; import io.netty.util.internal.MathUtil; import io.netty.util.internal.StringUtil; @@ -225,7 +224,7 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter { } private static Buffer newEmptyBuffer() { - return CompositeBuffer.compose(BufferAllocator.heap()); + return CompositeBuffer.compose(BufferAllocator.onHeapUnpooled()); } @Override @@ -271,7 +270,7 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter { cumulation = data; } else { // ByteBufAllocator alloc = ctx.alloc(); // TODO this API integration needs more work - BufferAllocator alloc = BufferAllocator.heap(); + BufferAllocator alloc = BufferAllocator.onHeapUnpooled(); cumulation = cumulator.cumulate(alloc, cumulation, data); } assert context.ctx == ctx || ctx == context; @@ -470,7 +469,7 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter { private static Buffer expandCumulation(BufferAllocator alloc, Buffer oldCumulation, Buffer in) { int newSize = MathUtil.safeFindNextPositivePowerOfTwo(oldCumulation.readableBytes() + in.readableBytes()); - Buffer newCumulation = alloc.allocate(newSize, oldCumulation.order()); + Buffer newCumulation = alloc.allocate(newSize); Buffer toRelease = newCumulation; try { newCumulation.writeBytes(oldCumulation); @@ -597,6 +596,11 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter { return this; } + @Override + public Future write(Object msg) { + return ctx.write(msg); + } + @Override public ChannelHandlerContext flush() { ctx.flush(); @@ -626,118 +630,58 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter { } @Override - public ChannelFuture bind(SocketAddress localAddress) { + public Future bind(SocketAddress localAddress) { return ctx.bind(localAddress); } @Override - public ChannelFuture connect(SocketAddress remoteAddress) { + public Future connect(SocketAddress remoteAddress) { return ctx.connect(remoteAddress); } @Override - public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) { + public Future connect(SocketAddress remoteAddress, SocketAddress localAddress) { return ctx.connect(remoteAddress, localAddress); } @Override - public ChannelFuture disconnect() { + public Future disconnect() { return ctx.disconnect(); } @Override - public ChannelFuture close() { + public Future close() { return ctx.close(); } @Override - public ChannelFuture deregister() { + public Future deregister() { return ctx.deregister(); } @Override - public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) { - return ctx.bind(localAddress, promise); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) { - return ctx.connect(remoteAddress, promise); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { - return ctx.connect(remoteAddress, localAddress, promise); - } - - @Override - public ChannelFuture disconnect(ChannelPromise promise) { - return ctx.disconnect(promise); - } - - @Override - public ChannelFuture close(ChannelPromise promise) { - return ctx.close(promise); - } - - @Override - public ChannelFuture register() { + public Future register() { return ctx.register(); } @Override - public ChannelFuture register(ChannelPromise promise) { - return ctx.register(promise); - } - - @Override - public ChannelFuture deregister(ChannelPromise promise) { - return ctx.deregister(promise); - } - - @Override - public ChannelFuture write(Object msg) { - return ctx.write(msg); - } - - @Override - public ChannelFuture write(Object msg, ChannelPromise promise) { - return ctx.write(msg, promise); - } - - @Override - public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { - return ctx.writeAndFlush(msg, promise); - } - - @Override - public ChannelFuture writeAndFlush(Object msg) { + public Future writeAndFlush(Object msg) { return ctx.writeAndFlush(msg); } @Override - public ChannelPromise newPromise() { + public Promise newPromise() { return ctx.newPromise(); } @Override - public ChannelProgressivePromise newProgressivePromise() { - return ctx.newProgressivePromise(); - } - - @Override - public ChannelFuture newSucceededFuture() { + public Future newSucceededFuture() { return ctx.newSucceededFuture(); } @Override - public ChannelFuture newFailedFuture(Throwable cause) { + public Future newFailedFuture(Throwable cause) { return ctx.newFailedFuture(cause); } - - @Override - public ChannelPromise voidPromise() { - return ctx.voidPromise(); - } } } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/ByteToMessageDecoderTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/ByteToMessageDecoderTest.java index 782d9a2..2c3e7f3 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/ByteToMessageDecoderTest.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/bytetomessagedecoder/ByteToMessageDecoderTest.java @@ -15,8 +15,8 @@ */ package io.netty.buffer.api.tests.examples.bytetomessagedecoder; -import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.Buffer; +import io.netty.buffer.api.BufferAllocator; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.embedded.EmbeddedChannel; @@ -29,12 +29,12 @@ import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; -import static io.netty.buffer.api.tests.BufferTestSupport.assertEquals; +import static io.netty.buffer.api.BufferAllocator.onHeapUnpooled; import static io.netty.buffer.api.CompositeBuffer.compose; +import static io.netty.buffer.api.tests.BufferTestSupport.assertEquals; import static io.netty.buffer.api.tests.BufferTestSupport.assertReadableEquals; -import static java.nio.ByteOrder.BIG_ENDIAN; -import static java.nio.ByteOrder.LITTLE_ENDIAN; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -61,7 +61,7 @@ public class ByteToMessageDecoderTest { } }); - channel.writeInbound(BufferAllocator.heap().allocate(4, BIG_ENDIAN).writeInt(0x01020304)); + channel.writeInbound(onHeapUnpooled().allocate(4).writeInt(0x01020304)); try (Buffer b = channel.readInbound()) { assertEquals(3, b.readableBytes()); assertEquals(0x02, b.readByte()); @@ -72,7 +72,7 @@ public class ByteToMessageDecoderTest { @Test public void testRemoveItselfWriteBuffer() { - try (Buffer buf = BufferAllocator.heap().allocate(5, BIG_ENDIAN).writeInt(0x01020304)) { + try (Buffer buf = onHeapUnpooled().allocate(5).writeInt(0x01020304)) { EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() { private boolean removed; @@ -89,7 +89,7 @@ public class ByteToMessageDecoderTest { }); channel.writeInbound(buf.copy()); - try (Buffer expected = BufferAllocator.heap().allocate(3, BIG_ENDIAN).writeShort((short) 0x0203).writeByte((byte) 0x04); + try (Buffer expected = onHeapUnpooled().allocate(3).writeShort((short) 0x0203).writeByte((byte) 0x04); Buffer actual = channel.readInbound()) { assertReadableEquals(expected, actual); } @@ -98,7 +98,7 @@ public class ByteToMessageDecoderTest { @Test public void testRemoveItselfWriteBuffer2() { - Buffer buf = BufferAllocator.heap().allocate(5, BIG_ENDIAN).writeInt(0x01020304); + Buffer buf = onHeapUnpooled().allocate(5).writeInt(0x01020304); EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() { private boolean removed; @@ -115,7 +115,7 @@ public class ByteToMessageDecoderTest { }); channel.writeInbound(buf); - try (Buffer expected = BufferAllocator.heap().allocate(4, BIG_ENDIAN).writeInt(0x02030405); + try (Buffer expected = onHeapUnpooled().allocate(4).writeInt(0x02030405); Buffer actual = channel.readInbound()) { assertReadableEquals(expected, actual); } @@ -127,7 +127,7 @@ public class ByteToMessageDecoderTest { */ @Test public void testInternalBufferClearReadAll() { - Buffer buf = BufferAllocator.heap().allocate(1).writeByte((byte) 'a'); + Buffer buf = onHeapUnpooled().allocate(1).writeByte((byte) 'a'); EmbeddedChannel channel = newInternalBufferTestChannel(); assertFalse(channel.writeInbound(buf)); assertFalse(channel.finish()); @@ -139,11 +139,11 @@ public class ByteToMessageDecoderTest { */ @Test public void testInternalBufferClearReadPartly() { - final Buffer buf = BufferAllocator.heap().allocate(2, BIG_ENDIAN).writeShort((short) 0x0102); + final Buffer buf = onHeapUnpooled().allocate(2).writeShort((short) 0x0102); EmbeddedChannel channel = newInternalBufferTestChannel(); assertTrue(channel.writeInbound(buf)); assertTrue(channel.finish()); - try (Buffer expected = BufferAllocator.heap().allocate(1).writeByte((byte) 0x02); + try (Buffer expected = onHeapUnpooled().allocate(1).writeByte((byte) 0x02); Buffer actual = channel.readInbound()) { assertReadableEquals(expected, actual); assertNull(channel.readInbound()); @@ -185,7 +185,7 @@ public class ByteToMessageDecoderTest { byte[] bytes = new byte[1024]; ThreadLocalRandom.current().nextBytes(bytes); - Buffer buffer = BufferAllocator.heap().allocate(bytes.length); + Buffer buffer = onHeapUnpooled().allocate(bytes.length); for (byte b : bytes) { buffer.writeByte(b); } @@ -232,7 +232,7 @@ public class ByteToMessageDecoderTest { } } }); - Buffer buf = BufferAllocator.heap().allocate(2, BIG_ENDIAN).writeShort((short) 0x0102); + Buffer buf = onHeapUnpooled().allocate(2).writeShort((short) 0x0102); assertFalse(channel.writeInbound(buf)); channel.finish(); assertEquals(1, queue.take()); @@ -265,7 +265,7 @@ public class ByteToMessageDecoderTest { } }); - try (Buffer buf = BufferAllocator.heap().allocate(4, BIG_ENDIAN).writeInt(0x01020304)) { + try (Buffer buf = onHeapUnpooled().allocate(4).writeInt(0x01020304)) { assertTrue(channel.writeInbound(buf.copy())); try (Buffer expected = buf.copy(1, 3); Buffer actual = channel.readInbound()) { @@ -288,7 +288,7 @@ public class ByteToMessageDecoderTest { byte[] bytes = new byte[1024]; ThreadLocalRandom.current().nextBytes(bytes); - try (Buffer buf = BufferAllocator.heap().allocate(bytes.length)) { + try (Buffer buf = onHeapUnpooled().allocate(bytes.length)) { for (byte b : bytes) { buf.writeByte(b); } @@ -328,7 +328,7 @@ public class ByteToMessageDecoderTest { }); byte[] bytes = new byte[1024]; ThreadLocalRandom.current().nextBytes(bytes); - Buffer buf = BufferAllocator.heap().allocate(bytes.length, BIG_ENDIAN).writeBytes(bytes); + Buffer buf = onHeapUnpooled().allocate(bytes.length).writeBytes(bytes); try (Buffer part1 = buf.copy(0, bytes.length - 1); Buffer part2 = buf.copy(bytes.length - 1, 1)) { assertTrue(channel.writeInbound(buf)); @@ -350,8 +350,8 @@ public class ByteToMessageDecoderTest { @Override protected void decode(ChannelHandlerContext ctx, Buffer in) { } }); - assertFalse(channel.writeInbound(BufferAllocator.heap().allocate(8).writeByte((byte) 1).makeReadOnly())); - assertFalse(channel.writeInbound(BufferAllocator.heap().allocate(1).writeByte((byte) 2))); + assertFalse(channel.writeInbound(onHeapUnpooled().allocate(8).writeByte((byte) 1).makeReadOnly())); + assertFalse(channel.writeInbound(onHeapUnpooled().allocate(1).writeByte((byte) 2))); assertFalse(channel.finish()); } @@ -359,11 +359,11 @@ public class ByteToMessageDecoderTest { public void releaseWhenMergeCumulateThrows() { Buffer oldCumulation = writeFailingCumulation(1, 64); oldCumulation.writeByte((byte) 0); - Buffer in = BufferAllocator.heap().allocate(12, BIG_ENDIAN).writerOffset(12); + Buffer in = onHeapUnpooled().allocate(12).writerOffset(12); Throwable thrown = null; try { - ByteToMessageDecoder.MERGE_CUMULATOR.cumulate(BufferAllocator.heap(), oldCumulation, in); + ByteToMessageDecoder.MERGE_CUMULATOR.cumulate(onHeapUnpooled(), oldCumulation, in); } catch (Throwable t) { thrown = t; } @@ -375,7 +375,7 @@ public class ByteToMessageDecoderTest { } private static Buffer writeFailingCumulation(int untilFailure, int capacity) { - Buffer realBuffer = BufferAllocator.heap().allocate(capacity, BIG_ENDIAN); + Buffer realBuffer = onHeapUnpooled().allocate(capacity); Answer callRealBuffer = inv -> { Object result = inv.getMethod().invoke(realBuffer, inv.getArguments()); if (result == realBuffer) { @@ -403,7 +403,7 @@ public class ByteToMessageDecoderTest { } private static void releaseWhenMergeCumulateThrowsInExpand(int untilFailure, boolean shouldFail) { - Buffer oldCumulation = BufferAllocator.heap().allocate(8, BIG_ENDIAN).writeByte((byte) 0); + Buffer oldCumulation = onHeapUnpooled().allocate(8).writeByte((byte) 0); Buffer newCumulation = writeFailingCumulation(untilFailure, 16); BufferAllocator allocator = new BufferAllocator() { @@ -411,9 +411,20 @@ public class ByteToMessageDecoderTest { public Buffer allocate(int capacity) { return newCumulation; } + + @Override + public Supplier constBufferSupplier(byte[] bytes) { + fail(); + return null; + } + + @Override + public void close() { + fail(); + } }; - Buffer in = BufferAllocator.heap().allocate(12, BIG_ENDIAN).writerOffset(12); + Buffer in = onHeapUnpooled().allocate(12).writerOffset(12); Throwable thrown = null; try { ByteToMessageDecoder.MERGE_CUMULATOR.cumulate(allocator, oldCumulation, in); @@ -438,9 +449,9 @@ public class ByteToMessageDecoderTest { @Test public void releaseWhenCompositeCumulateThrows() { - Buffer in = BufferAllocator.heap().allocate(12, LITTLE_ENDIAN).writerOffset(12); - try (Buffer cumulation = compose(BufferAllocator.heap(), BufferAllocator.heap().allocate(1, BIG_ENDIAN).writeByte((byte) 0).send())) { - ByteToMessageDecoder.COMPOSITE_CUMULATOR.cumulate(BufferAllocator.heap(), cumulation, in); + Buffer in = onHeapUnpooled().allocate(12).writerOffset(12); + try (Buffer cumulation = compose(onHeapUnpooled(), onHeapUnpooled().allocate(1).writeByte((byte) 0).send())) { + ByteToMessageDecoder.COMPOSITE_CUMULATOR.cumulate(onHeapUnpooled(), cumulation, in); fail(); } catch (IllegalArgumentException expected) { assertThat(expected).hasMessageContaining("byte order"); @@ -467,30 +478,30 @@ public class ByteToMessageDecoderTest { assertEquals(0, interceptor.readsTriggered); // 0 complete frames, 1 partial frame: SHOULD trigger a read - channel.writeInbound(BufferAllocator.heap().allocate(2, BIG_ENDIAN).writeShort((short) 0x0001)); + channel.writeInbound(onHeapUnpooled().allocate(2).writeShort((short) 0x0001)); assertEquals(1, interceptor.readsTriggered); // 2 complete frames, 0 partial frames: should NOT trigger a read - channel.writeInbound(BufferAllocator.heap().allocate(1).writeByte((byte) 2), - BufferAllocator.heap().allocate(3).writeByte((byte) 3).writeByte((byte) 4).writeByte((byte) 5)); + channel.writeInbound(onHeapUnpooled().allocate(1).writeByte((byte) 2), + onHeapUnpooled().allocate(3).writeByte((byte) 3).writeByte((byte) 4).writeByte((byte) 5)); assertEquals(1, interceptor.readsTriggered); // 1 complete frame, 1 partial frame: should NOT trigger a read - channel.writeInbound(BufferAllocator.heap().allocate(3).writeByte((byte) 6).writeByte((byte) 7).writeByte((byte) 8), - BufferAllocator.heap().allocate(1).writeByte((byte) 9)); + channel.writeInbound(onHeapUnpooled().allocate(3).writeByte((byte) 6).writeByte((byte) 7).writeByte((byte) 8), + onHeapUnpooled().allocate(1).writeByte((byte) 9)); assertEquals(1, interceptor.readsTriggered); // 1 complete frame, 1 partial frame: should NOT trigger a read - channel.writeInbound(BufferAllocator.heap().allocate(2).writeByte((byte) 10).writeByte((byte) 11), - BufferAllocator.heap().allocate(1).writeByte((byte) 12)); + channel.writeInbound(onHeapUnpooled().allocate(2).writeByte((byte) 10).writeByte((byte) 11), + onHeapUnpooled().allocate(1).writeByte((byte) 12)); assertEquals(1, interceptor.readsTriggered); // 0 complete frames, 1 partial frame: SHOULD trigger a read - channel.writeInbound(BufferAllocator.heap().allocate(1).writeByte((byte) 13)); + channel.writeInbound(onHeapUnpooled().allocate(1).writeByte((byte) 13)); assertEquals(2, interceptor.readsTriggered); // 1 complete frame, 0 partial frames: should NOT trigger a read - channel.writeInbound(BufferAllocator.heap().allocate(1).writeByte((byte) 14)); + channel.writeInbound(onHeapUnpooled().allocate(1).writeByte((byte) 14)); assertEquals(2, interceptor.readsTriggered); for (int i = 0; i < 5; i++) { @@ -519,7 +530,7 @@ public class ByteToMessageDecoderTest { }; EmbeddedChannel channel = new EmbeddedChannel(decoder); byte[] bytes = {1, 2, 3, 4, 5}; - Buffer buf = BufferAllocator.heap().allocate(bytes.length); + Buffer buf = onHeapUnpooled().allocate(bytes.length); for (byte b : bytes) { buf.writeByte(b); } @@ -549,7 +560,7 @@ public class ByteToMessageDecoderTest { }); byte[] bytes = new byte[1024]; ThreadLocalRandom.current().nextBytes(bytes); - try (Buffer buf = BufferAllocator.heap().allocate(bytes.length).writeBytes(bytes)) { + try (Buffer buf = onHeapUnpooled().allocate(bytes.length).writeBytes(bytes)) { assertFalse(channel.writeInbound(buf.copy())); assertNull(channel.readInbound()); removeHandler.set(true); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoClient.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoClient.java index aa7a833..f8dac4f 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoClient.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoClient.java @@ -16,7 +16,7 @@ package io.netty.buffer.api.tests.examples.echo; import io.netty.bootstrap.Bootstrap; -import io.netty.channel.ChannelFuture; +import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; @@ -74,10 +74,10 @@ public final class EchoClient { }); // Start the client. - ChannelFuture f = b.connect(HOST, PORT).sync(); + Channel channel = b.connect(HOST, PORT).sync().getNow(); // Wait until the connection is closed. - f.channel().closeFuture().sync(); + channel.closeFuture().sync(); } finally { // Shut down the event loop to terminate all threads. group.shutdownGracefully(); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoClientHandler.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoClientHandler.java index 321741f..35798d2 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoClientHandler.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoClientHandler.java @@ -15,8 +15,8 @@ */ package io.netty.buffer.api.tests.examples.echo; -import io.netty.buffer.api.BufferAllocator; import io.netty.buffer.api.Buffer; +import io.netty.buffer.api.BufferAllocator; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; @@ -33,7 +33,7 @@ public class EchoClientHandler implements ChannelHandler { * Creates a client-side handler. */ public EchoClientHandler() { - firstMessage = BufferAllocator.heap().allocate(EchoClient.SIZE); + firstMessage = BufferAllocator.onHeapUnpooled().allocate(EchoClient.SIZE); for (int i = 0; i < firstMessage.capacity(); i ++) { firstMessage.writeByte((byte) i); } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoServer.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoServer.java index 99485ca..8bb90e8 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoServer.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/echo/EchoServer.java @@ -17,7 +17,7 @@ package io.netty.buffer.api.tests.examples.echo; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor; -import io.netty.channel.ChannelFuture; +import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; @@ -75,10 +75,10 @@ public final class EchoServer { }); // Start the server. - ChannelFuture f = b.bind(PORT).sync(); + Channel channel = b.bind(PORT).sync().getNow(); // Wait until the server socket is closed. - f.channel().closeFuture().sync(); + channel.closeFuture().sync(); } finally { // Shut down all event loops to terminate all threads. bossGroup.shutdownGracefully(); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/snoop/HttpSnoopClient.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/snoop/HttpSnoopClient.java index c61a6ac..8cc15c2 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/snoop/HttpSnoopClient.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/snoop/HttpSnoopClient.java @@ -85,7 +85,7 @@ public final class HttpSnoopClient { .handler(new HttpSnoopClientInitializer(sslCtx, allocator)); // Make the connection attempt. - Channel ch = b.connect(host, port).sync().channel(); + Channel ch = b.connect(host, port).sync().getNow(); // Prepare the HTTP request. HttpRequest request = new DefaultFullHttpRequest( diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/snoop/HttpSnoopClientHandler.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/snoop/HttpSnoopClientHandler.java index 2638003..e69f8a9 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/snoop/HttpSnoopClientHandler.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/snoop/HttpSnoopClientHandler.java @@ -28,8 +28,7 @@ public class HttpSnoopClientHandler extends SimpleChannelInboundHandler if (!writeResponse(trailer, ctx)) { // If keep-alive is off, close the connection once the content is fully written. - ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ctx, ChannelFutureListeners.CLOSE); } } } diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/upload/HttpUploadClient.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/upload/HttpUploadClient.java index 6c76344..7377d2c 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/upload/HttpUploadClient.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/upload/HttpUploadClient.java @@ -18,7 +18,6 @@ package io.netty.buffer.api.tests.examples.http.upload; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.api.adaptor.ByteBufAllocatorAdaptor; import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.MultithreadEventLoopGroup; @@ -156,7 +155,7 @@ public final class HttpUploadClient { Bootstrap bootstrap, String host, int port, String get, URI uriSimple) throws Exception { // XXX /formget // No use of HttpPostRequestEncoder since not a POST - Channel channel = bootstrap.connect(host, port).sync().channel(); + Channel channel = bootstrap.connect(host, port).sync().getNow(); // Prepare the HTTP request. QueryStringEncoder encoder = new QueryStringEncoder(get); @@ -213,9 +212,9 @@ public final class HttpUploadClient { List> headers) throws Exception { // XXX /formpost // Start the connection attempt. - ChannelFuture future = bootstrap.connect(SocketUtils.socketAddress(host, port)); + var future = bootstrap.connect(SocketUtils.socketAddress(host, port)); // Wait until the connection attempt succeeds or fails. - Channel channel = future.sync().channel(); + Channel channel = future.sync().getNow(); // Prepare the HTTP request. HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString()); @@ -273,9 +272,9 @@ public final class HttpUploadClient { Iterable> headers, List bodylist) throws Exception { // XXX /formpostmultipart // Start the connection attempt. - ChannelFuture future = bootstrap.connect(SocketUtils.socketAddress(host, port)); + var future = bootstrap.connect(SocketUtils.socketAddress(host, port)); // Wait until the connection attempt succeeds or fails. - Channel channel = future.sync().channel(); + Channel channel = future.sync().getNow(); // Prepare the HTTP request. HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriFile.toASCIIString()); diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/upload/HttpUploadClientHandler.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/upload/HttpUploadClientHandler.java index 1524cea..8bb5af3 100644 --- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/upload/HttpUploadClientHandler.java +++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/examples/http/upload/HttpUploadClientHandler.java @@ -33,9 +33,7 @@ public class HttpUploadClientHandler extends SimpleChannelInboundHandler 11 - 11 + 17 5.7.0 3.0.0-M5 + --add-modules jdk.incubator.foreign - buffer-api + buffer-memseg buffer-tests - - - Java 17 support - - 17 - - - 17 - --add-modules jdk.incubator.foreign - - - buffer-memseg - - - - Java 11 support for tests - - !17 - - - buffer-memseg-dummy - - - -