class BufferPool {

    public ByteBuffer allocate(int size, long maxTimeToBlockMs) throws InterruptedException {
        if (size > this.totalMemory) {
            throw new IllegalArgumentException("Attempt to allocate " + size
                + " bytes, but there is a hard limit of "
                + this.totalMemory
                + " on memory allocations.");
        }

        this.lock.lock();
        try {
            // check if we have a free buffer of the right size pooled
            // 校验是否有合适的小的空闲的buffer
            if (size == poolableSize && !this.free.isEmpty()) {
                return this.free.pollFirst();
            }

            // now check if the request is immediately satisfiable with the
            // memory on hand or if we need to block
            // 校验现在的内存是否可以立即满足请求，或者是否需要阻塞
            int freeListSize = this.free.size() * this.poolableSize;

            // 如果可用内存+freeList大小大于申请大小
            if (this.availableMemory + freeListSize >= size) {
                // we have enough unallocated or pooled memory to immediately
                // satisfy the request
                // 有足够的被释放或存放在池中的内存来立即满足请求
                freeUp(size);
                this.availableMemory -= size;
                lock.unlock();
                return ByteBuffer.allocate(size);
            } else {// 现在可用的内存大小无法满足
                // we are out of memory and will have to block
                // 需要的内存可能会导致溢出，所以需要阻塞
                int accumulated = 0;
                ByteBuffer buffer = null;

                Condition moreMemory = this.lock.newCondition();
                long remainingTimeToBlockNs = TimeUnit.MILLISECONDS.toNanos(maxTimeToBlockMs);
                this.waiters.addLast(moreMemory);

                // loop over and over until we have a buffer or have reserved
                // enough memory to allocate one
                // 循环等待，直到获取到申请到足够的内存
                while (accumulated < size) {
                    long startWaitNs = time.nanoseconds();
                    long timeNs;
                    boolean waitingTimeElapsed;
                    try {
                        // 当前condition进行等待 remainingTimeToBlockNs 毫秒
                        waitingTimeElapsed = !moreMemory.await(remainingTimeToBlockNs, TimeUnit.NANOSECONDS);
                    } catch (InterruptedException e) {
                        this.waiters.remove(moreMemory);
                        throw e;
                    } finally {
                        long endWaitNs = time.nanoseconds();
                        timeNs = Math.max(0L, endWaitNs - startWaitNs);
                        // 统计阻塞时间
                        this.waitTime.record(timeNs, time.milliseconds());
                    }

                    // 代表超时了
                    if (waitingTimeElapsed) {
                        this.waiters.remove(moreMemory);
                        throw new TimeoutException("Failed to allocate memory within the configured max blocking time " + maxTimeToBlockMs + " ms.");
                    }

                    // 没超时，剩余时间等于自己减去耗时
                    remainingTimeToBlockNs -= timeNs;
                    // check if we can satisfy this request from the free list,
                    // otherwise allocate memory
                    // 检查free list是否可以满足请求，不满足则申请内存
                    if (accumulated == 0 && size == this.poolableSize && !this.free.isEmpty()) {
                        // just grab a buffer from the free list
                        // 和前面是一样的，从free list中取一个出来
                        buffer = this.free.pollFirst();
                        accumulated = size;
                    } else {

                        //todo: 走到这里说明申请的大小要大于poolableSize，或者free为空
                        // we'll need to allocate memory, but we may only get
                        // part of what we need on this iteration
                        // 需要申请内存，但是在这个循环可能只能从中获取需要内存的一部分，也就是说太大了，会再获取一次
                        // size：要申请的大小。
                        freeUp(size - accumulated);

                        int got = (int) Math.min(size - accumulated, this.availableMemory);
                        this.availableMemory -= got;
                        accumulated += got;
                    }
                }

                // remove the condition for this thread to let the next thread
                // in line start getting memory
                Condition removed = this.waiters.removeFirst();
                if (removed != moreMemory) {
                    throw new IllegalStateException("Wrong condition: this shouldn't happen.");
                }

                // signal any additional waiters if there is more memory left
                // over for them
                // 通知其他waiters去拿内存
                if (this.availableMemory > 0 || !this.free.isEmpty()) {
                    if (!this.waiters.isEmpty()) {
                        this.waiters.peekFirst()
                                    .signal();
                    }
                }

                // unlock and return the buffer
                lock.unlock();
                if (buffer == null) {// buffer = null 代表内存时直接从free中轮询释放的
                    return ByteBuffer.allocate(size);
                } else {// buffer不为空，是直接复用free中的内存
                    return buffer;
                }
            }
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public  BufferPool(long memory, int poolableSize, Metrics metrics, Time time, String metricGrpName);

}