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

org.eclipse.jetty.io.ByteBufferAggregator 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 org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 

Aggregates data into a single ByteBuffer of a specified maximum size.

*

The buffer automatically grows as data is written to it, up until it reaches the specified maximum size. * Once the buffer is full, the aggregator will not aggregate any more bytes until its buffer is taken out, * after which a new aggregate/take buffer cycle can start.

*

The buffers are taken from the supplied {@link ByteBufferPool} or freshly allocated if one is not supplied.

*/ public class ByteBufferAggregator { private static final Logger LOG = LoggerFactory.getLogger(ByteBufferAggregator.class); private final ByteBufferPool _bufferPool; private final boolean _direct; private final int _maxSize; private RetainableByteBuffer _retainableByteBuffer; private int _aggregatedSize; private int _currentSize; /** * Creates a ByteBuffer aggregator. * @param bufferPool The {@link ByteBufferPool} from which to acquire the buffers * @param direct whether to get direct buffers * @param startSize the starting size of the buffer * @param maxSize the maximum size of the buffer which must be greater than {@code startSize} */ public ByteBufferAggregator(ByteBufferPool bufferPool, boolean direct, int startSize, int maxSize) { if (maxSize <= 0) throw new IllegalArgumentException("maxSize must be > 0, was: " + maxSize); if (startSize <= 0) throw new IllegalArgumentException("startSize must be > 0, was: " + startSize); if (startSize > maxSize) throw new IllegalArgumentException("maxSize (" + maxSize + ") must be >= startSize (" + startSize + ")"); _bufferPool = (bufferPool == null) ? new ByteBufferPool.NonPooling() : bufferPool; _direct = direct; _maxSize = maxSize; _currentSize = startSize; } /** * Get the currently aggregated length. * @return The current total aggregated bytes. */ public int length() { return _aggregatedSize; } /** * Aggregates the given ByteBuffer. This copies bytes up to the specified maximum size, at which * time this method returns {@code true} and {@link #takeRetainableByteBuffer()} must be called * for this method to accept aggregating again. * @param buffer the buffer to copy into this aggregator; its position is updated according to * the number of aggregated bytes * @return true if the aggregator's buffer is full and should be taken, false otherwise */ public boolean aggregate(ByteBuffer buffer) { tryExpandBufferCapacity(buffer.remaining()); if (_retainableByteBuffer == null) { _retainableByteBuffer = _bufferPool.acquire(_currentSize, _direct); BufferUtil.flipToFill(_retainableByteBuffer.getByteBuffer()); } int copySize = Math.min(_currentSize - _aggregatedSize, buffer.remaining()); ByteBuffer byteBuffer = _retainableByteBuffer.getByteBuffer(); byteBuffer.put(byteBuffer.position(), buffer, buffer.position(), copySize); byteBuffer.position(byteBuffer.position() + copySize); buffer.position(buffer.position() + copySize); _aggregatedSize += copySize; return _aggregatedSize == _maxSize; } private void tryExpandBufferCapacity(int remaining) { if (LOG.isDebugEnabled()) LOG.debug("tryExpandBufferCapacity remaining: {} _currentSize: {} _accumulatedSize={}", remaining, _currentSize, _aggregatedSize); if (_currentSize == _maxSize) return; int capacityLeft = _currentSize - _aggregatedSize; if (remaining <= capacityLeft) return; int need = remaining - capacityLeft; _currentSize = Math.min(_maxSize, TypeUtil.ceilToNextPowerOfTwo(_currentSize + need)); if (_retainableByteBuffer != null) { BufferUtil.flipToFlush(_retainableByteBuffer.getByteBuffer(), 0); RetainableByteBuffer newBuffer = _bufferPool.acquire(_currentSize, _direct); BufferUtil.flipToFill(newBuffer.getByteBuffer()); newBuffer.getByteBuffer().put(_retainableByteBuffer.getByteBuffer()); _retainableByteBuffer.release(); _retainableByteBuffer = newBuffer; } } /** * Takes the buffer out of the aggregator. Once the buffer has been taken out, * the aggregator resets itself and a new buffer will be acquired from the pool * during the next {@link #aggregate(ByteBuffer)} call. * @return the aggregated buffer, or null if nothing has been buffered yet */ public RetainableByteBuffer takeRetainableByteBuffer() { if (_retainableByteBuffer == null) return null; BufferUtil.flipToFlush(_retainableByteBuffer.getByteBuffer(), 0); RetainableByteBuffer result = _retainableByteBuffer; _retainableByteBuffer = null; _aggregatedSize = 0; return result; } @Override public String toString() { return "%s@%x{a=%d c=%d m=%d b=%s}".formatted(getClass().getSimpleName(), hashCode(), _aggregatedSize, _currentSize, _maxSize, _retainableByteBuffer); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy