Skip to content

Commit e320ebc

Browse files
CR: Fix incorrect consistency and deleting of empty trees
1 parent e7587cb commit e320ebc

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

server/src/test/java/org/elasticsearch/snapshots/SnapshotResiliencyTests.java

+34
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,12 @@
171171

172172
import java.io.IOException;
173173
import java.nio.ByteBuffer;
174+
import java.nio.file.DirectoryNotEmptyException;
175+
import java.nio.file.FileVisitResult;
174176
import java.nio.file.Files;
175177
import java.nio.file.Path;
178+
import java.nio.file.SimpleFileVisitor;
179+
import java.nio.file.attribute.BasicFileAttributes;
176180
import java.util.Collection;
177181
import java.util.Collections;
178182
import java.util.Comparator;
@@ -538,6 +542,7 @@ private void assertNoStaleRepositoryData() throws IOException {
538542
repos = reposDir.filter(s -> s.getFileName().toString().startsWith("extra") == false).collect(Collectors.toList());
539543
}
540544
for (Path repoRoot : repos) {
545+
cleanupEmptyTrees(repoRoot);
541546
final Path latestIndexGenBlob = repoRoot.resolve("index.latest");
542547
assertTrue("Could not find index.latest blob for repo at [" + repoRoot + ']', Files.exists(latestIndexGenBlob));
543548
final long latestGen = ByteBuffer.wrap(Files.readAllBytes(latestIndexGenBlob)).getLong(0);
@@ -553,6 +558,35 @@ private void assertNoStaleRepositoryData() throws IOException {
553558
}
554559
}
555560

561+
// Lucene's mock file system randomly generates empty `extra0` files that break the deletion of blob-store directories.
562+
// We clean those up here before checking a blob-store for stale files in this test.
563+
private void cleanupEmptyTrees(Path repoPath) {
564+
try {
565+
Files.walkFileTree(repoPath, new SimpleFileVisitor<>() {
566+
567+
@Override
568+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
569+
if (file.getFileName().toString().startsWith("extra")) {
570+
Files.delete(file);
571+
}
572+
return FileVisitResult.CONTINUE;
573+
}
574+
575+
@Override
576+
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
577+
try {
578+
Files.delete(dir);
579+
} catch (DirectoryNotEmptyException e) {
580+
// We're only interested in deleting empty trees here, just ignore directories with content
581+
}
582+
return FileVisitResult.CONTINUE;
583+
}
584+
});
585+
} catch (IOException e) {
586+
throw new AssertionError(e);
587+
}
588+
}
589+
556590
private static void assertIndexGenerations(Path repoRoot, long latestGen) throws IOException {
557591
try (Stream<Path> repoRootBlobs = Files.list(repoRoot)) {
558592
final long[] indexGenerations = repoRootBlobs.filter(p -> p.getFileName().toString().startsWith("index-"))

server/src/test/java/org/elasticsearch/snapshots/mockstore/MockEventuallyConsistentRepository.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,17 @@ public InputStream readBlob(String name) throws IOException {
131131
}
132132

133133
private void ensureReadAfterWrite(String blobName) {
134-
if (cachedMisses.contains(blobName) == false && pendingWrites.containsKey(blobName)) {
134+
// TODO: Make this even less consistent by keeping track of blobs that existed before instead of simply ensuring
135+
// read after first write again if the blob doesn't exist
136+
if (cachedMisses.contains(blobName) == false && pendingWrites.containsKey(blobName)
137+
&& super.blobExists(blobName) == false) {
135138
pendingWrites.remove(blobName).run();
136139
}
137140
}
138141

139142
@Override
140143
public void deleteBlob(String blobName) {
144+
ensureReadAfterWrite(blobName);
141145
// TODO: simulate longer delays here once the S3 blob store implementation can handle them
142146
deterministicTaskQueue.scheduleNow(() -> {
143147
try {

0 commit comments

Comments
 (0)