X-Git-Url: http://git.lttng.org/?p=lttng-ust.git;a=blobdiff_plain;f=liblttng-ust-java-agent%2Fjava%2Flttng-ust-agent-common%2Forg%2Flttng%2Fust%2Fagent%2FAbstractLttngAgent.java;h=0d04a30f4203eed073669a8b804a66371e6a2c65;hp=a58803640f79c15e931fd51ce23e39c31aca394d;hb=c0e418b;hpb=f35c6aa089659c7d16867ce4eac740d30c2c0213 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 a5880364..0d04a30f 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 @@ -19,13 +19,14 @@ 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; @@ -43,7 +44,6 @@ import org.lttng.ust.agent.utils.LttngUstAgentLogger; 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 */ @@ -52,29 +52,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. @@ -205,28 +207,19 @@ public abstract class AbstractLttngAgent */ FilterChangeNotifier fcn = FilterChangeNotifier.getInstance(); - for (Map.Entry entry : enabledEvents.entrySet()) { - String eventName = entry.getKey(); - Integer nb = entry.getValue(); - for (int i = 0; i < nb.intValue(); i++) { - fcn.removeEventRules(eventName); - } - } - enabledEvents.clear(); - - for (Map.Entry entry : enabledEventPrefixes.entrySet()) { - /* Re-add the * at the end, the FCN tracks the rules that way */ - String eventName = (entry.getKey() + "*"); - Integer nb = entry.getValue(); - for (int i = 0; i < nb.intValue(); i++) { - fcn.removeEventRules(eventName); + 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); + } } - } - enabledEventPrefixes.clear(); - - int wildcardRules = enabledWildcards.getAndSet(0); - for (int i = 0; i < wildcardRules; i++) { - fcn.removeEventRules(WILDCARD); + enabledPatterns.clear(); + enabledEventNamesCache.clear(); + } finally { + enabledEventNamesLock.unlock(); } /* @@ -244,18 +237,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 @@ -263,23 +254,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 @@ -324,23 +308,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 @@ -348,7 +348,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) { @@ -366,7 +366,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) {