|
@@ -30,10 +30,8 @@ import org.elasticsearch.cluster.Diffable;
|
|
|
import org.elasticsearch.cluster.DiffableUtils;
|
|
|
import org.elasticsearch.cluster.block.ClusterBlock;
|
|
|
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
|
|
-import org.elasticsearch.cluster.node.DiscoveryNode;
|
|
|
import org.elasticsearch.cluster.node.DiscoveryNodeFilters;
|
|
|
import org.elasticsearch.cluster.routing.RoutingTable;
|
|
|
-import org.elasticsearch.cluster.routing.ShardRouting;
|
|
|
import org.elasticsearch.cluster.routing.allocation.AllocationService;
|
|
|
import org.elasticsearch.common.Nullable;
|
|
|
import org.elasticsearch.common.ParseFieldMatcher;
|
|
@@ -56,6 +54,7 @@ import org.elasticsearch.common.xcontent.XContentType;
|
|
|
import org.elasticsearch.gateway.MetaDataStateFormat;
|
|
|
import org.elasticsearch.index.Index;
|
|
|
import org.elasticsearch.index.mapper.MapperService;
|
|
|
+import org.elasticsearch.index.shard.ShardId;
|
|
|
import org.elasticsearch.rest.RestStatus;
|
|
|
import org.joda.time.DateTime;
|
|
|
import org.joda.time.DateTimeZone;
|
|
@@ -226,6 +225,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
|
|
|
public static final String KEY_ACTIVE_ALLOCATIONS = "active_allocations";
|
|
|
static final String KEY_VERSION = "version";
|
|
|
+ static final String KEY_ROUTING_NUM_SHARDS = "routing_num_shards";
|
|
|
static final String KEY_SETTINGS = "settings";
|
|
|
static final String KEY_STATE = "state";
|
|
|
static final String KEY_MAPPINGS = "mappings";
|
|
@@ -233,6 +233,8 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
public static final String KEY_PRIMARY_TERMS = "primary_terms";
|
|
|
|
|
|
public static final String INDEX_STATE_FILE_PREFIX = "state-";
|
|
|
+ private final int routingNumShards;
|
|
|
+ private final int routingFactor;
|
|
|
|
|
|
private final int numberOfShards;
|
|
|
private final int numberOfReplicas;
|
|
@@ -268,7 +270,8 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
ImmutableOpenMap<String, MappingMetaData> mappings, ImmutableOpenMap<String, AliasMetaData> aliases,
|
|
|
ImmutableOpenMap<String, Custom> customs, ImmutableOpenIntMap<Set<String>> activeAllocationIds,
|
|
|
DiscoveryNodeFilters requireFilters, DiscoveryNodeFilters initialRecoveryFilters, DiscoveryNodeFilters includeFilters, DiscoveryNodeFilters excludeFilters,
|
|
|
- Version indexCreatedVersion, Version indexUpgradedVersion, org.apache.lucene.util.Version minimumCompatibleLuceneVersion) {
|
|
|
+ Version indexCreatedVersion, Version indexUpgradedVersion, org.apache.lucene.util.Version minimumCompatibleLuceneVersion,
|
|
|
+ int routingNumShards) {
|
|
|
|
|
|
this.index = index;
|
|
|
this.version = version;
|
|
@@ -290,6 +293,9 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
this.indexCreatedVersion = indexCreatedVersion;
|
|
|
this.indexUpgradedVersion = indexUpgradedVersion;
|
|
|
this.minimumCompatibleLuceneVersion = minimumCompatibleLuceneVersion;
|
|
|
+ this.routingNumShards = routingNumShards;
|
|
|
+ this.routingFactor = routingNumShards / numberOfShards;
|
|
|
+ assert numberOfShards * routingFactor == routingNumShards : routingNumShards + " must be a multiple of " + numberOfShards;
|
|
|
}
|
|
|
|
|
|
public Index getIndex() {
|
|
@@ -484,7 +490,12 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
if (!customs.equals(that.customs)) {
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
+ if (routingNumShards != that.routingNumShards) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (routingFactor != that.routingFactor) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
if (Arrays.equals(primaryTerms, that.primaryTerms) == false) {
|
|
|
return false;
|
|
|
}
|
|
@@ -503,6 +514,8 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
result = 31 * result + settings.hashCode();
|
|
|
result = 31 * result + mappings.hashCode();
|
|
|
result = 31 * result + customs.hashCode();
|
|
|
+ result = 31 * result + Long.hashCode(routingFactor);
|
|
|
+ result = 31 * result + Long.hashCode(routingNumShards);
|
|
|
result = 31 * result + Arrays.hashCode(primaryTerms);
|
|
|
result = 31 * result + activeAllocationIds.hashCode();
|
|
|
return result;
|
|
@@ -533,6 +546,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
private static class IndexMetaDataDiff implements Diff<IndexMetaData> {
|
|
|
|
|
|
private final String index;
|
|
|
+ private final int routingNumShards;
|
|
|
private final long version;
|
|
|
private final long[] primaryTerms;
|
|
|
private final State state;
|
|
@@ -545,6 +559,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
public IndexMetaDataDiff(IndexMetaData before, IndexMetaData after) {
|
|
|
index = after.index.getName();
|
|
|
version = after.version;
|
|
|
+ routingNumShards = after.routingNumShards;
|
|
|
state = after.state;
|
|
|
settings = after.settings;
|
|
|
primaryTerms = after.primaryTerms;
|
|
@@ -557,6 +572,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
|
|
|
public IndexMetaDataDiff(StreamInput in) throws IOException {
|
|
|
index = in.readString();
|
|
|
+ routingNumShards = in.readInt();
|
|
|
version = in.readLong();
|
|
|
state = State.fromId(in.readByte());
|
|
|
settings = Settings.readSettingsFromStream(in);
|
|
@@ -582,6 +598,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
@Override
|
|
|
public void writeTo(StreamOutput out) throws IOException {
|
|
|
out.writeString(index);
|
|
|
+ out.writeInt(routingNumShards);
|
|
|
out.writeLong(version);
|
|
|
out.writeByte(state.id);
|
|
|
Settings.writeSettingsToStream(settings, out);
|
|
@@ -596,6 +613,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
public IndexMetaData apply(IndexMetaData part) {
|
|
|
Builder builder = builder(index);
|
|
|
builder.version(version);
|
|
|
+ builder.setRoutingNumShards(routingNumShards);
|
|
|
builder.state(state);
|
|
|
builder.settings(settings);
|
|
|
builder.primaryTerms(primaryTerms);
|
|
@@ -611,6 +629,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
public IndexMetaData readFrom(StreamInput in) throws IOException {
|
|
|
Builder builder = new Builder(in.readString());
|
|
|
builder.version(in.readLong());
|
|
|
+ builder.setRoutingNumShards(in.readInt());
|
|
|
builder.state(State.fromId(in.readByte()));
|
|
|
builder.settings(readSettingsFromStream(in));
|
|
|
builder.primaryTerms(in.readVLongArray());
|
|
@@ -643,6 +662,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
public void writeTo(StreamOutput out) throws IOException {
|
|
|
out.writeString(index.getName()); // uuid will come as part of settings
|
|
|
out.writeLong(version);
|
|
|
+ out.writeInt(routingNumShards);
|
|
|
out.writeByte(state.id());
|
|
|
writeSettingsToStream(settings, out);
|
|
|
out.writeVLongArray(primaryTerms);
|
|
@@ -685,6 +705,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
private final ImmutableOpenMap.Builder<String, AliasMetaData> aliases;
|
|
|
private final ImmutableOpenMap.Builder<String, Custom> customs;
|
|
|
private final ImmutableOpenIntMap.Builder<Set<String>> activeAllocationIds;
|
|
|
+ private Integer routingNumShards;
|
|
|
|
|
|
public Builder(String index) {
|
|
|
this.index = index;
|
|
@@ -703,6 +724,7 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
this.mappings = ImmutableOpenMap.builder(indexMetaData.mappings);
|
|
|
this.aliases = ImmutableOpenMap.builder(indexMetaData.aliases);
|
|
|
this.customs = ImmutableOpenMap.builder(indexMetaData.customs);
|
|
|
+ this.routingNumShards = indexMetaData.routingNumShards;
|
|
|
this.activeAllocationIds = ImmutableOpenIntMap.builder(indexMetaData.activeAllocationIds);
|
|
|
}
|
|
|
|
|
@@ -720,6 +742,26 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Sets the number of shards that should be used for routing. This should only be used if the number of shards in
|
|
|
+ * an index has changed ie if the index is shrunk.
|
|
|
+ */
|
|
|
+ public Builder setRoutingNumShards(int routingNumShards) {
|
|
|
+ this.routingNumShards = routingNumShards;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns number of shards that should be used for routing. By default this method will return the number of shards
|
|
|
+ * for this index.
|
|
|
+ *
|
|
|
+ * @see #setRoutingNumShards(int)
|
|
|
+ * @see #numberOfShards()
|
|
|
+ */
|
|
|
+ public int getRoutingNumShards() {
|
|
|
+ return routingNumShards == null ? numberOfShards() : routingNumShards;
|
|
|
+ }
|
|
|
+
|
|
|
public int numberOfShards() {
|
|
|
return settings.getAsInt(SETTING_NUMBER_OF_SHARDS, -1);
|
|
|
}
|
|
@@ -934,13 +976,14 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
final String uuid = settings.get(SETTING_INDEX_UUID, INDEX_UUID_NA_VALUE);
|
|
|
return new IndexMetaData(new Index(index, uuid), version, primaryTerms, state, numberOfShards, numberOfReplicas, tmpSettings, mappings.build(),
|
|
|
tmpAliases.build(), customs.build(), filledActiveAllocationIds.build(), requireFilters, initialRecoveryFilters, includeFilters, excludeFilters,
|
|
|
- indexCreatedVersion, indexUpgradedVersion, minimumCompatibleLuceneVersion);
|
|
|
+ indexCreatedVersion, indexUpgradedVersion, minimumCompatibleLuceneVersion, getRoutingNumShards());
|
|
|
}
|
|
|
|
|
|
public static void toXContent(IndexMetaData indexMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException {
|
|
|
builder.startObject(indexMetaData.getIndex().getName());
|
|
|
|
|
|
builder.field(KEY_VERSION, indexMetaData.getVersion());
|
|
|
+ builder.field(KEY_ROUTING_NUM_SHARDS, indexMetaData.getRoutingNumShards());
|
|
|
builder.field(KEY_STATE, indexMetaData.getState().toString().toLowerCase(Locale.ENGLISH));
|
|
|
|
|
|
boolean binary = params.paramAsBoolean("binary", false);
|
|
@@ -1101,6 +1144,8 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
builder.state(State.fromString(parser.text()));
|
|
|
} else if (KEY_VERSION.equals(currentFieldName)) {
|
|
|
builder.version(parser.longValue());
|
|
|
+ } else if (KEY_ROUTING_NUM_SHARDS.equals(currentFieldName)) {
|
|
|
+ builder.setRoutingNumShards(parser.intValue());
|
|
|
} else {
|
|
|
throw new IllegalArgumentException("Unexpected field [" + currentFieldName + "]");
|
|
|
}
|
|
@@ -1175,4 +1220,68 @@ public class IndexMetaData implements Diffable<IndexMetaData>, FromXContentBuild
|
|
|
return Builder.fromXContent(parser);
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the number of shards that should be used for routing. This basically defines the hash space we use in
|
|
|
+ * {@link org.elasticsearch.cluster.routing.OperationRouting#generateShardId(IndexMetaData, String, String)} to route documents
|
|
|
+ * to shards based on their ID or their specific routing value. The default value is {@link #getNumberOfShards()}. This value only
|
|
|
+ * changes if and index is shrunk.
|
|
|
+ */
|
|
|
+ public int getRoutingNumShards() {
|
|
|
+ return routingNumShards;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the routing factor for this index. The default is <tt>1</tt>.
|
|
|
+ *
|
|
|
+ * @see #getRoutingFactor(IndexMetaData, int) for details
|
|
|
+ */
|
|
|
+ public int getRoutingFactor() {
|
|
|
+ return routingFactor;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the source shard ids to shrink into the given shard id.
|
|
|
+ * @param shardId the id of the target shard to shrink to
|
|
|
+ * @param sourceIndexMetadata the source index metadata
|
|
|
+ * @param numTargetShards the total number of shards in the target index
|
|
|
+ * @return a set of shard IDs to shrink into the given shard ID.
|
|
|
+ */
|
|
|
+ public static Set<ShardId> selectShrinkShards(int shardId, IndexMetaData sourceIndexMetadata, int numTargetShards) {
|
|
|
+ if (shardId >= numTargetShards) {
|
|
|
+ throw new IllegalArgumentException("the number of target shards (" + numTargetShards + ") must be greater than the shard id: "
|
|
|
+ + shardId);
|
|
|
+ }
|
|
|
+ int routingFactor = getRoutingFactor(sourceIndexMetadata, numTargetShards);
|
|
|
+ Set<ShardId> shards = new HashSet<>(routingFactor);
|
|
|
+ for (int i = shardId * routingFactor; i < routingFactor*shardId + routingFactor; i++) {
|
|
|
+ shards.add(new ShardId(sourceIndexMetadata.getIndex(), i));
|
|
|
+ }
|
|
|
+ return shards;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the routing factor for and shrunk index with the given number of target shards.
|
|
|
+ * This factor is used in the hash function in
|
|
|
+ * {@link org.elasticsearch.cluster.routing.OperationRouting#generateShardId(IndexMetaData, String, String)} to guarantee consistent
|
|
|
+ * hashing / routing of documents even if the number of shards changed (ie. a shrunk index).
|
|
|
+ *
|
|
|
+ * @param sourceIndexMetadata the metadata of the source index
|
|
|
+ * @param targetNumberOfShards the total number of shards in the target index
|
|
|
+ * @return the routing factor for and shrunk index with the given number of target shards.
|
|
|
+ * @throw IllegalArgumentException if the number of source shards is greater than the number of target shards or if the source shards
|
|
|
+ * are not divisible by the number of target shards.
|
|
|
+ */
|
|
|
+ public static int getRoutingFactor(IndexMetaData sourceIndexMetadata, int targetNumberOfShards) {
|
|
|
+ int sourceNumberOfShards = sourceIndexMetadata.getNumberOfShards();
|
|
|
+ if (sourceNumberOfShards < targetNumberOfShards) {
|
|
|
+ throw new IllegalArgumentException("the number of target shards must be less that the number of source shards");
|
|
|
+ }
|
|
|
+ int factor = sourceNumberOfShards / targetNumberOfShards;
|
|
|
+ if (factor * targetNumberOfShards != sourceNumberOfShards || factor <= 1) {
|
|
|
+ throw new IllegalArgumentException("the number of source shards [" + sourceNumberOfShards + "] must be a must be a multiple of ["
|
|
|
+ + targetNumberOfShards + "]");
|
|
|
+ }
|
|
|
+ return factor;
|
|
|
+ }
|
|
|
}
|