svn commit: r569949 - /xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/LuceneIndexer.java

[email protected]
Newsgroups gmane.text.xml.xindice.devel
Message-ID <[email protected]>
Author: natalia
Date: Sun Aug 26 18:27:50 2007
New Revision: 569949

URL: http://svn.apache.org/viewvc?rev=569949&view=rev
Log:
Make search not synchronized

Modified:
    xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/LuceneIndexer.java

Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/LuceneIndexer.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/LuceneIndexer.java?rev=569949&r1=569948&r2=569949&view=diff
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/LuceneIndexer.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/LuceneIndexer.java Sun Aug 26 18:27:50 2007
@@ -99,10 +99,18 @@
 
     private File          idxFile;
     private IndexWriter   iw;
-    private IndexReader   ir;
-    private IndexSearcher is;
     private Analyzer      an;
 
+    /**
+     * Most recently opened searcher. The same Searcher instance is going to
+     * be used for all the searches unless index has changed and new Searcher
+     * is required to access the changes.
+     *
+     * Searcher cannot be closed if it is being used (if there is a query in
+     * progress or hits are iterated).
+     */
+    private Searcher searcher;
+
     private Configuration config;
     private Collection    collection;
 
@@ -113,6 +121,8 @@
     private int docsAdded;
     private int docsDeleted;
 
+    private final Object lock = new Object();
+
     private String defaultField = "";
 
     private void setFile(File f) {
@@ -214,7 +224,7 @@
         return config;
     }
 
-    public synchronized boolean exists() {
+    public boolean exists() {
         return IndexReader.indexExists(idxFile);
     }
 
@@ -246,22 +256,24 @@
         return false;
     }
 
-    public synchronized boolean open() throws DBException {
+    public boolean open() throws DBException {
         openWrite(false);
         return true;
     }
 
-    public synchronized boolean isOpened() {
-        return (null != iw) || (null != ir);
+    public boolean isOpened() {
+        return null != iw;
     }
 
     public synchronized boolean close() throws DBException {
         closeWrite();
-        closeRead();
+        if (searcher != null) {
+            searcher.close(true);
+        }
         return true;
     }
 
-    public synchronized boolean drop() throws DBException {
+    public boolean drop() throws DBException {
         try {
             if (IndexReader.indexExists(idxFile)) {
                 close();
@@ -271,7 +283,7 @@
             }
         } catch (IOException e) {
             throw new DBException(FaultCodes.IDX_CORRUPTED,
-                    "Failed to delete index " + name + ", collection " + collection.getCanonicalName(), e);
+                                  "Failed to delete index " + name + ", collection " + collection.getCanonicalName(), e);
         }
     }
 
@@ -287,50 +299,22 @@
         return an;
     }
 
-    private void openRead() throws DBException {
-        if (log.isTraceEnabled()) {
-            log.trace("Calling openRead()");
-        }
-
-        if (null == ir) {
-            closeWrite();
-            try {
-                ir = IndexReader.open(getFile());
-            } catch (IOException e) {
-                throw new DBException(FaultCodes.IDX_CORRUPTED,
-                        "Failed to open index " + name + ", collection " + collection.getCanonicalName(), e);
-            }
-        }
-    }
-
-    private void openSearch() throws DBException {
-        if (log.isTraceEnabled()) {
-            log.trace("Calling openSearch()");
-        }
-
-        if (null == is) {
-            openRead();
-            is = new IndexSearcher(ir);
-        }
-    }
-
     private void openWrite(boolean create) throws DBException {
         if (log.isTraceEnabled()) {
             log.trace("Calling openWrite(" + create + ")");
         }
 
-        if (null == iw) {
-            closeRead();
-            try {
+        try {
+            if (iw == null) {
                 iw = new IndexWriter(getFile(), getAnalyzer(), create);
-            } catch (IOException e) {
-                if (create) {
-                    throw new DBException(FaultCodes.IDX_CANNOT_CREATE,
-                            "Failed to cleate index " + name + ", collection " + collection.getCanonicalName(), e);
-                } else {
-                    throw new DBException(FaultCodes.IDX_CORRUPTED,
-                            "Failed to open index " + name + ", collection " + collection.getCanonicalName(), e);
-                }
+            }
+        } catch (IOException e) {
+            if (create) {
+                throw new DBException(FaultCodes.IDX_CANNOT_CREATE,
+                                      "Failed to cleate index " + name + ", collection " + collection.getCanonicalName(), e);
+            } else {
+                throw new DBException(FaultCodes.IDX_CORRUPTED,
+                                      "Failed to open index " + name + ", collection " + collection.getCanonicalName(), e);
             }
         }
     }
@@ -341,63 +325,14 @@
         }
     }
 
-    private void assertRead() throws DBException {
-        assertOpen();
-        openRead();
-    }
-
-    private void assertWrite() throws DBException {
-        assertOpen();
-        openWrite(false);
-    }
-
-    private void closeRead() throws DBException {
-        if (null != ir) {
-            closeSearch();
-            try {
-                ir.close();
-                ir = null;
-            } catch (IOException e) {
-                throw new DBException(FaultCodes.IDX_CORRUPTED,
-                        "Failed to close reader for index " + name + ", collection " + collection.getCanonicalName(), e);
-            }
-        }
-    }
-
-    private void closeSearch() throws DBException {
-        if (null != is) {
-            try {
-                is.close();
-                is = null;
-            } catch (IOException e) {
-                throw new DBException(FaultCodes.IDX_CORRUPTED,
-                        "Failed to close searcher for index " + name + ", collection " + collection.getCanonicalName(), e);
-            }
-        }
-    }
-
     private void closeWrite() throws DBException {
         if (null != iw) {
             try {
-                int nDocs = iw.docCount();
-                /* Fairly arbitrary rules for triggering index optimisation. Need to
-                 * play with these.
-                 */
-                if (docsAdded > nDocs / 10 || docsAdded > 50 || docsDeleted > 10) {
-                    if (log.isDebugEnabled()) {
-                        log.debug("Optimizing text index for " + collection.getCanonicalName() + "...");
-                    }
-
-                    iw.optimize();
-                    docsAdded = 0;
-                    docsDeleted = 0;
-                }
-
                 iw.close();
                 iw = null;
             } catch (IOException e) {
                 throw new DBException(FaultCodes.IDX_CORRUPTED,
-                        "Failed to close writer for index " + name + ", collection " + collection.getCanonicalName(), e);
+                                      "Failed to close writer for index " + name + ", collection " + collection.getCanonicalName(), e);
             }
         }
     }
