From d9d452a1ef15f8b37677544ae6f1c4672462cef5 Mon Sep 17 00:00:00 2001 From: Shay Banon Date: Fri, 23 Sep 2011 17:35:31 +0300 Subject: [PATCH] Allow to disable shard allocations, closes #1358. --- .../decider/AllocationDeciders.java | 1 + .../decider/AllocationDecidersModule.java | 1 + .../decider/DisableAllocationDecider.java | 77 +++++++++++++ .../allocation/DisableAllocationTests.java | 107 ++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/DisableAllocationDecider.java create mode 100644 modules/elasticsearch/src/test/java/org/elasticsearch/cluster/routing/allocation/DisableAllocationTests.java diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/AllocationDeciders.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/AllocationDeciders.java index 551ed870dec..36e29614cbc 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/AllocationDeciders.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/AllocationDeciders.java @@ -45,6 +45,7 @@ public class AllocationDeciders extends AllocationDecider { .add(new RebalanceOnlyWhenActiveAllocationDecider(settings)) .add(new ClusterRebalanceAllocationDecider(settings)) .add(new ConcurrentRebalanceAllocationDecider(settings)) + .add(new DisableAllocationDecider(settings, nodeSettingsService)) .add(new AwarenessAllocationDecider(settings, nodeSettingsService)) .build() ); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/AllocationDecidersModule.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/AllocationDecidersModule.java index 675fbe8bf1f..2bece7079e8 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/AllocationDecidersModule.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/AllocationDecidersModule.java @@ -47,6 +47,7 @@ public class AllocationDecidersModule extends AbstractModule { allocationMultibinder.addBinding().to(RebalanceOnlyWhenActiveAllocationDecider.class); allocationMultibinder.addBinding().to(ClusterRebalanceAllocationDecider.class); allocationMultibinder.addBinding().to(ConcurrentRebalanceAllocationDecider.class); + allocationMultibinder.addBinding().to(DisableAllocationDecider.class); allocationMultibinder.addBinding().to(AwarenessAllocationDecider.class); for (Class allocation : allocations) { allocationMultibinder.addBinding().to(allocation); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/DisableAllocationDecider.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/DisableAllocationDecider.java new file mode 100644 index 00000000000..5e6acf73d70 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/allocation/decider/DisableAllocationDecider.java @@ -0,0 +1,77 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.cluster.routing.allocation.decider; + +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.cluster.routing.RoutingNode; +import org.elasticsearch.cluster.routing.ShardRouting; +import org.elasticsearch.cluster.routing.allocation.RoutingAllocation; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.node.settings.NodeSettingsService; + +/** + */ +public class DisableAllocationDecider extends AllocationDecider { + + static { + MetaData.addDynamicSettings( + "cluster.routing.allocation.disable_allocation", + "cluster.routing.allocation.disable_replica_allocation" + ); + } + + class ApplySettings implements NodeSettingsService.Listener { + @Override public void onRefreshSettings(Settings settings) { + boolean disableAllocation = settings.getAsBoolean("cluster.routing.allocation.disable_allocation", DisableAllocationDecider.this.disableAllocation); + if (disableAllocation != DisableAllocationDecider.this.disableAllocation) { + logger.info("updating [cluster.routing.allocation.disable_allocation] from [{}] to [{}]", DisableAllocationDecider.this.disableAllocation, disableAllocation); + DisableAllocationDecider.this.disableAllocation = disableAllocation; + } + + boolean disableReplicaAllocation = settings.getAsBoolean("cluster.routing.allocation.disable_replica_allocation", DisableAllocationDecider.this.disableReplicaAllocation); + if (disableReplicaAllocation != DisableAllocationDecider.this.disableReplicaAllocation) { + logger.info("updating [cluster.routing.allocation.disable_replica_allocation] from [{}] to [{}]", DisableAllocationDecider.this.disableReplicaAllocation, disableReplicaAllocation); + DisableAllocationDecider.this.disableReplicaAllocation = disableReplicaAllocation; + } + } + } + + private volatile boolean disableAllocation; + private volatile boolean disableReplicaAllocation; + + @Inject public DisableAllocationDecider(Settings settings, NodeSettingsService nodeSettingsService) { + super(settings); + this.disableAllocation = settings.getAsBoolean("cluster.routing.allocation.disable_allocation", false); + this.disableReplicaAllocation = settings.getAsBoolean("cluster.routing.allocation.disable_replica_allocation", false); + + nodeSettingsService.addListener(new ApplySettings()); + } + + @Override public Decision canAllocate(ShardRouting shardRouting, RoutingNode node, RoutingAllocation allocation) { + if (disableAllocation) { + return Decision.NO; + } + if (disableReplicaAllocation) { + return shardRouting.primary() ? Decision.YES : Decision.NO; + } + return Decision.YES; + } +} diff --git a/modules/elasticsearch/src/test/java/org/elasticsearch/cluster/routing/allocation/DisableAllocationTests.java b/modules/elasticsearch/src/test/java/org/elasticsearch/cluster/routing/allocation/DisableAllocationTests.java new file mode 100644 index 00000000000..18ed1c0a936 --- /dev/null +++ b/modules/elasticsearch/src/test/java/org/elasticsearch/cluster/routing/allocation/DisableAllocationTests.java @@ -0,0 +1,107 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.cluster.routing.allocation; + +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.cluster.routing.RoutingTable; +import org.elasticsearch.common.logging.ESLogger; +import org.elasticsearch.common.logging.Loggers; +import org.testng.annotations.Test; + +import static org.elasticsearch.cluster.ClusterState.*; +import static org.elasticsearch.cluster.metadata.IndexMetaData.*; +import static org.elasticsearch.cluster.metadata.MetaData.*; +import static org.elasticsearch.cluster.node.DiscoveryNodes.*; +import static org.elasticsearch.cluster.routing.RoutingBuilders.*; +import static org.elasticsearch.cluster.routing.ShardRoutingState.*; +import static org.elasticsearch.cluster.routing.allocation.RoutingAllocationTests.*; +import static org.elasticsearch.common.settings.ImmutableSettings.*; +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.Matchers.*; + +/** + */ +@Test +public class DisableAllocationTests { + + private final ESLogger logger = Loggers.getLogger(DisableAllocationTests.class); + + @Test public void testDisableAllocation() { + AllocationService strategy = new AllocationService(settingsBuilder() + .put("cluster.routing.allocation.disable_allocation", true) + .build()); + + logger.info("Building initial routing table"); + + MetaData metaData = newMetaDataBuilder() + .put(newIndexMetaDataBuilder("test").numberOfShards(1).numberOfReplicas(1)) + .build(); + + RoutingTable routingTable = routingTable() + .add(indexRoutingTable("test").initializeEmpty(metaData.index("test"))) + .build(); + + ClusterState clusterState = newClusterStateBuilder().metaData(metaData).routingTable(routingTable).build(); + + logger.info("--> adding two nodes on same rack and do rerouting"); + clusterState = newClusterStateBuilder().state(clusterState).nodes(newNodesBuilder() + .put(newNode("node1")) + .put(newNode("node2")) + ).build(); + routingTable = strategy.reroute(clusterState).routingTable(); + clusterState = newClusterStateBuilder().state(clusterState).routingTable(routingTable).build(); + assertThat(clusterState.routingNodes().shardsWithState(INITIALIZING).size(), equalTo(0)); + + } + + @Test public void testDisableReplicaAllocation() { + AllocationService strategy = new AllocationService(settingsBuilder() + .put("cluster.routing.allocation.disable_replica_allocation", true) + .build()); + + logger.info("Building initial routing table"); + + MetaData metaData = newMetaDataBuilder() + .put(newIndexMetaDataBuilder("test").numberOfShards(1).numberOfReplicas(1)) + .build(); + + RoutingTable routingTable = routingTable() + .add(indexRoutingTable("test").initializeEmpty(metaData.index("test"))) + .build(); + + ClusterState clusterState = newClusterStateBuilder().metaData(metaData).routingTable(routingTable).build(); + + logger.info("--> adding two nodes on same rack and do rerouting"); + clusterState = newClusterStateBuilder().state(clusterState).nodes(newNodesBuilder() + .put(newNode("node1")) + .put(newNode("node2")) + ).build(); + routingTable = strategy.reroute(clusterState).routingTable(); + clusterState = newClusterStateBuilder().state(clusterState).routingTable(routingTable).build(); + assertThat(clusterState.routingNodes().shardsWithState(INITIALIZING).size(), equalTo(1)); + + logger.info("--> start the shards (primaries)"); + routingTable = strategy.applyStartedShards(clusterState, clusterState.routingNodes().shardsWithState(INITIALIZING)).routingTable(); + clusterState = newClusterStateBuilder().state(clusterState).routingTable(routingTable).build(); + + assertThat(clusterState.routingNodes().shardsWithState(INITIALIZING).size(), equalTo(0)); + } +}