Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clone Snapshot API #61839

Merged
Merged
Show file tree
Hide file tree
Changes from 154 commits
Commits
Show all changes
157 commits
Select commit Hold shift + click to select a range
87d721e
bck
original-brownbear Aug 3, 2020
4ae3119
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 3, 2020
d84264d
Clone snapshot API start
original-brownbear Aug 3, 2020
f6d287e
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 3, 2020
38da49a
works
original-brownbear Aug 3, 2020
988490b
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 3, 2020
b4be1f6
r/w
original-brownbear Aug 3, 2020
2e3fbcc
bck
original-brownbear Aug 3, 2020
28d6e97
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 4, 2020
eb7b620
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 5, 2020
cf5d199
fix
original-brownbear Aug 5, 2020
bf0671f
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 5, 2020
6a06ae8
progress
original-brownbear Aug 5, 2020
789a07d
bck
original-brownbear Aug 5, 2020
9218b62
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 6, 2020
9647e44
fix
original-brownbear Aug 6, 2020
41463b6
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 10, 2020
e140322
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 10, 2020
ddbcb23
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 11, 2020
f662c47
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 11, 2020
e95a9e2
bck
original-brownbear Aug 11, 2020
bf6ec96
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 11, 2020
1c13596
bck
original-brownbear Aug 11, 2020
4d816e3
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 12, 2020
e01a58e
bck
original-brownbear Aug 12, 2020
c319448
bck
original-brownbear Aug 30, 2020
4c754d1
bck
original-brownbear Aug 30, 2020
fc3fd52
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 30, 2020
6d18df3
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 31, 2020
617ee9b
bck
original-brownbear Aug 31, 2020
c1d9e93
bck
original-brownbear Aug 31, 2020
5a9ce25
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Aug 31, 2020
7b52722
bck
original-brownbear Aug 31, 2020
214901f
worksish
original-brownbear Aug 31, 2020
5b14bd4
bck
original-brownbear Aug 31, 2020
c125348
bck
original-brownbear Aug 31, 2020
a56e826
bck
original-brownbear Aug 31, 2020
bdac60a
bck
original-brownbear Aug 31, 2020
82808e5
better
original-brownbear Aug 31, 2020
95638b2
bck
original-brownbear Aug 31, 2020
862e8ca
green
original-brownbear Aug 31, 2020
c882c9f
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 1, 2020
8494701
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 1, 2020
19e6e7b
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 1, 2020
ecd821d
bck
original-brownbear Sep 1, 2020
0eb072d
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 1, 2020
8a74150
bck
original-brownbear Sep 1, 2020
ec4b167
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 1, 2020
b1b950e
clone prevents delete
original-brownbear Sep 1, 2020
2090a54
delete prevents clone
original-brownbear Sep 1, 2020
24dfb6c
bck
original-brownbear Sep 1, 2020
087f522
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 2, 2020
e363042
bck
original-brownbear Sep 2, 2020
4c6b0d5
cleanup rest action
original-brownbear Sep 2, 2020
daeb2fa
shorter diff
original-brownbear Sep 2, 2020
6999ea2
bck
original-brownbear Sep 2, 2020
4658086
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 2, 2020
94ba717
docs test
original-brownbear Sep 2, 2020
96f2617
one more case handled
original-brownbear Sep 2, 2020
09de3d6
error handling
original-brownbear Sep 2, 2020
33012dc
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 2, 2020
a50e506
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 2, 2020
d2c47f8
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 2, 2020
0f61e83
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 3, 2020
9db152f
more fixes
original-brownbear Sep 3, 2020
10b3516
last one?
original-brownbear Sep 3, 2020
1cf9a67
bck
original-brownbear Sep 3, 2020
d962226
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 5, 2020
e3dfef3
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 7, 2020
a06ee9d
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 7, 2020
a51f0a3
fix state machine
original-brownbear Sep 7, 2020
6f149f7
optimize
original-brownbear Sep 7, 2020
52020af
better not great
original-brownbear Sep 7, 2020
8a8f985
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 10, 2020
aab9077
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 12, 2020
176fb7d
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 13, 2020
5b7b795
mroe efficient
original-brownbear Sep 14, 2020
b756cc2
fix
original-brownbear Sep 14, 2020
0f71f8b
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 14, 2020
1059222
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 15, 2020
b26c47c
fix
original-brownbear Sep 15, 2020
13d4b98
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 15, 2020
ab787bd
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 15, 2020
6bf7bc0
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 15, 2020
1defbd5
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 15, 2020
f7d2588
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 15, 2020
87e1c3d
Merge branch 'master' of github.com:elastic/elasticsearch into clone-…
original-brownbear Sep 15, 2020
ad4d438
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 15, 2020
f04e0d1
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 16, 2020
c0027c2
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 17, 2020
d2dc4f8
reproducer
original-brownbear Sep 17, 2020
225cac0
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 17, 2020
43242d8
fix master failover part 1
original-brownbear Sep 17, 2020
4f6eec8
fix master failover part 2
original-brownbear Sep 17, 2020
c01ebbc
nicer
original-brownbear Sep 17, 2020
9c1d38c
nicer
original-brownbear Sep 17, 2020
c011f13
cleaner
original-brownbear Sep 17, 2020
51bfc4a
fix more edge cases
original-brownbear Sep 17, 2020
cf5dc89
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 17, 2020
7eb9762
shorter
original-brownbear Sep 17, 2020
ae3f108
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 17, 2020
1f9d701
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 20, 2020
f1bf399
fix docs?
original-brownbear Sep 20, 2020
eed6214
remove settings for now
original-brownbear Sep 20, 2020
06ce72d
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 21, 2020
55b2d84
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 21, 2020
95ffa6f
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 22, 2020
30e623b
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 28, 2020
72a7f4b
less noise
original-brownbear Sep 28, 2020
9141f37
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 29, 2020
c0504fb
remove noisy changes
original-brownbear Sep 29, 2020
157ec27
reduce noise
original-brownbear Sep 29, 2020
56779b4
align style
original-brownbear Sep 29, 2020
d504a4e
align style
original-brownbear Sep 29, 2020
ad43cea
making things look nicer
original-brownbear Sep 29, 2020
1a4f1f9
drier
original-brownbear Sep 29, 2020
911457a
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 29, 2020
0a15e5d
drier
original-brownbear Sep 29, 2020
c3ae02d
nicer
original-brownbear Sep 29, 2020
80facac
make some things nicer
original-brownbear Sep 29, 2020
75821af
add validation
original-brownbear Sep 29, 2020
9d4c348
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 30, 2020
3b5b057
less noisy
original-brownbear Sep 30, 2020
9c73e11
less noise
original-brownbear Sep 30, 2020
0cccd4e
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 30, 2020
6942a0f
cleaner
original-brownbear Sep 30, 2020
c941042
safer
original-brownbear Sep 30, 2020
855a1cb
better docs
original-brownbear Sep 30, 2020
de8ca37
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 30, 2020
78e3110
better
original-brownbear Sep 30, 2020
38d56ea
better
original-brownbear Sep 30, 2020
f0c7df1
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 30, 2020
db3e957
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Sep 30, 2020
e0d3815
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Oct 1, 2020
7266d3e
nicer
original-brownbear Oct 1, 2020
ec76593
simpler diff
original-brownbear Oct 1, 2020
631df59
fix
original-brownbear Oct 1, 2020
e7bd833
TODO
original-brownbear Oct 1, 2020
3c5f8cd
tests are hard
original-brownbear Oct 1, 2020
6ba89cb
fix doc
original-brownbear Oct 1, 2020
2432ab2
fix doc
original-brownbear Oct 1, 2020
bdd6943
include global metadata
original-brownbear Oct 1, 2020
6d6c592
fix indent
original-brownbear Oct 1, 2020
900eaba
fix indent
original-brownbear Oct 1, 2020
468359d
add assertion
original-brownbear Oct 1, 2020
60df5f9
isCLone
original-brownbear Oct 1, 2020
ad9fe18
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Oct 1, 2020
df09e3e
some UTs
original-brownbear Oct 1, 2020
c8d5961
moar UTs
original-brownbear Oct 2, 2020
4c2a212
even moar tests
original-brownbear Oct 2, 2020
3b1085f
even moar tests (80% cov)
original-brownbear Oct 2, 2020
208985e
full coverage
original-brownbear Oct 2, 2020
5316fc3
shorter
original-brownbear Oct 2, 2020
6e5b74b
IT
original-brownbear Oct 2, 2020
c5f3bd5
Update server/src/main/java/org/elasticsearch/snapshots/SnapshotsServ…
original-brownbear Oct 2, 2020
2a5a226
Merge remote-tracking branch 'elastic/master' into clone-snapshot-on-…
original-brownbear Oct 2, 2020
6ad3552
gotta fix message in tests as well
original-brownbear Oct 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions docs/reference/snapshot-restore/apis/clone-snapshot-api.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[[clone-snapshot-api]]
=== Clone snapshot API
++++
<titleabbrev>Clone snapshot</titleabbrev>
++++

