Author: mreutegg Date: Wed Dec 14 16:53:25 2016 New Revision: 1774292 URL: http://svn.apache.org/viewvc?rev=1774292&view=rev Log: OAK-5186: ChangeSetFilterImpl: support many includePaths by filtering for 1st path name
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImpl.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImplTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImpl.java?rev=1774292&r1=1774291&r2=1774292&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImpl.java Wed Dec 14 16:53:25 2016 @@ -42,6 +42,7 @@ public class ChangeSetFilterImpl impleme private static final int MAX_EXCLUDE_PATH_CUTOFF_LEVEL = 6; private final Set<String> rootIncludePaths; + private final Set<String> firstLevelIncludeNames; private final Set<Pattern> includePathPatterns; private final Set<Pattern> excludePathPatterns; private final Set<Pattern> unpreciseExcludePathPatterns; @@ -69,6 +70,7 @@ public class ChangeSetFilterImpl impleme int maxExcludedPaths) { this.rootIncludePaths = new HashSet<String>(); this.includePathPatterns = new HashSet<Pattern>(); + Set<String> firstLevelIncludePaths = new HashSet<String>(); for (String aRawIncludePath : includedParentPaths) { final String aGlobbingIncludePath; if (aRawIncludePath.contains("*")) { @@ -79,13 +81,31 @@ public class ChangeSetFilterImpl impleme } this.rootIncludePaths.add(aRawIncludePath); this.includePathPatterns.add(asPattern(aGlobbingIncludePath)); + if (firstLevelIncludePaths != null) { + final String firstLevelName = firstLevelName(aRawIncludePath); + if (firstLevelName != null && !firstLevelName.contains("*")) { + firstLevelIncludePaths.add(firstLevelName); + } else { + firstLevelIncludePaths = null; + } + } } if (additionalIncludedParentPaths != null) { for (String path : additionalIncludedParentPaths) { this.rootIncludePaths.add(path); this.includePathPatterns.add(asPattern(path)); + if (firstLevelIncludePaths != null) { + final String firstLevelName = firstLevelName(path); + if (firstLevelName != null && !firstLevelName.contains("*")) { + firstLevelIncludePaths.add(firstLevelName); + } else { + firstLevelIncludePaths = null; + } + } } } + this.firstLevelIncludeNames = firstLevelIncludePaths; + // OAK-5169: // excludedParentPaths could in theory be a large list, in which case // the excludes() algorithm becomes non-performing. Reason is, that it @@ -119,6 +139,18 @@ public class ChangeSetFilterImpl impleme this.parentNodeNames = parentNodeNames == null ? null : new HashSet<String>(parentNodeNames); } + private String firstLevelName(String path) { + if (path.isEmpty() || path.equals("/")) { + return null; + } + int secondSlash = path.indexOf("/", 1); + if (secondSlash != -1) { + return path.substring(1, secondSlash); + } else { + return path.substring(1); + } + } + private Set<String> unprecisePaths(Set<String> paths, int maxExcludedPaths, int maxExcludePathCutOffLevel) { int level = maxExcludePathCutOffLevel; while(level > 1) { @@ -228,6 +260,15 @@ public class ChangeSetFilterImpl impleme included = true; break; } + if (firstLevelIncludeNames != null) { + final String firstLevelName = firstLevelName(aPath); + if (firstLevelName != null && !firstLevelIncludeNames.contains(firstLevelName)) { + // then the 'first level name check' concluded that + // it's not in any include path - hence we can skip + // the (more expensive) pattern check + continue; + } + } if (patternsMatch(this.includePathPatterns, aPath)) { included = true; break; Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImplTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImplTest.java?rev=1774292&r1=1774291&r2=1774292&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImplTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImplTest.java Wed Dec 14 16:53:25 2016 @@ -25,13 +25,20 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import com.google.common.base.Stopwatch; +import com.google.common.collect.Sets; + import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.plugins.observation.ChangeSet; import org.apache.jackrabbit.oak.plugins.observation.ChangeSetBuilder; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ChangeSetFilterImplTest { + private static final Logger LOG = LoggerFactory.getLogger(ChangeSetFilterImplTest.class); + /** shortcut for creating a set of strings */ private Set<String> s(String... entries) { return new HashSet<String>(Arrays.asList(entries)); @@ -332,4 +339,36 @@ public class ChangeSetFilterImplTest { assertFalse(prefilter.excludes(builder.build())); } } + + @Test + public void manyIncludePaths() throws Exception { + int numPaths = 50; + ChangeSetBuilder builder = newBuilder(50, 9); + for (int i = 0; i < numPaths; i++) { + builder.addParentPath("/a/b/c/d/e/n" + i); + } + ChangeSet cs = builder.build(); + + Set<String> includes = Sets.newHashSet(); + for (int i = 0; i < 100; i++) { + includes.add("/foo/bar/n-" + i + "/*.jsp"); + } + ChangeSetFilter filter = new ChangeSetFilterImpl(s(),true, + includes, s(), s(), s(), s()); + + // warm up + doManyIncludePaths(filter, cs); + + // and measure + Stopwatch sw = Stopwatch.createStarted(); + doManyIncludePaths(filter, cs); + LOG.info("manyIncludePaths() took {}", sw.stop()); + } + + private void doManyIncludePaths(ChangeSetFilter filter, ChangeSet cs) + throws Exception { + for (int i = 0; i < 20000; i++) { + assertTrue(filter.excludes(cs)); + } + } }