Author: fortino
Date: Sat Jul 25 12:13:20 2020
New Revision: 1880297

URL: http://svn.apache.org/viewvc?rev=1880297&view=rev
Log:
OAK-9148: introduced ElasticIndexTracker

Added:
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNodeManager.java
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexTracker.java
Modified:
    
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFacetSearchTest.java
    
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithGlobalIndexSearchTest.java
    
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithoutGlobalIndexSearchTest.java
    
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTIndexedContentAvailability.java
    
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTSeparatedIndexedContentAvailability.java
    
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyTextSearchTest.java
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticIndexProviderService.java
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndex.java
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNode.java
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexProvider.java
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/ElasticTestRepositoryBuilder.java
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticAbstractQueryTest.java
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticFacetTest.java
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticSpellcheckTest.java
    
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTracker.java
    
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNodeManager.java

Modified: 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFacetSearchTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFacetSearchTest.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFacetSearchTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFacetSearchTest.java
 Sat Jul 25 12:13:20 2020
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.oak.benchmark;
 
-
 import org.apache.commons.io.FileUtils;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.benchmark.util.TestHelper;
@@ -31,6 +30,8 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 
 import javax.jcr.Repository;
 import java.util.LinkedHashMap;
@@ -49,7 +50,7 @@ public class ElasticFacetSearchTest exte
     @Override
     protected Repository[] createRepository(RepositoryFixture fixture) throws 
Exception {
         indexName = TestHelper.getUniqueIndexName("elasticFacetTest");
-        Map<String, Boolean> propMap = new LinkedHashMap();
+        Map<String, Boolean> propMap = new LinkedHashMap<>();
         propMap.put(SEARCH_PROP, false);
         propMap.put(FACET_PROP_1, true);
         propMap.put(FACET_PROP_2, true);
@@ -61,7 +62,8 @@ public class ElasticFacetSearchTest exte
                             new ExtractedTextCache(10 * FileUtils.ONE_MB, 
100));
                     ElasticIndexProvider indexProvider = new 
ElasticIndexProvider(coordinate);
                     oak.with(editorProvider)
-                            .with(indexProvider)
+                            .with((Observer) indexProvider)
+                            .with((QueryIndexProvider) indexProvider)
                             .with(new PropertyIndexEditorProvider())
                             .with(new NodeTypeIndexProvider())
                             .with(new 
FacetSearchTest.FacetIndexInitializer(indexName, propMap,

Modified: 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithGlobalIndexSearchTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithGlobalIndexSearchTest.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithGlobalIndexSearchTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithGlobalIndexSearchTest.java
 Sat Jul 25 12:13:20 2020
@@ -18,8 +18,6 @@
  */
 package org.apache.jackrabbit.oak.benchmark;
 
-
-
 import org.apache.commons.io.FileUtils;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.benchmark.util.ElasticGlobalInitializer;
@@ -34,6 +32,8 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 
 import javax.jcr.Repository;
 import java.io.File;
@@ -59,7 +59,8 @@ public class ElasticFullTextWithGlobalIn
                             new ExtractedTextCache(10 * FileUtils.ONE_MB, 
100));
                     ElasticIndexProvider indexProvider = new 
ElasticIndexProvider(coordinate);
                     oak.with(editorProvider)
-                            .with(indexProvider)
+                            .with((Observer) indexProvider)
+                            .with((QueryIndexProvider) indexProvider)
                             .with(new PropertyIndexEditorProvider())
                             .with(new NodeTypeIndexProvider())
                             .with(new 
ElasticGlobalInitializer(elasticGlobalIndexName, storageEnabled))

Modified: 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithoutGlobalIndexSearchTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithoutGlobalIndexSearchTest.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithoutGlobalIndexSearchTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticFullTextWithoutGlobalIndexSearchTest.java
 Sat Jul 25 12:13:20 2020
@@ -18,7 +18,6 @@
  */
 package org.apache.jackrabbit.oak.benchmark;
 
-
 import org.apache.commons.io.FileUtils;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.benchmark.util.TestHelper;
@@ -33,6 +32,9 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
+
 import javax.jcr.Repository;
 import java.io.File;
 
@@ -59,7 +61,8 @@ public class ElasticFullTextWithoutGloba
                             new ExtractedTextCache(10 * FileUtils.ONE_MB, 
100));
                     ElasticIndexProvider indexProvider = new 
ElasticIndexProvider(coordinate);
                     oak.with(editorProvider)
