UnsafeBuffer implementation, based on sun.misc.Unsafe
Motivation: When Unsafe is available, we can supposedly do certain things faster than when it is not. Modification: Add a Buffer implementation that take advantage of sun.misc.Unsafe. It has not yet been verified if this is faster in any way than, say the ByteBuffer implementation or the MemorySegment implementation. Result: Another Buffer implementation that can be used when Unsafe is available.
This commit is contained in:
parent
e7f7335804
commit
c73dd07384
2
pom.xml
2
pom.xml
@ -78,6 +78,8 @@
|
||||
-server
|
||||
-dsa -da -ea:io.netty...
|
||||
-XX:+HeapDumpOnOutOfMemoryError
|
||||
-Dio.netty.tryReflectionSetAccessible=true
|
||||
--add-opens java.base/java.nio=io.netty.common
|
||||
</argLine.common>
|
||||
<!-- <argLine.printGC>-XX:+PrintGCDetails</argLine.printGC>-->
|
||||
<argLine.printGC/>
|
||||
|
@ -26,5 +26,6 @@ public interface MemoryManager {
|
||||
Drop<Buffer> drop();
|
||||
Object unwrapRecoverableMemory(Buffer buf);
|
||||
int capacityOfRecoverableMemory(Object memory);
|
||||
// todo should recoverMemory re-attach a cleaner?
|
||||
Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop<Buffer> drop);
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ReadOnlyBufferException;
|
||||
|
||||
import static io.netty.buffer.api.internal.Statics.bufferIsClosed;
|
||||
import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly;
|
||||
|
||||
class NioBuffer extends RcSupport<Buffer, NioBuffer> implements Buffer, ReadableComponent, WritableComponent {
|
||||
private static final ByteBuffer CLOSED_BUFFER = ByteBuffer.allocate(0);
|
||||
|
||||
@ -417,9 +420,9 @@ class NioBuffer extends RcSupport<Buffer, NioBuffer> implements Buffer, Readable
|
||||
}
|
||||
var drop = (ArcDrop<NioBuffer>) unsafeGetDrop();
|
||||
unsafeSetDrop(new ArcDrop<>(drop));
|
||||
var bifurcatedSeg = rmem.slice(0, woff);
|
||||
var bifurcatedBuffer = rmem.slice(0, woff);
|
||||
// TODO maybe incrementing the existing ArcDrop is enough; maybe we don't need to wrap it in another ArcDrop.
|
||||
var bifurcatedBuf = new NioBuffer(base, bifurcatedSeg, control, new ArcDrop<>(drop.increment()));
|
||||
var bifurcatedBuf = new NioBuffer(base, bifurcatedBuffer, control, new ArcDrop<>(drop.increment()));
|
||||
bifurcatedBuf.woff = woff;
|
||||
bifurcatedBuf.roff = roff;
|
||||
bifurcatedBuf.order(order());
|
||||
@ -893,7 +896,7 @@ class NioBuffer extends RcSupport<Buffer, NioBuffer> implements Buffer, Readable
|
||||
wmem.putInt(woff, value);
|
||||
return this;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw checkWriteState(e, NioBuffer.this.woff);
|
||||
throw checkWriteState(e, this.woff);
|
||||
} catch (ReadOnlyBufferException e) {
|
||||
throw bufferIsReadOnly();
|
||||
}
|
||||
@ -918,7 +921,7 @@ class NioBuffer extends RcSupport<Buffer, NioBuffer> implements Buffer, Readable
|
||||
wmem.putInt(woff, (int) (value & 0xFFFFFFFFL));
|
||||
return this;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw checkWriteState(e, NioBuffer.this.woff);
|
||||
throw checkWriteState(e, this.woff);
|
||||
} catch (ReadOnlyBufferException e) {
|
||||
throw bufferIsReadOnly();
|
||||
}
|
||||
@ -1135,14 +1138,6 @@ class NioBuffer extends RcSupport<Buffer, NioBuffer> implements Buffer, Readable
|
||||
return outOfBounds(index);
|
||||
}
|
||||
|
||||
private static IllegalStateException bufferIsClosed() {
|
||||
return new IllegalStateException("This buffer is closed.");
|
||||
}
|
||||
|
||||
private static IllegalStateException bufferIsReadOnly() {
|
||||
return new IllegalStateException("This buffer is read-only.");
|
||||
}
|
||||
|
||||
private IndexOutOfBoundsException outOfBounds(int index) {
|
||||
return new IndexOutOfBoundsException(
|
||||
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
||||
|
@ -68,4 +68,12 @@ public interface Statics {
|
||||
dest.order(prevOrder);
|
||||
}
|
||||
}
|
||||
|
||||
static IllegalStateException bufferIsClosed() {
|
||||
return new IllegalStateException("This buffer is closed.");
|
||||
}
|
||||
|
||||
static IllegalStateException bufferIsReadOnly() {
|
||||
return new IllegalStateException("This buffer is read-only.");
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ import jdk.incubator.foreign.ResourceScope;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import static io.netty.buffer.api.internal.Statics.bufferIsClosed;
|
||||
import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly;
|
||||
import static jdk.incubator.foreign.MemoryAccess.getByteAtOffset;
|
||||
import static jdk.incubator.foreign.MemoryAccess.getCharAtOffset;
|
||||
import static jdk.incubator.foreign.MemoryAccess.getDoubleAtOffset;
|
||||
@ -1168,14 +1170,6 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
||||
return outOfBounds(index);
|
||||
}
|
||||
|
||||
private static IllegalStateException bufferIsClosed() {
|
||||
return new IllegalStateException("This buffer is closed.");
|
||||
}
|
||||
|
||||
private static IllegalStateException bufferIsReadOnly() {
|
||||
return new IllegalStateException("This buffer is read-only.");
|
||||
}
|
||||
|
||||
private IndexOutOfBoundsException outOfBounds(int index) {
|
||||
return new IndexOutOfBoundsException(
|
||||
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
||||
|
55
src/main/java/io/netty/buffer/api/unsafe/CleanerDrop.java
Normal file
55
src/main/java/io/netty/buffer/api/unsafe/CleanerDrop.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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<Buffer> {
|
||||
private final Drop<Buffer> drop;
|
||||
|
||||
public CleanerDrop(UnsafeMemory memory, Drop<Buffer> 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);
|
||||
}
|
||||
}
|
||||
}
|
1557
src/main/java/io/netty/buffer/api/unsafe/UnsafeBuffer.java
Normal file
1557
src/main/java/io/netty/buffer/api/unsafe/UnsafeBuffer.java
Normal file
File diff suppressed because it is too large
Load Diff
28
src/main/java/io/netty/buffer/api/unsafe/UnsafeMemory.java
Normal file
28
src/main/java/io/netty/buffer/api/unsafe/UnsafeMemory.java
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 allocateConfined(AllocatorControl allocatorControl, long size, Drop<Buffer> drop, Cleaner cleaner) {
|
||||
return allocateShared(allocatorControl, size, drop, cleaner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Buffer allocateShared(AllocatorControl allocatorControl, long size, Drop<Buffer> 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 Drop<Buffer> 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 Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop<Buffer> drop) {
|
||||
UnsafeMemory memory = (UnsafeMemory) recoverableMemory;
|
||||
return new UnsafeBuffer(memory, 0, memory.size, allocatorControl, convert(drop));
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 toString() {
|
||||
return "US";
|
||||
}
|
||||
}
|
20
src/main/java/io/netty/buffer/api/unsafe/package-info.java
Normal file
20
src/main/java/io/netty/buffer/api/unsafe/package-info.java
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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;
|
@ -32,5 +32,6 @@ module netty.incubator.buffer {
|
||||
|
||||
provides io.netty.buffer.api.MemoryManagers with
|
||||
io.netty.buffer.api.memseg.SegmentMemoryManagers,
|
||||
io.netty.buffer.api.bytebuffer.ByteBufferMemoryManagers;
|
||||
io.netty.buffer.api.bytebuffer.ByteBufferMemoryManagers,
|
||||
io.netty.buffer.api.unsafe.UnsafeMemoryManagers;
|
||||
}
|
Loading…
Reference in New Issue
Block a user