diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2021-10-04 17:20:40 +0200 |
---|---|---|
committer | Henning Baldersheim <balder@yahoo-inc.com> | 2021-10-05 14:49:20 +0200 |
commit | c9982ddc5ce3083101541a301cca20b19b4914e8 (patch) | |
tree | f63fa1165e4b8572a7dd7c24ed056e851b97660d /jdisc_core | |
parent | 5f5cb7aa87195c92b374dcbc742a5263559c8bb0 (diff) |
Add option to attach a context to refer.
Introduce a lightweight debug mode.
Diffstat (limited to 'jdisc_core')
15 files changed, 412 insertions, 161 deletions
diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/AbstractResource.java b/jdisc_core/src/main/java/com/yahoo/jdisc/AbstractResource.java index 05c3582a541..a5b5dad2583 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/AbstractResource.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/AbstractResource.java @@ -2,16 +2,13 @@ package com.yahoo.jdisc; import com.yahoo.jdisc.handler.RequestHandler; +import com.yahoo.jdisc.refcount.DebugReferencesByContextMap; +import com.yahoo.jdisc.refcount.DebugReferencesWithStack; +import com.yahoo.jdisc.refcount.DestructableResource; +import com.yahoo.jdisc.refcount.ReferencesByCount; import com.yahoo.jdisc.service.ClientProvider; import com.yahoo.jdisc.service.ServerProvider; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; -import java.util.logging.Logger; +import com.yahoo.jdisc.refcount.References; /** * This class provides a thread-safe implementation of the {@link SharedResource} interface, and should be used for @@ -22,75 +19,33 @@ import java.util.logging.Logger; */ public abstract class AbstractResource implements SharedResource { - private static final Logger log = Logger.getLogger(AbstractResource.class.getName()); + private static final Debug debug = DEBUG; - private final boolean debug = SharedResource.DEBUG; - private final AtomicInteger refCount; - private final Object monitor; - private final Set<Throwable> activeReferences; - private final ResourceReference initialCreationReference; + private final References references; protected AbstractResource() { - if (!debug) { - this.refCount = new AtomicInteger(1); - this.monitor = null; - this.activeReferences = null; - this.initialCreationReference = new NoDebugResourceReference(this); + DestructableResource destructable = new WrappedResource(this); + if (debug == Debug.SIMPLE) { + references = new DebugReferencesByContextMap(destructable, this); + } else if (debug == Debug.STACK) { + references = new DebugReferencesWithStack(destructable); } else { - this.refCount = null; - this.monitor = new Object(); - this.activeReferences = new HashSet<>(); - final Throwable referenceStack = new Throwable(); - this.activeReferences.add(referenceStack); - this.initialCreationReference = new DebugResourceReference(this, referenceStack); + references = new ReferencesByCount(destructable); } } @Override public final ResourceReference refer() { - if (!debug) { - addRef(1); - return new NoDebugResourceReference(this); - } - - final Throwable referenceStack = new Throwable(); - final String state; - synchronized (monitor) { - if (activeReferences.isEmpty()) { - throw new IllegalStateException("Object is already destroyed, no more new references may be created." - + " State={ " + currentStateDebugWithLock() + " }"); - } - activeReferences.add(referenceStack); - state = currentStateDebugWithLock(); - } - log.log(Level.FINE, referenceStack, () -> - getClass().getName() + "@" + System.identityHashCode(this) + ".refer(): state={ " + state + " }"); - return new DebugResourceReference(this, referenceStack); + return refer(null); } - @Override - public final void release() { - initialCreationReference.close(); + public final ResourceReference refer(Object context) { + return references.refer(context); } - private void removeReferenceStack(final Throwable referenceStack, final Throwable releaseStack) { - final boolean doDestroy; - final String state; - synchronized (monitor) { - final boolean wasThere = activeReferences.remove(referenceStack); - state = currentStateDebugWithLock(); - if (!wasThere) { - throw new IllegalStateException("Reference is already released and can only be released once." - + " reference=" + Arrays.toString(referenceStack.getStackTrace()) - + ". State={ " + state + "}"); - } - doDestroy = activeReferences.isEmpty(); - } - log.log(Level.FINE, releaseStack, - () ->getClass().getName() + "@" + System.identityHashCode(this) + " release: state={ " + state + " }"); - if (doDestroy) { - destroy(); - } + @Override + public final void release() { + references.release(); } /** @@ -100,105 +55,25 @@ public abstract class AbstractResource implements SharedResource { * @return The current value of the reference counter. */ public final int retainCount() { - if (!debug) { - return refCount.get(); - } - - synchronized (monitor) { - return activeReferences.size(); - } + return references.referenceCount(); } /** * <p>This method signals that this AbstractResource can dispose of any internal resources, and commence with shut * down of any internal threads. This will be called once the reference count of this resource reaches zero.</p> */ - protected void destroy() { - - } - - private int addRef(int value) { - while (true) { - int prev = refCount.get(); - if (prev == 0) { - throw new IllegalStateException(getClass().getName() + ".addRef(" + value + "):" - + " Object is already destroyed." - + " Consider toggling the " + SharedResource.SYSTEM_PROPERTY_NAME_DEBUG - + " system property to get debugging assistance with reference tracking."); - } - int next = prev + value; - if (refCount.compareAndSet(prev, next)) { - return next; - } - } - } + protected void destroy() { } /** * Returns a string describing the current state of references in human-friendly terms. May be used for debugging. */ public String currentState() { - if (!debug) { - return "Active references: " + refCount.get() + "." - + " Resource reference debugging is turned off. Consider toggling the " - + SharedResource.SYSTEM_PROPERTY_NAME_DEBUG - + " system property to get debugging assistance with reference tracking."; - } - synchronized (monitor) { - return currentStateDebugWithLock(); - } - } - - private String currentStateDebugWithLock() { - return "Active references: " + makeListOfActiveReferences(); - } - - private String makeListOfActiveReferences() { - final StringBuilder builder = new StringBuilder(); - builder.append("["); - for (final Throwable activeReference : activeReferences) { - builder.append(" "); - builder.append(Arrays.toString(activeReference.getStackTrace())); - } - builder.append(" ]"); - return builder.toString(); - } - - private static class NoDebugResourceReference implements ResourceReference { - private final AbstractResource resource; - private final AtomicBoolean isReleased = new AtomicBoolean(false); - - public NoDebugResourceReference(final AbstractResource resource) { - this.resource = resource; - } - - @Override - public final void close() { - final boolean wasReleasedBefore = isReleased.getAndSet(true); - if (wasReleasedBefore) { - final String message = "Reference is already released and can only be released once." - + " State={ " + resource.currentState() + " }"; - throw new IllegalStateException(message); - } - int refCount = resource.addRef(-1); - if (refCount == 0) { - resource.destroy(); - } - } + return references.currentState(); } - private static class DebugResourceReference implements ResourceReference { + static private class WrappedResource implements DestructableResource { private final AbstractResource resource; - private final Throwable referenceStack; - - public DebugResourceReference(final AbstractResource resource, final Throwable referenceStack) { - this.resource = resource; - this.referenceStack = referenceStack; - } - - @Override - public final void close() { - final Throwable releaseStack = new Throwable(); - resource.removeReferenceStack(referenceStack, releaseStack); - } + WrappedResource(AbstractResource resource) { this.resource = resource; } + @Override public void close() { resource.destroy(); } } } diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/Request.java b/jdisc_core/src/main/java/com/yahoo/jdisc/Request.java index e2cde8e806c..eeb787e59dd 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/Request.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/Request.java @@ -87,7 +87,7 @@ public class Request extends AbstractResource { parentReference = null; serverRequest = isServerRequest; setUri(uri); - container = current.newReference(uri); + container = current.newReference(uri, this); creationTime = container.currentTimeMillis(); } diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/SharedResource.java b/jdisc_core/src/main/java/com/yahoo/jdisc/SharedResource.java index 20656bf7d1d..dee0f8ee410 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/SharedResource.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/SharedResource.java @@ -28,10 +28,22 @@ import com.yahoo.jdisc.service.ServerProvider; public interface SharedResource { String SYSTEM_PROPERTY_NAME_DEBUG = "jdisc.debug.resources"; - boolean DEBUG = Boolean.valueOf(System.getProperty(SYSTEM_PROPERTY_NAME_DEBUG)); + enum Debug {NO, SIMPLE, STACK} + Debug DEBUG = valueOfDebug(); + private static Debug valueOfDebug() { + String val = System.getProperty(SYSTEM_PROPERTY_NAME_DEBUG); + if (val != null) { + val = val.toUpperCase(); + if (Boolean.valueOf(val)) return Debug.SIMPLE; + try { + return Debug.valueOf(val); + } catch (IllegalArgumentException e) { } + } + return Debug.NO; + } /** - * <p>Increments the reference count of this resource. You call this method to prevent an object from being + * <p>Creates a reference to this resource. You call this method to prevent an object from being * destroyed until you have finished using it.</p> * * <p>You MUST keep the returned {@link ResourceReference} object and release the reference by calling @@ -43,6 +55,21 @@ public interface SharedResource { ResourceReference refer(); /** + * <p>Creates a reference to this resource. You call this method to prevent an object from being + * destroyed until you have finished using it. You can attach a context that will live as long as the reference.</p> + * + * @param context A context to be associated with the reference. It should give some clue as to who referenced it. + * <p>You MUST keep the returned {@link ResourceReference} object and release the reference by calling + * {@link ResourceReference#close()} on it. A reference created by this method can NOT be released by calling + * {@link #release()}.</p> + * + * @see ResourceReference#close() + */ + default ResourceReference refer(Object context) { + return refer(); + } + + /** * <p>Releases the "main" reference to this resource (the implicit reference due to creation of the object).</p> * * <p>References obtained by calling {@link #refer()} must be released by calling {@link ResourceReference#close()} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/core/ActiveContainer.java b/jdisc_core/src/main/java/com/yahoo/jdisc/core/ActiveContainer.java index a9fd2c747ff..1e76f34939f 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/core/ActiveContainer.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/core/ActiveContainer.java @@ -106,7 +106,7 @@ public class ActiveContainer extends AbstractResource implements CurrentContaine } @Override - public ContainerSnapshot newReference(URI uri) { + public ContainerSnapshot newReference(URI uri, Object context) { String name = bindingSetSelector.select(uri); if (name == null) { throw new NoBindingSetSelectedException(uri); @@ -116,7 +116,7 @@ public class ActiveContainer extends AbstractResource implements CurrentContaine if (serverBindings == null || clientBindings == null) { throw new BindingSetNotFoundException(name); } - return new ContainerSnapshot(this, serverBindings, clientBindings); + return new ContainerSnapshot(this, serverBindings, clientBindings, context); } } diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/core/ApplicationLoader.java b/jdisc_core/src/main/java/com/yahoo/jdisc/core/ApplicationLoader.java index f28731a47c7..34fcd2be9ba 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/core/ApplicationLoader.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/core/ApplicationLoader.java @@ -81,12 +81,12 @@ public class ApplicationLoader implements BootstrapLoader, ContainerActivator, C } @Override - public ContainerSnapshot newReference(URI uri) { + public ContainerSnapshot newReference(URI uri, Object context) { ActiveContainer container = containerRef.get(); if (container == null) { throw new ContainerNotReadyException(); } - return container.newReference(uri); + return container.newReference(uri, context); } @Override diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/core/ContainerSnapshot.java b/jdisc_core/src/main/java/com/yahoo/jdisc/core/ContainerSnapshot.java index 7b72e95ac09..becfa94e71f 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/core/ContainerSnapshot.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/core/ContainerSnapshot.java @@ -28,13 +28,13 @@ class ContainerSnapshot extends AbstractResource implements Container { private final BindingSet<RequestHandler> clientBindings; ContainerSnapshot(ActiveContainer container, BindingSet<RequestHandler> serverBindings, - BindingSet<RequestHandler> clientBindings) + BindingSet<RequestHandler> clientBindings, Object context) { this.timeoutMgr = container.timeoutManager(); this.container = container; this.serverBindings = serverBindings; this.clientBindings = clientBindings; - this.containerReference = container.refer(); + this.containerReference = container.refer(context); } @Override diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/CloseableOnce.java b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/CloseableOnce.java new file mode 100644 index 00000000000..f5b41c5ee9f --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/CloseableOnce.java @@ -0,0 +1,27 @@ +package com.yahoo.jdisc.refcount; + +import com.yahoo.jdisc.ResourceReference; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Ensures that a ResourceReference can only be closed exactly once. + * + * @author baldersheim + */ +abstract class CloseableOnce implements ResourceReference { + private final AtomicBoolean isReleased = new AtomicBoolean(false); + + @Override + public final void close() { + final boolean wasReleasedBefore = isReleased.getAndSet(true); + if (wasReleasedBefore) { + final String message = "Reference is already released and can only be released once." + + " State={ " + getReferences().currentState() + " }"; + throw new IllegalStateException(message); + } + onClose(); + } + abstract void onClose(); + abstract References getReferences(); +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/DebugReferencesByContextMap.java b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/DebugReferencesByContextMap.java new file mode 100644 index 00000000000..e18980967c8 --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/DebugReferencesByContextMap.java @@ -0,0 +1,80 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.refcount; + +import com.yahoo.jdisc.ResourceReference; + +import java.util.HashMap; +import java.util.Map; + +/** + * Does reference counting by putting a unique key together with optional context in map + * Used if system property jdisc.debug.resources=simple/true + * + * @author baldersheim + */ +public class DebugReferencesByContextMap implements References { + private final Map<Object, Object> contextMap = new HashMap<>(); + private final DestructableResource resource; + private final Reference initialReference; + private long contextId = 1; + + public DebugReferencesByContextMap(DestructableResource resource, Object context) { + this.resource = resource; + Long key = 0L; + initialReference = new Reference(this, key); + contextMap.put(key, context); + } + + @Override + public void release() { + initialReference.close(); + } + + @Override + public int referenceCount() { + synchronized (contextMap) { return contextMap.size(); } + } + + @Override + public ResourceReference refer(Object context) { + synchronized (contextMap) { + if (contextMap.isEmpty()) { + throw new IllegalStateException("Object is already destroyed, no more new references may be created." + + " State={ " + currentState() + " }"); + } + Long key = contextId++; + contextMap.put(key, context != null ? context : key); + return new Reference(this, key); + } + } + + private void removeRef(Long key) { + synchronized (contextMap) { + contextMap.remove(key); + if (contextMap.isEmpty()) { + resource.close(); + } + } + } + + @Override + public String currentState() { + synchronized (contextMap) { + return contextMap.toString(); + } + } + + private static class Reference extends CloseableOnce { + private final DebugReferencesByContextMap references; + private final Long key; + + Reference(DebugReferencesByContextMap references, Long key) { + this.references = references; + this.key = key; + } + + @Override final void onClose() { references.removeRef(key); } + @Override + final References getReferences() { return references; } + } +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/DebugReferencesWithStack.java b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/DebugReferencesWithStack.java new file mode 100644 index 00000000000..db6c266534f --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/DebugReferencesWithStack.java @@ -0,0 +1,114 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.refcount; + +import com.yahoo.jdisc.ResourceReference; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Does reference counting by putting stacktraces in a map together with an optional context. + * Intended only for debugging as it is slow. + * Used if system property jdisc.debug.resources=stack + * + * @author baldersheim + */ +public class DebugReferencesWithStack implements References { + private static final Logger log = Logger.getLogger(DebugReferencesWithStack.class.getName()); + private final Map<Throwable, Object> activeReferences = new HashMap<>(); + private final DestructableResource resource; + private final DebugResourceReference initialreference; + + public DebugReferencesWithStack(DestructableResource resource) { + final Throwable referenceStack = new Throwable(); + this.activeReferences.put(referenceStack, this); + this.resource = resource; + initialreference = new DebugResourceReference(this, referenceStack); + } + + @Override + public void release() { + initialreference.close(); + } + + @Override + public int referenceCount() { + synchronized (activeReferences) { + return activeReferences.size(); + } + } + + @Override + public ResourceReference refer(Object context) { + final Throwable referenceStack = new Throwable(); + synchronized (activeReferences) { + if (activeReferences.isEmpty()) { + throw new IllegalStateException("Object is already destroyed, no more new references may be created." + + " State={ " + currentState() + " }"); + } + activeReferences.put(referenceStack, context); + } + log.log(Level.FINE, referenceStack, () -> + getClass().getName() + "@" + System.identityHashCode(this) + ".refer(): state={ " + currentState() + " }"); + return new DebugResourceReference(this, referenceStack); + } + + private void removeReferenceStack(final Throwable referenceStack, final Throwable releaseStack) { + final boolean doDestroy; + synchronized (activeReferences) { + final boolean wasThere = activeReferences.containsKey(referenceStack); + activeReferences.remove(referenceStack); + if (!wasThere) { + throw new IllegalStateException("Reference is already released and can only be released once." + + " reference=" + Arrays.toString(referenceStack.getStackTrace()) + + ". State={ " + currentState() + "}"); + } + doDestroy = activeReferences.isEmpty(); + log.log(Level.FINE, releaseStack, + () -> getClass().getName() + "@" + System.identityHashCode(this) + " release: state={ " + currentState() + " }"); + } + + if (doDestroy) { + resource.close(); + } + } + + @Override + public String currentState() { + return "Active references: " + makeListOfActiveReferences(); + } + + private String makeListOfActiveReferences() { + final StringBuilder builder = new StringBuilder(); + builder.append("["); + synchronized (activeReferences) { + for (var activeReference : activeReferences.entrySet()) { + builder.append(" "); + builder.append(Arrays.toString(activeReference.getKey().getStackTrace())); + } + } + builder.append(" ]"); + return builder.toString(); + } + + private static class DebugResourceReference extends CloseableOnce { + private final DebugReferencesWithStack resource; + private final Throwable referenceStack; + + public DebugResourceReference(DebugReferencesWithStack resource, final Throwable referenceStack) { + this.resource = resource; + this.referenceStack = referenceStack; + } + + @Override + final void onClose() { + final Throwable releaseStack = new Throwable(); + resource.removeReferenceStack(referenceStack, releaseStack); + } + @Override + final References getReferences() { return resource; } + } +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/DestructableResource.java b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/DestructableResource.java new file mode 100644 index 00000000000..b373473f214 --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/DestructableResource.java @@ -0,0 +1,11 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.refcount; + +public interface DestructableResource extends AutoCloseable { + + /** + * Wrapper to allow access to protected AbstractResource.destroy() + */ + @Override + void close(); +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/References.java b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/References.java new file mode 100644 index 00000000000..35b4e7c759e --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/References.java @@ -0,0 +1,22 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.refcount; + +import com.yahoo.jdisc.ResourceReference; + +/** + * Interface for implementations of reference counting + * @author baldersheim + */ +public interface References { + /** Release the initial reference */ + void release(); + /** Returns number of held references */ + int referenceCount(); + /** + * Adds a reference and return an objects that when closed will return the reference. + * Supply a context that can provide link to the one holding the link. Useful for debugging + */ + ResourceReference refer(Object context); + + String currentState(); +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/ReferencesByCount.java b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/ReferencesByCount.java new file mode 100644 index 00000000000..0f417c81a8b --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/ReferencesByCount.java @@ -0,0 +1,83 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.refcount; + +import com.yahoo.jdisc.ResourceReference; +import com.yahoo.jdisc.SharedResource; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Does reference counting by using atomic counting of references + * Default in production + * + * @author baldersheim + */ +public class ReferencesByCount implements References { + private final AtomicInteger refCount; + private final DestructableResource resource; + private final NoDebugResourceReference initialReference; + + public ReferencesByCount(DestructableResource resource) { + refCount = new AtomicInteger(1); + this.resource = resource; + initialReference = new NoDebugResourceReference(this); + } + + @Override + public void release() { + initialReference.close(); + } + + @Override + public int referenceCount() { + return refCount.get(); + } + + @Override + public ResourceReference refer(Object context) { + addRef(1); + return new NoDebugResourceReference(this); + } + + @Override + public String currentState() { + return "Active references: " + refCount.get() + "." + + " Resource reference debugging is turned off. Consider toggling the " + + SharedResource.SYSTEM_PROPERTY_NAME_DEBUG + + " system property to get debugging assistance with reference tracking."; + } + + private void removeRef() { + int refCount = addRef(-1); + if (refCount == 0) { + resource.close(); + } + } + + private int addRef(int value) { + while (true) { + int prev = refCount.get(); + if (prev == 0) { + throw new IllegalStateException(getClass().getName() + ".addRef(" + value + "):" + + " Object is already destroyed." + + " Consider toggling the " + SharedResource.SYSTEM_PROPERTY_NAME_DEBUG + + " system property to get debugging assistance with reference tracking."); + } + int next = prev + value; + if (refCount.compareAndSet(prev, next)) { + return next; + } + } + } + + private static class NoDebugResourceReference extends CloseableOnce { + private final ReferencesByCount resource; + + NoDebugResourceReference(final ReferencesByCount resource) { + this.resource = resource; + } + + @Override final void onClose() { resource.removeRef(); } + @Override References getReferences() { return resource; } + } +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/package-info.java b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/package-info.java new file mode 100644 index 00000000000..0797951df9e --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/refcount/package-info.java @@ -0,0 +1,4 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +@com.yahoo.osgi.annotation.ExportPackage +package com.yahoo.jdisc.refcount; diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/CurrentContainer.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/CurrentContainer.java index 9b7af7e49f5..f0a39e0f045 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/service/CurrentContainer.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/CurrentContainer.java @@ -27,11 +27,19 @@ public interface CurrentContainer { * * @param uri The identifier used to match this Request to an appropriate {@link ClientProvider} or {@link * RequestHandler}. The hostname must be "localhost" or a fully qualified domain name. + * @param context that can be attached for reference tracking * @return A reference to the current Container. * @throws NoBindingSetSelectedException If no {@link BindingSet} was selected by the {@link BindingSetSelector}. * @throws BindingSetNotFoundException If the named BindingSet was not found. * @throws ContainerNotReadyException If no active Container was found, this can only happen during initial * setup. */ - public Container newReference(URI uri); + default Container newReference(URI uri, Object context) { + return newReference(uri); + } + + default Container newReference(URI uri) { + return newReference(uri, null); + } + } diff --git a/jdisc_core/src/test/java/com/yahoo/jdisc/core/ContainerSnapshotTestCase.java b/jdisc_core/src/test/java/com/yahoo/jdisc/core/ContainerSnapshotTestCase.java index ac2efafbba5..472ac095188 100644 --- a/jdisc_core/src/test/java/com/yahoo/jdisc/core/ContainerSnapshotTestCase.java +++ b/jdisc_core/src/test/java/com/yahoo/jdisc/core/ContainerSnapshotTestCase.java @@ -146,7 +146,7 @@ public class ContainerSnapshotTestCase { } }); ActiveContainer active = new ActiveContainer(driver.newContainerBuilder()); - ContainerSnapshot snapshot = new ContainerSnapshot(active, null, null); + ContainerSnapshot snapshot = new ContainerSnapshot(active, null, null, null); assertSame(obj, snapshot.getInstance(Object.class)); assertEquals("foo", snapshot.getInstance(Key.get(String.class, Names.named("foo")))); snapshot.release(); |