|
@@ -19,6 +19,7 @@
|
|
|
package org.elasticsearch.cluster.routing.allocation;
|
|
|
|
|
|
import org.elasticsearch.Version;
|
|
|
+import org.elasticsearch.action.ActionListener;
|
|
|
import org.elasticsearch.cluster.ClusterInfo;
|
|
|
import org.elasticsearch.cluster.ClusterName;
|
|
|
import org.elasticsearch.cluster.ClusterState;
|
|
@@ -35,16 +36,17 @@ import org.elasticsearch.common.settings.ClusterSettings;
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
+import java.util.Collections;
|
|
|
import java.util.HashSet;
|
|
|
import java.util.Set;
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
+import java.util.concurrent.atomic.AtomicLong;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
|
|
import static org.elasticsearch.cluster.routing.ShardRoutingState.INITIALIZING;
|
|
|
|
|
|
public class DiskThresholdMonitorTests extends ESAllocationTestCase {
|
|
|
|
|
|
-
|
|
|
public void testMarkFloodStageIndicesReadOnly() {
|
|
|
AllocationService allocation = createAllocationService(Settings.builder()
|
|
|
.put("cluster.routing.allocation.node_concurrent_recoveries", 10).build());
|
|
@@ -61,7 +63,6 @@ public class DiskThresholdMonitorTests extends ESAllocationTestCase {
|
|
|
.addAsNew(metaData.index("test"))
|
|
|
.addAsNew(metaData.index("test_1"))
|
|
|
.addAsNew(metaData.index("test_2"))
|
|
|
-
|
|
|
.build();
|
|
|
ClusterState clusterState = ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY))
|
|
|
.metaData(metaData).routingTable(routingTable).build();
|
|
@@ -74,18 +75,21 @@ public class DiskThresholdMonitorTests extends ESAllocationTestCase {
|
|
|
ClusterState finalState = clusterState;
|
|
|
AtomicBoolean reroute = new AtomicBoolean(false);
|
|
|
AtomicReference<Set<String>> indices = new AtomicReference<>();
|
|
|
+ AtomicLong currentTime = new AtomicLong();
|
|
|
DiskThresholdMonitor monitor = new DiskThresholdMonitor(settings, () -> finalState,
|
|
|
- new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), null) {
|
|
|
+ new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), null, currentTime::get) {
|
|
|
@Override
|
|
|
- protected void reroute() {
|
|
|
- assertTrue(reroute.compareAndSet(false, true));
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- protected void markIndicesReadOnly(Set<String> indicesToMarkReadOnly) {
|
|
|
+ protected void markIndicesReadOnly(Set<String> indicesToMarkReadOnly, ActionListener<Void> listener) {
|
|
|
assertTrue(indices.compareAndSet(null, indicesToMarkReadOnly));
|
|
|
+ listener.onResponse(null);
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+ monitor.setRerouteAction((reason, listener) -> {
|
|
|
+ assertTrue(reroute.compareAndSet(false, true));
|
|
|
+ listener.onResponse(null);
|
|
|
+ });
|
|
|
+
|
|
|
ImmutableOpenMap.Builder<String, DiskUsage> builder = ImmutableOpenMap.builder();
|
|
|
builder.put("node1", new DiskUsage("node1","node1", "/foo/bar", 100, 4));
|
|
|
builder.put("node2", new DiskUsage("node2","node2", "/foo/bar", 100, 30));
|
|
@@ -97,6 +101,7 @@ public class DiskThresholdMonitorTests extends ESAllocationTestCase {
|
|
|
builder = ImmutableOpenMap.builder();
|
|
|
builder.put("node1", new DiskUsage("node1","node1", "/foo/bar", 100, 4));
|
|
|
builder.put("node2", new DiskUsage("node2","node2", "/foo/bar", 100, 5));
|
|
|
+ currentTime.addAndGet(randomLongBetween(60001, 120000));
|
|
|
monitor.onNewInfo(new ClusterInfo(builder.build(), null, null, null));
|
|
|
assertTrue(reroute.get());
|
|
|
assertEquals(new HashSet<>(Arrays.asList("test_1", "test_2")), indices.get());
|
|
@@ -114,17 +119,17 @@ public class DiskThresholdMonitorTests extends ESAllocationTestCase {
|
|
|
assertTrue(anotherFinalClusterState.blocks().indexBlocked(ClusterBlockLevel.WRITE, "test_2"));
|
|
|
|
|
|
monitor = new DiskThresholdMonitor(settings, () -> anotherFinalClusterState,
|
|
|
- new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), null) {
|
|
|
+ new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), null, currentTime::get) {
|
|
|
@Override
|
|
|
- protected void reroute() {
|
|
|
- assertTrue(reroute.compareAndSet(false, true));
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- protected void markIndicesReadOnly(Set<String> indicesToMarkReadOnly) {
|
|
|
+ protected void markIndicesReadOnly(Set<String> indicesToMarkReadOnly, ActionListener<Void> listener) {
|
|
|
assertTrue(indices.compareAndSet(null, indicesToMarkReadOnly));
|
|
|
+ listener.onResponse(null);
|
|
|
}
|
|
|
};
|
|
|
+ monitor.setRerouteAction((reason, listener) -> {
|
|
|
+ assertTrue(reroute.compareAndSet(false, true));
|
|
|
+ listener.onResponse(null);
|
|
|
+ });
|
|
|
|
|
|
indices.set(null);
|
|
|
reroute.set(false);
|
|
@@ -133,6 +138,90 @@ public class DiskThresholdMonitorTests extends ESAllocationTestCase {
|
|
|
builder.put("node2", new DiskUsage("node2","node2", "/foo/bar", 100, 5));
|
|
|
monitor.onNewInfo(new ClusterInfo(builder.build(), null, null, null));
|
|
|
assertTrue(reroute.get());
|
|
|
- assertEquals(new HashSet<>(Arrays.asList("test_1")), indices.get());
|
|
|
+ assertEquals(Collections.singleton("test_1"), indices.get());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testDoesNotSubmitRerouteTaskTooFrequently() {
|
|
|
+ final ClusterState clusterState = ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY))
|
|
|
+ .nodes(DiscoveryNodes.builder().add(newNode("node1")).add(newNode("node2"))).build();
|
|
|
+ AtomicLong currentTime = new AtomicLong();
|
|
|
+ AtomicReference<ActionListener<Void>> listenerReference = new AtomicReference<>();
|
|
|
+ DiskThresholdMonitor monitor = new DiskThresholdMonitor(Settings.EMPTY, () -> clusterState,
|
|
|
+ new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), null, currentTime::get) {
|
|
|
+ @Override
|
|
|
+ protected void markIndicesReadOnly(Set<String> indicesToMarkReadOnly, ActionListener<Void> listener) {
|
|
|
+ throw new AssertionError("unexpected");
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ monitor.setRerouteAction((reason, listener) -> {
|
|
|
+ assertNotNull(listener);
|
|
|
+ assertTrue(listenerReference.compareAndSet(null, listener));
|
|
|
+ });
|
|
|
+
|
|
|
+ final ImmutableOpenMap.Builder<String, DiskUsage> allDisksOkBuilder;
|
|
|
+ allDisksOkBuilder = ImmutableOpenMap.builder();
|
|
|
+ allDisksOkBuilder.put("node1", new DiskUsage("node1","node1", "/foo/bar", 100, 50));
|
|
|
+ allDisksOkBuilder.put("node2", new DiskUsage("node2","node2", "/foo/bar", 100, 50));
|
|
|
+ final ImmutableOpenMap<String, DiskUsage> allDisksOk = allDisksOkBuilder.build();
|
|
|
+
|
|
|
+ final ImmutableOpenMap.Builder<String, DiskUsage> oneDiskAboveWatermarkBuilder = ImmutableOpenMap.builder();
|
|
|
+ oneDiskAboveWatermarkBuilder.put("node1", new DiskUsage("node1", "node1", "/foo/bar", 100, between(5, 9)));
|
|
|
+ oneDiskAboveWatermarkBuilder.put("node2", new DiskUsage("node2", "node2", "/foo/bar", 100, 50));
|
|
|
+ final ImmutableOpenMap<String, DiskUsage> oneDiskAboveWatermark = oneDiskAboveWatermarkBuilder.build();
|
|
|
+
|
|
|
+ // should not reroute when all disks are ok
|
|
|
+ currentTime.addAndGet(randomLongBetween(0, 120000));
|
|
|
+ monitor.onNewInfo(new ClusterInfo(allDisksOk, null, null, null));
|
|
|
+ assertNull(listenerReference.get());
|
|
|
+
|
|
|
+ // should reroute when one disk goes over the watermark
|
|
|
+ currentTime.addAndGet(randomLongBetween(0, 120000));
|
|
|
+ monitor.onNewInfo(new ClusterInfo(oneDiskAboveWatermark, null, null, null));
|
|
|
+ assertNotNull(listenerReference.get());
|
|
|
+ listenerReference.getAndSet(null).onResponse(null);
|
|
|
+
|
|
|
+ if (randomBoolean()) {
|
|
|
+ // should not re-route again within the reroute interval
|
|
|
+ currentTime.addAndGet(randomLongBetween(0,
|
|
|
+ DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_REROUTE_INTERVAL_SETTING.get(Settings.EMPTY).millis()));
|
|
|
+ monitor.onNewInfo(new ClusterInfo(allDisksOk, null, null, null));
|
|
|
+ assertNull(listenerReference.get());
|
|
|
+ }
|
|
|
+
|
|
|
+ // should reroute again when one disk is still over the watermark
|
|
|
+ currentTime.addAndGet(randomLongBetween(
|
|
|
+ DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_REROUTE_INTERVAL_SETTING.get(Settings.EMPTY).millis() + 1, 120000));
|
|
|
+ monitor.onNewInfo(new ClusterInfo(oneDiskAboveWatermark, null, null, null));
|
|
|
+ assertNotNull(listenerReference.get());
|
|
|
+ final ActionListener<Void> rerouteListener1 = listenerReference.getAndSet(null);
|
|
|
+
|
|
|
+ // should not re-route again before reroute has completed
|
|
|
+ currentTime.addAndGet(randomLongBetween(0, 120000));
|
|
|
+ monitor.onNewInfo(new ClusterInfo(allDisksOk, null, null, null));
|
|
|
+ assertNull(listenerReference.get());
|
|
|
+
|
|
|
+ // complete reroute
|
|
|
+ rerouteListener1.onResponse(null);
|
|
|
+
|
|
|
+ if (randomBoolean()) {
|
|
|
+ // should not re-route again within the reroute interval
|
|
|
+ currentTime.addAndGet(randomLongBetween(0,
|
|
|
+ DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_REROUTE_INTERVAL_SETTING.get(Settings.EMPTY).millis()));
|
|
|
+ monitor.onNewInfo(new ClusterInfo(allDisksOk, null, null, null));
|
|
|
+ assertNull(listenerReference.get());
|
|
|
+ }
|
|
|
+
|
|
|
+ // should reroute again after the reroute interval
|
|
|
+ currentTime.addAndGet(randomLongBetween(
|
|
|
+ DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_REROUTE_INTERVAL_SETTING.get(Settings.EMPTY).millis() + 1, 120000));
|
|
|
+ monitor.onNewInfo(new ClusterInfo(allDisksOk, null, null, null));
|
|
|
+ assertNotNull(listenerReference.get());
|
|
|
+ listenerReference.getAndSet(null).onResponse(null);
|
|
|
+
|
|
|
+ // should not reroute again when it is not required
|
|
|
+ currentTime.addAndGet(randomLongBetween(0, 120000));
|
|
|
+ monitor.onNewInfo(new ClusterInfo(allDisksOk, null, null, null));
|
|
|
+ assertNull(listenerReference.get());
|
|
|
}
|
|
|
}
|