blob: c1969138cb1d9e3fc7b9fb0e7837231891e3869f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.index;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
public class TestIndexWriterFromReader extends LuceneTestCase {
// Pull NRT reader immediately after writer has committed
public void testRightAfterCommit() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());
w.commit();
DirectoryReader r = DirectoryReader.open(w);
assertEquals(1, r.maxDoc());
w.close();
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(r.getIndexCommit());
IndexWriter w2 = new IndexWriter(dir, iwc);
r.close();
assertEquals(1, w2.getDocStats().maxDoc);
w2.addDocument(new Document());
assertEquals(2, w2.getDocStats().maxDoc);
w2.close();
IndexReader r2 = DirectoryReader.open(dir);
assertEquals(2, r2.maxDoc());
r2.close();
dir.close();
}
// Open from non-NRT reader
public void testFromNonNRTReader() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());
w.close();
DirectoryReader r = DirectoryReader.open(dir);
assertEquals(1, r.maxDoc());
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(r.getIndexCommit());
IndexWriter w2 = new IndexWriter(dir, iwc);
assertEquals(1, r.maxDoc());
r.close();
assertEquals(1, w2.getDocStats().maxDoc);
w2.addDocument(new Document());
assertEquals(2, w2.getDocStats().maxDoc);
w2.close();
IndexReader r2 = DirectoryReader.open(dir);
assertEquals(2, r2.maxDoc());
r2.close();
dir.close();
}
// Pull NRT reader from a writer on a new index with no commit:
public void testWithNoFirstCommit() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());
DirectoryReader r = DirectoryReader.open(w);
w.rollback();
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(r.getIndexCommit());
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new IndexWriter(dir, iwc);
});
assertEquals("cannot use IndexWriterConfig.setIndexCommit() when index has no commit", expected.getMessage());
r.close();
dir.close();
}
// Pull NRT reader after writer has committed and then indexed another doc:
public void testAfterCommitThenIndex() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());
w.commit();
w.addDocument(new Document());
DirectoryReader r = DirectoryReader.open(w);
assertEquals(2, r.maxDoc());
w.close();
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(r.getIndexCommit());
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new IndexWriter(dir, iwc);
});
assertTrue(expected.getMessage().contains("the provided reader is stale: its prior commit file"));
r.close();
dir.close();
}
// NRT rollback: pull NRT reader after writer has committed and then before indexing another doc
public void testNRTRollback() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());
w.commit();
DirectoryReader r = DirectoryReader.open(w);
assertEquals(1, r.maxDoc());
// Add another doc
w.addDocument(new Document());
assertEquals(2, w.getDocStats().maxDoc);
w.close();
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(r.getIndexCommit());
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new IndexWriter(dir, iwc);
});
assertTrue(expected.getMessage().contains("the provided reader is stale: its prior commit file"));
r.close();
dir.close();
}
public void testRandom() throws Exception {
Directory dir = newDirectory();
int numOps = atLeast(100);
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
// We must have a starting commit for this test because whenever we rollback with
// an NRT reader, the commit before that NRT reader must exist
w.commit();
DirectoryReader r = DirectoryReader.open(w);
int nrtReaderNumDocs = 0;
int writerNumDocs = 0;
boolean commitAfterNRT = false;
Set<Integer> liveIDs = new HashSet<>();
Set<Integer> nrtLiveIDs = new HashSet<>();
for(int op=0;op<numOps;op++) {
if (VERBOSE) {
System.out.println("\nITER op=" + op + " nrtReaderNumDocs=" + nrtReaderNumDocs + " writerNumDocs=" + writerNumDocs + " r=" + r + " r.numDocs()=" + r.numDocs());
}
assertEquals(nrtReaderNumDocs, r.numDocs());
int x = random().nextInt(5);
switch(x) {
case 0:
if (VERBOSE) {
System.out.println(" add doc id=" + op);
}
// add doc
Document doc = new Document();
doc.add(newStringField("id", ""+op, Field.Store.NO));
w.addDocument(doc);
liveIDs.add(op);
writerNumDocs++;
break;
case 1:
if (VERBOSE) {
System.out.println(" delete doc");
}
// delete docs
if (liveIDs.size() > 0) {
int id = random().nextInt(op);
if (VERBOSE) {
System.out.println(" id=" + id);
}
w.deleteDocuments(new Term("id", ""+id));
if (liveIDs.remove(id)) {
if (VERBOSE) {
System.out.println(" really deleted");
}
writerNumDocs--;
}
} else {
if (VERBOSE) {
System.out.println(" nothing to delete yet");
}
}
break;
case 2:
// reopen NRT reader
if (VERBOSE) {
System.out.println(" reopen NRT reader");
}
DirectoryReader r2 = DirectoryReader.openIfChanged(r);
if (r2 != null) {
r.close();
r = r2;
if (VERBOSE) {
System.out.println(" got new reader oldNumDocs=" + nrtReaderNumDocs + " newNumDocs=" + writerNumDocs);
}
nrtReaderNumDocs = writerNumDocs;
nrtLiveIDs = new HashSet<>(liveIDs);
} else {
if (VERBOSE) {
System.out.println(" reader is unchanged");
}
assertEquals(nrtReaderNumDocs, r.numDocs());
}
commitAfterNRT = false;
break;
case 3:
if (commitAfterNRT == false) {
// rollback writer to last nrt reader
if (random().nextBoolean()) {
if (VERBOSE) {
System.out.println(" close writer and open new writer from non-NRT reader numDocs=" + w.getDocStats().numDocs);
}
w.close();
r.close();
r = DirectoryReader.open(dir);
assertEquals(writerNumDocs, r.numDocs());
nrtReaderNumDocs = writerNumDocs;
nrtLiveIDs = new HashSet<>(liveIDs);
} else {
if (VERBOSE) {
System.out.println(" rollback writer and open new writer from NRT reader numDocs=" + w.getDocStats().numDocs);
}
w.rollback();
}
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(r.getIndexCommit());
w = new IndexWriter(dir, iwc);
writerNumDocs = nrtReaderNumDocs;
liveIDs = new HashSet<>(nrtLiveIDs);
r.close();
r = DirectoryReader.open(w);
}
break;
case 4:
if (VERBOSE) {
System.out.println(" commit");
}
w.commit();
commitAfterNRT = true;
break;
}
}
IOUtils.close(w, r, dir);
}
public void testConsistentFieldNumbers() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
// Empty first commit:
w.commit();
Document doc = new Document();
doc.add(newStringField("f0", "foo", Field.Store.NO));
w.addDocument(doc);
DirectoryReader r = DirectoryReader.open(w);
assertEquals(1, r.maxDoc());
doc = new Document();
doc.add(newStringField("f1", "foo", Field.Store.NO));
w.addDocument(doc);
DirectoryReader r2 = DirectoryReader.openIfChanged(r);
assertNotNull(r2);
r.close();
assertEquals(2, r2.maxDoc());
w.rollback();
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(r2.getIndexCommit());
IndexWriter w2 = new IndexWriter(dir, iwc);
r2.close();
doc = new Document();
doc.add(newStringField("f1", "foo", Field.Store.NO));
doc.add(newStringField("f0", "foo", Field.Store.NO));
w2.addDocument(doc);
w2.close();
dir.close();
}
public void testInvalidOpenMode() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());
w.commit();
DirectoryReader r = DirectoryReader.open(w);
assertEquals(1, r.maxDoc());
w.close();
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
iwc.setIndexCommit(r.getIndexCommit());
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new IndexWriter(dir, iwc);
});
assertEquals("cannot use IndexWriterConfig.setIndexCommit() with OpenMode.CREATE", expected.getMessage());
IOUtils.close(r, dir);
}
public void testOnClosedReader() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());
w.commit();
DirectoryReader r = DirectoryReader.open(w);
assertEquals(1, r.maxDoc());
IndexCommit commit = r.getIndexCommit();
r.close();
w.close();
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(commit);
expectThrows(AlreadyClosedException.class, () -> {
new IndexWriter(dir, iwc);
});
IOUtils.close(r, dir);
}
public void testStaleNRTReader() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());
w.commit();
DirectoryReader r = DirectoryReader.open(w);
assertEquals(1, r.maxDoc());
w.addDocument(new Document());
DirectoryReader r2 = DirectoryReader.openIfChanged(r);
assertNotNull(r2);
r2.close();
w.rollback();
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(r.getIndexCommit());
w = new IndexWriter(dir, iwc);
assertEquals(1, w.getDocStats().numDocs);
r.close();
DirectoryReader r3 = DirectoryReader.open(w);
assertEquals(1, r3.numDocs());
w.addDocument(new Document());
DirectoryReader r4 = DirectoryReader.openIfChanged(r3);
r3.close();
assertEquals(2, r4.numDocs());
r4.close();
w.close();
IOUtils.close(r, dir);
}
public void testAfterRollback() throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());
w.commit();
w.addDocument(new Document());
DirectoryReader r = DirectoryReader.open(w);
assertEquals(2, r.maxDoc());
w.rollback();
IndexWriterConfig iwc = newIndexWriterConfig();
iwc.setIndexCommit(r.getIndexCommit());
w = new IndexWriter(dir, iwc);
assertEquals(2, w.getDocStats().numDocs);
r.close();
w.close();
DirectoryReader r2 = DirectoryReader.open(dir);
assertEquals(2, r2.numDocs());
IOUtils.close(r2, dir);
}
// Pull NRT reader after writer has committed and then indexed another doc:
public void testAfterCommitThenIndexKeepCommits() throws Exception {
Directory dir = newDirectory();
IndexWriterConfig iwc = newIndexWriterConfig();
// Keep all commits:
iwc.setIndexDeletionPolicy(new IndexDeletionPolicy() {
@Override
public void onInit(List<? extends IndexCommit> commits) {
}
@Override
public void onCommit(List<? extends IndexCommit> commits) {
}
});
IndexWriter w = new IndexWriter(dir, iwc);
w.addDocument(new Document());
w.commit();
w.addDocument(new Document());
DirectoryReader r = DirectoryReader.open(w);
assertEquals(2, r.maxDoc());
w.addDocument(new Document());
DirectoryReader r2 = DirectoryReader.open(w);
assertEquals(3, r2.maxDoc());
IOUtils.close(r2, w);
// r is not stale because, even though we've committed the original writer since it was open, we are keeping all commit points:
iwc = newIndexWriterConfig();
iwc.setIndexCommit(r.getIndexCommit());
IndexWriter w2 = new IndexWriter(dir, iwc);
assertEquals(2, w2.getDocStats().maxDoc);
IOUtils.close(r, w2, dir);
}
}