Author: chetanm
Date: Wed Oct  4 13:52:58 2017
New Revision: 1811074

URL: http://svn.apache.org/viewvc?rev=1811074&view=rev
Log:
OAK-6535 - Synchronous Lucene Property Indexes

MBean operation to expose index info for hybrid indexes

Added:
    
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java
   (with props)
Modified:
    jackrabbit/oak/trunk/oak-lucene/pom.xml
    
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBean.java
    
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBeanImpl.java
    
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexUtil.java
    
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleaner.java
    
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java

Modified: jackrabbit/oak/trunk/oak-lucene/pom.xml
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/pom.xml?rev=1811074&r1=1811073&r2=1811074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-lucene/pom.xml Wed Oct  4 13:52:58 2017
@@ -396,5 +396,11 @@
       <version>1.3</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>2.8.0</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBean.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBean.java?rev=1811074&r1=1811073&r2=1811074&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBean.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBean.java
 Wed Oct  4 13:52:58 2017
@@ -111,4 +111,8 @@ public interface LuceneIndexMBean {
     @Description("Performs any possible cleanup of the hybrid property 
indexes")
     String performPropertyIndexCleanup() throws CommitFailedException;
 
+
+    @Description("Fetches hybrid property index info as json for index at 
given path")
+    String getHybridIndexInfo(@Name("indexPath") String indexPath);
+
 }

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBeanImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBeanImpl.java?rev=1811074&r1=1811073&r2=1811074&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBeanImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexMBeanImpl.java
 Wed Oct  4 13:52:58 2017
@@ -51,6 +51,7 @@ import org.apache.jackrabbit.oak.json.Js
 import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
 import org.apache.jackrabbit.oak.plugins.index.IndexPathService;
 import 
org.apache.jackrabbit.oak.plugins.index.lucene.BadIndexTracker.BadIndexInfo;
+import 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexInfo;
 import 
org.apache.jackrabbit.oak.plugins.index.lucene.property.PropertyIndexCleaner;
 import 
org.apache.jackrabbit.oak.plugins.index.lucene.util.PathStoredFieldVisitor;
 import 
org.apache.jackrabbit.oak.plugins.index.lucene.directory.IndexConsistencyChecker;
@@ -346,6 +347,12 @@ public class LuceneIndexMBeanImpl extend
         return result;
     }
 
+    @Override
+    public String getHybridIndexInfo(String indexPath) {
+        NodeState idx = NodeStateUtils.getNode(nodeStore.getRoot(), indexPath);
+        return new HybridPropertyIndexInfo(idx).getInfoAsJson();
+    }
+
     private Result getConsistencyCheckResult(String indexPath, boolean 
fullCheck) throws IOException {
         NodeState root = nodeStore.getRoot();
         Level level = fullCheck ? Level.FULL : Level.BLOBS_ONLY;

Added: 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java?rev=1811074&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java
 Wed Oct  4 13:52:58 2017
@@ -0,0 +1,108 @@
+/*
+ * 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.lucene.property;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.TreeTraverser;
+import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.PROPERTY_INDEX;
+import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.PROP_HEAD_BUCKET;
+import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.PROP_PREVIOUS_BUCKET;
+import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.simplePropertyIndex;
+import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.uniquePropertyIndex;
+
+public class HybridPropertyIndexInfo {
+    private final JsopBuilder json = new JsopBuilder();
+    private final NodeState idx;
+
+    public HybridPropertyIndexInfo(NodeState idx) {
+        this.idx = idx;
+    }
+
+    public String getInfoAsJson(){
+        json.resetWriter();
+        json.object();
+        NodeState propertyIndexNode = idx.getChildNode(PROPERTY_INDEX);
+        for (ChildNodeEntry cne : propertyIndexNode.getChildNodeEntries()) {
+            NodeState propIdxState = cne.getNodeState();
+            String propName = cne.getName();
+            json.key(propName).object();
+            if (simplePropertyIndex(propIdxState)) {
+                collectBucketData(propIdxState);
+            } else if (uniquePropertyIndex(propIdxState)) {
+                
json.key("entryCount").value(propIdxState.getChildNodeCount(Integer.MAX_VALUE));
+                json.key("unique").value(true);
+            }
+            json.endObject();
+        }
+        json.endObject();
+        return JsopBuilder.prettyPrint(json.toString());
+    }
+
+    private void collectBucketData(NodeState propIdxState) {
+        String head = propIdxState.getString(PROP_HEAD_BUCKET);
+        String previous = propIdxState.getString(PROP_PREVIOUS_BUCKET);
+
+        for (ChildNodeEntry cne : propIdxState.getChildNodeEntries()) {
+            String bucketName = cne.getName();
+            NodeState bucket = cne.getNodeState();
+            json.key(bucketName).object();
+
+            json.key("type");
+            if (Objects.equals(head, bucketName)) {
+                json.value("head");
+            } else if (Objects.equals(previous, bucketName)) {
+                json.value("previous");
+            } else {
+                json.value("garbage");
+            }
+
+            
json.key("keyCount").value(bucket.getChildNodeCount(Integer.MAX_VALUE));
+            collectCounts(bucket);
+
+            json.endObject();
+        }
+    }
+
+    private void collectCounts(NodeState bucket) {
+        TreeTraverser<NodeState> t = new TreeTraverser<NodeState>() {
+            @Override
+            public Iterable<NodeState> children(NodeState root) {
+                return Iterables.transform(root.getChildNodeEntries(), 
ChildNodeEntry::getNodeState);
+            }
+        };
+        AtomicInteger matches = new AtomicInteger();
+        int totalCount = t.preOrderTraversal(bucket)
+                .transform((st) -> {
+                    if (st.getBoolean("match")) {
+                        matches.incrementAndGet();
+                    }
+                    return st;
+                }).size();
+        json.key("entryCount").value(matches.get());
+        json.key("totalCount").value(totalCount);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexUtil.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexUtil.java?rev=1811074&r1=1811073&r2=1811074&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexUtil.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexUtil.java
 Wed Oct  4 13:52:58 2017
@@ -20,6 +20,7 @@
 package org.apache.jackrabbit.oak.plugins.index.lucene.property;
 
 import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 class HybridPropertyIndexUtil {
     /**
@@ -59,4 +60,12 @@ class HybridPropertyIndexUtil {
     static String getNodeName(String propertyRelativePath) {
         return propertyRelativePath.replace('/', '_');
     }
+
+    static boolean simplePropertyIndex(NodeState propIdxState) {
+        return 
STORAGE_TYPE_CONTENT_MIRROR.equals(propIdxState.getString(PROP_STORAGE_TYPE));
+    }
+
+    static boolean uniquePropertyIndex(NodeState propIdxState) {
+        return 
STORAGE_TYPE_UNIQUE.equals(propIdxState.getString(PROP_STORAGE_TYPE));
+    }
 }

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleaner.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleaner.java?rev=1811074&r1=1811073&r2=1811074&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleaner.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleaner.java
 Wed Oct  4 13:52:58 2017
@@ -50,9 +50,8 @@ import static com.google.common.base.Pre
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
 import static 
org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.TYPE_LUCENE;
 import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.PROPERTY_INDEX;
-import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.PROP_STORAGE_TYPE;
-import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.STORAGE_TYPE_CONTENT_MIRROR;
-import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.STORAGE_TYPE_UNIQUE;
+import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.simplePropertyIndex;
+import static 
org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexUtil.uniquePropertyIndex;
 import static org.apache.jackrabbit.oak.spi.state.NodeStateUtils.getNode;
 
 public class PropertyIndexCleaner implements Runnable{
@@ -246,14 +245,6 @@ public class PropertyIndexCleaner implem
         return nb;
     }
 
-    private static boolean simplePropertyIndex(NodeState propIdxState) {
-        return 
STORAGE_TYPE_CONTENT_MIRROR.equals(propIdxState.getString(PROP_STORAGE_TYPE));
-    }
-
-    private static boolean uniquePropertyIndex(NodeState propIdxState) {
-        return 
STORAGE_TYPE_UNIQUE.equals(propIdxState.getString(PROP_STORAGE_TYPE));
-    }
-
     private static final class IndexInfo {
         final List<String> oldBucketPaths = new ArrayList<>();
 

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java?rev=1811074&r1=1811073&r2=1811074&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java
 Wed Oct  4 13:52:58 2017
@@ -27,6 +27,8 @@ import java.util.concurrent.TimeUnit;
 import javax.annotation.CheckForNull;
 
 import com.google.common.collect.ImmutableList;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
 import org.apache.jackrabbit.oak.InitialContent;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfo;
@@ -43,8 +45,10 @@ import org.apache.jackrabbit.oak.spi.com
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.apache.jackrabbit.oak.stats.Clock;
+import org.json.simple.parser.ParseException;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -58,9 +62,7 @@ import static org.apache.jackrabbit.oak.
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.empty;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 public class PropertyIndexCleanerTest {
@@ -175,6 +177,12 @@ public class PropertyIndexCleanerTest {
         //------------------------ Run 1
         asyncService.addInfo("async", 1200);
         assertCleanUpPerformed(cleaner.performCleanup(false), true);
+        assertJsonInfo(indexPath, "{\n" +
+                "  \"foo\": {\n" +
+                "    \"entryCount\": 1,\n" +
+                "    \"unique\": true\n" +
+                "  }\n" +
+                "}");
 
         // /a would be purged, /b would be retained as its created time 1150 
is not older than 100 wrt
         // indexer time of 1200
@@ -221,6 +229,22 @@ public class PropertyIndexCleanerTest {
         //------------------------ Run 1
         asyncService.addInfo("async", 1000);
         assertCleanUpPerformed(cleaner.performCleanup(false), true);
+        assertJsonInfo(indexPath, "{\n" +
+                "  \"foo\": {\n" +
+                "    \"1\": {\n" +
+                "      \"type\": \"previous\",\n" +
+                "      \"keyCount\": 1,\n" +
+                "      \"entryCount\": 1,\n" +
+                "      \"totalCount\": 3\n" +
+                "    },\n" +
+                "    \"2\": {\n" +
+                "      \"type\": \"head\",\n" +
+                "      \"keyCount\": 0,\n" +
+                "      \"entryCount\": 0,\n" +
+                "      \"totalCount\": 1\n" +
+                "    }\n" +
+                "  }\n" +
+                "}");
 
         //Second run should not run
         assertCleanUpPerformed(cleaner.performCleanup(false), false);
@@ -230,6 +254,17 @@ public class PropertyIndexCleanerTest {
         assertEquals(expected, stats.cleanupPerformed);
     }
 
+    private void assertJsonInfo(String indexPath, String expectedJson) throws 
ParseException {
+        NodeState idx = NodeStateUtils.getNode(nodeStore.getRoot(), indexPath);
+        String json = new HybridPropertyIndexInfo(idx).getInfoAsJson();
+        JsonObject j1 = (JsonObject) new JsonParser().parse(json);
+        JsonObject j2 = (JsonObject) new JsonParser().parse(expectedJson);
+
+        if (!j1.equals(j2)){
+            assertEquals(j1, j2);
+        }
+    }
+
     private void addIndex(String indexPath, IndexDefinitionBuilder defnb) 
throws CommitFailedException {
         NodeBuilder nb = nodeStore.getRoot().builder();
         child(nb, getParentPath(indexPath)).setChildNode(getName(indexPath), 
defnb.build());


Reply via email to