X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=liblttng-ust-java-agent%2Fjava%2Flttng-ust-agent-common%2Forg%2Flttng%2Fust%2Fagent%2FAbstractLttngAgent.java;fp=liblttng-ust-java-agent%2Fjava%2Flttng-ust-agent-common%2Forg%2Flttng%2Fust%2Fagent%2FAbstractLttngAgent.java;h=0000000000000000000000000000000000000000;hb=9d4c8b2d907edb9ebc9bfde55602598e7ba0832e;hp=acbdc4f124512225828f900369522db6b81348d8;hpb=6ba6fd60507f8e045bdc4f1be14e9d99c6a15f7f;p=lttng-ust.git diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java deleted file mode 100644 index acbdc4f1..00000000 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.regex.Matcher; - -import org.lttng.ust.agent.client.ILttngTcpClientListener; -import org.lttng.ust.agent.client.LttngTcpSessiondClient; -import org.lttng.ust.agent.filter.FilterChangeNotifier; -import org.lttng.ust.agent.session.EventRule; -import org.lttng.ust.agent.utils.LttngUstAgentLogger; - -/** - * Base implementation of a {@link ILttngAgent}. - * - * @author Alexandre Montplaisir - * @param - * The type of logging handler that should register to this agent - */ -public abstract class AbstractLttngAgent - implements ILttngAgent, ILttngTcpClientListener { - - private static final int INIT_TIMEOUT = 3; /* Seconds */ - - /** The handlers registered to this agent */ - private final Set registeredHandlers = new HashSet(); - - /** - * The trace events currently enabled in the sessions. - * - * The key is the {@link EventNamePattern} that comes from the event name. - * The value is the ref count (how many different sessions currently have - * this event enabled). Once the ref count falls to 0, this means we can - * avoid sending log events through JNI because nobody wants them. - * - * Its accesses should be protected by the {@link #enabledEventNamesLock} - * below. - */ - private final Map enabledPatterns = new HashMap(); - - /** - * Cache of already-checked event names. As long as enabled/disabled events - * don't change in the session, we can avoid re-checking events that were - * previously checked against all known enabled patterns. - * - * Its accesses should be protected by the {@link #enabledEventNamesLock} - * below, with the exception of concurrent get operations. - */ - private final Map enabledEventNamesCache = new ConcurrentHashMap(); - - /** - * Lock protecting accesses to the {@link #enabledPatterns} and - * {@link #enabledEventNamesCache} maps. - */ - private final Lock enabledEventNamesLock = new ReentrantLock(); - - /** - * The application contexts currently enabled in the tracing sessions. - * - * It is first indexed by context retriever, then by context name. This - * allows to efficiently query all the contexts for a given retriever. - * - * Works similarly as {@link #enabledEvents}, but for app contexts (and with - * an extra degree of indexing). - * - * TODO Could be changed to a Guava Table once/if we start using it. - */ - private final Map> enabledAppContexts = new ConcurrentHashMap>(); - - /** Tracing domain. Defined by the sub-classes via the constructor. */ - private final Domain domain; - - /* Lazy-loaded sessiond clients and their thread objects */ - private LttngTcpSessiondClient rootSessiondClient = null; - private LttngTcpSessiondClient userSessiondClient = null; - private Thread rootSessiondClientThread = null; - private Thread userSessiondClientThread = null; - - /** Indicates if this agent has been initialized. */ - private boolean initialized = false; - - /** - * Constructor. Should only be called by sub-classes via super(...); - * - * @param domain - * The tracing domain of this agent. - */ - protected AbstractLttngAgent(Domain domain) { - this.domain = domain; - } - - @Override - public Domain getDomain() { - return domain; - } - - @Override - public void registerHandler(T handler) { - synchronized (registeredHandlers) { - if (registeredHandlers.isEmpty()) { - /* - * This is the first handler that registers, we will initialize - * the agent. - */ - init(); - } - registeredHandlers.add(handler); - } - } - - @Override - public void unregisterHandler(T handler) { - synchronized (registeredHandlers) { - registeredHandlers.remove(handler); - if (registeredHandlers.isEmpty()) { - /* There are no more registered handlers, close the connection. */ - dispose(); - } - } - } - - private void init() { - /* - * Only called from a synchronized (registeredHandlers) block, should - * not need additional synchronization. - */ - if (initialized) { - return; - } - - LttngUstAgentLogger.log(AbstractLttngAgent.class, "Initializing Agent for domain: " + domain.name()); - - String rootClientThreadName = "Root sessiond client started by agent: " + this.getClass().getSimpleName(); - - rootSessiondClient = new LttngTcpSessiondClient(this, getDomain().value(), true); - rootSessiondClientThread = new Thread(rootSessiondClient, rootClientThreadName); - rootSessiondClientThread.setDaemon(true); - rootSessiondClientThread.start(); - - String userClientThreadName = "User sessiond client started by agent: " + this.getClass().getSimpleName(); - - userSessiondClient = new LttngTcpSessiondClient(this, getDomain().value(), false); - userSessiondClientThread = new Thread(userSessiondClient, userClientThreadName); - userSessiondClientThread.setDaemon(true); - userSessiondClientThread.start(); - - /* Give the threads' registration a chance to end. */ - if (!rootSessiondClient.waitForConnection(INIT_TIMEOUT)) { - userSessiondClient.waitForConnection(INIT_TIMEOUT); - } - - initialized = true; - } - - /** - * Dispose the agent - */ - private void dispose() { - LttngUstAgentLogger.log(AbstractLttngAgent.class, "Disposing Agent for domain: " + domain.name()); - - /* - * Only called from a synchronized (registeredHandlers) block, should - * not need additional synchronization. - */ - rootSessiondClient.close(); - userSessiondClient.close(); - - try { - rootSessiondClientThread.join(); - userSessiondClientThread.join(); - - } catch (InterruptedException e) { - e.printStackTrace(); - } - rootSessiondClient = null; - rootSessiondClientThread = null; - userSessiondClient = null; - userSessiondClientThread = null; - - /* - * Send filter change notifications for all event rules currently - * active, then clear them. - */ - FilterChangeNotifier fcn = FilterChangeNotifier.getInstance(); - - enabledEventNamesLock.lock(); - try { - for (Map.Entry entry : enabledPatterns.entrySet()) { - String eventName = entry.getKey().getEventName(); - Integer nb = entry.getValue(); - for (int i = 0; i < nb.intValue(); i++) { - fcn.removeEventRules(eventName); - } - } - enabledPatterns.clear(); - enabledEventNamesCache.clear(); - } finally { - enabledEventNamesLock.unlock(); - } - - /* - * Also clear tracked app contexts (no filter notifications sent for - * those currently). - */ - enabledAppContexts.clear(); - - initialized = false; - } - - @Override - public boolean eventEnabled(EventRule eventRule) { - /* Notify the filter change manager of the command */ - FilterChangeNotifier.getInstance().addEventRule(eventRule); - - String eventName = eventRule.getEventName(); - EventNamePattern pattern = new EventNamePattern(eventName); - - enabledEventNamesLock.lock(); - try { - boolean ret = incrementRefCount(pattern, enabledPatterns); - enabledEventNamesCache.clear(); - return ret; - } finally { - enabledEventNamesLock.unlock(); - } - } - - @Override - public boolean eventDisabled(String eventName) { - /* Notify the filter change manager of the command */ - FilterChangeNotifier.getInstance().removeEventRules(eventName); - - EventNamePattern pattern = new EventNamePattern(eventName); - - enabledEventNamesLock.lock(); - try { - boolean ret = decrementRefCount(pattern, enabledPatterns); - enabledEventNamesCache.clear(); - return ret; - } finally { - enabledEventNamesLock.unlock(); - } - } - - @Override - public boolean appContextEnabled(String contextRetrieverName, String contextName) { - synchronized (enabledAppContexts) { - Map retrieverMap = enabledAppContexts.get(contextRetrieverName); - if (retrieverMap == null) { - /* There is no submap for this retriever, let's create one. */ - retrieverMap = new ConcurrentHashMap(); - enabledAppContexts.put(contextRetrieverName, retrieverMap); - } - - return incrementRefCount(contextName, retrieverMap); - } - } - - @Override - public boolean appContextDisabled(String contextRetrieverName, String contextName) { - synchronized (enabledAppContexts) { - Map retrieverMap = enabledAppContexts.get(contextRetrieverName); - if (retrieverMap == null) { - /* There was no submap for this retriever, invalid command? */ - return false; - } - - boolean ret = decrementRefCount(contextName, retrieverMap); - - /* If the submap is now empty we can remove it from the main map. */ - if (retrieverMap.isEmpty()) { - enabledAppContexts.remove(contextRetrieverName); - } - - return ret; - } - } - - /* - * Implementation of this method is domain-specific. - */ - @Override - public abstract Collection listAvailableEvents(); - - @Override - public boolean isEventEnabled(String eventName) { - Boolean cachedEnabled = enabledEventNamesCache.get(eventName); - if (cachedEnabled != null) { - /* We have seen this event previously */ - /* - * Careful! enabled == null could also mean that the null value is - * associated with the key. But we should have never inserted null - * values in the map. - */ - return cachedEnabled.booleanValue(); - } - - /* - * We have not previously checked this event. Run it against all known - * enabled event patterns to determine if it should pass or not. - */ - enabledEventNamesLock.lock(); - try { - boolean enabled = false; - for (EventNamePattern enabledPattern : enabledPatterns.keySet()) { - Matcher matcher = enabledPattern.getPattern().matcher(eventName); - if (matcher.matches()) { - enabled = true; - break; - } - } - - /* Add the result to the cache */ - enabledEventNamesCache.put(eventName, Boolean.valueOf(enabled)); - return enabled; - - } finally { - enabledEventNamesLock.unlock(); - } - } - - @Override - public Collection>> getEnabledAppContexts() { - return enabledAppContexts.entrySet(); - } - - private static boolean incrementRefCount(T key, Map refCountMap) { - synchronized (refCountMap) { - Integer count = refCountMap.get(key); - if (count == null) { - /* This is the first instance of this event being enabled */ - refCountMap.put(key, Integer.valueOf(1)); - return true; - } - if (count.intValue() <= 0) { - /* It should not have been in the map in the first place! */ - throw new IllegalStateException(); - } - /* The event was already enabled, increment its refcount */ - refCountMap.put(key, Integer.valueOf(count.intValue() + 1)); - return true; - } - } - - private static boolean decrementRefCount(T key, Map refCountMap) { - synchronized (refCountMap) { - Integer count = refCountMap.get(key); - if (count == null || count.intValue() <= 0) { - /* - * The sessiond asked us to disable an event that was not - * enabled previously. Command error? - */ - return false; - } - if (count.intValue() == 1) { - /* - * This is the last instance of this event being disabled, - * remove it from the map so that we stop sending it. - */ - refCountMap.remove(key); - return true; - } - /* - * Other sessions are still looking for this event, simply decrement - * its refcount. - */ - refCountMap.put(key, Integer.valueOf(count.intValue() - 1)); - return true; - } - } -} -