Skip to content

Commit b3e8d32

Browse files
committed
fix loop when updating reposity and creating snapshot
Signed-off-by: kkewwei <[email protected]> Signed-off-by: kkewwei <[email protected]>
1 parent 1c86dd1 commit b3e8d32

File tree

7 files changed

+105
-1
lines changed

7 files changed

+105
-1
lines changed

CHANGELOG-3.0.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1515
### Removed
1616

1717
### Fixed
18+
- Fix simultaneously creating a snapshot and updating the repository can potentially trigger an infinite loop ([#17532](https://github.com/opensearch-project/OpenSearch/pull/17532))
1819

1920
### Security
2021

server/src/internalClusterTest/java/org/opensearch/repositories/RepositoriesServiceIT.java

+69
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232

3333
package org.opensearch.repositories;
3434

35+
import org.opensearch.action.admin.cluster.repositories.get.GetRepositoriesRequest;
3536
import org.opensearch.action.admin.cluster.repositories.get.GetRepositoriesResponse;
37+
import org.opensearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
3638
import org.opensearch.cluster.metadata.RepositoryMetadata;
3739
import org.opensearch.common.settings.Settings;
3840
import org.opensearch.plugins.Plugin;
@@ -42,9 +44,14 @@
4244
import org.opensearch.test.OpenSearchIntegTestCase;
4345
import org.opensearch.transport.client.Client;
4446

47+
import java.io.IOException;
4548
import java.util.Collection;
4649
import java.util.Collections;
4750

51+
import static org.hamcrest.Matchers.containsString;
52+
import static org.hamcrest.Matchers.hasToString;
53+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_REPLICAS;
54+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_SHARDS;
4855
import static org.hamcrest.Matchers.equalTo;
4956
import static org.hamcrest.Matchers.hasSize;
5057
import static org.hamcrest.Matchers.instanceOf;
@@ -122,4 +129,66 @@ public void testSystemRepositoryCantBeCreated() {
122129

123130
assertThrows(RepositoryException.class, () -> createRepository(repositoryName, FsRepository.TYPE, repoSettings));
124131
}
132+
133+
public void testCreatSnapAndUpdateReposityCauseInfiniteLoop() throws InterruptedException {
134+
// create index
135+
internalCluster();
136+
String indexName = "test-index";
137+
createIndex(indexName, Settings.builder().put(SETTING_NUMBER_OF_REPLICAS, 0).put(SETTING_NUMBER_OF_SHARDS, 1).build());
138+
index(indexName, "_doc", "1", Collections.singletonMap("user", generateRandomStringArray(1, 10, false, false)));
139+
flush(indexName);
140+
141+
// create repository
142+
final String repositoryName = "test-repo";
143+
Settings.Builder repoSettings = Settings.builder()
144+
.put("location", randomRepoPath())
145+
.put("max_snapshot_bytes_per_sec", "10mb")
146+
.put("max_restore_bytes_per_sec", "10mb");
147+
OpenSearchIntegTestCase.putRepositoryWithNoSettingOverrides(
148+
client().admin().cluster(),
149+
repositoryName,
150+
FsRepository.TYPE,
151+
true,
152+
repoSettings
153+
);
154+
155+
String snapshotName = "test-snapshot";
156+
Runnable createSnapshot = () -> {
157+
logger.info("--> begining snapshot");
158+
client().admin()
159+
.cluster()
160+
.prepareCreateSnapshot(repositoryName, snapshotName)
161+
.setWaitForCompletion(true)
162+
.setIndices(indexName)
163+
.get();
164+
logger.info("--> finishing snapshot");
165+
};
166+
167+
// snapshot mab be failed when updating repository
168+
Thread thread = new Thread(() -> {
169+
try {
170+
createSnapshot.run();
171+
} catch (Exception e) {
172+
assertThat(e, instanceOf(RepositoryException.class));
173+
assertThat(e, hasToString(containsString(("the repository is closed"))));
174+
}
175+
});
176+
thread.start();
177+
178+
logger.info("--> begin to reset repository");
179+
repoSettings = Settings.builder().put("location", randomRepoPath()).put("max_snapshot_bytes_per_sec", "300mb");
180+
OpenSearchIntegTestCase.putRepositoryWithNoSettingOverrides(
181+
client().admin().cluster(),
182+
repositoryName,
183+
FsRepository.TYPE,
184+
true,
185+
repoSettings
186+
);
187+
logger.info("--> finish to reset repository");
188+
189+
// after updating repository, snapshot should be success
190+
createSnapshot.run();
191+
192+
thread.join();
193+
}
125194
}

server/src/main/java/org/opensearch/repositories/FilterRepository.java

+5
Original file line numberDiff line numberDiff line change
@@ -345,4 +345,9 @@ public void stop() {
345345
public void close() {
346346
in.close();
347347
}
348+
349+
@Override
350+
public boolean isOpen() {
351+
return in.isOpen();
352+
}
348353
}

server/src/main/java/org/opensearch/repositories/Repository.java

+3
Original file line numberDiff line numberDiff line change
@@ -611,4 +611,7 @@ default void reload(RepositoryMetadata repositoryMetadata) {}
611611
* Validate the repository metadata
612612
*/
613613
default void validateMetadata(RepositoryMetadata repositoryMetadata) {}
614+
615+
boolean isOpen();
616+
614617
}

