Merge pull request #36 from netty/rc-thread-safety
Allow slices to obtain ownership when parent is closed
This commit is contained in:
commit
0272b1cf84
@ -45,6 +45,7 @@ class CleanerPooledDrop implements Drop<Buffer> {
|
|||||||
GatedCleanable c = (GatedCleanable) CLEANABLE.getAndSet(this, null);
|
GatedCleanable c = (GatedCleanable) CLEANABLE.getAndSet(this, null);
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
c.clean();
|
c.clean();
|
||||||
|
delegate.drop(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,24 +58,43 @@ class CleanerPooledDrop implements Drop<Buffer> {
|
|||||||
c.clean();
|
c.clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
var pool = this.pool;
|
|
||||||
var mem = manager.unwrapRecoverableMemory(buf);
|
var mem = manager.unwrapRecoverableMemory(buf);
|
||||||
var delegate = this.delegate;
|
WeakReference<CleanerPooledDrop> ref = new WeakReference<>(this);
|
||||||
WeakReference<Buffer> ref = new WeakReference<>(buf);
|
|
||||||
AtomicBoolean gate = new AtomicBoolean(true);
|
AtomicBoolean gate = new AtomicBoolean(true);
|
||||||
cleanable = new GatedCleanable(gate, CLEANER.register(this, () -> {
|
cleanable = new GatedCleanable(gate, CLEANER.register(this, new CleanAction(pool, mem, ref, gate)));
|
||||||
if (gate.getAndSet(false)) {
|
|
||||||
Buffer b = ref.get();
|
|
||||||
if (b == null) {
|
|
||||||
pool.recoverMemory(mem);
|
|
||||||
} else {
|
|
||||||
delegate.drop(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GatedCleanable implements Cleanable {
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CleanerPooledDrop(" + delegate + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class CleanAction implements Runnable {
|
||||||
|
private final SizeClassedMemoryPool pool;
|
||||||
|
private final Object mem;
|
||||||
|
private final WeakReference<CleanerPooledDrop> ref;
|
||||||
|
private final AtomicBoolean gate;
|
||||||
|
|
||||||
|
private CleanAction(SizeClassedMemoryPool pool, Object mem, WeakReference<CleanerPooledDrop> ref,
|
||||||
|
AtomicBoolean gate) {
|
||||||
|
this.pool = pool;
|
||||||
|
this.mem = mem;
|
||||||
|
this.ref = ref;
|
||||||
|
this.gate = gate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (gate.getAndSet(false)) {
|
||||||
|
var monitored = ref.get();
|
||||||
|
if (monitored == null) {
|
||||||
|
pool.recoverMemory(mem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class GatedCleanable implements Cleanable {
|
||||||
private final AtomicBoolean gate;
|
private final AtomicBoolean gate;
|
||||||
private final Cleanable cleanable;
|
private final Cleanable cleanable;
|
||||||
|
|
||||||
|
@ -31,16 +31,23 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
* non-composite copy of the buffer.
|
* non-composite copy of the buffer.
|
||||||
*/
|
*/
|
||||||
private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8;
|
private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8;
|
||||||
private static final Drop<CompositeBuffer> COMPOSITE_DROP = buf -> {
|
private static final Drop<CompositeBuffer> COMPOSITE_DROP = new Drop<CompositeBuffer>() {
|
||||||
for (Buffer b : buf.bufs) {
|
@Override
|
||||||
b.close();
|
public void drop(CompositeBuffer buf) {
|
||||||
|
for (Buffer b : buf.bufs) {
|
||||||
|
b.close();
|
||||||
|
}
|
||||||
|
buf.makeInaccessible();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "COMPOSITE_DROP";
|
||||||
}
|
}
|
||||||
buf.makeInaccessible();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private final BufferAllocator allocator;
|
private final BufferAllocator allocator;
|
||||||
private final TornBufferAccessors tornBufAccessors;
|
private final TornBufferAccessors tornBufAccessors;
|
||||||
private final boolean isSendable;
|
|
||||||
private Buffer[] bufs;
|
private Buffer[] bufs;
|
||||||
private int[] offsets; // The offset, for the composite buffer, where each constituent buffer starts.
|
private int[] offsets; // The offset, for the composite buffer, where each constituent buffer starts.
|
||||||
private int capacity;
|
private int capacity;
|
||||||
@ -52,7 +59,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
private boolean readOnly;
|
private boolean readOnly;
|
||||||
|
|
||||||
CompositeBuffer(BufferAllocator allocator, Deref<Buffer>[] refs) {
|
CompositeBuffer(BufferAllocator allocator, Deref<Buffer>[] refs) {
|
||||||
this(allocator, true, filterExternalBufs(refs), COMPOSITE_DROP, false);
|
this(allocator, filterExternalBufs(refs), COMPOSITE_DROP, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Buffer[] filterExternalBufs(Deref<Buffer>[] refs) {
|
private static Buffer[] filterExternalBufs(Deref<Buffer>[] refs) {
|
||||||
@ -106,11 +113,10 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
return Stream.of(buf);
|
return Stream.of(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompositeBuffer(BufferAllocator allocator, boolean isSendable, Buffer[] bufs, Drop<CompositeBuffer> drop,
|
private CompositeBuffer(BufferAllocator allocator, Buffer[] bufs, Drop<CompositeBuffer> drop,
|
||||||
boolean acquireBufs) {
|
boolean acquireBufs) {
|
||||||
super(drop);
|
super(drop);
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
this.isSendable = isSendable;
|
|
||||||
if (acquireBufs) {
|
if (acquireBufs) {
|
||||||
for (Buffer buf : bufs) {
|
for (Buffer buf : bufs) {
|
||||||
buf.acquire();
|
buf.acquire();
|
||||||
@ -297,46 +303,31 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
offset + ", and length was " + length + '.');
|
offset + ", and length was " + length + '.');
|
||||||
}
|
}
|
||||||
Buffer choice = (Buffer) chooseBuffer(offset, 0);
|
Buffer choice = (Buffer) chooseBuffer(offset, 0);
|
||||||
Buffer[] slices = null;
|
Buffer[] slices;
|
||||||
acquire(); // Increase reference count of the original composite buffer.
|
|
||||||
Drop<CompositeBuffer> drop = obj -> {
|
|
||||||
close(); // Decrement the reference count of the original composite buffer.
|
|
||||||
COMPOSITE_DROP.drop(obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
if (length > 0) {
|
||||||
if (length > 0) {
|
slices = new Buffer[bufs.length];
|
||||||
slices = new Buffer[bufs.length];
|
int off = subOffset;
|
||||||
int off = subOffset;
|
int cap = length;
|
||||||
int cap = length;
|
int i;
|
||||||
int i;
|
for (i = searchOffsets(offset); cap > 0; i++) {
|
||||||
for (i = searchOffsets(offset); cap > 0; i++) {
|
var buf = bufs[i];
|
||||||
var buf = bufs[i];
|
int avail = buf.capacity() - off;
|
||||||
int avail = buf.capacity() - off;
|
slices[i] = buf.slice(off, Math.min(cap, avail));
|
||||||
slices[i] = buf.slice(off, Math.min(cap, avail));
|
cap -= avail;
|
||||||
cap -= avail;
|
off = 0;
|
||||||
off = 0;
|
|
||||||
}
|
|
||||||
slices = Arrays.copyOf(slices, i);
|
|
||||||
} else {
|
|
||||||
// Specialize for length == 0, since we must slice from at least one constituent buffer.
|
|
||||||
slices = new Buffer[] { choice.slice(subOffset, 0) };
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CompositeBuffer(allocator, false, slices, drop, true);
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
// We called acquire prior to the try-clause. We need to undo that if we're not creating a composite buffer:
|
|
||||||
close();
|
|
||||||
throw throwable;
|
|
||||||
} finally {
|
|
||||||
if (slices != null) {
|
|
||||||
for (Buffer slice : slices) {
|
|
||||||
if (slice != null) {
|
|
||||||
slice.close(); // Ownership now transfers to the composite buffer.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
slices = Arrays.copyOf(slices, i);
|
||||||
|
} else {
|
||||||
|
// Specialize for length == 0, since we must slice from at least one constituent buffer.
|
||||||
|
slices = new Buffer[] { choice.slice(subOffset, 0) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use the constructor that skips filtering out empty buffers, and skips acquiring on the buffers.
|
||||||
|
// This is important because 1) slice() already acquired the buffers, and 2) if this slice is empty
|
||||||
|
// then we need to keep holding on to it to prevent this originating composite buffer from getting
|
||||||
|
// ownership. If it did, its behaviour would be inconsistent with that of a non-composite buffer.
|
||||||
|
return new CompositeBuffer(allocator, slices, COMPOSITE_DROP, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -749,7 +740,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
}
|
}
|
||||||
if (bufs.length == 0) {
|
if (bufs.length == 0) {
|
||||||
// Bifurcating a zero-length buffer is trivial.
|
// Bifurcating a zero-length buffer is trivial.
|
||||||
return new CompositeBuffer(allocator, true, bufs, unsafeGetDrop(), true).order(order);
|
return new CompositeBuffer(allocator, bufs, unsafeGetDrop(), true).order(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = searchOffsets(woff);
|
int i = searchOffsets(woff);
|
||||||
@ -761,7 +752,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
}
|
}
|
||||||
computeBufferOffsets();
|
computeBufferOffsets();
|
||||||
try {
|
try {
|
||||||
var compositeBuf = new CompositeBuffer(allocator, true, bifs, unsafeGetDrop(), true);
|
var compositeBuf = new CompositeBuffer(allocator, bifs, unsafeGetDrop(), true);
|
||||||
compositeBuf.order = order; // Preserve byte order even if bifs array is empty.
|
compositeBuf.order = order; // Preserve byte order even if bifs array is empty.
|
||||||
return compositeBuf;
|
return compositeBuf;
|
||||||
} finally {
|
} finally {
|
||||||
@ -1164,7 +1155,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
for (int i = 0; i < sends.length; i++) {
|
for (int i = 0; i < sends.length; i++) {
|
||||||
received[i] = sends[i].receive();
|
received[i] = sends[i].receive();
|
||||||
}
|
}
|
||||||
var composite = new CompositeBuffer(allocator, true, received, drop, true);
|
var composite = new CompositeBuffer(allocator, received, drop, true);
|
||||||
composite.readOnly = readOnly;
|
composite.readOnly = readOnly;
|
||||||
drop.attach(composite);
|
drop.attach(composite);
|
||||||
return composite;
|
return composite;
|
||||||
@ -1179,18 +1170,9 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
|
|||||||
closed = true;
|
closed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IllegalStateException notSendableException() {
|
|
||||||
if (!isSendable) {
|
|
||||||
return new IllegalStateException(
|
|
||||||
"Cannot send() this buffer. This buffer might be a slice of another buffer.");
|
|
||||||
}
|
|
||||||
return super.notSendableException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOwned() {
|
public boolean isOwned() {
|
||||||
return isSendable && super.isOwned() && allConstituentsAreOwned();
|
return super.isOwned() && allConstituentsAreOwned();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean allConstituentsAreOwned() {
|
private boolean allConstituentsAreOwned() {
|
||||||
|
@ -34,5 +34,6 @@ public interface MemoryManager {
|
|||||||
Buffer allocateShared(AllocatorControl allo, long size, Drop<Buffer> drop, Cleaner cleaner);
|
Buffer allocateShared(AllocatorControl allo, long size, Drop<Buffer> drop, Cleaner cleaner);
|
||||||
Drop<Buffer> drop();
|
Drop<Buffer> drop();
|
||||||
Object unwrapRecoverableMemory(Buffer buf);
|
Object unwrapRecoverableMemory(Buffer buf);
|
||||||
|
int capacityOfRecoverableMemory(Object memory);
|
||||||
Buffer recoverMemory(Object recoverableMemory, Drop<Buffer> drop);
|
Buffer recoverMemory(Object recoverableMemory, Drop<Buffer> drop);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ public abstract class RcSupport<I extends Rc<I>, T extends RcSupport<I, T>> impl
|
|||||||
@Override
|
@Override
|
||||||
public final I acquire() {
|
public final I acquire() {
|
||||||
if (acquires < 0) {
|
if (acquires < 0) {
|
||||||
throw attachTrace(new IllegalStateException("Resource is closed."));
|
throw attachTrace(new IllegalStateException("This resource is closed: " + this + '.'));
|
||||||
}
|
}
|
||||||
if (acquires == Integer.MAX_VALUE) {
|
if (acquires == Integer.MAX_VALUE) {
|
||||||
throw new IllegalStateException("Cannot acquire more references; counter would overflow.");
|
throw new IllegalStateException("Cannot acquire more references; counter would overflow.");
|
||||||
@ -98,7 +98,7 @@ public abstract class RcSupport<I extends Rc<I>, T extends RcSupport<I, T>> impl
|
|||||||
*/
|
*/
|
||||||
protected IllegalStateException notSendableException() {
|
protected IllegalStateException notSendableException() {
|
||||||
return new IllegalStateException(
|
return new IllegalStateException(
|
||||||
"Cannot send() a reference counted object with " + acquires + " outstanding acquires: " + this + '.');
|
"Cannot send() a reference counted object with " + countBorrows() + " borrows: " + this + '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -28,7 +28,7 @@ class SizeClassedMemoryPool implements BufferAllocator, AllocatorControl, Drop<B
|
|||||||
private static final VarHandle CLOSE = Statics.findVarHandle(
|
private static final VarHandle CLOSE = Statics.findVarHandle(
|
||||||
lookup(), SizeClassedMemoryPool.class, "closed", boolean.class);
|
lookup(), SizeClassedMemoryPool.class, "closed", boolean.class);
|
||||||
private final MemoryManager manager;
|
private final MemoryManager manager;
|
||||||
private final ConcurrentHashMap<Integer, ConcurrentLinkedQueue<Send<Buffer>>> pool;
|
private final ConcurrentHashMap<Integer, ConcurrentLinkedQueue<Object>> pool;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private volatile boolean closed;
|
private volatile boolean closed;
|
||||||
|
|
||||||
@ -41,9 +41,9 @@ class SizeClassedMemoryPool implements BufferAllocator, AllocatorControl, Drop<B
|
|||||||
public Buffer allocate(int size) {
|
public Buffer allocate(int size) {
|
||||||
BufferAllocator.checkSize(size);
|
BufferAllocator.checkSize(size);
|
||||||
var sizeClassPool = getSizeClassPool(size);
|
var sizeClassPool = getSizeClassPool(size);
|
||||||
Send<Buffer> send = sizeClassPool.poll();
|
Object memory = sizeClassPool.poll();
|
||||||
if (send != null) {
|
if (memory != null) {
|
||||||
return send.receive()
|
return recoverMemoryIntoBuffer(memory)
|
||||||
.reset()
|
.reset()
|
||||||
.readOnly(false)
|
.readOnly(false)
|
||||||
.fill((byte) 0)
|
.fill((byte) 0)
|
||||||
@ -71,10 +71,10 @@ class SizeClassedMemoryPool implements BufferAllocator, AllocatorControl, Drop<B
|
|||||||
if (CLOSE.compareAndSet(this, false, true)) {
|
if (CLOSE.compareAndSet(this, false, true)) {
|
||||||
var capturedExceptions = new ArrayList<Exception>(4);
|
var capturedExceptions = new ArrayList<Exception>(4);
|
||||||
pool.forEach((k, v) -> {
|
pool.forEach((k, v) -> {
|
||||||
Send<Buffer> send;
|
Object memory;
|
||||||
while ((send = v.poll()) != null) {
|
while ((memory = v.poll()) != null) {
|
||||||
try {
|
try {
|
||||||
send.receive().close();
|
dispose(recoverMemoryIntoBuffer(memory));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
capturedExceptions.add(e);
|
capturedExceptions.add(e);
|
||||||
}
|
}
|
||||||
@ -94,40 +94,47 @@ class SizeClassedMemoryPool implements BufferAllocator, AllocatorControl, Drop<B
|
|||||||
dispose(buf);
|
dispose(buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var sizeClassPool = getSizeClassPool(buf.capacity());
|
Object mem = manager.unwrapRecoverableMemory(buf);
|
||||||
sizeClassPool.offer(buf.send());
|
var sizeClassPool = getSizeClassPool(manager.capacityOfRecoverableMemory(mem));
|
||||||
|
sizeClassPool.offer(mem);
|
||||||
if (closed) {
|
if (closed) {
|
||||||
Send<Buffer> send;
|
Object memory;
|
||||||
while ((send = sizeClassPool.poll()) != null) {
|
while ((memory = sizeClassPool.poll()) != null) {
|
||||||
send.receive().close();
|
dispose(recoverMemoryIntoBuffer(memory));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SizeClassedMemoryPool";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object allocateUntethered(Buffer originator, int size) {
|
public Object allocateUntethered(Buffer originator, int size) {
|
||||||
var sizeClassPool = getSizeClassPool(size);
|
var sizeClassPool = getSizeClassPool(size);
|
||||||
Send<Buffer> send = sizeClassPool.poll();
|
Object memory = sizeClassPool.poll();
|
||||||
Buffer untetheredBuf;
|
if (memory == null) {
|
||||||
if (send != null) {
|
Buffer untetheredBuf = createBuf(size, NO_OP_DROP);
|
||||||
var transfer = (TransferSend<Buffer, Buffer>) send;
|
memory = manager.unwrapRecoverableMemory(untetheredBuf);
|
||||||
var owned = transfer.unsafeUnwrapOwned();
|
|
||||||
untetheredBuf = owned.transferOwnership(NO_OP_DROP);
|
|
||||||
} else {
|
|
||||||
untetheredBuf = createBuf(size, NO_OP_DROP);
|
|
||||||
}
|
}
|
||||||
return manager.unwrapRecoverableMemory(untetheredBuf);
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recoverMemory(Object memory) {
|
public void recoverMemory(Object memory) {
|
||||||
var drop = getDrop();
|
Buffer buf = recoverMemoryIntoBuffer(memory);
|
||||||
var buf = manager.recoverMemory(memory, drop);
|
|
||||||
drop.attach(buf);
|
|
||||||
buf.close();
|
buf.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConcurrentLinkedQueue<Send<Buffer>> getSizeClassPool(int size) {
|
private Buffer recoverMemoryIntoBuffer(Object memory) {
|
||||||
|
var drop = getDrop();
|
||||||
|
var buf = manager.recoverMemory(memory, drop);
|
||||||
|
drop.attach(buf);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConcurrentLinkedQueue<Object> getSizeClassPool(int size) {
|
||||||
return pool.computeIfAbsent(size, k -> new ConcurrentLinkedQueue<>());
|
return pool.computeIfAbsent(size, k -> new ConcurrentLinkedQueue<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,15 @@ import java.lang.ref.Cleaner;
|
|||||||
|
|
||||||
interface Statics {
|
interface Statics {
|
||||||
Cleaner CLEANER = Cleaner.create();
|
Cleaner CLEANER = Cleaner.create();
|
||||||
Drop<Buffer> NO_OP_DROP = buf -> {
|
Drop<Buffer> NO_OP_DROP = new Drop<Buffer>() {
|
||||||
|
@Override
|
||||||
|
public void drop(Buffer obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "NO_OP_DROP";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static VarHandle findVarHandle(Lookup lookup, Class<?> recv, String name, Class<?> type) {
|
static VarHandle findVarHandle(Lookup lookup, Class<?> recv, String name, Class<?> type) {
|
||||||
|
@ -19,6 +19,8 @@ import io.netty.buffer.ByteBufConvertible;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import io.netty.buffer.DuplicatedByteBuf;
|
||||||
|
import io.netty.buffer.SlicedByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.buffer.api.Buffer;
|
import io.netty.buffer.api.Buffer;
|
||||||
import io.netty.buffer.api.BufferAllocator;
|
import io.netty.buffer.api.BufferAllocator;
|
||||||
@ -957,8 +959,8 @@ public final class ByteBufAdaptor extends ByteBuf {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf readSlice(int length) {
|
public ByteBuf readSlice(int length) {
|
||||||
ByteBuf slice = readRetainedSlice(length);
|
ByteBuf slice = slice(readerIndex(), length);
|
||||||
release();
|
buffer.readerOffset(buffer.readerOffset() + length);
|
||||||
return slice;
|
return slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1411,22 +1413,18 @@ public final class ByteBufAdaptor extends ByteBuf {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf slice() {
|
public ByteBuf slice() {
|
||||||
ByteBuf slice = retainedSlice();
|
return slice(readerIndex(), readableBytes());
|
||||||
release();
|
|
||||||
return slice;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf retainedSlice() {
|
public ByteBuf retainedSlice() {
|
||||||
checkAccess();
|
return retainedSlice(readerIndex(), readableBytes());
|
||||||
return wrap(buffer.slice());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf slice(int index, int length) {
|
public ByteBuf slice(int index, int length) {
|
||||||
ByteBuf slice = retainedSlice(index, length);
|
checkAccess();
|
||||||
release();
|
return new Slice(this, index, length);
|
||||||
return slice;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1439,11 +1437,55 @@ public final class ByteBufAdaptor extends ByteBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuf retainedDuplicate() {
|
||||||
|
return unwrap().retainedDuplicate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuf retainedSlice(int index, int length) {
|
||||||
|
return unwrap().retainedSlice(index, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuf duplicate() {
|
public ByteBuf duplicate() {
|
||||||
ByteBuf duplicate = retainedDuplicate();
|
checkAccess();
|
||||||
release();
|
Duplicate duplicatedByteBuf = new Duplicate(this);
|
||||||
return duplicate;
|
return duplicatedByteBuf.setIndex(readerIndex(), writerIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -34,7 +34,7 @@ public abstract class AbstractMemorySegmentManager implements MemoryManager {
|
|||||||
if (cleaner != null) {
|
if (cleaner != null) {
|
||||||
segment = segment.registerCleaner(cleaner);
|
segment = segment.registerCleaner(cleaner);
|
||||||
}
|
}
|
||||||
return new MemSegBuffer(segment, convert(drop), alloc);
|
return new MemSegBuffer(segment, segment, convert(drop), alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -43,7 +43,7 @@ public abstract class AbstractMemorySegmentManager implements MemoryManager {
|
|||||||
if (cleaner != null) {
|
if (cleaner != null) {
|
||||||
segment = segment.registerCleaner(cleaner);
|
segment = segment.registerCleaner(cleaner);
|
||||||
}
|
}
|
||||||
return new MemSegBuffer(segment, convert(drop), alloc);
|
return new MemSegBuffer(segment, segment, convert(drop), alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract MemorySegment createSegment(long size);
|
protected abstract MemorySegment createSegment(long size);
|
||||||
@ -59,6 +59,11 @@ public abstract class AbstractMemorySegmentManager implements MemoryManager {
|
|||||||
return b.recoverableMemory();
|
return b.recoverableMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int capacityOfRecoverableMemory(Object memory) {
|
||||||
|
return ((RecoverableMemory) memory).capacity();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Buffer recoverMemory(Object recoverableMemory, Drop<Buffer> drop) {
|
public Buffer recoverMemory(Object recoverableMemory, Drop<Buffer> drop) {
|
||||||
var recovery = (RecoverableMemory) recoverableMemory;
|
var recovery = (RecoverableMemory) recoverableMemory;
|
||||||
|
@ -20,33 +20,47 @@ import io.netty.buffer.api.Drop;
|
|||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
|
|
||||||
class BifurcatedDrop implements Drop<MemSegBuffer> {
|
final class ArcDrop implements Drop<MemSegBuffer> {
|
||||||
private static final VarHandle COUNT;
|
private static final VarHandle COUNT;
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
COUNT = MethodHandles.lookup().findVarHandle(BifurcatedDrop.class, "count", int.class);
|
COUNT = MethodHandles.lookup().findVarHandle(ArcDrop.class, "count", int.class);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ExceptionInInitializerError(e);
|
throw new ExceptionInInitializerError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final MemSegBuffer originalBuf;
|
|
||||||
private final Drop<MemSegBuffer> delegate;
|
private final Drop<MemSegBuffer> delegate;
|
||||||
@SuppressWarnings("FieldMayBeFinal")
|
@SuppressWarnings("FieldMayBeFinal")
|
||||||
private volatile int count;
|
private volatile int count;
|
||||||
|
|
||||||
BifurcatedDrop(MemSegBuffer originalBuf, Drop<MemSegBuffer> delegate) {
|
ArcDrop(Drop<MemSegBuffer> delegate) {
|
||||||
this.originalBuf = originalBuf;
|
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
count = 2; // These are created by buffer bifurcation, so we initially have 2 references to this drop.
|
count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void increment() {
|
static Drop<MemSegBuffer> wrap(Drop<MemSegBuffer> drop) {
|
||||||
|
if (drop.getClass() == ArcDrop.class) {
|
||||||
|
return drop;
|
||||||
|
}
|
||||||
|
return new ArcDrop(drop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Drop<MemSegBuffer> acquire(Drop<MemSegBuffer> drop) {
|
||||||
|
if (drop.getClass() == ArcDrop.class) {
|
||||||
|
((ArcDrop) drop).increment();
|
||||||
|
return drop;
|
||||||
|
}
|
||||||
|
return new ArcDrop(drop);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArcDrop increment() {
|
||||||
int c;
|
int c;
|
||||||
do {
|
do {
|
||||||
c = count;
|
c = count;
|
||||||
checkValidState(c);
|
checkValidState(c);
|
||||||
} while (!COUNT.compareAndSet(this, c, c + 1));
|
} while (!COUNT.compareAndSet(this, c, c + 1));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -59,10 +73,8 @@ class BifurcatedDrop implements Drop<MemSegBuffer> {
|
|||||||
checkValidState(c);
|
checkValidState(c);
|
||||||
} while (!COUNT.compareAndSet(this, c, n));
|
} while (!COUNT.compareAndSet(this, c, n));
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
delegate.attach(originalBuf);
|
delegate.drop(buf);
|
||||||
delegate.drop(originalBuf);
|
|
||||||
}
|
}
|
||||||
buf.makeInaccessible();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,10 +82,28 @@ class BifurcatedDrop implements Drop<MemSegBuffer> {
|
|||||||
delegate.attach(obj);
|
delegate.attach(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isOwned() {
|
||||||
|
return count <= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int countBorrows() {
|
||||||
|
return count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
Drop<MemSegBuffer> unwrap() {
|
Drop<MemSegBuffer> unwrap() {
|
||||||
return delegate;
|
return delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder().append("ArcDrop(").append(count).append(", ");
|
||||||
|
Drop<MemSegBuffer> 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) {
|
private static void checkValidState(int count) {
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
throw new IllegalStateException("Underlying resources have already been freed.");
|
throw new IllegalStateException("Underlying resources have already been freed.");
|
@ -15,8 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.buffer.api.memseg;
|
package io.netty.buffer.api.memseg;
|
||||||
|
|
||||||
import io.netty.buffer.api.Buffer;
|
|
||||||
import io.netty.buffer.api.Drop;
|
|
||||||
import jdk.incubator.foreign.MemorySegment;
|
import jdk.incubator.foreign.MemorySegment;
|
||||||
|
|
||||||
public class HeapMemorySegmentManager extends AbstractMemorySegmentManager {
|
public class HeapMemorySegmentManager extends AbstractMemorySegmentManager {
|
||||||
@ -29,15 +27,4 @@ public class HeapMemorySegmentManager extends AbstractMemorySegmentManager {
|
|||||||
protected MemorySegment createSegment(long size) {
|
protected MemorySegment createSegment(long size) {
|
||||||
return MemorySegment.ofArray(new byte[Math.toIntExact(size)]);
|
return MemorySegment.ofArray(new byte[Math.toIntExact(size)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Drop<Buffer> drop() {
|
|
||||||
return convert(buf -> buf.makeInaccessible());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "UnnecessaryLocalVariable" })
|
|
||||||
private static Drop<Buffer> convert(Drop<MemSegBuffer> drop) {
|
|
||||||
Drop<?> tmp = drop;
|
|
||||||
return (Drop<Buffer>) tmp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -58,32 +58,72 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
static {
|
static {
|
||||||
CLOSED_SEGMENT = MemorySegment.ofArray(new byte[0]);
|
CLOSED_SEGMENT = MemorySegment.ofArray(new byte[0]);
|
||||||
CLOSED_SEGMENT.close();
|
CLOSED_SEGMENT.close();
|
||||||
SEGMENT_CLOSE = buf -> {
|
SEGMENT_CLOSE = new Drop<MemSegBuffer>() {
|
||||||
try (var ignore = buf.seg) {
|
@Override
|
||||||
buf.makeInaccessible();
|
public void drop(MemSegBuffer buf) {
|
||||||
|
buf.base.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SEGMENT_CLOSE";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private final AllocatorControl alloc;
|
private final AllocatorControl alloc;
|
||||||
private final boolean isSendable;
|
private MemorySegment base;
|
||||||
private MemorySegment seg;
|
private MemorySegment seg;
|
||||||
private MemorySegment wseg;
|
private MemorySegment wseg;
|
||||||
private ByteOrder order;
|
private ByteOrder order;
|
||||||
private int roff;
|
private int roff;
|
||||||
private int woff;
|
private int woff;
|
||||||
|
|
||||||
MemSegBuffer(MemorySegment segmet, Drop<MemSegBuffer> drop, AllocatorControl alloc) {
|
MemSegBuffer(MemorySegment base, MemorySegment view, Drop<MemSegBuffer> drop, AllocatorControl alloc) {
|
||||||
this(segmet, drop, alloc, true);
|
super(new MakeInaccisbleOnDrop(ArcDrop.wrap(drop)));
|
||||||
|
this.alloc = alloc;
|
||||||
|
this.base = base;
|
||||||
|
seg = view;
|
||||||
|
wseg = view;
|
||||||
|
order = ByteOrder.nativeOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MemSegBuffer(MemorySegment segment, Drop<MemSegBuffer> drop, AllocatorControl alloc, boolean isSendable) {
|
private static final class MakeInaccisbleOnDrop implements Drop<MemSegBuffer> {
|
||||||
super(drop);
|
final Drop<MemSegBuffer> delegate;
|
||||||
this.alloc = alloc;
|
|
||||||
seg = segment;
|
private MakeInaccisbleOnDrop(Drop<MemSegBuffer> delegate) {
|
||||||
wseg = segment;
|
this.delegate = delegate;
|
||||||
this.isSendable = isSendable;
|
}
|
||||||
order = ByteOrder.nativeOrder();
|
|
||||||
|
@Override
|
||||||
|
public void drop(MemSegBuffer buf) {
|
||||||
|
try {
|
||||||
|
delegate.drop(buf);
|
||||||
|
} finally {
|
||||||
|
buf.makeInaccessible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attach(MemSegBuffer buf) {
|
||||||
|
delegate.attach(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "MemSegDrop(" + delegate + ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Drop<MemSegBuffer> unsafeGetDrop() {
|
||||||
|
MakeInaccisbleOnDrop drop = (MakeInaccisbleOnDrop) super.unsafeGetDrop();
|
||||||
|
return drop.delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void unsafeSetDrop(Drop<MemSegBuffer> replacement) {
|
||||||
|
super.unsafeSetDrop(new MakeInaccisbleOnDrop(replacement));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -233,14 +273,12 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
throw new IllegalArgumentException("Length cannot be negative: " + length + '.');
|
throw new IllegalArgumentException("Length cannot be negative: " + length + '.');
|
||||||
}
|
}
|
||||||
|
if (!isAccessible()) {
|
||||||
|
throw new IllegalStateException("This buffer is closed: " + this + '.');
|
||||||
|
}
|
||||||
var slice = seg.asSlice(offset, length);
|
var slice = seg.asSlice(offset, length);
|
||||||
acquire();
|
Drop<MemSegBuffer> drop = ArcDrop.acquire(unsafeGetDrop());
|
||||||
Drop<MemSegBuffer> drop = b -> {
|
return new MemSegBuffer(base, slice, drop, alloc)
|
||||||
close();
|
|
||||||
b.makeInaccessible();
|
|
||||||
};
|
|
||||||
var sendable = false; // Sending implies ownership change, which we can't do for slices.
|
|
||||||
return new MemSegBuffer(slice, drop, alloc, sendable)
|
|
||||||
.writerOffset(length)
|
.writerOffset(length)
|
||||||
.order(order())
|
.order(order())
|
||||||
.readOnly(readOnly());
|
.readOnly(readOnly());
|
||||||
@ -482,19 +520,22 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
|
|
||||||
// Release old memory segment:
|
// Release old memory segment:
|
||||||
var drop = unsafeGetDrop();
|
var drop = unsafeGetDrop();
|
||||||
if (drop instanceof BifurcatedDrop) {
|
if (drop instanceof ArcDrop) {
|
||||||
// Disconnect from the bifurcated drop, since we'll get our own fresh memory segment.
|
// Disconnect from the current arc drop, since we'll get our own fresh memory segment.
|
||||||
int roff = this.roff;
|
int roff = this.roff;
|
||||||
int woff = this.woff;
|
int woff = this.woff;
|
||||||
drop.drop(this);
|
drop.drop(this);
|
||||||
drop = ((BifurcatedDrop) drop).unwrap();
|
while (drop instanceof ArcDrop) {
|
||||||
unsafeSetDrop(drop);
|
drop = ((ArcDrop) drop).unwrap();
|
||||||
|
}
|
||||||
|
unsafeSetDrop(new ArcDrop(drop));
|
||||||
this.roff = roff;
|
this.roff = roff;
|
||||||
this.woff = woff;
|
this.woff = woff;
|
||||||
} else {
|
} else {
|
||||||
alloc.recoverMemory(recoverableMemory());
|
alloc.recoverMemory(recoverableMemory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base = newSegment;
|
||||||
seg = newSegment;
|
seg = newSegment;
|
||||||
wseg = newSegment;
|
wseg = newSegment;
|
||||||
drop.attach(this);
|
drop.attach(this);
|
||||||
@ -505,19 +546,10 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
if (!isOwned()) {
|
if (!isOwned()) {
|
||||||
throw attachTrace(new IllegalStateException("Cannot bifurcate a buffer that is not owned."));
|
throw attachTrace(new IllegalStateException("Cannot bifurcate a buffer that is not owned."));
|
||||||
}
|
}
|
||||||
var drop = unsafeGetDrop();
|
var drop = (ArcDrop) unsafeGetDrop();
|
||||||
if (seg.ownerThread() != null) {
|
unsafeSetDrop(new ArcDrop(drop));
|
||||||
seg = seg.share();
|
|
||||||
drop.attach(this);
|
|
||||||
}
|
|
||||||
if (drop instanceof BifurcatedDrop) {
|
|
||||||
((BifurcatedDrop) drop).increment();
|
|
||||||
} else {
|
|
||||||
drop = new BifurcatedDrop(new MemSegBuffer(seg, drop, alloc), drop);
|
|
||||||
unsafeSetDrop(drop);
|
|
||||||
}
|
|
||||||
var bifurcatedSeg = seg.asSlice(0, woff);
|
var bifurcatedSeg = seg.asSlice(0, woff);
|
||||||
var bifurcatedBuf = new MemSegBuffer(bifurcatedSeg, drop, alloc);
|
var bifurcatedBuf = new MemSegBuffer(base, bifurcatedSeg, new ArcDrop(drop.increment()), alloc);
|
||||||
bifurcatedBuf.woff = woff;
|
bifurcatedBuf.woff = woff;
|
||||||
bifurcatedBuf.roff = roff;
|
bifurcatedBuf.roff = roff;
|
||||||
bifurcatedBuf.order(order);
|
bifurcatedBuf.order(order);
|
||||||
@ -1052,11 +1084,12 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
var readOnly = readOnly();
|
var readOnly = readOnly();
|
||||||
boolean isConfined = seg.ownerThread() == null;
|
boolean isConfined = seg.ownerThread() == null;
|
||||||
MemorySegment transferSegment = isConfined? seg : seg.share();
|
MemorySegment transferSegment = isConfined? seg : seg.share();
|
||||||
|
MemorySegment base = this.base;
|
||||||
makeInaccessible();
|
makeInaccessible();
|
||||||
return new Owned<MemSegBuffer>() {
|
return new Owned<MemSegBuffer>() {
|
||||||
@Override
|
@Override
|
||||||
public MemSegBuffer transferOwnership(Drop<MemSegBuffer> drop) {
|
public MemSegBuffer transferOwnership(Drop<MemSegBuffer> drop) {
|
||||||
MemSegBuffer copy = new MemSegBuffer(transferSegment, drop, alloc);
|
MemSegBuffer copy = new MemSegBuffer(base, transferSegment, drop, alloc);
|
||||||
copy.order = order;
|
copy.order = order;
|
||||||
copy.roff = roff;
|
copy.roff = roff;
|
||||||
copy.woff = woff;
|
copy.woff = woff;
|
||||||
@ -1067,6 +1100,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
void makeInaccessible() {
|
void makeInaccessible() {
|
||||||
|
base = CLOSED_SEGMENT;
|
||||||
seg = CLOSED_SEGMENT;
|
seg = CLOSED_SEGMENT;
|
||||||
wseg = CLOSED_SEGMENT;
|
wseg = CLOSED_SEGMENT;
|
||||||
roff = 0;
|
roff = 0;
|
||||||
@ -1074,17 +1108,13 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IllegalStateException notSendableException() {
|
public boolean isOwned() {
|
||||||
if (!isSendable) {
|
return super.isOwned() && ((ArcDrop) unsafeGetDrop()).isOwned();
|
||||||
return new IllegalStateException(
|
|
||||||
"Cannot send() this buffer. This buffer might be a slice of another buffer.");
|
|
||||||
}
|
|
||||||
return super.notSendableException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOwned() {
|
public int countBorrows() {
|
||||||
return isSendable && super.isOwned();
|
return super.countBorrows() + ((ArcDrop) unsafeGetDrop()).countBorrows();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkRead(int index, int size) {
|
private void checkRead(int index, int size) {
|
||||||
@ -1153,7 +1183,7 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object recoverableMemory() {
|
Object recoverableMemory() {
|
||||||
return new RecoverableMemory(seg, alloc);
|
return new RecoverableMemory(base, alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// <editor-fold name="BufferIntegratable methods">
|
// <editor-fold name="BufferIntegratable methods">
|
||||||
@ -1226,7 +1256,11 @@ class MemSegBuffer extends RcSupport<Buffer, MemSegBuffer> implements Buffer, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
Buffer recover(Drop<MemSegBuffer> drop) {
|
Buffer recover(Drop<MemSegBuffer> drop) {
|
||||||
return new MemSegBuffer(segment, drop, alloc);
|
return new MemSegBuffer(segment, segment, ArcDrop.acquire(drop), alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int capacity() {
|
||||||
|
return (int) segment.byteSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,8 +63,6 @@ public class BufferTest {
|
|||||||
|
|
||||||
private static final Memoize<Fixture[]> ALL_COMBINATIONS = new Memoize<>(
|
private static final Memoize<Fixture[]> ALL_COMBINATIONS = new Memoize<>(
|
||||||
() -> fixtureCombinations().toArray(Fixture[]::new));
|
() -> fixtureCombinations().toArray(Fixture[]::new));
|
||||||
private static final Memoize<Fixture[]> NON_SLICED = new Memoize<>(
|
|
||||||
() -> Arrays.stream(ALL_COMBINATIONS.get()).filter(f -> !f.isSlice()).toArray(Fixture[]::new));
|
|
||||||
private static final Memoize<Fixture[]> NON_COMPOSITE = new Memoize<>(
|
private static final Memoize<Fixture[]> NON_COMPOSITE = new Memoize<>(
|
||||||
() -> Arrays.stream(ALL_COMBINATIONS.get()).filter(f -> !f.isComposite()).toArray(Fixture[]::new));
|
() -> Arrays.stream(ALL_COMBINATIONS.get()).filter(f -> !f.isComposite()).toArray(Fixture[]::new));
|
||||||
private static final Memoize<Fixture[]> HEAP_ALLOCS = new Memoize<>(
|
private static final Memoize<Fixture[]> HEAP_ALLOCS = new Memoize<>(
|
||||||
@ -78,10 +76,6 @@ public class BufferTest {
|
|||||||
return ALL_COMBINATIONS.get();
|
return ALL_COMBINATIONS.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Fixture[] nonSliceAllocators() {
|
|
||||||
return NON_SLICED.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
static Fixture[] nonCompositeAllocators() {
|
static Fixture[] nonCompositeAllocators() {
|
||||||
return NON_COMPOSITE.get();
|
return NON_COMPOSITE.get();
|
||||||
}
|
}
|
||||||
@ -349,7 +343,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
void allocateAndSendToThread(Fixture fixture) throws Exception {
|
void allocateAndSendToThread(Fixture fixture) throws Exception {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator()) {
|
try (BufferAllocator allocator = fixture.createAllocator()) {
|
||||||
ArrayBlockingQueue<Send<Buffer>> queue = new ArrayBlockingQueue<>(10);
|
ArrayBlockingQueue<Send<Buffer>> queue = new ArrayBlockingQueue<>(10);
|
||||||
@ -369,7 +363,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
void allocateAndSendToThreadViaSyncQueue(Fixture fixture) throws Exception {
|
void allocateAndSendToThreadViaSyncQueue(Fixture fixture) throws Exception {
|
||||||
SynchronousQueue<Send<Buffer>> queue = new SynchronousQueue<>();
|
SynchronousQueue<Send<Buffer>> queue = new SynchronousQueue<>();
|
||||||
Future<Byte> future = executor.submit(() -> {
|
Future<Byte> future = executor.submit(() -> {
|
||||||
@ -388,7 +382,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
void sendMustThrowWhenBufIsAcquired(Fixture fixture) {
|
void sendMustThrowWhenBufIsAcquired(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -403,7 +397,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void originalBufferMustNotBeAccessibleAfterSend(Fixture fixture) {
|
public void originalBufferMustNotBeAccessibleAfterSend(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer orig = allocator.allocate(24)) {
|
Buffer orig = allocator.allocate(24)) {
|
||||||
@ -505,7 +499,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void cannotSendMoreThanOnce(Fixture fixture) {
|
public void cannotSendMoreThanOnce(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -822,7 +816,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
void sendOnSliceWithoutOffsetAndSizeMustThrow(Fixture fixture) {
|
void sendOnSliceWithoutOffsetAndSizeMustThrow(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -837,7 +831,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
void sendOnSliceWithOffsetAndSizeMustThrow(Fixture fixture) {
|
void sendOnSliceWithOffsetAndSizeMustThrow(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -926,6 +920,51 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("nonCompositeAllocators")
|
||||||
|
public void acquireComposingAndSlicingMustIncrementBorrowsWithData(Fixture fixture) {
|
||||||
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
|
Buffer buf = allocator.allocate(8)) {
|
||||||
|
buf.writeByte((byte) 1);
|
||||||
|
int borrows = buf.countBorrows();
|
||||||
|
try (Buffer ignored = buf.acquire()) {
|
||||||
|
assertEquals(borrows + 1, buf.countBorrows());
|
||||||
|
try (Buffer slice = buf.slice()) {
|
||||||
|
assertEquals(1, slice.capacity());
|
||||||
|
int sliceBorrows = slice.countBorrows();
|
||||||
|
assertEquals(borrows + 2, buf.countBorrows());
|
||||||
|
try (Buffer ignored1 = Buffer.compose(allocator, buf, slice)) {
|
||||||
|
assertEquals(borrows + 3, buf.countBorrows());
|
||||||
|
assertEquals(sliceBorrows + 1, slice.countBorrows());
|
||||||
|
}
|
||||||
|
assertEquals(sliceBorrows, slice.countBorrows());
|
||||||
|
assertEquals(borrows + 2, buf.countBorrows());
|
||||||
|
}
|
||||||
|
assertEquals(borrows + 1, buf.countBorrows());
|
||||||
|
}
|
||||||
|
assertEquals(borrows, buf.countBorrows());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("allocators")
|
||||||
|
public void sliceMustBecomeOwnedOnSourceBufferClose(Fixture fixture) {
|
||||||
|
try (BufferAllocator allocator = fixture.createAllocator()) {
|
||||||
|
Buffer buf = allocator.allocate(8);
|
||||||
|
buf.writeInt(42);
|
||||||
|
try (Buffer slice = buf.slice()) {
|
||||||
|
buf.close();
|
||||||
|
assertFalse(buf.isAccessible());
|
||||||
|
assertTrue(slice.isOwned());
|
||||||
|
try (Buffer receive = slice.send().receive()) {
|
||||||
|
assertTrue(receive.isOwned());
|
||||||
|
assertFalse(slice.isAccessible());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("allocators")
|
@MethodSource("allocators")
|
||||||
void copyIntoByteArray(Fixture fixture) {
|
void copyIntoByteArray(Fixture fixture) {
|
||||||
@ -1737,7 +1776,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableMustThrowForNegativeSize(Fixture fixture) {
|
public void ensureWritableMustThrowForNegativeSize(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -1746,7 +1785,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableMustThrowIfRequestedSizeWouldGrowBeyondMaxAllowed(Fixture fixture) {
|
public void ensureWritableMustThrowIfRequestedSizeWouldGrowBeyondMaxAllowed(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(512)) {
|
Buffer buf = allocator.allocate(512)) {
|
||||||
@ -1755,7 +1794,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableMustNotThrowWhenSpaceIsAlreadyAvailable(Fixture fixture) {
|
public void ensureWritableMustNotThrowWhenSpaceIsAlreadyAvailable(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -1766,7 +1805,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableMustExpandBufferCapacity(Fixture fixture) {
|
public void ensureWritableMustExpandBufferCapacity(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -1801,7 +1840,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void mustBeAbleToSliceAfterEnsureWritable(Fixture fixture) {
|
public void mustBeAbleToSliceAfterEnsureWritable(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(4)) {
|
Buffer buf = allocator.allocate(4)) {
|
||||||
@ -1816,7 +1855,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableOnCompositeBuffersMustRespectExistingBigEndianByteOrder(Fixture fixture) {
|
public void ensureWritableOnCompositeBuffersMustRespectExistingBigEndianByteOrder(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator()) {
|
try (BufferAllocator allocator = fixture.createAllocator()) {
|
||||||
Buffer composite;
|
Buffer composite;
|
||||||
@ -1833,7 +1872,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableOnCompositeBuffersMustRespectExistingLittleEndianByteOrder(Fixture fixture) {
|
public void ensureWritableOnCompositeBuffersMustRespectExistingLittleEndianByteOrder(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator()) {
|
try (BufferAllocator allocator = fixture.createAllocator()) {
|
||||||
Buffer composite;
|
Buffer composite;
|
||||||
@ -1850,7 +1889,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableWithCompactionMustNotAllocateIfCompactionIsEnough(Fixture fixture) {
|
public void ensureWritableWithCompactionMustNotAllocateIfCompactionIsEnough(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(64)) {
|
Buffer buf = allocator.allocate(64)) {
|
||||||
@ -2175,7 +2214,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void bifurcateOfNonOwnedBufferMustThrow(Fixture fixture) {
|
public void bifurcateOfNonOwnedBufferMustThrow(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -2188,7 +2227,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void bifurcatedPartMustContainFirstHalfOfBuffer(Fixture fixture) {
|
public void bifurcatedPartMustContainFirstHalfOfBuffer(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(16).order(BIG_ENDIAN)) {
|
Buffer buf = allocator.allocate(16).order(BIG_ENDIAN)) {
|
||||||
@ -2224,7 +2263,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void bifurcatedPartsMustBeIndividuallySendable(Fixture fixture) {
|
public void bifurcatedPartsMustBeIndividuallySendable(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(16).order(BIG_ENDIAN)) {
|
Buffer buf = allocator.allocate(16).order(BIG_ENDIAN)) {
|
||||||
@ -2253,7 +2292,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void mustBePossibleToBifurcateMoreThanOnce(Fixture fixture) {
|
public void mustBePossibleToBifurcateMoreThanOnce(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(16).order(BIG_ENDIAN)) {
|
Buffer buf = allocator.allocate(16).order(BIG_ENDIAN)) {
|
||||||
@ -2281,7 +2320,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void bifurcatedBufferMustHaveSameByteOrderAsParent(Fixture fixture) {
|
public void bifurcatedBufferMustHaveSameByteOrderAsParent(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8).order(BIG_ENDIAN)) {
|
Buffer buf = allocator.allocate(8).order(BIG_ENDIAN)) {
|
||||||
@ -2299,7 +2338,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableOnBifurcatedBuffers(Fixture fixture) {
|
public void ensureWritableOnBifurcatedBuffers(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -2318,7 +2357,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableOnBifurcatedBuffersWithOddOffsets(Fixture fixture) {
|
public void ensureWritableOnBifurcatedBuffersWithOddOffsets(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(10).order(BIG_ENDIAN)) {
|
Buffer buf = allocator.allocate(10).order(BIG_ENDIAN)) {
|
||||||
@ -2367,7 +2406,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void bifurcatedBuffersMustBeAccessibleInOtherThreads(Fixture fixture) throws Exception {
|
public void bifurcatedBuffersMustBeAccessibleInOtherThreads(Fixture fixture) throws Exception {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -2387,7 +2426,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void sendMustNotMakeBifurcatedBuffersInaccessible(Fixture fixture) throws Exception {
|
public void sendMustNotMakeBifurcatedBuffersInaccessible(Fixture fixture) throws Exception {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(16)) {
|
Buffer buf = allocator.allocate(16)) {
|
||||||
@ -2411,7 +2450,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void compactMustDiscardReadBytes(Fixture fixture) {
|
public void compactMustDiscardReadBytes(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(16, BIG_ENDIAN)) {
|
Buffer buf = allocator.allocate(16, BIG_ENDIAN)) {
|
||||||
@ -2433,7 +2472,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void compactMustThrowForUnownedBuffer(Fixture fixture) {
|
public void compactMustThrowForUnownedBuffer(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8, BIG_ENDIAN)) {
|
Buffer buf = allocator.allocate(8, BIG_ENDIAN)) {
|
||||||
@ -2548,7 +2587,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void readOnlyBufferMustRemainReadOnlyAfterSend(Fixture fixture) {
|
public void readOnlyBufferMustRemainReadOnlyAfterSend(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -2613,7 +2652,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void bifurcateOfReadOnlyBufferMustBeReadOnly(Fixture fixture) {
|
public void bifurcateOfReadOnlyBufferMustBeReadOnly(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(16)) {
|
Buffer buf = allocator.allocate(16)) {
|
||||||
@ -2665,7 +2704,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void compactOnReadOnlyBufferMustThrow(Fixture fixture) {
|
public void compactOnReadOnlyBufferMustThrow(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -2675,7 +2714,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void ensureWritableOnReadOnlyBufferMustThrow(Fixture fixture) {
|
public void ensureWritableOnReadOnlyBufferMustThrow(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer buf = allocator.allocate(8)) {
|
Buffer buf = allocator.allocate(8)) {
|
||||||
@ -2685,7 +2724,7 @@ public class BufferTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("nonSliceAllocators")
|
@MethodSource("allocators")
|
||||||
public void copyIntoOnReadOnlyBufferMustThrow(Fixture fixture) {
|
public void copyIntoOnReadOnlyBufferMustThrow(Fixture fixture) {
|
||||||
try (BufferAllocator allocator = fixture.createAllocator();
|
try (BufferAllocator allocator = fixture.createAllocator();
|
||||||
Buffer dest = allocator.allocate(8)) {
|
Buffer dest = allocator.allocate(8)) {
|
||||||
|
@ -39,36 +39,6 @@ public class ByteBufAdaptorTest extends AbstractByteBufTest {
|
|||||||
return alloc.buffer(capacity, capacity);
|
return alloc.buffer(capacity, capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("New buffers not thread-safe like this.")
|
|
||||||
@Override
|
|
||||||
public void testSliceReadGatheringByteChannelMultipleThreads() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("New buffers not thread-safe like this.")
|
|
||||||
@Override
|
|
||||||
public void testDuplicateReadGatheringByteChannelMultipleThreads() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("New buffers not thread-safe like this.")
|
|
||||||
@Override
|
|
||||||
public void testSliceReadOutputStreamMultipleThreads() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("New buffers not thread-safe like this.")
|
|
||||||
@Override
|
|
||||||
public void testDuplicateReadOutputStreamMultipleThreads() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("New buffers not thread-safe like this.")
|
|
||||||
@Override
|
|
||||||
public void testSliceBytesInArrayMultipleThreads() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("New buffers not thread-safe like this.")
|
|
||||||
@Override
|
|
||||||
public void testDuplicateBytesInArrayMultipleThreads() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This test codifies that asking to reading 0 bytes from an empty but unclosed stream should return -1, " +
|
@Ignore("This test codifies that asking to reading 0 bytes from an empty but unclosed stream should return -1, " +
|
||||||
"which is just weird.")
|
"which is just weird.")
|
||||||
@Override
|
@Override
|
||||||
@ -112,152 +82,8 @@ public class ByteBufAdaptorTest extends AbstractByteBufTest {
|
|||||||
public void testToByteBuffer2() {
|
public void testToByteBuffer2() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedDuplicateUnreleasable3() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedDuplicateUnreleasable4() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedDuplicateAndRetainedSliceContentIsExpected() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testMultipleRetainedSliceReleaseOriginal2() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testMultipleRetainedSliceReleaseOriginal3() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testMultipleRetainedSliceReleaseOriginal4() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testReadRetainedSliceUnreleasable3() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testReadRetainedSliceUnreleasable4() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedSliceUnreleasable3() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedSliceUnreleasable4() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedSliceReleaseOriginal2() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedSliceReleaseOriginal3() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedSliceReleaseOriginal4() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testMultipleRetainedDuplicateReleaseOriginal2() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testMultipleRetainedDuplicateReleaseOriginal3() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testMultipleRetainedDuplicateReleaseOriginal4() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedDuplicateReleaseOriginal2() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedDuplicateReleaseOriginal3() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("This assumes a single reference count for the memory, but all buffers (views of memory) have " +
|
|
||||||
"independent reference counts now. Also, this plays tricks with reference that we cannot support.")
|
|
||||||
@Override
|
|
||||||
public void testRetainedDuplicateReleaseOriginal4() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("No longer allowed to allocate 0 sized buffers, except for composite buffers with no components.")
|
@Ignore("No longer allowed to allocate 0 sized buffers, except for composite buffers with no components.")
|
||||||
@Override
|
@Override
|
||||||
public void testLittleEndianWithExpand() {
|
public void testLittleEndianWithExpand() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("Test seems to inherently have double-free bug?")
|
|
||||||
@Override
|
|
||||||
public void testRetainedSliceAfterReleaseRetainedSliceDuplicate() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Test seems to inherently have double-free bug?")
|
|
||||||
@Override
|
|
||||||
public void testRetainedSliceAfterReleaseRetainedDuplicateSlice() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Test seems to inherently have double-free bug?")
|
|
||||||
@Override
|
|
||||||
public void testSliceAfterReleaseRetainedSliceDuplicate() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Test seems to inherently have double-free bug?")
|
|
||||||
@Override
|
|
||||||
public void testDuplicateAfterReleaseRetainedSliceDuplicate() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Test seems to inherently have double-free bug?")
|
|
||||||
@Override
|
|
||||||
public void testDuplicateAfterReleaseRetainedDuplicateSlice() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Test seems to inherently have double-free bug?")
|
|
||||||
@Override
|
|
||||||
public void testSliceAfterReleaseRetainedDuplicateSlice() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user