Files
KLALB/src/org/kne/cloud/network/BufferedArena.java
T
2025-11-15 11:08:16 +08:00

178 lines
4.2 KiB
Java

package org.kne.cloud.network;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySegment.Scope;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
public class BufferedArena implements Arena{
private static long blockSize=10*1024L*1024L;
private volatile PreAlloc buffer;
private static ReferenceQueue<MemorySegment> refq=new ReferenceQueue<>();
private static MemorySegmentPool msp=new MemorySegmentPool(1000, blockSize,true);
public static long getBlockSize() {
return blockSize;
}
public static void setBlockSize(long blockSizex) {
blockSize = blockSizex;
}
private ReentrantLock lock=new ReentrantLock();
private class PreAlloc{
private MemorySegment segment;
private AtomicLong pos=new AtomicLong(0);
private AtomicLong refs=new AtomicLong(0);
public MemorySegment getSegment() {
return segment;
}
public AtomicLong getPos() {
return pos;
}
public PreAlloc(MemorySegment segment) {
super();
this.segment = segment;
}
public long byteSize() {
return segment.byteSize();
}
public AtomicLong getRefs() {
return refs;
}
}
private void allocateNew(long blockSize2) {
lock.lock();
try {
//buffer=Arena.ofAuto().allocate(blockSize);
MemorySegment raw=msp.borrow();
buffer=new PreAlloc(raw);
}finally {
lock.unlock();
}
}
static {
Thread t= new Thread(()->{
while(true) {
try {
Reference<? extends MemorySegment> ref;
ref = refq.remove();
if(ref!=null) {
ref.clear();
}
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
});
t.setDaemon(true);
t.setPriority(Thread.MAX_PRIORITY-1);
t.start();
}
public BufferedArena() {
super();
allocateNew(blockSize);
}
@Override
public MemorySegment allocate(long byteSize, long byteAlignment) {
if(byteSize>blockSize)
throw new IndexOutOfBoundsException("byteSize can't large than buffer block");
long pos;
PreAlloc bufferx;
do{
bufferx=this.buffer;
pos=bufferx.getPos().getAndAdd(byteSize);
if(pos+byteSize>bufferx.byteSize()) {
allocateNew(blockSize);
}else {
break;
}
}while(true);
bufferx.getRefs().incrementAndGet();
MemorySegment sliced=bufferx.getSegment().asSlice(pos, byteSize);
new MemorySegmentPhantomReference(sliced, refq, bufferx, msp);
return sliced;
}
@Override
public Scope scope() {
return Arena.ofAuto().scope();
}
@Override
public void close() {
Arena.ofAuto().close();
}
public static BufferedArena ofBuffered() {
return new BufferedArena();
}
private class MemorySegmentPhantomReference extends PhantomReference<MemorySegment>{
private static AtomicReference<MemorySegmentPhantomReference> first=new AtomicReference<>(null);
private AtomicReference<MemorySegmentPhantomReference> next=new AtomicReference<>(null);
private AtomicReference<MemorySegmentPhantomReference> prev=new AtomicReference<>(null);
private PreAlloc father;
private MemorySegmentPool pool;
public MemorySegmentPhantomReference(MemorySegment referent, ReferenceQueue<? super MemorySegment> q,PreAlloc bufferx,MemorySegmentPool pool) {
super(referent, q);
this.father=bufferx;
this.pool=pool;
insert();
}
private void insert() {
MemorySegmentPhantomReference refn= first.getAndSet(this);
if(refn!=null) {
next.set(refn);
refn.prev.set(this);
}
}
private void remove() {
MemorySegmentPhantomReference prevn= prev.getAndSet(null);
MemorySegmentPhantomReference nextn=next.getAndSet(null);
if(prevn!=null)
prevn.next.set(nextn);
if(nextn!=null)
nextn.prev.set(prevn);
}
@Override
public void clear() {
if(father.getRefs().decrementAndGet()<=0) {
if(buffer!=father)
pool.back(father.getSegment());
}
remove();
super.clear();
}
}
}