Remove the Snapshot class in favor of using SnapshotInfo

o/e/snapshots/Snapshot and o/e/snapshots/SnapshotInfo contain the same
fields and represent the same information.  Snapshot was used to
maintain snapshot information to the snapshot repository, while
SnapshotInfo was used to represent the snapshot information as presented
through the REST layer.  This removes the Snapshot class and combines
all uses into the SnapshotInfo class.

Closes #18167
This commit is contained in:
Ali Beyad 2016-05-05 16:43:20 -04:00
parent 3912761572
commit c4090a1841
11 changed files with 305 additions and 519 deletions

View File

@ -778,7 +778,6 @@
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]suggest[/\\]phrase[/\\]WordScorer.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]suggest[/\\]term[/\\]TermSuggestParser.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]snapshots[/\\]RestoreService.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]snapshots[/\\]SnapshotInfo.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]snapshots[/\\]SnapshotShardFailure.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]snapshots[/\\]SnapshotShardsService.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]snapshots[/\\]SnapshotsService.java" checks="LineLength" />

View File

@ -57,13 +57,13 @@ public class CreateSnapshotResponse extends ActionResponse implements ToXContent
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
snapshotInfo = SnapshotInfo.readOptionalSnapshotInfo(in);
snapshotInfo = in.readOptionalWriteable(SnapshotInfo::new);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeOptionalStreamable(snapshotInfo);
out.writeOptionalWriteable(snapshotInfo);
}
/**
@ -90,7 +90,7 @@ public class CreateSnapshotResponse extends ActionResponse implements ToXContent
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (snapshotInfo != null) {
builder.field(Fields.SNAPSHOT);
snapshotInfo.toXContent(builder, params);
snapshotInfo.toExternalXContent(builder, params);
} else {
builder.field(Fields.ACCEPTED, true);
}

View File

@ -60,7 +60,7 @@ public class GetSnapshotsResponse extends ActionResponse implements ToXContent {
int size = in.readVInt();
List<SnapshotInfo> builder = new ArrayList<>();
for (int i = 0; i < size; i++) {
builder.add(SnapshotInfo.readSnapshotInfo(in));
builder.add(new SnapshotInfo(in));
}
snapshots = Collections.unmodifiableList(builder);
}
@ -82,7 +82,7 @@ public class GetSnapshotsResponse extends ActionResponse implements ToXContent {
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
builder.startArray(Fields.SNAPSHOTS);
for (SnapshotInfo snapshotInfo : snapshots) {
snapshotInfo.toXContent(builder, params);
snapshotInfo.toExternalXContent(builder, params);
}
builder.endArray();
return builder;

View File

@ -31,7 +31,6 @@ import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.snapshots.Snapshot;
import org.elasticsearch.snapshots.SnapshotInfo;
import org.elasticsearch.snapshots.SnapshotsService;
import org.elasticsearch.threadpool.ThreadPool;
@ -77,18 +76,12 @@ public class TransportGetSnapshotsAction extends TransportMasterNodeAction<GetSn
try {
List<SnapshotInfo> snapshotInfoBuilder = new ArrayList<>();
if (isAllSnapshots(request.snapshots())) {
List<Snapshot> snapshots = snapshotsService.snapshots(request.repository(), request.ignoreUnavailable());
for (Snapshot snapshot : snapshots) {
snapshotInfoBuilder.add(new SnapshotInfo(snapshot));
}
snapshotInfoBuilder.addAll(snapshotsService.snapshots(request.repository(), request.ignoreUnavailable()));
} else if (isCurrentSnapshots(request.snapshots())) {
List<Snapshot> snapshots = snapshotsService.currentSnapshots(request.repository());
for (Snapshot snapshot : snapshots) {
snapshotInfoBuilder.add(new SnapshotInfo(snapshot));
}
snapshotInfoBuilder.addAll(snapshotsService.currentSnapshots(request.repository()));
} else {
Set<String> snapshotsToGet = new LinkedHashSet<>(); // to keep insertion order
List<Snapshot> snapshots = null;
List<SnapshotInfo> snapshots = null;
for (String snapshotOrPattern : request.snapshots()) {
if (Regex.isSimpleMatchPattern(snapshotOrPattern) == false) {
snapshotsToGet.add(snapshotOrPattern);
@ -96,7 +89,7 @@ public class TransportGetSnapshotsAction extends TransportMasterNodeAction<GetSn
if (snapshots == null) { // lazily load snapshots
snapshots = snapshotsService.snapshots(request.repository(), request.ignoreUnavailable());
}
for (Snapshot snapshot : snapshots) {
for (SnapshotInfo snapshot : snapshots) {
if (Regex.simpleMatch(snapshotOrPattern, snapshot.name())) {
snapshotsToGet.add(snapshot.name());
}
@ -105,7 +98,7 @@ public class TransportGetSnapshotsAction extends TransportMasterNodeAction<GetSn
}
for (String snapshot : snapshotsToGet) {
SnapshotId snapshotId = new SnapshotId(request.repository(), snapshot);
snapshotInfoBuilder.add(new SnapshotInfo(snapshotsService.snapshot(snapshotId)));
snapshotInfoBuilder.add(snapshotsService.snapshot(snapshotId));
}
}
listener.onResponse(new GetSnapshotsResponse(Collections.unmodifiableList(snapshotInfoBuilder)));

View File

@ -36,7 +36,7 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.snapshots.IndexShardSnapshotStatus;
import org.elasticsearch.snapshots.Snapshot;
import org.elasticsearch.snapshots.SnapshotInfo;
import org.elasticsearch.snapshots.SnapshotsService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
@ -202,7 +202,7 @@ public class TransportSnapshotsStatusAction extends TransportMasterNodeAction<Sn
// This is a snapshot the is currently running - skipping
continue;
}
Snapshot snapshot = snapshotsService.snapshot(snapshotId);
SnapshotInfo snapshot = snapshotsService.snapshot(snapshotId);
List<SnapshotIndexShardStatus> shardStatusBuilder = new ArrayList<>();
if (snapshot.state().completed()) {
Map<ShardId, IndexShardSnapshotStatus> shardStatues = snapshotsService.snapshotShards(snapshotId);

View File

@ -24,7 +24,7 @@ import org.elasticsearch.cluster.metadata.SnapshotId;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.snapshots.IndexShardSnapshotStatus;
import org.elasticsearch.snapshots.Snapshot;
import org.elasticsearch.snapshots.SnapshotInfo;
import org.elasticsearch.snapshots.SnapshotShardFailure;
import java.io.IOException;
@ -54,7 +54,7 @@ public interface Repository extends LifecycleComponent<Repository> {
* @param snapshotId snapshot ID
* @return information about snapshot
*/
Snapshot readSnapshot(SnapshotId snapshotId);
SnapshotInfo readSnapshot(SnapshotId snapshotId);
/**
* Returns global metadata associate with the snapshot.
@ -65,7 +65,7 @@ public interface Repository extends LifecycleComponent<Repository> {
* @param indices list of indices
* @return information about snapshot
*/
MetaData readSnapshotMetaData(SnapshotId snapshotId, Snapshot snapshot, List<String> indices) throws IOException;
MetaData readSnapshotMetaData(SnapshotId snapshotId, SnapshotInfo snapshot, List<String> indices) throws IOException;
/**
* Returns the list of snapshots currently stored in the repository
@ -94,7 +94,7 @@ public interface Repository extends LifecycleComponent<Repository> {
* @param shardFailures list of shard failures
* @return snapshot description
*/
Snapshot finalizeSnapshot(SnapshotId snapshotId, List<String> indices, long startTime, String failure, int totalShards, List<SnapshotShardFailure> shardFailures);
SnapshotInfo finalizeSnapshot(SnapshotId snapshotId, List<String> indices, long startTime, String failure, int totalShards, List<SnapshotShardFailure> shardFailures);
/**
* Deletes snapshot

View File

@ -57,9 +57,9 @@ import org.elasticsearch.repositories.RepositoryException;
import org.elasticsearch.repositories.RepositorySettings;
import org.elasticsearch.repositories.RepositoryVerificationException;
import org.elasticsearch.snapshots.InvalidSnapshotNameException;
import org.elasticsearch.snapshots.Snapshot;
import org.elasticsearch.snapshots.SnapshotCreationException;
import org.elasticsearch.snapshots.SnapshotException;
import org.elasticsearch.snapshots.SnapshotInfo;
import org.elasticsearch.snapshots.SnapshotMissingException;
import org.elasticsearch.snapshots.SnapshotShardFailure;
@ -165,9 +165,9 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent<Rep
private LegacyBlobStoreFormat<IndexMetaData> indexMetaDataLegacyFormat;
private ChecksumBlobStoreFormat<Snapshot> snapshotFormat;
private ChecksumBlobStoreFormat<SnapshotInfo> snapshotFormat;
private LegacyBlobStoreFormat<Snapshot> snapshotLegacyFormat;
private LegacyBlobStoreFormat<SnapshotInfo> snapshotLegacyFormat;
private final boolean readOnly;
@ -202,8 +202,8 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent<Rep
indexMetaDataFormat = new ChecksumBlobStoreFormat<>(INDEX_METADATA_CODEC, METADATA_NAME_FORMAT, IndexMetaData.PROTO, parseFieldMatcher, isCompress());
indexMetaDataLegacyFormat = new LegacyBlobStoreFormat<>(LEGACY_SNAPSHOT_NAME_FORMAT, IndexMetaData.PROTO, parseFieldMatcher);
snapshotFormat = new ChecksumBlobStoreFormat<>(SNAPSHOT_CODEC, SNAPSHOT_NAME_FORMAT, Snapshot.PROTO, parseFieldMatcher, isCompress());
snapshotLegacyFormat = new LegacyBlobStoreFormat<>(LEGACY_SNAPSHOT_NAME_FORMAT, Snapshot.PROTO, parseFieldMatcher);
snapshotFormat = new ChecksumBlobStoreFormat<>(SNAPSHOT_CODEC, SNAPSHOT_NAME_FORMAT, SnapshotInfo.PROTO, parseFieldMatcher, isCompress());
snapshotLegacyFormat = new LegacyBlobStoreFormat<>(LEGACY_SNAPSHOT_NAME_FORMAT, SnapshotInfo.PROTO, parseFieldMatcher);
}
/**
@ -294,7 +294,7 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent<Rep
throw new RepositoryException(this.repositoryName, "cannot delete snapshot from a readonly repository");
}
List<String> indices = Collections.emptyList();
Snapshot snapshot = null;
SnapshotInfo snapshot = null;
try {
snapshot = readSnapshot(snapshotId);
indices = snapshot.indices();
@ -368,9 +368,9 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent<Rep
* {@inheritDoc}
*/
@Override
public Snapshot finalizeSnapshot(SnapshotId snapshotId, List<String> indices, long startTime, String failure, int totalShards, List<SnapshotShardFailure> shardFailures) {
public SnapshotInfo finalizeSnapshot(SnapshotId snapshotId, List<String> indices, long startTime, String failure, int totalShards, List<SnapshotShardFailure> shardFailures) {
try {
Snapshot blobStoreSnapshot = new Snapshot(snapshotId.getSnapshot(), indices, startTime, failure, System.currentTimeMillis(), totalShards, shardFailures);
SnapshotInfo blobStoreSnapshot = new SnapshotInfo(snapshotId.getSnapshot(), indices, startTime, failure, System.currentTimeMillis(), totalShards, shardFailures);
snapshotFormat.write(blobStoreSnapshot, snapshotsBlobContainer, snapshotId.getSnapshot());
List<SnapshotId> snapshotIds = snapshots();
if (!snapshotIds.contains(snapshotId)) {
@ -425,7 +425,7 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent<Rep
* {@inheritDoc}
*/
@Override
public MetaData readSnapshotMetaData(SnapshotId snapshotId, Snapshot snapshot, List<String> indices) throws IOException {
public MetaData readSnapshotMetaData(SnapshotId snapshotId, SnapshotInfo snapshot, List<String> indices) throws IOException {
return readSnapshotMetaData(snapshotId, snapshot.version(), indices, false);
}
@ -433,7 +433,7 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent<Rep
* {@inheritDoc}
*/
@Override
public Snapshot readSnapshot(SnapshotId snapshotId) {
public SnapshotInfo readSnapshot(SnapshotId snapshotId) {
try {
return snapshotFormat.read(snapshotsBlobContainer, snapshotId.getSnapshot());
} catch (FileNotFoundException | NoSuchFileException ex) {
@ -520,7 +520,7 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent<Rep
/**
* Returns appropriate snapshot format based on the provided version of the snapshot
*/
private BlobStoreFormat<Snapshot> snapshotFormat(Version version) {
private BlobStoreFormat<SnapshotInfo> snapshotFormat(Version version) {
if(legacyMetaData(version)) {
return snapshotLegacyFormat;
} else {

View File

@ -190,7 +190,7 @@ public class RestoreService extends AbstractComponent implements ClusterStateLis
// Read snapshot info and metadata from the repository
Repository repository = repositoriesService.repository(request.repository());
final SnapshotId snapshotId = new SnapshotId(request.repository(), request.name());
final Snapshot snapshot = repository.readSnapshot(snapshotId);
final SnapshotInfo snapshot = repository.readSnapshot(snapshotId);
List<String> filteredIndices = SnapshotUtils.filterIndices(snapshot.indices(), request.indices(), request.indicesOptions());
MetaData metaDataIn = repository.readSnapshotMetaData(snapshotId, snapshot, filteredIndices);
@ -708,7 +708,7 @@ public class RestoreService extends AbstractComponent implements ClusterStateLis
* @param snapshotId snapshot id
* @param snapshot snapshot metadata
*/
private void validateSnapshotRestorable(SnapshotId snapshotId, Snapshot snapshot) {
private void validateSnapshotRestorable(SnapshotId snapshotId, SnapshotInfo snapshot) {
if (!snapshot.state().restorable()) {
throw new SnapshotRestoreException(snapshotId, "unsupported snapshot state [" + snapshot.state() + "]");
}
@ -765,7 +765,7 @@ public class RestoreService extends AbstractComponent implements ClusterStateLis
UPDATE_RESTORE_ACTION_NAME, request, EmptyTransportResponseHandler.INSTANCE_SAME);
}
private boolean failed(Snapshot snapshot, String index) {
private boolean failed(SnapshotInfo snapshot, String index) {
for (SnapshotShardFailure failure : snapshot.shardFailures()) {
if (index.equals(failure.index())) {
return true;

View File

@ -1,358 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.snapshots;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.xcontent.FromXContentBuilder;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Represent information about snapshot
*/
public class Snapshot implements Comparable<Snapshot>, ToXContent, FromXContentBuilder<Snapshot> {
private final String name;
private final Version version;
private final SnapshotState state;
private final String reason;
private final List<String> indices;
private final long startTime;
private final long endTime;
private final int totalShard;
private final int successfulShards;
private final List<SnapshotShardFailure> shardFailures;
private final static List<SnapshotShardFailure> NO_FAILURES = Collections.emptyList();
public final static Snapshot PROTO = new Snapshot();
private Snapshot(String name, List<String> indices, SnapshotState state, String reason, Version version, long startTime, long endTime,
int totalShard, int successfulShards, List<SnapshotShardFailure> shardFailures) {
assert name != null;
assert indices != null;
assert state != null;
assert shardFailures != null;
this.name = name;
this.indices = indices;
this.state = state;
this.reason = reason;
this.version = version;
this.startTime = startTime;
this.endTime = endTime;
this.totalShard = totalShard;
this.successfulShards = successfulShards;
this.shardFailures = shardFailures;
}
public Snapshot(String name, List<String> indices, long startTime) {
this(name, indices, SnapshotState.IN_PROGRESS, null, Version.CURRENT, startTime, 0L, 0, 0, NO_FAILURES);
}
public Snapshot(String name, List<String> indices, long startTime, String reason, long endTime,
int totalShard, List<SnapshotShardFailure> shardFailures) {
this(name, indices, snapshotState(reason, shardFailures), reason, Version.CURRENT,
startTime, endTime, totalShard, totalShard - shardFailures.size(), shardFailures);
}
/**
* Special constructor for the prototype object
*/
private Snapshot() {
this("", Collections.emptyList(), 0);
}
private static SnapshotState snapshotState(String reason, List<SnapshotShardFailure> shardFailures) {
if (reason == null) {
if (shardFailures.isEmpty()) {
return SnapshotState.SUCCESS;
} else {
return SnapshotState.PARTIAL;
}
} else {
return SnapshotState.FAILED;
}
}
/**
* Returns snapshot name
*
* @return snapshot name
*/
public String name() {
return name;
}
/**
* Returns current snapshot state
*
* @return snapshot state
*/
public SnapshotState state() {
return state;
}
/**
* Returns reason for complete snapshot failure
*
* @return snapshot failure reason
*/
public String reason() {
return reason;
}
/**
* Returns version of Elasticsearch that was used to create this snapshot
*
* @return Elasticsearch version
*/
public Version version() {
return version;
}
/**
* Returns indices that were included into this snapshot
*
* @return list of indices
*/
public List<String> indices() {
return indices;
}
/**
* Returns time when snapshot started
*
* @return snapshot start time
*/
public long startTime() {
return startTime;
}
/**
* Returns time when snapshot ended
* <p>
* Can be 0L if snapshot is still running
*
* @return snapshot end time
*/
public long endTime() {
return endTime;
}
/**
* Returns total number of shards that were snapshotted
*
* @return number of shards
*/
public int totalShard() {
return totalShard;
}
/**
* Returns total number of shards that were successfully snapshotted
*
* @return number of successful shards
*/
public int successfulShards() {
return successfulShards;
}
/**
* Returns shard failures
*/
public List<SnapshotShardFailure> shardFailures() {
return shardFailures;
}
/**
* Compares two snapshots by their start time
*
* @param o other snapshot
* @return the value {@code 0} if snapshots were created at the same time;
* a value less than {@code 0} if this snapshot was created before snapshot {@code o}; and
* a value greater than {@code 0} if this snapshot was created after snapshot {@code o};
*/
@Override
public int compareTo(Snapshot o) {
return Long.compare(startTime, o.startTime);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Snapshot that = (Snapshot) o;
if (startTime != that.startTime) return false;
if (!name.equals(that.name)) return false;
return true;
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + Long.hashCode(startTime);
return result;
}
@Override
public Snapshot fromXContent(XContentParser parser, ParseFieldMatcher parseFieldMatcher) throws IOException {
return fromXContent(parser);
}
static final class Fields {
static final String SNAPSHOT = "snapshot";
static final String NAME = "name";
static final String VERSION_ID = "version_id";
static final String INDICES = "indices";
static final String STATE = "state";
static final String REASON = "reason";
static final String START_TIME = "start_time";
static final String END_TIME = "end_time";
static final String TOTAL_SHARDS = "total_shards";
static final String SUCCESSFUL_SHARDS = "successful_shards";
static final String FAILURES = "failures";
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
builder.startObject(Fields.SNAPSHOT);
builder.field(Fields.NAME, name);
builder.field(Fields.VERSION_ID, version.id);
builder.startArray(Fields.INDICES);
for (String index : indices) {
builder.value(index);
}
builder.endArray();
builder.field(Fields.STATE, state);
if (reason != null) {
builder.field(Fields.REASON, reason);
}
builder.field(Fields.START_TIME, startTime);
builder.field(Fields.END_TIME, endTime);
builder.field(Fields.TOTAL_SHARDS, totalShard);
builder.field(Fields.SUCCESSFUL_SHARDS, successfulShards);
builder.startArray(Fields.FAILURES);
for (SnapshotShardFailure shardFailure : shardFailures) {
builder.startObject();
shardFailure.toXContent(builder, params);
builder.endObject();
}
builder.endArray();
builder.endObject();
return builder;
}
public static Snapshot fromXContent(XContentParser parser) throws IOException {
String name = null;
Version version = Version.CURRENT;
SnapshotState state = SnapshotState.IN_PROGRESS;
String reason = null;
List<String> indices = Collections.emptyList();
long startTime = 0;
long endTime = 0;
int totalShard = 0;
int successfulShards = 0;
List<SnapshotShardFailure> shardFailures = NO_FAILURES;
if (parser.currentToken() == null) { // fresh parser? move to the first token
parser.nextToken();
}
if (parser.currentToken() == XContentParser.Token.START_OBJECT) { // on a start object move to next token
parser.nextToken();
}
XContentParser.Token token;
if ((token = parser.nextToken()) == XContentParser.Token.START_OBJECT) {
String currentFieldName = parser.currentName();
if ("snapshot".equals(currentFieldName)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
token = parser.nextToken();
if (token.isValue()) {
if ("name".equals(currentFieldName)) {
name = parser.text();
} else if ("state".equals(currentFieldName)) {
state = SnapshotState.valueOf(parser.text());
} else if ("reason".equals(currentFieldName)) {
reason = parser.text();
} else if ("start_time".equals(currentFieldName)) {
startTime = parser.longValue();
} else if ("end_time".equals(currentFieldName)) {
endTime = parser.longValue();
} else if ("total_shards".equals(currentFieldName)) {
totalShard = parser.intValue();
} else if ("successful_shards".equals(currentFieldName)) {
successfulShards = parser.intValue();
} else if ("version_id".equals(currentFieldName)) {
version = Version.fromId(parser.intValue());
}
} else if (token == XContentParser.Token.START_ARRAY) {
if ("indices".equals(currentFieldName)) {
ArrayList<String> indicesArray = new ArrayList<>();
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
indicesArray.add(parser.text());
}
indices = Collections.unmodifiableList(indicesArray);
} else if ("failures".equals(currentFieldName)) {
ArrayList<SnapshotShardFailure> shardFailureArrayList = new ArrayList<>();
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
shardFailureArrayList.add(SnapshotShardFailure.fromXContent(parser));
}
shardFailures = Collections.unmodifiableList(shardFailureArrayList);
} else {
// It was probably created by newer version - ignoring
parser.skipChildren();
}
} else if (token == XContentParser.Token.START_OBJECT) {
// It was probably created by newer version - ignoring
parser.skipChildren();
}
}
}
}
} else {
throw new ElasticsearchParseException("unexpected token [" + token + "]");
}
return new Snapshot(name, indices, state, reason, version, startTime, endTime, totalShard, successfulShards, shardFailures);
}
}

View File

@ -18,15 +18,19 @@
*/
package org.elasticsearch.snapshots;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
import org.elasticsearch.action.ShardOperationFailedException;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Streamable;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.xcontent.FromXContentBuilder;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.rest.RestStatus;
import java.io.IOException;
@ -35,52 +39,109 @@ import java.util.Collections;
import java.util.List;
/**
* Information about snapshot
* Information about a snapshot
*/
public class SnapshotInfo implements ToXContent, Streamable {
public final class SnapshotInfo implements Comparable<SnapshotInfo>, ToXContent, FromXContentBuilder<SnapshotInfo>, Writeable {
public static final SnapshotInfo PROTO = new SnapshotInfo("", Collections.emptyList(), 0);
private static final FormatDateTimeFormatter DATE_TIME_FORMATTER = Joda.forPattern("strictDateOptionalTime");
private static final String SNAPSHOT = "snapshot";
private static final String INDICES = "indices";
private static final String STATE = "state";
private static final String REASON = "reason";
private static final String START_TIME = "start_time";
private static final String START_TIME_IN_MILLIS = "start_time_in_millis";
private static final String END_TIME = "end_time";
private static final String END_TIME_IN_MILLIS = "end_time_in_millis";
private static final String DURATION = "duration";
private static final String DURATION_IN_MILLIS = "duration_in_millis";
private static final String FAILURES = "failures";
private static final String SHARDS = "shards";
private static final String TOTAL = "total";
private static final String FAILED = "failed";
private static final String SUCCESSFUL = "successful";
private static final String VERSION_ID = "version_id";
private static final String VERSION = "version";
private static final String NAME = "name";
private static final String TOTAL_SHARDS = "total_shards";
private static final String SUCCESSFUL_SHARDS = "successful_shards";
private String name;
private final String name;
private SnapshotState state;
private final SnapshotState state;
private String reason;
private final String reason;
private List<String> indices;
private final List<String> indices;
private long startTime;
private final long startTime;
private long endTime;
private final long endTime;
private int totalShards;
private final int totalShards;
private int successfulShards;
private final int successfulShards;
private Version version;
private final Version version;
private List<SnapshotShardFailure> shardFailures;
private final List<SnapshotShardFailure> shardFailures;
SnapshotInfo() {
public SnapshotInfo(String name, List<String> indices, long startTime) {
this(name, indices, SnapshotState.IN_PROGRESS, null, Version.CURRENT, startTime, 0L, 0, 0, Collections.emptyList());
}
public SnapshotInfo(String name, List<String> indices, long startTime, String reason, long endTime,
int totalShards, List<SnapshotShardFailure> shardFailures) {
this(name, indices, snapshotState(reason, shardFailures), reason, Version.CURRENT,
startTime, endTime, totalShards, totalShards - shardFailures.size(), shardFailures);
}
private SnapshotInfo(String name, List<String> indices, SnapshotState state, String reason, Version version, long startTime,
long endTime, int totalShards, int successfulShards, List<SnapshotShardFailure> shardFailures) {
assert name != null;
assert indices != null;
assert state != null;
assert shardFailures != null;
this.name = name;
this.indices = indices;
this.state = state;
this.reason = reason;
this.version = version;
this.startTime = startTime;
this.endTime = endTime;
this.totalShards = totalShards;
this.successfulShards = successfulShards;
this.shardFailures = shardFailures;
}
/**
* Creates a new snapshot information from a {@link Snapshot}
*
* @param snapshot snapshot information returned by repository
* Constructs snapshot information from stream input
*/
public SnapshotInfo(Snapshot snapshot) {
name = snapshot.name();
state = snapshot.state();
reason = snapshot.reason();
indices = snapshot.indices();
startTime = snapshot.startTime();
endTime = snapshot.endTime();
totalShards = snapshot.totalShard();
successfulShards = snapshot.successfulShards();
shardFailures = snapshot.shardFailures();
version = snapshot.version();
public SnapshotInfo(final StreamInput in) throws IOException {
name = in.readString();
int size = in.readVInt();
List<String> indicesListBuilder = new ArrayList<>();
for (int i = 0; i < size; i++) {
indicesListBuilder.add(in.readString());
}
indices = Collections.unmodifiableList(indicesListBuilder);
state = SnapshotState.fromValue(in.readByte());
reason = in.readOptionalString();
startTime = in.readVLong();
endTime = in.readVLong();
totalShards = in.readVInt();
successfulShards = in.readVInt();
size = in.readVInt();
if (size > 0) {
List<SnapshotShardFailure> failureBuilder = new ArrayList<>();
for (int i = 0; i < size; i++) {
failureBuilder.add(SnapshotShardFailure.readSnapshotShardFailure(in));
}
shardFailures = Collections.unmodifiableList(failureBuilder);
} else {
shardFailures = Collections.emptyList();
}
version = Version.readVersion(in);
}
/**
@ -184,6 +245,39 @@ public class SnapshotInfo implements ToXContent, Streamable {
return version;
}
/**
* Compares two snapshots by their start time
*
* @param o other snapshot
* @return the value {@code 0} if snapshots were created at the same time;
* a value less than {@code 0} if this snapshot was created before snapshot {@code o}; and
* a value greater than {@code 0} if this snapshot was created after snapshot {@code o};
*/
@Override
public int compareTo(final SnapshotInfo o) {
return Long.compare(startTime, o.startTime);
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final SnapshotInfo that = (SnapshotInfo) o;
return startTime == that.startTime && name.equals(that.name);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + Long.hashCode(startTime);
return result;
}
/**
* Returns snapshot REST status
*/
@ -194,98 +288,166 @@ public class SnapshotInfo implements ToXContent, Streamable {
if (shardFailures.size() == 0) {
return RestStatus.OK;
}
return RestStatus.status(successfulShards, totalShards, shardFailures.toArray(new ShardOperationFailedException[shardFailures.size()]));
}
static final class Fields {
static final String INDICES = "indices";
static final String STATE = "state";
static final String REASON = "reason";
static final String START_TIME = "start_time";
static final String START_TIME_IN_MILLIS = "start_time_in_millis";
static final String END_TIME = "end_time";
static final String END_TIME_IN_MILLIS = "end_time_in_millis";
static final String DURATION = "duration";
static final String DURATION_IN_MILLIS = "duration_in_millis";
static final String FAILURES = "failures";
static final String SHARDS = "shards";
static final String TOTAL = "total";
static final String FAILED = "failed";
static final String SUCCESSFUL = "successful";
static final String VERSION_ID = "version_id";
static final String VERSION = "version";
return RestStatus.status(successfulShards, totalShards,
shardFailures.toArray(new ShardOperationFailedException[shardFailures.size()]));
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field("snapshot", name);
builder.field(Fields.VERSION_ID, version.id);
builder.field(Fields.VERSION, version.toString());
builder.startArray(Fields.INDICES);
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
builder.startObject(SNAPSHOT);
builder.field(NAME, name);
builder.field(VERSION_ID, version.id);
builder.startArray(INDICES);
for (String index : indices) {
builder.value(index);
}
builder.endArray();
builder.field(Fields.STATE, state);
builder.field(STATE, state);
if (reason != null) {
builder.field(Fields.REASON, reason);
builder.field(REASON, reason);
}
if (startTime != 0) {
builder.field(Fields.START_TIME, DATE_TIME_FORMATTER.printer().print(startTime));
builder.field(Fields.START_TIME_IN_MILLIS, startTime);
}
if (endTime != 0) {
builder.field(Fields.END_TIME, DATE_TIME_FORMATTER.printer().print(endTime));
builder.field(Fields.END_TIME_IN_MILLIS, endTime);
builder.timeValueField(Fields.DURATION_IN_MILLIS, Fields.DURATION, endTime - startTime);
}
builder.startArray(Fields.FAILURES);
builder.field(START_TIME, startTime);
builder.field(END_TIME, endTime);
builder.field(TOTAL_SHARDS, totalShards);
builder.field(SUCCESSFUL_SHARDS, successfulShards);
builder.startArray(FAILURES);
for (SnapshotShardFailure shardFailure : shardFailures) {
builder.startObject();
shardFailure.toXContent(builder, params);
builder.endObject();
}
builder.endArray();
builder.startObject(Fields.SHARDS);
builder.field(Fields.TOTAL, totalShards);
builder.field(Fields.FAILED, failedShards());
builder.field(Fields.SUCCESSFUL, successfulShards);
builder.endObject();
return builder;
}
/**
* Produces the external X-content that is delivered through the REST layer.
*/
public XContentBuilder toExternalXContent(final XContentBuilder builder, final ToXContent.Params params) throws IOException {
builder.startObject();
builder.field(SNAPSHOT, name);
builder.field(VERSION_ID, version.id);
builder.field(VERSION, version.toString());
builder.startArray(INDICES);
for (String index : indices) {
builder.value(index);
}
builder.endArray();
builder.field(STATE, state);
if (reason != null) {
builder.field(REASON, reason);
}
if (startTime != 0) {
builder.field(START_TIME, DATE_TIME_FORMATTER.printer().print(startTime));
builder.field(START_TIME_IN_MILLIS, startTime);
}
if (endTime != 0) {
builder.field(END_TIME, DATE_TIME_FORMATTER.printer().print(endTime));
builder.field(END_TIME_IN_MILLIS, endTime);
builder.timeValueField(DURATION_IN_MILLIS, DURATION, endTime - startTime);
}
builder.startArray(FAILURES);
for (SnapshotShardFailure shardFailure : shardFailures) {
builder.startObject();
shardFailure.toXContent(builder, params);
builder.endObject();
}
builder.endArray();
builder.startObject(SHARDS);
builder.field(TOTAL, totalShards);
builder.field(FAILED, failedShards());
builder.field(SUCCESSFUL, successfulShards);
builder.endObject();
builder.endObject();
return builder;
}
@Override
public void readFrom(StreamInput in) throws IOException {
name = in.readString();
int size = in.readVInt();
List<String> indicesListBuilder = new ArrayList<>();
for (int i = 0; i < size; i++) {
indicesListBuilder.add(in.readString());
public SnapshotInfo fromXContent(final XContentParser parser, final ParseFieldMatcher matcher) throws IOException {
return fromXContent(parser);
}
/**
* This method creates a SnapshotInfo from internal x-content. It does not
* handle x-content written with the external version as external x-content
* is only for display purposes and does not need to be parsed.
*/
public static SnapshotInfo fromXContent(final XContentParser parser) throws IOException {
String name = null;
Version version = Version.CURRENT;
SnapshotState state = SnapshotState.IN_PROGRESS;
String reason = null;
List<String> indices = Collections.emptyList();
long startTime = 0;
long endTime = 0;
int totalShard = 0;
int successfulShards = 0;
List<SnapshotShardFailure> shardFailures = Collections.emptyList();
if (parser.currentToken() == null) { // fresh parser? move to the first token
parser.nextToken();
}
indices = Collections.unmodifiableList(indicesListBuilder);
state = SnapshotState.fromValue(in.readByte());
reason = in.readOptionalString();
startTime = in.readVLong();
endTime = in.readVLong();
totalShards = in.readVInt();
successfulShards = in.readVInt();
size = in.readVInt();
if (size > 0) {
List<SnapshotShardFailure> failureBuilder = new ArrayList<>();
for (int i = 0; i < size; i++) {
failureBuilder.add(SnapshotShardFailure.readSnapshotShardFailure(in));
if (parser.currentToken() == XContentParser.Token.START_OBJECT) { // on a start object move to next token
parser.nextToken();
}
XContentParser.Token token;
if ((token = parser.nextToken()) == XContentParser.Token.START_OBJECT) {
String currentFieldName = parser.currentName();
if (SNAPSHOT.equals(currentFieldName)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
token = parser.nextToken();
if (token.isValue()) {
if (NAME.equals(currentFieldName)) {
name = parser.text();
} else if (STATE.equals(currentFieldName)) {
state = SnapshotState.valueOf(parser.text());
} else if (REASON.equals(currentFieldName)) {
reason = parser.text();
} else if (START_TIME.equals(currentFieldName)) {
startTime = parser.longValue();
} else if (END_TIME.equals(currentFieldName)) {
endTime = parser.longValue();
} else if (TOTAL_SHARDS.equals(currentFieldName)) {
totalShard = parser.intValue();
} else if (SUCCESSFUL_SHARDS.equals(currentFieldName)) {
successfulShards = parser.intValue();
} else if (VERSION_ID.equals(currentFieldName)) {
version = Version.fromId(parser.intValue());
}
} else if (token == XContentParser.Token.START_ARRAY) {
if (INDICES.equals(currentFieldName)) {
ArrayList<String> indicesArray = new ArrayList<>();
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
indicesArray.add(parser.text());
}
indices = Collections.unmodifiableList(indicesArray);
} else if (FAILURES.equals(currentFieldName)) {
ArrayList<SnapshotShardFailure> shardFailureArrayList = new ArrayList<>();
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
shardFailureArrayList.add(SnapshotShardFailure.fromXContent(parser));
}
shardFailures = Collections.unmodifiableList(shardFailureArrayList);
} else {
// It was probably created by newer version - ignoring
parser.skipChildren();
}
} else if (token == XContentParser.Token.START_OBJECT) {
// It was probably created by newer version - ignoring
parser.skipChildren();
}
}
}
}
shardFailures = Collections.unmodifiableList(failureBuilder);
} else {
shardFailures = Collections.emptyList();
throw new ElasticsearchParseException("unexpected token [" + token + "]");
}
version = Version.readVersion(in);
return new SnapshotInfo(name, indices, state, reason, version, startTime, endTime, totalShard, successfulShards, shardFailures);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
public void writeTo(final StreamOutput out) throws IOException {
out.writeString(name);
out.writeVInt(indices.size());
for (String index : indices) {
@ -304,26 +466,16 @@ public class SnapshotInfo implements ToXContent, Streamable {
Version.writeVersion(version, out);
}
/**
* Reads snapshot information from stream input
*
* @param in stream input
* @return deserialized snapshot info
*/
public static SnapshotInfo readSnapshotInfo(StreamInput in) throws IOException {
SnapshotInfo snapshotInfo = new SnapshotInfo();
snapshotInfo.readFrom(in);
return snapshotInfo;
}
/**
* Reads optional snapshot information from stream input
*
* @param in stream input
* @return deserialized snapshot info or null
*/
public static SnapshotInfo readOptionalSnapshotInfo(StreamInput in) throws IOException {
return in.readOptionalStreamable(SnapshotInfo::new);
private static SnapshotState snapshotState(final String reason, final List<SnapshotShardFailure> shardFailures) {
if (reason == null) {
if (shardFailures.isEmpty()) {
return SnapshotState.SUCCESS;
} else {
return SnapshotState.PARTIAL;
}
} else {
return SnapshotState.FAILED;
}
}
}

View File

@ -126,7 +126,7 @@ public class SnapshotsService extends AbstractLifecycleComponent<SnapshotsServic
* @return snapshot
* @throws SnapshotMissingException if snapshot is not found
*/
public Snapshot snapshot(SnapshotId snapshotId) {
public SnapshotInfo snapshot(SnapshotId snapshotId) {
validate(snapshotId);
List<SnapshotsInProgress.Entry> entries = currentSnapshots(snapshotId.getRepository(), new String[]{snapshotId.getSnapshot()});
if (!entries.isEmpty()) {
@ -141,8 +141,8 @@ public class SnapshotsService extends AbstractLifecycleComponent<SnapshotsServic
* @param repositoryName repository name
* @return list of snapshots
*/
public List<Snapshot> snapshots(String repositoryName, boolean ignoreUnavailable) {
Set<Snapshot> snapshotSet = new HashSet<>();
public List<SnapshotInfo> snapshots(String repositoryName, boolean ignoreUnavailable) {
Set<SnapshotInfo> snapshotSet = new HashSet<>();
List<SnapshotsInProgress.Entry> entries = currentSnapshots(repositoryName, null);
for (SnapshotsInProgress.Entry entry : entries) {
snapshotSet.add(inProgressSnapshot(entry));
@ -161,7 +161,7 @@ public class SnapshotsService extends AbstractLifecycleComponent<SnapshotsServic
}
}
ArrayList<Snapshot> snapshotList = new ArrayList<>(snapshotSet);
ArrayList<SnapshotInfo> snapshotList = new ArrayList<>(snapshotSet);
CollectionUtil.timSort(snapshotList);
return Collections.unmodifiableList(snapshotList);
}
@ -172,8 +172,8 @@ public class SnapshotsService extends AbstractLifecycleComponent<SnapshotsServic
* @param repositoryName repository name
* @return list of snapshots
*/
public List<Snapshot> currentSnapshots(String repositoryName) {
List<Snapshot> snapshotList = new ArrayList<>();
public List<SnapshotInfo> currentSnapshots(String repositoryName) {
List<SnapshotInfo> snapshotList = new ArrayList<>();
List<SnapshotsInProgress.Entry> entries = currentSnapshots(repositoryName, null);
for (SnapshotsInProgress.Entry entry : entries) {
snapshotList.add(inProgressSnapshot(entry));
@ -408,8 +408,8 @@ public class SnapshotsService extends AbstractLifecycleComponent<SnapshotsServic
}
}
private Snapshot inProgressSnapshot(SnapshotsInProgress.Entry entry) {
return new Snapshot(entry.snapshotId().getSnapshot(), entry.indices(), entry.startTime());
private SnapshotInfo inProgressSnapshot(SnapshotsInProgress.Entry entry) {
return new SnapshotInfo(entry.snapshotId().getSnapshot(), entry.indices(), entry.startTime());
}
/**
@ -482,7 +482,7 @@ public class SnapshotsService extends AbstractLifecycleComponent<SnapshotsServic
Map<ShardId, IndexShardSnapshotStatus> shardStatus = new HashMap<>();
Repository repository = repositoriesService.repository(snapshotId.getRepository());
IndexShardRepository indexShardRepository = repositoriesService.indexShardRepository(snapshotId.getRepository());
Snapshot snapshot = repository.readSnapshot(snapshotId);
SnapshotInfo snapshot = repository.readSnapshot(snapshotId);
MetaData metaData = repository.readSnapshotMetaData(snapshotId, snapshot, snapshot.indices());
for (String index : snapshot.indices()) {
IndexMetaData indexMetaData = metaData.indices().get(index);
@ -800,8 +800,8 @@ public class SnapshotsService extends AbstractLifecycleComponent<SnapshotsServic
shardFailures.add(new SnapshotShardFailure(status.nodeId(), shardId, status.reason()));
}
}
Snapshot snapshot = repository.finalizeSnapshot(snapshotId, entry.indices(), entry.startTime(), failure, entry.shards().size(), Collections.unmodifiableList(shardFailures));
removeSnapshotFromClusterState(snapshotId, new SnapshotInfo(snapshot), null);
SnapshotInfo snapshot = repository.finalizeSnapshot(snapshotId, entry.indices(), entry.startTime(), failure, entry.shards().size(), Collections.unmodifiableList(shardFailures));
removeSnapshotFromClusterState(snapshotId, snapshot, null);
} catch (Throwable t) {
logger.warn("[{}] failed to finalize snapshot", t, snapshotId);
removeSnapshotFromClusterState(snapshotId, null, t);