add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / contrib / facet / src / test / org / apache / lucene / facet / taxonomy / lucene / TestIndexClose.java
1 package org.apache.lucene.facet.taxonomy.lucene;
2
3 import java.io.IOException;
4 import java.util.HashSet;
5 import java.util.Set;
6
7 import org.apache.lucene.index.CorruptIndexException;
8 import org.apache.lucene.index.FilterIndexReader;
9 import org.apache.lucene.index.IndexReader;
10 import org.apache.lucene.index.IndexWriter;
11 import org.apache.lucene.index.IndexWriterConfig;
12 import org.apache.lucene.index.IndexWriterConfig.OpenMode;
13 import org.apache.lucene.store.Directory;
14 import org.apache.lucene.store.LockObtainFailedException;
15 import org.junit.Test;
16
17 import org.apache.lucene.util.LuceneTestCase;
18 import org.apache.lucene.analysis.MockAnalyzer;
19 import org.apache.lucene.analysis.MockTokenizer;
20 import org.apache.lucene.facet.taxonomy.CategoryPath;
21 import org.apache.lucene.facet.taxonomy.lucene.LuceneTaxonomyReader;
22 import org.apache.lucene.facet.taxonomy.lucene.LuceneTaxonomyWriter;
23
24 /**
25  * Licensed to the Apache Software Foundation (ASF) under one or more
26  * contributor license agreements.  See the NOTICE file distributed with
27  * this work for additional information regarding copyright ownership.
28  * The ASF licenses this file to You under the Apache License, Version 2.0
29  * (the "License"); you may not use this file except in compliance with
30  * the License.  You may obtain a copy of the License at
31  *
32  *     http://www.apache.org/licenses/LICENSE-2.0
33  *
34  * Unless required by applicable law or agreed to in writing, software
35  * distributed under the License is distributed on an "AS IS" BASIS,
36  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
37  * See the License for the specific language governing permissions and
38  * limitations under the License.
39  */
40
41 /**
42  * This test case attempts to catch index "leaks" in LuceneTaxonomyReader/Writer,
43  * i.e., cases where an index has been opened, but never closed; In that case,
44  * Java would eventually collect this object and close the index, but leaving
45  * the index open might nevertheless cause problems - e.g., on Windows it prevents
46  * deleting it.
47  */
48 public class TestIndexClose extends LuceneTestCase {
49
50   @Test
51   public void testLeaks() throws Exception {
52     LeakChecker checker = new LeakChecker();
53     Directory dir = newDirectory();
54     LuceneTaxonomyWriter tw = checker.openWriter(dir);
55     tw.close();
56     assertEquals(0, checker.nopen());
57
58     tw = checker.openWriter(dir);
59     tw.addCategory(new CategoryPath("animal", "dog"));
60     tw.close();
61     assertEquals(0, checker.nopen());
62
63     LuceneTaxonomyReader tr = checker.openReader(dir);
64     tr.getPath(1);
65     tr.refresh();
66     tr.close();
67     assertEquals(0, checker.nopen());
68
69     tr = checker.openReader(dir);
70     tw = checker.openWriter(dir);
71     tw.addCategory(new CategoryPath("animal", "cat"));
72     tr.refresh();
73     tw.commit();
74     tw.close();
75     tr.refresh();
76     tr.close();
77     assertEquals(0, checker.nopen());
78
79     tw = checker.openWriter(dir);
80     for (int i=0; i<10000; i++) {
81       tw.addCategory(new CategoryPath("number", Integer.toString(i)));
82     }
83     tw.close();
84     assertEquals(0, checker.nopen());
85     tw = checker.openWriter(dir);
86     for (int i=0; i<10000; i++) {
87       tw.addCategory(new CategoryPath("number", Integer.toString(i*2)));
88     }
89     tw.close();
90     assertEquals(0, checker.nopen());
91     dir.close();
92   }
93
94   private static class LeakChecker {
95     int ireader=0;
96     Set<Integer> openReaders = new HashSet<Integer>();
97
98     int iwriter=0;
99     Set<Integer> openWriters = new HashSet<Integer>();
100
101     LeakChecker() { }
102     
103     public LuceneTaxonomyWriter openWriter(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
104       return new InstrumentedTaxonomyWriter(dir);
105     }
106
107     public LuceneTaxonomyReader openReader(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
108       return new InstrumentedTaxonomyReader(dir);
109     }
110
111     public int nopen() {
112       int ret=0;
113       for (int i: openReaders) {
114         System.err.println("reader "+i+" still open");
115         ret++;
116       }
117       for (int i: openWriters) {
118         System.err.println("writer "+i+" still open");
119         ret++;
120       }
121       return ret;
122     }
123
124     private class InstrumentedTaxonomyWriter extends LuceneTaxonomyWriter {
125       public InstrumentedTaxonomyWriter(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
126         super(dir);
127       }    
128       @Override
129       protected IndexReader openReader() throws IOException {
130         return new InstrumentedIndexReader(super.openReader()); 
131       }
132       @Override
133       protected void openLuceneIndex (Directory directory, OpenMode openMode)
134       throws CorruptIndexException, LockObtainFailedException, IOException {
135         indexWriter = new InstrumentedIndexWriter(directory,
136             newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random, MockTokenizer.KEYWORD, false))
137                 .setOpenMode(openMode));
138       }
139
140     }
141
142     private class InstrumentedTaxonomyReader extends LuceneTaxonomyReader {
143       public InstrumentedTaxonomyReader(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
144         super(dir);
145       }  
146       @Override
147       protected IndexReader openIndexReader(Directory dir) throws CorruptIndexException, IOException {
148         return new InstrumentedIndexReader(IndexReader.open(dir,true)); 
149       }
150
151     }
152
153     private class InstrumentedIndexReader extends FilterIndexReader {
154       int mynum;
155       public InstrumentedIndexReader(IndexReader in) {
156         super(in);
157         this.in = in;
158         mynum = ireader++;
159         openReaders.add(mynum);
160         //        System.err.println("opened "+mynum);
161       }
162       @Override
163       public synchronized IndexReader reopen() throws CorruptIndexException, IOException {
164         IndexReader n = in.reopen();
165         if (n==in) {
166           return this;
167         }
168         return new InstrumentedIndexReader(n);
169       }
170
171       // Unfortunately, IndexReader.close() is marked final so we can't
172       // change it! Fortunately, close() calls (if the object wasn't
173       // already closed) doClose() so we can override it to do our thing -
174       // just like FilterIndexReader does.
175       @Override
176       public void doClose() throws IOException {
177         in.close();
178         if (!openReaders.contains(mynum)) { // probably can't happen...
179           fail("Reader #"+mynum+" was closed twice!");
180         }
181         openReaders.remove(mynum);
182         //        System.err.println("closed "+mynum);
183       }
184     }
185     private class InstrumentedIndexWriter extends IndexWriter {
186       int mynum;
187       public InstrumentedIndexWriter(Directory d, IndexWriterConfig conf) throws CorruptIndexException, LockObtainFailedException, IOException {
188         super(d, conf);
189         mynum = iwriter++;
190         openWriters.add(mynum);
191         //        System.err.println("openedw "+mynum);
192       }
193
194       @Override
195       public void close() throws IOException {
196         super.close();
197         if (!openWriters.contains(mynum)) { // probably can't happen...
198           fail("Writer #"+mynum+" was closed twice!");
199         }
200         openWriters.remove(mynum);
201         //        System.err.println("closedw "+mynum);
202       }
203     }
204   }
205 }