Repository: nifi
Updated Branches:
  refs/heads/master 353fcdda9 -> 2fbe922a2


NIFI-2169: This closes #2343. Cache compiled regexp for RouteText

Signed-off-by: joewitt <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/2fbe922a
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/2fbe922a
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/2fbe922a

Branch: refs/heads/master
Commit: 2fbe922a2b0388f7541b2704ab621a9c7f9ba37d
Parents: 353fcdd
Author: Marco Gaido <[email protected]>
Authored: Fri Dec 15 00:44:32 2017 +0100
Committer: joewitt <[email protected]>
Committed: Tue Dec 26 18:02:02 2017 -0500

----------------------------------------------------------------------
 .../nifi/processors/standard/RouteText.java     | 34 +++++++++++++++----
 .../nifi/processors/standard/TestRouteText.java | 35 ++++++++++++++++++++
 2 files changed, 63 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/2fbe922a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/RouteText.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/RouteText.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/RouteText.java
index 6872e41..edec3c1 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/RouteText.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/RouteText.java
@@ -31,11 +31,15 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.cache.CacheBuilder;
 import org.apache.commons.lang3.StringUtils;
+
 import org.apache.nifi.annotation.behavior.DynamicProperty;
 import org.apache.nifi.annotation.behavior.DynamicRelationship;
 import org.apache.nifi.annotation.behavior.EventDriven;
@@ -209,6 +213,24 @@ public class RouteText extends AbstractProcessor {
     private volatile Map<Relationship, PropertyValue> propertyMap = new 
HashMap<>();
     private volatile Pattern groupingRegex = null;
 
+    @VisibleForTesting
+    final static int PATTERNS_CACHE_MAXIMUM_ENTRIES = 1024;
+
+    /**
+     * LRU cache for the compiled patterns. The size of the cache is 
determined by the value of
+     * {@link #PATTERNS_CACHE_MAXIMUM_ENTRIES}.
+     */
+    @VisibleForTesting
+    final ConcurrentMap<String, Pattern> patternsCache = 
CacheBuilder.newBuilder()
+            .maximumSize(PATTERNS_CACHE_MAXIMUM_ENTRIES)
+            .<String, Pattern>build()
+            .asMap();
+
+    private Pattern cachedCompiledPattern(final String regex, final boolean 
ignoreCase) {
+        return patternsCache.computeIfAbsent(regex,
+                r -> ignoreCase ? Pattern.compile(r, Pattern.CASE_INSENSITIVE) 
: Pattern.compile(r));
+    }
+
     @Override
     protected void init(final ProcessorInitializationContext context) {
         final Set<Relationship> set = new HashSet<>();
@@ -249,6 +271,10 @@ public class RouteText extends AbstractProcessor {
 
     @Override
     public void onPropertyModified(final PropertyDescriptor descriptor, final 
String oldValue, final String newValue) {
+        if (descriptor.equals(IGNORE_CASE) && !newValue.equals(oldValue)) {
+            patternsCache.clear();
+        }
+
         if (descriptor.equals(ROUTE_STRATEGY)) {
             configuredRouteStrategy = newValue;
         } else {
@@ -384,11 +410,7 @@ public class RouteText extends AbstractProcessor {
             for (final Map.Entry<Relationship, PropertyValue> entry : 
propMap.entrySet()) {
                 final String value = 
entry.getValue().evaluateAttributeExpressions(originalFlowFile).getValue();
 
-                Pattern compiledRegex = null;
-                if (compileRegex) {
-                    compiledRegex = ignoreCase ? Pattern.compile(value, 
Pattern.CASE_INSENSITIVE) : Pattern.compile(value);
-                }
-                propValueMap.put(entry.getKey(), compileRegex ? compiledRegex 
: value);
+                propValueMap.put(entry.getKey(), compileRegex ? 
cachedCompiledPattern(value, ignoreCase) : value);
             }
         }
 
@@ -435,7 +457,7 @@ public class RouteText extends AbstractProcessor {
 
                         int propertiesThatMatchedLine = 0;
                         for (final Map.Entry<Relationship, Object> entry : 
propValueMap.entrySet()) {
-                            boolean lineMatchesProperty = 
lineMatches(matchLine, entry.getValue(), 
context.getProperty(MATCH_STRATEGY).getValue(), ignoreCase, originalFlowFile, 
variables);
+                            boolean lineMatchesProperty = 
lineMatches(matchLine, entry.getValue(), matchStrategy, ignoreCase, 
originalFlowFile, variables);
                             if (lineMatchesProperty) {
                                 propertiesThatMatchedLine++;
                             }

http://git-wip-us.apache.org/repos/asf/nifi/blob/2fbe922a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestRouteText.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestRouteText.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestRouteText.java
index 71bd83b..32048a5 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestRouteText.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestRouteText.java
@@ -28,6 +28,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import com.google.common.collect.ImmutableMap;
 import org.apache.nifi.processor.Relationship;
 import org.apache.nifi.util.MockFlowFile;
 import org.apache.nifi.util.TestRunner;
@@ -763,6 +764,40 @@ public class TestRouteText {
         
outOriginal.assertContentEquals(Paths.get("src/test/resources/TestXml/XmlBundle.xsd"));
     }
 
+    @Test
+    public void testPatternCache() throws IOException {
+        final RouteText routeText = new RouteText();
+        final TestRunner runner = TestRunners.newTestRunner(routeText);
+        runner.setProperty(RouteText.MATCH_STRATEGY, 
RouteText.MATCHES_REGULAR_EXPRESSION);
+        runner.setProperty("simple", ".*(${someValue}).*");
+
+        runner.enqueue("some text", ImmutableMap.of("someValue", "a value"));
+        runner.enqueue("some other text", ImmutableMap.of("someValue", "a 
value"));
+        runner.run(2);
+
+        assertEquals("Expected 1 elements in the cache for the patterns, got" +
+                routeText.patternsCache.size(), 1, 
routeText.patternsCache.size());
+
+        for (int i = 0; i < RouteText.PATTERNS_CACHE_MAXIMUM_ENTRIES * 2; ++i) 
{
+            String iString = Long.toString(i);
+            runner.enqueue("some text with " + iString + "in it",
+                    ImmutableMap.of("someValue", iString));
+            runner.run();
+        }
+
+        assertEquals("Expected " + RouteText.PATTERNS_CACHE_MAXIMUM_ENTRIES +
+                " elements in the cache for the patterns, got" + 
routeText.patternsCache.size(),
+                RouteText.PATTERNS_CACHE_MAXIMUM_ENTRIES, 
routeText.patternsCache.size());
+
+        runner.assertTransferCount("simple", 
RouteText.PATTERNS_CACHE_MAXIMUM_ENTRIES * 2);
+        runner.assertTransferCount("unmatched", 2);
+        runner.assertTransferCount("original", 
RouteText.PATTERNS_CACHE_MAXIMUM_ENTRIES * 2 + 2);
+
+        runner.setProperty(RouteText.IGNORE_CASE, "true");
+        assertEquals("Pattern cache is not cleared after changing 
IGNORE_CASE", 0, routeText.patternsCache.size());
+    }
+
+
     public static int countLines(String str) {
         if (str == null || str.isEmpty()) {
             return 0;

Reply via email to