Преглед на файлове

Introduce RepositoryData.SnapshotDetails (#71826)

Today we track a couple of values for each snapshot in the top-level
`RepositoryData` blob: the overall snapshot state and the version of
Elasticsearch which took the snapshot. In the blob these values are
fields of the corresponding snapshot object, but in code they're kept in
independent maps. In the near future we would like to track some more
values in the same way, but adding a new field for every tracked value
is a little ugly. This commit refactors these values into a single
object, `SnapshotDetails`, so that it can be more easily extended in
future.
David Turner преди 4 години
родител
ревизия
aa5d1948ba

+ 5 - 2
plugins/repository-s3/src/internalClusterTest/java/org/elasticsearch/repositories/s3/S3BlobStoreRepositoryTests.java

@@ -146,8 +146,11 @@ public class S3BlobStoreRepositoryTests extends ESMockAPIBasedRepositoryIntegTes
         final RepositoriesService repositoriesService = internalCluster().getCurrentMasterNodeInstance(RepositoriesService.class);
         final BlobStoreRepository repository = (BlobStoreRepository) repositoriesService.repository(repoName);
         final RepositoryData repositoryData = getRepositoryData(repository);
-        final RepositoryData modifiedRepositoryData = repositoryData.withVersions(Collections.singletonMap(fakeOldSnapshot,
-            SnapshotsService.SHARD_GEN_IN_REPO_DATA_VERSION.minimumCompatibilityVersion())).withoutUUIDs();
+        final RepositoryData modifiedRepositoryData = repositoryData
+                .withoutSnapshotVersion(fakeOldSnapshot.getUUID())
+                .withVersions(Collections.singletonMap(
+                        fakeOldSnapshot,
+                        SnapshotsService.SHARD_GEN_IN_REPO_DATA_VERSION.minimumCompatibilityVersion()));
         final BytesReference serialized = BytesReference.bytes(modifiedRepositoryData.snapshotsToXContent(XContentFactory.jsonBuilder(),
             SnapshotsService.OLD_SNAPSHOT_FORMAT));
         PlainActionFuture.get(f -> repository.threadPool().generic().execute(ActionRunnable.run(f, () ->

+ 3 - 4
server/src/internalClusterTest/java/org/elasticsearch/snapshots/CorruptedBlobStoreRepositoryIT.java

@@ -199,8 +199,8 @@ public class CorruptedBlobStoreRepositoryIT extends AbstractSnapshotIntegTestCas
                 RepositoryData.MISSING_UUID, // old-format repository data has no UUID
                 repositoryData.getGenId(),
                 repositoryData.getSnapshotIds().stream().collect(Collectors.toMap(SnapshotId::getUUID, Function.identity())),
-                repositoryData.getSnapshotIds().stream().collect(Collectors.toMap(SnapshotId::getUUID, repositoryData::getSnapshotState)),
-                Collections.emptyMap(),
+                repositoryData.getSnapshotIds().stream().collect(Collectors.toMap(SnapshotId::getUUID,
+                        s -> new RepositoryData.SnapshotDetails(repositoryData.getSnapshotState(s), null))),
                 Collections.emptyMap(),
                 ShardGenerations.EMPTY,
                 IndexMetaDataGenerations.EMPTY,
@@ -332,8 +332,7 @@ public class CorruptedBlobStoreRepositoryIT extends AbstractSnapshotIntegTestCas
                 repositoryData.getUuid(),
                 repositoryData.getGenId(),
                 snapshotIds,
-                snapshotIds.values().stream().collect(Collectors.toMap(SnapshotId::getUUID, repositoryData::getSnapshotState)),
-                snapshotIds.values().stream().collect(Collectors.toMap(SnapshotId::getUUID, repositoryData::getVersion)),
+                snapshotIds.values().stream().collect(Collectors.toMap(SnapshotId::getUUID, repositoryData::getSnapshotDetails)),
                 repositoryData.getIndices().values().stream().collect(Collectors.toMap(Function.identity(), repositoryData::getSnapshots)),
                 ShardGenerations.builder().putAll(repositoryData.shardGenerations()).put(indexId, 0, "0").build(),
                 repositoryData.indexMetaDataGenerations(), repositoryData.getClusterUUID());

+ 123 - 62
server/src/main/java/org/elasticsearch/repositories/RepositoryData.java

@@ -20,6 +20,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.common.xcontent.XContentParserUtils;
 import org.elasticsearch.snapshots.SnapshotId;
+import org.elasticsearch.snapshots.SnapshotInfo;
 import org.elasticsearch.snapshots.SnapshotState;
 import org.elasticsearch.snapshots.SnapshotsService;
 
@@ -73,7 +74,6 @@ public final class RepositoryData {
             Collections.emptyMap(),
             Collections.emptyMap(),
             Collections.emptyMap(),
-            Collections.emptyMap(),
             ShardGenerations.EMPTY,
             IndexMetaDataGenerations.EMPTY,
             MISSING_UUID);
@@ -92,25 +92,27 @@ public final class RepositoryData {
      * The generational id of the index file from which the repository data was read.
      */
     private final long genId;
+
     /**
      * The ids of the snapshots in the repository.
      */
     private final Map<String, SnapshotId> snapshotIds;
+
     /**
-     * The states of each snapshot in the repository.
+     * The details of each snapshot in the repository.
      */
-    private final Map<String, SnapshotState> snapshotStates;
+    private final Map<String, SnapshotDetails> snapshotsDetails;
+
     /**
      * The indices found in the repository across all snapshots, as a name to {@link IndexId} mapping
      */
     private final Map<String, IndexId> indices;
+
     /**
      * The snapshots that each index belongs to.
      */
     private final Map<IndexId, List<SnapshotId>> indexSnapshots;
 
-    private final Map<String, Version> snapshotVersions;
-
     /**
      * Index metadata generations.
      */
@@ -125,8 +127,7 @@ public final class RepositoryData {
             String uuid,
             long genId,
             Map<String, SnapshotId> snapshotIds,
-            Map<String, SnapshotState> snapshotStates,
-            Map<String, Version> snapshotVersions,
+            Map<String, SnapshotDetails> snapshotsDetails,
             Map<IndexId, List<SnapshotId>> indexSnapshots,
             ShardGenerations shardGenerations,
             IndexMetaDataGenerations indexMetaDataGenerations,
@@ -135,8 +136,7 @@ public final class RepositoryData {
                 uuid,
                 genId,
                 Collections.unmodifiableMap(snapshotIds),
-                Collections.unmodifiableMap(snapshotStates),
-                Collections.unmodifiableMap(snapshotVersions),
+                Collections.unmodifiableMap(snapshotsDetails),
                 indexSnapshots.keySet().stream().collect(Collectors.toUnmodifiableMap(IndexId::getName, Function.identity())),
                 Collections.unmodifiableMap(indexSnapshots),
                 shardGenerations,
@@ -148,8 +148,7 @@ public final class RepositoryData {
             String uuid,
             long genId,
             Map<String, SnapshotId> snapshotIds,
-            Map<String, SnapshotState> snapshotStates,
-            Map<String, Version> snapshotVersions,
+            Map<String, SnapshotDetails> snapshotsDetails,
             Map<String, IndexId> indices,
             Map<IndexId, List<SnapshotId>> indexSnapshots,
             ShardGenerations shardGenerations,
@@ -158,12 +157,11 @@ public final class RepositoryData {
         this.uuid = Objects.requireNonNull(uuid);
         this.genId = genId;
         this.snapshotIds = snapshotIds;
-        this.snapshotStates = snapshotStates;
+        this.snapshotsDetails = snapshotsDetails;
         this.indices = indices;
         this.indexSnapshots = indexSnapshots;
         this.shardGenerations = shardGenerations;
         this.indexMetaDataGenerations = indexMetaDataGenerations;
-        this.snapshotVersions = snapshotVersions;
         this.clusterUUID = Objects.requireNonNull(clusterUUID);
         assert uuid.equals(MISSING_UUID) == clusterUUID.equals(MISSING_UUID) : "Either repository- and cluster UUID must both be missing" +
                 " or neither of them must be missing but saw [" + uuid + "][" + clusterUUID + "]";
@@ -178,8 +176,7 @@ public final class RepositoryData {
                 uuid,
                 genId,
                 snapshotIds,
-                snapshotStates,
-                snapshotVersions,
+                snapshotsDetails,
                 indices,
                 indexSnapshots,
                 shardGenerations,
@@ -196,14 +193,20 @@ public final class RepositoryData {
         if (versions.isEmpty()) {
             return this;
         }
-        final Map<String, Version> newVersions = new HashMap<>(snapshotVersions);
-        versions.forEach((id, version) -> newVersions.put(id.getUUID(), version));
+        final Map<String, SnapshotDetails> newDetails = new HashMap<>(snapshotsDetails);
+        versions.forEach((id, version) -> newDetails.compute(id.getUUID(), (uuid, existingDetails) -> {
+            if (existingDetails == null) {
+                return new SnapshotDetails(null, version);
+            } else {
+                assert existingDetails.getVersion() == null;
+                return new SnapshotDetails(existingDetails.getSnapshotState(), version);
+            }
+        }));
         return new RepositoryData(
                 uuid,
                 genId,
                 snapshotIds,
-                snapshotStates,
-                newVersions,
+                newDetails,
                 indices,
                 indexSnapshots,
                 shardGenerations,
@@ -245,13 +248,21 @@ public final class RepositoryData {
         return snapshotIds.values();
     }
 
+    /**
+     * Returns the {@link SnapshotDetails} for the given snapshot. Returns {@code null} if there are no details for the snapshot.
+     */
+    @Nullable
+    public SnapshotDetails getSnapshotDetails(final SnapshotId snapshotId) {
+        return snapshotsDetails.get(snapshotId.getUUID());
+    }
+
     /**
      * Returns the {@link SnapshotState} for the given snapshot.  Returns {@code null} if
      * there is no state for the snapshot.
      */
     @Nullable
     public SnapshotState getSnapshotState(final SnapshotId snapshotId) {
-        return snapshotStates.get(snapshotId.getUUID());
+        return snapshotsDetails.getOrDefault(snapshotId.getUUID(), SnapshotDetails.EMPTY).getSnapshotState();
     }
 
     /**
@@ -259,7 +270,7 @@ public final class RepositoryData {
      */
     @Nullable
     public Version getVersion(SnapshotId snapshotId) {
-        return snapshotVersions.get(snapshotId.getUUID());
+        return snapshotsDetails.getOrDefault(snapshotId.getUUID(), SnapshotDetails.EMPTY).getVersion();
     }
 
     /**
@@ -322,7 +333,7 @@ public final class RepositoryData {
      * already exists in the repository data, this method throws an IllegalArgumentException.
      *
      * @param snapshotId       Id of the new snapshot
-     * @param snapshotState    State of the new snapshot
+     * @param details          Details of the new snapshot
      * @param shardGenerations Updated shard generations in the new snapshot. For each index contained in the snapshot an array of new
      *                         generations indexed by the shard id they correspond to must be supplied.
      * @param indexMetaBlobs   Map of index metadata blob uuids
@@ -330,8 +341,7 @@ public final class RepositoryData {
      *                         {@link IndexMetadata} in them
      */
     public RepositoryData addSnapshot(final SnapshotId snapshotId,
-                                      final SnapshotState snapshotState,
-                                      final Version version,
+                                      final SnapshotDetails details,
                                       final ShardGenerations shardGenerations,
                                       @Nullable final Map<IndexId, String> indexMetaBlobs,
                                       @Nullable final Map<String, String> newIdentifiers) {
@@ -343,10 +353,8 @@ public final class RepositoryData {
         }
         Map<String, SnapshotId> snapshots = new HashMap<>(snapshotIds);
         snapshots.put(snapshotId.getUUID(), snapshotId);
-        Map<String, SnapshotState> newSnapshotStates = new HashMap<>(snapshotStates);
-        newSnapshotStates.put(snapshotId.getUUID(), snapshotState);
-        Map<String, Version> newSnapshotVersions = new HashMap<>(snapshotVersions);
-        newSnapshotVersions.put(snapshotId.getUUID(), version);
+        Map<String, SnapshotDetails> newSnapshotDetails = new HashMap<>(snapshotsDetails);
+        newSnapshotDetails.put(snapshotId.getUUID(), details);
         Map<IndexId, List<SnapshotId>> allIndexSnapshots = new HashMap<>(indexSnapshots);
         for (final IndexId indexId : shardGenerations.indices()) {
             final List<SnapshotId> snapshotIds = allIndexSnapshots.get(indexId);
@@ -374,8 +382,7 @@ public final class RepositoryData {
                 uuid,
                 genId,
                 snapshots,
-                newSnapshotStates,
-                newSnapshotVersions,
+                newSnapshotDetails,
                 allIndexSnapshots,
                 ShardGenerations.builder().putAll(this.shardGenerations).putAll(shardGenerations).build(),
                 newIndexMetaGenerations,
@@ -396,8 +403,7 @@ public final class RepositoryData {
                 uuid,
                 newGeneration,
                 snapshotIds,
-                snapshotStates,
-                snapshotVersions,
+                snapshotsDetails,
                 indices,
                 indexSnapshots,
                 shardGenerations,
@@ -414,8 +420,27 @@ public final class RepositoryData {
                 MISSING_UUID,
                 genId,
                 snapshotIds,
-                snapshotStates,
-                snapshotVersions,
+                snapshotsDetails,
+                indices,
+                indexSnapshots,
+                shardGenerations,
+                indexMetaDataGenerations,
+                MISSING_UUID);
+    }
+
+    /**
+     * For test purposes, make a copy of this instance with the version field missing for the given snapshot UUID, as if from an
+     * older version. Also removes the UUIDs since these were missing from the older version in question, see {@link #withoutUUIDs}.
+     */
+    public RepositoryData withoutSnapshotVersion(String snapshotUuid) {
+        final Map<String, SnapshotDetails> newSnapshotsDetails = new HashMap<>(snapshotsDetails);
+        final SnapshotState snapshotState = newSnapshotsDetails.get(snapshotUuid).getSnapshotState();
+        newSnapshotsDetails.put(snapshotUuid, new SnapshotDetails(snapshotState, null));
+        return new RepositoryData(
+                MISSING_UUID,
+                genId,
+                snapshotIds,
+                newSnapshotsDetails,
                 indices,
                 indexSnapshots,
                 shardGenerations,
@@ -429,8 +454,7 @@ public final class RepositoryData {
                 uuid.equals(MISSING_UUID) ? UUIDs.randomBase64UUID() : uuid,
                 genId,
                 snapshotIds,
-                snapshotStates,
-                snapshotVersions,
+                snapshotsDetails,
                 indices,
                 indexSnapshots,
                 shardGenerations,
@@ -454,11 +478,9 @@ public final class RepositoryData {
             notFound.removeAll(snapshotIds.values());
             throw new ResourceNotFoundException("Attempting to remove non-existent snapshots {} from repository data", notFound);
         }
-        Map<String, SnapshotState> newSnapshotStates = new HashMap<>(snapshotStates);
-        final Map<String, Version> newSnapshotVersions = new HashMap<>(snapshotVersions);
+        final Map<String, SnapshotDetails> newSnapshotsDetails = new HashMap<>(snapshotsDetails);
         for (SnapshotId snapshotId : snapshots) {
-            newSnapshotStates.remove(snapshotId.getUUID());
-            newSnapshotVersions.remove(snapshotId.getUUID());
+            newSnapshotsDetails.remove(snapshotId.getUUID());
         }
         Map<IndexId, List<SnapshotId>> indexSnapshots = new HashMap<>();
         for (final IndexId indexId : indices.values()) {
@@ -479,8 +501,7 @@ public final class RepositoryData {
                 uuid,
                 genId,
                 newSnapshotIds,
-                newSnapshotStates,
-                newSnapshotVersions,
+                newSnapshotsDetails,
                 indexSnapshots,
                 ShardGenerations.builder().putAll(shardGenerations).putAll(updatedShardGenerations)
                         .retainIndicesAndPruneDeletes(indexSnapshots.keySet()).build(),
@@ -510,8 +531,7 @@ public final class RepositoryData {
         }
         RepositoryData that = (RepositoryData) obj;
         return snapshotIds.equals(that.snapshotIds)
-                   && snapshotStates.equals(that.snapshotStates)
-                   && snapshotVersions.equals(that.snapshotVersions)
+                   && snapshotsDetails.equals(that.snapshotsDetails)
                    && indices.equals(that.indices)
                    && indexSnapshots.equals(that.indexSnapshots)
                    && shardGenerations.equals(that.shardGenerations)
@@ -521,7 +541,7 @@ public final class RepositoryData {
     @Override
     public int hashCode() {
         return Objects.hash(
-            snapshotIds, snapshotStates, snapshotVersions, indices, indexSnapshots, shardGenerations, indexMetaDataGenerations);
+            snapshotIds, snapshotsDetails, indices, indexSnapshots, shardGenerations, indexMetaDataGenerations);
     }
 
     /**
@@ -641,7 +661,8 @@ public final class RepositoryData {
             builder.field(NAME, snapshot.getName());
             final String snapshotUUID = snapshot.getUUID();
             builder.field(UUID, snapshotUUID);
-            final SnapshotState state = snapshotStates.get(snapshotUUID);
+            final SnapshotDetails snapshotDetails = snapshotsDetails.getOrDefault(snapshotUUID, SnapshotDetails.EMPTY);
+            final SnapshotState state = snapshotDetails.getSnapshotState();
             if (state != null) {
                 builder.field(STATE, state.value());
             }
@@ -653,7 +674,7 @@ public final class RepositoryData {
                 }
                 builder.endObject();
             }
-            final Version version = snapshotVersions.get(snapshotUUID);
+            final Version version = snapshotDetails.getVersion();
             if (version != null) {
                 builder.field(VERSION, version.toString());
             }
@@ -708,8 +729,7 @@ public final class RepositoryData {
         XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
 
         final Map<String, SnapshotId> snapshots = new HashMap<>();
-        final Map<String, SnapshotState> snapshotStates = new HashMap<>();
-        final Map<String, Version> snapshotVersions = new HashMap<>();
+        final Map<String, SnapshotDetails> snapshotsDetails = new HashMap<>();
         final Map<IndexId, List<SnapshotId>> indexSnapshots = new HashMap<>();
         final Map<String, IndexId> indexLookup = new HashMap<>();
         final ShardGenerations.Builder shardGenerations = ShardGenerations.builder();
@@ -721,7 +741,7 @@ public final class RepositoryData {
             final String field = parser.currentName();
             switch (field) {
                 case SNAPSHOTS:
-                    parseSnapshots(parser, snapshots, snapshotStates, snapshotVersions, indexMetaLookup);
+                    parseSnapshots(parser, snapshots, snapshotsDetails, indexMetaLookup);
                     break;
                 case INDICES:
                     parseIndices(parser, fixBrokenShardGens, snapshots, indexSnapshots, indexLookup, shardGenerations);
@@ -761,8 +781,7 @@ public final class RepositoryData {
                 uuid,
                 genId,
                 snapshots,
-                snapshotStates,
-                snapshotVersions,
+                snapshotsDetails,
                 indexSnapshots,
                 shardGenerations.build(),
                 buildIndexMetaGenerations(indexMetaLookup, indexLookup, indexMetaIdentifiers),
@@ -804,14 +823,15 @@ public final class RepositoryData {
      *
      * @param parser           x-content parse
      * @param snapshots        map of snapshot uuid to {@link SnapshotId}
-     * @param snapshotStates   map of snapshot uuid to {@link SnapshotState}
-     * @param snapshotVersions map of snapshot uuid to {@link Version} that the snapshot was taken in
+     * @param snapshotsDetails map of snapshot uuid to {@link SnapshotDetails}
      * @param indexMetaLookup  map of {@link SnapshotId} to map of index id (as returned by {@link IndexId#getId}) that defines the index
      *                         metadata generations for the snapshot
      */
-    private static void parseSnapshots(XContentParser parser, Map<String, SnapshotId> snapshots, Map<String, SnapshotState> snapshotStates,
-                                       Map<String, Version> snapshotVersions,
-                                       Map<SnapshotId, Map<String, String>> indexMetaLookup) throws IOException {
+    private static void parseSnapshots(
+            XContentParser parser,
+            Map<String, SnapshotId> snapshots,
+            Map<String, SnapshotDetails> snapshotsDetails,
+            Map<SnapshotId, Map<String, String>> indexMetaLookup) throws IOException {
         XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.nextToken(), parser);
         final Map<String, String> stringDeduplicator = new HashMap<>();
         while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
@@ -842,11 +862,8 @@ public final class RepositoryData {
                 }
             }
             final SnapshotId snapshotId = new SnapshotId(name, uuid);
-            if (state != null) {
-                snapshotStates.put(uuid, state);
-            }
-            if (version != null) {
-                snapshotVersions.put(uuid, version);
+            if (state != null || version != null) {
+                snapshotsDetails.put(uuid, new SnapshotDetails(state, version));
             }
             snapshots.put(uuid, snapshotId);
             if (metaGenerations != null && metaGenerations.isEmpty() == false) {
@@ -944,4 +961,48 @@ public final class RepositoryData {
         return uuid;
     }
 
+    /**
+     * A few details of an individual snapshot stored in the top-level index blob, so they are readily accessible without having to load
+     * the corresponding {@link SnapshotInfo} blob for each snapshot.
+     */
+    public static class SnapshotDetails {
+
+        public static SnapshotDetails EMPTY = new SnapshotDetails(null, null);
+
+        @Nullable // TODO forbid nulls here, this only applies to very old repositories
+        private final SnapshotState snapshotState;
+
+        @Nullable // may be omitted if pre-7.6 nodes were involved somewhere
+        private final Version version;
+
+        public SnapshotDetails(@Nullable SnapshotState snapshotState, @Nullable Version version) {
+            this.snapshotState = snapshotState;
+            this.version = version;
+        }
+
+        @Nullable
+        public SnapshotState getSnapshotState() {
+            return snapshotState;
+        }
+
+        @Nullable
+        public Version getVersion() {
+            return version;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            SnapshotDetails that = (SnapshotDetails) o;
+            return snapshotState == that.snapshotState && Objects.equals(version, that.version);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(snapshotState, version);
+        }
+
+    }
+
 }

+ 3 - 1
server/src/main/java/org/elasticsearch/repositories/blobstore/BlobStoreRepository.java

@@ -97,6 +97,7 @@ import org.elasticsearch.repositories.RepositoriesService;
 import org.elasticsearch.repositories.Repository;
 import org.elasticsearch.repositories.RepositoryCleanupResult;
 import org.elasticsearch.repositories.RepositoryData;
+import org.elasticsearch.repositories.RepositoryData.SnapshotDetails;
 import org.elasticsearch.repositories.RepositoryException;
 import org.elasticsearch.repositories.RepositoryOperation;
 import org.elasticsearch.repositories.RepositoryShardId;
@@ -1113,8 +1114,9 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent imp
 
             final ActionListener<Void> allMetaListener = new GroupedActionListener<>(
                 ActionListener.wrap(v -> {
+                    final SnapshotDetails snapshotDetails = new SnapshotDetails(snapshotInfo.state(), Version.CURRENT);
                     final RepositoryData updatedRepositoryData = existingRepositoryData.addSnapshot(
-                        snapshotId, snapshotInfo.state(), Version.CURRENT, shardGenerations, indexMetas, indexMetaIdentifiers);
+                        snapshotId, snapshotDetails, shardGenerations, indexMetas, indexMetaIdentifiers);
                     writeIndexGen(updatedRepositoryData, repositoryStateId, repositoryMetaVersion, stateTransformer,
                             ActionListener.wrap(
                                     newRepoData -> {

+ 31 - 25
server/src/test/java/org/elasticsearch/repositories/RepositoryDataTests.java

@@ -102,11 +102,14 @@ public class RepositoryDataTests extends ESTestCase {
         final ShardGenerations shardGenerations = builder.build();
         final Map<IndexId, String> indexLookup =
             shardGenerations.indices().stream().collect(Collectors.toMap(Function.identity(), ind -> randomAlphaOfLength(256)));
-        RepositoryData newRepoData = repositoryData.addSnapshot(newSnapshot,
-            randomFrom(SnapshotState.SUCCESS, SnapshotState.PARTIAL, SnapshotState.FAILED),
-            randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()),
-            shardGenerations, indexLookup,
-            indexLookup.values().stream().collect(Collectors.toMap(Function.identity(), ignored -> UUIDs.randomBase64UUID(random()))));
+        RepositoryData newRepoData = repositoryData.addSnapshot(
+                newSnapshot,
+                new RepositoryData.SnapshotDetails(
+                        randomFrom(SnapshotState.SUCCESS, SnapshotState.PARTIAL, SnapshotState.FAILED),
+                        randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion())),
+                shardGenerations,
+                indexLookup,
+                indexLookup.values().stream().collect(Collectors.toMap(Function.identity(), ignored -> UUIDs.randomBase64UUID(random()))));
         // verify that the new repository data has the new snapshot and its indices
         assertTrue(newRepoData.getSnapshotIds().contains(newSnapshot));
         for (IndexId indexId : indices) {
@@ -122,13 +125,14 @@ public class RepositoryDataTests extends ESTestCase {
     public void testInitIndices() {
         final int numSnapshots = randomIntBetween(1, 30);
         final Map<String, SnapshotId> snapshotIds = new HashMap<>(numSnapshots);
-        final Map<String, SnapshotState> snapshotStates = new HashMap<>(numSnapshots);
-        final Map<String, Version> snapshotVersions = new HashMap<>(numSnapshots);
+        final Map<String, RepositoryData.SnapshotDetails> snapshotsDetails = new HashMap<>(numSnapshots);
         for (int i = 0; i < numSnapshots; i++) {
             final SnapshotId snapshotId = new SnapshotId(randomAlphaOfLength(8), UUIDs.randomBase64UUID());
             snapshotIds.put(snapshotId.getUUID(), snapshotId);
-            snapshotStates.put(snapshotId.getUUID(), randomFrom(SnapshotState.values()));
-            snapshotVersions.put(snapshotId.getUUID(), randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()));
+            snapshotsDetails.put(snapshotId.getUUID(),
+                    new RepositoryData.SnapshotDetails(
+                            randomFrom(SnapshotState.values()),
+                            randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion())));
         }
         RepositoryData repositoryData = new RepositoryData(
                 MISSING_UUID,
@@ -136,7 +140,6 @@ public class RepositoryDataTests extends ESTestCase {
                 snapshotIds,
                 Collections.emptyMap(),
                 Collections.emptyMap(),
-                Collections.emptyMap(),
                 ShardGenerations.EMPTY,
                 IndexMetaDataGenerations.EMPTY,
                 MISSING_UUID);
@@ -146,8 +149,7 @@ public class RepositoryDataTests extends ESTestCase {
                 UUIDs.randomBase64UUID(random()),
                 repositoryData.getGenId(),
                 snapshotIds,
-                snapshotStates,
-                snapshotVersions,
+                snapshotsDetails,
                 indices,
                 ShardGenerations.EMPTY,
                 IndexMetaDataGenerations.EMPTY,
@@ -188,9 +190,12 @@ public class RepositoryDataTests extends ESTestCase {
     public void testGetSnapshotState() {
         final SnapshotId snapshotId = new SnapshotId(randomAlphaOfLength(8), UUIDs.randomBase64UUID());
         final SnapshotState state = randomFrom(SnapshotState.values());
-        final RepositoryData repositoryData =
-            RepositoryData.EMPTY.addSnapshot(snapshotId, state, randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()),
-                ShardGenerations.EMPTY, Collections.emptyMap(), Collections.emptyMap());
+        final RepositoryData repositoryData = RepositoryData.EMPTY.addSnapshot(
+                snapshotId,
+                new RepositoryData.SnapshotDetails(state, randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion())),
+                ShardGenerations.EMPTY,
+                Collections.emptyMap(),
+                Collections.emptyMap());
         assertEquals(state, repositoryData.getSnapshotState(snapshotId));
         assertNull(repositoryData.getSnapshotState(new SnapshotId(randomAlphaOfLength(8), UUIDs.randomBase64UUID())));
     }
@@ -208,12 +213,12 @@ public class RepositoryDataTests extends ESTestCase {
         assertEquals(repositoryData, parsedRepositoryData);
 
         Map<String, SnapshotId> snapshotIds = new HashMap<>();
-        Map<String, SnapshotState> snapshotStates = new HashMap<>();
-        Map<String, Version> snapshotVersions = new HashMap<>();
+        Map<String, RepositoryData.SnapshotDetails> snapshotsDetails = new HashMap<>();
         for (SnapshotId snapshotId : parsedRepositoryData.getSnapshotIds()) {
             snapshotIds.put(snapshotId.getUUID(), snapshotId);
-            snapshotStates.put(snapshotId.getUUID(), parsedRepositoryData.getSnapshotState(snapshotId));
-            snapshotVersions.put(snapshotId.getUUID(), parsedRepositoryData.getVersion(snapshotId));
+            snapshotsDetails.put(snapshotId.getUUID(),
+                    new RepositoryData.SnapshotDetails(
+                            parsedRepositoryData.getSnapshotState(snapshotId), parsedRepositoryData.getVersion(snapshotId)));
         }
 
         final IndexId corruptedIndexId = randomFrom(parsedRepositoryData.getIndices().values());
@@ -238,8 +243,7 @@ public class RepositoryDataTests extends ESTestCase {
                 parsedRepositoryData.getUuid(),
                 parsedRepositoryData.getGenId(),
                 snapshotIds,
-                snapshotStates,
-                snapshotVersions,
+                snapshotsDetails,
                 indexSnapshots,
                 shardGenBuilder.build(),
                 IndexMetaDataGenerations.EMPTY,
@@ -336,8 +340,8 @@ public class RepositoryDataTests extends ESTestCase {
         indexLookup.putAll(newIndices);
         final SnapshotId newSnapshot = new SnapshotId(randomAlphaOfLength(7), UUIDs.randomBase64UUID(random()));
 
-        RepositoryData newRepoData =
-            repositoryData.addSnapshot(newSnapshot, SnapshotState.SUCCESS, Version.CURRENT, shardGenerations, indexLookup, newIdentifiers);
+        final RepositoryData.SnapshotDetails details = new RepositoryData.SnapshotDetails(SnapshotState.SUCCESS, Version.CURRENT);
+        final RepositoryData newRepoData = repositoryData.addSnapshot(newSnapshot, details, shardGenerations, indexLookup, newIdentifiers);
         assertEquals(newRepoData.indexMetaDataToRemoveAfterRemovingSnapshots(Collections.singleton(newSnapshot)),
                 newIndices.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
                         e -> Collections.singleton(newIdentifiers.get(e.getValue())))));
@@ -385,8 +389,10 @@ public class RepositoryDataTests extends ESTestCase {
             final Map<IndexId, String> indexLookup =
                 someIndices.stream().collect(Collectors.toMap(Function.identity(), ind -> randomAlphaOfLength(256)));
             repositoryData = repositoryData.addSnapshot(
-                snapshotId, randomFrom(SnapshotState.values()),
-                randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()),
+                snapshotId,
+                new RepositoryData.SnapshotDetails(
+                        randomFrom(SnapshotState.values()),
+                        randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion())),
                 builder.build(),
                 indexLookup,
                 indexLookup.values().stream().collect(Collectors.toMap(Function.identity(), ignored -> UUIDs.randomBase64UUID(random()))));

+ 7 - 2
server/src/test/java/org/elasticsearch/repositories/blobstore/BlobStoreRepositoryTests.java

@@ -254,8 +254,13 @@ public class BlobStoreRepositoryTests extends ESSingleNodeTestCase {
             final ShardGenerations shardGenerations = builder.build();
             final Map<IndexId, String> indexLookup =
                 shardGenerations.indices().stream().collect(Collectors.toMap(Function.identity(), ind -> randomAlphaOfLength(256)));
-            repoData = repoData.addSnapshot(snapshotId,
-                randomFrom(SnapshotState.SUCCESS, SnapshotState.PARTIAL, SnapshotState.FAILED), Version.CURRENT, shardGenerations,
+            final RepositoryData.SnapshotDetails details = new RepositoryData.SnapshotDetails(
+                    randomFrom(SnapshotState.SUCCESS, SnapshotState.PARTIAL, SnapshotState.FAILED),
+                    Version.CURRENT);
+            repoData = repoData.addSnapshot(
+                snapshotId,
+                details,
+                shardGenerations,
                 indexLookup,
                 indexLookup.values().stream().collect(Collectors.toMap(Function.identity(), ignored -> UUIDs.randomBase64UUID(random()))));
         }

+ 0 - 1
test/framework/src/main/java/org/elasticsearch/index/shard/RestoreOnlyRepository.java

@@ -88,7 +88,6 @@ public abstract class RestoreOnlyRepository extends AbstractLifecycleComponent i
                 EMPTY_REPO_GEN,
                 Collections.emptyMap(),
                 Collections.emptyMap(),
-                Collections.emptyMap(),
                 Collections.singletonMap(indexId, emptyList()),
                 ShardGenerations.EMPTY,
                 IndexMetaDataGenerations.EMPTY,

+ 3 - 6
x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/repository/CcrRepository.java

@@ -246,8 +246,7 @@ public class CcrRepository extends AbstractLifecycleComponent implements Reposit
             Metadata remoteMetadata = response.getState().getMetadata();
 
             Map<String, SnapshotId> copiedSnapshotIds = new HashMap<>();
-            Map<String, SnapshotState> snapshotStates = new HashMap<>(copiedSnapshotIds.size());
-            Map<String, Version> snapshotVersions = new HashMap<>(copiedSnapshotIds.size());
+            Map<String, RepositoryData.SnapshotDetails> snapshotsDetails = new HashMap<>(copiedSnapshotIds.size());
             Map<IndexId, List<SnapshotId>> indexSnapshots = new HashMap<>(copiedSnapshotIds.size());
 
             ImmutableOpenMap<String, IndexMetadata> remoteIndices = remoteMetadata.getIndices();
@@ -255,8 +254,7 @@ public class CcrRepository extends AbstractLifecycleComponent implements Reposit
                 // Both the Snapshot name and UUID are set to _latest_
                 SnapshotId snapshotId = new SnapshotId(LATEST, LATEST);
                 copiedSnapshotIds.put(indexName, snapshotId);
-                snapshotStates.put(indexName, SnapshotState.SUCCESS);
-                snapshotVersions.put(indexName, Version.CURRENT);
+                snapshotsDetails.put(indexName, new RepositoryData.SnapshotDetails(SnapshotState.SUCCESS, Version.CURRENT));
                 Index index = remoteIndices.get(indexName).getIndex();
                 indexSnapshots.put(new IndexId(indexName, index.getUUID()), Collections.singletonList(snapshotId));
             }
@@ -264,8 +262,7 @@ public class CcrRepository extends AbstractLifecycleComponent implements Reposit
                     MISSING_UUID,
                     1,
                     copiedSnapshotIds,
-                    snapshotStates,
-                    snapshotVersions,
+                    snapshotsDetails,
                     indexSnapshots,
                     ShardGenerations.EMPTY,
                     IndexMetaDataGenerations.EMPTY,