2010-08-08 09:17:09 +03:00
|
|
|
/*
|
2011-12-06 02:42:25 +02:00
|
|
|
* Licensed to ElasticSearch and Shay Banon under one
|
2010-08-08 09:17:09 +03:00
|
|
|
* or more contributor license agreements. See the NOTICE file
|
|
|
|
* distributed with this work for additional information
|
2011-12-06 02:42:25 +02:00
|
|
|
* regarding copyright ownership. ElasticSearch licenses this
|
2010-08-08 09:17:09 +03:00
|
|
|
* 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.metadata;
|
|
|
|
|
2011-12-06 02:42:25 +02:00
|
|
|
import com.google.common.collect.Sets;
|
2011-06-08 13:49:22 +03:00
|
|
|
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
2011-12-06 02:42:25 +02:00
|
|
|
import org.elasticsearch.cluster.*;
|
2011-12-14 17:40:21 -05:00
|
|
|
import org.elasticsearch.cluster.block.ClusterBlocks;
|
2010-08-08 09:17:09 +03:00
|
|
|
import org.elasticsearch.cluster.routing.RoutingTable;
|
2011-09-06 17:11:55 +03:00
|
|
|
import org.elasticsearch.cluster.routing.allocation.AllocationService;
|
2011-07-26 11:16:13 +03:00
|
|
|
import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
|
2011-03-21 16:18:03 +02:00
|
|
|
import org.elasticsearch.common.Booleans;
|
2013-02-05 22:17:49 +01:00
|
|
|
import org.elasticsearch.common.Priority;
|
2010-08-08 09:17:09 +03:00
|
|
|
import org.elasticsearch.common.component.AbstractComponent;
|
|
|
|
import org.elasticsearch.common.inject.Inject;
|
2010-09-04 14:04:51 +03:00
|
|
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
2010-08-08 09:17:09 +03:00
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
|
|
2010-09-04 14:04:51 +03:00
|
|
|
import java.util.Map;
|
2011-05-31 22:27:43 +03:00
|
|
|
import java.util.Set;
|
2010-09-04 14:04:51 +03:00
|
|
|
|
2011-12-06 02:42:25 +02:00
|
|
|
import static org.elasticsearch.cluster.ClusterState.newClusterStateBuilder;
|
2011-07-26 11:16:13 +03:00
|
|
|
|
2010-08-08 09:17:09 +03:00
|
|
|
/**
|
2011-12-06 02:42:25 +02:00
|
|
|
*
|
2010-08-08 09:17:09 +03:00
|
|
|
*/
|
2011-01-12 16:27:36 +02:00
|
|
|
public class MetaDataUpdateSettingsService extends AbstractComponent implements ClusterStateListener {
|
2010-08-08 09:17:09 +03:00
|
|
|
|
|
|
|
private final ClusterService clusterService;
|
|
|
|
|
2011-09-06 17:11:55 +03:00
|
|
|
private final AllocationService allocationService;
|
2011-07-26 11:16:13 +03:00
|
|
|
|
2011-12-06 02:42:25 +02:00
|
|
|
@Inject
|
|
|
|
public MetaDataUpdateSettingsService(Settings settings, ClusterService clusterService, AllocationService allocationService) {
|
2010-08-08 09:17:09 +03:00
|
|
|
super(settings);
|
|
|
|
this.clusterService = clusterService;
|
2011-01-12 16:27:36 +02:00
|
|
|
this.clusterService.add(this);
|
2011-09-06 17:11:55 +03:00
|
|
|
this.allocationService = allocationService;
|
2011-01-12 16:27:36 +02:00
|
|
|
}
|
|
|
|
|
2011-12-06 02:42:25 +02:00
|
|
|
@Override
|
|
|
|
public void clusterChanged(ClusterChangedEvent event) {
|
2011-01-12 16:27:36 +02:00
|
|
|
// update an index with number of replicas based on data nodes if possible
|
|
|
|
if (!event.state().nodes().localNodeMaster()) {
|
|
|
|
return;
|
|
|
|
}
|
2011-08-12 02:21:47 +03:00
|
|
|
// we need to do this each time in case it was changed by update settings
|
2011-01-12 16:27:36 +02:00
|
|
|
for (final IndexMetaData indexMetaData : event.state().metaData()) {
|
2011-01-13 16:20:31 +02:00
|
|
|
String autoExpandReplicas = indexMetaData.settings().get(IndexMetaData.SETTING_AUTO_EXPAND_REPLICAS);
|
2011-03-21 16:18:03 +02:00
|
|
|
if (autoExpandReplicas != null && Booleans.parseBoolean(autoExpandReplicas, true)) { // Booleans only work for false values, just as we want it here
|
2011-01-12 16:27:36 +02:00
|
|
|
try {
|
2011-03-21 14:36:28 +02:00
|
|
|
int min;
|
2011-01-12 16:27:36 +02:00
|
|
|
int max;
|
2011-03-21 14:36:28 +02:00
|
|
|
try {
|
|
|
|
min = Integer.parseInt(autoExpandReplicas.substring(0, autoExpandReplicas.indexOf('-')));
|
|
|
|
String sMax = autoExpandReplicas.substring(autoExpandReplicas.indexOf('-') + 1);
|
|
|
|
if (sMax.equals("all")) {
|
|
|
|
max = event.state().nodes().dataNodes().size() - 1;
|
|
|
|
} else {
|
|
|
|
max = Integer.parseInt(sMax);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
2011-03-21 14:36:56 +02:00
|
|
|
logger.warn("failed to set [{}], wrong format [{}]", e, IndexMetaData.SETTING_AUTO_EXPAND_REPLICAS, autoExpandReplicas);
|
2011-03-21 14:36:28 +02:00
|
|
|
continue;
|
2011-01-12 16:27:36 +02:00
|
|
|
}
|
|
|
|
|
2011-08-12 02:21:47 +03:00
|
|
|
int numberOfReplicas = event.state().nodes().dataNodes().size() - 1;
|
|
|
|
if (numberOfReplicas < min) {
|
|
|
|
numberOfReplicas = min;
|
|
|
|
} else if (numberOfReplicas > max) {
|
|
|
|
numberOfReplicas = max;
|
|
|
|
}
|
|
|
|
|
2011-01-13 16:20:31 +02:00
|
|
|
// same value, nothing to do there
|
|
|
|
if (numberOfReplicas == indexMetaData.numberOfReplicas()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-01-12 16:27:36 +02:00
|
|
|
if (numberOfReplicas >= min && numberOfReplicas <= max) {
|
2011-08-12 02:21:47 +03:00
|
|
|
final int fNumberOfReplicas = numberOfReplicas;
|
|
|
|
Settings settings = ImmutableSettings.settingsBuilder().put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, fNumberOfReplicas).build();
|
2011-01-12 16:27:36 +02:00
|
|
|
updateSettings(settings, new String[]{indexMetaData.index()}, new Listener() {
|
2011-12-06 02:42:25 +02:00
|
|
|
@Override
|
|
|
|
public void onSuccess() {
|
2011-08-12 02:21:47 +03:00
|
|
|
logger.info("[{}] auto expanded replicas to [{}]", indexMetaData.index(), fNumberOfReplicas);
|
2011-01-12 16:27:36 +02:00
|
|
|
}
|
|
|
|
|
2011-12-06 02:42:25 +02:00
|
|
|
@Override
|
|
|
|
public void onFailure(Throwable t) {
|
2011-08-12 02:21:47 +03:00
|
|
|
logger.warn("[{}] fail to auto expand replicas to [{}]", indexMetaData.index(), fNumberOfReplicas);
|
2011-01-12 16:27:36 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
logger.warn("[{}] failed to parse auto expand replicas", e, indexMetaData.index());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-08-08 09:17:09 +03:00
|
|
|
}
|
|
|
|
|
2010-09-04 14:04:51 +03:00
|
|
|
public void updateSettings(final Settings pSettings, final String[] indices, final Listener listener) {
|
|
|
|
ImmutableSettings.Builder updatedSettingsBuilder = ImmutableSettings.settingsBuilder();
|
|
|
|
for (Map.Entry<String, String> entry : pSettings.getAsMap().entrySet()) {
|
2011-05-31 22:27:43 +03:00
|
|
|
if (entry.getKey().equals("index")) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-09-04 14:04:51 +03:00
|
|
|
if (!entry.getKey().startsWith("index.")) {
|
|
|
|
updatedSettingsBuilder.put("index." + entry.getKey(), entry.getValue());
|
|
|
|
} else {
|
|
|
|
updatedSettingsBuilder.put(entry.getKey(), entry.getValue());
|
|
|
|
}
|
|
|
|
}
|
2011-06-08 13:49:22 +03:00
|
|
|
// never allow to change the number of shards
|
|
|
|
for (String key : updatedSettingsBuilder.internalMap().keySet()) {
|
|
|
|
if (key.equals(IndexMetaData.SETTING_NUMBER_OF_SHARDS)) {
|
|
|
|
listener.onFailure(new ElasticSearchIllegalArgumentException("can't change the number of shards for an index"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-19 17:15:05 +03:00
|
|
|
final Settings closeSettings = updatedSettingsBuilder.build();
|
|
|
|
|
|
|
|
final Set<String> removedSettings = Sets.newHashSet();
|
2011-05-31 22:27:43 +03:00
|
|
|
for (String key : updatedSettingsBuilder.internalMap().keySet()) {
|
2011-09-06 22:01:25 +03:00
|
|
|
if (!IndexMetaData.hasDynamicSetting(key)) {
|
2011-05-31 22:27:43 +03:00
|
|
|
removedSettings.add(key);
|
|
|
|
}
|
2011-05-30 19:26:45 +03:00
|
|
|
}
|
2011-05-31 22:27:43 +03:00
|
|
|
if (!removedSettings.isEmpty()) {
|
|
|
|
for (String removedSetting : removedSettings) {
|
|
|
|
updatedSettingsBuilder.remove(removedSetting);
|
|
|
|
}
|
|
|
|
}
|
2011-06-19 17:15:05 +03:00
|
|
|
final Settings openSettings = updatedSettingsBuilder.build();
|
2011-05-31 22:27:43 +03:00
|
|
|
|
2013-02-05 22:17:49 +01:00
|
|
|
clusterService.submitStateUpdateTask("update-settings", Priority.URGENT, new ProcessedClusterStateUpdateTask() {
|
2011-12-06 02:42:25 +02:00
|
|
|
@Override
|
|
|
|
public ClusterState execute(ClusterState currentState) {
|
2010-08-08 09:17:09 +03:00
|
|
|
try {
|
|
|
|
String[] actualIndices = currentState.metaData().concreteIndices(indices);
|
2011-06-29 14:51:32 +03:00
|
|
|
RoutingTable.Builder routingTableBuilder = RoutingTable.builder().routingTable(currentState.routingTable());
|
2010-08-08 09:17:09 +03:00
|
|
|
MetaData.Builder metaDataBuilder = MetaData.newMetaDataBuilder().metaData(currentState.metaData());
|
|
|
|
|
2013-02-13 13:10:56 +01:00
|
|
|
// allow to change any settings to a close index, and only allow dynamic settings to be changed
|
|
|
|
// on an open index
|
|
|
|
Set<String> openIndices = Sets.newHashSet();
|
|
|
|
Set<String> closeIndices = Sets.newHashSet();
|
|
|
|
for (String index : actualIndices) {
|
|
|
|
if (currentState.metaData().index(index).state() == IndexMetaData.State.OPEN) {
|
|
|
|
openIndices.add(index);
|
|
|
|
} else {
|
|
|
|
closeIndices.add(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!removedSettings.isEmpty() && !openIndices.isEmpty()) {
|
|
|
|
listener.onFailure(new ElasticSearchIllegalArgumentException(String.format(
|
|
|
|
"Can't update non dynamic settings[%s] for open indices[%s]",
|
|
|
|
removedSettings,
|
|
|
|
openIndices
|
|
|
|
)));
|
|
|
|
return currentState;
|
|
|
|
}
|
|
|
|
|
2011-06-19 17:15:05 +03:00
|
|
|
int updatedNumberOfReplicas = openSettings.getAsInt(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, -1);
|
2010-08-08 09:17:09 +03:00
|
|
|
if (updatedNumberOfReplicas != -1) {
|
|
|
|
routingTableBuilder.updateNumberOfReplicas(updatedNumberOfReplicas, actualIndices);
|
|
|
|
metaDataBuilder.updateNumberOfReplicas(updatedNumberOfReplicas, actualIndices);
|
2011-06-19 17:15:05 +03:00
|
|
|
logger.info("updating number_of_replicas to [{}] for indices {}", updatedNumberOfReplicas, actualIndices);
|
|
|
|
}
|
|
|
|
|
2011-12-14 17:40:21 -05:00
|
|
|
ClusterBlocks.Builder blocks = ClusterBlocks.builder().blocks(currentState.blocks());
|
|
|
|
Boolean updatedReadOnly = openSettings.getAsBoolean(IndexMetaData.SETTING_READ_ONLY, null);
|
|
|
|
if (updatedReadOnly != null) {
|
|
|
|
for (String index : actualIndices) {
|
|
|
|
if (updatedReadOnly) {
|
|
|
|
blocks.addIndexBlock(index, IndexMetaData.INDEX_READ_ONLY_BLOCK);
|
2011-12-27 20:35:07 +02:00
|
|
|
} else {
|
2011-12-14 17:40:21 -05:00
|
|
|
blocks.removeIndexBlock(index, IndexMetaData.INDEX_READ_ONLY_BLOCK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-08 21:56:13 +02:00
|
|
|
Boolean updateMetaDataBlock = openSettings.getAsBoolean(IndexMetaData.SETTING_BLOCKS_METADATA, null);
|
|
|
|
if (updateMetaDataBlock != null) {
|
|
|
|
for (String index : actualIndices) {
|
|
|
|
if (updateMetaDataBlock) {
|
|
|
|
blocks.addIndexBlock(index, IndexMetaData.INDEX_METADATA_BLOCK);
|
|
|
|
} else {
|
|
|
|
blocks.removeIndexBlock(index, IndexMetaData.INDEX_METADATA_BLOCK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Boolean updateWriteBlock = openSettings.getAsBoolean(IndexMetaData.SETTING_BLOCKS_WRITE, null);
|
|
|
|
if (updateWriteBlock != null) {
|
|
|
|
for (String index : actualIndices) {
|
|
|
|
if (updateWriteBlock) {
|
|
|
|
blocks.addIndexBlock(index, IndexMetaData.INDEX_WRITE_BLOCK);
|
|
|
|
} else {
|
|
|
|
blocks.removeIndexBlock(index, IndexMetaData.INDEX_WRITE_BLOCK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Boolean updateReadBlock = openSettings.getAsBoolean(IndexMetaData.SETTING_BLOCKS_READ, null);
|
|
|
|
if (updateReadBlock != null) {
|
|
|
|
for (String index : actualIndices) {
|
|
|
|
if (updateReadBlock) {
|
|
|
|
blocks.addIndexBlock(index, IndexMetaData.INDEX_READ_BLOCK);
|
|
|
|
} else {
|
|
|
|
blocks.removeIndexBlock(index, IndexMetaData.INDEX_READ_BLOCK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-14 17:40:21 -05:00
|
|
|
|
2011-06-19 17:15:05 +03:00
|
|
|
if (!openIndices.isEmpty()) {
|
|
|
|
String[] indices = openIndices.toArray(new String[openIndices.size()]);
|
|
|
|
metaDataBuilder.updateSettings(openSettings, indices);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!closeIndices.isEmpty()) {
|
|
|
|
String[] indices = closeIndices.toArray(new String[closeIndices.size()]);
|
|
|
|
metaDataBuilder.updateSettings(closeSettings, indices);
|
2010-08-08 09:17:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-14 17:40:21 -05:00
|
|
|
ClusterState updatedState = ClusterState.builder().state(currentState).metaData(metaDataBuilder).routingTable(routingTableBuilder).blocks(blocks).build();
|
2011-07-26 11:16:13 +03:00
|
|
|
|
|
|
|
// now, reroute in case things change that require it (like number of replicas)
|
2011-09-06 17:11:55 +03:00
|
|
|
RoutingAllocation.Result routingResult = allocationService.reroute(updatedState);
|
2011-07-26 11:16:13 +03:00
|
|
|
updatedState = newClusterStateBuilder().state(updatedState).routingResult(routingResult).build();
|
|
|
|
|
|
|
|
return updatedState;
|
2010-08-08 09:17:09 +03:00
|
|
|
} catch (Exception e) {
|
|
|
|
listener.onFailure(e);
|
|
|
|
return currentState;
|
|
|
|
}
|
|
|
|
}
|
2010-10-19 19:33:27 +02:00
|
|
|
|
2011-12-06 02:42:25 +02:00
|
|
|
@Override
|
|
|
|
public void clusterStateProcessed(ClusterState clusterState) {
|
2010-10-19 19:33:27 +02:00
|
|
|
listener.onSuccess();
|
|
|
|
}
|
2010-08-08 09:17:09 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public static interface Listener {
|
|
|
|
void onSuccess();
|
|
|
|
|
|
|
|
void onFailure(Throwable t);
|
|
|
|
}
|
|
|
|
}
|