// 
// Decompiled by Procyon v0.6.0
// 

package io.netty.buffer;

import io.netty.util.concurrent.EventExecutor;
import java.util.concurrent.TimeUnit;
import io.netty.util.internal.ThreadExecutorMap;
import io.netty.util.concurrent.FastThreadLocal;
import io.netty.util.NettyRuntime;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.util.internal.StringUtil;
import io.netty.util.concurrent.FastThreadLocalThread;
import java.util.Collections;
import java.util.ArrayList;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.PlatformDependent;
import java.util.List;
import java.nio.ByteBuffer;
import io.netty.util.internal.logging.InternalLogger;

public class PooledByteBufAllocator extends AbstractByteBufAllocator implements ByteBufAllocatorMetricProvider
{
    private static final InternalLogger logger;
    private static final int DEFAULT_NUM_HEAP_ARENA;
    private static final int DEFAULT_NUM_DIRECT_ARENA;
    private static final int DEFAULT_PAGE_SIZE;
    private static final int DEFAULT_MAX_ORDER;
    private static final int DEFAULT_SMALL_CACHE_SIZE;
    private static final int DEFAULT_NORMAL_CACHE_SIZE;
    static final int DEFAULT_MAX_CACHED_BUFFER_CAPACITY;
    private static final int DEFAULT_CACHE_TRIM_INTERVAL;
    private static final long DEFAULT_CACHE_TRIM_INTERVAL_MILLIS;
    private static final boolean DEFAULT_USE_CACHE_FOR_ALL_THREADS;
    private static final int DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT;
    static final int DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK;
    private static final boolean DEFAULT_DISABLE_CACHE_FINALIZERS_FOR_FAST_THREAD_LOCAL_THREADS;
    private static final int MIN_PAGE_SIZE = 4096;
    private static final int MAX_CHUNK_SIZE = 1073741824;
    private static final int CACHE_NOT_USED = 0;
    private final Runnable trimTask;
    public static final PooledByteBufAllocator DEFAULT;
    private final PoolArena<byte[]>[] heapArenas;
    private final PoolArena<ByteBuffer>[] directArenas;
    private final int smallCacheSize;
    private final int normalCacheSize;
    private final List<PoolArenaMetric> heapArenaMetrics;
    private final List<PoolArenaMetric> directArenaMetrics;
    private final PoolThreadLocalCache threadCache;
    private final int chunkSize;
    private final PooledByteBufAllocatorMetric metric;
    
    public PooledByteBufAllocator() {
        this(false);
    }
    
    public PooledByteBufAllocator(final boolean preferDirect) {
        this(preferDirect, PooledByteBufAllocator.DEFAULT_NUM_HEAP_ARENA, PooledByteBufAllocator.DEFAULT_NUM_DIRECT_ARENA, PooledByteBufAllocator.DEFAULT_PAGE_SIZE, PooledByteBufAllocator.DEFAULT_MAX_ORDER);
    }
    
    public PooledByteBufAllocator(final int nHeapArena, final int nDirectArena, final int pageSize, final int maxOrder) {
        this(false, nHeapArena, nDirectArena, pageSize, maxOrder);
    }
    
