package net.minestom.server.utils.binary; import org.jctools.queues.MessagePassingQueue; import org.jctools.queues.MpmcUnboundedXaddArrayQueue; import org.jetbrains.annotations.ApiStatus; import java.lang.ref.Cleaner; import java.lang.ref.SoftReference; import java.util.Collection; import java.util.concurrent.atomic.AtomicReference; @ApiStatus.Internal @ApiStatus.Experimental public final class PooledBuffers { private final static MessagePassingQueue> POOLED_BUFFERS = new MpmcUnboundedXaddArrayQueue<>(1024); private final static int BUFFER_SIZE = Integer.getInteger("minestom.pooled-buffer-size", 262_143); private final static Cleaner CLEANER = Cleaner.create(); public static BinaryBuffer get() { BinaryBuffer buffer; SoftReference ref; while ((ref = POOLED_BUFFERS.relaxedPoll()) != null) { if ((buffer = ref.get()) != null) return buffer; } return BinaryBuffer.ofSize(BUFFER_SIZE); } public static void add(BinaryBuffer buffer) { POOLED_BUFFERS.relaxedOffer(new SoftReference<>(buffer.clear())); } public static void clear() { POOLED_BUFFERS.clear(); } public static int count() { return POOLED_BUFFERS.size(); } public static int bufferSize() { return BUFFER_SIZE; } public static void registerBuffer(Object ref, AtomicReference buffer) { CLEANER.register(ref, new BufferRefCleaner(buffer)); } public static void registerBuffer(Object ref, BinaryBuffer buffer) { CLEANER.register(ref, new BufferCleaner(buffer)); } public static void registerBuffers(Object ref, Collection buffers) { CLEANER.register(ref, new BuffersCleaner(buffers)); } private record BufferRefCleaner(AtomicReference bufferRef) implements Runnable { @Override public void run() { add(bufferRef.get()); } } private record BufferCleaner(BinaryBuffer buffer) implements Runnable { @Override public void run() { add(buffer); } } private record BuffersCleaner(Collection buffers) implements Runnable { @Override public void run() { if (buffers.isEmpty()) return; for (BinaryBuffer buffer : buffers) { add(buffer); } } } }