@@ -414,15 +349,32 @@
         return f.delete();
     }
 
-    public synchronized void flush() throws DBException {
+    public void flush() throws DBException {
         try {
             assertOpen();
             if (iw != null) {
                 iw.flush();
+
+                int nDocs = iw.docCount();
+                /* Fairly arbitrary rules for triggering index optimisation. Need to
+                 * play with these.
+                 */
+                synchronized(lock) {
+                    if (docsAdded > nDocs / 10 || docsAdded > 50 || docsDeleted > 10) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("Optimizing text index for " + collection.getCanonicalName() + "...");
+                        }
+
+                        iw.optimize();
+                        docsAdded = 0;
+                        docsDeleted = 0;
+                    }
+                }
+
             }
         } catch (IOException e) {
             throw new DBException(FaultCodes.IDX_CORRUPTED,
-                    "Could not force unwritten data to disk for index " + name + ", collection " + collection.getCanonicalName(), e);
+                                  "Could not force unwritten data to disk for index " + name + ", collection " + collection.getCanonicalName(), e);
         }
     }
 
@@ -437,29 +389,33 @@
         return new BasicIndexerEventHandler() {
             Document doc;
 
-            public synchronized void onDocumentAdded(Key key) throws DBException {
+            public void onDocumentAdded(Key key) throws DBException {
                 if (doc != null) {
-                    assertWrite();
+                    assertOpen();
 
                     try {
                         iw.addDocument(doc);
-                        docsAdded++;
+                        synchronized(lock) {
+                            docsAdded++;
+                        }
                     } catch (IOException e) {
                         throw new DBException(FaultCodes.IDX_CORRUPTED,
-                            "Failed to add document to the index " + name + ", collection " + collection.getCanonicalName(), e);
+                                              "Failed to add document to the index " + name + ", collection " + collection.getCanonicalName(), e);
                     }
                 }
             }
 
-            public synchronized void onDocumentDeleted(Key key) throws DBException {
-                assertRead();
+            public void onDocumentDeleted(Key key) throws DBException {
+                assertOpen();
 
                 try {
-                    ir.deleteDocuments(new Term(KEYNAME, key.toString()));
-                    docsDeleted++;
+                    iw.deleteDocuments(new Term(KEYNAME, key.toString()));
+                    synchronized(lock) {
+                        docsDeleted++;
+                    }
                 } catch (IOException e) {
                     throw new DBException(FaultCodes.IDX_CORRUPTED,
-                            "Failed to delete document from the index " + name + ", collection " + collection.getCanonicalName(), e);
+                                          "Failed to delete document from the index " + name + ", collection " + collection.getCanonicalName(), e);
                 }
             }
 
@@ -497,11 +453,12 @@
      * @return The resulting matches
      * @throws DBException if IOException prevented indexer from executing the query.
      */
-    public synchronized IndexMatch[] queryMatches(Query query) throws DBException {
+    public IndexMatch[] queryMatches(Query query) throws DBException {
         ArrayList matches = new ArrayList();
-        openSearch();
+        Searcher searcher = getSearcher();
+
         try {
-            Hits hits = is.search(query);
+            Hits hits = searcher.search(query);
             for (Iterator i = hits.iterator(); i.hasNext(); ) {
                 Hit hit = (Hit) i.next();
                 Key key = new Key(hit.getDocument().getField(KEYNAME).stringValue());
@@ -509,8 +466,113 @@
             }
         } catch (IOException e) {
             throw new ProcessingException("Failed to process a query", e);
+        } finally {
+            searcher.free();
         }
 
         return (IndexMatch[]) matches.toArray(EMPTY_MATCHES);
     }
-}
+
+    /**
+     * getSearcher returns Searcher that uses current version of the index.
+     * If index has been modified since last time searcher was requested
+     * this method will create new Searcher instance, otherwise it will
+     * return Searcher instance it created previously.
+     *
+     * @return current Searcher
+     * @throws DBException
+     */
+    private synchronized Searcher getSearcher() throws DBException {
+
+        if (searcher != null && !searcher.isCurrent()) {
+            searcher.close(false);
+            searcher = null;
+        }
+
+        if (searcher == null) {
+            searcher = new Searcher();
+        } else {
+            searcher.incRef();
+        }
+
+        return searcher;
+    }
+
+    private class Searcher {
+        private IndexReader ir;
+        private IndexSearcher is;
+
+        // number of searches in progress using that searcher
+        private int ref = 1;
+
+        public Searcher() throws DBException {
+            try {
+                ir = IndexReader.open(getFile());
+                is = new IndexSearcher(ir);
+            } catch (IOException e) {
+                throw new DBException(FaultCodes.IDX_CORRUPTED,
+                                      "Failed to open access " + name + ", collection " + collection.getCanonicalName(), e);
+            }
+        }
+
+        public boolean isCurrent() throws DBException {
+            try {
+                return ir.isCurrent();
+            } catch (IOException e) {
+                throw new DBException(FaultCodes.IDX_CORRUPTED,
+                                      "Failed to access index " + name + ", collection " + collection.getCanonicalName(), e);
+            }
+        }
+
+        public void incRef() {
+            ref++;
+        }
+
+        /**
+         * This method must be called after executing text query to cleanup
+         * resources that are not in use anymore. It decrements number of
+         * searches referencing this searcher and then attempts to close it
+         * unless it is the most recently opened searcher. If there were no
+         * searchers opened after this one, the searcher will be kept open
+         * for future use, even if it is not used at the moment.
+         *
+         * @throws DBException if there was IOException
+         */
+        public void free() throws DBException {
+            synchronized (LuceneIndexer.this) {
+                ref--;
+
+                if (searcher != this) {
+                    close(false);
+                }
+            }
+        }
+
+        /**
+         * Closes the searcher if it is not used in any search.
+         *
+         * @param force true if searcher has to be closed even if it is used
+         * @throws DBException if there was IOException
+         */
+        public void close(boolean force) throws DBException {
+            try {
+                if (ref == 0 || force) {
+                    is.close();
+                    ir.close();
+                }
+            } catch (IOException e) {
+                throw new DBException(FaultCodes.IDX_CORRUPTED,
+                                      "Failed to access index " + name + ", collection " + collection.getCanonicalName(), e);
+            }
+        }
+
+        public Hits search(Query query) throws DBException {
+            try {
+                return is.search(query);
+            } catch (IOException e) {
+                throw new DBException(FaultCodes.IDX_CORRUPTED,
+                                      "Failed to access index " + name + ", collection " + collection.getCanonicalName(), e);
+            }
+        }
+    }
+}
\ No newline at end of file
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.