TEST: Corrupt some translog files used in recovery (#27887)
Currently, method corruptTranslogFiles corrupts some translog files whose translog_gen are at least the min_required_translog_gen from the translog checkpoint. However this condition is not enough for recoverFromTranslog to be always failed. If we corrupt only translog operations from only translog files whose translog_gen are smaller than the min_translog_gen of a recovering index commit, recoverFromTranslog will be ok as we won't read translog operations from those files. This commit makes sure corruptTranslogFiles to corrupt some translog files that will be used in recoverFromTranslog. Closes #27538
This commit is contained in:
parent
25b0a7b20f
commit
6b0d90b9d4
|
@ -22,6 +22,9 @@ package org.elasticsearch.index.translog;
|
||||||
import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
|
import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
|
||||||
import com.carrotsearch.randomizedtesting.generators.RandomPicks;
|
import com.carrotsearch.randomizedtesting.generators.RandomPicks;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.apache.lucene.index.DirectoryReader;
|
||||||
|
import org.apache.lucene.index.IndexCommit;
|
||||||
|
import org.apache.lucene.store.NIOFSDirectory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
@ -32,13 +35,13 @@ import java.nio.file.Path;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static org.elasticsearch.index.translog.Translog.CHECKPOINT_FILE_NAME;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
|
@ -56,18 +59,16 @@ public class TestTranslog {
|
||||||
*/
|
*/
|
||||||
public static Set<Path> corruptTranslogFiles(Logger logger, Random random, Collection<Path> translogDirs) throws IOException {
|
public static Set<Path> corruptTranslogFiles(Logger logger, Random random, Collection<Path> translogDirs) throws IOException {
|
||||||
Set<Path> candidates = new TreeSet<>(); // TreeSet makes sure iteration order is deterministic
|
Set<Path> candidates = new TreeSet<>(); // TreeSet makes sure iteration order is deterministic
|
||||||
|
|
||||||
for (Path translogDir : translogDirs) {
|
for (Path translogDir : translogDirs) {
|
||||||
logger.info("--> Translog dir: {}", translogDir);
|
|
||||||
if (Files.isDirectory(translogDir)) {
|
if (Files.isDirectory(translogDir)) {
|
||||||
final Checkpoint checkpoint = Checkpoint.read(translogDir.resolve(CHECKPOINT_FILE_NAME));
|
final long minUsedTranslogGen = minTranslogGenUsedInRecovery(translogDir.getParent().resolve("index"));
|
||||||
final long minTranslogGeneration = checkpoint.minTranslogGeneration;
|
logger.info("--> Translog dir [{}], minUsedTranslogGen [{}]", translogDir, minUsedTranslogGen);
|
||||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(translogDir)) {
|
try (DirectoryStream<Path> stream = Files.newDirectoryStream(translogDir)) {
|
||||||
for (Path item : stream) {
|
for (Path item : stream) {
|
||||||
if (Files.isRegularFile(item)) {
|
if (Files.isRegularFile(item)) {
|
||||||
// Makes sure that we will corrupt tlog files that are referenced by the Checkpoint.
|
// Makes sure that we will corrupt tlog files that are referenced by the Checkpoint.
|
||||||
final Matcher matcher = TRANSLOG_FILE_PATTERN.matcher(item.getFileName().toString());
|
final Matcher matcher = TRANSLOG_FILE_PATTERN.matcher(item.getFileName().toString());
|
||||||
if (matcher.matches() && Long.parseLong(matcher.group(1)) >= minTranslogGeneration) {
|
if (matcher.matches() && Long.parseLong(matcher.group(1)) >= minUsedTranslogGen) {
|
||||||
candidates.add(item);
|
candidates.add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +84,7 @@ public class TestTranslog {
|
||||||
Path fileToCorrupt = RandomPicks.randomFrom(random, candidates);
|
Path fileToCorrupt = RandomPicks.randomFrom(random, candidates);
|
||||||
try (FileChannel raf = FileChannel.open(fileToCorrupt, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
try (FileChannel raf = FileChannel.open(fileToCorrupt, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||||
// read
|
// read
|
||||||
raf.position(RandomNumbers.randomIntBetween(random, 0, (int) Math.min(Integer.MAX_VALUE, raf.size() - 1)));
|
raf.position(RandomNumbers.randomLongBetween(random, 0, raf.size() - 1));
|
||||||
long filePointer = raf.position();
|
long filePointer = raf.position();
|
||||||
ByteBuffer bb = ByteBuffer.wrap(new byte[1]);
|
ByteBuffer bb = ByteBuffer.wrap(new byte[1]);
|
||||||
raf.read(bb);
|
raf.read(bb);
|
||||||
|
@ -107,4 +108,16 @@ public class TestTranslog {
|
||||||
assertThat("no translog file corrupted", corruptedFiles, not(empty()));
|
assertThat("no translog file corrupted", corruptedFiles, not(empty()));
|
||||||
return corruptedFiles;
|
return corruptedFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all existing commits in a given index path, then read the minimum translog generation that will be used in recoverFromTranslog.
|
||||||
|
*/
|
||||||
|
private static long minTranslogGenUsedInRecovery(Path indexPath) throws IOException {
|
||||||
|
try (NIOFSDirectory directory = new NIOFSDirectory(indexPath)) {
|
||||||
|
final List<IndexCommit> commits = DirectoryReader.listCommits(directory);
|
||||||
|
// TODO: We should call CombinedDeletionPolicy to get a correct recovering commit.
|
||||||
|
final IndexCommit recoveringCommit = commits.get(commits.size() - 1);
|
||||||
|
return Long.parseLong(recoveringCommit.getUserData().get(Translog.TRANSLOG_GENERATION_KEY));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue