//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.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.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Retainable;
A Retainable ByteBuffer.
Acquires a ByteBuffer from a ByteBufferPool
and maintains a reference count that is initially 1, incremented with retain()
and decremented with release()
. The buffer is released to the pool when the reference count is decremented to 0.
/**
* A Retainable ByteBuffer.
* <p>Acquires a ByteBuffer from a {@link ByteBufferPool} and maintains a reference count that is
* initially 1, incremented with {@link #retain()} and decremented with {@link #release()}. The buffer
* is released to the pool when the reference count is decremented to 0.</p>
*/
public class RetainableByteBuffer implements Retainable
{
private final ByteBufferPool pool;
private final ByteBuffer buffer;
private final AtomicInteger references;
public RetainableByteBuffer(ByteBufferPool pool, int size)
{
this(pool, size, false);
}
public RetainableByteBuffer(ByteBufferPool pool, int size, boolean direct)
{
this.pool = pool;
this.buffer = pool.acquire(size, direct);
this.references = new AtomicInteger(1);
}
public ByteBuffer getBuffer()
{
return buffer;
}
public int getReferences()
{
return references.get();
}
@Override
public void retain()
{
while (true)
{
int r = references.get();
if (r == 0)
throw new IllegalStateException("released " + this);
if (references.compareAndSet(r, r + 1))
break;
}
}
public int release()
{
int ref = references.decrementAndGet();
if (ref == 0)
pool.release(buffer);
else if (ref < 0)
throw new IllegalStateException("already released " + this);
return ref;
}
public int remaining()
{
return buffer.remaining();
}
public boolean hasRemaining()
{
return remaining() > 0;
}
public boolean isEmpty()
{
return !hasRemaining();
}
public void clear()
{
BufferUtil.clear(buffer);
}
@Override
public String toString()
{
return String.format("%s@%x{%s,r=%d}", getClass().getSimpleName(), hashCode(), BufferUtil.toDetailString(buffer), getReferences());
}
}