org.eclipse.jetty.util.LockedPool Maven / Gradle / Ivy
Show all versions of jetty-util Show documentation
//
// ========================================================================
// 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.util;
import java.util.Collection;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jetty.util.thread.AutoLock;
/**
* A {@link Pool.Wrapper} that tracks the acquire/release/remove pool events.
* The acquire/release/remove pool events are forwarded atomically to be handled
* by a {@link Tracker} implementation, so that the pool event and the handling of
* the event by the tracker are atomic.
*
* @param the type of the pooled objects
*/
public class LockedPool
extends Pool.Wrapper
{
private final AutoLock lock = new AutoLock();
private final Tracker
tracker;
public LockedPool(Pool
pool)
{
this(pool, Tracker.noTracker());
}
public LockedPool(Pool
pool, Tracker
tracker)
{
super(pool);
this.tracker = tracker;
}
@Override
public Entry
reserve()
{
try (AutoLock ignored = lock.lock())
{
Entry
entry = super.reserve();
if (entry == null)
return null;
return new LockedEntry(entry);
}
}
@Override
public Entry
acquire()
{
try (AutoLock ignored = lock.lock())
{
Entry
entry = super.acquire();
if (entry == null)
return null;
LockedEntry lockedEntry = new LockedEntry(entry);
tracker.acquired(getWrapped(), entry);
return lockedEntry;
}
}
@Override
public Entry
acquire(Function, P> creator)
{
try (AutoLock ignored = lock.lock())
{
Entry entry = super.acquire(creator);
if (entry == null)
return null;
LockedEntry lockedEntry = new LockedEntry(entry);
tracker.acquired(getWrapped(), entry);
return lockedEntry;
}
}
@Override
public boolean isTerminated()
{
try (AutoLock ignored = lock.lock())
{
return super.isTerminated();
}
}
@Override
public Collection> terminate()
{
try (AutoLock ignored = lock.lock())
{
Collection> result = super.terminate();
tracker.terminated(getWrapped(), result);
return result.stream()
.map(LockedEntry::new)
.collect(Collectors.toList());
}
}
@Override
public int size()
{
try (AutoLock ignored = lock.lock())
{
return super.size();
}
}
@Override
public int getMaxSize()
{
try (AutoLock ignored = lock.lock())
{
return super.getMaxSize();
}
}
@Override
public Stream> stream()
{
try (AutoLock ignored = lock.lock())
{
return super.stream().map(LockedEntry::new);
}
}
private class LockedEntry extends Entry.Wrapper
{
public LockedEntry(Entry
wrapped)
{
super(wrapped);
}
@Override
public boolean release()
{
try (AutoLock ignored = lock.lock())
{
boolean released = super.release();
if (released)
tracker.released(LockedPool.this.getWrapped(), getWrapped());
return released;
}
}
@Override
public boolean remove()
{
try (AutoLock ignored = lock.lock())
{
boolean removed = super.remove();
if (removed)
tracker.removed(LockedPool.this.getWrapped(), getWrapped());
return removed;
}
}
}
/**
*
A {@link Pool.Factory} that wraps newly created
* {@link Pool} instances with {@link LockedPool}.
*
* @param the type of pooled objects
*/
public interface Factory extends Pool.Factory
{
@Override
public default Pool wrap(Pool pool)
{
return new LockedPool<>(pool);
}
}
/**
* A receiver of {@link Pool} events.
* A simple implementations may just count acquire/release/remove
* pool events via, respectively, {@link #acquired(Pool, Entry)},
* {@link #released(Pool, Entry)} and {@link #removed(Pool, Entry)},
* and make sure that the count is {@code 0} when
* {@link #terminated(Pool, Collection)} is called.
* More advanced implementations may also obtain a stack trace at
* the time of the event to troubleshoot leaking of pooled entries.
*
* @param the type of pooled objects
*/
public interface Tracker
{
/**
* @return a no-op implementation of {@code Tracker}
* @param the type of pooled objects
*/
@SuppressWarnings("unchecked")
public static Tracker noTracker()
{
class NoTracker implements Tracker
{
private static final Tracker> INSTANCE = new NoTracker();
}
return (Tracker)NoTracker.INSTANCE;
}
/**
* Callback method invoked when an entry is
* {@link Pool#acquire() acquired}.
*
* @param pool the pool
* @param entry the acquired entry
*/
public default void acquired(Pool pool, Entry entry)
{
}
/**
* Callback method invoked when an entry is
* {@link Entry#release() released}.
*
* @param pool the pool
* @param entry the released entry
*/
public default void released(Pool pool, Entry entry)
{
}
/**
* Callback method invoked when an entry is
* {@link Entry#remove() removed}.
*
* @param pool the pool
* @param entry the removed entry
*/
public default void removed(Pool pool, Entry entry)
{
}
/**
* Callback method invoked when the {@code Pool}
* is {@link Pool#terminate() terminated}.
*
* @param pool the pool
* @param entries the list of entries at termination
*/
public default void terminated(Pool pool, Collection> entries)
{
}
}
}