You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2019/08/07 09:58:56 UTC

svn commit: r1864609 - in /jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite: CompositeNodeStoreLuceneIndexTest.java CompositeNodeStoreQueryTest.java CompositeNodeStoreQueryTestBase.java

Author: thomasm
Date: Wed Aug  7 09:58:56 2019
New Revision: 1864609

URL: http://svn.apache.org/viewvc?rev=1864609&view=rev
Log:
OAK-7917 Composite node store: technical debt for create index / reindex

Added:
    jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreLuceneIndexTest.java
Modified:
    jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTest.java
    jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTestBase.java

Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreLuceneIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreLuceneIndexTest.java?rev=1864609&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreLuceneIndexTest.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreLuceneIndexTest.java Wed Aug  7 09:58:56 2019
@@ -0,0 +1,479 @@
+/*
+ * 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.composite;
+
+
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.RowIterator;
+import java.util.List;
+
+import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_COUNT;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.TestUtil.shutdown;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+@SuppressWarnings("ConstantConditions")
+public class CompositeNodeStoreLuceneIndexTest extends CompositeNodeStoreQueryTestBase {
+
+    private static String READ_ONLY_MOUNT_V1_NAME = "readOnlyV1";
+    private static String READ_ONLY_MOUNT_V2_NAME = "readOnlyV2";
+    // JCR repository
+    private CompositeRepo repoV1;
+    private CompositeRepo repoV2;
+    private static final int VERSION_1 = 1;
+    private static final int VERSION_2 = 2;
+
+    public CompositeNodeStoreLuceneIndexTest(NodeStoreKind root, NodeStoreKind mounts) {
+        super(root, mounts);
+    }
+
+    @Override
+    @Before
+    public void initStore() throws Exception {
+        globalStore = register(nodeStoreRoot.create(null));
+        repoV1 = new CompositeRepo(READ_ONLY_MOUNT_V1_NAME);
+        repoV1.initCompositeRepo();
+    }
+
+    /**
+     * Steps overview -
+     * Add a new index to composite repo and reindex
+     * Add the index def in global read write part of composite repo (read write part)
+     * Add the index def in read only repo
+     * Add content served by this index in both parts
+     * Query using composite repo session to see if index is used and results from both parts are returned correctly
+     * Reindex on composite session
+     */
+    @Test
+    public void addLuceneIndexAndReindex() throws Exception {
+        // create indexes in read-only and read write parts of repo 
+        // and content covered by them and check if index is used properly
+        repoV1.setupIndexAndContentInRepo("luceneTest", "foo", false, VERSION_1);
+
+        Session s1 = repoV1.getSession();
+        Node luceneTest = s1.getRootNode().getNode(INDEX_DEFINITIONS_NAME).getNode("luceneTest");
+        long reindexCount = luceneTest.getProperty(REINDEX_COUNT).getValue().getLong();
+
+        // Now we reindex and see everything works fine
+        luceneTest.setProperty(REINDEX_PROPERTY_NAME, true);
+        s1.save();
+
+        long reindexCount2 = luceneTest.getProperty(REINDEX_COUNT).getValue().getLong();
+        assertEquals(reindexCount2, reindexCount + 1);
+
+        repoV1.cleanup();
+    }
+
+    /**
+     * Given a composite node store , trying to create an index in read-write part
+     * with the same index node already existing in the read only part already
+     * we should get OakConstraint001 . This is the current behaviour,
+     * but can be worked upon (improved) in the future .
+     */
+    @Test
+    public void tryAddIndexInReadWriteWithIndexExistinginReadOnly() {
+        try {
+            repoV1.setupIndexAndContentInRepo("luceneTest", "foo", true, VERSION_1);
+            assertTrue(false);
+        } catch (Exception e) {
+            assert (e.getLocalizedMessage().contains(
+                    "OakConstraint0001: /oak:index/luceneTest/:oak:mount-readOnlyV1-index-data[[]]: The primary type null does not exist"));
+        }
+    }
+
+    /**
+     * Given a composite jcr repo with a lucene index with indexed data from both read only and read write parts
+     * We create a V2 of this repo which will have the lucene index removed -
+     * Expected behaviour - The same query that returned resutls from both readonly
+     * and readwrite in V1 should now return
+     * results - but it would be a traversal query and not use the index .
+     */
+    @Test
+    public void removeLuceneIndex() throws Exception {
+        repoV1.setupIndexAndContentInRepo("luceneTest", "foo", false, VERSION_1);
+
+        repoV2 = new CompositeRepo(READ_ONLY_MOUNT_V2_NAME);
+
+        repoV2.getReadOnlyRoot().getNode("libs").addNode("node-foo-0").setProperty("foo", "bar");
+        repoV2.getReadOnlySession().save();
+
+        repoV2.initCompositeRepo();
+
+        // Now we  have a read only V2 setup that doesn't have the lucene index and also doesn't have the
+        // USE_IF_EXISTS node that would enable the index .
+        // So now composite repo V2 - this will act as 2nd version of composite app
+        // This uses same global read write store as used in V1
+
+        // Check query traverses - and doesn't use the index available in read-write part
+        // since it is now disabled as path corresponding to useIfExists property is not present in new read only lib
+        QueryResult result = repoV2.executeQuery("explain /jcr:root//*[@foo = 'bar']", "xpath");
+        assertThat(result.getRows().next().toString(),
+                containsString("/* traverse \"//*\" where ([a].[foo] = 'bar'"));
+
+        // Check that proper nodes are returned by the query 
+        // even after traversal from both readonly version 2 and global read write parts
+        result = repoV2.executeQuery("/jcr:root//*[@foo = 'bar'] order by @jcr:path", "xpath");
+        assertEquals("/content-foo/node-0, /content-foo/node-1, " +
+                "/libs/node-foo-0", getResult(result, "jcr:path"));
+
+        // Now just for sake of completeness - check that the index is still used if we use V1 of composite app.
+        result = repoV1.executeQuery("explain /jcr:root//*[@foo = 'bar']", "xpath");
+        assertThat(result.getRows().next().toString(),
+                containsString("/* lucene:luceneTest(/oak:index/luceneTest) foo:bar"));
+
+        result = repoV1.executeQuery("/jcr:root//*[@foo = 'bar'] order by @jcr:path", "xpath");
+        assertEquals("/content-foo/node-0, " +
+                "/content-foo/node-1, " +
+                "/libs/node-luceneTest-0, " +
+                "/libs/node-luceneTest-1, " +
+                "/libs/node-luceneTest-2", getResult(result, "jcr:path"));
+
+        // At this point we have a V2 of app up and runnin with the index removed . 
+        // We can now close the V1 of the app
+        // and remove the index defintion from the global repo
+
+        repoV1.cleanup();
+
+        repoV2.getRoot().getNode(INDEX_DEFINITIONS_NAME).getNode("luceneTest").remove();
+
+        result = repoV2.executeQuery("explain /jcr:root//*[@foo = 'bar']", "xpath");
+        assertThat(result.getRows().next().toString(),
+                containsString("/* traverse \"//*\" where ([a].[foo] = 'bar'"));
+
+        // Check that proper nodes are returned by the query 
+        // even after traversal from both readonly version 2 and global read write parts
+        result = repoV2.executeQuery("/jcr:root//*[@foo = 'bar'] order by jcr:path", "xpath");
+        assertEquals("/content-foo/node-0, " +
+                "/content-foo/node-1, " +
+                "/libs/node-foo-0", getResult(result, "jcr:path"));
+
+        repoV2.cleanup();
+
+    }
+
+    /**
+     * Steps Overview -
+     * Create 2 indexes A and B and corresponding content in V1 app - in both global/composite  and readonly v1 repos
+     * Create 2 indexes B2 and C in read only v2 - B2 is effective replacement of B and C is a new index .
+     * Create respective content and new indexes in global repo as well.
+     * Create a version 2 of composite repo using the new read only repo V2
+     * Check that B2 and C are NOT used in composite repo V1 and are correctly used in composite repo V2
+     * Check that A and B are NOT used in composite repo V2 .
+     */
+    @Test
+    public void updateLuceneIndex() throws Exception {
+
+        // Create 2 index defintions in Version 1
+        // A
+        repoV1.setupIndexAndContentInRepo("luceneTest", "foo", false, VERSION_1);
+        // B
+        repoV1.setupIndexAndContentInRepo("luceneTest2", "foo2", false, VERSION_1);
+
+        // Now initialize V2 composite Repo
+        repoV2 = new CompositeRepo(READ_ONLY_MOUNT_V2_NAME);
+        repoV2.initCompositeRepo();
+
+        // Now Create 2 index definitons in Version 2 - one supposed to replace B and one entirely new
+        // C
+        repoV2.setupIndexAndContentInRepo("luceneTest3", "foo3", false, VERSION_2);
+        // B2
+        repoV2.setupIndexAndContentInRepo("luceneTest2_V2", "foo2", false, VERSION_2);
+
+        // Check V2 now uses luceneTest2_V2 for foo2 and no index for foo i.e traversal
+        QueryResult result = repoV2.executeQuery("explain /jcr:root//*[@foo = 'bar']", "xpath");
+        assertThat(result.getRows().next().toString(),
+                containsString("/* traverse \"//*\" where ([a].[foo] = 'bar'"));
+
+        // Check that proper nodes are returned by the query 
+        // even after traversal from both readonly version 2 and global read write parts
+        result = repoV2.executeQuery("/jcr:root//*[@foo = 'bar'] order by @jcr:path", "xpath");
+        assertEquals("/content-foo/node-0, /content-foo/node-1", getResult(result, "jcr:path"));
+
+        // Checking for prop foo2 now
+        result = repoV2.executeQuery("explain /jcr:root//*[@foo2 = 'bar']", "xpath");
+        assertThat(result.getRows().next().toString(),
+                containsString("/* lucene:luceneTest2_V2(/oak:index/luceneTest2_V2) foo2:bar"));
+
+        result = repoV2.executeQuery("/jcr:root//*[@foo2 = 'bar'] order by @jcr:path", "xpath");
+        assertEquals("/content-foo2/node-0, /content-foo2/node-1, " +
+                "/libs/node-luceneTest2_V2-0, " +
+                "/libs/node-luceneTest2_V2-1, " +
+                "/libs/node-luceneTest2_V2-2", getResult(result, "jcr:path"));
+
+        // Checking for foo3 now - new index on V2
+        result = repoV2.executeQuery("explain /jcr:root//*[@foo3 = 'bar']", "xpath");
+        assertThat(result.getRows().next().toString(),
+                containsString("/* lucene:luceneTest3(/oak:index/luceneTest3) foo3:bar"));
+
+        // Check that proper nodes are returned by the query 
+        // even after traversal from both readonly version 2 and global read write parts
+        result = repoV2.executeQuery("/jcr:root//*[@foo3 = 'bar'] order by @jcr:path", "xpath");
+        assertEquals("/content-foo3/node-0, " +
+                "/content-foo3/node-1, " +
+                "/libs/node-luceneTest3-0, " +
+                "/libs/node-luceneTest3-1, " +
+                "/libs/node-luceneTest3-2", getResult(result, "jcr:path"));
+
+        // Now check that the V1 instance still uses B for foo2 , A for foo and traverses for foo3
+        result = repoV1.executeQuery("explain /jcr:root//*[@foo = 'bar']", "xpath");
+        assertThat(result.getRows().next().toString(),
+                containsString("/* lucene:luceneTest(/oak:index/luceneTest) foo:bar"));
+
+        result = repoV1.executeQuery("/jcr:root//*[@foo = 'bar'] order by @jcr:path", "xpath");
+        assertEquals("/content-foo/node-0, " +
+                "/content-foo/node-1, " +
+                "/libs/node-luceneTest-0, " +
+                "/libs/node-luceneTest-1, " +
+                "/libs/node-luceneTest-2", getResult(result, "jcr:path"));
+
+        // foo 2 check
+        result = repoV1.executeQuery("explain /jcr:root//*[@foo2 = 'bar']", "xpath");
+        assertThat(result.getRows().next().toString(),
+                containsString("/* lucene:luceneTest2(/oak:index/luceneTest2) foo2:bar"));
+
+        result = repoV1.executeQuery("/jcr:root//*[@foo2 = 'bar'] order by @jcr:path", "xpath");
+        assertEquals("/content-foo2/node-0, " +
+                "/content-foo2/node-1, " +
+                "/libs/node-luceneTest2-0, " +
+                "/libs/node-luceneTest2-1, " +
+                "/libs/node-luceneTest2-2", getResult(result, "jcr:path"));
+
+        // foo 3 check
+        repoV1.login();
+        result = repoV1.executeQuery("explain /jcr:root//*[@foo3 = 'bar']", "xpath");
+        assertThat(result.getRows().next().toString(),
+                containsString("/* traverse \"//*\" where ([a].[foo3] = 'bar'"));
+
+        result = repoV1.executeQuery("/jcr:root//*[@foo3 = 'bar'] order by @jcr:path", "xpath");
+        assertEquals("/content-foo3/node-0, " +
+                "/content-foo3/node-1", getResult(result, "jcr:path"));
+
+        repoV1.cleanup();
+        repoV2.cleanup();
+    }
+
+    private static String getResult(QueryResult result, String propertyName) throws RepositoryException {
+        StringBuilder buff = new StringBuilder();
+        RowIterator it = result.getRows();
+        while (it.hasNext()) {
+            if (buff.length() > 0) {
+                buff.append(", ");
+            }
+            buff.append(it.nextRow().getValue(propertyName).getString());
+        }
+        return buff.toString();
+    }
+
+    private static Node createLuceneIndex(JackrabbitSession session, String name, String property) throws Exception {
+        Node n = session.getRootNode().getNode(INDEX_DEFINITIONS_NAME);
+        n = n.addNode(name);
+        n.setPrimaryType(IndexConstants.INDEX_DEFINITIONS_NODE_TYPE);
+        n.setProperty("compatVersion", 2);
+        n.setProperty(TYPE_PROPERTY_NAME, "lucene");
+        n.setProperty(REINDEX_PROPERTY_NAME, true);
+        n.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+        n.setProperty("includePropertyNames", new String[]{property});
+        session.save();
+        return n;
+    }
+
+    private static Node addOrGetNode(Node parent, String path, String primaryType) throws Exception {
+        return parent.hasNode(path) ? parent.getNode(path) : parent.addNode(path, primaryType);
+    }
+
+    private class CompositeRepo {
+        private Repository compositeRepository;
+        private JackrabbitSession compositeSession;
+        private Node compositeRoot;
+        private QueryManager compositeQueryManager;
+
+        private NodeStore readOnlyStore;
+        private Repository readOnlyRepository;
+        private CompositeNodeStore store;
+        private MountInfoProvider mip;
+        private JackrabbitSession readOnlySession;
+        private Node readOnlyRoot;
+        private String readOnlyMountName;
+
+        public Node getReadOnlyRoot() {
+            return readOnlyRoot;
+        }
+
+        public JackrabbitSession getReadOnlySession() {
+            return readOnlySession;
+        }
+
+        public JackrabbitSession getSession() {
+            return compositeSession;
+        }
+
+        public Node getRoot() {
+            return compositeRoot;
+        }
+
+        public QueryResult executeQuery(String statement, String language) throws RepositoryException {
+            return compositeQueryManager.createQuery(statement, language).execute();
+        }
+
+        CompositeRepo(String readOnlyMountName) throws Exception {
+            this.readOnlyMountName = readOnlyMountName;
+            this.readOnlyStore = register(mounts.create(readOnlyMountName));
+
+            this.mip = Mounts.newBuilder().readOnlyMount(readOnlyMountName, "/libs").build();
+
+            initReadOnlySeedRepo();
+            List<MountedNodeStore> nonDefaultStores = Lists.newArrayList();
+            nonDefaultStores.add(new MountedNodeStore(this.mip.getMountByName(readOnlyMountName), readOnlyStore));
+            this.store = new CompositeNodeStore(this.mip, globalStore, nonDefaultStores);
+
+        }
+
+        private void initCompositeRepo() throws Exception {
+            compositeRepository = createJCRRepository(this.store, this.mip);
+            compositeSession = (JackrabbitSession) compositeRepository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+            compositeRoot = compositeSession.getRootNode();
+            compositeQueryManager = compositeSession.getWorkspace().getQueryManager();
+        }
+
+        private void initReadOnlySeedRepo() throws Exception {
+            readOnlyRepository = createJCRRepository(readOnlyStore, this.mip);
+            readOnlySession = (JackrabbitSession) readOnlyRepository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+            readOnlyRoot = readOnlySession.getRootNode();
+            Node libs = readOnlyRoot.addNode("libs", NT_UNSTRUCTURED);
+            libs.setPrimaryType(NT_UNSTRUCTURED);
+        }
+
+        private void setupIndexAndContentInRepo(String indexName, String indexedProperty, boolean createIndexInReadOnlyFirst, int version) throws Exception {
+            String versionProp = (version == VERSION_1) ? "@v1" : "@v2";
+
+            if (createIndexInReadOnlyFirst) {
+                setupIndexAndContentInReadOnly(indexName, indexedProperty, version);
+            }
+
+            Node indexNode = createLuceneIndex(compositeSession, indexName, indexedProperty);
+            indexNode.setProperty(IndexConstants.USE_IF_EXISTS, "/libs/indexes/" + indexName + "/" + versionProp);
+            indexNode.setProperty(FulltextIndexConstants.PROP_REFRESH_DEFN, true);
+
+            // Add some content to read write now
+
+            Node n1 = addOrGetNode(compositeRoot, "content-" + indexedProperty, NT_UNSTRUCTURED);
+            for (int i = 0; i < 2; i++) {
+                Node n2 = addOrGetNode(n1, "node-" + i, NT_UNSTRUCTURED);
+                n2.setProperty(indexedProperty, "bar");
+                n2.setPrimaryType(NT_UNSTRUCTURED);
+            }
+            compositeSession.save();
+
+            if (!createIndexInReadOnlyFirst) {
+                setupIndexAndContentInReadOnly(indexName, indexedProperty, version);
+            }
+            ///////////////////////////////////////////////////////////////////////////////////////////
+            // Need to restart the composite repo after changes done to the read only part - needed for segement node store
+            // Otherwise the changes in read only repo are not visible to the cached reader.
+            restartRepo();
+            ///////////////////////////////////////////////////////////////////////////////////////////
+
+            // Need to save the composite session and login again for query to return results frorm read only part
+            compositeSession.save();
+
+            login();
+            QueryResult result = executeQuery("explain /jcr:root//*[@" + indexedProperty + " = 'bar']", "xpath");
+
+            assertThat(result.getRows().next().toString(),
+                    containsString("/* lucene:" + indexName + "(/oak:index/" + indexName + ") " + indexedProperty + ":bar"));
+
+            result = executeQuery("/jcr:root//*[@" + indexedProperty + " = 'bar'] order by @jcr:path", "xpath");
+            assertEquals("/content-" + indexedProperty + "/node-0, " +
+                    "/content-" + indexedProperty + "/node-1, " +
+                    "/libs/node-" + indexName + "-0, " +
+                    "/libs/node-" + indexName + "-1, " +
+                    "/libs/node-" + indexName + "-2", getResult(result, "jcr:path"));
+        }
+
+        private void setupIndexAndContentInReadOnly(String indexName, String indexedProperty, int version) throws Exception {
+            String versionProp = (version == 1) ? "@v1" : "@v2";
+            // Add some content to read-only  repo
+            for (int i = 0; i < 3; i++) {
+                Node b = readOnlyRoot.getNode("libs").addNode("node-" + indexName + "-" + i, NT_UNSTRUCTURED);
+                b.setProperty(indexedProperty, "bar");
+                b.setPrimaryType(NT_UNSTRUCTURED);
+            }
+
+            // index creation
+            Node readOnlyIndex = createLuceneIndex(readOnlySession, indexName, indexedProperty);
+            readOnlyIndex.setProperty(IndexConstants.USE_IF_EXISTS, "/libs/indexes/" + indexName + "/@" + versionProp);
+            readOnlyIndex.setProperty(FulltextIndexConstants.PROP_REFRESH_DEFN, true);
+
+            // Add /libs/indexes/luceneTest/@v1 to make this index usable/enabled
+            addOrGetNode(readOnlyRoot.getNode("libs"), "indexes", NT_UNSTRUCTURED).
+                    addNode(indexName, NT_UNSTRUCTURED).setProperty(versionProp.replace("@", ""), true);
+            readOnlySession.save();
+        }
+
+        private void restartRepo() throws Exception {
+            compositeSession.logout();
+            shutdown(compositeRepository);
+
+            List<MountedNodeStore> nonDefaultStores = Lists.newArrayList();
+            nonDefaultStores.add(new MountedNodeStore(this.mip.getMountByName(readOnlyMountName), readOnlyStore));
+            this.store = new CompositeNodeStore(this.mip, globalStore, nonDefaultStores);
+            compositeRepository = createJCRRepository(this.store, this.mip);
+            login();
+        }
+
+        private void login() throws Exception {
+            if (compositeSession != null) {
+                compositeSession.logout();
+            }
+            compositeSession = (JackrabbitSession) compositeRepository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+            compositeRoot = compositeSession.getRootNode();
+            compositeQueryManager = compositeSession.getWorkspace().getQueryManager();
+        }
+
+        private void cleanup() {
+            compositeSession.logout();
+            shutdown(compositeRepository);
+            readOnlySession.logout();
+            shutdown(readOnlyRepository);
+        }
+
+    }
+}

Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTest.java?rev=1864609&r1=1864608&r2=1864609&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTest.java Wed Aug  7 09:58:56 2019
@@ -23,6 +23,8 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_COUNT;
 import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
 import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
 import static org.hamcrest.CoreMatchers.containsString;
@@ -194,6 +196,46 @@ public class CompositeNodeStoreQueryTest
     }
 
     @Test
+    public void createAndReindex() throws Exception {
+        // create an index in both the read-only and the read-write store
+        NodeBuilder readOnlyBuilder = readOnlyStore.getRoot().builder();
+
+        // add nodes in the read-only area
+        for (int i = 0; i < 3; i++) {
+            NodeBuilder b = readOnlyBuilder.child("readOnly").child("node-" + i);
+            b.setProperty("asyncFoo", "bar");
+            b.setProperty("jcr:primaryType", "nt:base", Type.NAME);
+        }
+        createLuceneIndex(readOnlyBuilder);
+
+        NodeBuilder globalBuilder = globalStore.getRoot().builder();
+        createLuceneIndex(globalBuilder);
+
+        LuceneIndexEditorProvider iep = new LuceneIndexEditorProvider(indexCopier, indexTracker, null, null, mip);
+        EditorHook hook = new EditorHook(
+                new IndexUpdateProvider(iep, "async", false));
+        readOnlyStore.merge(readOnlyBuilder, hook, CommitInfo.EMPTY);
+        globalStore.merge(globalBuilder, hook, CommitInfo.EMPTY);
+        root.commit();
+
+        indexTracker.update(readOnlyStore.getRoot());
+        indexTracker.update(globalStore.getRoot());
+
+        //reindex
+        NodeBuilder builder;
+        builder = store.getRoot().builder();
+
+
+        builder.child(INDEX_DEFINITIONS_NAME).child("lucene").setProperty(REINDEX_PROPERTY_NAME,true);
+        store.merge(builder, hook, CommitInfo.EMPTY);
+        root.commit();
+
+        assertEquals(builder.child(INDEX_DEFINITIONS_NAME).child("lucene").getProperty(REINDEX_COUNT).getValue(Type.STRING),"2");
+
+
+    }
+
+    @Test
     public void luceneIndex() throws Exception {
         // create an index in both the read-only and the read-write store
         NodeBuilder readOnlyBuilder = readOnlyStore.getRoot().builder();
@@ -266,4 +308,4 @@ public class CompositeNodeStoreQueryTest
 
     }
 
-}
\ No newline at end of file
+}

Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTestBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTestBase.java?rev=1864609&r1=1864608&r2=1864609&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTestBase.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreQueryTestBase.java Wed Aug  7 09:58:56 2019
@@ -31,14 +31,15 @@ import java.io.File;
 import java.io.IOException;
 import java.text.ParseException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Arrays;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
+import javax.jcr.Repository;
 import javax.sql.DataSource;
 
 import org.apache.commons.io.FileUtils;
@@ -52,6 +53,7 @@ import org.apache.jackrabbit.oak.api.Res
 import org.apache.jackrabbit.oak.api.ResultRow;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.jcr.Jcr;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDataSourceFactory;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentNodeStoreBuilder;
@@ -102,8 +104,8 @@ import com.google.common.collect.Lists;
 @RunWith(Parameterized.class)
 public class CompositeNodeStoreQueryTestBase {
 
-    private final NodeStoreKind nodeStoreRoot;
-    private final NodeStoreKind mounts;
+    protected final NodeStoreKind nodeStoreRoot;
+    protected final NodeStoreKind mounts;
 
     private final List<NodeStoreRegistration> registrations = newArrayList();
 
@@ -139,7 +141,7 @@ public class CompositeNodeStoreQueryTest
     public static Collection<Object[]> data() {
         return Arrays.asList(new Object[][] {
             { NodeStoreKind.MEMORY, NodeStoreKind.MEMORY },
-            { NodeStoreKind.SEGMENT, NodeStoreKind.SEGMENT},
+            { NodeStoreKind.SEGMENT, NodeStoreKind.SEGMENT}
 //            { NodeStoreKind.DOCUMENT_H2, NodeStoreKind.DOCUMENT_H2},
 //            { NodeStoreKind.DOCUMENT_H2, NodeStoreKind.SEGMENT}
         });
@@ -265,6 +267,52 @@ public class CompositeNodeStoreQueryTest
         return oak;
     }
 
+    protected ContentRepository createRepository(NodeStore store, MountInfoProvider mip) {
+        return getOakRepo(store, mip).createContentRepository();
+    }
+
+    protected Repository createJCRRepository(NodeStore store, MountInfoProvider mip) {
+        return new Jcr(getOakRepo(store, mip)).createRepository();
+    }
+
+    Oak getOakRepo(NodeStore store, MountInfoProvider mip) {
+
+        try {
+            indexCopier = new IndexCopier(executorService, temporaryFolder.getRoot());
+        } catch (IOException e) {
+            throw new RuntimeException();
+        }
+        DefaultIndexReaderFactory indexReaderFactory = new DefaultIndexReaderFactory(mip, indexCopier);
+        indexTracker = new IndexTracker(indexReaderFactory);
+
+        LuceneIndexProvider luceneIndexProvider =
+                new LuceneIndexProvider(indexTracker);
+        LuceneIndexEditorProvider luceneIndexEditor;
+
+        if (mip == null ){
+            luceneIndexEditor = new LuceneIndexEditorProvider();
+            return new Oak(store).with(new InitialContent())
+                    .with(new OpenSecurityProvider())
+                    .with(luceneIndexEditor)
+                    .with((QueryIndexProvider) luceneIndexProvider)
+                    .with((Observer) luceneIndexProvider);
+        } else {
+            luceneIndexEditor = new LuceneIndexEditorProvider(indexCopier, indexTracker, null, null, mip);
+            return new Oak(store).with(new InitialContent())
+                    .with(new OpenSecurityProvider())
+                    .with(new PropertyIndexEditorProvider().with(mip))
+                    .with(new NodeCounterEditorProvider().with(mip))
+                    .with(new PropertyIndexProvider().with(mip))
+                    .with(luceneIndexEditor)
+                    .with((QueryIndexProvider) luceneIndexProvider)
+                    .with((Observer) luceneIndexProvider)
+                    .with(new NodeTypeIndexProvider().with(mip))
+                    .with(new ReferenceEditorProvider().with(mip))
+                    .with(new ReferenceIndexProvider().with(mip));
+        }
+
+    }
+
     protected List<String> executeQuery(String query, String language) {
         boolean pathsOnly = false;
         if (language.equals("xpath")) {
@@ -416,7 +464,8 @@ public class CompositeNodeStoreQueryTest
                         String directoryName = name != null ? "segment-" + name : "segment";
                         storePath = new File("target/classes/" + directoryName);
 
-                        String blobStoreDirectoryName = name != null ? "blob-" + name : "blob";
+                        //String blobStoreDirectoryName = name != null ? "blob-" + name : "blob";
+                        String blobStoreDirectoryName = "blob" ;
                         blobStorePath = "target/classes/" + blobStoreDirectoryName;
 
                         BlobStore blobStore = new FileBlobStore(blobStorePath);
@@ -492,10 +541,11 @@ public class CompositeNodeStoreQueryTest
         void close() throws Exception;
     }
 
-    private NodeStore register(NodeStoreRegistration reg) throws Exception {
+    protected NodeStore register(NodeStoreRegistration reg) throws Exception {
         registrations.add(reg);
 
         return reg.get();
     }
 
+
 }
\ No newline at end of file