Clones part or all of a snapshot into a new snapshot.

[source,console]
----
PUT /_snapshot/my_repository/source_snapshot/_clone/target_snapshot
{
"indices": "index_a,index_b"
}
----
// TEST[skip:TODO]

[[clone-snapshot-api-request]]
==== {api-request-title}

`PUT /_snapshot/<repository>/<source_snapshot>/_clone/<target_snapshot>`

[[clone-snapshot-api-desc]]
==== {api-description-title}

The clone snapshot API allows creating a copy of all or part of an existing snapshot
within the same repository.

[[clone-snapshot-api-params]]
==== {api-path-parms-title}

`<repository>`::
(Required, string)
Name of the snapshot repository that both source and target snapshot belong to.

[[clone-snapshot-api-query-params]]
==== {api-query-parms-title}

`master_timeout`::
(Optional, <<time-units, time units>>) Specifies the period of time to wait for
a connection to the master node. If no response is received before the timeout
expires, the request fails and returns an error. Defaults to `30s`.

`timeout`::
(Optional, <<time-units, time units>>) Specifies the period of time to wait for
a response. If no response is received before the timeout expires, the request
fails and returns an error. Defaults to `30s`.

`indices`::
(Required, string)
A comma-separated list of indices to include in the snapshot.
<<multi-index,Multi-index syntax>> is supported.
1 change: 1 addition & 0 deletions docs/reference/snapshot-restore/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ understand the time requirements before proceeding.
--