-                            .with(indexProvider)
+                            .with((Observer) indexProvider)
+                            .with((QueryIndexProvider) indexProvider)
                             .with(new PropertyIndexEditorProvider())
                             .with(new NodeTypeIndexProvider())
                             .with(new 
PropertyFullTextTest.FullTextPropertyInitialiser(indexName, of("text"),

Modified: 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTIndexedContentAvailability.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTIndexedContentAvailability.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTIndexedContentAvailability.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTIndexedContentAvailability.java
 Sat Jul 25 12:13:20 2020
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.oak.benchmark;
 
-
 import org.apache.commons.io.FileUtils;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.benchmark.util.ElasticGlobalInitializer;
@@ -31,6 +30,8 @@ import org.apache.jackrabbit.oak.plugins
 import 
org.apache.jackrabbit.oak.plugins.index.elastic.index.ElasticIndexEditorProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.elastic.query.ElasticIndexProvider;
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -82,9 +83,9 @@ public class ElasticPropertyFTIndexedCon
 
 
     ElasticPropertyFTIndexedContentAvailability(final File dump,
-                                                       final boolean flat,
-                                                       final boolean doReport,
-                                                       final Boolean 
storageEnabled, ElasticConnection coordinate) {
+                                                final boolean flat,
+                                                final boolean doReport,
+                                                final Boolean storageEnabled, 
ElasticConnection coordinate) {
         super(dump, flat, doReport, storageEnabled);
         this.coordinate = coordinate;
     }
@@ -102,9 +103,10 @@ public class ElasticPropertyFTIndexedCon
                             new ExtractedTextCache(10 * FileUtils.ONE_MB, 
100));
                     ElasticIndexProvider indexProvider = new 
ElasticIndexProvider(coordinate);
                     oak.with(editorProvider)
-                            .with(indexProvider)
+                            .with((Observer) indexProvider)
+                            .with((QueryIndexProvider) indexProvider)
                             .with((new 
ElasticGlobalInitializer(elasticGlobalIndexName, storageEnabled)).async())
-                                    // the WikipediaImporter set a property 
`title`
+                            // the WikipediaImporter set a property `title`
                             .with(new 
FullTextPropertyInitialiser(elasticTitleIndexName, of("title"),
                                     
ElasticIndexDefinition.TYPE_ELASTICSEARCH).async())
                             .withAsyncIndexing("async", 5);
@@ -122,5 +124,4 @@ public class ElasticPropertyFTIndexedCon
         TestHelper.cleanupRemoteElastic(coordinate, elasticTitleIndexName);
     }
 
-
 }

Modified: 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTSeparatedIndexedContentAvailability.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTSeparatedIndexedContentAvailability.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTSeparatedIndexedContentAvailability.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyFTSeparatedIndexedContentAvailability.java
 Sat Jul 25 12:13:20 2020
@@ -18,7 +18,6 @@
  */
 package org.apache.jackrabbit.oak.benchmark;
 
-
 import org.apache.commons.io.FileUtils;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.benchmark.util.ElasticGlobalInitializer;
@@ -32,6 +31,8 @@ import org.apache.jackrabbit.oak.plugins
 import 
org.apache.jackrabbit.oak.plugins.index.elastic.index.ElasticIndexEditorProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.elastic.query.ElasticIndexProvider;
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 
 import javax.jcr.Repository;
 import java.io.File;
@@ -50,9 +51,9 @@ public class ElasticPropertyFTSeparatedI
     private String elasticTitleIndexName;
 
     ElasticPropertyFTSeparatedIndexedContentAvailability(final File dump,
-                                                                final boolean 
flat,
-                                                                final boolean 
doReport,
-                                                                final Boolean 
storageEnabled, ElasticConnection coordinate) {
+                                                         final boolean flat,
+                                                         final boolean 
doReport,
+                                                         final Boolean 
storageEnabled, ElasticConnection coordinate) {
         super(dump, flat, doReport, storageEnabled);
         this.coordinate = coordinate;
     }
@@ -80,9 +81,10 @@ public class ElasticPropertyFTSeparatedI
                             new ExtractedTextCache(10 * FileUtils.ONE_MB, 
100));
                     ElasticIndexProvider indexProvider = new 
ElasticIndexProvider(coordinate);
                     oak.with(editorProvider)
-                            .with(indexProvider)
+                            .with((Observer) indexProvider)
+                            .with((QueryIndexProvider) indexProvider)
                             .with((new 
ElasticGlobalInitializer(elasticGlobalIndexName, 
storageEnabled)).async("fulltext-async"))
-                                    // the WikipediaImporter set a property 
`title`
+                            // the WikipediaImporter set a property `title`
                             .with(new 
FullTextPropertyInitialiser(elasticTitleIndexName, of("title"),
                                     
ElasticIndexDefinition.TYPE_ELASTICSEARCH).async())
                             .withAsyncIndexing("async", 5)

Modified: 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyTextSearchTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyTextSearchTest.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyTextSearchTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-benchmarks-elastic/src/main/java/org/apache/jackrabbit/oak/benchmark/ElasticPropertyTextSearchTest.java
 Sat Jul 25 12:13:20 2020
@@ -18,7 +18,6 @@
  */
 package org.apache.jackrabbit.oak.benchmark;
 
