LUCENE-8048: Filesystems do not guarantee order of directories updates

This commit is contained in:
Erick Erickson 2017-12-05 09:09:28 -08:00
commit 0688be6c66
3 changed files with 23 additions and 9 deletions

View File

@ -145,6 +145,9 @@ Optimizations
caching as they could break memory accounting of the query cache. caching as they could break memory accounting of the query cache.
(Adrien Grand) (Adrien Grand)
* LUCENE-8048: Filesystems do not guarantee order of directories updates
(Nikolay Martynov, Simon Willnauer, Erick Erickson)
Tests Tests
* LUCENE-8035: Run tests with JDK-specific options: --illegal-access=deny * LUCENE-8035: Run tests with JDK-specific options: --illegal-access=deny

View File

@ -747,6 +747,7 @@ public final class SegmentInfos implements Cloneable, Iterable<SegmentCommitInfo
if (pendingCommit) { if (pendingCommit) {
throw new IllegalStateException("prepareCommit was already called"); throw new IllegalStateException("prepareCommit was already called");
} }
dir.syncMetaData();
write(dir); write(dir);
} }

View File

@ -885,14 +885,16 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
private static class FailOnlyInCommit extends MockDirectoryWrapper.Failure { private static class FailOnlyInCommit extends MockDirectoryWrapper.Failure {
boolean failOnCommit, failOnDeleteFile; boolean failOnCommit, failOnDeleteFile, failOnSyncMetadata;
private final boolean dontFailDuringGlobalFieldMap; private final boolean dontFailDuringGlobalFieldMap;
private final boolean dontFailDuringSyncMetadata;
private static final String PREPARE_STAGE = "prepareCommit"; private static final String PREPARE_STAGE = "prepareCommit";
private static final String FINISH_STAGE = "finishCommit"; private static final String FINISH_STAGE = "finishCommit";
private final String stage; private final String stage;
public FailOnlyInCommit(boolean dontFailDuringGlobalFieldMap, String stage) { public FailOnlyInCommit(boolean dontFailDuringGlobalFieldMap, boolean dontFailDuringSyncMetadata, String stage) {
this.dontFailDuringGlobalFieldMap = dontFailDuringGlobalFieldMap; this.dontFailDuringGlobalFieldMap = dontFailDuringGlobalFieldMap;
this.dontFailDuringSyncMetadata = dontFailDuringSyncMetadata;
this.stage = stage; this.stage = stage;
} }
@ -901,9 +903,10 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
StackTraceElement[] trace = new Exception().getStackTrace(); StackTraceElement[] trace = new Exception().getStackTrace();
boolean isCommit = false; boolean isCommit = false;
boolean isDelete = false; boolean isDelete = false;
boolean isSyncMetadata = false;
boolean isInGlobalFieldMap = false; boolean isInGlobalFieldMap = false;
for (int i = 0; i < trace.length; i++) { for (int i = 0; i < trace.length; i++) {
if (isCommit && isDelete && isInGlobalFieldMap) { if (isCommit && isDelete && isInGlobalFieldMap && isSyncMetadata) {
break; break;
} }
if (SegmentInfos.class.getName().equals(trace[i].getClassName()) && stage.equals(trace[i].getMethodName())) { if (SegmentInfos.class.getName().equals(trace[i].getClassName()) && stage.equals(trace[i].getMethodName())) {
@ -915,14 +918,20 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
if (SegmentInfos.class.getName().equals(trace[i].getClassName()) && "writeGlobalFieldMap".equals(trace[i].getMethodName())) { if (SegmentInfos.class.getName().equals(trace[i].getClassName()) && "writeGlobalFieldMap".equals(trace[i].getMethodName())) {
isInGlobalFieldMap = true; isInGlobalFieldMap = true;
} }
if (MockDirectoryWrapper.class.getName().equals(trace[i].getClassName()) && "syncMetaData".equals(trace[i].getMethodName())) {
isSyncMetadata = true;
}
} }
if (isInGlobalFieldMap && dontFailDuringGlobalFieldMap) { if (isInGlobalFieldMap && dontFailDuringGlobalFieldMap) {
isCommit = false; isCommit = false;
} }
if (isSyncMetadata && dontFailDuringSyncMetadata) {
isCommit = false;
}
if (isCommit) { if (isCommit) {
if (!isDelete) { if (!isDelete) {
failOnCommit = true; failOnCommit = true;
failOnSyncMetadata = isSyncMetadata;
throw new RuntimeException("now fail first"); throw new RuntimeException("now fail first");
} else { } else {
failOnDeleteFile = true; failOnDeleteFile = true;
@ -935,9 +944,10 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
public void testExceptionsDuringCommit() throws Throwable { public void testExceptionsDuringCommit() throws Throwable {
FailOnlyInCommit[] failures = new FailOnlyInCommit[] { FailOnlyInCommit[] failures = new FailOnlyInCommit[] {
// LUCENE-1214 // LUCENE-1214
new FailOnlyInCommit(false, FailOnlyInCommit.PREPARE_STAGE), // fail during global field map is written new FailOnlyInCommit(false, true, FailOnlyInCommit.PREPARE_STAGE), // fail during global field map is written
new FailOnlyInCommit(true, FailOnlyInCommit.PREPARE_STAGE), // fail after global field map is written new FailOnlyInCommit(true, false, FailOnlyInCommit.PREPARE_STAGE), // fail during sync metadata
new FailOnlyInCommit(false, FailOnlyInCommit.FINISH_STAGE) // fail while running finishCommit new FailOnlyInCommit(true, true, FailOnlyInCommit.PREPARE_STAGE), // fail after global field map is written
new FailOnlyInCommit(false, true, FailOnlyInCommit.FINISH_STAGE) // fail while running finishCommit
}; };
for (FailOnlyInCommit failure : failures) { for (FailOnlyInCommit failure : failures) {
@ -952,8 +962,8 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
expectThrows(RuntimeException.class, () -> { expectThrows(RuntimeException.class, () -> {
w.close(); w.close();
}); });
assertTrue("failOnCommit=" + failure.failOnCommit + " failOnDeleteFile=" + failure.failOnDeleteFile
assertTrue("failOnCommit=" + failure.failOnCommit + " failOnDeleteFile=" + failure.failOnDeleteFile, failure.failOnCommit && failure.failOnDeleteFile); + " failOnSyncMetadata=" + failure.failOnSyncMetadata + "", failure.failOnCommit && (failure.failOnDeleteFile || failure.failOnSyncMetadata));
w.rollback(); w.rollback();
String files[] = dir.listAll(); String files[] = dir.listAll();
assertTrue(files.length == fileCount || (files.length == fileCount+1 && Arrays.asList(files).contains(IndexWriter.WRITE_LOCK_NAME))); assertTrue(files.length == fileCount || (files.length == fileCount+1 && Arrays.asList(files).contains(IndexWriter.WRITE_LOCK_NAME)));