include::register-repository.asciidoc[]
include::apis/clone-snapshot-api.asciidoc[]
include::take-snapshot.asciidoc[]
include::restore-snapshot.asciidoc[]
include::monitor-snapshot-restore.asciidoc[]
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/snapshot-restore/take-snapshot.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,5 @@ PUT /_snapshot/my_backup/<snapshot-{now/d}>
PUT /_snapshot/my_backup/%3Csnapshot-%7Bnow%2Fd%7D%3E
-----------------------------------
// TEST[continued]

NOTE: You can also create snapshots that are copies of part of an existing snapshot using the <<clone-snapshot-api,clone snapshot API>>.
tlrx marked this conversation as resolved.
Show resolved Hide resolved

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -1293,11 +1293,6 @@ private ActionFuture<CreateSnapshotResponse> startFullSnapshotFromMasterClient(S
.setWaitForCompletion(true).execute();
}

// Large snapshot pool settings to set up nodes for tests involving multiple repositories that need to have enough
// threads so that blocking some threads on one repository doesn't block other repositories from doing work
private static final Settings LARGE_SNAPSHOT_POOL_SETTINGS = Settings.builder()
.put("thread_pool.snapshot.core", 5).put("thread_pool.snapshot.max", 5).build();

private void createIndexWithContent(String indexName, String nodeInclude, String nodeExclude) {
createIndexWithContent(indexName, indexSettingsNoReplicas(1)
.put("index.routing.allocation.include._name", nodeInclude)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ protected ClusterBlockException checkBlock(CloneSnapshotRequest request, Cluster
@Override
protected void masterOperation(Task task, final CloneSnapshotRequest request, ClusterState state,
final ActionListener<AcknowledgedResponse> listener) {
throw new UnsupportedOperationException("not implemented yet");
snapshotsService.cloneSnapshot(request, ActionListener.map(listener, v -> new AcknowledgedResponse(true)));
}
}
133 changes: 123 additions & 10 deletions server/src/main/java/org/elasticsearch/cluster/SnapshotsInProgress.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.repositories.IndexId;
import org.elasticsearch.repositories.RepositoryShardId;
import org.elasticsearch.repositories.RepositoryOperation;
import org.elasticsearch.snapshots.Snapshot;
import org.elasticsearch.snapshots.SnapshotId;
import org.elasticsearch.snapshots.SnapshotsService;

import java.io.IOException;
import java.util.Collections;
Expand Down Expand Up @@ -96,18 +99,52 @@ public static Entry startedEntry(Snapshot snapshot, boolean includeGlobalState,
indices, dataStreams, startTime, repositoryStateId, shards, null, userMetadata, version);
}

/**
* Creates the initial snapshot clone entry
*
* @param snapshot snapshot to clone into
* @param source snapshot to clone from
* @param indices indices to clone
* @param startTime start time
* @param repositoryStateId repository state id that this clone is based on
* @param version repository metadata version to write
* @return snapshot clone entry
*/
public static Entry startClone(Snapshot snapshot, SnapshotId source, List<IndexId> indices, long startTime,
long repositoryStateId, Version version) {
return new SnapshotsInProgress.Entry(snapshot, true, false, State.STARTED, indices, Collections.emptyList(),
startTime, repositoryStateId, ImmutableOpenMap.of(), null, Collections.emptyMap(), version, source,
ImmutableOpenMap.of());
}

public static class Entry implements Writeable, ToXContent, RepositoryOperation {
private final State state;
private final Snapshot snapshot;
private final boolean includeGlobalState;
private final boolean partial;
/**
* Map of {@link ShardId} to {@link ShardSnapshotStatus} tracking the state of each shard snapshot operation.
*/
private final ImmutableOpenMap<ShardId, ShardSnapshotStatus> shards;
private final List<IndexId> indices;
private final List<String> dataStreams;
private final long startTime;
private final long repositoryStateId;
// see #useShardGenerations
private final Version version;

/**
* Source snapshot if this is a clone operation or {@code null} if this is a snapshot.
*/
@Nullable
private final SnapshotId source;

/**
* Map of {@link RepositoryShardId} to {@link ShardSnapshotStatus} tracking the state of each shard clone operation in this entry
* the same way {@link #shards} tracks the status of each shard snapshot operation in non-clone entries.
*/
private final ImmutableOpenMap<RepositoryShardId, ShardSnapshotStatus> clones;

@Nullable private final Map<String, Object> userMetadata;
@Nullable private final String failure;

Expand All @@ -116,6 +153,15 @@ public Entry(Snapshot snapshot, boolean includeGlobalState, boolean partial, Sta
List<String> dataStreams, long startTime, long repositoryStateId,
ImmutableOpenMap<ShardId, ShardSnapshotStatus> shards, String failure, Map<String, Object> userMetadata,
Version version) {
this(snapshot, includeGlobalState, partial, state, indices, dataStreams, startTime, repositoryStateId, shards, failure,
userMetadata, version, null, ImmutableOpenMap.of());
}

private Entry(Snapshot snapshot, boolean includeGlobalState, boolean partial, State state, List<IndexId> indices,
List<String> dataStreams, long startTime, long repositoryStateId,
ImmutableOpenMap<ShardId, ShardSnapshotStatus> shards, String failure, Map<String, Object> userMetadata,
Version version, @Nullable SnapshotId source,
@Nullable ImmutableOpenMap<RepositoryShardId, ShardSnapshotStatus> clones) {
this.state = state;
this.snapshot = snapshot;
this.includeGlobalState = includeGlobalState;
Expand All @@ -124,11 +170,18 @@ public Entry(Snapshot snapshot, boolean includeGlobalState, boolean partial, Sta
this.dataStreams = dataStreams;
this.startTime = startTime;
this.shards = shards;
assert assertShardsConsistent(state, indices, shards);
this.repositoryStateId = repositoryStateId;
this.failure = failure;
this.userMetadata = userMetadata;
this.version = version;
this.source = source;
if (source == null) {
assert clones == null || clones.isEmpty() : "Provided [" + clones + "] but no source";
this.clones = ImmutableOpenMap.of();
} else {
this.clones = clones;
}
assert assertShardsConsistent(this.source, this.state, this.indices, this.shards, this.clones);
}

private Entry(StreamInput in) throws IOException {
Expand All @@ -144,29 +197,59 @@ private Entry(StreamInput in) throws IOException {
userMetadata = in.readMap();
version = Version.readVersion(in);
dataStreams = in.readStringList();
if (in.getVersion().onOrAfter(SnapshotsService.CLONE_SNAPSHOT_VERSION)) {
source = in.readOptionalWriteable(SnapshotId::new);
clones = in.readImmutableMap(RepositoryShardId::new, ShardSnapshotStatus::readFrom);
} else {
source = null;
clones = ImmutableOpenMap.of();
}
}

private static boolean assertShardsConsistent(State state, List<IndexId> indices,
ImmutableOpenMap<ShardId, ShardSnapshotStatus> shards) {
private static boolean assertShardsConsistent(SnapshotId source, State state, List<IndexId> indices,
ImmutableOpenMap<ShardId, ShardSnapshotStatus> shards,
ImmutableOpenMap<RepositoryShardId, ShardSnapshotStatus> clones) {
if ((state == State.INIT || state == State.ABORTED) && shards.isEmpty()) {
return true;
}
final Set<String> indexNames = indices.stream().map(IndexId::getName).collect(Collectors.toSet());
final Set<String> indexNamesInShards = new HashSet<>();
shards.keysIt().forEachRemaining(s -> indexNamesInShards.add(s.getIndexName()));
assert indexNames.equals(indexNamesInShards)
shards.iterator().forEachRemaining(s -> {
indexNamesInShards.add(s.key.getIndexName());
assert source == null || s.value.nodeId == null :
"Shard snapshot must not be assigned to data node when copying from snapshot [" + source + "]";
});
assert source == null || indexNames.isEmpty() == false : "No empty snapshot clones allowed";
assert source != null || indexNames.equals(indexNamesInShards)
: "Indices in shards " + indexNamesInShards + " differ from expected indices " + indexNames + " for state [" + state + "]";
final boolean shardsCompleted = completed(shards.values());
assert (state.completed() && shardsCompleted) || (state.completed() == false && shardsCompleted == false)
: "Completed state must imply all shards completed but saw state [" + state + "] and shards " + shards;
final boolean shardsCompleted = completed(shards.values()) && completed(clones.values());
// Check state consistency for normal snapshots and started clone operations
if (source == null || clones.isEmpty() == false) {
assert (state.completed() && shardsCompleted) || (state.completed() == false && shardsCompleted == false)
: "Completed state must imply all shards completed but saw state [" + state + "] and shards " + shards;
}
if (source != null && state.completed()) {
assert hasFailures(clones) == false || state == State.FAILED
: "Failed shard clones in [" + clones + "] but state was [" + state + "]";
}
return true;
}

public Entry withRepoGen(long newRepoGen) {
assert newRepoGen > repositoryStateId : "Updated repository generation [" + newRepoGen
+ "] must be higher than current generation [" + repositoryStateId + "]";
return new Entry(snapshot, includeGlobalState, partial, state, indices, dataStreams, startTime, newRepoGen, shards, failure,
userMetadata, version);
userMetadata, version, source, clones);
}

public Entry withClones(ImmutableOpenMap<RepositoryShardId, ShardSnapshotStatus> updatedClones) {
if (updatedClones.equals(clones)) {
return this;
}
return new Entry(snapshot, includeGlobalState, partial,
completed(updatedClones.values()) ? (hasFailures(updatedClones) ? State.FAILED : State.SUCCESS) :
state, indices, dataStreams, startTime, repositoryStateId, shards, failure, userMetadata, version, source,
updatedClones);
}

/**
Expand Down Expand Up @@ -203,7 +286,7 @@ public Entry abort() {

public Entry fail(ImmutableOpenMap<ShardId, ShardSnapshotStatus> shards, State state, String failure) {
return new Entry(snapshot, includeGlobalState, partial, state, indices, dataStreams, startTime, repositoryStateId, shards,
failure, userMetadata, version);
failure, userMetadata, version, source, clones);
}

/**
Expand Down Expand Up @@ -291,6 +374,19 @@ public Version version() {
return version;
}

@Nullable
public SnapshotId source() {
return source;
}

public boolean isClone() {
return source != null;
}

public ImmutableOpenMap<RepositoryShardId, ShardSnapshotStatus> clones() {
return clones;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -307,6 +403,8 @@ public boolean equals(Object o) {
if (state != entry.state) return false;
if (repositoryStateId != entry.repositoryStateId) return false;
if (version.equals(entry.version) == false) return false;
if (Objects.equals(source, ((Entry) o).source) == false) return false;
if (clones.equals(((Entry) o).clones) == false) return false;

return true;
}
Expand All @@ -322,6 +420,8 @@ public int hashCode() {
result = 31 * result + Long.hashCode(startTime);
result = 31 * result + Long.hashCode(repositoryStateId);
result = 31 * result + version.hashCode();
result = 31 * result + (source == null ? 0 : source.hashCode());
result = 31 * result + clones.hashCode();
return result;
}

Expand Down Expand Up @@ -383,6 +483,10 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeMap(userMetadata);
Version.writeVersion(version, out);
out.writeStringCollection(dataStreams);
if (out.getVersion().onOrAfter(SnapshotsService.CLONE_SNAPSHOT_VERSION)) {
out.writeOptionalWriteable(source);
out.writeMap(clones);
}
}

@Override
Expand All @@ -406,6 +510,15 @@ public static boolean completed(ObjectContainer<ShardSnapshotStatus> shards) {
return true;
}

private static boolean hasFailures(ImmutableOpenMap<RepositoryShardId, ShardSnapshotStatus> clones) {
for (ObjectCursor<ShardSnapshotStatus> value : clones.values()) {
if (value.value.state().failed()) {
return true;
}
}
return false;
}

public static class ShardSnapshotStatus implements Writeable {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ private static void validateSnapshotRestorable(final String repository, final Sn
}
}

private static boolean failed(SnapshotInfo snapshot, String index) {
public static boolean failed(SnapshotInfo snapshot, String index) {
for (SnapshotShardFailure failure : snapshot.shardFailures()) {
if (index.equals(failure.index())) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ private void startNewSnapshots(SnapshotsInProgress snapshotsInProgress) {
final String localNodeId = clusterService.localNode().getId();
for (SnapshotsInProgress.Entry entry : snapshotsInProgress.entries()) {
final State entryState = entry.state();
if (entry.isClone()) {
// This is a snapshot clone, it will be executed on the current master
continue;
}
if (entryState == State.STARTED) {
Map<ShardId, IndexShardSnapshotStatus> startedShards = null;
final Snapshot snapshot = entry.snapshot();
Expand Down
Loading