-
 import org.apache.commons.io.FileUtils;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.benchmark.util.TestHelper;
@@ -33,6 +32,8 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 
 import javax.jcr.Repository;
 import javax.jcr.query.Query;
@@ -76,7 +77,8 @@ public class ElasticPropertyTextSearchTe
                             new ExtractedTextCache(10 * FileUtils.ONE_MB, 
100));
                     ElasticIndexProvider indexProvider = new 
ElasticIndexProvider(coordinate);
                     oak.with(editorProvider)
-                            .with(indexProvider)
+                            .with((Observer) indexProvider)
+                            .with((QueryIndexProvider) indexProvider)
                             .with(new PropertyIndexEditorProvider())
                             .with(new NodeTypeIndexProvider())
                             .with(new 
PropertyFullTextTest.FullTextPropertyInitialiser(indexName, of("title"),

Modified: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticIndexProviderService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticIndexProviderService.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticIndexProviderService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticIndexProviderService.java
 Sat Jul 25 12:13:20 2020
@@ -35,6 +35,7 @@ import org.apache.jackrabbit.oak.plugins
 import 
org.apache.jackrabbit.oak.plugins.index.elastic.query.ElasticIndexProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.fulltext.PreExtractedTextProvider;
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
 import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
@@ -185,6 +186,9 @@ public class ElasticIndexProviderService
     private void registerIndexProvider(BundleContext bundleContext) {
         ElasticIndexProvider indexProvider = new 
ElasticIndexProvider(elasticConnection);
 
+        // register observer needed for index tracking
+        regs.add(bundleContext.registerService(Observer.class.getName(), 
indexProvider, null));
+
         Dictionary<String, Object> props = new Hashtable<>();
         props.put("type", ElasticIndexDefinition.TYPE_ELASTICSEARCH);
         
regs.add(bundleContext.registerService(QueryIndexProvider.class.getName(), 
indexProvider, props));

Modified: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndex.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndex.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndex.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndex.java
 Sat Jul 25 12:13:20 2020
@@ -17,7 +17,6 @@
 package org.apache.jackrabbit.oak.plugins.index.elastic.query;
 
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.plugins.index.elastic.ElasticConnection;
 import 
org.apache.jackrabbit.oak.plugins.index.elastic.query.async.ElasticResultRowAsyncIterator;
 import org.apache.jackrabbit.oak.plugins.index.search.IndexNode;
 import org.apache.jackrabbit.oak.plugins.index.search.SizeEstimator;
@@ -28,7 +27,6 @@ import org.apache.jackrabbit.oak.spi.que
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.elasticsearch.common.Strings;
-import org.jetbrains.annotations.NotNull;
 
 import java.util.Iterator;
 import java.util.List;
@@ -51,12 +49,10 @@ class ElasticIndex extends FulltextIndex
     // higher than some threshold below which the query should rather be 
answered by something else if possible
     private static final double MIN_COST = 100.1;
 
-    private final ElasticConnection elasticConnection;
-    private final NodeState root;
+    private final ElasticIndexTracker elasticIndexTracker;
 
-    ElasticIndex(@NotNull ElasticConnection elasticConnection, @NotNull 
NodeState root) {
-        this.elasticConnection = elasticConnection;
-        this.root = root;
+    ElasticIndex(ElasticIndexTracker elasticIndexTracker) {
+        this.elasticIndexTracker = elasticIndexTracker;
     }
 
     @Override
@@ -96,7 +92,7 @@ class ElasticIndex extends FulltextIndex
 
     @Override
     protected IndexNode acquireIndexNode(String indexPath) {
-        return new ElasticIndexNode(root, indexPath, elasticConnection);
+        return elasticIndexTracker.acquireIndexNode(indexPath, 
TYPE_ELASTICSEARCH);
     }
 
     @Override
@@ -113,24 +109,29 @@ class ElasticIndex extends FulltextIndex
         final ElasticResponseHandler responseHandler = new 
ElasticResponseHandler(planResult, filter);
 
         final Iterator<FulltextResultRow> itr;
-        if (requestHandler.requiresSpellCheck()) {
-            itr = new ElasticSpellcheckIterator(acquireIndexNode(plan), 
requestHandler, responseHandler);
-        } else {
-            // this function is called for each extracted row. Passing 
FulltextIndex::shouldInclude means that for each
-            // row we evaluate getPathRestriction(plan) & 
plan.getFilter().getPathRestriction(). Providing a partial
-            // function (https://en.wikipedia.org/wiki/Partial_function) we 
can evaluate them once and still use a predicate as before
-            BiFunction<String, Filter.PathRestriction, Predicate<String>> 
partialShouldInclude = (path, pathRestriction) -> docPath ->
-                    shouldInclude(path, pathRestriction, docPath);
-
-            itr = new ElasticResultRowAsyncIterator(
-                    acquireIndexNode(plan),
-                    requestHandler,
-                    responseHandler,
-                    plan,
-                    partialShouldInclude.apply(getPathRestriction(plan), 
filter.getPathRestriction()),
-                    getEstimator(plan.getPlanName())
-            );
-
+        ElasticIndexNode indexNode = acquireIndexNode(plan);
+        try {
+            if (requestHandler.requiresSpellCheck()) {
+                itr = new ElasticSpellcheckIterator(indexNode, requestHandler, 
responseHandler);
+            } else {
+                // this function is called for each extracted row. Passing 
FulltextIndex::shouldInclude means that for each
+                // row we evaluate getPathRestriction(plan) & 
plan.getFilter().getPathRestriction(). Providing a partial
+                // function (https://en.wikipedia.org/wiki/Partial_function) 
we can evaluate them once and still use a predicate as before
+                BiFunction<String, Filter.PathRestriction, Predicate<String>> 
partialShouldInclude = (path, pathRestriction) -> docPath ->
+                        shouldInclude(path, pathRestriction, docPath);
+
+                itr = new ElasticResultRowAsyncIterator(
+                        indexNode,
+                        requestHandler,
+                        responseHandler,
+                        plan,
+                        partialShouldInclude.apply(getPathRestriction(plan), 
filter.getPathRestriction()),
+                        getEstimator(plan.getPlanName())
+                );
+
+            }
+        } finally {
+            indexNode.release();
         }
         return new FulltextPathCursor(itr, REWOUND_STATE_PROVIDER_NOOP, plan, 
filter.getQueryLimits(), getSizeEstimator(plan));
     }

Modified: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNode.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNode.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNode.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNode.java
 Sat Jul 25 12:13:20 2020
@@ -29,12 +29,14 @@ public class ElasticIndexNode implements
 
     private final ElasticConnection elasticConnection;
     private final ElasticIndexDefinition indexDefinition;
+    private final ElasticIndexStatistics indexStatistics;
 
-    ElasticIndexNode(@NotNull NodeState root, @NotNull String indexPath,
-                     @NotNull ElasticConnection elasticConnection) {
+    public ElasticIndexNode(@NotNull NodeState root, @NotNull String indexPath,
+                            @NotNull ElasticConnection elasticConnection) {
         final NodeState indexNS = NodeStateUtils.getNode(root, indexPath);
         this.elasticConnection = elasticConnection;
         this.indexDefinition = new ElasticIndexDefinition(root, indexNS, 
indexPath, elasticConnection.getIndexPrefix());
+        this.indexStatistics = new ElasticIndexStatistics(elasticConnection, 
indexDefinition);
     }
 
     @Override
@@ -60,6 +62,6 @@ public class ElasticIndexNode implements
 
     @Override
     public @Nullable IndexStatistics getIndexStatistics() {
-        return new ElasticIndexStatistics(elasticConnection, indexDefinition);
+        return indexStatistics;
     }
 }

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNodeManager.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNodeManager.java?rev=1880297&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNodeManager.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexNodeManager.java
 Sat Jul 25 12:13:20 2020
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elastic.query;
+
+import org.apache.jackrabbit.oak.plugins.index.elastic.ElasticConnection;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import 
org.apache.jackrabbit.oak.plugins.index.search.spi.query.IndexNodeManager;
+import 
org.apache.jackrabbit.oak.plugins.index.search.update.ReaderRefreshPolicy;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+class ElasticIndexNodeManager extends IndexNodeManager<ElasticIndexNode> {
+
+    private final ElasticIndexNode elasticIndexNode;
+    private final String path;
+
+    ElasticIndexNodeManager(ElasticConnection elasticConnection, String path, 
NodeState root) {
+        this.path = path;
+        this.elasticIndexNode = new ElasticIndexNode(root, path, 
elasticConnection) {
+            @Override
+            public void release() {
+                ElasticIndexNodeManager.this.release();
+                super.release();
+            }
+        };
+    }
+
+    @Override
+    protected String getName() {
+        return path;
+    }
+
+    @Override
+    protected ElasticIndexNode getIndexNode() {
+        return elasticIndexNode;
+    }
+
+    @Override
+    protected IndexDefinition getDefinition() {
+        return elasticIndexNode.getDefinition();
+    }
+
+    @Override
+    protected ReaderRefreshPolicy getReaderRefreshPolicy() {
+        return ReaderRefreshPolicy.NEVER;
+    }
+
+    @Override
+    protected void refreshReaders() {
+        // do nothing
+    }
+
+    @Override
+    protected void releaseResources() {
+        // do nothing
+    }
+}

Modified: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexProvider.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexProvider.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexProvider.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexProvider.java
 Sat Jul 25 12:13:20 2020
@@ -17,6 +17,8 @@
 package org.apache.jackrabbit.oak.plugins.index.elastic.query;
 
 import org.apache.jackrabbit.oak.plugins.index.elastic.ElasticConnection;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
 import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -25,16 +27,21 @@ import org.jetbrains.annotations.NotNull
 import java.util.Collections;
 import java.util.List;
 
-public class ElasticIndexProvider implements QueryIndexProvider {
-    private final ElasticConnection elasticConnection;
+public class ElasticIndexProvider implements QueryIndexProvider, Observer {
+
+    private final ElasticIndexTracker elasticIndexTracker;
 
     public ElasticIndexProvider(ElasticConnection elasticConnection) {
-        this.elasticConnection = elasticConnection;
+        this.elasticIndexTracker = new ElasticIndexTracker(elasticConnection);
     }
 
     @Override
     public @NotNull List<? extends QueryIndex> getQueryIndexes(NodeState 
nodeState) {
-        return Collections.singletonList(new ElasticIndex(elasticConnection, 
nodeState));
+        return Collections.singletonList(new 
ElasticIndex(elasticIndexTracker));
     }
 
+    @Override
+    public void contentChanged(@NotNull NodeState root, @NotNull CommitInfo 
info) {
+        elasticIndexTracker.update(root);
+    }
 }

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexTracker.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexTracker.java?rev=1880297&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexTracker.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticIndexTracker.java
 Sat Jul 25 12:13:20 2020
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elastic.query;
+
+import org.apache.jackrabbit.oak.plugins.index.elastic.ElasticConnection;
+import 
org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexTracker;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.jetbrains.annotations.NotNull;
+
+class ElasticIndexTracker extends 
FulltextIndexTracker<ElasticIndexNodeManager> {
+
+    private final ElasticConnection elasticConnection;
+
+    ElasticIndexTracker(@NotNull ElasticConnection elasticConnection) {
+        this.elasticConnection = elasticConnection;
+    }
+
+    @Override
+    public boolean isUpdateNeeded(NodeState before, NodeState after) {
+        // for Elastic we are not interested in checking for updates on 
:status, index definition is enough.
+        // The :status gets updated every time the indexed content is changed 
(with properties like last_update_ts),
+        // removing the check on :status reduces drastically the contention 
between queries (that need to acquire the
+        // read lock) and updates (need to acquire the write lock).
+        return isIndexDefinitionChanged(before, after);
+    }
+
+    @Override
+    protected ElasticIndexNodeManager openIndex(String path, NodeState root, 
NodeState node) {
+        return new ElasticIndexNodeManager(elasticConnection, path, root);
+    }
+}

Modified: 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/ElasticTestRepositoryBuilder.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/ElasticTestRepositoryBuilder.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/ElasticTestRepositoryBuilder.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/ElasticTestRepositoryBuilder.java
 Sat Jul 25 12:13:20 2020
@@ -26,6 +26,7 @@ import org.apache.jackrabbit.oak.plugins
 import 
org.apache.jackrabbit.oak.plugins.index.elastic.index.ElasticIndexEditorProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.elastic.query.ElasticIndexProvider;
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
 
 import static com.google.common.collect.Lists.newArrayList;
 import static 
org.apache.jackrabbit.oak.plugins.index.CompositeIndexEditorProvider.compose;
@@ -52,7 +53,7 @@ public class ElasticTestRepositoryBuilde
                 .with(initialContent)
                 .with(securityProvider)
                 .with(editorProvider)
-                .with(indexProvider)
+                .with((Observer) indexProvider)
                 .with(indexProvider)
                 .with(queryIndexProvider);
         if (isAsync) {

Modified: 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticAbstractQueryTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticAbstractQueryTest.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticAbstractQueryTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticAbstractQueryTest.java
 Sat Jul 25 12:13:20 2020
@@ -34,6 +34,8 @@ import org.apache.jackrabbit.oak.plugins
 import 
org.apache.jackrabbit.oak.plugins.index.search.util.IndexDefinitionBuilder;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
 import org.apache.jackrabbit.oak.query.AbstractQueryTest;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
@@ -155,7 +157,8 @@ public abstract class ElasticAbstractQue
                 .with(getInitialContent())
                 .with(new OpenSecurityProvider())
                 .with(editorProvider)
-                .with(indexProvider)
+                .with((Observer) indexProvider)
+                .with((QueryIndexProvider) indexProvider)
                 .with(new PropertyIndexEditorProvider())
                 .with(new NodeTypeIndexProvider());
 

Modified: 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticFacetTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticFacetTest.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticFacetTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticFacetTest.java
 Sat Jul 25 12:13:20 2020
@@ -30,6 +30,8 @@ import org.apache.jackrabbit.oak.plugins
 import 
org.apache.jackrabbit.oak.plugins.index.search.util.IndexDefinitionBuilder;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
 import org.apache.jackrabbit.oak.query.facet.FacetResult;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.junit.After;
 import org.junit.Before;
@@ -124,7 +126,8 @@ public class ElasticFacetTest {
         NodeStore nodeStore = new MemoryNodeStore(INITIAL_CONTENT);
         Oak oak = new Oak(nodeStore)
                 .with(editorProvider)
-                .with(indexProvider);
+                .with((Observer) indexProvider)
+                .with((QueryIndexProvider) indexProvider);
 
         Jcr jcr = new Jcr(oak);
         Repository repository = jcr.createRepository();

Modified: 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticSpellcheckTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticSpellcheckTest.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticSpellcheckTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticSpellcheckTest.java
 Sat Jul 25 12:13:20 2020
@@ -28,6 +28,8 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
 import 
org.apache.jackrabbit.oak.plugins.index.search.util.IndexDefinitionBuilder;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.junit.After;
 import org.junit.Before;
@@ -103,7 +105,8 @@ public class ElasticSpellcheckTest {
         NodeStore nodeStore = new MemoryNodeStore(INITIAL_CONTENT);
         Oak oak = new Oak(nodeStore)
                 .with(editorProvider)
-                .with(indexProvider);
+                .with((Observer) indexProvider)
+                .with((QueryIndexProvider) indexProvider);
 
         Jcr jcr = new Jcr(oak);
         Repository repository = jcr.createRepository();

Modified: 
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTracker.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTracker.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTracker.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTracker.java
 Sat Jul 25 12:13:20 2020
@@ -16,14 +16,15 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.search.spi.query;
 
-import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.commons.PerfLogger;
 import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoService;
@@ -46,18 +47,16 @@ import static com.google.common.base.Pre
 import static com.google.common.base.Predicates.in;
 import static com.google.common.base.Predicates.not;
 import static com.google.common.base.Predicates.notNull;
-import static com.google.common.collect.Lists.newArrayListWithCapacity;
 import static com.google.common.collect.Maps.filterKeys;
 import static com.google.common.collect.Maps.filterValues;
-import static com.google.common.collect.Maps.newHashMap;
 import static java.util.Collections.emptyMap;
 import static 
org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.INDEX_DEFINITION_NODE;
 import static 
org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.STATUS_NODE;
 import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 
-public abstract class FulltextIndexTracker {
+public abstract class FulltextIndexTracker<I extends IndexNodeManager<?>> {
 
-    private static final Logger log = 
LoggerFactory.getLogger(FulltextIndexTracker.class);
+    private static final Logger LOG = 
LoggerFactory.getLogger(FulltextIndexTracker.class);
     private static final PerfLogger PERF_LOGGER =
             new 
PerfLogger(LoggerFactory.getLogger(FulltextIndexTracker.class.getName() + 
".perf"));
 
@@ -67,22 +66,18 @@ public abstract class FulltextIndexTrack
 
     private AsyncIndexInfoService asyncIndexInfoService;
 
-    private volatile Map<String, IndexNodeManager> indices = emptyMap();
+    private volatile Map<String, I> indices = emptyMap();
 
     private volatile boolean refresh;
 
-    protected abstract IndexNodeManager openIndex(String path, NodeState root, 
NodeState node);
+    protected abstract I openIndex(String path, NodeState root, NodeState 
node);
 
     synchronized void close() {
-        Map<String, IndexNodeManager> indices = this.indices;
+        Map<String, I> indices = this.indices;
         this.indices = emptyMap();
 
-        for (Map.Entry<String, IndexNodeManager> entry : indices.entrySet()) {
-            try {
-                entry.getValue().close();
-            } catch (IOException e) {
-                log.error("Failed to close the Lucene index at " + 
entry.getKey(), e);
-            }
+        for (Map.Entry<String, I> entry : indices.entrySet()) {
+            entry.getValue().close();
         }
     }
 
@@ -91,12 +86,24 @@ public abstract class FulltextIndexTrack
             this.root = root;
             close();
             refresh = false;
-            log.info("Refreshed the opened indexes");
+            LOG.info("Refreshed the opened indexes");
         } else {
             diffAndUpdate(root);
         }
     }
 
+    /**
+     * Receives the before and after state to decide when to reload the {@link 
IndexNode}.
+     * By default it checks for changes of the :status node and the index 
definition.
+     *
+     * @param before before state, non-existent if this node was added
+     * @param after after state, non-existent if this node was removed
+     * @return true if the {@link IndexNode} need to be opened and updated
+     */
+    public boolean isUpdateNeeded(NodeState before, NodeState after) {
+        return isStatusChanged(before, after) || 
isIndexDefinitionChanged(before, after);
+    }
+
     public void setAsyncIndexInfoService(AsyncIndexInfoService 
asyncIndexInfoService) {
         this.asyncIndexInfoService = asyncIndexInfoService;
     }
@@ -107,27 +114,27 @@ public abstract class FulltextIndexTrack
 
     private synchronized void diffAndUpdate(final NodeState root) {
         if (asyncIndexInfoService != null && 
!asyncIndexInfoService.hasIndexerUpdatedForAnyLane(this.root, root)) {
-            log.trace("No changed detected in async indexer state. Skipping 
further diff");
+            LOG.trace("No changed detected in async indexer state. Skipping 
further diff");
             this.root = root;
             return;
         }
 
-        Map<String, IndexNodeManager> original = indices;
-        final Map<String, IndexNodeManager> updates = newHashMap();
+        Map<String, I> original = indices;
+        final Map<String, I> updates = new HashMap<>();
 
-        Set<String> indexPaths = Sets.newHashSet();
+        Set<String> indexPaths = new HashSet<>();
         indexPaths.addAll(original.keySet());
         indexPaths.addAll(badIndexTracker.getIndexPaths());
 
-        List<Editor> editors = newArrayListWithCapacity(indexPaths.size());
+        List<Editor> editors = new ArrayList<>(indexPaths.size());
         for (final String path : indexPaths) {
             editors.add(new SubtreeEditor(new DefaultEditor() {
                 @Override
                 public void leave(NodeState before, NodeState after) {
                     try {
-                        if (isStatusChanged(before, after) || 
isIndexDefinitionChanged(before, after)) {
+                        if (isUpdateNeeded(before, after)) {
                             long start = PERF_LOGGER.start();
-                            IndexNodeManager index = openIndex(path, root, 
after);
+                            I index = openIndex(path, root, after);
                             PERF_LOGGER.end(start, -1, "[{}] Index found to be 
updated. Reopening the IndexNode", path);
                             updates.put(path, index); // index can be null
                         }
@@ -142,7 +149,7 @@ public abstract class FulltextIndexTrack
         this.root = root;
 
         if (!updates.isEmpty()) {
-            indices = ImmutableMap.<String, IndexNodeManager>builder()
+            indices = ImmutableMap.<String, I>builder()
                     .putAll(filterKeys(original, not(in(updates.keySet()))))
                     .putAll(filterValues(updates, notNull()))
                     .build();
@@ -154,25 +161,21 @@ public abstract class FulltextIndexTrack
             //Given that Tracker is now invoked from a BackgroundObserver
             //not a high concern
             for (String path : updates.keySet()) {
-                IndexNodeManager index = original.get(path);
-                try {
-                    if (index != null) {
-                        index.close();
-                    }
-                } catch (IOException e) {
-                    log.error("Failed to close Lucene index at " + path, e);
+                I index = original.get(path);
+                if (index != null) {
+                    index.close();
                 }
             }
         }
     }
 
     void refresh() {
-        log.info("Marked tracker to refresh upon next cycle");
+        LOG.info("Marked tracker to refresh upon next cycle");
         refresh = true;
     }
 
     public IndexNode acquireIndexNode(String path, String type) {
-        IndexNodeManager index = indices.get(path);
+        I index = indices.get(path);
         IndexNode indexNode = index != null ? index.acquire() : null;
         if (indexNode != null) {
             return indexNode;
@@ -183,7 +186,7 @@ public abstract class FulltextIndexTrack
 
     @Nullable
     public IndexDefinition getIndexDefinition(String indexPath){
-        IndexNodeManager node = indices.get(indexPath);
+        I node = indices.get(indexPath);
         if (node != null){
             //Accessing the definition should not require
             //locking as its immutable state
@@ -208,7 +211,7 @@ public abstract class FulltextIndexTrack
         // Retry the lookup from acquireIndexNode now that we're
         // synchronized. The acquire() call is guaranteed to succeed
         // since the close() method is also synchronized.
-        IndexNodeManager index = indices.get(path);
+        I index = indices.get(path);
         if (index != null) {
             IndexNode indexNode = index.acquire();
             return checkNotNull(indexNode);
@@ -229,7 +232,7 @@ public abstract class FulltextIndexTrack
                 if (index != null) {
                     IndexNode indexNode = index.acquire();
                     checkNotNull(indexNode);
-                    indices = ImmutableMap.<String, IndexNodeManager>builder()
+                    indices = ImmutableMap.<String, I>builder()
                             .putAll(indices)
                             .put(path, index)
                             .build();
@@ -237,7 +240,7 @@ public abstract class FulltextIndexTrack
                     return indexNode;
                 }
             } else if (node.exists()) {
-                log.warn("Cannot open Index at path {} as the index is not of 
type {}", path, type);
+                LOG.warn("Cannot open Index at path {} as the index is not of 
type {}", path, type);
             }
         } catch (Throwable e) {
             badIndexTracker.markBadIndexForRead(path, e);
@@ -251,7 +254,7 @@ public abstract class FulltextIndexTrack
         return !EqualsDiff.equals(before.getChildNode(STATUS_NODE), 
after.getChildNode(STATUS_NODE));
     }
 
-    private static boolean isIndexDefinitionChanged(NodeState before, 
NodeState after) {
+    protected static boolean isIndexDefinitionChanged(NodeState before, 
NodeState after) {
         return !EqualsDiff.equals(before.getChildNode(INDEX_DEFINITION_NODE), 
after.getChildNode(INDEX_DEFINITION_NODE));
     }
 }

Modified: 
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNodeManager.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNodeManager.java?rev=1880297&r1=1880296&r2=1880297&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNodeManager.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNodeManager.java
 Sat Jul 25 12:13:20 2020
@@ -16,53 +16,56 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.search.spi.query;
 
-import java.io.IOException;
 import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import org.apache.jackrabbit.oak.commons.PerfLogger;
 import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
 import org.apache.jackrabbit.oak.plugins.index.search.IndexNode;
 import 
org.apache.jackrabbit.oak.plugins.index.search.update.ReaderRefreshPolicy;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.jetbrains.annotations.Nullable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import static com.google.common.base.Preconditions.checkState;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.ASYNC_PROPERTY_NAME;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexUtils.getAsyncLaneName;
 
 /**
  * Keeps track of the open read sessions for an index.
  */
-public abstract class IndexNodeManager {
+public abstract class IndexNodeManager<I extends IndexNode> {
     /**
      * Name of the hidden node under which information about the checkpoints
      * seen and indexed by each async indexer is kept.
      */
     public static final String ASYNC = ":async";
 
-    private static final AtomicInteger SEARCHER_ID_COUNTER = new 
AtomicInteger();
+    private boolean closed = false;
 
-    private static final PerfLogger PERF_LOGGER =
-            new 
PerfLogger(LoggerFactory.getLogger(IndexNodeManager.class.getName() + ".perf"));
+    private final ReadWriteLock lock = new ReentrantReadWriteLock();
 
-    protected abstract IndexNodeManager open(String indexPath, NodeState root, 
NodeState defnNodeState);
+    private final Semaphore refreshLock = new Semaphore(1);
 
-    protected abstract void releaseResources();
+    private final Runnable refreshCallback = () -> {
+        if (refreshLock.tryAcquire()) {
+            try {
+                refreshReaders();
+            } finally {
+                refreshLock.release();
+            }
+        }
+    };
 
-    protected abstract IndexNode getIndexNode();
+    protected abstract String getName();
+
+    protected abstract I getIndexNode();
+
+    protected abstract IndexDefinition getDefinition();
 
     protected abstract ReaderRefreshPolicy getReaderRefreshPolicy();
 
     protected abstract void refreshReaders();
 
-    protected abstract String getName();
-
-    protected abstract IndexDefinition getDefinition();
+    protected abstract void releaseResources();
 
     static boolean hasAsyncIndexerRun(NodeState root, String indexPath, 
NodeState defnNodeState) {
         boolean hasAsyncNode = root.hasChildNode(ASYNC);
@@ -75,34 +78,16 @@ public abstract class IndexNodeManager {
             // useful only for tests - basically non-async index defs which 
don't rely on /:async
             // hence either readers are there (and this method doesn't come 
into play during open)
             // OR there is no cycle (where we return false correctly)
-            return  false;
+            return false;
         }
     }
 
-    private static final Logger log = 
LoggerFactory.getLogger(IndexNodeManager.class);
-
-    private final ReadWriteLock lock = new ReentrantReadWriteLock();
-
-    private final Semaphore refreshLock = new Semaphore(1);
-
-    private final Runnable refreshCallback = new Runnable() {
-        @Override
-        public void run() {
-            if (refreshLock.tryAcquire()) {
-                try {
-                    refreshReaders();
-                }finally {
-                    refreshLock.release();
-                }
-            }
-        }
-    };
-
-    private boolean closed = false;
-
+    protected void release() {
+        lock.readLock().unlock();
+    }
 
     @Nullable
-    IndexNode acquire() {
+    public I acquire() {
         lock.readLock().lock();
         if (closed) {
             lock.readLock().unlock();
@@ -111,7 +96,7 @@ public abstract class IndexNodeManager {
             boolean success = false;
             try {
                 
getReaderRefreshPolicy().refreshOnReadIfRequired(refreshCallback);
-                IndexNode indexNode = getIndexNode();
+                I indexNode = getIndexNode();
                 success = true;
                 return indexNode;
             } finally {
@@ -122,14 +107,12 @@ public abstract class IndexNodeManager {
         }
     }
 
-    private void release() {
-        lock.readLock().unlock();
-    }
-
-    void close() throws IOException {
+    public void close() {
         lock.writeLock().lock();
         try {
-            checkState(!closed);
+            if (closed) {
+                throw new IllegalStateException("IndexNodeManager already 
closed");
+            }
             closed = true;
         } finally {
             lock.writeLock().unlock();


Reply via email to