diff --git a/server/src/main/java/org/elasticsearch/gateway/PriorityComparator.java b/server/src/main/java/org/elasticsearch/gateway/PriorityComparator.java
index fb27d5fde1ad8..3b2b31fc6dd50 100644
--- a/server/src/main/java/org/elasticsearch/gateway/PriorityComparator.java
+++ b/server/src/main/java/org/elasticsearch/gateway/PriorityComparator.java
@@ -28,12 +28,16 @@
import java.util.Comparator;
/**
- * A comparator that compares ShardRouting based on it's indexes priority (index.priority),
- * it's creation date (index.creation_date), or eventually by it's index name in reverse order.
- * We try to recover first shards from an index with the highest priority, if that's the same
- * we try to compare the timestamp the index is created and pick the newer first (time-based indices,
- * here the newer indices matter more). If even that is the same, we compare the index name which is useful
- * if the date is baked into the index name. ie logstash-2015.05.03.
+ * A comparator that compares {@link ShardRouting} instances based on various properties. Instances
+ * are ordered as follows.
+ *
+ * - First, system indices are ordered before non-system indices
+ * - Then indices are ordered by their priority, in descending order (index.priority)
+ * - Then newer indices are ordered before older indices, based on their creation date. This benefits
+ * time-series indices, where newer indices are considered more urgent (index.creation_date)
+ * - Lastly the index names are compared, which is useful when a date is baked into the index
+ * name, e.g.
logstash-2015.05.03
+ *
*/
public abstract class PriorityComparator implements Comparator {
@@ -43,13 +47,20 @@ public final int compare(ShardRouting o1, ShardRouting o2) {
final String o2Index = o2.getIndexName();
int cmp = 0;
if (o1Index.equals(o2Index) == false) {
- final Settings settingsO1 = getIndexSettings(o1.index());
- final Settings settingsO2 = getIndexSettings(o2.index());
- cmp = Long.compare(priority(settingsO2), priority(settingsO1));
+ final IndexMetadata metadata01 = getMetadata(o1.index());
+ final IndexMetadata metadata02 = getMetadata(o2.index());
+ cmp = Boolean.compare(metadata02.isSystem(), metadata01.isSystem());
+
if (cmp == 0) {
- cmp = Long.compare(timeCreated(settingsO2), timeCreated(settingsO1));
+ final Settings settingsO1 = metadata01.getSettings();
+ final Settings settingsO2 = metadata02.getSettings();
+ cmp = Long.compare(priority(settingsO2), priority(settingsO1));
+
if (cmp == 0) {
- cmp = o2Index.compareTo(o1Index);
+ cmp = Long.compare(timeCreated(settingsO2), timeCreated(settingsO1));
+ if (cmp == 0) {
+ cmp = o2Index.compareTo(o1Index);
+ }
}
}
}
@@ -64,7 +75,7 @@ private static long timeCreated(Settings settings) {
return settings.getAsLong(IndexMetadata.SETTING_CREATION_DATE, -1L);
}
- protected abstract Settings getIndexSettings(Index index);
+ protected abstract IndexMetadata getMetadata(Index index);
/**
* Returns a PriorityComparator that uses the RoutingAllocation index metadata to access the index setting per index.
@@ -72,9 +83,8 @@ private static long timeCreated(Settings settings) {
public static PriorityComparator getAllocationComparator(final RoutingAllocation allocation) {
return new PriorityComparator() {
@Override
- protected Settings getIndexSettings(Index index) {
- IndexMetadata indexMetadata = allocation.metadata().getIndexSafe(index);
- return indexMetadata.getSettings();
+ protected IndexMetadata getMetadata(Index index) {
+ return allocation.metadata().getIndexSafe(index);
}
};
}
diff --git a/server/src/test/java/org/elasticsearch/gateway/PriorityComparatorTests.java b/server/src/test/java/org/elasticsearch/gateway/PriorityComparatorTests.java
index ec49c501f84b7..2fa84b5c54931 100644
--- a/server/src/test/java/org/elasticsearch/gateway/PriorityComparatorTests.java
+++ b/server/src/test/java/org/elasticsearch/gateway/PriorityComparatorTests.java
@@ -18,6 +18,7 @@
*/
package org.elasticsearch.gateway;
+import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.cluster.routing.RoutingNodes;
import org.elasticsearch.cluster.routing.ShardRouting;
@@ -35,6 +36,7 @@
import java.util.Locale;
import java.util.Map;
+import static org.hamcrest.Matchers.greaterThan;
import static org.mockito.Mockito.mock;
public class PriorityComparatorTests extends ESTestCase {
@@ -52,15 +54,17 @@ public void testPreferNewIndices() {
}
shards.sort(new PriorityComparator() {
@Override
- protected Settings getIndexSettings(Index index) {
+ protected IndexMetadata getMetadata(Index index) {
+ Settings settings;
if ("oldest".equals(index.getName())) {
- return Settings.builder().put(IndexMetadata.SETTING_CREATION_DATE, 10)
- .put(IndexMetadata.SETTING_PRIORITY, 1).build();
+ settings = buildSettings(10, 1);
} else if ("newest".equals(index.getName())) {
- return Settings.builder().put(IndexMetadata.SETTING_CREATION_DATE, 100)
- .put(IndexMetadata.SETTING_PRIORITY, 1).build();
+ settings = buildSettings(100, 1);
+ } else {
+ settings = Settings.EMPTY;
}
- return Settings.EMPTY;
+
+ return IndexMetadata.builder(index.getName()).settings(settings).build();
}
});
RoutingNodes.UnassignedShards.UnassignedIterator iterator = shards.iterator();
@@ -84,15 +88,53 @@ public void testPreferPriorityIndices() {
}
shards.sort(new PriorityComparator() {
@Override
- protected Settings getIndexSettings(Index index) {
+ protected IndexMetadata getMetadata(Index index) {
+ Settings settings;
+ if ("oldest".equals(index.getName())) {
+ settings = buildSettings(10, 100);
+ } else if ("newest".equals(index.getName())) {
+ settings = buildSettings(100, 1);
+ } else {
+ settings = Settings.EMPTY;
+ }
+
+ return IndexMetadata.builder(index.getName()).settings(settings).build();
+ }
+ });
+ RoutingNodes.UnassignedShards.UnassignedIterator iterator = shards.iterator();
+ ShardRouting next = iterator.next();
+ assertEquals("oldest", next.getIndexName());
+ next = iterator.next();
+ assertEquals("newest", next.getIndexName());
+ assertFalse(iterator.hasNext());
+ }
+
+ public void testPreferSystemIndices() {
+ RoutingNodes.UnassignedShards shards = new RoutingNodes.UnassignedShards(mock(RoutingNodes.class));
+ List shardRoutings = Arrays.asList(
+ TestShardRouting.newShardRouting("oldest", 0, null, null,
+ randomBoolean(), ShardRoutingState.UNASSIGNED, new UnassignedInfo(randomFrom(UnassignedInfo.Reason.values()), "foobar")),
+ TestShardRouting.newShardRouting("newest", 0, null, null,
+ randomBoolean(), ShardRoutingState.UNASSIGNED, new UnassignedInfo(randomFrom(UnassignedInfo.Reason.values()), "foobar")));
+ Collections.shuffle(shardRoutings, random());
+ for (ShardRouting routing : shardRoutings) {
+ shards.add(routing);
+ }
+ shards.sort(new PriorityComparator() {
+ @Override
+ protected IndexMetadata getMetadata(Index index) {
+ Settings settings;
+ boolean isSystem = false;
if ("oldest".equals(index.getName())) {
- return Settings.builder().put(IndexMetadata.SETTING_CREATION_DATE, 10)
- .put(IndexMetadata.SETTING_PRIORITY, 100).build();
+ settings = buildSettings(10, 100);
+ isSystem = true;
} else if ("newest".equals(index.getName())) {
- return Settings.builder().put(IndexMetadata.SETTING_CREATION_DATE, 100)
- .put(IndexMetadata.SETTING_PRIORITY, 1).build();
+ settings = buildSettings(100, 1);
+ } else {
+ settings = Settings.EMPTY;
}
- return Settings.EMPTY;
+
+ return IndexMetadata.builder(index.getName()).system(isSystem).settings(settings).build();
}
});
RoutingNodes.UnassignedShards.UnassignedIterator iterator = shards.iterator();
@@ -106,75 +148,99 @@ protected Settings getIndexSettings(Index index) {
public void testPriorityComparatorSort() {
RoutingNodes.UnassignedShards shards = new RoutingNodes.UnassignedShards(mock(RoutingNodes.class));
int numIndices = randomIntBetween(3, 99);
- IndexMeta[] indices = new IndexMeta[numIndices];
- final Map map = new HashMap<>();
+ IndexMetadata[] indices = new IndexMetadata[numIndices];
+ final Map map = new HashMap<>();
for (int i = 0; i < indices.length; i++) {
+ int priority = 0;
+ int creationDate = 0;
+ boolean isSystem = false;
+
if (frequently()) {
- indices[i] = new IndexMeta("idx_2015_04_" + String.format(Locale.ROOT, "%02d", i), randomIntBetween(1, 1000),
- randomIntBetween(1, 10000));
- } else { // sometimes just use defaults
- indices[i] = new IndexMeta("idx_2015_04_" + String.format(Locale.ROOT, "%02d", i));
+ priority = randomIntBetween(1, 1000);
+ creationDate = randomIntBetween(1, 10000);
}
- map.put(indices[i].name, indices[i]);
+ if (rarely()) {
+ isSystem = true;
+ }
+ // else sometimes just use the defaults
+
+ indices[i] = IndexMetadata.builder(String.format(Locale.ROOT, "idx_%04d", i))
+ .system(isSystem)
+ .settings(buildSettings(creationDate, priority))
+ .build();
+
+ map.put(indices[i].getIndex().getName(), indices[i]);
}
int numShards = randomIntBetween(10, 100);
for (int i = 0; i < numShards; i++) {
- IndexMeta indexMeta = randomFrom(indices);
- shards.add(TestShardRouting.newShardRouting(indexMeta.name, randomIntBetween(1, 5), null, null,
+ IndexMetadata indexMeta = randomFrom(indices);
+ shards.add(TestShardRouting.newShardRouting(indexMeta.getIndex().getName(), randomIntBetween(1, 5), null, null,
randomBoolean(), ShardRoutingState.UNASSIGNED, new UnassignedInfo(randomFrom(UnassignedInfo.Reason.values()),
"foobar")));
}
shards.sort(new PriorityComparator() {
@Override
- protected Settings getIndexSettings(Index index) {
- IndexMeta indexMeta = map.get(index.getName());
- return indexMeta.settings;
+ protected IndexMetadata getMetadata(Index index) {
+ return map.get(index.getName());
}
});
ShardRouting previous = null;
for (ShardRouting routing : shards) {
if (previous != null) {
- IndexMeta prevMeta = map.get(previous.getIndexName());
- IndexMeta currentMeta = map.get(routing.getIndexName());
- if (prevMeta.priority == currentMeta.priority) {
- if (prevMeta.creationDate == currentMeta.creationDate) {
- if (prevMeta.name.equals(currentMeta.name) == false) {
- assertTrue("indexName mismatch, expected:" + currentMeta.name + " after " + prevMeta.name + " " +
- prevMeta.name.compareTo(currentMeta.name), prevMeta.name.compareTo(currentMeta.name) > 0);
+ IndexMetadata prevMeta = map.get(previous.getIndexName());
+ IndexMetadata currentMeta = map.get(routing.getIndexName());
+
+ if (prevMeta.isSystem() == currentMeta.isSystem()) {
+ final int prevPriority = prevMeta.getSettings().getAsInt(IndexMetadata.SETTING_PRIORITY, -1);
+ final int currentPriority = currentMeta.getSettings().getAsInt(IndexMetadata.SETTING_PRIORITY, -1);
+
+ if (prevPriority == currentPriority) {
+ final int prevCreationDate = prevMeta.getSettings().getAsInt(IndexMetadata.SETTING_CREATION_DATE, -1);
+ final int currentCreationDate = currentMeta.getSettings().getAsInt(IndexMetadata.SETTING_CREATION_DATE, -1);
+
+ if (prevCreationDate == currentCreationDate) {
+ final String prevName = prevMeta.getIndex().getName();
+ final String currentName = currentMeta.getIndex().getName();
+
+ if (prevName.equals(currentName) == false) {
+ assertThat(
+ "indexName mismatch, expected:" + currentName + " after " + prevName,
+ prevName,
+ greaterThan(currentName)
+ );
+ }
+ } else {
+ assertThat(
+ "creationDate mismatch, expected:" + currentCreationDate + " after " + prevCreationDate,
+ prevCreationDate, greaterThan(currentCreationDate)
+ );
}
} else {
- assertTrue("creationDate mismatch, expected:" + currentMeta.creationDate + " after " + prevMeta.creationDate,
- prevMeta.creationDate > currentMeta.creationDate);
+ assertThat(
+ "priority mismatch, expected:" + currentPriority + " after " + prevPriority,
+ prevPriority, greaterThan(currentPriority)
+ );
}
} else {
- assertTrue("priority mismatch, expected:" + currentMeta.priority + " after " + prevMeta.priority,
- prevMeta.priority > currentMeta.priority);
+ assertThat(
+ "system mismatch, expected:" + currentMeta.isSystem() + " after " + prevMeta.isSystem(),
+ prevMeta.isSystem(),
+ greaterThan(currentMeta.isSystem())
+ );
}
}
previous = routing;
}
}
- private static class IndexMeta {
- final String name;
- final int priority;
- final long creationDate;
- final Settings settings;
-
- private IndexMeta(String name) { // default
- this.name = name;
- this.priority = 1;
- this.creationDate = -1;
- this.settings = Settings.EMPTY;
- }
-
- private IndexMeta(String name, int priority, long creationDate) {
- this.name = name;
- this.priority = priority;
- this.creationDate = creationDate;
- this.settings = Settings.builder().put(IndexMetadata.SETTING_CREATION_DATE, creationDate)
- .put(IndexMetadata.SETTING_PRIORITY, priority).build();
- }
+ private static Settings buildSettings(int creationDate, int priority) {
+ return Settings.builder()
+ .put(IndexMetadata.SETTING_CREATION_DATE, creationDate)
+ .put(IndexMetadata.SETTING_PRIORITY, priority)
+ .put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
+ .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
+ .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
+ .build();
}
}