Repository: netty/netty
File: buffer/src/main/java/io/netty/buffer/AdaptivePoolingAllocator.java (Java)

Code before:

            int startIndex = segmentId * segmentSize;
            allocatedBytes += segmentSize;
            Chunk chunk = this;
            chunk.retain();
            try {
                buf.init(delegate, chunk, 0, 0, startIndex, size, startingCapacity, maxCapacity, segmentId);
                chunk = null;
            } finally {
                if (chunk != null) {
                    // If chunk is not null we know that buf.init(...) failed and so we need to manually release
                    // the chunk again as we retained it before calling buf.init(...). Beside this we also need to
                    // restore the old allocatedBytes value.
                    allocatedBytes -= segmentSize;
                    chunk.releaseSegment(segmentId);
                }
            }
        }

        @Override
        boolean releaseFromMagazine() {
            // Size-classed chunks can be reused before they become empty.
            // We can therefor put them in the shared queue as soon as the magazine is done with this chunk.
            Magazine mag = magazine;
            detachFromMagazine();
            if (!mag.offerToQueue(this)) {
                return super.releaseFromMagazine();
            }
            return false;
        }

        @Override
        boolean releaseSegment(int segmentId) {
            boolean released = release();
            boolean segmentReturned = freeList.offer(segmentId);
            assert segmentReturned: "Unable to return segment " + segmentId + " to free list";
            return released;
        }
    }

    @SuppressWarnings("Since15")
    abstract static class AbstractChunkEvent extends Event {
        @DataAmount
        @Description("Size of the chunk")
        int capacity;
        @Description("Is this chunk referencing off-heap memory?")
        boolean direct;
        @Description("The memory address of the off-heap memory, if available")
        @MemoryAddress
        long address;


Review comment (performance):
This is the same ratio of JCTools's cached producer limits: to save bothering to have an up-to-date value, update it only if the current value implies no progress - verifying that we live in a better (up-to-dated) world.

Said that - I still dislike using `size` here, although is shouldn't be an hot path

Code after:

            int startIndex = segmentId * segmentSize;
            allocatedBytes += segmentSize;
            Chunk chunk = this;
            chunk.retain();
            try {
                buf.init(delegate, chunk, 0, 0, startIndex, size, startingCapacity, maxCapacity, segmentId);
                chunk = null;
            } finally {
                if (chunk != null) {
                    // If chunk is not null we know that buf.init(...) failed and so we need to manually release
                    // the chunk again as we retained it before calling buf.init(...). Beside this we also need to
                    // restore the old allocatedBytes value.
                    allocatedBytes -= segmentSize;
                    chunk.releaseSegment(segmentId);
                }
            }
        }

        @Override
        public int remainingCapacity() {
            int remainingCapacity = super.remainingCapacity();
            if (remainingCapacity > segmentSize) {
                return remainingCapacity;
            }
            int updatedRemainingCapacity = freeList.size() * segmentSize;
            if (updatedRemainingCapacity == remainingCapacity) {
                return remainingCapacity;
            }
            // update allocatedBytes based on what's available in the free list
            allocatedBytes = capacity() - updatedRemainingCapacity;
            return updatedRemainingCapacity;
        }

        @Override
        boolean releaseFromMagazine() {
            // Size-classed chunks can be reused before they become empty.
            // We can therefor put them in the shared queue as soon as the magazine is done with this chunk.
            Magazine mag = magazine;
            detachFromMagazine();
            if (!mag.offerToQueue(this)) {
                return super.releaseFromMagazine();
            }
            return false;
        }

        @Override
        boolean releaseSegment(int segmentId) {
            boolean released = release();
            boolean segmentReturned = freeList.offer(segmentId);
            assert segmentReturned: "Unable to return segment " + segmentId + " to free list";