blob: f1efa170e361d837528328b33b5da573000eec4d [file] [log] [blame]
/*
* Copyright (c) 2007-2012 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.internal.net4j.buffer;
import org.eclipse.net4j.buffer.IBuffer;
import org.eclipse.net4j.buffer.IBufferPool;
import org.eclipse.net4j.buffer.IBufferProvider;
import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.net4j.util.ref.CleanableReferenceQueue;
import org.eclipse.internal.net4j.bundle.OM;
import org.eclipse.spi.net4j.InternalBuffer;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.text.MessageFormat;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* @author Eike Stepper
*/
public class BufferPool extends BufferProvider implements IBufferPool.Introspection
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_BUFFER, BufferPool.class);
private final IBufferProvider provider;
private int pooledBuffers;
@ExcludeFromDump
private final Queue<BufferRef> buffers = new ConcurrentLinkedQueue<BufferRef>();
@ExcludeFromDump
private final CleanableReferenceQueue<IBuffer> referenceQueue = new CleanableReferenceQueue<IBuffer>()
{
@Override
protected Reference<IBuffer> createReference(IBuffer buffer)
{
return new BufferRef(buffer, this);
}
@Override
protected void cleanReference(Reference<? extends IBuffer> reference)
{
if (buffers.remove(reference))
{
--pooledBuffers;
if (TRACER.isEnabled())
{
TRACER.trace("Collected buffer"); //$NON-NLS-1$
}
}
}
};
public BufferPool(IBufferProvider provider)
{
super(provider.getBufferCapacity());
this.provider = provider;
}
public IBufferProvider getProvider()
{
return provider;
}
public ReferenceQueue<IBuffer> getReferenceQueue()
{
return referenceQueue;
}
public int getPooledBuffers()
{
return pooledBuffers;
}
public boolean evictOne()
{
for (;;)
{
BufferRef bufferRef = buffers.poll();
if (bufferRef == null)
{
return false;
}
IBuffer buffer = bufferRef.get();
if (buffer != null)
{
if (TRACER.isEnabled())
{
TRACER.trace("Evicting " + buffer); //$NON-NLS-1$
}
provider.retainBuffer(buffer);
--pooledBuffers;
return true;
}
}
}
public int evict(int survivors)
{
int evictedBuffers = 0;
while (pooledBuffers > survivors)
{
if (evictOne())
{
++evictedBuffers;
}
else
{
break;
}
}
return evictedBuffers;
}
@Override
public String toString()
{
return MessageFormat.format("BufferPool[{0}]", getBufferCapacity()); //$NON-NLS-1$
}
protected BufferRef createBufferRef(IBuffer buffer)
{
return new BufferRef(buffer, referenceQueue);
}
@Override
protected IBuffer doProvideBuffer()
{
IBuffer buffer = null;
BufferRef bufferRef = buffers.poll();
if (bufferRef != null)
{
buffer = bufferRef.get();
}
if (buffer == null)
{
buffer = provider.provideBuffer();
((InternalBuffer)buffer).setBufferProvider(this);
}
else
{
--pooledBuffers;
}
buffer.clear();
if (TRACER.isEnabled())
{
TRACER.trace("Obtained " + buffer); //$NON-NLS-1$
}
return buffer;
}
@Override
protected void doRetainBuffer(IBuffer buffer)
{
if (buffer.getCapacity() != getBufferCapacity())
{
throw new IllegalArgumentException("buffer.getCapacity() != getBufferCapacity()"); //$NON-NLS-1$
}
if (TRACER.isEnabled())
{
TRACER.trace("Retaining " + buffer); //$NON-NLS-1$
}
BufferRef bufferRef = createBufferRef(buffer);
buffers.add(bufferRef);
++pooledBuffers;
}
private static final class BufferRef extends SoftReference<IBuffer>
{
public BufferRef(IBuffer buffer, ReferenceQueue<IBuffer> queue)
{
super(buffer, queue);
}
}
}