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 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 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{ private static AtomicReference first=new AtomicReference<>(null); private AtomicReference next=new AtomicReference<>(null); private AtomicReference prev=new AtomicReference<>(null); private PreAlloc father; private MemorySegmentPool pool; public MemorySegmentPhantomReference(MemorySegment referent, ReferenceQueue 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(); } } }