    @Deprecated
    public PooledByteBufAllocator(final boolean preferDirect, final int nHeapArena, final int nDirectArena, final int pageSize, final int maxOrder) {
        this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder, 0, PooledByteBufAllocator.DEFAULT_SMALL_CACHE_SIZE, PooledByteBufAllocator.DEFAULT_NORMAL_CACHE_SIZE);
    }
    
    @Deprecated
    public PooledByteBufAllocator(final boolean preferDirect, final int nHeapArena, final int nDirectArena, final int pageSize, final int maxOrder, final int tinyCacheSize, final int smallCacheSize, final int normalCacheSize) {
        this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder, smallCacheSize, normalCacheSize, PooledByteBufAllocator.DEFAULT_USE_CACHE_FOR_ALL_THREADS, PooledByteBufAllocator.DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT);
    }
    
    @Deprecated
    public PooledByteBufAllocator(final boolean preferDirect, final int nHeapArena, final int nDirectArena, final int pageSize, final int maxOrder, final int tinyCacheSize, final int smallCacheSize, final int normalCacheSize, final boolean useCacheForAllThreads) {
        this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder, smallCacheSize, normalCacheSize, useCacheForAllThreads);
    }
    
    public PooledByteBufAllocator(final boolean preferDirect, final int nHeapArena, final int nDirectArena, final int pageSize, final int maxOrder, final int smallCacheSize, final int normalCacheSize, final boolean useCacheForAllThreads) {
        this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder, smallCacheSize, normalCacheSize, useCacheForAllThreads, PooledByteBufAllocator.DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT);
    }
    
    @Deprecated
    public PooledByteBufAllocator(final boolean preferDirect, final int nHeapArena, final int nDirectArena, final int pageSize, final int maxOrder, final int tinyCacheSize, final int smallCacheSize, final int normalCacheSize, final boolean useCacheForAllThreads, final int directMemoryCacheAlignment) {
        this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder, smallCacheSize, normalCacheSize, useCacheForAllThreads, directMemoryCacheAlignment);
    }
    
    public PooledByteBufAllocator(final boolean preferDirect, final int nHeapArena, final int nDirectArena, int pageSize, final int maxOrder, final int smallCacheSize, final int normalCacheSize, final boolean useCacheForAllThreads, final int directMemoryCacheAlignment) {
        super(preferDirect);
        this.trimTask = new Runnable() {
            @Override
            public void run() {
                PooledByteBufAllocator.this.trimCurrentThreadCache();
            }
        };
        this.threadCache = new PoolThreadLocalCache(useCacheForAllThreads);
        this.smallCacheSize = smallCacheSize;
        this.normalCacheSize = normalCacheSize;
        if (directMemoryCacheAlignment != 0) {
            if (!PlatformDependent.hasAlignDirectByteBuffer()) {
                throw new UnsupportedOperationException("Buffer alignment is not supported. Either Unsafe or ByteBuffer.alignSlice() must be available.");
            }
            pageSize = (int)PlatformDependent.align(pageSize, directMemoryCacheAlignment);
        }
        this.chunkSize = validateAndCalculateChunkSize(pageSize, maxOrder);
        ObjectUtil.checkPositiveOrZero(nHeapArena, "nHeapArena");
        ObjectUtil.checkPositiveOrZero(nDirectArena, "nDirectArena");
        ObjectUtil.checkPositiveOrZero(directMemoryCacheAlignment, "directMemoryCacheAlignment");
        if (directMemoryCacheAlignment > 0 && !isDirectMemoryCacheAlignmentSupported()) {
            throw new IllegalArgumentException("directMemoryCacheAlignment is not supported");
        }
        if ((directMemoryCacheAlignment & -directMemoryCacheAlignment) != directMemoryCacheAlignment) {
            throw new IllegalArgumentException("directMemoryCacheAlignment: " + directMemoryCacheAlignment + " (expected: power of two)");
        }
        final int pageShifts = validateAndCalculatePageShifts(pageSize, directMemoryCacheAlignment);
        if (nHeapArena > 0) {
            this.heapArenas = newArenaArray(nHeapArena);
            final List<PoolArenaMetric> metrics = new ArrayList<PoolArenaMetric>(this.heapArenas.length);
            final SizeClasses sizeClasses = new SizeClasses(pageSize, pageShifts, this.chunkSize, 0);
            for (int i = 0; i < this.heapArenas.length; ++i) {
                final PoolArena.HeapArena arena = new PoolArena.HeapArena(this, sizeClasses);
                metrics.add(this.heapArenas[i] = arena);
            }
            this.heapArenaMetrics = Collections.unmodifiableList((List<? extends PoolArenaMetric>)metrics);
        }
        else {
            this.heapArenas = null;
            this.heapArenaMetrics = Collections.emptyList();
        }
        if (nDirectArena > 0) {
            this.directArenas = newArenaArray(nDirectArena);
            final List<PoolArenaMetric> metrics = new ArrayList<PoolArenaMetric>(this.directArenas.length);
            final SizeClasses sizeClasses = new SizeClasses(pageSize, pageShifts, this.chunkSize, directMemoryCacheAlignment);
            for (int i = 0; i < this.directArenas.length; ++i) {
                final PoolArena.DirectArena arena2 = new PoolArena.DirectArena(this, sizeClasses);
                metrics.add(this.directArenas[i] = arena2);
            }
            this.directArenaMetrics = Collections.unmodifiableList((List<? extends PoolArenaMetric>)metrics);
        }
        else {
            this.directArenas = null;
            this.directArenaMetrics = Collections.emptyList();
        }
        this.metric = new PooledByteBufAllocatorMetric(this);
    }
    
    private static <T> PoolArena<T>[] newArenaArray(final int size) {
        return new PoolArena[size];
    }
    
    private static int validateAndCalculatePageShifts(final int pageSize, final int alignment) {
        if (pageSize < 4096) {
            throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: " + 4096 + ')');
        }
        if ((pageSize & pageSize - 1) != 0x0) {
            throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: power of 2)");
        }
        if (pageSize < alignment) {
            throw new IllegalArgumentException("Alignment cannot be greater than page size. Alignment: " + alignment + ", page size: " + pageSize + '.');
        }
        return 31 - Integer.numberOfLeadingZeros(pageSize);
    }
    
    private static int validateAndCalculateChunkSize(final int pageSize, final int maxOrder) {
        if (maxOrder > 14) {
            throw new IllegalArgumentException("maxOrder: " + maxOrder + " (expected: 0-14)");
        }
        int chunkSize = pageSize;
        for (int i = maxOrder; i > 0; --i) {
            if (chunkSize > 536870912) {
                throw new IllegalArgumentException(String.format("pageSize (%d) << maxOrder (%d) must not exceed %d", pageSize, maxOrder, 1073741824));
            }
            chunkSize <<= 1;
        }
        return chunkSize;
    }
    
    @Override
    protected ByteBuf newHeapBuffer(final int initialCapacity, final int maxCapacity) {
        final PoolThreadCache cache = this.threadCache.get();
        final PoolArena<byte[]> heapArena = cache.heapArena;
        AbstractByteBuf buf;
        if (heapArena != null) {
            buf = heapArena.allocate(cache, initialCapacity, maxCapacity);
        }
        else {
            buf = (PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) : new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity));
            onAllocateBuffer(buf, false, false);
        }
        return AbstractByteBufAllocator.toLeakAwareBuffer(buf);
    }
    
    @Override
    protected ByteBuf newDirectBuffer(final int initialCapacity, final int maxCapacity) {
        final PoolThreadCache cache = this.threadCache.get();
        final PoolArena<ByteBuffer> directArena = cache.directArena;
        AbstractByteBuf buf;
        if (directArena != null) {
            buf = directArena.allocate(cache, initialCapacity, maxCapacity);
        }
        else {
            buf = (PlatformDependent.hasUnsafe() ? UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity, true) : new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity, true));
            onAllocateBuffer(buf, false, false);
        }
        return AbstractByteBufAllocator.toLeakAwareBuffer(buf);
    }
    
    public static int defaultNumHeapArena() {
        return PooledByteBufAllocator.DEFAULT_NUM_HEAP_ARENA;
    }
    
    public static int defaultNumDirectArena() {
        return PooledByteBufAllocator.DEFAULT_NUM_DIRECT_ARENA;
    }
    
    public static int defaultPageSize() {
        return PooledByteBufAllocator.DEFAULT_PAGE_SIZE;
    }
    
    public static int defaultMaxOrder() {
        return PooledByteBufAllocator.DEFAULT_MAX_ORDER;
    }
    
    public static boolean defaultDisableCacheFinalizersForFastThreadLocalThreads() {
        return PooledByteBufAllocator.DEFAULT_DISABLE_CACHE_FINALIZERS_FOR_FAST_THREAD_LOCAL_THREADS;
    }
    
    public static boolean defaultUseCacheForAllThreads() {
        return PooledByteBufAllocator.DEFAULT_USE_CACHE_FOR_ALL_THREADS;
    }
    
    public static boolean defaultPreferDirect() {
        return PlatformDependent.directBufferPreferred();
    }
    
    @Deprecated
    public static int defaultTinyCacheSize() {
        return 0;
    }
    
    public static int defaultSmallCacheSize() {
        return PooledByteBufAllocator.DEFAULT_SMALL_CACHE_SIZE;
    }
    
    public static int defaultNormalCacheSize() {
        return PooledByteBufAllocator.DEFAULT_NORMAL_CACHE_SIZE;
    }
    
    public static boolean isDirectMemoryCacheAlignmentSupported() {
        return PlatformDependent.hasUnsafe();
    }
    
    @Override
    public boolean isDirectBufferPooled() {
        return this.directArenas != null;
    }
    
    @Deprecated
    public boolean hasThreadLocalCache() {
        return this.threadCache.isSet();
    }
    
    @Deprecated
    public void freeThreadLocalCache() {
        this.threadCache.remove();
    }
    
    private static boolean useCacheFinalizers() {
        return !defaultDisableCacheFinalizersForFastThreadLocalThreads() || FastThreadLocalThread.currentThreadWillCleanupFastThreadLocals();
    }
    
    @Override
    public PooledByteBufAllocatorMetric metric() {
        return this.metric;
    }
    
    @Deprecated
    public int numHeapArenas() {
        return this.heapArenaMetrics.size();
    }
    
    @Deprecated
    public int numDirectArenas() {
        return this.directArenaMetrics.size();
    }
    
    @Deprecated
    public List<PoolArenaMetric> heapArenas() {
        return this.heapArenaMetrics;
    }
    
    @Deprecated
    public List<PoolArenaMetric> directArenas() {
        return this.directArenaMetrics;
    }
    
    @Deprecated
    public int numThreadLocalCaches() {
        return Math.max(numThreadLocalCaches(this.heapArenas), numThreadLocalCaches(this.directArenas));
    }
    
    private static int numThreadLocalCaches(final PoolArena<?>[] arenas) {
        if (arenas == null) {
            return 0;
        }
        int total = 0;
        for (final PoolArena<?> arena : arenas) {
            total += arena.numThreadCaches.get();
        }
        return total;
    }
    
    @Deprecated
    public int tinyCacheSize() {
        return 0;
    }
    
    @Deprecated
    public int smallCacheSize() {
        return this.smallCacheSize;
    }
    
    @Deprecated
    public int normalCacheSize() {
        return this.normalCacheSize;
    }
    
    @Deprecated
    public final int chunkSize() {
        return this.chunkSize;
    }
    
    final long usedHeapMemory() {
        return usedMemory(this.heapArenas);
    }
    
    final long usedDirectMemory() {
        return usedMemory(this.directArenas);
    }
    
    private static long usedMemory(final PoolArena<?>[] arenas) {
        if (arenas == null) {
            return -1L;
        }
        long used = 0L;
        for (final PoolArena<?> arena : arenas) {
            used += arena.numActiveBytes();
            if (used < 0L) {
                return Long.MAX_VALUE;
            }
        }
        return used;
    }
    
    public final long pinnedHeapMemory() {
        return pinnedMemory(this.heapArenas);
    }
    
    public final long pinnedDirectMemory() {
        return pinnedMemory(this.directArenas);
    }
    
    private static long pinnedMemory(final PoolArena<?>[] arenas) {
        if (arenas == null) {
            return -1L;
        }
        long used = 0L;
        for (final PoolArena<?> arena : arenas) {
            used += arena.numPinnedBytes();
            if (used < 0L) {
                return Long.MAX_VALUE;
            }
        }
        return used;
    }
    
    final PoolThreadCache threadCache() {
        final PoolThreadCache cache = this.threadCache.get();
        assert cache != null;
        return cache;
    }
    
    public boolean trimCurrentThreadCache() {
        final PoolThreadCache cache = this.threadCache.getIfExists();
        if (cache != null) {
            cache.trim();
            return true;
        }
        return false;
    }
    
    public String dumpStats() {
        final int heapArenasLen = (this.heapArenas == null) ? 0 : this.heapArenas.length;
        final StringBuilder buf = new StringBuilder(512).append(heapArenasLen).append(" heap arena(s):").append(StringUtil.NEWLINE);
        if (heapArenasLen > 0) {
            for (final PoolArena<byte[]> a : this.heapArenas) {
                buf.append(a);
            }
        }
        final int directArenasLen = (this.directArenas == null) ? 0 : this.directArenas.length;
        buf.append(directArenasLen).append(" direct arena(s):").append(StringUtil.NEWLINE);
        if (directArenasLen > 0) {
            for (final PoolArena<ByteBuffer> a2 : this.directArenas) {
                buf.append(a2);
            }
        }
        return buf.toString();
    }
    
    static void onAllocateBuffer(final AbstractByteBuf buf, final boolean pooled, final boolean threadLocal) {
        if (PlatformDependent.isJfrEnabled() && AllocateBufferEvent.isEventEnabled()) {
            final AllocateBufferEvent event = new AllocateBufferEvent();
            if (event.shouldCommit()) {
                event.fill(buf, PooledByteBufAllocator.class);
                event.chunkPooled = pooled;
                event.chunkThreadLocal = threadLocal;
                event.commit();
            }
        }
    }
    
    static void onDeallocateBuffer(final AbstractByteBuf buf) {
        if (PlatformDependent.isJfrEnabled() && FreeBufferEvent.isEventEnabled()) {
            final FreeBufferEvent event = new FreeBufferEvent();
            if (event.shouldCommit()) {
                event.fill(buf, PooledByteBufAllocator.class);
                event.commit();
            }
        }
    }
    
    static void onReallocateBuffer(final AbstractByteBuf buf, final int newCapacity) {
        if (PlatformDependent.isJfrEnabled() && ReallocateBufferEvent.isEventEnabled()) {
            final ReallocateBufferEvent event = new ReallocateBufferEvent();
            if (event.shouldCommit()) {
                event.fill(buf, PooledByteBufAllocator.class);
                event.newCapacity = newCapacity;
                event.commit();
            }
        }
    }
    
    static void onAllocateChunk(final ChunkInfo chunk, final boolean pooled) {
        if (PlatformDependent.isJfrEnabled() && AllocateChunkEvent.isEventEnabled()) {
            final AllocateChunkEvent event = new AllocateChunkEvent();
            if (event.shouldCommit()) {
                event.fill(chunk, PooledByteBufAllocator.class);
                event.pooled = pooled;
                event.threadLocal = false;
                event.commit();
            }
        }
    }
    
    static void onDeallocateChunk(final ChunkInfo chunk, final boolean pooled) {
        if (PlatformDependent.isJfrEnabled() && FreeChunkEvent.isEventEnabled()) {
            final FreeChunkEvent event = new FreeChunkEvent();
            if (event.shouldCommit()) {
                event.fill(chunk, PooledByteBufAllocator.class);
                event.pooled = pooled;
                event.commit();
            }
        }
    }
    
    static {
        logger = InternalLoggerFactory.getInstance(PooledByteBufAllocator.class);
        int defaultAlignment = SystemPropertyUtil.getInt("io.netty.allocator.directMemoryCacheAlignment", 0);
        int defaultPageSize = SystemPropertyUtil.getInt("io.netty.allocator.pageSize", 8192);
        Throwable pageSizeFallbackCause = null;
        try {
            validateAndCalculatePageShifts(defaultPageSize, defaultAlignment);
        }
        catch (final Throwable t) {
            pageSizeFallbackCause = t;
            defaultPageSize = 8192;
            defaultAlignment = 0;
        }
        DEFAULT_PAGE_SIZE = defaultPageSize;
        DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT = defaultAlignment;
        int defaultMaxOrder = SystemPropertyUtil.getInt("io.netty.allocator.maxOrder", 9);
        Throwable maxOrderFallbackCause = null;
        try {
            validateAndCalculateChunkSize(PooledByteBufAllocator.DEFAULT_PAGE_SIZE, defaultMaxOrder);
        }
        catch (final Throwable t2) {
            maxOrderFallbackCause = t2;
            defaultMaxOrder = 9;
        }
        DEFAULT_MAX_ORDER = defaultMaxOrder;
        final Runtime runtime = Runtime.getRuntime();
        final int defaultMinNumArena = NettyRuntime.availableProcessors() * 2;
        final int defaultChunkSize = PooledByteBufAllocator.DEFAULT_PAGE_SIZE << PooledByteBufAllocator.DEFAULT_MAX_ORDER;
        DEFAULT_NUM_HEAP_ARENA = Math.max(0, SystemPropertyUtil.getInt("io.netty.allocator.numHeapArenas", (int)Math.min(defaultMinNumArena, runtime.maxMemory() / defaultChunkSize / 2L / 3L)));
        DEFAULT_NUM_DIRECT_ARENA = Math.max(0, SystemPropertyUtil.getInt("io.netty.allocator.numDirectArenas", (int)Math.min(defaultMinNumArena, PlatformDependent.maxDirectMemory() / defaultChunkSize / 2L / 3L)));
        DEFAULT_SMALL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.smallCacheSize", 256);
        DEFAULT_NORMAL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.normalCacheSize", 64);
        DEFAULT_MAX_CACHED_BUFFER_CAPACITY = SystemPropertyUtil.getInt("io.netty.allocator.maxCachedBufferCapacity", 32768);
        DEFAULT_CACHE_TRIM_INTERVAL = SystemPropertyUtil.getInt("io.netty.allocator.cacheTrimInterval", 8192);
        if (SystemPropertyUtil.contains("io.netty.allocation.cacheTrimIntervalMillis")) {
            PooledByteBufAllocator.logger.warn("-Dio.netty.allocation.cacheTrimIntervalMillis is deprecated, use -Dio.netty.allocator.cacheTrimIntervalMillis");
            if (SystemPropertyUtil.contains("io.netty.allocator.cacheTrimIntervalMillis")) {
                DEFAULT_CACHE_TRIM_INTERVAL_MILLIS = SystemPropertyUtil.getLong("io.netty.allocator.cacheTrimIntervalMillis", 0L);
            }
            else {
                DEFAULT_CACHE_TRIM_INTERVAL_MILLIS = SystemPropertyUtil.getLong("io.netty.allocation.cacheTrimIntervalMillis", 0L);
            }
        }
        else {
            DEFAULT_CACHE_TRIM_INTERVAL_MILLIS = SystemPropertyUtil.getLong("io.netty.allocator.cacheTrimIntervalMillis", 0L);
        }
        DEFAULT_USE_CACHE_FOR_ALL_THREADS = SystemPropertyUtil.getBoolean("io.netty.allocator.useCacheForAllThreads", false);
        DEFAULT_DISABLE_CACHE_FINALIZERS_FOR_FAST_THREAD_LOCAL_THREADS = SystemPropertyUtil.getBoolean("io.netty.allocator.disableCacheFinalizersForFastThreadLocalThreads", false);
        DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK = SystemPropertyUtil.getInt("io.netty.allocator.maxCachedByteBuffersPerChunk", 1023);
        if (PooledByteBufAllocator.logger.isDebugEnabled()) {
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.numHeapArenas: {}", (Object)PooledByteBufAllocator.DEFAULT_NUM_HEAP_ARENA);
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.numDirectArenas: {}", (Object)PooledByteBufAllocator.DEFAULT_NUM_DIRECT_ARENA);
            if (pageSizeFallbackCause == null) {
                PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.pageSize: {}", (Object)PooledByteBufAllocator.DEFAULT_PAGE_SIZE);
            }
            else {
                PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.pageSize: {}", (Object)PooledByteBufAllocator.DEFAULT_PAGE_SIZE, pageSizeFallbackCause);
            }
            if (maxOrderFallbackCause == null) {
                PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.maxOrder: {}", (Object)PooledByteBufAllocator.DEFAULT_MAX_ORDER);
            }
            else {
                PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.maxOrder: {}", (Object)PooledByteBufAllocator.DEFAULT_MAX_ORDER, maxOrderFallbackCause);
            }
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.chunkSize: {}", (Object)(PooledByteBufAllocator.DEFAULT_PAGE_SIZE << PooledByteBufAllocator.DEFAULT_MAX_ORDER));
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.smallCacheSize: {}", (Object)PooledByteBufAllocator.DEFAULT_SMALL_CACHE_SIZE);
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.normalCacheSize: {}", (Object)PooledByteBufAllocator.DEFAULT_NORMAL_CACHE_SIZE);
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.maxCachedBufferCapacity: {}", (Object)PooledByteBufAllocator.DEFAULT_MAX_CACHED_BUFFER_CAPACITY);
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.cacheTrimInterval: {}", (Object)PooledByteBufAllocator.DEFAULT_CACHE_TRIM_INTERVAL);
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.cacheTrimIntervalMillis: {}", (Object)PooledByteBufAllocator.DEFAULT_CACHE_TRIM_INTERVAL_MILLIS);
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.useCacheForAllThreads: {}", (Object)PooledByteBufAllocator.DEFAULT_USE_CACHE_FOR_ALL_THREADS);
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.maxCachedByteBuffersPerChunk: {}", (Object)PooledByteBufAllocator.DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK);
            PooledByteBufAllocator.logger.debug("-Dio.netty.allocator.disableCacheFinalizersForFastThreadLocalThreads: {}", (Object)PooledByteBufAllocator.DEFAULT_DISABLE_CACHE_FINALIZERS_FOR_FAST_THREAD_LOCAL_THREADS);
        }
        DEFAULT = new PooledByteBufAllocator(!PlatformDependent.isExplicitNoPreferDirect());
    }
    
    private final class PoolThreadLocalCache extends FastThreadLocal<PoolThreadCache>
    {
        private final boolean useCacheForAllThreads;
        
        PoolThreadLocalCache(final boolean useCacheForAllThreads) {
            this.useCacheForAllThreads = useCacheForAllThreads;
        }
        
        @Override
        protected synchronized PoolThreadCache initialValue() {
            final PoolArena<byte[]> heapArena = this.leastUsedArena(PooledByteBufAllocator.this.heapArenas);
            final PoolArena<ByteBuffer> directArena = this.leastUsedArena(PooledByteBufAllocator.this.directArenas);
            final Thread current = Thread.currentThread();
            final EventExecutor executor = ThreadExecutorMap.currentExecutor();
            if (this.useCacheForAllThreads || FastThreadLocalThread.currentThreadHasFastThreadLocal() || executor != null) {
                final PoolThreadCache cache = new PoolThreadCache(heapArena, directArena, PooledByteBufAllocator.this.smallCacheSize, PooledByteBufAllocator.this.normalCacheSize, PooledByteBufAllocator.DEFAULT_MAX_CACHED_BUFFER_CAPACITY, PooledByteBufAllocator.DEFAULT_CACHE_TRIM_INTERVAL, useCacheFinalizers());
                if (PooledByteBufAllocator.DEFAULT_CACHE_TRIM_INTERVAL_MILLIS > 0L && executor != null) {
                    executor.scheduleAtFixedRate(PooledByteBufAllocator.this.trimTask, PooledByteBufAllocator.DEFAULT_CACHE_TRIM_INTERVAL_MILLIS, PooledByteBufAllocator.DEFAULT_CACHE_TRIM_INTERVAL_MILLIS, TimeUnit.MILLISECONDS);
                }
                return cache;
            }
            return new PoolThreadCache(heapArena, directArena, 0, 0, 0, 0, false);
        }
        
        @Override
        protected void onRemoval(final PoolThreadCache threadCache) {
            threadCache.free(false);
        }
        
        private <T> PoolArena<T> leastUsedArena(final PoolArena<T>[] arenas) {
            if (arenas == null || arenas.length == 0) {
                return null;
            }
            PoolArena<T> minArena = arenas[0];
            if (minArena.numThreadCaches.get() == 0) {
                return minArena;
            }
            for (int i = 1; i < arenas.length; ++i) {
                final PoolArena<T> arena = arenas[i];
                if (arena.numThreadCaches.get() < minArena.numThreadCaches.get()) {
                    minArena = arena;
                }
            }
            return minArena;
        }
    }
}
