You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2008/09/18 15:18:00 UTC

svn commit: r696653 - in /jackrabbit/trunk: ./ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/

Author: mreutegg
Date: Thu Sep 18 06:17:59 2008
New Revision: 696653

URL: http://svn.apache.org/viewvc?rev=696653&view=rev
Log:
JCR-1363: Migrate to Lucene 2.3

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexReader.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RefCountingIndexReader.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReleaseableIndexReader.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractExcerpt.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CachingMultiIndexReader.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CommittableIndexReader.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMerger.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndexReader.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReadOnlyIndexReader.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Recovery.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedIndexReader.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/VolatileIndex.java
    jackrabbit/trunk/pom.xml

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractExcerpt.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractExcerpt.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractExcerpt.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractExcerpt.java Thu Sep 18 06:17:59 2008
@@ -144,7 +144,7 @@
                 return null;
             }
         } finally {
-            reader.close();
+            Util.closeOrRelease(reader);
         }
     }
 
@@ -217,7 +217,7 @@
             } finally {
                 // only close reader if this method opened one
                 if (reader == null) {
-                    r.close();
+                    Util.closeOrRelease(r);
                 }
             }
             rewritten = true;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java Thu Sep 18 06:17:59 2008
@@ -20,6 +20,8 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.index.SerialMergeScheduler;
+import org.apache.lucene.index.LogDocMergePolicy;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
@@ -109,6 +111,12 @@
     private IndexingQueue indexingQueue;
 
     /**
+     * Flag that indicates whether there was an index present in the directory
+     * when this AbstractIndex was created.
+     */
+    private boolean isExisting;
+
+    /**
      * Constructs an index with an <code>analyzer</code> and a
      * <code>directory</code>.
      *
@@ -131,8 +139,9 @@
         this.directory = directory;
         this.cache = cache;
         this.indexingQueue = indexingQueue;
+        this.isExisting = IndexReader.indexExists(directory);
 
-        if (!IndexReader.indexExists(directory)) {
+        if (!isExisting) {
             indexWriter = new IndexWriter(directory, analyzer);
             // immediately close, now that index has been created
             indexWriter.close();
@@ -152,6 +161,17 @@
     }
 
     /**
+     * Returns <code>true</code> if this index was openend on a directory with
+     * an existing index in it; <code>false</code> otherwise.
+     *
+     * @return <code>true</code> if there was an index present when this index
+     *          was created; <code>false</code> otherwise.
+     */
+    boolean isExisting() {
+        return isExisting;
+    }
+
+    /**
      * Adds documents to this index and invalidates the shared reader.
      *
      * @param docs the documents to add.
@@ -248,7 +268,7 @@
         if (readOnlyReader != null) {
             if (readOnlyReader.getDeletedDocsVersion() == modCount) {
                 // reader up-to-date
-                readOnlyReader.incrementRefCount();
+                readOnlyReader.acquire();
                 return readOnlyReader;
             } else {
                 // reader outdated
@@ -256,12 +276,12 @@
                     // not in use, except by this index
                     // update the reader
                     readOnlyReader.updateDeletedDocs(modifiableReader);
-                    readOnlyReader.incrementRefCount();
+                    readOnlyReader.acquire();
                     return readOnlyReader;
                 } else {
                     // cannot update reader, it is still in use
                     // need to create a new instance
-                    readOnlyReader.close();
+                    readOnlyReader.release();
                     readOnlyReader = null;
                 }
             }
@@ -280,7 +300,7 @@
             sharedReader = new SharedIndexReader(cr);
         }
         readOnlyReader = new ReadOnlyIndexReader(sharedReader, deleted, modCount);
-        readOnlyReader.incrementRefCount();
+        readOnlyReader.acquire();
         return readOnlyReader;
     }
 
@@ -305,6 +325,9 @@
             indexWriter.setMaxFieldLength(maxFieldLength);
             indexWriter.setUseCompoundFile(useCompoundFile);
             indexWriter.setInfoStream(STREAM_LOGGER);
+            indexWriter.setRAMBufferSizeMB(IndexWriter.DISABLE_AUTO_FLUSH);
+            indexWriter.setMergeScheduler(new SerialMergeScheduler());
+            indexWriter.setMergePolicy(new LogDocMergePolicy());
         }
         return indexWriter;
     }
@@ -326,7 +349,7 @@
      */
     protected synchronized void commit(boolean optimize) throws IOException {
         if (indexReader != null) {
-            indexReader.commitDeleted();
+            indexReader.flush();
         }
         if (indexWriter != null) {
             log.debug("committing IndexWriter.");
@@ -346,6 +369,20 @@
      * Closes this index, releasing all held resources.
      */
     synchronized void close() {
+        releaseWriterAndReaders();
+        if (directory != null) {
+            try {
+                directory.close();
+            } catch (IOException e) {
+                directory = null;
+            }
+        }
+    }
+
+    /**
+     * Releases all potentially held index writer and readers.
+     */
+    protected void releaseWriterAndReaders() {
         if (indexWriter != null) {
             try {
                 indexWriter.close();
@@ -364,24 +401,19 @@
         }
         if (readOnlyReader != null) {
             try {
-                readOnlyReader.close();
+                readOnlyReader.release();
             } catch (IOException e) {
                 log.warn("Exception closing index reader: " + e.toString());
             }
+            readOnlyReader = null;
         }
         if (sharedReader != null) {
             try {
-                sharedReader.close();
+                sharedReader.release();
             } catch (IOException e) {
                 log.warn("Exception closing index reader: " + e.toString());
             }
-        }
-        if (directory != null) {
-            try {
-                directory.close();
-            } catch (IOException e) {
-                directory = null;
-            }
+            sharedReader = null;
         }
     }
 
@@ -393,12 +425,12 @@
     protected synchronized void invalidateSharedReader() throws IOException {
         // also close the read-only reader
         if (readOnlyReader != null) {
-            readOnlyReader.close();
+            readOnlyReader.release();
             readOnlyReader = null;
         }
         // invalidate shared reader
         if (sharedReader != null) {
-            sharedReader.close();
+            sharedReader.release();
             sharedReader = null;
         }
     }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CachingMultiIndexReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CachingMultiIndexReader.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CachingMultiIndexReader.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CachingMultiIndexReader.java Thu Sep 18 06:17:59 2008
@@ -65,11 +65,9 @@
      *
      * @param subReaders the sub readers.
      * @param cache the document number cache.
-     * @throws IOException if an error occurs while reading from the indexes.
      */
     public CachingMultiIndexReader(ReadOnlyIndexReader[] subReaders,
-                              DocNumberCache cache)
-            throws IOException {
+                                   DocNumberCache cache) {
         super(subReaders);
         this.cache = cache;
         this.subReaders = subReaders;
@@ -150,20 +148,27 @@
 
     /**
      * Increments the reference count of this reader. Each call to this method
-     * must later be acknowledged by a call to {@link #close()}
+     * must later be acknowledged by a call to {@link #release()}.
      */
-    synchronized void incrementRefCount() {
+    synchronized void acquire() {
         refCount++;
     }
 
     /**
-     * Decrements the reference count and closes the underlying readers if this
-     * reader is not in use anymore.
-     * @throws IOException if an error occurs while closing this reader.
+     * {@inheritDoc}
      */
-    protected synchronized void doClose() throws IOException {
+    public synchronized final void release() throws IOException {
         if (--refCount == 0) {
-            super.doClose();
+            close();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected synchronized void doClose() throws IOException {
+        for (int i = 0; i < subReaders.length; i++) {
+            subReaders[i].release();
         }
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CommittableIndexReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CommittableIndexReader.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CommittableIndexReader.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/CommittableIndexReader.java Thu Sep 18 06:17:59 2008
@@ -60,15 +60,6 @@
     //------------------------< additional methods >----------------------------
 
     /**
-     * Commits the documents marked as deleted to disc.
-     *
-     * @throws IOException if an error occurs while writing.
-     */
-    void commitDeleted() throws IOException {
-        commit();
-    }
-
-    /**
      * @return the modification count of this index reader.
      */
     long getModificationCount() {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java Thu Sep 18 06:17:59 2008
@@ -22,7 +22,6 @@
 import org.apache.jackrabbit.core.state.ChildNodeEntry;
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.uuid.UUID;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.document.Document;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -153,7 +152,7 @@
         Set multipleEntries = new HashSet();
         // collect all documents UUIDs
         documentUUIDs = new HashSet();
-        IndexReader reader = index.getIndexReader();
+        CachingMultiIndexReader reader = index.getIndexReader();
         try {
             for (int i = 0; i < reader.maxDoc(); i++) {
                 if (i > 10 && i % (reader.maxDoc() / 5) == 0) {
@@ -174,7 +173,7 @@
                 }
             }
         } finally {
-            reader.close();
+            reader.release();
         }
 
         // create multiple entries errors
@@ -212,7 +211,7 @@
                 }
             }
         } finally {
-            reader.close();
+            reader.release();
         }
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java Thu Sep 18 06:17:59 2008
@@ -115,14 +115,14 @@
 
     /**
      * Returns a named value for use as a term in the index. The named
-     * value is of the form: <code>fieldName</code> + '\uFFFF' + value
+     * value is of the form: <code>fieldName</code> + '[' + value
      *
      * @param fieldName the field name.
      * @param value the value.
      * @return value prefixed with field name.
      */
     public static String createNamedValue(String fieldName, String value) {
-        return fieldName + '\uFFFF' + value;
+        return fieldName + '[' + value;
     }
 
     /**
@@ -131,10 +131,9 @@
      * does not contain a name prefix, this method return 0.
      *
      * @param namedValue the named value as created by {@link #createNamedValue(String, String)}.
-     * @return the length of the field prefix including the separator char
-     *         (\uFFFF).
+     * @return the length of the field prefix including the separator char '['.
      */
     public static int getNameLength(String namedValue) {
-        return namedValue.indexOf('\uFFFF') + 1;
+        return namedValue.indexOf('[') + 1;
     }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMerger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMerger.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMerger.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMerger.java Thu Sep 18 06:17:59 2008
@@ -305,13 +305,13 @@
 
                         // force initializing of caches
                         time = System.currentTimeMillis();
-                        index.getReadOnlyIndexReader().close();
+                        index.getReadOnlyIndexReader().release();
                         time = System.currentTimeMillis() - time;
                         log.debug("reader obtained in {} ms", new Long(time));
                     } finally {
                         for (int i = 0; i < readers.length; i++) {
                             try {
-                                readers[i].close();
+                                Util.closeOrRelease(readers[i]);
                             } catch (IOException e) {
                                 log.warn("Unable to close IndexReader: " + e);
                             }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java?rev=696653&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java Thu Sep 18 06:17:59 2008
@@ -0,0 +1,216 @@
+/*
+ * 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.core.query.lucene;
+
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.index.FilterIndexReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.TermPositions;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.store.NoLockFactory;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.FieldSelector;
+import org.apache.lucene.document.Fieldable;
+import org.apache.lucene.document.Field;
+import org.apache.jackrabbit.core.fs.local.FileUtil;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * <code>IndexMigration</code> implements a utility that migrates a Jackrabbit
+ * 1.4.x index to version 1.5. Until version 1.4.x, indexes used the character
+ * '\uFFFF' to separate the name of a property from the value. As of Lucene
+ * 2.3 this does not work anymore. See LUCENE-1221. Jackrabbit >= 1.5 uses
+ * the character '[' as a separator. Whenever an index is opened from disk, a
+ * quick check is run to find out whether a migration is required. See also
+ * JCR-1363 for more details.
+ */
+public class IndexMigration {
+
+    /**
+     * The logger instance for this class.
+     */
+    private static final Logger log = LoggerFactory.getLogger(IndexMigration.class);
+
+    /**
+     * Checks if the given <code>index</code> needs to be migrated.
+     *
+     * @param index the index to check and migration if needed.
+     * @param indexDir the directory where the index is stored.
+     * @throws IOException if an error occurs while migrating the index.
+     */
+    public static void migrate(PersistentIndex index, File indexDir) throws IOException {
+        log.debug("Checking {} ...", indexDir.getAbsolutePath());
+        ReadOnlyIndexReader reader = index.getReadOnlyIndexReader();
+        try {
+            if (IndexFormatVersion.getVersion(reader).getVersion() >=
+                    IndexFormatVersion.V3.getVersion()) {
+                // index was created with Jackrabbit 1.5 or higher
+                // no need for migration
+                log.debug("IndexFormatVersion >= V3, no migration needed");
+                return;
+            }
+            // assert: there is at least one node in the index, otherwise the
+            //         index format version would be at least V3
+            TermEnum terms = reader.terms(new Term(FieldNames.PROPERTIES, ""));
+            try {
+                Term t = terms.term();
+                if (t.text().indexOf('\uFFFF') == -1) {
+                    log.debug("Index already migrated");
+                    return;
+                }
+            } finally {
+                terms.close();
+            }
+        } finally {
+            reader.release();
+        }
+
+        // if we get here then the index must be migrated
+        log.debug("Index requires migration {}", indexDir.getAbsolutePath());
+
+        // make sure readers are closed, otherwise the directory
+        // cannot be deleted
+        index.releaseWriterAndReaders();
+
+        File migrationDir = new File(indexDir.getAbsoluteFile().getParentFile(), indexDir.getName() + "_v2.3");
+        if (migrationDir.exists()) {
+            FileUtil.delete(migrationDir);
+        }
+        if (!migrationDir.mkdirs()) {
+            throw new IOException("failed to create directory " +
+                    migrationDir.getAbsolutePath());
+        }
+        FSDirectory fsDir = FSDirectory.getDirectory(migrationDir,
+                NoLockFactory.getNoLockFactory());
+        try {
+            IndexWriter writer = new IndexWriter(fsDir, new JackrabbitAnalyzer());
+            try {
+                IndexReader r = new MigrationIndexReader(
+                        IndexReader.open(index.getDirectory()));
+                try {
+                    writer.addIndexes(new IndexReader[]{r});
+                    writer.close();
+                } finally {
+                    r.close();
+                }
+            } finally {
+                writer.close();
+            }
+        } finally {
+            fsDir.close();
+        }
+        FileUtil.delete(indexDir);
+        if (!migrationDir.renameTo(indexDir)) {
+            throw new IOException("failed to move migrated directory " +
+                    migrationDir.getAbsolutePath());
+        }
+        log.info("Migrated " + indexDir.getAbsolutePath());
+    }
+
+    //---------------------------< internal helper >----------------------------
+
+    /**
+     * An index reader that migrates stored field values and term text on the
+     * fly.
+     */
+    private static class MigrationIndexReader extends FilterIndexReader {
+
+        public MigrationIndexReader(IndexReader in) {
+            super(in);
+        }
+
+        public Document document(int n, FieldSelector fieldSelector)
+                throws CorruptIndexException, IOException {
+            Document doc = super.document(n, fieldSelector);
+            Fieldable[] fields = doc.getFieldables(FieldNames.PROPERTIES);
+            if (fields != null) {
+                doc.removeFields(FieldNames.PROPERTIES);
+                for (int i = 0; i < fields.length; i++) {
+                    String value = fields[i].stringValue();
+                    value = value.replace('\uFFFF', '[');
+                    doc.add(new Field(FieldNames.PROPERTIES, value,
+                            Field.Store.YES, Field.Index.NO_NORMS));
+                }
+            }
+            return doc;
+        }
+
+        public TermEnum terms() throws IOException {
+            return new MigrationTermEnum(in.terms());
+        }
+
+        public TermPositions termPositions() throws IOException {
+            return new MigrationTermPositions(in.termPositions());
+        }
+
+        private static class MigrationTermEnum extends FilterTermEnum {
+
+            public MigrationTermEnum(TermEnum in) {
+                super(in);
+            }
+
+            public Term term() {
+                Term t = super.term();
+                if (t == null) {
+                    return t;
+                }
+                if (t.field().equals(FieldNames.PROPERTIES)) {
+                    String text = t.text();
+                    return t.createTerm(text.replace('\uFFFF', '['));
+                } else {
+                    return t;
+                }
+            }
+
+            TermEnum unwrap() {
+                return in;
+            }
+        }
+
+        private static class MigrationTermPositions extends FilterTermPositions {
+
+            public MigrationTermPositions(TermPositions in) {
+                super(in);
+            }
+
+            public void seek(Term term) throws IOException {
+                if (term.field().equals(FieldNames.PROPERTIES)) {
+                    char[] text = term.text().toCharArray();
+                    text[term.text().indexOf('[')] = '\uFFFF';
+                    super.seek(term.createTerm(new String(text)));
+                } else {
+                    super.seek(term);
+                }
+            }
+
+            public void seek(TermEnum termEnum) throws IOException {
+                if (termEnum instanceof MigrationTermEnum) {
+                    super.seek(((MigrationTermEnum) termEnum).unwrap());
+                } else {
+                    super.seek(termEnum);
+                }
+            }
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexReader.java?rev=696653&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexReader.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexReader.java Thu Sep 18 06:17:59 2008
@@ -0,0 +1,118 @@
+/*
+ * 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.core.query.lucene;
+
+import org.apache.lucene.index.FilterIndexReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.jackrabbit.uuid.UUID;
+
+import java.io.IOException;
+
+/**
+ * <code>JackrabbitIndexReader</code> wraps an index reader and
+ * {@link ReleaseableIndexReader#release() releases} the underlying reader
+ * when a client calls {@link #close()} on this reader. This allows reusing
+ * of the underlying index reader instance.
+ */
+public final class JackrabbitIndexReader
+        extends FilterIndexReader
+        implements HierarchyResolver, MultiIndexReader {
+
+    /**
+     * The hierarchy resolver.
+     */
+    private final HierarchyResolver resolver;
+
+    /**
+     * The underlying index reader exposed as a {@link MultiIndexReader}.
+     */
+    private final MultiIndexReader reader;
+
+    /**
+     * Creates a new <code>JackrabbitIndexReader</code>. The passed index reader
+     * must also implement the interfaces {@link HierarchyResolver} and
+     * {@link MultiIndexReader}.
+     *
+     * @param in the underlying index reader.
+     * @throws IllegalArgumentException if <code>in</code> does not implement
+     *                                  {@link HierarchyResolver} and
+     *                                  {@link MultiIndexReader}.
+     */
+    public JackrabbitIndexReader(IndexReader in) {
+        super(in);
+        if (!(in instanceof MultiIndexReader)) {
+            throw new IllegalArgumentException("IndexReader must also implement MultiIndexReader");
+        }
+        if (!(in instanceof HierarchyResolver)) {
+            throw new IllegalArgumentException("IndexReader must also implement HierarchyResolver");
+        }
+        this.resolver = (HierarchyResolver) in;
+        this.reader = (MultiIndexReader) in;
+    }
+
+    //--------------------------< FilterIndexReader >---------------------------
+
+    /**
+     * Calls release on the underlying {@link MultiIndexReader} instead of
+     * closing it.
+     *
+     * @throws IOException if an error occurs while releaseing the underlying
+     *                     index reader.
+     */
+    protected void doClose() throws IOException {
+        reader.release();
+    }
+
+    //------------------------< HierarchyResolver >-----------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getParent(int n) throws IOException {
+        return resolver.getParent(n);
+    }
+
+    //-------------------------< MultiIndexReader >-----------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public IndexReader[] getIndexReaders() {
+        return reader.getIndexReaders();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ForeignSegmentDocId createDocId(UUID uuid) throws IOException {
+        return reader.createDocId(uuid);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getDocumentNumber(ForeignSegmentDocId docId) throws IOException {
+        return reader.getDocumentNumber(docId);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void release() throws IOException {
+        reader.release();
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java Thu Sep 18 06:17:59 2008
@@ -298,11 +298,11 @@
         resetVolatileIndex();
 
         // set index format version
-        IndexReader reader = getIndexReader();
+        CachingMultiIndexReader reader = getIndexReader();
         try {
             version = IndexFormatVersion.getVersion(reader);
         } finally {
-            reader.close();
+            reader.release();
         }
 
         indexingQueue.initialize(this);
@@ -349,11 +349,11 @@
         if (indexNames.size() == 0) {
             return volatileIndex.getNumDocuments();
         } else {
-            IndexReader reader = getIndexReader();
+            CachingMultiIndexReader reader = getIndexReader();
             try {
                 return reader.numDocs();
             } finally {
-                reader.close();
+                reader.release();
             }
         }
     }
@@ -441,7 +441,7 @@
             synchronized (updateMonitor) {
                 updateInProgress = false;
                 updateMonitor.notifyAll();
-                closeMultiReader();
+                releaseMultiReader();
             }
         }
     }
@@ -504,7 +504,7 @@
             synchronized (updateMonitor) {
                 updateInProgress = false;
                 updateMonitor.notifyAll();
-                closeMultiReader();
+                releaseMultiReader();
             }
         }
         return num;
@@ -538,14 +538,14 @@
                 }
             }
         } catch (IOException e) {
-            // close readers obtained so far
+            // release readers obtained so far
             for (Iterator it = indexReaders.entrySet().iterator(); it.hasNext();) {
                 Map.Entry entry = (Map.Entry) it.next();
                 ReadOnlyIndexReader reader = (ReadOnlyIndexReader) entry.getKey();
                 try {
-                    reader.close();
+                    reader.release();
                 } catch (IOException ex) {
-                    log.warn("Exception closing index reader: " + ex);
+                    log.warn("Exception releasing index reader: " + ex);
                 }
                 ((PersistentIndex) entry.getValue()).resetListener();
             }
@@ -674,7 +674,7 @@
                 synchronized (updateMonitor) {
                     updateInProgress = false;
                     updateMonitor.notifyAll();
-                    closeMultiReader();
+                    releaseMultiReader();
                 }
             }
         }
@@ -694,7 +694,7 @@
     public CachingMultiIndexReader getIndexReader() throws IOException {
         synchronized (updateMonitor) {
             if (multiReader != null) {
-                multiReader.incrementRefCount();
+                multiReader.acquire();
                 return multiReader;
             }
             // no reader available
@@ -721,7 +721,7 @@
                         (ReadOnlyIndexReader[]) readerList.toArray(new ReadOnlyIndexReader[readerList.size()]);
                 multiReader = new CachingMultiIndexReader(readers, cache);
             }
-            multiReader.incrementRefCount();
+            multiReader.acquire();
             return multiReader;
         }
     }
@@ -751,7 +751,7 @@
 
             // commit / close indexes
             try {
-                closeMultiReader();
+                releaseMultiReader();
             } catch (IOException e) {
                 log.error("Exception while closing search index.", e);
             }
@@ -895,7 +895,7 @@
     }
 
     /**
-     * Closes the {@link #multiReader} and sets it <code>null</code>. If the
+     * Releases the {@link #multiReader} and sets it <code>null</code>. If the
      * reader is already <code>null</code> this method does nothing. When this
      * method returns {@link #multiReader} is guaranteed to be <code>null</code>
      * even if an exception is thrown.
@@ -904,12 +904,12 @@
      * A caller must ensure that it is the only thread operating on this multi
      * index, or that it holds the {@link #updateMonitor}.
      *
-     * @throws IOException if an error occurs while closing the reader.
+     * @throws IOException if an error occurs while releasing the reader.
      */
-    void closeMultiReader() throws IOException {
+    void releaseMultiReader() throws IOException {
         if (multiReader != null) {
             try {
-                multiReader.close();
+                multiReader.release();
             } finally {
                 multiReader = null;
             }
@@ -1143,7 +1143,7 @@
                         synchronized (updateMonitor) {
                             updateInProgress = false;
                             updateMonitor.notifyAll();
-                            closeMultiReader();
+                            releaseMultiReader();
                         }
                     }
                 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndexReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndexReader.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndexReader.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndexReader.java Thu Sep 18 06:17:59 2008
@@ -25,7 +25,7 @@
  * <code>MultiIndexReader</code> exposes methods to get access to the contained
  * {@link IndexReader}s of this <code>MultiIndexReader</code>.
  */
-public interface MultiIndexReader {
+public interface MultiIndexReader extends ReleaseableIndexReader {
 
     /**
      * @return the <code>IndexReader</code>s that are contained in this
@@ -53,5 +53,4 @@
      * @throws IOException if an error occurs while reading from the index.
      */
     int getDocumentNumber(ForeignSegmentDocId docId) throws IOException;
-
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java Thu Sep 18 06:17:59 2008
@@ -483,11 +483,10 @@
             field.setOmitNorms(true);
             return field;
         } else {
-            Field field = new Field(FieldNames.PROPERTIES,
+            return new Field(FieldNames.PROPERTIES,
                     FieldNames.createNamedValue(fieldName, internalValue),
                     Field.Store.NO, Field.Index.NO_NORMS,
                     Field.TermVector.NO);
-            return field;
         }
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java Thu Sep 18 06:17:59 2008
@@ -55,8 +55,6 @@
      * @param indexingQueue the indexing queue.
      * @throws IOException if an error occurs while opening / creating the
      *  index.
-     * @throws IOException if an error occurs while opening / creating
-     *  the index.
      */
     PersistentIndex(String name, File indexDir, Analyzer analyzer,
                     Similarity similarity, DocNumberCache cache,
@@ -65,6 +63,9 @@
         super(analyzer, similarity, FSDirectory.getDirectory(indexDir, new NativeFSLockFactory(indexDir)),
                 cache, indexingQueue);
         this.name = name;
+        if (isExisting()) {
+            IndexMigration.migrate(this, indexDir);
+        }
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReadOnlyIndexReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReadOnlyIndexReader.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReadOnlyIndexReader.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReadOnlyIndexReader.java Thu Sep 18 06:17:59 2008
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.core.query.lucene;
 
-import org.apache.lucene.index.FilterIndexReader;
 import org.apache.lucene.index.TermDocs;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermPositions;
@@ -30,7 +29,7 @@
  * <code>ReadOnlyIndexReader</code> will always show all documents that have
  * not been deleted at the time when the index reader is created.
  */
-class ReadOnlyIndexReader extends FilterIndexReader {
+class ReadOnlyIndexReader extends RefCountingIndexReader {
 
     /**
      * The underlying shared reader.
@@ -50,11 +49,6 @@
     private long deletedDocsVersion;
 
     /**
-     * A reference counter. When constructed the refCount is one.
-     */
-    private int refCount = 1;
-
-    /**
      * Creates a new index reader based on <code>reader</code> at
      * <code>modificationTick</code>.
      *
@@ -71,23 +65,8 @@
         this.reader = reader;
         this.deleted = deleted;
         this.deletedDocsVersion = deletedDocsVersion;
-        // register this
-        reader.addClient(this);
-    }
-
-    /**
-     * Increments the reference count on this index reader. The reference count
-     * is decremented on {@link #close()}.
-     */
-    synchronized void incrementRefCount() {
-        refCount++;
-    }
-
-    /**
-     * @return the current reference count value.
-     */
-    synchronized int getRefCount() {
-        return refCount;
+        // acquire underlying reader
+        reader.acquire();
     }
 
     /**
@@ -201,22 +180,6 @@
     }
 
     /**
-     * Unregisters this reader from the shared index reader if the reference
-     * count for this reader drops to zero. Specifically, this method does
-     * <b>not</b> close the underlying index reader, because it is shared by
-     * multiple <code>ReadOnlyIndexReader</code>s.
-     *
-     * @throws IOException if an error occurs while closing the reader.
-     */
-    protected void doClose() throws IOException {
-        synchronized (this) {
-            if (--refCount == 0) {
-                reader.removeClient(this);
-            }
-        }
-    }
-
-    /**
      * Wraps the underlying <code>TermDocs</code> and filters out documents
      * marked as deleted.<br/>
      * If <code>term</code> is for a {@link FieldNames#UUID} field and this

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Recovery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Recovery.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Recovery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Recovery.java Thu Sep 18 06:17:59 2008
@@ -170,6 +170,6 @@
 
         // now we are consistent again -> flush
         index.flush();
-        index.closeMultiReader();
+        index.releaseMultiReader();
     }
 }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RefCountingIndexReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RefCountingIndexReader.java?rev=696653&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RefCountingIndexReader.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RefCountingIndexReader.java Thu Sep 18 06:17:59 2008
@@ -0,0 +1,71 @@
+/*
+ * 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.core.query.lucene;
+
+import org.apache.lucene.index.FilterIndexReader;
+import org.apache.lucene.index.IndexReader;
+
+import java.io.IOException;
+
+/**
+ * <code>RefCountingIndexReader</code>...
+ */
+public class RefCountingIndexReader
+        extends FilterIndexReader
+        implements ReleaseableIndexReader {
+
+    /**
+     * A reference counter. When constructed the refCount is one.
+     */
+    private int refCount = 1;
+
+    public RefCountingIndexReader(IndexReader in) {
+        super(in);
+    }
+
+    /**
+     * Increments the reference count on this index reader. The reference count
+     * is decremented on {@link #release()}.
+     */
+    synchronized final void acquire() {
+        refCount++;
+    }
+
+    /**
+     * @return the current reference count value.
+     */
+    synchronized int getRefCount() {
+        return refCount;
+    }
+
+    //-----------------------< ReleaseableIndexReader >--------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized final void release() throws IOException {
+        if (--refCount == 0) {
+            close();
+        }
+    }
+
+    //-----------------------< FilterIndexReader >--------------------------
+
+    protected void doClose() throws IOException {
+        Util.closeOrRelease(in);
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RefCountingIndexReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReleaseableIndexReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReleaseableIndexReader.java?rev=696653&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReleaseableIndexReader.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReleaseableIndexReader.java Thu Sep 18 06:17:59 2008
@@ -0,0 +1,35 @@
+/*
+ * 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.core.query.lucene;
+
+import java.io.IOException;
+
+/**
+ * <code>ReleaseableIndexReader</code>...
+ */
+public interface ReleaseableIndexReader {
+
+    /**
+     * Releases this index reader and potentially frees resources. In contrast
+     * to {@link org.apache.lucene.index.IndexReader#close()} this method
+     * does not necessarily close the index reader, but gives the implementation
+     * the opportunity to do reference counting.
+     *
+     * @throws IOException if an error occurs while releasing the index reader.
+     */
+    public void release() throws IOException;
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ReleaseableIndexReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java Thu Sep 18 06:17:59 2008
@@ -706,7 +706,7 @@
                     super.close();
                 } finally {
                     PerQueryCache.getInstance().dispose();
-                    reader.close();
+                    Util.closeOrRelease(reader);
                 }
             }
         };
@@ -852,13 +852,14 @@
             parentReader = ((SearchIndex) parentHandler).index.getIndexReader();
         }
 
-        CachingMultiIndexReader reader = index.getIndexReader();
+        IndexReader reader;
         if (parentReader != null) {
-            CachingMultiIndexReader[] readers = {reader, parentReader};
-            return new CombinedIndexReader(readers);
+            CachingMultiIndexReader[] readers = {index.getIndexReader(), parentReader};
+            reader = new CombinedIndexReader(readers);
         } else {
-            return reader;
+            reader = index.getIndexReader();
         }
+        return new JackrabbitIndexReader(reader);
     }
 
     /**
@@ -1181,7 +1182,7 @@
             int found = 0;
             long time = System.currentTimeMillis();
             try {
-                IndexReader reader = index.getIndexReader();
+                CachingMultiIndexReader reader = index.getIndexReader();
                 try {
                     Term aggregateUUIDs = new Term(
                             FieldNames.AGGREGATED_NODE_UUID, "");
@@ -1206,7 +1207,7 @@
                         tDocs.close();
                     }
                 } finally {
-                    reader.close();
+                    reader.release();
                 }
             } catch (Exception e) {
                 log.warn("Exception while retrieving aggregate roots", e);
@@ -1237,7 +1238,7 @@
          */
         private int[] starts;
 
-        public CombinedIndexReader(CachingMultiIndexReader[] indexReaders) throws IOException {
+        public CombinedIndexReader(CachingMultiIndexReader[] indexReaders) {
             super(indexReaders);
             this.subReaders = indexReaders;
             this.starts = new int[subReaders.length + 1];
@@ -1271,6 +1272,15 @@
             return readers;
         }
 
+        /**
+         * {@inheritDoc}
+         */
+        public void release() throws IOException {
+            for (int i = 0; i < subReaders.length; i++) {
+                subReaders[i].release();
+            }
+        }
+
         //---------------------------< internal >-------------------------------
 
         /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedIndexReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedIndexReader.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedIndexReader.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedIndexReader.java Thu Sep 18 06:17:59 2008
@@ -30,20 +30,7 @@
  * clients are disconnected AND the <code>SharedIndexReader</code>s
  * <code>close()</code> method itself has been called.
  */
-class SharedIndexReader extends FilterIndexReader {
-
-    /**
-     * Set to <code>true</code> if this index reader should be closed, when
-     * all connected clients are disconnected.
-     */
-    private boolean closeRequested = false;
-
-    /**
-     * Map of all registered clients to this shared index reader. The Map
-     * is rather used as a Set, because each value is the same Object as its
-     * associated key.
-     */
-    private final Map clients = new IdentityHashMap();
+class SharedIndexReader extends RefCountingIndexReader {
 
     /**
      * Creates a new <code>SharedIndexReader</code> which is based on
@@ -79,46 +66,6 @@
     }
 
     /**
-     * Registeres <code>client</code> with this reader. As long as clients are
-     * registered, this shared reader will not release resources on {@link
-     * #close()} and will not actually close but only marks itself to close when
-     * the last client is unregistered.
-     *
-     * @param client the client to register.
-     */
-    public synchronized void addClient(Object client) {
-        clients.put(client, client);
-    }
-
-    /**
-     * Unregisters the <code>client</code> from this index reader.
-     *
-     * @param client a client of this reader.
-     * @throws IOException if an error occurs while detaching the client from
-     *                     this shared reader.
-     */
-    public synchronized void removeClient(Object client) throws IOException {
-        clients.remove(client);
-        if (clients.isEmpty() && closeRequested) {
-            super.doClose();
-        }
-    }
-
-    /**
-     * Closes this index if no client is registered, otherwise this reader is
-     * marked to close when the last client is disconnected.
-     *
-     * @throws IOException if an error occurs while closing.
-     */
-    protected synchronized void doClose() throws IOException {
-        if (clients.isEmpty()) {
-            super.doClose();
-        } else {
-            closeRequested = true;
-        }
-    }
-
-    /**
      * Simply passes the call to the wrapped reader as is.<br/>
      * If <code>term</code> is for a {@link FieldNames#UUID} field and this
      * <code>SharedIndexReader</code> does not have such a document,
@@ -140,5 +87,4 @@
     public CachingIndexReader getBase() {
         return (CachingIndexReader) in;
     }
-
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java Thu Sep 18 06:17:59 2008
@@ -21,6 +21,7 @@
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.index.IndexReader;
 import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
 
@@ -108,4 +109,21 @@
         ex.initCause(t);
         return ex;
     }
+
+    /**
+     * Depending on the type of the <code>reader</code> this method either
+     * closes or releases the reader. The reader is released if it implements
+     * {@link ReleaseableIndexReader}.
+     *
+     * @param reader the index reader to close or release.
+     * @throws IOException if an error occurs while closing or releasing the
+     *                     index reader.
+     */
+    public static void closeOrRelease(IndexReader reader) throws IOException {
+        if (reader instanceof ReleaseableIndexReader) {
+            ((ReleaseableIndexReader) reader).release();
+        } else {
+            reader.close();
+        }
+    }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/VolatileIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/VolatileIndex.java?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/VolatileIndex.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/VolatileIndex.java Thu Sep 18 06:17:59 2008
@@ -156,6 +156,9 @@
      * Commits pending documents to the index.
      */
     private void commitPending() throws IOException {
+        if (pending.isEmpty()) {
+            return;
+        }
         super.addDocuments((Document[]) pending.values().toArray(
                 new Document[pending.size()]));
         pending.clear();

Modified: jackrabbit/trunk/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/pom.xml?rev=696653&r1=696652&r2=696653&view=diff
==============================================================================
--- jackrabbit/trunk/pom.xml (original)
+++ jackrabbit/trunk/pom.xml Thu Sep 18 06:17:59 2008
@@ -811,7 +811,7 @@
       <dependency>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-core</artifactId>
-        <version>2.2.0</version>
+        <version>2.3.2</version>
       </dependency>
       <dependency>
         <groupId>org.apache.derby</groupId>