server/src/main/java/org/opensearch/repositories/blobstore/BlobStoreRepository.java

+12
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,8 @@ protected static long calculateMaxWithinIntLimit(long defaultThresholdOfHeap, lo
551551
*/
552552
protected volatile int bufferSize;
553553

554+
private volatile boolean closed;
555+
554556
/**
555557
* Constructs new BlobStoreRepository
556558
* @param repositoryMetadata The metadata for this repository including name and settings
@@ -630,6 +632,7 @@ protected void doClose() {
630632
}
631633
if (store != null) {
632634
try {
635+
closed = true;
633636
store.close();
634637
} catch (Exception t) {
635638
logger.warn("cannot close blob store", t);
@@ -643,6 +646,10 @@ public void executeConsistentStateUpdate(
643646
String source,
644647
Consumer<Exception> onFailure
645648
) {
649+
if (this.isOpen() == false) {
650+
onFailure.accept(new RepositoryException(metadata.name(), "the repository is closed, maybe updated or deleted, please retry"));
651+
return;
652+
}
646653
final RepositoryMetadata repositoryMetadataStart = metadata;
647654
getRepositoryData(ActionListener.wrap(repositoryData -> {
648655
final ClusterStateUpdateTask updateTask = createUpdateTask.apply(repositoryData);
@@ -4690,6 +4697,11 @@ private void checkAborted() {
46904697
}
46914698
}
46924699

4700+
@Override
4701+
public boolean isOpen() {
4702+
return closed == false;
4703+
}
4704+
46934705
private static void failStoreIfCorrupted(Store store, Exception e) {
46944706
if (Lucene.isCorruptionException(e)) {
46954707
try {

server/src/test/java/org/opensearch/repositories/RepositoriesServiceTests.java

+5
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,11 @@ public void cloneRemoteStoreIndexShardSnapshot(
841841

842842
}
843843

844+
@Override
845+
public boolean isOpen() {
846+
return isClosed == false;
847+
}
848+
844849
@Override
845850
public Lifecycle.State lifecycleState() {
846851
return null;

test/framework/src/main/java/org/opensearch/index/shard/RestoreOnlyRepository.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,18 @@ public RestoreOnlyRepository(String indexName) {
7373
this.indexName = indexName;
7474
}
7575

76+
private volatile boolean closed;
77+
7678
@Override
7779
protected void doStart() {}
7880

7981
@Override
8082
protected void doStop() {}
8183

8284
@Override
83-
protected void doClose() {}
85+
protected void doClose() {
86+
closed = true;
87+
}
8488

8589
@Override
8690
public RepositoryMetadata getMetadata() {
@@ -249,4 +253,9 @@ public void cloneRemoteStoreIndexShardSnapshot(
249253
) {
250254
throw new UnsupportedOperationException("Unsupported for restore-only repository");
251255
}
256+
257+
@Override
258+
public boolean isOpen() {
259+
return closed == false;
260+
}
252261
}

0 commit comments

Comments
 (0)