001: package org.apache.lucene.index;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import java.io.IOException;
021: import java.util.ArrayList;
022: import java.util.Collections;
023: import java.util.HashSet;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Random;
027: import java.util.Set;
028:
029: import org.apache.lucene.analysis.WhitespaceAnalyzer;
030: import org.apache.lucene.analysis.standard.StandardAnalyzer;
031: import org.apache.lucene.document.Document;
032: import org.apache.lucene.document.Field;
033: import org.apache.lucene.document.Field.Index;
034: import org.apache.lucene.document.Field.Store;
035: import org.apache.lucene.search.Hits;
036: import org.apache.lucene.search.IndexSearcher;
037: import org.apache.lucene.search.TermQuery;
038: import org.apache.lucene.store.Directory;
039: import org.apache.lucene.store.RAMDirectory;
040:
041: import junit.framework.TestCase;
042:
043: public class TestIndexReaderReopen extends TestCase {
044:
045: public void testReopen() throws Exception {
046: final Directory dir1 = new RAMDirectory();
047:
048: createIndex(dir1, false);
049: performDefaultTests(new TestReopen() {
050:
051: protected void modifyIndex(int i) throws IOException {
052: TestIndexReaderReopen.modifyIndex(i, dir1);
053: }
054:
055: protected IndexReader openReader() throws IOException {
056: return IndexReader.open(dir1);
057: }
058:
059: });
060:
061: final Directory dir2 = new RAMDirectory();
062:
063: createIndex(dir2, true);
064: performDefaultTests(new TestReopen() {
065:
066: protected void modifyIndex(int i) throws IOException {
067: TestIndexReaderReopen.modifyIndex(i, dir2);
068: }
069:
070: protected IndexReader openReader() throws IOException {
071: return IndexReader.open(dir2);
072: }
073:
074: });
075: }
076:
077: public void testParallelReaderReopen() throws Exception {
078: final Directory dir1 = new RAMDirectory();
079: createIndex(dir1, true);
080: final Directory dir2 = new RAMDirectory();
081: createIndex(dir2, true);
082:
083: performDefaultTests(new TestReopen() {
084:
085: protected void modifyIndex(int i) throws IOException {
086: TestIndexReaderReopen.modifyIndex(i, dir1);
087: TestIndexReaderReopen.modifyIndex(i, dir2);
088: }
089:
090: protected IndexReader openReader() throws IOException {
091: ParallelReader pr = new ParallelReader();
092: pr.add(IndexReader.open(dir1));
093: pr.add(IndexReader.open(dir2));
094: return pr;
095: }
096:
097: });
098:
099: final Directory dir3 = new RAMDirectory();
100: createIndex(dir3, true);
101: final Directory dir4 = new RAMDirectory();
102: createIndex(dir4, true);
103:
104: performTestsWithExceptionInReopen(new TestReopen() {
105:
106: protected void modifyIndex(int i) throws IOException {
107: TestIndexReaderReopen.modifyIndex(i, dir3);
108: TestIndexReaderReopen.modifyIndex(i, dir4);
109: }
110:
111: protected IndexReader openReader() throws IOException {
112: ParallelReader pr = new ParallelReader();
113: pr.add(IndexReader.open(dir3));
114: pr.add(IndexReader.open(dir4));
115: pr.add(new FilterIndexReader(IndexReader.open(dir3)));
116: return pr;
117: }
118:
119: });
120: }
121:
122: public void testMultiReaderReopen() throws Exception {
123: final Directory dir1 = new RAMDirectory();
124: createIndex(dir1, true);
125: final Directory dir2 = new RAMDirectory();
126: createIndex(dir2, true);
127:
128: performDefaultTests(new TestReopen() {
129:
130: protected void modifyIndex(int i) throws IOException {
131: TestIndexReaderReopen.modifyIndex(i, dir1);
132: TestIndexReaderReopen.modifyIndex(i, dir2);
133: }
134:
135: protected IndexReader openReader() throws IOException {
136: return new MultiReader(
137: new IndexReader[] { IndexReader.open(dir1),
138: IndexReader.open(dir2) });
139: }
140:
141: });
142:
143: final Directory dir3 = new RAMDirectory();
144: createIndex(dir3, true);
145: final Directory dir4 = new RAMDirectory();
146: createIndex(dir4, true);
147:
148: performTestsWithExceptionInReopen(new TestReopen() {
149:
150: protected void modifyIndex(int i) throws IOException {
151: TestIndexReaderReopen.modifyIndex(i, dir3);
152: TestIndexReaderReopen.modifyIndex(i, dir4);
153: }
154:
155: protected IndexReader openReader() throws IOException {
156: return new MultiReader(new IndexReader[] {
157: IndexReader.open(dir3), IndexReader.open(dir4),
158: new FilterIndexReader(IndexReader.open(dir3)) });
159: }
160:
161: });
162:
163: }
164:
165: public void testMixedReaders() throws Exception {
166: final Directory dir1 = new RAMDirectory();
167: createIndex(dir1, true);
168: final Directory dir2 = new RAMDirectory();
169: createIndex(dir2, true);
170: final Directory dir3 = new RAMDirectory();
171: createIndex(dir3, false);
172: final Directory dir4 = new RAMDirectory();
173: createIndex(dir4, true);
174: final Directory dir5 = new RAMDirectory();
175: createIndex(dir5, false);
176:
177: performDefaultTests(new TestReopen() {
178:
179: protected void modifyIndex(int i) throws IOException {
180: // only change norms in this index to maintain the same number of docs for each of ParallelReader's subreaders
181: if (i == 1)
182: TestIndexReaderReopen.modifyIndex(i, dir1);
183:
184: TestIndexReaderReopen.modifyIndex(i, dir4);
185: TestIndexReaderReopen.modifyIndex(i, dir5);
186: }
187:
188: protected IndexReader openReader() throws IOException {
189: ParallelReader pr = new ParallelReader();
190: pr.add(IndexReader.open(dir1));
191: pr.add(IndexReader.open(dir2));
192: MultiReader mr = new MultiReader(
193: new IndexReader[] { IndexReader.open(dir3),
194: IndexReader.open(dir4) });
195: return new MultiReader(new IndexReader[] { pr, mr,
196: IndexReader.open(dir5) });
197: }
198: });
199: }
200:
201: private void performDefaultTests(TestReopen test) throws Exception {
202: IndexReader index1 = test.openReader();
203: IndexReader index2 = test.openReader();
204:
205: TestIndexReader.assertIndexEquals(index1, index2);
206:
207: // verify that reopen() does not return a new reader instance
208: // in case the index has no changes
209: ReaderCouple couple = refreshReader(index2, false);
210: assertTrue(couple.refreshedReader == index2);
211:
212: couple = refreshReader(index2, test, 0, true);
213: index1 = couple.newReader;
214: IndexReader index2_refreshed = couple.refreshedReader;
215: index2.close();
216:
217: // test if refreshed reader and newly opened reader return equal results
218: TestIndexReader.assertIndexEquals(index1, index2_refreshed);
219:
220: index1.close();
221: index2_refreshed.close();
222: assertReaderClosed(index2, true, true);
223: assertReaderClosed(index2_refreshed, true, true);
224:
225: index2 = test.openReader();
226:
227: for (int i = 1; i < 4; i++) {
228:
229: index1.close();
230: couple = refreshReader(index2, test, i, true);
231: // refresh IndexReader
232: index2.close();
233:
234: index2 = couple.refreshedReader;
235: index1 = couple.newReader;
236: TestIndexReader.assertIndexEquals(index1, index2);
237: }
238:
239: index1.close();
240: index2.close();
241: assertReaderClosed(index1, true, true);
242: assertReaderClosed(index2, true, true);
243: }
244:
245: public void testReferenceCounting() throws IOException {
246:
247: for (int mode = 0; mode < 4; mode++) {
248: Directory dir1 = new RAMDirectory();
249: createIndex(dir1, true);
250:
251: IndexReader reader0 = IndexReader.open(dir1);
252: assertRefCountEquals(1, reader0);
253:
254: assertTrue(reader0 instanceof MultiSegmentReader);
255: SegmentReader[] subReaders0 = ((MultiSegmentReader) reader0)
256: .getSubReaders();
257: for (int i = 0; i < subReaders0.length; i++) {
258: assertRefCountEquals(1, subReaders0[i]);
259: }
260:
261: // delete first document, so that only one of the subReaders have to be re-opened
262: IndexReader modifier = IndexReader.open(dir1);
263: modifier.deleteDocument(0);
264: modifier.close();
265:
266: IndexReader reader1 = refreshReader(reader0, true).refreshedReader;
267: assertTrue(reader1 instanceof MultiSegmentReader);
268: SegmentReader[] subReaders1 = ((MultiSegmentReader) reader1)
269: .getSubReaders();
270: assertEquals(subReaders0.length, subReaders1.length);
271:
272: for (int i = 0; i < subReaders0.length; i++) {
273: assertRefCountEquals(2, subReaders0[i]);
274: if (subReaders0[i] != subReaders1[i]) {
275: assertRefCountEquals(1, subReaders1[i]);
276: }
277: }
278:
279: // delete first document, so that only one of the subReaders have to be re-opened
280: modifier = IndexReader.open(dir1);
281: modifier.deleteDocument(1);
282: modifier.close();
283:
284: IndexReader reader2 = refreshReader(reader1, true).refreshedReader;
285: assertTrue(reader2 instanceof MultiSegmentReader);
286: SegmentReader[] subReaders2 = ((MultiSegmentReader) reader2)
287: .getSubReaders();
288: assertEquals(subReaders1.length, subReaders2.length);
289:
290: for (int i = 0; i < subReaders2.length; i++) {
291: if (subReaders2[i] == subReaders1[i]) {
292: if (subReaders1[i] == subReaders0[i]) {
293: assertRefCountEquals(3, subReaders2[i]);
294: } else {
295: assertRefCountEquals(2, subReaders2[i]);
296: }
297: } else {
298: assertRefCountEquals(1, subReaders2[i]);
299: if (subReaders0[i] == subReaders1[i]) {
300: assertRefCountEquals(3, subReaders2[i]);
301: assertRefCountEquals(2, subReaders0[i]);
302: } else {
303: assertRefCountEquals(3, subReaders0[i]);
304: assertRefCountEquals(1, subReaders1[i]);
305: }
306: }
307: }
308:
309: IndexReader reader3 = refreshReader(reader0, true).refreshedReader;
310: assertTrue(reader3 instanceof MultiSegmentReader);
311: SegmentReader[] subReaders3 = ((MultiSegmentReader) reader3)
312: .getSubReaders();
313: assertEquals(subReaders3.length, subReaders0.length);
314:
315: // try some permutations
316: switch (mode) {
317: case 0:
318: reader0.close();
319: reader1.close();
320: reader2.close();
321: reader3.close();
322: break;
323: case 1:
324: reader3.close();
325: reader2.close();
326: reader1.close();
327: reader0.close();
328: break;
329: case 2:
330: reader2.close();
331: reader3.close();
332: reader0.close();
333: reader1.close();
334: break;
335: case 3:
336: reader1.close();
337: reader3.close();
338: reader2.close();
339: reader0.close();
340: break;
341: }
342:
343: assertReaderClosed(reader0, true, true);
344: assertReaderClosed(reader1, true, true);
345: assertReaderClosed(reader2, true, true);
346: assertReaderClosed(reader3, true, true);
347: }
348: }
349:
350: public void testReferenceCountingMultiReader() throws IOException {
351: for (int mode = 0; mode <= 1; mode++) {
352: Directory dir1 = new RAMDirectory();
353: createIndex(dir1, false);
354: Directory dir2 = new RAMDirectory();
355: createIndex(dir2, true);
356:
357: IndexReader reader1 = IndexReader.open(dir1);
358: assertRefCountEquals(1, reader1);
359:
360: IndexReader multiReader1 = new MultiReader(
361: new IndexReader[] { reader1, IndexReader.open(dir2) },
362: (mode == 0));
363: modifyIndex(0, dir2);
364: assertRefCountEquals(1 + mode, reader1);
365:
366: IndexReader multiReader2 = multiReader1.reopen();
367: // index1 hasn't changed, so multiReader2 should share reader1 now with multiReader1
368: assertRefCountEquals(2 + mode, reader1);
369:
370: modifyIndex(0, dir1);
371: IndexReader reader2 = reader1.reopen();
372: assertRefCountEquals(3 + mode, reader1);
373:
374: modifyIndex(1, dir1);
375: IndexReader reader3 = reader2.reopen();
376: assertRefCountEquals(4 + mode, reader1);
377: assertRefCountEquals(1, reader2);
378:
379: multiReader1.close();
380: assertRefCountEquals(3 + mode, reader1);
381:
382: multiReader1.close();
383: assertRefCountEquals(3 + mode, reader1);
384:
385: reader1.close();
386: assertRefCountEquals(3, reader1);
387:
388: multiReader2.close();
389: assertRefCountEquals(2, reader1);
390:
391: multiReader2.close();
392: assertRefCountEquals(2, reader1);
393:
394: reader3.close();
395: assertRefCountEquals(1, reader1);
396: assertReaderOpen(reader1);
397:
398: reader2.close();
399: assertRefCountEquals(0, reader1);
400: assertReaderClosed(reader1, true, false);
401:
402: reader2.close();
403: assertRefCountEquals(0, reader1);
404:
405: reader3.close();
406: assertRefCountEquals(0, reader1);
407: assertReaderClosed(reader1, true, true);
408: }
409:
410: }
411:
412: public void testReferenceCountingParallelReader()
413: throws IOException {
414: for (int mode = 0; mode <= 1; mode++) {
415: Directory dir1 = new RAMDirectory();
416: createIndex(dir1, false);
417: Directory dir2 = new RAMDirectory();
418: createIndex(dir2, true);
419:
420: IndexReader reader1 = IndexReader.open(dir1);
421: assertRefCountEquals(1, reader1);
422:
423: ParallelReader parallelReader1 = new ParallelReader(
424: mode == 0);
425: parallelReader1.add(reader1);
426: parallelReader1.add(IndexReader.open(dir2));
427: modifyIndex(1, dir2);
428: assertRefCountEquals(1 + mode, reader1);
429:
430: IndexReader parallelReader2 = parallelReader1.reopen();
431: // index1 hasn't changed, so parallelReader2 should share reader1 now with multiReader1
432: assertRefCountEquals(2 + mode, reader1);
433:
434: modifyIndex(0, dir1);
435: modifyIndex(0, dir2);
436: IndexReader reader2 = reader1.reopen();
437: assertRefCountEquals(3 + mode, reader1);
438:
439: modifyIndex(4, dir1);
440: IndexReader reader3 = reader2.reopen();
441: assertRefCountEquals(4 + mode, reader1);
442: assertRefCountEquals(1, reader2);
443:
444: parallelReader1.close();
445: assertRefCountEquals(3 + mode, reader1);
446:
447: parallelReader1.close();
448: assertRefCountEquals(3 + mode, reader1);
449:
450: reader1.close();
451: assertRefCountEquals(3, reader1);
452:
453: parallelReader2.close();
454: assertRefCountEquals(2, reader1);
455:
456: parallelReader2.close();
457: assertRefCountEquals(2, reader1);
458:
459: reader3.close();
460: assertRefCountEquals(1, reader1);
461: assertReaderOpen(reader1);
462:
463: reader2.close();
464: assertRefCountEquals(0, reader1);
465: assertReaderClosed(reader1, true, false);
466:
467: reader2.close();
468: assertRefCountEquals(0, reader1);
469:
470: reader3.close();
471: assertRefCountEquals(0, reader1);
472: assertReaderClosed(reader1, true, true);
473: }
474:
475: }
476:
477: public void testNormsRefCounting() throws IOException {
478: Directory dir1 = new RAMDirectory();
479: createIndex(dir1, false);
480:
481: SegmentReader reader1 = (SegmentReader) IndexReader.open(dir1);
482: IndexReader modifier = IndexReader.open(dir1);
483: modifier.deleteDocument(0);
484: modifier.close();
485:
486: SegmentReader reader2 = (SegmentReader) reader1.reopen();
487: modifier = IndexReader.open(dir1);
488: modifier.setNorm(1, "field1", 50);
489: modifier.setNorm(1, "field2", 50);
490: modifier.close();
491:
492: SegmentReader reader3 = (SegmentReader) reader2.reopen();
493: modifier = IndexReader.open(dir1);
494: modifier.deleteDocument(2);
495: modifier.close();
496: SegmentReader reader4 = (SegmentReader) reader3.reopen();
497:
498: modifier = IndexReader.open(dir1);
499: modifier.deleteDocument(3);
500: modifier.close();
501: SegmentReader reader5 = (SegmentReader) reader3.reopen();
502:
503: // Now reader2-reader5 references reader1. reader1 and reader2
504: // share the same norms. reader3, reader4, reader5 also share norms.
505: assertRefCountEquals(5, reader1);
506: assertFalse(reader1.normsClosed());
507: reader1.close();
508: assertRefCountEquals(4, reader1);
509: assertFalse(reader1.normsClosed());
510: reader2.close();
511: assertRefCountEquals(3, reader1);
512: // now the norms for field1 and field2 should be closed
513: assertTrue(reader1.normsClosed("field1"));
514: assertTrue(reader1.normsClosed("field2"));
515: // but the norms for field3 and field4 should still be open
516: assertFalse(reader1.normsClosed("field3"));
517: assertFalse(reader1.normsClosed("field4"));
518:
519: reader3.close();
520: assertRefCountEquals(2, reader1);
521: assertFalse(reader3.normsClosed());
522: reader5.close();
523: assertRefCountEquals(1, reader1);
524: assertFalse(reader3.normsClosed());
525: reader4.close();
526: assertRefCountEquals(0, reader1);
527:
528: // and now all norms that reader1 used should be closed
529: assertTrue(reader1.normsClosed());
530:
531: // now that reader3, reader4 and reader5 are closed,
532: // the norms that those three readers shared should be
533: // closed as well
534: assertTrue(reader3.normsClosed());
535: }
536:
537: private void performTestsWithExceptionInReopen(TestReopen test)
538: throws Exception {
539: IndexReader index1 = test.openReader();
540: IndexReader index2 = test.openReader();
541:
542: TestIndexReader.assertIndexEquals(index1, index2);
543:
544: try {
545: ReaderCouple couple = refreshReader(index1, test, 0, true);
546: fail("Expected exception not thrown.");
547: } catch (Exception e) {
548: // expected exception
549: }
550:
551: // index2 should still be usable and unaffected by the failed reopen() call
552: TestIndexReader.assertIndexEquals(index1, index2);
553: }
554:
555: public void testThreadSafety() throws Exception {
556: final Directory dir = new RAMDirectory();
557: final int n = 150;
558:
559: IndexWriter writer = new IndexWriter(dir,
560: new StandardAnalyzer());
561: for (int i = 0; i < n; i++) {
562: writer.addDocument(createDocument(i, 3));
563: }
564: writer.optimize();
565: writer.close();
566:
567: final TestReopen test = new TestReopen() {
568: protected void modifyIndex(int i) throws IOException {
569: if (i % 3 == 0) {
570: IndexReader modifier = IndexReader.open(dir);
571: modifier.setNorm(i, "field1", 50);
572: modifier.close();
573: } else if (i % 3 == 1) {
574: IndexReader modifier = IndexReader.open(dir);
575: modifier.deleteDocument(i);
576: modifier.close();
577: } else {
578: IndexWriter modifier = new IndexWriter(dir,
579: new StandardAnalyzer());
580: modifier.addDocument(createDocument(n + i, 6));
581: modifier.close();
582: }
583: }
584:
585: protected IndexReader openReader() throws IOException {
586: return IndexReader.open(dir);
587: }
588: };
589:
590: final List readers = Collections
591: .synchronizedList(new ArrayList());
592: IndexReader firstReader = IndexReader.open(dir);
593: IndexReader reader = firstReader;
594: final Random rnd = new Random();
595:
596: ReaderThread[] threads = new ReaderThread[n];
597: final Set readersToClose = Collections
598: .synchronizedSet(new HashSet());
599:
600: for (int i = 0; i < n; i++) {
601: if (i % 10 == 0) {
602: IndexReader refreshed = reader.reopen();
603: if (refreshed != reader) {
604: readersToClose.add(reader);
605: }
606: reader = refreshed;
607: }
608: final IndexReader r = reader;
609:
610: final int index = i;
611:
612: ReaderThreadTask task;
613:
614: if (i < 20 || (i >= 50 && i < 70) || i > 90) {
615: task = new ReaderThreadTask() {
616:
617: public void run() throws Exception {
618: while (!stopped) {
619: if (index % 2 == 0) {
620: // refresh reader synchronized
621: ReaderCouple c = (refreshReader(r,
622: test, index, true));
623: readersToClose.add(c.newReader);
624: readersToClose.add(c.refreshedReader);
625: readers.add(c);
626: // prevent too many readers
627: break;
628: } else {
629: // not synchronized
630: IndexReader refreshed = r.reopen();
631:
632: IndexSearcher searcher = new IndexSearcher(
633: refreshed);
634: Hits hits = searcher
635: .search(new TermQuery(
636: new Term(
637: "field1",
638: "a"
639: + rnd
640: .nextInt(refreshed
641: .maxDoc()))));
642: if (hits.length() > 0) {
643: hits.doc(0);
644: }
645:
646: // r might have changed because this is not a
647: // synchronized method. However we don't want
648: // to make it synchronized to test
649: // thread-safety of IndexReader.close().
650: // That's why we add refreshed also to
651: // readersToClose, because double closing is fine
652: if (refreshed != r) {
653: refreshed.close();
654: }
655: readersToClose.add(refreshed);
656: }
657: try {
658: synchronized (this ) {
659: wait(1000);
660: }
661: } catch (InterruptedException e) {
662: }
663: }
664: }
665:
666: };
667: } else {
668: task = new ReaderThreadTask() {
669: public void run() throws Exception {
670: while (!stopped) {
671: int numReaders = readers.size();
672: if (numReaders > 0) {
673: ReaderCouple c = (ReaderCouple) readers
674: .get(rnd.nextInt(numReaders));
675: TestIndexReader.assertIndexEquals(
676: c.newReader, c.refreshedReader);
677: }
678:
679: try {
680: synchronized (this ) {
681: wait(100);
682: }
683: } catch (InterruptedException e) {
684: }
685: }
686:
687: }
688:
689: };
690: }
691:
692: threads[i] = new ReaderThread(task);
693: threads[i].start();
694: }
695:
696: synchronized (this ) {
697: try {
698: wait(15000);
699: } catch (InterruptedException e) {
700: }
701: }
702:
703: for (int i = 0; i < n; i++) {
704: if (threads[i] != null) {
705: threads[i].stopThread();
706: }
707: }
708:
709: for (int i = 0; i < n; i++) {
710: if (threads[i] != null) {
711: try {
712: threads[i].join();
713: if (threads[i].exception != null) {
714: throw threads[i].exception;
715: }
716: } catch (InterruptedException e) {
717: }
718: }
719:
720: }
721:
722: Iterator it = readersToClose.iterator();
723: while (it.hasNext()) {
724: ((IndexReader) it.next()).close();
725: }
726:
727: firstReader.close();
728: reader.close();
729:
730: it = readersToClose.iterator();
731: while (it.hasNext()) {
732: assertReaderClosed((IndexReader) it.next(), true, true);
733: }
734:
735: assertReaderClosed(reader, true, true);
736: assertReaderClosed(firstReader, true, true);
737: }
738:
739: private static class ReaderCouple {
740: ReaderCouple(IndexReader r1, IndexReader r2) {
741: newReader = r1;
742: refreshedReader = r2;
743: }
744:
745: IndexReader newReader;
746: IndexReader refreshedReader;
747: }
748:
749: private abstract static class ReaderThreadTask {
750: protected boolean stopped;
751:
752: public void stop() {
753: this .stopped = true;
754: }
755:
756: public abstract void run() throws Exception;
757: }
758:
759: private static class ReaderThread extends Thread {
760: private ReaderThreadTask task;
761: private Exception exception;
762:
763: ReaderThread(ReaderThreadTask task) {
764: this .task = task;
765: }
766:
767: public void stopThread() {
768: this .task.stop();
769: }
770:
771: public void run() {
772: try {
773: this .task.run();
774: } catch (Exception e) {
775: this .exception = e;
776: }
777: }
778: }
779:
780: private Object createReaderMutex = new Object();
781:
782: private ReaderCouple refreshReader(IndexReader reader,
783: boolean hasChanges) throws IOException {
784: return refreshReader(reader, null, -1, hasChanges);
785: }
786:
787: private ReaderCouple refreshReader(IndexReader reader,
788: TestReopen test, int modify, boolean hasChanges)
789: throws IOException {
790: synchronized (createReaderMutex) {
791: IndexReader r = null;
792: if (test != null) {
793: test.modifyIndex(modify);
794: r = test.openReader();
795: }
796:
797: IndexReader refreshed = reader.reopen();
798: if (hasChanges) {
799: if (refreshed == reader) {
800: fail("No new IndexReader instance created during refresh.");
801: }
802: } else {
803: if (refreshed != reader) {
804: fail("New IndexReader instance created during refresh even though index had no changes.");
805: }
806: }
807:
808: return new ReaderCouple(r, refreshed);
809: }
810: }
811:
812: private static void createIndex(Directory dir, boolean multiSegment)
813: throws IOException {
814: IndexWriter w = new IndexWriter(dir, new WhitespaceAnalyzer());
815:
816: w.setMergePolicy(new LogDocMergePolicy());
817:
818: for (int i = 0; i < 100; i++) {
819: w.addDocument(createDocument(i, 4));
820: if (multiSegment && (i % 10) == 0) {
821: w.flush();
822: }
823: }
824:
825: if (!multiSegment) {
826: w.optimize();
827: }
828:
829: w.close();
830:
831: IndexReader r = IndexReader.open(dir);
832: if (multiSegment) {
833: assertTrue(r instanceof MultiSegmentReader);
834: } else {
835: assertTrue(r instanceof SegmentReader);
836: }
837: r.close();
838: }
839:
840: private static Document createDocument(int n, int numFields) {
841: StringBuffer sb = new StringBuffer();
842: Document doc = new Document();
843: sb.append("a");
844: sb.append(n);
845: doc.add(new Field("field1", sb.toString(), Store.YES,
846: Index.TOKENIZED));
847: sb.append(" b");
848: sb.append(n);
849: for (int i = 1; i < numFields; i++) {
850: doc.add(new Field("field" + (i + 1), sb.toString(),
851: Store.YES, Index.TOKENIZED));
852: }
853: return doc;
854: }
855:
856: private static void modifyIndex(int i, Directory dir)
857: throws IOException {
858: switch (i) {
859: case 0: {
860: IndexWriter w = new IndexWriter(dir,
861: new WhitespaceAnalyzer());
862: w.deleteDocuments(new Term("field2", "a11"));
863: w.deleteDocuments(new Term("field2", "b30"));
864: w.close();
865: break;
866: }
867: case 1: {
868: IndexReader reader = IndexReader.open(dir);
869: reader.setNorm(4, "field1", 123);
870: reader.setNorm(44, "field2", 222);
871: reader.setNorm(44, "field4", 22);
872: reader.close();
873: break;
874: }
875: case 2: {
876: IndexWriter w = new IndexWriter(dir,
877: new WhitespaceAnalyzer());
878: w.optimize();
879: w.close();
880: break;
881: }
882: case 3: {
883: IndexWriter w = new IndexWriter(dir,
884: new WhitespaceAnalyzer());
885: w.addDocument(createDocument(101, 4));
886: w.optimize();
887: w.addDocument(createDocument(102, 4));
888: w.addDocument(createDocument(103, 4));
889: w.close();
890: break;
891: }
892: case 4: {
893: IndexReader reader = IndexReader.open(dir);
894: reader.setNorm(5, "field1", 123);
895: reader.setNorm(55, "field2", 222);
896: reader.close();
897: break;
898: }
899:
900: }
901: }
902:
903: private void assertReaderClosed(IndexReader reader,
904: boolean checkSubReaders, boolean checkNormsClosed) {
905: assertEquals(0, reader.getRefCount());
906:
907: if (checkNormsClosed && reader instanceof SegmentReader) {
908: assertTrue(((SegmentReader) reader).normsClosed());
909: }
910:
911: if (checkSubReaders) {
912: if (reader instanceof MultiSegmentReader) {
913: SegmentReader[] subReaders = ((MultiSegmentReader) reader)
914: .getSubReaders();
915: for (int i = 0; i < subReaders.length; i++) {
916: assertReaderClosed(subReaders[i], checkSubReaders,
917: checkNormsClosed);
918: }
919: }
920:
921: if (reader instanceof MultiReader) {
922: IndexReader[] subReaders = ((MultiReader) reader)
923: .getSubReaders();
924: for (int i = 0; i < subReaders.length; i++) {
925: assertReaderClosed(subReaders[i], checkSubReaders,
926: checkNormsClosed);
927: }
928: }
929:
930: if (reader instanceof ParallelReader) {
931: IndexReader[] subReaders = ((ParallelReader) reader)
932: .getSubReaders();
933: for (int i = 0; i < subReaders.length; i++) {
934: assertReaderClosed(subReaders[i], checkSubReaders,
935: checkNormsClosed);
936: }
937: }
938: }
939: }
940:
941: private void assertReaderOpen(IndexReader reader) {
942: reader.ensureOpen();
943:
944: if (reader instanceof MultiSegmentReader) {
945: SegmentReader[] subReaders = ((MultiSegmentReader) reader)
946: .getSubReaders();
947: for (int i = 0; i < subReaders.length; i++) {
948: assertReaderOpen(subReaders[i]);
949: }
950: }
951: }
952:
953: private void assertRefCountEquals(int refCount, IndexReader reader) {
954: assertEquals("Reader has wrong refCount value.", refCount,
955: reader.getRefCount());
956: }
957:
958: private abstract static class TestReopen {
959: protected abstract IndexReader openReader() throws IOException;
960:
961: protected abstract void modifyIndex(int i) throws IOException;
962: }
963:
964: }
|