|
@@ -48,6 +48,7 @@ import org.elasticsearch.cluster.metadata.IndexMetadata;
|
|
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
|
import org.elasticsearch.cluster.metadata.Metadata;
|
|
|
import org.elasticsearch.cluster.metadata.RepositoriesMetadata;
|
|
|
+import org.elasticsearch.cluster.metadata.RepositoryMetadata;
|
|
|
import org.elasticsearch.cluster.node.DiscoveryNode;
|
|
|
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
|
|
import org.elasticsearch.cluster.routing.IndexRoutingTable;
|
|
@@ -294,7 +295,7 @@ public class SnapshotsService extends AbstractLifecycleComponent implements Clus
|
|
|
featureStatesSet = Collections.emptySet();
|
|
|
}
|
|
|
|
|
|
- repository.executeConsistentStateUpdate(repositoryData -> new ClusterStateUpdateTask(request.masterNodeTimeout()) {
|
|
|
+ executeConsistentStateUpdate(repository, repositoryData -> new ClusterStateUpdateTask(request.masterNodeTimeout()) {
|
|
|
|
|
|
private SnapshotsInProgress.Entry newEntry;
|
|
|
|
|
@@ -462,7 +463,7 @@ public class SnapshotsService extends AbstractLifecycleComponent implements Clus
|
|
|
final SnapshotId snapshotId = new SnapshotId(snapshotName, UUIDs.randomBase64UUID());
|
|
|
final Snapshot snapshot = new Snapshot(repositoryName, snapshotId);
|
|
|
initializingClones.add(snapshot);
|
|
|
- repository.executeConsistentStateUpdate(repositoryData -> new ClusterStateUpdateTask(request.masterNodeTimeout()) {
|
|
|
+ executeConsistentStateUpdate(repository, repositoryData -> new ClusterStateUpdateTask(request.masterNodeTimeout()) {
|
|
|
|
|
|
private SnapshotsInProgress.Entry newEntry;
|
|
|
|
|
@@ -627,7 +628,7 @@ public class SnapshotsService extends AbstractLifecycleComponent implements Clus
|
|
|
}, onFailure);
|
|
|
|
|
|
// 3. step, we have all the shard counts, now update the cluster state to have clone jobs in the snap entry
|
|
|
- allShardCountsListener.whenComplete(counts -> repository.executeConsistentStateUpdate(repoData -> new ClusterStateUpdateTask() {
|
|
|
+ allShardCountsListener.whenComplete(counts -> executeConsistentStateUpdate(repository, repoData -> new ClusterStateUpdateTask() {
|
|
|
|
|
|
private SnapshotsInProgress.Entry updatedEntry;
|
|
|
|
|
@@ -2066,7 +2067,7 @@ public class SnapshotsService extends AbstractLifecycleComponent implements Clus
|
|
|
);
|
|
|
|
|
|
final Repository repository = repositoriesService.repository(repositoryName);
|
|
|
- repository.executeConsistentStateUpdate(repositoryData -> new ClusterStateUpdateTask(request.masterNodeTimeout()) {
|
|
|
+ executeConsistentStateUpdate(repository, repositoryData -> new ClusterStateUpdateTask(request.masterNodeTimeout()) {
|
|
|
|
|
|
private SnapshotDeletionsInProgress.Entry newDelete = null;
|
|
|
|
|
@@ -2399,6 +2400,72 @@ public class SnapshotsService extends AbstractLifecycleComponent implements Clus
|
|
|
clusterService.submitUnbatchedStateUpdateTask(source, task);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Execute a cluster state update with a consistent view of the current {@link RepositoryData}. The {@link ClusterState} passed to the
|
|
|
+ * task generated through {@code createUpdateTask} is guaranteed to point at the same state for this repository as the did the state
|
|
|
+ * at the time the {@code RepositoryData} was loaded.
|
|
|
+ * This allows for operations on the repository that need a consistent view of both the cluster state and the repository contents at
|
|
|
+ * one point in time like for example, checking if a snapshot is in the repository before adding the delete operation for it to the
|
|
|
+ * cluster state.
|
|
|
+ *
|
|
|
+ * @param repository repository to execute update for
|
|
|
+ * @param createUpdateTask function to supply cluster state update task
|
|
|
+ * @param source the source of the cluster state update task
|
|
|
+ * @param onFailure error handler invoked on failure to get a consistent view of the current {@link RepositoryData}
|
|
|
+ */
|
|
|
+ private void executeConsistentStateUpdate(
|
|
|
+ Repository repository,
|
|
|
+ Function<RepositoryData, ClusterStateUpdateTask> createUpdateTask,
|
|
|
+ String source,
|
|
|
+ Consumer<Exception> onFailure
|
|
|
+ ) {
|
|
|
+ final RepositoryMetadata repositoryMetadataStart = repository.getMetadata();
|
|
|
+ repository.getRepositoryData(ActionListener.wrap(repositoryData -> {
|
|
|
+ final ClusterStateUpdateTask updateTask = createUpdateTask.apply(repositoryData);
|
|
|
+ submitUnbatchedTask(source, new ClusterStateUpdateTask(updateTask.priority(), updateTask.timeout()) {
|
|
|
+
|
|
|
+ private boolean executedTask = false;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ClusterState execute(ClusterState currentState) throws Exception {
|
|
|
+ // Comparing the full metadata here on purpose instead of simply comparing the safe generation.
|
|
|
+ // If the safe generation has changed, then we have to reload repository data and start over.
|
|
|
+ // If the pending generation has changed we are in the midst of a write operation and might pick up the
|
|
|
+ // updated repository data and state on the retry. We don't want to wait for the write to finish though
|
|
|
+ // because it could fail for any number of reasons so we just retry instead of waiting on the cluster state
|
|
|
+ // to change in any form.
|
|
|
+ if (repositoryMetadataStart.equals(
|
|
|
+ currentState.getMetadata()
|
|
|
+ .<RepositoriesMetadata>custom(RepositoriesMetadata.TYPE)
|
|
|
+ .repository(repository.getMetadata().name())
|
|
|
+ )) {
|
|
|
+ executedTask = true;
|
|
|
+ return updateTask.execute(currentState);
|
|
|
+ }
|
|
|
+ return currentState;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onFailure(Exception e) {
|
|
|
+ if (executedTask) {
|
|
|
+ updateTask.onFailure(e);
|
|
|
+ } else {
|
|
|
+ onFailure.accept(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void clusterStateProcessed(ClusterState oldState, ClusterState newState) {
|
|
|
+ if (executedTask) {
|
|
|
+ updateTask.clusterStateProcessed(oldState, newState);
|
|
|
+ } else {
|
|
|
+ executeConsistentStateUpdate(repository, createUpdateTask, source, onFailure);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }, onFailure));
|
|
|
+ }
|
|
|
+
|
|
|
/** Deletes snapshot from repository
|
|
|
*
|
|
|
* @param deleteEntry delete entry in cluster state
|