1
package org.apache.lucene.index;
4
* Licensed to the Apache Software Foundation (ASF) under one or more
5
* contributor license agreements. See the NOTICE file distributed with
6
* this work for additional information regarding copyright ownership.
7
* The ASF licenses this file to You under the Apache License, Version 2.0
8
* (the "License"); you may not use this file except in compliance with
9
* the License. You may obtain a copy of the License at
11
* http://www.apache.org/licenses/LICENSE-2.0
13
* Unless required by applicable law or agreed to in writing, software
14
* distributed under the License is distributed on an "AS IS" BASIS,
15
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
* See the License for the specific language governing permissions and
17
* limitations under the License.
21
import java.io.IOException;
22
import java.util.ArrayList;
23
import java.util.Collection;
24
import java.util.Collections;
25
import java.util.HashMap;
26
import java.util.HashSet;
27
import java.util.List;
29
import java.util.Random;
32
import org.apache.lucene.analysis.MockAnalyzer;
33
import org.apache.lucene.document.Document;
34
import org.apache.lucene.document.Field.Index;
35
import org.apache.lucene.document.Field.Store;
36
import org.apache.lucene.document.Field;
37
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
38
import org.apache.lucene.search.FieldCache;
39
import org.apache.lucene.search.IndexSearcher;
40
import org.apache.lucene.search.ScoreDoc;
41
import org.apache.lucene.search.TermQuery;
42
import org.apache.lucene.store.AlreadyClosedException;
43
import org.apache.lucene.store.Directory;
44
import org.apache.lucene.util.BitVector;
45
import org.apache.lucene.util.LuceneTestCase;
46
import org.apache.lucene.util._TestUtil;
48
public class TestIndexReaderReopen extends LuceneTestCase {
50
public void testReopen() throws Exception {
51
final Directory dir1 = newDirectory();
53
createIndex(random, dir1, false);
54
performDefaultTests(new TestReopen() {
57
protected void modifyIndex(int i) throws IOException {
58
TestIndexReaderReopen.modifyIndex(i, dir1);
62
protected IndexReader openReader() throws IOException {
63
return IndexReader.open(dir1, false);
69
final Directory dir2 = newDirectory();
71
createIndex(random, dir2, true);
72
performDefaultTests(new TestReopen() {
75
protected void modifyIndex(int i) throws IOException {
76
TestIndexReaderReopen.modifyIndex(i, dir2);
80
protected IndexReader openReader() throws IOException {
81
return IndexReader.open(dir2, false);
88
public void testParallelReaderReopen() throws Exception {
89
final Directory dir1 = newDirectory();
90
createIndex(random, dir1, true);
91
final Directory dir2 = newDirectory();
92
createIndex(random, dir2, true);
94
performDefaultTests(new TestReopen() {
97
protected void modifyIndex(int i) throws IOException {
98
TestIndexReaderReopen.modifyIndex(i, dir1);
99
TestIndexReaderReopen.modifyIndex(i, dir2);
103
protected IndexReader openReader() throws IOException {
104
ParallelReader pr = new ParallelReader();
105
pr.add(IndexReader.open(dir1, false));
106
pr.add(IndexReader.open(dir2, false));
114
final Directory dir3 = newDirectory();
115
createIndex(random, dir3, true);
116
final Directory dir4 = newDirectory();
117
createIndex(random, dir4, true);
119
performTestsWithExceptionInReopen(new TestReopen() {
122
protected void modifyIndex(int i) throws IOException {
123
TestIndexReaderReopen.modifyIndex(i, dir3);
124
TestIndexReaderReopen.modifyIndex(i, dir4);
128
protected IndexReader openReader() throws IOException {
129
ParallelReader pr = new ParallelReader();
130
pr.add(IndexReader.open(dir3, false));
131
pr.add(IndexReader.open(dir4, false));
132
// Does not implement reopen, so
134
pr.add(new FilterIndexReader(IndexReader.open(dir3, false)));
143
// LUCENE-1228: IndexWriter.commit() does not update the index version
144
// populate an index in iterations.
145
// at the end of every iteration, commit the index and reopen/recreate the reader.
146
// in each iteration verify the work of previous iteration.
147
// try this once with reopen once recreate, on both RAMDir and FSDir.
148
public void testCommitReopen () throws IOException {
149
Directory dir = newDirectory();
150
doTestReopenWithCommit(random, dir, true);
153
public void testCommitRecreate () throws IOException {
154
Directory dir = newDirectory();
155
doTestReopenWithCommit(random, dir, false);
159
private void doTestReopenWithCommit (Random random, Directory dir, boolean withReopen) throws IOException {
160
IndexWriter iwriter = new IndexWriter(dir, newIndexWriterConfig(
161
TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(
162
OpenMode.CREATE).setMergeScheduler(new SerialMergeScheduler()).setMergePolicy(newLogMergePolicy()));
164
IndexReader reader = IndexReader.open(dir, false);
167
for (int i=0; i<4; i++) {
168
for (int j=0; j<M; j++) {
169
Document doc = new Document();
170
doc.add(newField("id", i+"_"+j, Store.YES, Index.NOT_ANALYZED));
171
doc.add(newField("id2", i+"_"+j, Store.YES, Index.NOT_ANALYZED_NO_NORMS));
172
doc.add(newField("id3", i+"_"+j, Store.YES, Index.NO));
173
iwriter.addDocument(doc);
177
Document prevItereationDoc = reader.document(n);
178
assertNotNull(prevItereationDoc);
179
String id = prevItereationDoc.get("id");
180
assertEquals(k+"_"+j, id);
186
IndexReader r2 = reader.reopen();
194
reader = IndexReader.open(dir, false);
203
public void testMultiReaderReopen() throws Exception {
204
final Directory dir1 = newDirectory();
205
createIndex(random, dir1, true);
207
final Directory dir2 = newDirectory();
208
createIndex(random, dir2, true);
210
performDefaultTests(new TestReopen() {
213
protected void modifyIndex(int i) throws IOException {
214
TestIndexReaderReopen.modifyIndex(i, dir1);
215
TestIndexReaderReopen.modifyIndex(i, dir2);
219
protected IndexReader openReader() throws IOException {
220
return new MultiReader(new IndexReader[]
221
{IndexReader.open(dir1, false),
222
IndexReader.open(dir2, false)});
230
final Directory dir3 = newDirectory();
231
createIndex(random, dir3, true);
233
final Directory dir4 = newDirectory();
234
createIndex(random, dir4, true);
236
performTestsWithExceptionInReopen(new TestReopen() {
239
protected void modifyIndex(int i) throws IOException {
240
TestIndexReaderReopen.modifyIndex(i, dir3);
241
TestIndexReaderReopen.modifyIndex(i, dir4);
245
protected IndexReader openReader() throws IOException {
246
return new MultiReader(new IndexReader[]
247
{IndexReader.open(dir3, false),
248
IndexReader.open(dir4, false),
249
// Does not implement reopen, so
251
new FilterIndexReader(IndexReader.open(dir3, false))});
259
public void testMixedReaders() throws Exception {
260
final Directory dir1 = newDirectory();
261
createIndex(random, dir1, true);
262
final Directory dir2 = newDirectory();
263
createIndex(random, dir2, true);
264
final Directory dir3 = newDirectory();
265
createIndex(random, dir3, false);
266
final Directory dir4 = newDirectory();
267
createIndex(random, dir4, true);
268
final Directory dir5 = newDirectory();
269
createIndex(random, dir5, false);
271
performDefaultTests(new TestReopen() {
274
protected void modifyIndex(int i) throws IOException {
275
// only change norms in this index to maintain the same number of docs for each of ParallelReader's subreaders
276
if (i == 1) TestIndexReaderReopen.modifyIndex(i, dir1);
278
TestIndexReaderReopen.modifyIndex(i, dir4);
279
TestIndexReaderReopen.modifyIndex(i, dir5);
283
protected IndexReader openReader() throws IOException {
284
ParallelReader pr = new ParallelReader();
285
pr.add(IndexReader.open(dir1, false));
286
pr.add(IndexReader.open(dir2, false));
287
MultiReader mr = new MultiReader(new IndexReader[] {
288
IndexReader.open(dir3, false), IndexReader.open(dir4, false)});
289
return new MultiReader(new IndexReader[] {
290
pr, mr, IndexReader.open(dir5, false)});
300
private void performDefaultTests(TestReopen test) throws Exception {
302
IndexReader index1 = test.openReader();
303
IndexReader index2 = test.openReader();
305
TestIndexReader.assertIndexEquals(index1, index2);
307
// verify that reopen() does not return a new reader instance
308
// in case the index has no changes
309
ReaderCouple couple = refreshReader(index2, false);
310
assertTrue(couple.refreshedReader == index2);
312
couple = refreshReader(index2, test, 0, true);
314
index1 = couple.newReader;
316
IndexReader index2_refreshed = couple.refreshedReader;
319
// test if refreshed reader and newly opened reader return equal results
320
TestIndexReader.assertIndexEquals(index1, index2_refreshed);
322
index2_refreshed.close();
323
assertReaderClosed(index2, true, true);
324
assertReaderClosed(index2_refreshed, true, true);
326
index2 = test.openReader();
328
for (int i = 1; i < 4; i++) {
331
couple = refreshReader(index2, test, i, true);
332
// refresh IndexReader
335
index2 = couple.refreshedReader;
336
index1 = couple.newReader;
337
TestIndexReader.assertIndexEquals(index1, index2);
342
assertReaderClosed(index1, true, true);
343
assertReaderClosed(index2, true, true);
346
public void testReferenceCounting() throws IOException {
347
for (int mode = 0; mode < 4; mode++) {
348
Directory dir1 = newDirectory();
349
createIndex(random, dir1, true);
351
IndexReader reader0 = IndexReader.open(dir1, false);
352
assertRefCountEquals(1, reader0);
354
assertTrue(reader0 instanceof DirectoryReader);
355
IndexReader[] subReaders0 = reader0.getSequentialSubReaders();
356
for (int i = 0; i < subReaders0.length; i++) {
357
assertRefCountEquals(1, subReaders0[i]);
360
// delete first document, so that only one of the subReaders have to be re-opened
361
IndexReader modifier = IndexReader.open(dir1, false);
362
modifier.deleteDocument(0);
365
IndexReader reader1 = refreshReader(reader0, true).refreshedReader;
366
assertTrue(reader1 instanceof DirectoryReader);
367
IndexReader[] subReaders1 = reader1.getSequentialSubReaders();
368
assertEquals(subReaders0.length, subReaders1.length);
370
for (int i = 0; i < subReaders0.length; i++) {
371
if (subReaders0[i] != subReaders1[i]) {
372
assertRefCountEquals(1, subReaders0[i]);
373
assertRefCountEquals(1, subReaders1[i]);
375
assertRefCountEquals(2, subReaders0[i]);
379
// delete first document, so that only one of the subReaders have to be re-opened
380
modifier = IndexReader.open(dir1, false);
381
modifier.deleteDocument(1);
384
IndexReader reader2 = refreshReader(reader1, true).refreshedReader;
385
assertTrue(reader2 instanceof DirectoryReader);
386
IndexReader[] subReaders2 = reader2.getSequentialSubReaders();
387
assertEquals(subReaders1.length, subReaders2.length);
389
for (int i = 0; i < subReaders2.length; i++) {
390
if (subReaders2[i] == subReaders1[i]) {
391
if (subReaders1[i] == subReaders0[i]) {
392
assertRefCountEquals(3, subReaders2[i]);
394
assertRefCountEquals(2, subReaders2[i]);
397
assertRefCountEquals(1, subReaders2[i]);
398
if (subReaders0[i] == subReaders1[i]) {
399
assertRefCountEquals(2, subReaders2[i]);
400
assertRefCountEquals(2, subReaders0[i]);
402
assertRefCountEquals(1, subReaders0[i]);
403
assertRefCountEquals(1, subReaders1[i]);
408
IndexReader reader3 = refreshReader(reader0, true).refreshedReader;
409
assertTrue(reader3 instanceof DirectoryReader);
410
IndexReader[] subReaders3 = reader3.getSequentialSubReaders();
411
assertEquals(subReaders3.length, subReaders0.length);
413
// try some permutations
441
assertReaderClosed(reader0, true, true);
442
assertReaderClosed(reader1, true, true);
443
assertReaderClosed(reader2, true, true);
444
assertReaderClosed(reader3, true, true);
451
public void testReferenceCountingMultiReader() throws IOException {
452
for (int mode = 0; mode <=1; mode++) {
453
Directory dir1 = newDirectory();
454
createIndex(random, dir1, false);
455
Directory dir2 = newDirectory();
456
createIndex(random, dir2, true);
458
IndexReader reader1 = IndexReader.open(dir1, false);
459
assertRefCountEquals(1, reader1);
461
IndexReader initReader2 = IndexReader.open(dir2, false);
462
IndexReader multiReader1 = new MultiReader(new IndexReader[] {reader1, initReader2}, (mode == 0));
463
modifyIndex(0, dir2);
464
assertRefCountEquals(1 + mode, reader1);
466
IndexReader multiReader2 = multiReader1.reopen();
467
// index1 hasn't changed, so multiReader2 should share reader1 now with multiReader1
468
assertRefCountEquals(2 + mode, reader1);
470
modifyIndex(0, dir1);
471
IndexReader reader2 = reader1.reopen();
472
assertRefCountEquals(2 + mode, reader1);
478
modifyIndex(1, dir1);
479
IndexReader reader3 = reader2.reopen();
480
assertRefCountEquals(2 + mode, reader1);
481
assertRefCountEquals(1, reader2);
483
multiReader1.close();
484
assertRefCountEquals(1 + mode, reader1);
486
multiReader1.close();
487
assertRefCountEquals(1 + mode, reader1);
494
assertRefCountEquals(1, reader1);
496
multiReader2.close();
497
assertRefCountEquals(0, reader1);
499
multiReader2.close();
500
assertRefCountEquals(0, reader1);
503
assertRefCountEquals(0, reader1);
504
assertReaderClosed(reader1, true, false);
507
assertRefCountEquals(0, reader1);
508
assertReaderClosed(reader1, true, false);
511
assertRefCountEquals(0, reader1);
514
assertRefCountEquals(0, reader1);
515
assertReaderClosed(reader1, true, true);
522
public void testReferenceCountingParallelReader() throws IOException {
523
for (int mode = 0; mode <=1; mode++) {
524
Directory dir1 = newDirectory();
525
createIndex(random, dir1, false);
526
Directory dir2 = newDirectory();
527
createIndex(random, dir2, true);
529
IndexReader reader1 = IndexReader.open(dir1, false);
530
assertRefCountEquals(1, reader1);
532
ParallelReader parallelReader1 = new ParallelReader(mode == 0);
533
parallelReader1.add(reader1);
534
IndexReader initReader2 = IndexReader.open(dir2, false);
535
parallelReader1.add(initReader2);
536
modifyIndex(1, dir2);
537
assertRefCountEquals(1 + mode, reader1);
539
IndexReader parallelReader2 = parallelReader1.reopen();
540
// index1 hasn't changed, so parallelReader2 should share reader1 now with multiReader1
541
assertRefCountEquals(2 + mode, reader1);
543
modifyIndex(0, dir1);
544
modifyIndex(0, dir2);
545
IndexReader reader2 = reader1.reopen();
546
assertRefCountEquals(2 + mode, reader1);
552
modifyIndex(4, dir1);
553
IndexReader reader3 = reader2.reopen();
554
assertRefCountEquals(2 + mode, reader1);
555
assertRefCountEquals(1, reader2);
557
parallelReader1.close();
558
assertRefCountEquals(1 + mode, reader1);
560
parallelReader1.close();
561
assertRefCountEquals(1 + mode, reader1);
568
assertRefCountEquals(1, reader1);
570
parallelReader2.close();
571
assertRefCountEquals(0, reader1);
573
parallelReader2.close();
574
assertRefCountEquals(0, reader1);
577
assertRefCountEquals(0, reader1);
578
assertReaderClosed(reader1, true, false);
581
assertRefCountEquals(0, reader1);
582
assertReaderClosed(reader1, true, false);
585
assertRefCountEquals(0, reader1);
588
assertRefCountEquals(0, reader1);
589
assertReaderClosed(reader1, true, true);
597
public void testNormsRefCounting() throws IOException {
598
Directory dir1 = newDirectory();
599
createIndex(random, dir1, false);
601
IndexReader reader1 = IndexReader.open(dir1, false);
602
SegmentReader segmentReader1 = SegmentReader.getOnlySegmentReader(reader1);
603
IndexReader modifier = IndexReader.open(dir1, false);
604
modifier.deleteDocument(0);
607
IndexReader reader2 = reader1.reopen();
608
modifier = IndexReader.open(dir1, false);
609
modifier.setNorm(1, "field1", 50);
610
modifier.setNorm(1, "field2", 50);
613
IndexReader reader3 = reader2.reopen();
614
SegmentReader segmentReader3 = SegmentReader.getOnlySegmentReader(reader3);
615
modifier = IndexReader.open(dir1, false);
616
modifier.deleteDocument(2);
619
IndexReader reader4 = reader3.reopen();
620
modifier = IndexReader.open(dir1, false);
621
modifier.deleteDocument(3);
624
IndexReader reader5 = reader3.reopen();
626
// Now reader2-reader5 references reader1. reader1 and reader2
627
// share the same norms. reader3, reader4, reader5 also share norms.
628
assertRefCountEquals(1, reader1);
629
assertFalse(segmentReader1.normsClosed());
633
assertRefCountEquals(0, reader1);
634
assertFalse(segmentReader1.normsClosed());
637
assertRefCountEquals(0, reader1);
639
// now the norms for field1 and field2 should be closed
640
assertTrue(segmentReader1.normsClosed("field1"));
641
assertTrue(segmentReader1.normsClosed("field2"));
643
// but the norms for field3 and field4 should still be open
644
assertFalse(segmentReader1.normsClosed("field3"));
645
assertFalse(segmentReader1.normsClosed("field4"));
648
assertRefCountEquals(0, reader1);
649
assertFalse(segmentReader3.normsClosed());
651
assertRefCountEquals(0, reader1);
652
assertFalse(segmentReader3.normsClosed());
654
assertRefCountEquals(0, reader1);
656
// and now all norms that reader1 used should be closed
657
assertTrue(segmentReader1.normsClosed());
659
// now that reader3, reader4 and reader5 are closed,
660
// the norms that those three readers shared should be
662
assertTrue(segmentReader3.normsClosed());
667
private void performTestsWithExceptionInReopen(TestReopen test) throws Exception {
668
IndexReader index1 = test.openReader();
669
IndexReader index2 = test.openReader();
671
TestIndexReader.assertIndexEquals(index1, index2);
674
refreshReader(index1, test, 0, true);
675
fail("Expected exception not thrown.");
676
} catch (Exception e) {
677
// expected exception
680
// index2 should still be usable and unaffected by the failed reopen() call
681
TestIndexReader.assertIndexEquals(index1, index2);
687
public void testThreadSafety() throws Exception {
688
final Directory dir = newDirectory();
689
// NOTE: this also controls the number of threads!
690
final int n = _TestUtil.nextInt(random, 20, 40);
691
IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
692
TEST_VERSION_CURRENT, new MockAnalyzer(random)));
693
for (int i = 0; i < n; i++) {
694
writer.addDocument(createDocument(i, 3));
699
final TestReopen test = new TestReopen() {
701
protected void modifyIndex(int i) throws IOException {
703
IndexReader modifier = IndexReader.open(dir, false);
704
modifier.setNorm(i, "field1", 50);
706
} else if (i % 3 == 1) {
707
IndexReader modifier = IndexReader.open(dir, false);
708
modifier.deleteDocument(i % modifier.maxDoc());
711
IndexWriter modifier = new IndexWriter(dir, new IndexWriterConfig(
712
TEST_VERSION_CURRENT, new MockAnalyzer(random)));
713
modifier.addDocument(createDocument(n + i, 6));
719
protected IndexReader openReader() throws IOException {
720
return IndexReader.open(dir, false);
724
final List<ReaderCouple> readers = Collections.synchronizedList(new ArrayList<ReaderCouple>());
725
IndexReader firstReader = IndexReader.open(dir, false);
726
IndexReader reader = firstReader;
727
final Random rnd = random;
729
ReaderThread[] threads = new ReaderThread[n];
730
final Set<IndexReader> readersToClose = Collections.synchronizedSet(new HashSet<IndexReader>());
732
for (int i = 0; i < n; i++) {
734
IndexReader refreshed = reader.reopen();
735
if (refreshed != reader) {
736
readersToClose.add(reader);
740
final IndexReader r = reader;
744
ReaderThreadTask task;
746
if (i < 4 || (i >=10 && i < 14) || i > 18) {
747
task = new ReaderThreadTask() {
750
public void run() throws Exception {
752
if (index % 2 == 0) {
753
// refresh reader synchronized
754
ReaderCouple c = (refreshReader(r, test, index, true));
755
readersToClose.add(c.newReader);
756
readersToClose.add(c.refreshedReader);
758
// prevent too many readers
762
IndexReader refreshed = r.reopen();
764
IndexSearcher searcher = newSearcher(refreshed);
765
ScoreDoc[] hits = searcher.search(
766
new TermQuery(new Term("field1", "a" + rnd.nextInt(refreshed.maxDoc()))),
767
null, 1000).scoreDocs;
768
if (hits.length > 0) {
769
searcher.doc(hits[0].doc);
772
if (refreshed != r) {
777
wait(_TestUtil.nextInt(random, 1, 100));
784
task = new ReaderThreadTask() {
786
public void run() throws Exception {
788
int numReaders = readers.size();
789
if (numReaders > 0) {
790
ReaderCouple c = readers.get(rnd.nextInt(numReaders));
791
TestIndexReader.assertIndexEquals(c.newReader, c.refreshedReader);
795
wait(_TestUtil.nextInt(random, 1, 100));
802
threads[i] = new ReaderThread(task);
810
for (int i = 0; i < n; i++) {
811
if (threads[i] != null) {
812
threads[i].stopThread();
816
for (int i = 0; i < n; i++) {
817
if (threads[i] != null) {
819
if (threads[i].error != null) {
820
String msg = "Error occurred in thread " + threads[i].getName() + ":\n" + threads[i].error.getMessage();
827
for (final IndexReader readerToClose : readersToClose) {
828
readerToClose.close();
834
for (final IndexReader readerToClose : readersToClose) {
835
assertReaderClosed(readerToClose, true, true);
838
assertReaderClosed(reader, true, true);
839
assertReaderClosed(firstReader, true, true);
844
private static class ReaderCouple {
845
ReaderCouple(IndexReader r1, IndexReader r2) {
847
refreshedReader = r2;
850
IndexReader newReader;
851
IndexReader refreshedReader;
854
private abstract static class ReaderThreadTask {
855
protected volatile boolean stopped;
860
public abstract void run() throws Exception;
863
private static class ReaderThread extends Thread {
864
private ReaderThreadTask task;
865
private Throwable error;
868
ReaderThread(ReaderThreadTask task) {
872
public void stopThread() {
880
} catch (Throwable r) {
881
r.printStackTrace(System.out);
887
private Object createReaderMutex = new Object();
889
private ReaderCouple refreshReader(IndexReader reader, boolean hasChanges) throws IOException {
890
return refreshReader(reader, null, -1, hasChanges);
893
ReaderCouple refreshReader(IndexReader reader, TestReopen test, int modify, boolean hasChanges) throws IOException {
894
synchronized (createReaderMutex) {
895
IndexReader r = null;
897
test.modifyIndex(modify);
898
r = test.openReader();
901
IndexReader refreshed = null;
903
refreshed = reader.reopen();
905
if (refreshed == null && r != null) {
906
// Hit exception -- close opened reader
912
if (refreshed == reader) {
913
fail("No new IndexReader instance created during refresh.");
916
if (refreshed != reader) {
917
fail("New IndexReader instance created during refresh even though index had no changes.");
921
return new ReaderCouple(r, refreshed);
925
public static void createIndex(Random random, Directory dir, boolean multiSegment) throws IOException {
926
IndexWriter.unlock(dir);
927
IndexWriter w = new IndexWriter(dir, LuceneTestCase.newIndexWriterConfig(random,
928
TEST_VERSION_CURRENT, new MockAnalyzer(random))
929
.setMergePolicy(new LogDocMergePolicy()));
931
for (int i = 0; i < 100; i++) {
932
w.addDocument(createDocument(i, 4));
933
if (multiSegment && (i % 10) == 0) {
944
IndexReader r = IndexReader.open(dir, false);
946
assertTrue(r.getSequentialSubReaders().length > 1);
948
assertTrue(r.getSequentialSubReaders().length == 1);
953
public static Document createDocument(int n, int numFields) {
954
StringBuilder sb = new StringBuilder();
955
Document doc = new Document();
958
doc.add(new Field("field1", sb.toString(), Store.YES, Index.ANALYZED));
959
doc.add(new Field("fielda", sb.toString(), Store.YES, Index.NOT_ANALYZED_NO_NORMS));
960
doc.add(new Field("fieldb", sb.toString(), Store.YES, Index.NO));
963
for (int i = 1; i < numFields; i++) {
964
doc.add(new Field("field" + (i+1), sb.toString(), Store.YES, Index.ANALYZED));
969
static void modifyIndex(int i, Directory dir) throws IOException {
973
System.out.println("TEST: modify index");
975
IndexWriter w = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
976
w.setInfoStream(VERBOSE ? System.out : null);
977
w.deleteDocuments(new Term("field2", "a11"));
978
w.deleteDocuments(new Term("field2", "b30"));
983
IndexReader reader = IndexReader.open(dir, false);
984
reader.setNorm(4, "field1", 123);
985
reader.setNorm(44, "field2", 222);
986
reader.setNorm(44, "field4", 22);
991
IndexWriter w = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
997
IndexWriter w = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
998
w.addDocument(createDocument(101, 4));
1000
w.addDocument(createDocument(102, 4));
1001
w.addDocument(createDocument(103, 4));
1006
IndexReader reader = IndexReader.open(dir, false);
1007
reader.setNorm(5, "field1", 123);
1008
reader.setNorm(55, "field2", 222);
1013
IndexWriter w = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
1014
w.addDocument(createDocument(101, 4));
1021
private void assertReaderClosed(IndexReader reader, boolean checkSubReaders, boolean checkNormsClosed) {
1022
assertEquals(0, reader.getRefCount());
1024
if (checkNormsClosed && reader instanceof SegmentReader) {
1025
assertTrue(((SegmentReader) reader).normsClosed());
1028
if (checkSubReaders) {
1029
if (reader instanceof DirectoryReader) {
1030
IndexReader[] subReaders = reader.getSequentialSubReaders();
1031
for (int i = 0; i < subReaders.length; i++) {
1032
assertReaderClosed(subReaders[i], checkSubReaders, checkNormsClosed);
1036
if (reader instanceof MultiReader) {
1037
IndexReader[] subReaders = reader.getSequentialSubReaders();
1038
for (int i = 0; i < subReaders.length; i++) {
1039
assertReaderClosed(subReaders[i], checkSubReaders, checkNormsClosed);
1043
if (reader instanceof ParallelReader) {
1044
IndexReader[] subReaders = ((ParallelReader) reader).getSubReaders();
1045
for (int i = 0; i < subReaders.length; i++) {
1046
assertReaderClosed(subReaders[i], checkSubReaders, checkNormsClosed);
1053
private void assertReaderOpen(IndexReader reader) {
1054
reader.ensureOpen();
1056
if (reader instanceof DirectoryReader) {
1057
IndexReader[] subReaders = reader.getSequentialSubReaders();
1058
for (int i = 0; i < subReaders.length; i++) {
1059
assertReaderOpen(subReaders[i]);
1065
private void assertRefCountEquals(int refCount, IndexReader reader) {
1066
assertEquals("Reader has wrong refCount value.", refCount, reader.getRefCount());
1070
private abstract static class TestReopen {
1071
protected abstract IndexReader openReader() throws IOException;
1072
protected abstract void modifyIndex(int i) throws IOException;
1075
public void testCloseOrig() throws Throwable {
1076
Directory dir = newDirectory();
1077
createIndex(random, dir, false);
1078
IndexReader r1 = IndexReader.open(dir, false);
1079
IndexReader r2 = IndexReader.open(dir, false);
1080
r2.deleteDocument(0);
1083
IndexReader r3 = r1.reopen();
1084
assertTrue(r1 != r3);
1088
fail("did not hit exception");
1089
} catch (AlreadyClosedException ace) {
1096
public void testDeletes() throws Throwable {
1097
Directory dir = newDirectory();
1098
createIndex(random, dir, false); // Create an index with a bunch of docs (1 segment)
1100
modifyIndex(0, dir); // Get delete bitVector on 1st segment
1101
modifyIndex(5, dir); // Add a doc (2 segments)
1103
IndexReader r1 = IndexReader.open(dir, false); // MSR
1105
modifyIndex(5, dir); // Add another doc (3 segments)
1107
IndexReader r2 = r1.reopen(); // MSR
1108
assertTrue(r1 != r2);
1110
SegmentReader sr1 = (SegmentReader) r1.getSequentialSubReaders()[0]; // Get SRs for the first segment from original
1111
SegmentReader sr2 = (SegmentReader) r2.getSequentialSubReaders()[0]; // and reopened IRs
1113
// At this point they share the same BitVector
1114
assertTrue(sr1.deletedDocs==sr2.deletedDocs);
1116
r2.deleteDocument(0);
1118
// r1 should not see the delete
1119
assertFalse(r1.isDeleted(0));
1121
// Now r2 should have made a private copy of deleted docs:
1122
assertTrue(sr1.deletedDocs!=sr2.deletedDocs);
1129
public void testDeletes2() throws Throwable {
1130
Directory dir = newDirectory();
1131
createIndex(random, dir, false);
1132
// Get delete bitVector
1133
modifyIndex(0, dir);
1134
IndexReader r1 = IndexReader.open(dir, false);
1137
modifyIndex(5, dir);
1139
IndexReader r2 = r1.reopen();
1140
assertTrue(r1 != r2);
1142
IndexReader[] rs2 = r2.getSequentialSubReaders();
1144
SegmentReader sr1 = SegmentReader.getOnlySegmentReader(r1);
1145
SegmentReader sr2 = (SegmentReader) rs2[0];
1147
// At this point they share the same BitVector
1148
assertTrue(sr1.deletedDocs==sr2.deletedDocs);
1149
final BitVector delDocs = sr1.deletedDocs;
1152
r2.deleteDocument(0);
1153
assertTrue(delDocs==sr2.deletedDocs);
1158
private static class KeepAllCommits implements IndexDeletionPolicy {
1159
public void onInit(List<? extends IndexCommit> commits) {
1161
public void onCommit(List<? extends IndexCommit> commits) {
1165
public void testReopenOnCommit() throws Throwable {
1166
Directory dir = newDirectory();
1167
IndexWriter writer = new IndexWriter(
1169
newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).
1170
setIndexDeletionPolicy(new KeepAllCommits()).
1171
setMaxBufferedDocs(-1).
1172
setMergePolicy(newLogMergePolicy(10))
1174
for(int i=0;i<4;i++) {
1175
Document doc = new Document();
1176
doc.add(newField("id", ""+i, Field.Store.NO, Field.Index.NOT_ANALYZED));
1177
writer.addDocument(doc);
1178
Map<String,String> data = new HashMap<String,String>();
1179
data.put("index", i+"");
1180
writer.commit(data);
1182
for(int i=0;i<4;i++) {
1183
writer.deleteDocuments(new Term("id", ""+i));
1184
Map<String,String> data = new HashMap<String,String>();
1185
data.put("index", (4+i)+"");
1186
writer.commit(data);
1190
IndexReader r = IndexReader.open(dir, false);
1191
assertEquals(0, r.numDocs());
1193
Collection<IndexCommit> commits = IndexReader.listCommits(dir);
1194
for (final IndexCommit commit : commits) {
1195
IndexReader r2 = r.reopen(commit);
1196
assertTrue(r2 != r);
1198
// Reader should be readOnly
1200
r2.deleteDocument(0);
1201
fail("no exception hit");
1202
} catch (UnsupportedOperationException uoe) {
1206
final Map<String,String> s = commit.getUserData();
1208
if (s.size() == 0) {
1209
// First commit created by IW
1212
v = Integer.parseInt(s.get("index"));
1215
assertEquals(1+v, r2.numDocs());
1217
assertEquals(7-v, r2.numDocs());
1226
// LUCENE-1579: Make sure all SegmentReaders are new when
1227
// reopen switches readOnly
1228
public void testReopenChangeReadonly() throws Exception {
1229
Directory dir = newDirectory();
1230
IndexWriter writer = new IndexWriter(
1232
newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).
1233
setMaxBufferedDocs(-1).
1234
setMergePolicy(newLogMergePolicy(10))
1236
Document doc = new Document();
1237
doc.add(newField("number", "17", Field.Store.NO, Field.Index.NOT_ANALYZED));
1238
writer.addDocument(doc);
1242
IndexReader r = IndexReader.open(dir, false);
1243
assertTrue(r instanceof DirectoryReader);
1244
IndexReader r1 = SegmentReader.getOnlySegmentReader(r);
1245
final int[] ints = FieldCache.DEFAULT.getInts(r1, "number");
1246
assertEquals(1, ints.length);
1247
assertEquals(17, ints[0]);
1249
// Reopen to readonly w/ no chnages
1250
IndexReader r3 = r.reopen(true);
1251
assertTrue(r3 instanceof ReadOnlyDirectoryReader);
1255
writer.addDocument(doc);
1258
// Reopen reader1 --> reader2
1259
IndexReader r2 = r.reopen(true);
1261
assertTrue(r2 instanceof ReadOnlyDirectoryReader);
1262
IndexReader[] subs = r2.getSequentialSubReaders();
1263
final int[] ints2 = FieldCache.DEFAULT.getInts(subs[0], "number");
1266
assertTrue(subs[0] instanceof ReadOnlySegmentReader);
1267
assertTrue(subs[1] instanceof ReadOnlySegmentReader);
1268
assertTrue(ints == ints2);