diff --git a/server/src/main/java/org/elasticsearch/repositories/blobstore/BlobStoreRepository.java b/server/src/main/java/org/elasticsearch/repositories/blobstore/BlobStoreRepository.java index 2c71215c135ee..19b9e47c996ce 100644 --- a/server/src/main/java/org/elasticsearch/repositories/blobstore/BlobStoreRepository.java +++ b/server/src/main/java/org/elasticsearch/repositories/blobstore/BlobStoreRepository.java @@ -2740,6 +2740,15 @@ public boolean supportURLRepo() { return supportURLRepo; } + /** + * @return whether this repository performs overwrites atomically. In practice we only overwrite the `index.latest` blob so this + * is not very important, but the repository analyzer does test that overwrites happen atomically. It will skip those tests if the + * repository overrides this method to indicate that it does not support atomic overwrites. + */ + public boolean hasAtomicOverwrites() { + return true; + } + /** * The result of removing a snapshot from a shard folder in the repository. */ diff --git a/server/src/main/java/org/elasticsearch/repositories/fs/FsRepository.java b/server/src/main/java/org/elasticsearch/repositories/fs/FsRepository.java index 30b7c935fbb16..746e6726f8ffe 100644 --- a/server/src/main/java/org/elasticsearch/repositories/fs/FsRepository.java +++ b/server/src/main/java/org/elasticsearch/repositories/fs/FsRepository.java @@ -103,4 +103,11 @@ protected BlobStore createBlobStore() throws Exception { protected ByteSizeValue chunkSize() { return chunkSize; } + + @Override + public boolean hasAtomicOverwrites() { + // We overwrite a file by deleting the old file and then renaming the new file into place, which is not atomic. + // Also on Windows the overwrite may fail if the file is opened for reading at the time. + return false; + } } diff --git a/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepository.java b/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepository.java index b39a62c7c5e42..7944c20d351e7 100644 --- a/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepository.java +++ b/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepository.java @@ -379,6 +379,11 @@ private void validateLocalRepositorySecret(Map snapshotUserMetad } } + @Override + public boolean hasAtomicOverwrites() { + return delegatedRepository.hasAtomicOverwrites(); + } + // pkg-private for tests static final class EncryptedBlobStore implements BlobStore { private final BlobStore delegatedBlobStore; diff --git a/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/BlobAnalyzeAction.java b/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/BlobAnalyzeAction.java index 1bba56bdbd7f6..c975d855178b4 100644 --- a/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/BlobAnalyzeAction.java +++ b/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/BlobAnalyzeAction.java @@ -486,8 +486,6 @@ private void onReadsComplete(Collection responses, WriteDetails wr if (response.isNotFound()) { if (request.readEarly) { nodeFailure = null; // "not found" is legitimate iff we tried to read it before the write completed - } else if (request.writeAndOverwrite) { - nodeFailure = null; // overwrites surprisingly not necessarily atomic, e.g. in a FsBlobContainer } else { nodeFailure = new RepositoryVerificationException( request.getRepositoryName(), diff --git a/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/RepositoryAnalyzeAction.java b/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/RepositoryAnalyzeAction.java index 0e03e2c9f3aa0..b9b0c057fb5f3 100644 --- a/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/RepositoryAnalyzeAction.java +++ b/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/RepositoryAnalyzeAction.java @@ -465,7 +465,10 @@ public void run() { request.getReadNodeCount(), request.getEarlyReadNodeCount(), smallBlob && random.nextDouble() < request.getRareActionProbability(), - repository.supportURLRepo() && smallBlob && random.nextDouble() < request.getRareActionProbability() + repository.supportURLRepo() + && repository.hasAtomicOverwrites() + && smallBlob + && random.nextDouble() < request.getRareActionProbability() ) ); queue.add(verifyBlobTask);