1 package com.atlassian.bonnie;
2
3 import java.io.IOException;
4 import java.io.File;
5
6 import junit.framework.TestCase;
7
8 import org.apache.lucene.analysis.standard.StandardAnalyzer;
9 import org.apache.lucene.document.Document;
10 import org.apache.lucene.document.Field;
11 import org.apache.lucene.index.IndexReader;
12 import org.apache.lucene.index.IndexWriter;
13 import org.apache.lucene.index.Term;
14 import org.apache.lucene.search.IndexSearcher;
15 import org.apache.lucene.search.TermQuery;
16 import org.apache.lucene.store.RAMDirectory;
17
18 import edu.emory.mathcs.backport.java.util.concurrent.*;
19 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
20 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicReference;
21
22 public final class TestConcurrentLuceneConnection extends TestCase
23 {
24 ConcurrentLuceneConnection lcon;
25 RAMDirectory directory = new RAMDirectory();
26
27 private static final String FIELD_NAME = "my.field";
28
29 private static final String FIELD_VALUE = "myvalue";
30 private final TermQuery query = new TermQuery(new Term(FIELD_NAME, FIELD_VALUE));
31
32 protected void setUp() throws Exception
33 {
34
35 new IndexWriter(directory, null, true).close();
36 lcon = new ConcurrentLuceneConnection(directory, new StandardAnalyzer(), ILuceneConnection.DEFAULT_CONFIGURATION);
37 }
38
39 public void testIsIndexCreated()
40 {
41 assertTrue(lcon.isIndexCreated());
42 assertFalse(new ConcurrentLuceneConnection(new RAMDirectory(), new StandardAnalyzer(), ILuceneConnection.DEFAULT_CONFIGURATION).isIndexCreated());
43 }
44
45 public void testSearcherReuse()
46 {
47 final int numDocs = 5;
48 addDocsToIndex(numDocs);
49
50 final AtomicReference searcherRef = new AtomicReference(null);
51 lcon.withSearch(new LuceneConnection.SearcherAction()
52 {
53 public void perform(IndexSearcher searcher) throws IOException
54 {
55 searcherRef.set(searcher);
56 assertEquals(5, searcher.search(query).length());
57 }
58 });
59
60 lcon.withSearch(new LuceneConnection.SearcherAction()
61 {
62 public void perform(IndexSearcher searcher) throws IOException
63 {
64 assertEquals(5, searcher.search(query).length());
65
66 assertTrue(searcherRef.get() == searcher);
67 searcherRef.set(searcher);
68 }
69 });
70
71 lcon.withWriter(new LuceneConnection.WriterAction()
72 {
73 public void perform(IndexWriter writer)
74 {
75 }
76 });
77
78 lcon.withSearch(new LuceneConnection.SearcherAction()
79 {
80 public void perform(IndexSearcher searcher) throws IOException
81 {
82 assertEquals(5, searcher.search(query).length());
83
84 assertFalse(searcherRef.get() == searcher);
85 searcherRef.set(searcher);
86 }
87 });
88 lcon.withSearch(new LuceneConnection.SearcherAction()
89 {
90 public void perform(IndexSearcher searcher) throws IOException
91 {
92 assertEquals(5, searcher.search(query).length());
93
94 assertTrue(searcherRef.get() == searcher);
95 searcherRef.set(searcher);
96 }
97 });
98 lcon.close();
99 lcon.withSearch(new LuceneConnection.SearcherAction()
100 {
101 public void perform(IndexSearcher searcher) throws IOException
102 {
103 assertEquals(5, searcher.search(query).length());
104
105 assertFalse(searcherRef.get() == searcher);
106 searcherRef.set(searcher);
107 }
108 });
109 lcon.withSearch(new LuceneConnection.SearcherAction()
110 {
111 public void perform(IndexSearcher searcher) throws IOException
112 {
113 assertEquals(5, searcher.search(query).length());
114
115 assertTrue(searcherRef.get() == searcher);
116 searcherRef.set(searcher);
117 }
118 });
119 lcon.withReaderAndDeletes(new ILuceneConnection.ReaderAction()
120 {
121 public Object perform(IndexReader reader)
122 {
123 return null;
124 }
125 });
126 lcon.withSearch(new LuceneConnection.SearcherAction()
127 {
128 public void perform(IndexSearcher searcher) throws IOException
129 {
130 assertEquals(5, searcher.search(query).length());
131
132 assertFalse(searcherRef.get() == searcher);
133 searcherRef.set(searcher);
134 }
135 });
136 lcon.withReader(new ILuceneConnection.ReaderAction()
137 {
138 public Object perform(IndexReader reader)
139 {
140 return null;
141 }
142 });
143 lcon.withSearch(new LuceneConnection.SearcherAction()
144 {
145 public void perform(IndexSearcher searcher) throws IOException
146 {
147 assertEquals(5, searcher.search(query).length());
148
149 assertTrue(searcherRef.get() == searcher);
150 }
151 });
152 }
153
154 public void testWriterIsInteractiveModeConfiguration() throws Exception
155 {
156 lcon.withWriter(new LuceneConnection.WriterAction()
157 {
158 public void perform(IndexWriter writer)
159 {
160
161 assertEquals("Should be interactive mode maxMergeSettings", ILuceneConnection.DEFAULT_CONFIGURATION.getInteractiveMaxMergeDocs(), writer.getMaxMergeDocs());
162 assertEquals("Should be interactive mode maxBufferedSettings", ILuceneConnection.DEFAULT_CONFIGURATION.getInteractiveMaxBufferedDocs(), writer.getMaxBufferedDocs());
163 assertEquals("Should be interactive mode mergeFactorSettings", ILuceneConnection.DEFAULT_CONFIGURATION.getInteractiveMergeFactor(), writer.getMergeFactor());
164 assertEquals("Should be default maxField", ILuceneConnection.DEFAULT_CONFIGURATION.getMaxFieldLength(), writer.getMaxFieldLength());
165 }
166 });
167 }
168
169 public void testReaderReuse()
170 {
171 final int numDocs = 5;
172 addDocsToIndex(numDocs);
173
174 final AtomicReference readerRef = new AtomicReference(null);
175 lcon.withReader(new ILuceneConnection.ReaderAction()
176 {
177 public Object perform(IndexReader reader)
178 {
179 readerRef.set(reader);
180 assertEquals(5, reader.numDocs());
181 return null;
182 }
183 });
184
185 lcon.withReader(new ILuceneConnection.ReaderAction()
186 {
187 public Object perform(IndexReader reader)
188 {
189 assertEquals(5, reader.numDocs());
190
191 assertTrue(readerRef.get() == reader);
192 readerRef.set(reader);
193 return null;
194 }
195 });
196
197 lcon.withWriter(new LuceneConnection.WriterAction()
198 {
199 public void perform(IndexWriter writer)
200 {
201 }
202 });
203
204 lcon.withReader(new ILuceneConnection.ReaderAction()
205 {
206 public Object perform(IndexReader reader)
207 {
208 assertEquals(5, reader.numDocs());
209
210 assertFalse(readerRef.get() == reader);
211 readerRef.set(reader);
212 return null;
213 }
214 });
215 lcon.withReader(new ILuceneConnection.ReaderAction()
216 {
217 public Object perform(IndexReader reader)
218 {
219 assertEquals(5, reader.numDocs());
220
221 assertTrue(readerRef.get() == reader);
222 readerRef.set(reader);
223 return null;
224 }
225 });
226 lcon.close();
227 lcon.withReader(new ILuceneConnection.ReaderAction()
228 {
229 public Object perform(IndexReader reader)
230 {
231 assertEquals(5, reader.numDocs());
232
233 assertFalse(readerRef.get() == reader);
234 readerRef.set(reader);
235 return null;
236 }
237 });
238 lcon.withReader(new ILuceneConnection.ReaderAction()
239 {
240 public Object perform(IndexReader reader)
241 {
242 assertEquals(5, reader.numDocs());
243
244 assertTrue(readerRef.get() == reader);
245 readerRef.set(reader);
246 return null;
247 }
248 });
249 lcon.withReaderAndDeletes(new ILuceneConnection.ReaderAction()
250 {
251 public Object perform(IndexReader reader)
252 {
253 return null;
254 }
255 });
256 lcon.withReader(new ILuceneConnection.ReaderAction()
257 {
258 public Object perform(IndexReader reader)
259 {
260 assertEquals(5, reader.numDocs());
261
262 assertFalse(readerRef.get() == reader);
263 readerRef.set(reader);
264 return null;
265 }
266 });
267 lcon.withSearch(new ILuceneConnection.SearcherAction()
268 {
269 public void perform(IndexSearcher searcher)
270 {
271 assertNotNull(searcher.getIndexReader());
272 assertTrue(readerRef.get() == searcher.getIndexReader());
273 }
274 });
275 lcon.withReader(new ILuceneConnection.ReaderAction()
276 {
277 public Object perform(IndexReader reader)
278 {
279 assertEquals(5, reader.numDocs());
280
281 assertTrue(readerRef.get() == reader);
282 return null;
283 }
284 });
285 }
286
287 public void testRecreateIndexDirectory() throws IOException
288 {
289 final int numDocs = 5;
290 addDocsToIndex(numDocs);
291
292 lcon.withSearch(new ILuceneConnection.SearcherAction()
293 {
294 public void perform(IndexSearcher searcher) throws IOException
295 {
296 assertEquals(5, searcher.search(query).length());
297 }
298 });
299 addDocsToIndex(numDocs);
300 lcon.withSearch(new ILuceneConnection.SearcherAction()
301 {
302 public void perform(IndexSearcher searcher) throws IOException
303 {
304 assertEquals(10, searcher.search(query).length());
305 }
306 });
307 lcon.recreateIndexDirectory();
308 lcon.withSearch(new ILuceneConnection.SearcherAction()
309 {
310 public void perform(IndexSearcher searcher) throws IOException
311 {
312 assertEquals(0, searcher.search(query).length());
313 }
314 });
315 }
316
317 public void testFileConstructor() throws IOException
318 {
319 final File tempDir = File.createTempFile(this.getClass().getName(), ".idx");
320 try
321 {
322 tempDir.delete();
323 tempDir.mkdirs();
324 lcon = new ConcurrentLuceneConnection(tempDir, new StandardAnalyzer(), ILuceneConnection.DEFAULT_CONFIGURATION);
325 assertFalse(IndexReader.indexExists(tempDir));
326 lcon.recreateIndexDirectory();
327 assertTrue(IndexReader.indexExists(tempDir));
328 }
329 finally
330 {
331 tempDir.delete();
332 }
333 }
334
335 public void testOptimizeCallsCorrectly() throws IOException
336 {
337 final AtomicBoolean optimizeCalled = new AtomicBoolean(false);
338 final IndexWriter mockWriter = new IndexWriter(directory, null, false)
339 {
340 public synchronized void optimize()
341 {
342 optimizeCalled.set(true);
343 }
344 };
345
346 lcon = new ConcurrentLuceneConnection(directory, new StandardAnalyzer(), ILuceneConnection.DEFAULT_CONFIGURATION)
347 {
348 public void withWriter(ILuceneConnection.WriterAction action) throws LuceneException
349 {
350 try
351 {
352 action.perform(mockWriter);
353 }
354 catch (IOException e)
355 {
356 throw new LuceneException(e);
357 }
358 }
359 };
360
361 lcon.optimize();
362
363 assertTrue(optimizeCalled.get());
364 }
365
366 public void testLeakedSearcher() throws Exception
367 {
368 addDocsToIndex(8);
369 IndexSearcher searcher = lcon.leakSearcher();
370 try
371 {
372 assertNotNull(searcher);
373 assertEquals(8, searcher.search(query).length());
374 }
375 finally
376 {
377 if (searcher != null)
378 {
379 searcher.close();
380 }
381 }
382
383 }
384
385 public void testFlipSearcher() throws IOException
386 {
387
388 lcon.flipCurrentSearcher();
389
390 IndexSearcher searcher = null;
391 IndexSearcher anotherSearcher = null;
392 try
393 {
394 searcher = lcon.leakSearcher();
395 lcon.flipCurrentSearcher();
396 anotherSearcher = lcon.leakSearcher();
397 assertFalse(searcher == anotherSearcher);
398 }
399 finally
400 {
401 if (searcher != null)
402 {
403 searcher.close();
404 }
405 if (anotherSearcher != null)
406 {
407 anotherSearcher.close();
408 }
409 }
410 }
411
412 public void testWriterBlocksDelete() throws InterruptedException
413 {
414 addDocsToIndex(5);
415
416 final ExecutorService pool = Executors.newSingleThreadExecutor();
417 final AtomicBoolean innerThreadStarted = new AtomicBoolean(false);
418 final CountDownLatch deleteComplete = new CountDownLatch(1);
419 final AtomicReference firstReaderRef = new AtomicReference(null);
420
421
422 lcon.withWriter(new ILuceneConnection.WriterAction()
423 {
424 public void perform(final IndexWriter writer) throws IOException
425 {
426 final CountDownLatch latch = new CountDownLatch(1);
427
428
429 Future deleteTask = pool.submit(new Runnable()
430 {
431 public void run()
432 {
433 innerThreadStarted.set(true);
434
435
436 latch.countDown();
437
438
439 lcon.withReaderAndDeletes(new ILuceneConnection.ReaderAction()
440 {
441 public Object perform(IndexReader reader) throws IOException
442 {
443 assertEquals("threaded withWriter: Added 2 documents not detected from thread", 7, reader.numDocs());
444 reader.deleteDocument(0);
445 firstReaderRef.set(reader);
446 deleteComplete.countDown();
447 return null;
448 }
449 });
450 }
451 });
452
453
454 try
455 {
456 latch.await();
457 }
458 catch (InterruptedException e)
459 {
460 throw new RuntimeException(e);
461 }
462
463
464 assertTrue(innerThreadStarted.get());
465
466
467
468 assertFalse(deleteTask.isDone());
469
470 assertEquals(5, writer.docCount());
471
472 writer.addDocument(createDocument());
473 writer.addDocument(createDocument());
474
475 assertFalse(deleteTask.isDone());
476 }
477 });
478
479
480 deleteComplete.await();
481
482 lcon.withReaderAndDeletes(new ILuceneConnection.ReaderAction()
483 {
484 public Object perform(IndexReader reader)
485 {
486
487 assertEquals(6, reader.numDocs());
488 return null;
489 }
490 });
491 assertEquals("threaded withReaderAndDeletes: Document not added in thread", 6, lcon.getNumDocs());
492 }
493
494 public void testDeleteBlocksWriter() throws InterruptedException
495 {
496 addDocsToIndex(5);
497
498 final ExecutorService pool = Executors.newSingleThreadExecutor();
499 final AtomicBoolean innerThreadStarted = new AtomicBoolean(false);
500 final CountDownLatch writeComplete = new CountDownLatch(1);
501 final AtomicReference firstWriterRef = new AtomicReference(null);
502
503
504 lcon.withReaderAndDeletes(new ILuceneConnection.ReaderAction()
505 {
506 public Object perform(final IndexReader reader) throws IOException
507 {
508 final CountDownLatch latch = new CountDownLatch(1);
509
510
511 Future writeTask = pool.submit(new Runnable()
512 {
513 public void run()
514 {
515 innerThreadStarted.set(true);
516
517
518 latch.countDown();
519
520
521 lcon.withWriter(new ILuceneConnection.WriterAction()
522 {
523 public void perform(IndexWriter writer) throws IOException
524 {
525 assertEquals("threaded withReaderAndDeletes: deleted documents not detected from thread", 3, reader.numDocs());
526 writer.addDocument(createDocument());
527 firstWriterRef.set(writer);
528 writeComplete.countDown();
529 }
530 });
531 }
532 });
533
534
535 try
536 {
537 latch.await();
538 }
539 catch (InterruptedException e)
540 {
541 throw new RuntimeException(e);
542 }
543
544
545 assertTrue(innerThreadStarted.get());
546
547
548
549 assertFalse(writeTask.isDone());
550
551 reader.deleteDocument(0);
552 reader.deleteDocument(1);
553 return null;
554 }
555 });
556
557
558 writeComplete.await();
559
560 lcon.withReaderAndDeletes(new ILuceneConnection.ReaderAction()
561 {
562 public Object perform(IndexReader reader)
563 {
564
565 assertEquals(4, reader.numDocs());
566 return null;
567 }
568 });
569 assertEquals("threaded withReaderAndDeletes: Document not added in thread", 4, lcon.getNumDocs());
570 }
571
572 public void testDeleteClosesReader()
573 {
574 final AtomicReference readerRef = new AtomicReference(null);
575 lcon.withReaderAndDeletes(new ILuceneConnection.ReaderAction()
576 {
577 public Object perform(IndexReader reader)
578 {
579 assertNotNull(reader);
580 readerRef.set(reader);
581 return null;
582 }
583 });
584 lcon.withReaderAndDeletes(new ILuceneConnection.ReaderAction()
585 {
586 public Object perform(IndexReader reader)
587 {
588 assertNotNull(reader);
589 assertFalse(readerRef.get() == reader);
590 return null;
591 }
592 });
593 }
594
595 public void testWriteClosesWriter()
596 {
597 final AtomicReference writerRef = new AtomicReference(null);
598 lcon.withWriter(new ILuceneConnection.WriterAction()
599 {
600 public void perform(IndexWriter writer)
601 {
602 assertNotNull(writer);
603 writerRef.set(writer);
604 }
605 });
606 lcon.withWriter(new ILuceneConnection.WriterAction()
607 {
608 public void perform(IndexWriter writer)
609 {
610 assertNotNull(writer);
611 assertFalse(writerRef.get() == writer);
612 }
613 });
614 }
615
616 public void testDeleteAndWriteAtomicity() throws Exception
617 {
618 final CountDownLatch latch = new CountDownLatch(1);
619 final ExecutorService pool = Executors.newSingleThreadExecutor();
620 final AtomicReference secondUpdateFuture = new AtomicReference(null);
621 final AtomicBoolean complete = new AtomicBoolean(false);
622
623 lcon.withDeleteAndWrites(new ILuceneConnection.ReaderAction()
624 {
625 public Object perform(IndexReader reader)
626 {
627 secondUpdateFuture.set(
628 pool.submit(
629 new Runnable()
630 {
631 public void run()
632 {
633 latch.countDown();
634 lcon.withReaderAndDeletes(
635 new ILuceneConnection.ReaderAction()
636 {
637 public Object perform(IndexReader reader)
638 {
639 assertNotNull(reader);
640 assertTrue(complete.get());
641 return null;
642 }
643 }
644 );
645 }
646 }
647 )
648 );
649 try
650 {
651
652 latch.await();
653 }
654 catch (InterruptedException e)
655 {
656 throw new RuntimeException(e);
657 }
658 Thread.yield();
659 return null;
660 }
661 },
662 new ILuceneConnection.WriterAction()
663 {
664 public void perform(IndexWriter writer)
665 {
666 assertNotNull(writer);
667 assertEquals("Should be interactive mode maxMergeSettings", ILuceneConnection.DEFAULT_CONFIGURATION.getInteractiveMaxMergeDocs(), writer.getMaxMergeDocs());
668 assertEquals("Should be interactive mode maxBufferedSettings", ILuceneConnection.DEFAULT_CONFIGURATION.getInteractiveMaxBufferedDocs(), writer.getMaxBufferedDocs());
669 assertEquals("Should be interactive mode mergeFactorSettings", ILuceneConnection.DEFAULT_CONFIGURATION.getInteractiveMergeFactor(), writer.getMergeFactor());
670
671 Future future = ((Future) secondUpdateFuture.get());
672 assertFalse(future.isDone());
673 assertFalse(future.isCancelled());
674 complete.set(true);
675 }
676 }
677 );
678 assertTrue(complete.get());
679 Future future = ((Future) secondUpdateFuture.get());
680 assertNull(future.get());
681 assertTrue(future.isDone());
682 assertFalse(future.isCancelled());
683 }
684
685 public void testBatchUpdateHoldsLock() throws Exception
686 {
687 final CountDownLatch latch = new CountDownLatch(1);
688 final ExecutorService pool = Executors.newSingleThreadExecutor();
689 final AtomicReference secondUpdateFuture = new AtomicReference(null);
690
691 lcon.withBatchUpdate(new ILuceneConnection.BatchUpdateAction()
692 {
693 public void perform() throws Exception
694 {
695 secondUpdateFuture.set(
696 pool.submit(
697 new Runnable()
698 {
699 public void run()
700 {
701 latch.countDown();
702 lcon.withReaderAndDeletes(
703 new ILuceneConnection.ReaderAction()
704 {
705 public Object perform(IndexReader reader)
706 {
707 assertNotNull(reader);
708 return null;
709 }
710 }
711 );
712 }
713 }
714 )
715 );
716 latch.await();
717 Thread.yield();
718 lcon.withReaderAndDeletes(
719 new ILuceneConnection.ReaderAction()
720 {
721 public Object perform(IndexReader reader)
722 {
723 assertNotNull(reader);
724 return null;
725 }
726 }
727 );
728 lcon.withWriter(
729 new ILuceneConnection.WriterAction()
730 {
731 public void perform(IndexWriter writer)
732 {
733 assertNotNull(writer);
734 assertEquals("Should be batch mode maxMergeSettings", ILuceneConnection.DEFAULT_CONFIGURATION.getBatchMaxMergeDocs(), writer.getMaxMergeDocs());
735 assertEquals("Should be batch mode maxBufferedSettings", ILuceneConnection.DEFAULT_CONFIGURATION.getBatchMaxBufferedDocs(), writer.getMaxBufferedDocs());
736 assertEquals("Should be batch mode mergeFactorSettings", ILuceneConnection.DEFAULT_CONFIGURATION.getBatchMergeFactor(), writer.getMergeFactor());
737 assertEquals("Should be default maxField", ILuceneConnection.DEFAULT_CONFIGURATION.getMaxFieldLength(), writer.getMaxFieldLength());
738 }
739 }
740 );
741
742 Future future = ((Future) secondUpdateFuture.get());
743 assertFalse(future.isDone());
744 assertFalse(future.isCancelled());
745 }
746 });
747 Future future = ((Future) secondUpdateFuture.get());
748 assertNull(future.get());
749 assertTrue(future.isDone());
750 assertFalse(future.isCancelled());
751 }
752
753 public void testDeleterDoesNotBlockSearches()
754 {
755 addDocsToIndex(5);
756
757 final int noOfSearches = 1000;
758 final ExecutorService pool = Executors.newFixedThreadPool(4);
759 final CountDownLatch complete = new CountDownLatch(noOfSearches);
760 final AtomicReference readerRef = new AtomicReference(null);
761
762 lcon.withReader(
763 new ILuceneConnection.ReaderAction()
764 {
765 public Object perform(IndexReader reader)
766 {
767 readerRef.set(reader);
768 return null;
769 }
770 }
771 );
772
773
774 lcon.withReaderAndDeletes(new ILuceneConnection.ReaderAction()
775 {
776 public Object perform(final IndexReader reader)
777 {
778 for (int i = 0; i < noOfSearches; i++)
779 {
780
781
782 pool.submit(
783 new Runnable()
784 {
785 public void run()
786 {
787
788 lcon.withSearch(new ILuceneConnection.SearcherAction()
789 {
790 public void perform(IndexSearcher searcher)
791 {
792 assertTrue(readerRef.get() == searcher.getIndexReader());
793 }
794 });
795 lcon.withReader(new ILuceneConnection.ReaderAction()
796 {
797 public Object perform(IndexReader reader)
798 {
799 assertTrue(readerRef.get() == reader);
800 return null;
801 }
802 });
803
804 complete.countDown();
805 }
806 }
807 );
808 }
809
810
811
812 try
813 {
814 assertTrue("We waited too long, should have passed", complete.await(5, TimeUnit.SECONDS));
815 }
816 catch (InterruptedException e)
817 {
818 throw new AssertionError("We should not have to wait here, tasks should be reentrant: " + e);
819 }
820 return null;
821 }
822 });
823
824
825 lcon.withReader(
826 new ILuceneConnection.ReaderAction()
827 {
828 public Object perform(IndexReader reader)
829 {
830 assertFalse(readerRef.get() == reader);
831 return null;
832 }
833 }
834 );
835 }
836
837 public void testWriterDoesNotBlockSearches()
838 {
839 addDocsToIndex(5);
840
841 final int noOfSearches = 1000;
842 final ExecutorService pool = Executors.newFixedThreadPool(4);
843 final CountDownLatch complete = new CountDownLatch(noOfSearches);
844 final AtomicReference readerRef = new AtomicReference(null);
845
846 lcon.withReader(
847 new ILuceneConnection.ReaderAction()
848 {
849 public Object perform(IndexReader reader)
850 {
851 readerRef.set(reader);
852 return null;
853 }
854 }
855 );
856
857
858 lcon.withWriter(new ILuceneConnection.WriterAction()
859 {
860 public void perform(final IndexWriter writer)
861 {
862 for (int i = 0; i < noOfSearches; i++)
863 {
864
865
866 pool.submit(
867 new Runnable()
868 {
869 public void run()
870 {
871
872 lcon.withSearch(new ILuceneConnection.SearcherAction()
873 {
874 public void perform(IndexSearcher searcher)
875 {
876 assertTrue(readerRef.get() == searcher.getIndexReader());
877 }
878 });
879 lcon.withReader(new ILuceneConnection.ReaderAction()
880 {
881 public Object perform(IndexReader reader)
882 {
883 assertTrue(readerRef.get() == reader);
884 return null;
885 }
886 });
887
888 complete.countDown();
889 }
890 }
891 );
892 }
893
894
895
896 try
897 {
898 assertTrue("We waited too long, should have passed", complete.await(5, TimeUnit.SECONDS));
899 }
900 catch (InterruptedException e)
901 {
902 throw new AssertionError("We should not have to wait here, tasks should be reentrant: " + e);
903 }
904 }
905 });
906
907
908 lcon.withReader(
909 new ILuceneConnection.ReaderAction()
910 {
911 public Object perform(IndexReader reader)
912 {
913 assertFalse(readerRef.get() == reader);
914 return null;
915 }
916 }
917 );
918 }
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990 private Document createDocument()
991 {
992 Document d = new Document();
993 d.add(new Field(FIELD_NAME, FIELD_VALUE, Field.Store.YES, Field.Index.TOKENIZED));
994 return d;
995 }
996
997 private void addDocsToIndex(final int numDocs)
998 {
999 lcon.withWriter(new ILuceneConnection.WriterAction()
1000 {
1001 public void perform(IndexWriter writer) throws IOException
1002 {
1003 for (int i = 0; i < numDocs; ++i)
1004 {
1005 writer.addDocument(createDocument());
1006 }
1007 }
1008 });
1009 }
1010 }