pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / facet / src / test / org / apache / lucene / facet / taxonomy / directory / TestIndexClose.java
diff --git a/lucene-java-3.5.0/lucene/contrib/facet/src/test/org/apache/lucene/facet/taxonomy/directory/TestIndexClose.java b/lucene-java-3.5.0/lucene/contrib/facet/src/test/org/apache/lucene/facet/taxonomy/directory/TestIndexClose.java
new file mode 100644 (file)
index 0000000..fff850f
--- /dev/null
@@ -0,0 +1,205 @@
+package org.apache.lucene.facet.taxonomy.directory;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.FilterIndexReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.IndexWriterConfig.OpenMode;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.LockObtainFailedException;
+import org.junit.Test;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.analysis.MockAnalyzer;
+import org.apache.lucene.analysis.MockTokenizer;
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
+import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
+
+/**
+ * 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.
+ */
+
+/**
+ * This test case attempts to catch index "leaks" in LuceneTaxonomyReader/Writer,
+ * i.e., cases where an index has been opened, but never closed; In that case,
+ * Java would eventually collect this object and close the index, but leaving
+ * the index open might nevertheless cause problems - e.g., on Windows it prevents
+ * deleting it.
+ */
+public class TestIndexClose extends LuceneTestCase {
+
+  @Test
+  public void testLeaks() throws Exception {
+    LeakChecker checker = new LeakChecker();
+    Directory dir = newDirectory();
+    DirectoryTaxonomyWriter tw = checker.openWriter(dir);
+    tw.close();
+    assertEquals(0, checker.nopen());
+
+    tw = checker.openWriter(dir);
+    tw.addCategory(new CategoryPath("animal", "dog"));
+    tw.close();
+    assertEquals(0, checker.nopen());
+
+    DirectoryTaxonomyReader tr = checker.openReader(dir);
+    tr.getPath(1);
+    tr.refresh();
+    tr.close();
+    assertEquals(0, checker.nopen());
+
+    tr = checker.openReader(dir);
+    tw = checker.openWriter(dir);
+    tw.addCategory(new CategoryPath("animal", "cat"));
+    tr.refresh();
+    tw.commit();
+    tw.close();
+    tr.refresh();
+    tr.close();
+    assertEquals(0, checker.nopen());
+
+    tw = checker.openWriter(dir);
+    for (int i=0; i<10000; i++) {
+      tw.addCategory(new CategoryPath("number", Integer.toString(i)));
+    }
+    tw.close();
+    assertEquals(0, checker.nopen());
+    tw = checker.openWriter(dir);
+    for (int i=0; i<10000; i++) {
+      tw.addCategory(new CategoryPath("number", Integer.toString(i*2)));
+    }
+    tw.close();
+    assertEquals(0, checker.nopen());
+    dir.close();
+  }
+
+  private static class LeakChecker {
+    int ireader=0;
+    Set<Integer> openReaders = new HashSet<Integer>();
+
+    int iwriter=0;
+    Set<Integer> openWriters = new HashSet<Integer>();
+
+    LeakChecker() { }
+    
+    public DirectoryTaxonomyWriter openWriter(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
+      return new InstrumentedTaxonomyWriter(dir);
+    }
+
+    public DirectoryTaxonomyReader openReader(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
+      return new InstrumentedTaxonomyReader(dir);
+    }
+
+    public int nopen() {
+      int ret=0;
+      for (int i: openReaders) {
+        System.err.println("reader "+i+" still open");
+        ret++;
+      }
+      for (int i: openWriters) {
+        System.err.println("writer "+i+" still open");
+        ret++;
+      }
+      return ret;
+    }
+
+    private class InstrumentedTaxonomyWriter extends DirectoryTaxonomyWriter {
+      public InstrumentedTaxonomyWriter(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
+        super(dir);
+      }    
+      @Override
+      protected IndexReader openReader() throws IOException {
+        return new InstrumentedIndexReader(super.openReader()); 
+      }
+      @Override
+      protected IndexWriter openIndexWriter (Directory directory, OpenMode openMode) throws IOException {
+        return new InstrumentedIndexWriter(directory,
+            newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random, MockTokenizer.KEYWORD, false))
+                .setOpenMode(openMode));
+      }
+
+    }
+
+    private class InstrumentedTaxonomyReader extends DirectoryTaxonomyReader {
+      public InstrumentedTaxonomyReader(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
+        super(dir);
+      }  
+      @Override
+      protected IndexReader openIndexReader(Directory dir) throws CorruptIndexException, IOException {
+        return new InstrumentedIndexReader(IndexReader.open(dir,true)); 
+      }
+
+    }
+
+    private class InstrumentedIndexReader extends FilterIndexReader {
+      int mynum;
+      public InstrumentedIndexReader(IndexReader in) {
+        super(in);
+        mynum = ireader++;
+        openReaders.add(mynum);
+        //        System.err.println("opened "+mynum);
+      }
+      
+      @Override
+      protected IndexReader doOpenIfChanged() throws CorruptIndexException,
+          IOException {
+        IndexReader n = IndexReader.openIfChanged(in);
+        if (n == null) {
+          return null;
+        }
+        return new InstrumentedIndexReader(n);
+      }
+      
+      // Unfortunately, IndexReader.close() is marked final so we can't
+      // change it! Fortunately, close() calls (if the object wasn't
+      // already closed) doClose() so we can override it to do our thing -
+      // just like FilterIndexReader does.
+      @Override
+      public void doClose() throws IOException {
+        in.close();
+        if (!openReaders.contains(mynum)) { // probably can't happen...
+          fail("Reader #"+mynum+" was closed twice!");
+        }
+        openReaders.remove(mynum);
+        //        System.err.println("closed "+mynum);
+      }
+    }
+    private class InstrumentedIndexWriter extends IndexWriter {
+      int mynum;
+      public InstrumentedIndexWriter(Directory d, IndexWriterConfig conf) throws CorruptIndexException, LockObtainFailedException, IOException {
+        super(d, conf);
+        mynum = iwriter++;
+        openWriters.add(mynum);
+        //        System.err.println("openedw "+mynum);
+      }
+
+      @Override
+      public void close() throws IOException {
+        super.close();
+        if (!openWriters.contains(mynum)) { // probably can't happen...
+          fail("Writer #"+mynum+" was closed twice!");
+        }
+        openWriters.remove(mynum);
+        //        System.err.println("closedw "+mynum);
+      }
+    }
+  }
+}