Skip to content

Commit 86e3d62

Browse files
bck
1 parent 6d7c993 commit 86e3d62

File tree

2 files changed

+32
-19
lines changed

2 files changed

+32
-19
lines changed

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

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
package org.elasticsearch.snapshots;
2121

22-
import com.carrotsearch.randomizedtesting.annotations.Repeat;
2322
import org.apache.logging.log4j.LogManager;
2423
import org.apache.logging.log4j.Logger;
2524
import org.elasticsearch.Version;
@@ -107,6 +106,7 @@
107106
import org.elasticsearch.cluster.service.ClusterApplierService;
108107
import org.elasticsearch.cluster.service.ClusterService;
109108
import org.elasticsearch.cluster.service.MasterService;
109+
import org.elasticsearch.common.Nullable;
110110
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
111111
import org.elasticsearch.common.network.NetworkModule;
112112
import org.elasticsearch.common.settings.ClusterSettings;
@@ -193,7 +193,6 @@
193193
import static org.hamcrest.Matchers.hasSize;
194194
import static org.mockito.Mockito.mock;
195195

196-
@Repeat(iterations = 5000)
197196
public class SnapshotResiliencyTests extends ESTestCase {
198197

199198
private DeterministicTaskQueue deterministicTaskQueue;
@@ -203,16 +202,15 @@ public class SnapshotResiliencyTests extends ESTestCase {
203202
private Path tempDir;
204203

205204
/**
206-
* Whether to use eventually consistent blob store in tests.
205+
* Context shared by all the node's {@link Repository} instances if the eventually consistent blobstore is to be used.
206+
* {@code null} if not using the eventually consistent blobstore.
207207
*/
208-
private boolean eventuallyConsistent;
208+
@Nullable private MockEventuallyConsistentRepository.Context blobStoreContext;
209209

210-
private MockEventuallyConsistentRepository.Context blobStoreContext;
211210
@Before
212211
public void createServices() {
213212
tempDir = createTempDir();
214-
eventuallyConsistent = randomBoolean();
215-
if (eventuallyConsistent) {
213+
if (randomBoolean()) {
216214
blobStoreContext = new MockEventuallyConsistentRepository.Context();
217215
}
218216
deterministicTaskQueue =
@@ -1086,16 +1084,9 @@ searchTransportService, new SearchPhaseController(searchService::createReduceCon
10861084
client.initialize(actions, () -> clusterService.localNode().getId(), transportService.getRemoteClusterService());
10871085
}
10881086

1089-
private Repository.Factory getRepoFactory(final Environment environment) {
1087+
private Repository.Factory getRepoFactory(Environment environment) {
10901088
// Run half the tests with the eventually consistent repository
1091-
if (eventuallyConsistent) {
1092-
return metaData -> {
1093-
final Repository repository = new MockEventuallyConsistentRepository(
1094-
metaData, environment, xContentRegistry(), deterministicTaskQueue, blobStoreContext);
1095-
repository.start();
1096-
return repository;
1097-
};
1098-
} else {
1089+
if (blobStoreContext == null) {
10991090
return metaData -> {
11001091
final Repository repository = new FsRepository(metaData, environment, xContentRegistry(), threadPool) {
11011092
@Override
@@ -1106,6 +1097,13 @@ protected void assertSnapshotOrGenericThread() {
11061097
repository.start();
11071098
return repository;
11081099
};
1100+
} else {
1101+
return metaData -> {
1102+
final Repository repository = new MockEventuallyConsistentRepository(
1103+
metaData, environment, xContentRegistry(), deterministicTaskQueue, blobStoreContext);
1104+
repository.start();
1105+
return repository;
1106+
};
11091107
}
11101108
}
11111109
public void restart() {

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,14 @@
4343
import java.util.Set;
4444

4545
/**
46-
* Mock Repository that simulates the mechanics of an eventually consistent blobstore.
46+
* Mock Repository that simulates the eventually consistent behaviour of AWS S3 as documented in the
47+
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#ConsistencyModel">AWS S3 docs</a>.
48+
* Specifically this implementation simulates:
49+
* <ul>
50+
* <li>First read after write is consistent for each blob. (see S3 docs for specifics)</li>
51+
* <li>Deletes and updates to a blob can become visible with a delay.</li>
52+
* <li>Blobs can become visible to list operations with a delay.</li>
53+
* </ul>
4754
*/
4855
public class MockEventuallyConsistentRepository extends FsRepository {
4956

@@ -68,14 +75,20 @@ protected BlobStore createBlobStore() throws Exception {
6875
return new MockBlobStore(super.createBlobStore());
6976
}
7077

78+
/**
79+
* Context that must be shared between all instances of {@link MockEventuallyConsistentRepository} in a test run.
80+
*/
7181
public static final class Context {
7282

83+
/**
84+
* Map of blob path to a tuple of cached non-existent blobs in them and a map of child blob name to {@link Runnable} that when
85+
* executed will create the blob.
86+
*/
7387
private final Map<BlobPath, Tuple<Set<String>, Map<String, Runnable>>> state = new HashMap<>();
7488

7589
public Tuple<Set<String>, Map<String, Runnable>> getState(BlobPath path) {
7690
return state.computeIfAbsent(path, p -> new Tuple<>(new HashSet<>(), new HashMap<>()));
7791
}
78-
7992
}
8093

8194
private class MockBlobStore extends BlobStoreWrapper {
@@ -125,11 +138,12 @@ private void ensureReadAfterWrite(String blobName) {
125138

126139
@Override
127140
public void deleteBlob(String blobName) {
141+
// TODO: simulate longer delays here once the S3 blob store implementation can handle them
128142
deterministicTaskQueue.scheduleNow(() -> {
129143
try {
130144
super.deleteBlob(blobName);
131145
} catch (DirectoryNotEmptyException | NoSuchFileException e) {
132-
// ignored
146+
// ignored since neither of these exceptions would occur on S3
133147
} catch (IOException e) {
134148
throw new AssertionError(e);
135149
}
@@ -154,6 +168,7 @@ public void writeBlob(String blobName, InputStream inputStream, long blobSize, b
154168
throw new AssertionError(e);
155169
}
156170
});
171+
// TODO: simulate longer delays here once the S3 blob store implementation can handle them
157172
deterministicTaskQueue.scheduleNow(() -> {
158173
if (pendingWrites.containsKey(blobName)) {
159174
pendingWrites.remove(blobName).run();

0 commit comments

Comments
 (0)