X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust-java-agent%2Fjava%2Flttng-ust-agent-common%2Forg%2Flttng%2Fust%2Fagent%2FAbstractLttngAgent.java;h=acbdc4f124512225828f900369522db6b81348d8;hb=c0c0989ab70574e09b2f7e8b48c2da6af664a849;hp=f8ad187bd99ce5e204a1a8d37dc4fb1fbb289936;hpb=e7a87e50da7383e013bf7250464df0b838cffca2;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 index f8ad187b..acbdc4f1 100644 --- 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 @@ -1,36 +1,28 @@ /* - * Copyright (C) 2015 - EfficiOS Inc., Alexandre Montplaisir - * Copyright (C) 2013 - David Goulet + * SPDX-License-Identifier: LGPL-2.1-only * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License, version 2.1 only, - * as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 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.NavigableMap; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentSkipListMap; -import java.util.concurrent.atomic.AtomicInteger; +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}. @@ -42,7 +34,6 @@ import org.lttng.ust.agent.session.EventRule; public abstract class AbstractLttngAgent implements ILttngAgent, ILttngTcpClientListener { - private static final String WILDCARD = "*"; private static final int INIT_TIMEOUT = 3; /* Seconds */ /** The handlers registered to this agent */ @@ -51,29 +42,31 @@ public abstract class AbstractLttngAgent /** * The trace events currently enabled in the sessions. * - * The key represents 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. + * 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. * - * It uses a concurrent hash map, so that the {@link #isEventEnabled} and - * read methods do not need to take a synchronization lock. + * Its accesses should be protected by the {@link #enabledEventNamesLock} + * below. */ - private final Map enabledEvents = new ConcurrentHashMap(); + private final Map enabledPatterns = new HashMap(); /** - * The trace events prefixes currently enabled in the sessions, which means - * the event names finishing in *, like "abcd*". We track them separately - * from the standard event names, so that we can use {@link String#equals} - * and {@link String#startsWith} appropriately. + * 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. * - * We track the lone wildcard "*" separately, in {@link #enabledWildcards}. + * Its accesses should be protected by the {@link #enabledEventNamesLock} + * below, with the exception of concurrent get operations. */ - private final NavigableMap enabledEventPrefixes = - new ConcurrentSkipListMap(); + private final Map enabledEventNamesCache = new ConcurrentHashMap(); - /** Number of sessions currently enabling the wildcard "*" event */ - private final AtomicInteger enabledWildcards = new AtomicInteger(0); + /** + * 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. @@ -148,6 +141,9 @@ public abstract class AbstractLttngAgent 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); @@ -174,6 +170,8 @@ public abstract class AbstractLttngAgent * 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. @@ -193,11 +191,31 @@ public abstract class AbstractLttngAgent userSessiondClient = null; userSessiondClientThread = null; - /* Reset all enabled event counts to 0 */ - enabledEvents.clear(); - enabledEventPrefixes.clear(); - enabledWildcards.set(0); + /* + * 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; @@ -209,18 +227,16 @@ public abstract class AbstractLttngAgent FilterChangeNotifier.getInstance().addEventRule(eventRule); String eventName = eventRule.getEventName(); + EventNamePattern pattern = new EventNamePattern(eventName); - if (eventName.equals(WILDCARD)) { - enabledWildcards.incrementAndGet(); - return true; - } - if (eventName.endsWith(WILDCARD)) { - /* Strip the "*" from the name. */ - String prefix = eventName.substring(0, eventName.length() - 1); - return incrementRefCount(prefix, enabledEventPrefixes); + enabledEventNamesLock.lock(); + try { + boolean ret = incrementRefCount(pattern, enabledPatterns); + enabledEventNamesCache.clear(); + return ret; + } finally { + enabledEventNamesLock.unlock(); } - - return incrementRefCount(eventName, enabledEvents); } @Override @@ -228,23 +244,16 @@ public abstract class AbstractLttngAgent /* Notify the filter change manager of the command */ FilterChangeNotifier.getInstance().removeEventRules(eventName); - if (eventName.equals(WILDCARD)) { - int newCount = enabledWildcards.decrementAndGet(); - if (newCount < 0) { - /* Event was not enabled, bring the count back to 0 */ - enabledWildcards.incrementAndGet(); - return false; - } - return true; - } + EventNamePattern pattern = new EventNamePattern(eventName); - if (eventName.endsWith(WILDCARD)) { - /* Strip the "*" from the name. */ - String prefix = eventName.substring(0, eventName.length() - 1); - return decrementRefCount(prefix, enabledEventPrefixes); + enabledEventNamesLock.lock(); + try { + boolean ret = decrementRefCount(pattern, enabledPatterns); + enabledEventNamesCache.clear(); + return ret; + } finally { + enabledEventNamesLock.unlock(); } - - return decrementRefCount(eventName, enabledEvents); } @Override @@ -289,23 +298,39 @@ public abstract class AbstractLttngAgent @Override public boolean isEventEnabled(String eventName) { - /* If at least one session enabled the "*" wildcard, send the event */ - if (enabledWildcards.get() > 0) { - return true; + 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(); } - /* Check if at least one session wants this exact event name */ - if (enabledEvents.containsKey(eventName)) { - return true; - } + /* + * 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; + } + } - /* Look in the enabled prefixes if one of them matches the event */ - String potentialMatch = enabledEventPrefixes.floorKey(eventName); - if (potentialMatch != null && eventName.startsWith(potentialMatch)) { - return true; - } + /* Add the result to the cache */ + enabledEventNamesCache.put(eventName, Boolean.valueOf(enabled)); + return enabled; - return false; + } finally { + enabledEventNamesLock.unlock(); + } } @Override @@ -313,7 +338,7 @@ public abstract class AbstractLttngAgent return enabledAppContexts.entrySet(); } - private static boolean incrementRefCount(String key, Map refCountMap) { + private static boolean incrementRefCount(T key, Map refCountMap) { synchronized (refCountMap) { Integer count = refCountMap.get(key); if (count == null) { @@ -331,7 +356,7 @@ public abstract class AbstractLttngAgent } } - private static boolean decrementRefCount(String key, Map refCountMap) { + private static boolean decrementRefCount(T key, Map refCountMap) { synchronized (refCountMap) { Integer count = refCountMap.get(key); if (count == null || count.intValue() <= 0) {