All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.io.ByteBufferPool Maven / Gradle / Ivy

There is a newer version: 12.1.0.alpha0
Show newest version
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.io;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.eclipse.jetty.util.BufferUtil;

/**
 * 

A pool for {@link RetainableByteBuffer} instances.

*

{@link RetainableByteBuffer} that are {@link #acquire(int, boolean) acquired} * must be released by calling {@link RetainableByteBuffer#release()} * otherwise the memory they hold will be leaked.

* *

API NOTE

*

This interface does not have a symmetric {@code release(RetainableByteBuffer)} * method, because it will be confusing to use due to the fact that the acquired instance * is-a {@link Retainable}.

*

Imagine this (hypothetical) code sequence:

*
{@code
 * RetainableByteBuffer buffer = pool.acquire(size, direct);
 * buffer.retain();
 * pool.release(buffer);
 * }
*

The hypothetical call to {@code release(RetainableByteBuffer)} would appear to * release the buffer to the pool, but in fact the buffer is retained one more time * (and therefore still in use) and not really released to the pool. * For this reason there is no {@code release(RetainableByteBuffer)} method.

*

Therefore, in order to track acquire/release counts both the pool and the * buffer returned by {@link #acquire(int, boolean)} must be wrapped, see * {@link RetainableByteBuffer.Wrapper}

*/ public interface ByteBufferPool { ByteBufferPool NON_POOLING = new NonPooling(); ByteBufferPool.Sized SIZED_NON_POOLING = new Sized(ByteBufferPool.NON_POOLING); /** *

Acquires a {@link RetainableByteBuffer} from this pool.

* * @param size The size of the buffer. The returned buffer will have at least this capacity. * @param direct true if a direct memory buffer is needed, false otherwise. * @return a {@link RetainableByteBuffer} with position and limit set to 0. */ RetainableByteBuffer acquire(int size, boolean direct); /** * {@link RetainableByteBuffer#release() Release} the buffer in a way that will remove it from any pool that it may be in. * If the buffer is not in a pool, calling this method is equivalent to calling {@link RetainableByteBuffer#release()}. * Calling this method satisfies any contract that requires a call to {@link RetainableByteBuffer#release()}. * @return {@code true} if a call to {@link RetainableByteBuffer#release()} would have returned {@code true}. * @see RetainableByteBuffer#release() * @deprecated This API is experimental and may be removed in future releases */ @Deprecated default boolean removeAndRelease(RetainableByteBuffer buffer) { return buffer != null && buffer.release(); } /** *

Removes all {@link RetainableByteBuffer#isRetained() non-retained} * pooled instances from this pool.

*/ void clear(); /** *

A wrapper for {@link ByteBufferPool} instances.

*/ class Wrapper implements ByteBufferPool { private final ByteBufferPool wrapped; public Wrapper(ByteBufferPool wrapped) { this.wrapped = wrapped; } public ByteBufferPool getWrapped() { return wrapped; } @Override public RetainableByteBuffer acquire(int size, boolean direct) { return getWrapped().acquire(size, direct); } @Override public void clear() { getWrapped().clear(); } } /** * A ByteBufferPool with an additional no-args {@link #acquire()} method to obtain a buffer of a * preconfigured specific size and type. */ class Sized extends Wrapper { private final boolean _direct; private final int _size; /** * Create a sized pool for non direct buffers of a default size from a wrapped pool. * @param wrapped The actual {@link ByteBufferPool} */ public Sized(ByteBufferPool wrapped) { this(wrapped, false, -1); } /** * Create a sized pool for a give directness and size from a wrapped pool. * @param wrapped The actual {@link ByteBufferPool} * @param direct {@code true} for direct buffers. * @param size The specified size in bytes of the buffer, or -1 for a default */ public Sized(ByteBufferPool wrapped, boolean direct, int size) { super(Objects.requireNonNullElse(wrapped, NON_POOLING)); _direct = direct; _size = size > 0 ? size : 4096; } public boolean isDirect() { return _direct; } public int getSize() { return _size; } /** * @return A {@link RetainableByteBuffer} suitable for the specified preconfigured size and type. */ public RetainableByteBuffer acquire() { return getWrapped().acquire(_size, _direct); } } /** *

A {@link ByteBufferPool} that does not pool its * {@link RetainableByteBuffer}s.

*

The returned {@code RetainableByteBuffer}s are reference * counted.

*

{@code RetainableByteBuffer}s returned by this class * are suitable to be wrapped in other {@link Retainable} * implementations that may delegate calls to * {@link Retainable#retain()}.

* * @see RetainableByteBuffer#wrap(ByteBuffer) */ class NonPooling implements ByteBufferPool { @Override public RetainableByteBuffer acquire(int size, boolean direct) { return new Buffer(BufferUtil.allocate(size, direct)); } @Override public void clear() { } private static class Buffer extends AbstractRetainableByteBuffer { private Buffer(ByteBuffer byteBuffer) { super(byteBuffer); acquire(); } } } /** *

Accumulates a sequence of {@link RetainableByteBuffer} that * are typically created during the generation of protocol bytes.

*

{@code RetainableByteBuffer}s can be either * {@link #append(RetainableByteBuffer) appended} to the sequence, * or {@link #insert(int, RetainableByteBuffer) inserted} at a * specific position in the sequence, and then * {@link #release() released} when they are consumed.

*/ class Accumulator { private final List buffers = new ArrayList<>(); private final List byteBuffers = new ArrayList<>(); public void append(RetainableByteBuffer buffer) { buffers.add(buffer); byteBuffers.add(buffer.getByteBuffer()); } public void insert(int index, RetainableByteBuffer buffer) { buffers.add(index, buffer); byteBuffers.add(index, buffer.getByteBuffer()); } public List getByteBuffers() { return byteBuffers; } public long getTotalLength() { long length = 0; for (ByteBuffer buffer : byteBuffers) { length += buffer.remaining(); } return length; } public int getSize() { return byteBuffers.size(); } public void release() { buffers.forEach(RetainableByteBuffer::release); buffers.clear(); byteBuffers.clear(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy