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 ch...@apache.org on 2014/10/31 07:26:55 UTC

svn commit: r1635686 - in /jackrabbit/oak/branches/1.0: ./ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/ oak-lucene/src/test/java/org/apache/jackra...

Author: chetanm
Date: Fri Oct 31 06:26:55 2014
New Revision: 1635686

URL: http://svn.apache.org/r1635686
Log:
OAK-1724 - Enable copying of Lucene index to local file system for read queries

Merging 1634505,1634513

Added:
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/CopyOnReadStatsMBean.java
      - copied unchanged from r1634513, jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/CopyOnReadStatsMBean.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexCopier.java
      - copied, changed from r1634505, jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexCopier.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/
      - copied from r1634505, jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/
Modified:
    jackrabbit/oak/branches/1.0/   (props changed)
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexNode.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java
    jackrabbit/oak/branches/1.0/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java

Propchange: jackrabbit/oak/branches/1.0/
------------------------------------------------------------------------------
  Merged /jackrabbit/oak/trunk:r1634505,1634513

Modified: jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexNode.java?rev=1635686&r1=1635685&r2=1635686&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexNode.java (original)
+++ jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexNode.java Fri Oct 31 06:26:55 2014
@@ -27,6 +27,10 @@ import java.io.IOException;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
+import javax.annotation.Nullable;
+
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexCopier;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.ReadOnlyBuilder;
 import org.apache.lucene.index.DirectoryReader;
@@ -37,13 +41,16 @@ import org.apache.lucene.store.FSDirecto
 
 class IndexNode {
 
-    static IndexNode open(String name, NodeState defnNodeState)
+    static IndexNode open(String indexPath, NodeState defnNodeState,@Nullable IndexCopier cloner)
             throws IOException {
         Directory directory = null;
         IndexDefinition definition = new IndexDefinition(new ReadOnlyBuilder(defnNodeState));
         NodeState data = defnNodeState.getChildNode(INDEX_DATA_CHILD_NAME);
         if (data.exists()) {
             directory = new OakDirectory(new ReadOnlyBuilder(data), definition);
+            if (cloner != null){
+                directory = cloner.wrap(indexPath, definition, directory);
+            }
         } else if (PERSISTENCE_FILE.equalsIgnoreCase(defnNodeState.getString(PERSISTENCE_NAME))) {
             String path = defnNodeState.getString(PERSISTENCE_PATH);
             if (path != null && new File(path).exists()) {
@@ -53,7 +60,7 @@ class IndexNode {
 
         if (directory != null) {
             try {
-                IndexNode index = new IndexNode(name, definition, directory);
+                IndexNode index = new IndexNode(PathUtils.getName(indexPath), definition, directory);
                 directory = null; // closed in Index.close()
                 return index;
             } finally {

Modified: jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java?rev=1635686&r1=1635685&r2=1635686&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java (original)
+++ jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java Fri Oct 31 06:26:55 2014
@@ -35,6 +35,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexCopier;
 import org.apache.jackrabbit.oak.spi.commit.CompositeEditor;
 import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
@@ -53,10 +54,20 @@ class IndexTracker {
     private static final Logger log =
             LoggerFactory.getLogger(IndexTracker.class);
 
+    private final IndexCopier cloner;
+
     private NodeState root = EMPTY_NODE;
 
     private volatile Map<String, IndexNode> indices = emptyMap();
 
+    IndexTracker() {
+        this(null);
+    }
+
+    IndexTracker(IndexCopier cloner){
+        this.cloner = cloner;
+    }
+
     synchronized void close() {
         Map<String, IndexNode> indices = this.indices;
         this.indices = emptyMap();
@@ -77,14 +88,13 @@ class IndexTracker {
         List<Editor> editors = newArrayListWithCapacity(original.size());
         for (Map.Entry<String, IndexNode> entry : original.entrySet()) {
             final String path = entry.getKey();
-            final String name = entry.getValue().getName();
 
             editors.add(new SubtreeEditor(new DefaultEditor() {
                 @Override
                 public void leave(NodeState before, NodeState after) {
                     try {
                         // TODO: Use DirectoryReader.openIfChanged()
-                        IndexNode index = IndexNode.open(name, after);
+                        IndexNode index = IndexNode.open(path, after, cloner);
                         updates.put(path, index); // index can be null
                     } catch (IOException e) {
                         log.error("Failed to open Lucene index at " + path, e);
@@ -102,6 +112,8 @@ class IndexTracker {
                     .putAll(filterValues(updates, notNull()))
                     .build();
 
+            //TODO This might take some time as close need to acquire the
+            //write lock which might be held by current running searches
             for (String path : updates.keySet()) {
                 IndexNode index = original.get(path);
                 try {
@@ -141,10 +153,9 @@ class IndexTracker {
             node = node.getChildNode(name);
         }
 
-        final String indexName = PathUtils.getName(path);
         try {
             if (isLuceneIndexNode(node)) {
-                index = IndexNode.open(indexName, node);
+                index = IndexNode.open(path, node, cloner);
                 if (index != null) {
                     checkState(index.acquire());
                     indices = ImmutableMap.<String, IndexNode>builder()

Modified: jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java?rev=1635686&r1=1635685&r2=1635686&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java (original)
+++ jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java Fri Oct 31 06:26:55 2014
@@ -38,12 +38,20 @@ import com.google.common.collect.Immutab
  */
 public class LuceneIndexProvider implements QueryIndexProvider, Observer, Closeable {
 
-    protected final IndexTracker tracker = new IndexTracker();
+    protected final IndexTracker tracker;
 
     protected volatile Analyzer analyzer = LuceneIndexConstants.ANALYZER;
 
     protected volatile NodeAggregator aggregator = null;
 
+    public LuceneIndexProvider() {
+        this(new IndexTracker());
+    }
+
+    public LuceneIndexProvider(IndexTracker tracker) {
+        this.tracker = tracker;
+    }
+
     public void close() {
         tracker.close();
     }

Modified: jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java?rev=1635686&r1=1635685&r2=1635686&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java (original)
+++ jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java Fri Oct 31 06:26:55 2014
@@ -19,12 +19,15 @@
 
 package org.apache.jackrabbit.oak.plugins.index.lucene;
 
+import java.io.File;
 import java.util.List;
 import java.util.Map;
 
 import javax.management.NotCompliantMBeanException;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
+import org.apache.commons.io.FilenameUtils;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -37,9 +40,12 @@ import org.apache.jackrabbit.oak.commons
 import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
 import org.apache.jackrabbit.oak.plugins.index.aggregate.AggregateIndexProvider;
 import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexCopier;
 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;
+import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardExecutor;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.util.InfoStream;
 import org.osgi.framework.BundleContext;
@@ -47,15 +53,18 @@ import org.osgi.framework.ServiceRegistr
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static com.google.common.base.Preconditions.checkNotNull;
 import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
 
 @SuppressWarnings("UnusedDeclaration")
 @Component(metatype = true, label = "Apache Jackrabbit Oak LuceneIndexProvider")
 public class LuceneIndexProviderService {
+    public static final String REPOSITORY_HOME = "repository.home";
 
     private LuceneIndexProvider indexProvider;
 
     private final List<ServiceRegistration> regs = Lists.newArrayList();
+    private final List<Registration> oakRegs = Lists.newArrayList();
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
@@ -80,12 +89,30 @@ public class LuceneIndexProviderService 
             "controlled via changing log level for category 'oak.lucene' to debug")
     private static final String PROP_DEBUG = "debug";
 
-    private Registration mbeanReg;
+    @Property(
+            boolValue = false,
+            label = "Enable CopyOnRead",
+            description = "Enable copying of Lucene index to local file system to improve query performance"
+    )
+    private static final String PROP_COPY_ON_READ = "enableCopyOnReadSupport";
+
+    @Property(
+            label = "Local index storage path",
+            description = "Local file system path where Lucene indexes would be copied when CopyOnRead is enabled. " +
+                    "If not specified then indexes would be stored under 'index' dir under Repository Home"
+    )
+    private static final String PROP_LOCAL_INDEX_DIR = "localIndexDir";
+
+    private Whiteboard whiteboard;
+
+    private WhiteboardExecutor executor;
 
     @Activate
     private void activate(BundleContext bundleContext, Map<String, ?> config)
             throws NotCompliantMBeanException {
-        indexProvider = new LuceneIndexProvider();
+        whiteboard = new OsgiWhiteboard(bundleContext);
+
+        indexProvider = new LuceneIndexProvider(createTracker(bundleContext, config));
         initializeLogging(config);
         initialize();
 
@@ -94,11 +121,11 @@ public class LuceneIndexProviderService 
         regs.add(bundleContext.registerService(QueryIndexProvider.class.getName(), aggregate, null));
         regs.add(bundleContext.registerService(Observer.class.getName(), indexProvider, null));
 
-        mbeanReg = registerMBean(new OsgiWhiteboard(bundleContext),
+        oakRegs.add(registerMBean(whiteboard,
                 LuceneIndexMBean.class,
                 new LuceneIndexMBeanImpl(indexProvider.getTracker()),
                 LuceneIndexMBean.TYPE,
-                "Lucene Index statistics");
+                "Lucene Index statistics"));
     }
 
     @Deactivate
@@ -107,8 +134,8 @@ public class LuceneIndexProviderService 
             reg.unregister();
         }
 
-        if(mbeanReg != null){
-            mbeanReg.unregister();
+        for (Registration reg : oakRegs){
+            reg.unregister();
         }
 
         if (indexProvider != null) {
@@ -116,6 +143,10 @@ public class LuceneIndexProviderService 
             indexProvider = null;
         }
 
+        if (executor != null){
+            executor.stop();
+        }
+
         InfoStream.setDefault(InfoStream.NO_OUTPUT);
     }
 
@@ -143,6 +174,38 @@ public class LuceneIndexProviderService 
         }
     }
 
+    private IndexTracker createTracker(BundleContext bundleContext, Map<String, ?> config) {
+        boolean enableCopyOnRead = PropertiesUtil.toBoolean(config.get(PROP_COPY_ON_READ), false);
+        if (enableCopyOnRead){
+            String indexDirPath = PropertiesUtil.toString(config.get(PROP_LOCAL_INDEX_DIR), null);
+            if (Strings.isNullOrEmpty(indexDirPath)) {
+                String repoHome = bundleContext.getProperty(REPOSITORY_HOME);
+                if (repoHome != null){
+                    indexDirPath = FilenameUtils.concat(repoHome, "index");
+                }
+            }
+
+            checkNotNull(indexDirPath, "Index directory cannot be determined as neither index " +
+                    "directory path [%s] nor repository home [%s] defined", PROP_LOCAL_INDEX_DIR, REPOSITORY_HOME);
+
+            File indexDir = new File(indexDirPath);
+            executor = new WhiteboardExecutor();
+            executor.start(whiteboard);
+            IndexCopier copier = new IndexCopier(executor, indexDir);
+            log.info("Enabling CopyOnRead support. Index files would be copied under {}", indexDir.getAbsolutePath());
+
+            oakRegs.add(registerMBean(whiteboard,
+                    CopyOnReadStatsMBean.class,
+                    copier,
+                    CopyOnReadStatsMBean.TYPE,
+                    "CopyOnRead support statistics"));
+
+            return new IndexTracker(copier);
+        }
+
+        return new IndexTracker();
+    }
+
     protected void bindNodeAggregator(NodeAggregator aggregator) {
         this.nodeAggregator = aggregator;
         initialize();

Copied: jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexCopier.java (from r1634505, jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexCopier.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexCopier.java?p2=jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexCopier.java&p1=jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexCopier.java&r1=1634505&r2=1635686&rev=1635686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexCopier.java (original)
+++ jackrabbit/oak/branches/1.0/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexCopier.java Fri Oct 31 06:26:55 2014
@@ -22,14 +22,30 @@ package org.apache.jackrabbit.oak.plugin
 import java.io.File;
 import java.io.IOException;
 import java.util.Collection;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
 
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.hash.Hashing;
+import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.oak.commons.IOUtils;
+import org.apache.jackrabbit.oak.plugins.index.lucene.CopyOnReadStatsMBean;
 import org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition;
 import org.apache.lucene.store.BaseDirectory;
 import org.apache.lucene.store.Directory;
@@ -43,13 +59,19 @@ import org.slf4j.LoggerFactory;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.Maps.newConcurrentMap;
 
-public class IndexCopier {
+public class IndexCopier implements CopyOnReadStatsMBean {
     private static final Set<String> REMOTE_ONLY = ImmutableSet.of("segments.gen");
 
     private final Logger log = LoggerFactory.getLogger(getClass());
     private final Executor executor;
     private final File indexRootDir;
 
+    private final AtomicInteger localReadCount = new AtomicInteger();
+    private final AtomicInteger remoteReadCount = new AtomicInteger();
+    private final AtomicLong downloadSize = new AtomicLong();
+    private final AtomicLong downloadTime = new AtomicLong();
+    private final Map<String, String> indexPathMapping = Maps.newConcurrentMap();
+
     public IndexCopier(Executor executor, File indexRootDir) {
         this.executor = executor;
         this.indexRootDir = indexRootDir;
@@ -67,6 +89,7 @@ public class IndexCopier {
         if (!indexDir.exists()) {
             checkState(indexDir.mkdirs(), "Cannot create directory %s", indexDir);
         }
+        indexPathMapping.put(indexPath, indexDir.getAbsolutePath());
         return FSDirectory.open(indexDir);
     }
 
@@ -126,6 +149,7 @@ public class IndexCopier {
                 if (ref.isLocalValid()) {
                     return files.get(name).openLocalInput(context);
                 } else {
+                    remoteReadCount.incrementAndGet();
                     return remote.openInput(name, context);
                 }
             }
@@ -151,8 +175,11 @@ public class IndexCopier {
                     String name = reference.name;
                     try {
                         if (!local.fileExists(name)) {
+                            long start = System.currentTimeMillis();
                             remote.copy(local, name, name, IOContext.READ);
                             reference.markValid();
+                            downloadTime.addAndGet(System.currentTimeMillis() - start);
+                            downloadSize.addAndGet(remote.fileLength(name));
                         } else {
                             long localLength = local.fileLength(name);
                             long remoteLength = remote.fileLength(name);
@@ -246,6 +273,7 @@ public class IndexCopier {
             }
 
             IndexInput openLocalInput( IOContext context) throws IOException {
+                localReadCount.incrementAndGet();
                 return local.openInput(name, context);
             }
 
@@ -254,4 +282,83 @@ public class IndexCopier {
             }
         }
     }
+
+    //~------------------------------------------< CopyOnReadStatsMBean >
+
+    @Override
+    public TabularData getIndexPathMapping() {
+        TabularDataSupport tds;
+        try{
+            TabularType tt = new TabularType(IndexMappingData.class.getName(),
+                    "Lucene Index Stats", IndexMappingData.TYPE, new String[]{"jcrPath"});
+            tds = new TabularDataSupport(tt);
+            for (Map.Entry<String, String> e : indexPathMapping.entrySet()){
+                tds.put(new CompositeDataSupport(IndexMappingData.TYPE,
+                        IndexMappingData.FIELD_NAMES,
+                        new String[] {e.getKey(), e.getValue()}));
+            }
+        } catch (OpenDataException e){
+            throw new IllegalStateException(e);
+        }
+        return tds;
+    }
+
+    @Override
+    public int getLocalReadCount() {
+        return localReadCount.get();
+    }
+
+    @Override
+    public int getRemoteReadCount() {
+        return remoteReadCount.get();
+    }
+
+    @Override
+    public String getDownloadSize() {
+        return IOUtils.humanReadableByteCount(downloadSize.get());
+    }
+
+    @Override
+    public long getDownloadTime() {
+        return downloadTime.get();
+    }
+
+    @Override
+    public String getLocalIndexSize() {
+        return IOUtils.humanReadableByteCount(FileUtils.sizeOfDirectory(indexRootDir));
+    }
+
+    private static class IndexMappingData {
+        static final String[] FIELD_NAMES = new String[]{
+                "jcrPath",
+                "fsPath",
+        };
+
+        static final String[] FIELD_DESCRIPTIONS = new String[]{
+                "JCR Path",
+                "Filesystem Path",
+        };
+
+        static final OpenType[] FIELD_TYPES = new OpenType[]{
+                SimpleType.STRING,
+                SimpleType.STRING,
+        };
+
+        static final CompositeType TYPE = createCompositeType();
+
+        static CompositeType createCompositeType() {
+            try {
+                return new CompositeType(
+                        IndexMappingData.class.getName(),
+                        "Composite data type for Index Mapping Data",
+                        IndexMappingData.FIELD_NAMES,
+                        IndexMappingData.FIELD_DESCRIPTIONS,
+                        IndexMappingData.FIELD_TYPES);
+            } catch (OpenDataException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+    }
+
 }

Modified: jackrabbit/oak/branches/1.0/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java?rev=1635686&r1=1635685&r2=1635686&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java (original)
+++ jackrabbit/oak/branches/1.0/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java Fri Oct 31 06:26:55 2014
@@ -24,6 +24,7 @@ import javax.annotation.Nullable;
 
 import static com.google.common.collect.ImmutableList.copyOf;
 import static com.google.common.collect.Iterators.transform;
+import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
 import static javax.jcr.PropertyType.TYPENAME_STRING;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -43,6 +44,7 @@ import static org.apache.jackrabbit.oak.
 import com.google.common.base.Function;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexCopier;
 import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
 import org.apache.jackrabbit.oak.query.ast.Operator;
@@ -271,6 +273,33 @@ public class LuceneIndexTest {
         assertQuery(tracker, indexed, "foo2", "bar2");
     }
 
+    @Test
+    public void luceneWithCopyOnReadDir() throws Exception{
+        NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+        newLuceneIndexDefinition(index, "lucene",
+                ImmutableSet.of(TYPENAME_STRING));
+
+        NodeState before = builder.getNodeState();
+        builder.setProperty("foo", "bar");
+        NodeState after = builder.getNodeState();
+
+        NodeState indexed = HOOK.processCommit(before, after,CommitInfo.EMPTY);
+
+        File indexRootDir = new File(getIndexDir());
+        IndexTracker tracker = new IndexTracker(new IndexCopier(sameThreadExecutor(), indexRootDir));
+        tracker.update(indexed);
+
+        assertQuery(tracker, indexed, "foo", "bar");
+
+        builder = indexed.builder();
+        builder.setProperty("foo2", "bar2");
+        indexed = HOOK.processCommit(indexed, builder.getNodeState(),CommitInfo.EMPTY);
+        tracker.update(indexed);
+
+        assertQuery(tracker, indexed, "foo2", "bar2");
+    }
+
+
     private void assertQuery(IndexTracker tracker, NodeState indexed, String key, String value){
         AdvancedQueryIndex queryIndex = new LuceneIndex(tracker, analyzer, null);
         FilterImpl filter = createFilter(NT_BASE);