netty-incubator-buffer-api/buffer-memseg/src/main/java/io/netty/buffer/api/memseg/AbstractMemorySegmentManage...

82 lines
2.8 KiB
Java
Raw Normal View History

/*
* 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<Buffer> 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<Buffer> drop() {
return Statics.convert(MemSegBuffer.SEGMENT_CLOSE);
}
@Override
public Object unwrapRecoverableMemory(Buffer buf) {
var b = (MemSegBuffer) buf;
return b.recoverableMemory();
}
Allow slices to obtain ownership when parent is closed Motivation: It is kind of a weird internal and hidden state, that slices were special. For instance, slices could not be sent, and they could never obtain ownership. This means buffers from slices behaved differently from allocated buffers. In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour. Modification: - The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting). - The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like. - Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop. - Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state. - SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices. - We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice). - CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with. - The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point. - MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice. Result: It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
@Override
public int capacityOfRecoverableMemory(Object memory) {
return (int) ((MemorySegment) memory).byteSize();
Allow slices to obtain ownership when parent is closed Motivation: It is kind of a weird internal and hidden state, that slices were special. For instance, slices could not be sent, and they could never obtain ownership. This means buffers from slices behaved differently from allocated buffers. In doing so, they violated both the principle that magic should stay hidden, and the principle of consistent behaviour. Modification: - The special reference-counting drop implementation that was added to support bifurcation, has been renamed to ArcDrop (for atomic reference counting). - The ArcDrop is then used throughout the MemSegBuffer implementation to account for every instance where multiple buffers reference the same memory, e.g. slices and the like. - Borrows of a buffer is then the sum of borrows from the buffer itself, and its ArcDrop. - Ownership is thus tied to both the buffer itself being owned, and the ArcDrop being in an owned state. - SizeClassedMemoryPool is changed to pool recoverable memory instead of sends, because the sends could come from slices. - We also take care to keep around a "base" memory segment, so that we don't return memory segment slices to the memory pool (doing so would leak the memory from the parent segment that is not part of the slice). - CleanerPooledDrop now keeps a weak reference to itself, rather than the buffer, which is more correct anyway, but now also required because we cannot rely on the buffer reference the cleaner was created with. - The CleanerPooledDrop now takes care to drop the buffer that is actually passed to it, rather than what it was referencing from some earlier point. - MemoryManager can now disclose the size of recoverable memory, so that SizeClassedMemoryPool can pick the correct size pool to return memory to. It cannot rely on the passed down buffer instance for this, because that buffer might have been a slice. Result: It is now possible for slices to obtain ownership when their parent buffer is closed.
2021-03-15 16:42:56 +01:00
}
@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<Buffer> 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);
}
}