1 package org.apache.lucene.facet.taxonomy.lucene;
3 import java.io.IOException;
4 import java.util.HashSet;
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;
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;
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
32 * http://www.apache.org/licenses/LICENSE-2.0
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.
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
48 public class TestIndexClose extends LuceneTestCase {
51 public void testLeaks() throws Exception {
52 LeakChecker checker = new LeakChecker();
53 Directory dir = newDirectory();
54 LuceneTaxonomyWriter tw = checker.openWriter(dir);
56 assertEquals(0, checker.nopen());
58 tw = checker.openWriter(dir);
59 tw.addCategory(new CategoryPath("animal", "dog"));
61 assertEquals(0, checker.nopen());
63 LuceneTaxonomyReader tr = checker.openReader(dir);
67 assertEquals(0, checker.nopen());
69 tr = checker.openReader(dir);
70 tw = checker.openWriter(dir);
71 tw.addCategory(new CategoryPath("animal", "cat"));
77 assertEquals(0, checker.nopen());
79 tw = checker.openWriter(dir);
80 for (int i=0; i<10000; i++) {
81 tw.addCategory(new CategoryPath("number", Integer.toString(i)));
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)));
90 assertEquals(0, checker.nopen());
94 private static class LeakChecker {
96 Set<Integer> openReaders = new HashSet<Integer>();
99 Set<Integer> openWriters = new HashSet<Integer>();
103 public LuceneTaxonomyWriter openWriter(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
104 return new InstrumentedTaxonomyWriter(dir);
107 public LuceneTaxonomyReader openReader(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
108 return new InstrumentedTaxonomyReader(dir);
113 for (int i: openReaders) {
114 System.err.println("reader "+i+" still open");
117 for (int i: openWriters) {
118 System.err.println("writer "+i+" still open");
124 private class InstrumentedTaxonomyWriter extends LuceneTaxonomyWriter {
125 public InstrumentedTaxonomyWriter(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
129 protected IndexReader openReader() throws IOException {
130 return new InstrumentedIndexReader(super.openReader());
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));
142 private class InstrumentedTaxonomyReader extends LuceneTaxonomyReader {
143 public InstrumentedTaxonomyReader(Directory dir) throws CorruptIndexException, LockObtainFailedException, IOException {
147 protected IndexReader openIndexReader(Directory dir) throws CorruptIndexException, IOException {
148 return new InstrumentedIndexReader(IndexReader.open(dir,true));
153 private class InstrumentedIndexReader extends FilterIndexReader {
155 public InstrumentedIndexReader(IndexReader in) {
159 openReaders.add(mynum);
160 // System.err.println("opened "+mynum);
163 public synchronized IndexReader reopen() throws CorruptIndexException, IOException {
164 IndexReader n = in.reopen();
168 return new InstrumentedIndexReader(n);
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.
176 public void doClose() throws IOException {
178 if (!openReaders.contains(mynum)) { // probably can't happen...
179 fail("Reader #"+mynum+" was closed twice!");
181 openReaders.remove(mynum);
182 // System.err.println("closed "+mynum);
185 private class InstrumentedIndexWriter extends IndexWriter {
187 public InstrumentedIndexWriter(Directory d, IndexWriterConfig conf) throws CorruptIndexException, LockObtainFailedException, IOException {
190 openWriters.add(mynum);
191 // System.err.println("openedw "+mynum);
195 public void close() throws IOException {
197 if (!openWriters.contains(mynum)) { // probably can't happen...
198 fail("Writer #"+mynum+" was closed twice!");
200 openWriters.remove(mynum);
201 // System.err.println("closedw "+mynum);